Skip to content

t1k:cocos:migration:migrate

FieldValue
Modulemigration
Version0.3.0
Efforthigh
Tools

Keywords: cocos, coexistence, cutover, js to ts, migration, orchestrator, pipeline

/t1k:cocos:migration:migrate

Khi muốn chạy CẢ pipeline JS->TS cho nhiều file/1 scene bằng 1 lệnh, thay vì gọi tay từng stage. Orchestrator MỎNG: chỉ điều phối + closure + topo-sort + gate + manifest, mọi logic nằm ở skill stage.

Pipeline 5 pha: dep-graph + 4 .d.ts (Phase0) → js2ts (Phase1) → tsc-validate (Phase2) → uuid-verify gen-meta+attach (Phase3, editor ĐÓNG) → uuid-verify verify=editor-compile-verify (Phase4).

Cách hoạt động — 5 PHA ĐỒNG BỘ (atomic theo closure)

Section titled “Cách hoạt động — 5 PHA ĐỒNG BỘ (atomic theo closure)”

Khác cách 1 vòng for trộn gate + side-effect mỗi file: tách thành các pha; pha side-effect (Phase3) CHỈ chạy khi pha validate (Phase2) xanh toàn bộ closure. Sai thì sai đồng bộ (STOP cả batch, prefab chưa đụng — sửa rule 1 chỗ, áp lại); đúng thì đúng đồng bộ (attach cả closure).

  1. Resolve target: --scene <path> (mọi component custom scene tham chiếu) HOẶC danh sách <file.js>.
  2. Closure = extends + require transitive (internal): base class + mọi require-dep được thêm để convert TRƯỚC (tsc-validate cần dep là module .cv mới type-check sạch; gate attach cần @property inherited). Topo-sort base+require-first.
  3. Phase 0 PRECONDITION (smart-refresh hash-gated): dep-graph + 4 .d.ts CHỈ regenerate khi nguồn đổi (hoặc --force-refresh). Stamp hash vào manifest.
  4. Phase 1 CONVERT (js2ts cả closure). GATE 1 (100% convert) + GATE dependency-holdout (§ Gotcha 6): holdout CÓ consumer trong closure → STOP NGAY Phase 1 (KHÔNG bypass).
  5. Phase 2 VALIDATE (tsc-validate cả closure, 1 lượt filter-arg). GATE 2: 0 SYNTAX (TS1xxx) → else STOP (chưa attach gì). [dry-run] write-real .cv.ts → validate → cleanup.
  6. Phase 3 ATTACH (chỉ --write + --editor-closed): gen-meta single-writer cả closure → attach re-point CHỈ nhóm A. GATE 3: @property completeness → fail → STOP + ROLLBACK.
  7. Phase 4 VERIFY: mở editor lại → dangling + isPlugin + editor-compile-verify.

Trạng thái mỗi file lưu ở manifest tmp/migrate-state.json (SSOT): file “current” (mọi hash khớp) → skip; “stale” → redo. Idempotent: re-run --write cho kết quả y hệt (uuid đã persist). --resync ép coi mọi file stale → reprocess đồng loạt.

Định tuyến nhóm file A/B/C (DATA-driven theo registry)

Section titled “Định tuyến nhóm file A/B/C (DATA-driven theo registry)”
NhómĐiều kiệngen-metaattach (re-point prefab)
A Component CÓ prefab-refisComponent && uuid trong prefab/scene(blast-radius DUY NHẤT)
B Component KHÔNG prefab-refisComponent && 0 ref (logic/base/runtime-add)❌ n/a
C Non-component!isComponent (object/class/global/ES)❌ n/a
  • gen-meta CHO MỌI nhóm — non-component vẫn cần .cv.ts.meta để file TS khác require/import resolve runtime. Không attach ≠ không gen-meta.
  • attach CHỈ nhóm A = phần DUY NHẤT sửa prefab. B/C revert = chỉ xoá .cv.ts/.meta.
  • single-writer/editor-đóng áp MỌI nhóm (gen-meta là một lần GHI single-writer).
Terminal window
# KẾ HOẠCH (mặc định — KHÔNG chạy stage, KHÔNG ghi). In closure + routing A/B/C + cột "cur" (manifest-current):
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --scene <assetsRoot>/scene/<scene>.fire
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs <scriptRoot>/<Path>/<Component>.js
# DRY-RUN (write-real .cv.ts → tsc-validate THẬT → cleanup; KHÔNG attach/meta/sửa prefab):
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --scene <scene>.fire --run
# THỰC THI (editor ĐÓNG — single-writer uuid): ghi .cv.ts + gen-meta + attach re-point prefab/scene:
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --scene <p> --run --write --editor-closed
# FULL LIỀN MẠCH: target = TOÀN BỘ registry (1 closure, topo toàn cục). KHÔNG cần --scene/<file>.
# ⚠ blast radius ≈ MỌI prefab/scene → BẮT BUỘC: baseline git sạch + editor ĐÓNG. Luôn --plan → --run (dry) TRƯỚC.
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --all # plan: closure + A/B/C
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --all --run # dry: validate toàn bộ (0 holdout/syntax)
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --all --run --write --editor-closed # THỰC THI full
# 2 PHA (khuyến nghị diện rộng): convert+validate trước (0 blast radius), attach sau:
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --scene <p> --run --write --no-attach
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --scene <p> --run --write --editor-closed
# ROLLBACK (sau gate-fail Phase3 hoặc muốn revert run gần nhất): git checkout prefab/scene + xoá .meta tool tạo:
node .claude/skills/t1k-cocos-migration-migrate/scripts/migrate.cjs --rollback

Flags:

  • --all — target = TOÀN BỘ registry (full liền mạch): closure = mọi entry, topo base+require-first toàn cục. BỎ QUA --scene/<file> nếu truyền kèm. Blast radius ≈ mọi prefab/scene → luôn --plan--run (dry) trước --write.
  • --editor-closedBẮT BUỘC trước Phase 3 --write (xác nhận editor ĐÓNG → single-writer uuid).
  • --no-attach — pha 1: chỉ js2ts + tsc-validate, KHÔNG re-point prefab (rollback = xoá .cv.ts).
  • --allow-holdout — cho phép leaf-holdout (requiredBy ∉ closure) tách khỏi batch. KHÔNG bypass dependency-holdout.
  • --resync — ép coi MỌI file STALE → reprocess đồng loạt (dùng sau khi sửa 1 bug codemod, áp lại toàn bộ).
  • --force-refresh — ép Phase 0 regenerate registry (dep-graph) + 4 .d.ts.
  • --rollback — thực thi rollback theo manifest.lastRun.repointed (git checkout + xoá .meta tool tạo). KHÔNG tự chạy khi không có cờ này.
  • --manifest <p> (mặc định tmp/migrate-state.json) · --registry <p> · --script-root <p> · --assets-root <p> · --skills-root <p> · --force (bỏ qua gate-fail attach, chuyển uuid-verify).

Config — .claude/cocos-migrate.json (SSOT đường dẫn, KHÔNG hardcode)

Section titled “Config — .claude/cocos-migrate.json (SSOT đường dẫn, KHÔNG hardcode)”

Mọi đường dẫn project lấy từ .claude/cocos-migrate.json (dùng chung cho t1k-cocos-migration-uuid-verify + t1k-cocos-migration-tsc-validate). Thứ tự ưu tiên: CLI flag > config > built-in fallback. Project khác chỉ cần sửa file này, KHÔNG đụng code skill. Các fallback dưới đây là MẶC ĐỊNH (giả định layout phổ biến Client/assets/...), KHÔNG phải bắt buộc — override mọi key cho layout của bạn:

{ "scriptRoot": "Client/assets/script", "assetsRoot": "Client/assets",
"registry": "tmp/dep-registry.json", "creatorDts": "Client/creator.d.ts", "tsconfig": "Client/tsconfig.json",
"skillsRoot": ".claude/skills" }

Thiếu config → dùng fallback (giá trị trên). Sai 1 key → CLI flag tương ứng override. skillsRoot chỉ cần đổi nếu install không-chuẩn (mặc định CI flatten về .claude/skills/).

  • Plan: bảng topo-order — # | grp(A/B/C) | isComp | .cv.ts | JS-ref | cur(manifest-current) | base/req-dep | file + tổng A/B/C.
  • Run: từng Phase 0–4 với gate; SUMMARY file | grp | phase1 | phase2 | phase3. Manifest tmp/migrate-state.json ghi trạng thái + lastRun.repointed (cho rollback).

⚠️ Blast radius (đọc trước khi —write)

Section titled “⚠️ Blast radius (đọc trước khi —write)”

attach re-point component ở MỌI prefab/scene tham chiếu nó (class uuid phải nhất quán toàn cục), KHÔNG chỉ scene bạn truyền. VD --scene <scene>.fire nhưng một widget dùng khắp project (<Label>/<Button>/<Widget>) → —write sẽ sửa hàng chục file. Luôn chạy --plan rồi --run (dry) trước --run --write. Revert = git checkout các prefab/scene.

  1. Mặc định KHÔNG chạy gì--plan chỉ đọc + in. Phải --run mới chạy stage; --run --write --editor-closed mới ghi. An toàn theo preview-first.
  2. Base+require-first BẮT BUỘC — closure = extends + require transitive (internal). gate attach cần @property inherited; tsc-validate cần dep là module .cv (bare cc.Class .js = TS2306). Orchestrator tự convert dep TRƯỚC. Base engine (cc.*, extendsAbs=null) → bỏ qua đúng.
  3. SYNTAX-FAIL (TS1xxx) chặn cả batch ở Gate 2 (không —force) — Phase 3 KHÔNG chạy, 0 prefab bị đụng. Type residual (TS2xxx) KHÔNG chặn (any-safe).
  4. isPlugin auto-fix nằm ở gen-meta/attach (uuid-verify) — orchestrator hưởng sẵn.
  5. Phase 4 verify cần editor đã reimport để library entry phản ánh đúng (editor-compile-verify). Chạy --write với editor đóng → mở editor lại → reload → rồi tin kết quả verify.
  6. GATE dependency-holdout — chặn RẺ ở Phase 1. Holdout = file js2ts KHÔNG convert được (codemod throw vì option cc.Class chưa support). Phân biệt leaf (requiredBy=0, target gốc) vs dependency (có consumer trong closure HOẶC bị expand kéo vào). Dependency-holdout sinh missing-module = TS2xxx NON-blocking → lọt Gate 2, chỉ lộ ở Phase 4 (đắt, SAU side-effect) → vì vậy GATE đặt ở Phase 1: holdout CÓ consumer trong closure → STOP NGAY, KHÔNG cho --allow-holdout bypass. --allow-holdout CHỈ tách leaf. File dependency-holdout cần thêm js2ts support TRƯỚC khi closure chứa nó chạy (gate sẽ STOP an toàn nếu chưa).
  7. Chạy với editor ĐÓNG (single-writer uuid — canonical). uuid là crypto.randomUUID()KHÔNG value-reproducible; “tất định” ở đây = single-writer / process-deterministic / stateful-idempotent: một khi .cv.ts.meta persist thì re-run giữ nguyên uuid (idempotent). --editor-closed BẮT BUỘC trước Phase 3 --write (tool là writer DUY NHẤT). Editor mở lúc attach → 2 writer → uuid khác/isPlugin:true → mất đồng bộ. Chi tiết: t1k-cocos-migration-uuid-verify gotcha 10.
  8. Manifest tmp/migrate-state.json là SSOT trạng thái — file “current” (srcHash + codemodHash + dtsHash + registryHash khớp) → skip; lệch → STALE → redo. --resync ép redo toàn bộ. Idempotent chỉ ở --write (.cv.ts persist); dry-run luôn write-real→cleanup nên không “current-skip”.
  9. Rollback dựa git checkout — yêu cầu prefab/scene SẠCH trước --write (commit/stash trước). Gate-fail Phase 3 → in lệnh rollback (KHÔNG tự chạy); --rollback thực thi theo manifest.lastRun.repointed. JS + .js.meta KHÔNG bao giờ bị đụng.
  • t1k-cocos-migration-js2ts · t1k-cocos-migration-tsc-validate · t1k-cocos-migration-uuid-verify (các stage).
  • t1k-cocos-migration-compref — rewrite string-name component lookup (Phase 1.5).
  • t1k-cocos-migration-dep-graph — registry (results[].extendsAbs/requires dùng để topo-sort).