@playcraft/cli 0.1.54 → 0.1.55-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. package/README.md +83 -15
  2. package/SKILLS_REGISTRY.md +149 -0
  3. package/dist/agent/local-backend.js +1 -1
  4. package/dist/assets/client.js +157 -0
  5. package/dist/assets/messages.js +48 -0
  6. package/dist/auth/account-activation.js +157 -0
  7. package/dist/auth/messages.js +30 -0
  8. package/dist/cli-root-help.js +4 -0
  9. package/dist/commands/assets.js +123 -0
  10. package/dist/commands/build-all.js +5 -19
  11. package/dist/commands/build-temp.js +26 -0
  12. package/dist/commands/build.js +15 -28
  13. package/dist/commands/create.js +26 -33
  14. package/dist/commands/image-layer-messages.js +37 -0
  15. package/dist/commands/image-layer-tools.js +185 -0
  16. package/dist/commands/image.js +2 -73
  17. package/dist/commands/library-messages.js +46 -0
  18. package/dist/commands/library.js +130 -0
  19. package/dist/commands/login.js +84 -42
  20. package/dist/commands/platform-skills.generated.js +19 -0
  21. package/dist/commands/playable.js +53 -0
  22. package/dist/commands/preview-runtime.js +21 -0
  23. package/dist/commands/skills.js +4 -0
  24. package/dist/commands/tools-3d.js +11 -0
  25. package/dist/commands/tools-batch.js +113 -0
  26. package/dist/commands/tools-generation.js +6 -0
  27. package/dist/commands/tools.js +2 -0
  28. package/dist/commands/video.js +122 -0
  29. package/dist/commands/workspace-runtime.js +54 -0
  30. package/dist/commands/workspace.js +40 -0
  31. package/dist/config.js +59 -4
  32. package/dist/index.js +47 -3
  33. package/dist/preview-runtime/distribution.js +77 -0
  34. package/dist/project-skills/builtin-import.js +225 -0
  35. package/dist/project-skills/commands.js +77 -0
  36. package/dist/project-skills/lifecycle.js +28 -0
  37. package/dist/project-skills/local-run.js +112 -0
  38. package/dist/project-skills/local-store.js +221 -0
  39. package/dist/project-skills/messages.js +80 -0
  40. package/dist/project-skills/reconcile.js +62 -0
  41. package/dist/project-skills/remote-cache.js +51 -0
  42. package/dist/project-skills/validation.js +19 -0
  43. package/dist/recording/messages.js +40 -0
  44. package/dist/recording/project-digest.js +85 -0
  45. package/dist/recording/recorder.js +293 -0
  46. package/dist/recording/scenario.js +50 -0
  47. package/dist/remix/clone.js +2 -0
  48. package/dist/remix/init-template.js +2 -0
  49. package/dist/remix/pull.js +2 -0
  50. package/dist/remix/push.js +21 -1
  51. package/dist/skill-registry/client.js +345 -0
  52. package/dist/skill-registry/commands.js +180 -0
  53. package/dist/skill-registry/evaluation-client.js +156 -0
  54. package/dist/skill-registry/evaluation-commands.js +174 -0
  55. package/dist/skill-registry/messages.js +177 -0
  56. package/dist/skill-registry/package.js +275 -0
  57. package/dist/skill-registry/platform-package.js +100 -0
  58. package/dist/utils/agent-api-client.js +245 -30
  59. package/dist/utils/environment-endpoints.js +17 -0
  60. package/dist/utils/error-diagnostics.js +20 -0
  61. package/dist/utils/playcraft-http-client.js +6 -4
  62. package/dist/utils/tool-operation-journal.js +124 -0
  63. package/dist/utils/video-evidence-git.js +81 -0
  64. package/dist/video-replication/client.js +234 -0
  65. package/dist/video-replication/comparison-evidence.js +149 -0
  66. package/dist/video-replication/comparison-files.js +57 -0
  67. package/dist/video-replication/comparison-log.js +72 -0
  68. package/dist/video-replication/comparison-messages.js +104 -0
  69. package/dist/video-replication/comparison-output.js +63 -0
  70. package/dist/video-replication/comparison-preflight.js +66 -0
  71. package/dist/video-replication/comparison.js +230 -0
  72. package/dist/video-replication/diagnostics.js +41 -0
  73. package/dist/video-replication/evidence.js +165 -0
  74. package/dist/video-replication/media.js +112 -0
  75. package/dist/video-replication/messages.js +97 -0
  76. package/dist/workspace/messages.js +67 -0
  77. package/dist/workspace/transfer-client.js +237 -0
  78. package/dist/workspace/transfer-errors.js +48 -0
  79. package/dist/workspace-runtime/batch/content-changes.js +30 -0
  80. package/dist/workspace-runtime/batch/control.js +86 -0
  81. package/dist/workspace-runtime/batch/deliver.js +173 -0
  82. package/dist/workspace-runtime/batch/freeze.js +101 -0
  83. package/dist/workspace-runtime/batch/generate.js +249 -0
  84. package/dist/workspace-runtime/batch/git.js +40 -0
  85. package/dist/workspace-runtime/batch/occupancy.js +8 -0
  86. package/dist/workspace-runtime/batch/policy.js +70 -0
  87. package/dist/workspace-runtime/batch/prepare.js +317 -0
  88. package/dist/workspace-runtime/batch/processes.js +72 -0
  89. package/dist/workspace-runtime/batch/records.js +113 -0
  90. package/dist/workspace-runtime/batch/routes.js +61 -0
  91. package/dist/workspace-runtime/batch/source-candidate.js +86 -0
  92. package/dist/workspace-runtime/batch/source-capture.js +146 -0
  93. package/dist/workspace-runtime/batch/source-failure.js +43 -0
  94. package/dist/workspace-runtime/batch/source-publish.js +130 -0
  95. package/dist/workspace-runtime/codex/app-server.js +1065 -0
  96. package/dist/workspace-runtime/codex/compact.js +46 -0
  97. package/dist/workspace-runtime/codex/config-toml.js +107 -0
  98. package/dist/workspace-runtime/codex/delivery-tools.js +144 -0
  99. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +145 -0
  100. package/dist/workspace-runtime/codex/launcher-client.js +177 -0
  101. package/dist/workspace-runtime/codex/loopback.js +146 -0
  102. package/dist/workspace-runtime/codex/mcp-config.js +39 -0
  103. package/dist/workspace-runtime/codex/model-broker.js +263 -0
  104. package/dist/workspace-runtime/codex/native-adapter.js +9 -0
  105. package/dist/workspace-runtime/codex/permissions.js +79 -0
  106. package/dist/workspace-runtime/codex/thread-image.js +38 -0
  107. package/dist/workspace-runtime/codex/tool-response.js +10 -0
  108. package/dist/workspace-runtime/codex/ui-instructions.js +4 -0
  109. package/dist/workspace-runtime/codex/ui-tools.js +203 -0
  110. package/dist/workspace-runtime/codex/work-mode.js +15 -0
  111. package/dist/workspace-runtime/main.js +10 -0
  112. package/dist/workspace-runtime/persistence/journal.js +365 -0
  113. package/dist/workspace-runtime/persistence/native-subagents.js +162 -0
  114. package/dist/workspace-runtime/persistence/sqlite-client.js +77 -0
  115. package/dist/workspace-runtime/persistence/sqlite-worker.js +1161 -0
  116. package/dist/workspace-runtime/persistence/stopped-execution.js +77 -0
  117. package/dist/workspace-runtime/previews/diagnostics.js +44 -0
  118. package/dist/workspace-runtime/previews/output.js +36 -0
  119. package/dist/workspace-runtime/previews/publish.js +283 -0
  120. package/dist/workspace-runtime/previews/runtime-preview.js +251 -0
  121. package/dist/workspace-runtime/previews/single-file.js +43 -0
  122. package/dist/workspace-runtime/processes/managed-writes.js +69 -0
  123. package/dist/workspace-runtime/serve.js +441 -0
  124. package/dist/workspace-runtime/server/accept-operation.js +61 -0
  125. package/dist/workspace-runtime/server/asset-transfers.js +63 -0
  126. package/dist/workspace-runtime/server/auth.js +21 -0
  127. package/dist/workspace-runtime/server/connectivity.js +211 -0
  128. package/dist/workspace-runtime/server/desktop-host.js +429 -0
  129. package/dist/workspace-runtime/server/desktop-preview-config.js +81 -0
  130. package/dist/workspace-runtime/server/desktop-preview-service.js +157 -0
  131. package/dist/workspace-runtime/server/desktop-preview-static.js +53 -0
  132. package/dist/workspace-runtime/server/desktop-preview.js +189 -0
  133. package/dist/workspace-runtime/server/dispatch.js +1655 -0
  134. package/dist/workspace-runtime/server/endpoints.js +21 -0
  135. package/dist/workspace-runtime/server/execution-group.js +90 -0
  136. package/dist/workspace-runtime/server/http.js +1363 -0
  137. package/dist/workspace-runtime/server/lock.js +53 -0
  138. package/dist/workspace-runtime/server/operation-record.js +33 -0
  139. package/dist/workspace-runtime/server/rfb-watch-gate.js +168 -0
  140. package/dist/workspace-runtime/server/session-restore.js +84 -0
  141. package/dist/workspace-runtime/server/source-uploader.js +138 -0
  142. package/dist/workspace-runtime/server/submit-operation.js +41 -0
  143. package/dist/workspace-runtime/server/terminal-host.js +366 -0
  144. package/dist/workspace-runtime/server/types.js +1 -0
  145. package/dist/workspace-runtime/server/workspace-transfer.js +168 -0
  146. package/dist/workspace-runtime/verify-artifact.js +59 -0
  147. package/dist/workspace-runtime/workspaces/append-only-log.js +62 -0
  148. package/dist/workspace-runtime/workspaces/archive.js +207 -0
  149. package/dist/workspace-runtime/workspaces/artifact-events.js +55 -0
  150. package/dist/workspace-runtime/workspaces/artifact-files.js +199 -0
  151. package/dist/workspace-runtime/workspaces/artifact-receipts.js +89 -0
  152. package/dist/workspace-runtime/workspaces/artifacts.js +282 -0
  153. package/dist/workspace-runtime/workspaces/asset-library-import.js +387 -0
  154. package/dist/workspace-runtime/workspaces/asset-publication-access.js +25 -0
  155. package/dist/workspace-runtime/workspaces/asset-transfer-dependencies.js +81 -0
  156. package/dist/workspace-runtime/workspaces/asset-transfer-publish.js +438 -0
  157. package/dist/workspace-runtime/workspaces/asset-transfer-storage.js +389 -0
  158. package/dist/workspace-runtime/workspaces/attachment-content.js +73 -0
  159. package/dist/workspace-runtime/workspaces/attachments.js +185 -0
  160. package/dist/workspace-runtime/workspaces/batch-commit.js +142 -0
  161. package/dist/workspace-runtime/workspaces/binary-content.js +65 -0
  162. package/dist/workspace-runtime/workspaces/binary-write.js +117 -0
  163. package/dist/workspace-runtime/workspaces/cli-context.js +23 -0
  164. package/dist/workspace-runtime/workspaces/cli-credentials.js +115 -0
  165. package/dist/workspace-runtime/workspaces/composer-context.js +147 -0
  166. package/dist/workspace-runtime/workspaces/context-error.js +2 -0
  167. package/dist/workspace-runtime/workspaces/delivery-build.js +331 -0
  168. package/dist/workspace-runtime/workspaces/delivery-store.js +168 -0
  169. package/dist/workspace-runtime/workspaces/delivery.js +64 -0
  170. package/dist/workspace-runtime/workspaces/dependencies.js +279 -0
  171. package/dist/workspace-runtime/workspaces/developer-command.js +98 -0
  172. package/dist/workspace-runtime/workspaces/directories.js +135 -0
  173. package/dist/workspace-runtime/workspaces/directory-access.js +37 -0
  174. package/dist/workspace-runtime/workspaces/directory-attachments.js +245 -0
  175. package/dist/workspace-runtime/workspaces/directory-create.js +57 -0
  176. package/dist/workspace-runtime/workspaces/directory-maintenance.js +111 -0
  177. package/dist/workspace-runtime/workspaces/directory-mutations.js +238 -0
  178. package/dist/workspace-runtime/workspaces/directory-revisions.js +56 -0
  179. package/dist/workspace-runtime/workspaces/directory-stats.js +49 -0
  180. package/dist/workspace-runtime/workspaces/disk-snapshot.js +31 -0
  181. package/dist/workspace-runtime/workspaces/empty-template.js +43 -0
  182. package/dist/workspace-runtime/workspaces/file-content.js +48 -0
  183. package/dist/workspace-runtime/workspaces/files-search.js +116 -0
  184. package/dist/workspace-runtime/workspaces/files.js +150 -0
  185. package/dist/workspace-runtime/workspaces/git-credential-broker.js +312 -0
  186. package/dist/workspace-runtime/workspaces/git-credential-helper.js +68 -0
  187. package/dist/workspace-runtime/workspaces/git-direct-store.js +155 -0
  188. package/dist/workspace-runtime/workspaces/git.js +670 -0
  189. package/dist/workspace-runtime/workspaces/instructions.js +56 -0
  190. package/dist/workspace-runtime/workspaces/json5-edit.js +313 -0
  191. package/dist/workspace-runtime/workspaces/library-attachments.js +268 -0
  192. package/dist/workspace-runtime/workspaces/operation-log.js +23 -0
  193. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +14 -0
  194. package/dist/workspace-runtime/workspaces/parameter-agent-inputs.js +97 -0
  195. package/dist/workspace-runtime/workspaces/parameter-agent-protocol.js +40 -0
  196. package/dist/workspace-runtime/workspaces/parameter-agent-store.js +58 -0
  197. package/dist/workspace-runtime/workspaces/parameter-agent.js +284 -0
  198. package/dist/workspace-runtime/workspaces/parameter-assets.js +189 -0
  199. package/dist/workspace-runtime/workspaces/parameters.js +329 -0
  200. package/dist/workspace-runtime/workspaces/prepare.js +284 -0
  201. package/dist/workspace-runtime/workspaces/registry.js +251 -0
  202. package/dist/workspace-runtime/workspaces/remix-references.js +301 -0
  203. package/dist/workspace-runtime/workspaces/revisions.js +31 -0
  204. package/dist/workspace-runtime/workspaces/session-image.js +104 -0
  205. package/dist/workspace-runtime/workspaces/shared-git.js +40 -0
  206. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +95 -0
  207. package/dist/workspace-runtime/workspaces/skills.js +191 -0
  208. package/dist/workspace-runtime/workspaces/theme-asset-index.js +157 -0
  209. package/dist/workspace-runtime/workspaces/transfer-quota.js +69 -0
  210. package/dist/workspace-runtime/workspaces/transfer.js +471 -0
  211. package/dist/workspace-runtime/workspaces/turn-changes.js +75 -0
  212. package/dist/workspace-runtime/workspaces/video-attachments.js +49 -0
  213. package/dist/workspace-runtime/workspaces/worktree-attachments.js +74 -0
  214. package/dist/workspace-runtime/workspaces/worktree-checkout.js +67 -0
  215. package/dist/workspace-runtime/workspaces/worktrees.js +73 -0
  216. package/package.json +16 -5
  217. package/project-template/.claude/skills/playcraft-audio-generation/SKILL.md +31 -4
  218. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +36 -5
  219. package/project-template/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +1 -1
  220. package/project-template/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +1 -1
  221. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +1 -1
  222. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +1 -1
  223. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +1 -1
  224. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +1 -1
  225. package/project-template/.claude/skills/playcraft-image-generation/reference/ta-image-generation-detail.md +300 -0
  226. package/project-template/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +1 -1
  227. package/project-template/.claude/skills/playcraft-image-processing/SKILL.md +50 -25
  228. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +25 -0
  229. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +79 -0
  230. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +29 -0
  231. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +37 -0
  232. package/project-template/.claude/skills/playcraft-workspace-assets/SKILL.md +53 -0
  233. package/project-template/.claude/skills/playcraft-workspace-assets/references/requests.json +32 -0
  234. package/project-template-v2/.claude/agents/artist.md +82 -0
  235. package/project-template-v2/.claude/agents/developer.md +153 -0
  236. package/project-template-v2/.claude/agents/game-designer.md +264 -0
  237. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +533 -0
  238. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +153 -0
  239. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +27 -0
  240. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +208 -0
  241. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +81 -0
  242. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +432 -0
  243. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +252 -0
  244. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +266 -0
  245. package/project-template-v2/.claude/agents/refs/framework-mda.md +147 -0
  246. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +123 -0
  247. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +88 -0
  248. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +67 -0
  249. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +120 -0
  250. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +300 -0
  251. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +495 -0
  252. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +1141 -0
  253. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +111 -0
  254. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +365 -0
  255. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +412 -0
  256. package/project-template-v2/.claude/agents/reviewer.md +75 -0
  257. package/project-template-v2/.claude/agents/technical-artist.md +86 -0
  258. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +243 -0
  259. package/project-template-v2/.claude/hooks/user-prompt.mjs +133 -0
  260. package/project-template-v2/.claude/settings.json +33 -0
  261. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +161 -0
  262. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +270 -0
  263. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +177 -0
  264. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +354 -0
  265. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +148 -0
  266. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +56 -0
  267. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +62 -0
  268. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  269. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +309 -0
  270. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +182 -0
  271. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +123 -0
  272. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +205 -0
  273. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +307 -0
  274. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +184 -0
  275. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +306 -0
  276. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +401 -0
  277. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +123 -0
  278. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +254 -0
  279. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +333 -0
  280. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +95 -0
  281. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +118 -0
  282. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +136 -0
  283. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +397 -0
  284. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/ta-image-generation-detail.md +300 -0
  285. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +296 -0
  286. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +122 -0
  287. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +244 -0
  288. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +373 -0
  289. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +161 -0
  290. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +215 -0
  291. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +382 -0
  292. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +423 -0
  293. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +158 -0
  294. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +100 -0
  295. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +167 -0
  296. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +270 -0
  297. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +236 -0
  298. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +130 -0
  299. package/project-template-v2/.claude/skills/playcraft-workspace-assets/SKILL.md +53 -0
  300. package/project-template-v2/.claude/skills/playcraft-workspace-assets/references/requests.json +32 -0
  301. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +390 -0
  302. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +23 -0
  303. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +39 -0
  304. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +87 -0
  305. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +240 -0
  306. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +226 -0
  307. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +308 -0
  308. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +275 -0
  309. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +134 -0
  310. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +142 -0
  311. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +153 -0
  312. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +386 -0
  313. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +182 -0
  314. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +72 -0
  315. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +121 -0
  316. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +102 -0
  317. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +127 -0
  318. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +106 -0
  319. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +128 -0
  320. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +67 -0
  321. package/project-template-v2/.claude/snapshot.mjs +263 -0
  322. package/project-template-v2/.playcraft/skills.lock.json +152 -0
  323. package/project-template-v2/CLAUDE.md +146 -0
  324. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  325. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  326. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  327. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  328. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  329. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  330. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  331. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  332. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  333. package/project-template-v2/assets/models/.gitkeep +0 -0
  334. package/project-template-v2/docs/harness/iteration-1/context-flow.md +254 -0
  335. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +91 -0
  336. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +214 -0
  337. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +75 -0
  338. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +63 -0
  339. package/project-template-v2/docs/harness/iteration-2/context-flow.md +223 -0
  340. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +129 -0
  341. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +267 -0
  342. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +164 -0
  343. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +115 -0
  344. package/project-template-v2/docs/harness/orchestrator-flow.md +364 -0
  345. package/project-template-v2/docs/project-state.json +60 -0
  346. package/project-template-v2/docs/project-state.md +72 -0
  347. package/project-template-v2/docs/standards/README.md +225 -0
  348. package/project-template-v2/docs/standards/agent-behavior-standards.md +174 -0
  349. package/project-template-v2/docs/standards/artifacts/design-brief.md +19 -0
  350. package/project-template-v2/docs/standards/artifacts/design.md +22 -0
  351. package/project-template-v2/docs/standards/artifacts/game-code.md +41 -0
  352. package/project-template-v2/docs/standards/artifacts/todo-list.md +41 -0
  353. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +343 -0
  354. package/project-template-v2/game/index.ts +18 -0
  355. package/project-template-v2/globals.d.ts +51 -0
  356. package/project-template-v2/index.css +34 -0
  357. package/project-template-v2/index.html +18 -0
  358. package/project-template-v2/main.ts +9 -0
  359. package/project-template-v2/package.json +46 -0
  360. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +31 -0
  361. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +86 -0
  362. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +153 -0
  363. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +70 -0
  364. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +91 -0
  365. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +131 -0
  366. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +80 -0
  367. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +90 -0
  368. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +93 -0
  369. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +23 -0
  370. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +230 -0
  371. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +58 -0
  372. package/project-template-v2/skills/_shared/scripts/state-get.mjs +339 -0
  373. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +39 -0
  374. package/project-template-v2/skills/_shared/scripts/state-set.mjs +94 -0
  375. package/project-template-v2/skills/_shared/scripts/state-store.mjs +783 -0
  376. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +88 -0
  377. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +130 -0
  378. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +33 -0
  379. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +47 -0
  380. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +268 -0
  381. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +285 -0
  382. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +161 -0
  383. package/project-template-v2/skills/playable-autoplay/SKILL.md +176 -0
  384. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +4 -0
  385. package/project-template-v2/skills/playable-debug/SKILL.md +116 -0
  386. package/project-template-v2/skills/playable-debug/agents/openai.yaml +4 -0
  387. package/project-template-v2/skills/playable-debug/references/debug-config.md +40 -0
  388. package/project-template-v2/skills/playable-record/SKILL.md +140 -0
  389. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +104 -0
  390. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +141 -0
  391. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +425 -0
  392. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +261 -0
  393. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +398 -0
  394. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +322 -0
  395. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +105 -0
  396. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +230 -0
  397. package/project-template-v2/skills/playable-validate/SKILL.md +61 -0
  398. package/project-template-v2/skills/playable-validate/validation-rules.md +14 -0
  399. package/project-template-v2/skills/playable-verify-ui/SKILL.md +63 -0
  400. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +1 -0
  401. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +218 -0
  402. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +51 -0
  403. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +59 -0
  404. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +106 -0
  405. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +116 -0
  406. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +59 -0
  407. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +64 -0
  408. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +58 -0
  409. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +333 -0
  410. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  411. package/project-template-v2/tsconfig.json +20 -0
  412. package/project-template-v2/vite.config.ts +27 -0
  413. package/project-templates/batch-locks/phaser.yaml +922 -0
  414. package/project-templates/batch-locks/threejs.yaml +978 -0
  415. package/project-templates/empty/AGENTS.md +53 -0
  416. package/project-templates/empty/gitignore +33 -0
  417. package/project-templates/phaser/.claude/skills/playcraft-audio-generation/SKILL.md +31 -4
  418. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +36 -5
  419. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +1 -1
  420. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +1 -1
  421. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +1 -1
  422. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +1 -1
  423. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +1 -1
  424. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +1 -1
  425. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/ta-image-generation-detail.md +300 -0
  426. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +1 -1
  427. package/project-templates/phaser/.claude/skills/playcraft-image-processing/SKILL.md +50 -25
  428. package/project-templates/phaser/.claude/skills/playcraft-workspace-assets/SKILL.md +53 -0
  429. package/project-templates/phaser/.claude/skills/playcraft-workspace-assets/references/requests.json +32 -0
  430. package/project-templates/threejs/.claude/skills/playcraft-audio-generation/SKILL.md +31 -4
  431. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +36 -5
  432. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +1 -1
  433. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +1 -1
  434. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +1 -1
  435. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +1 -1
  436. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +1 -1
  437. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +1 -1
  438. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/ta-image-generation-detail.md +300 -0
  439. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +1 -1
  440. package/project-templates/threejs/.claude/skills/playcraft-image-processing/SKILL.md +50 -25
  441. package/project-templates/threejs/.claude/skills/playcraft-workspace-assets/SKILL.md +53 -0
  442. package/project-templates/threejs/.claude/skills/playcraft-workspace-assets/references/requests.json +32 -0
  443. package/templates/preview-runtime/v1/README.md +71 -0
  444. package/templates/preview-runtime/v1/build-preview.mjs +1324 -0
  445. package/templates/preview-runtime/v1/manifest.json +17 -0
  446. package/templates/preview-runtime/v1/release-guard.mjs +87 -0
  447. package/templates/preview-runtime/v1/runtime.d.mts +3 -0
  448. package/templates/preview-runtime/v1/runtime.d.ts +3 -0
  449. package/templates/preview-runtime/v1/runtime.mjs +1121 -0
  450. package/templates/preview-runtime/v1/types/adapters.d.ts +26 -0
  451. package/templates/preview-runtime/v1/types/preview.d.ts +23 -0
  452. package/templates/preview-runtime/v1/types/protocol.d.ts +94 -0
  453. package/templates/preview-runtime/v1/types/runtime.d.ts +14 -0
@@ -0,0 +1,157 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { loadGlobalConfig } from '../config.js';
5
+ import { accountActivationMessage } from './messages.js';
6
+ export const ACCOUNT_PENDING_ACTIVATION = 'account_pending_activation';
7
+ export class AccountActivationError extends Error {
8
+ code;
9
+ status;
10
+ retryable = false;
11
+ constructor(code, message, status) {
12
+ super(message);
13
+ this.code = code;
14
+ this.status = status;
15
+ this.name = 'AccountActivationError';
16
+ }
17
+ }
18
+ export function responseErrorCode(payload) {
19
+ if (!payload || typeof payload !== 'object')
20
+ return undefined;
21
+ const { error, code } = payload;
22
+ return typeof error?.code === 'string' ? error.code : typeof code === 'string' ? code : undefined;
23
+ }
24
+ export function pendingAccountActivationError(status, payload) {
25
+ return status === 403 && responseErrorCode(payload) === ACCOUNT_PENDING_ACTIVATION
26
+ ? new AccountActivationError(ACCOUNT_PENDING_ACTIVATION, `${ACCOUNT_PENDING_ACTIVATION}: ${accountActivationMessage('pending')}`, status)
27
+ : undefined;
28
+ }
29
+ export function parseErrorPayload(text) {
30
+ try {
31
+ return JSON.parse(text);
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ function localActivationConfig() {
38
+ for (const path of [
39
+ join(process.cwd(), '.playcraft.json'),
40
+ '/project/.playcraft.json',
41
+ join(homedir(), '.playcraft.json'),
42
+ ]) {
43
+ if (!existsSync(path))
44
+ continue;
45
+ try {
46
+ const config = JSON.parse(readFileSync(path, 'utf8'));
47
+ if (config && typeof config === 'object' && !Array.isArray(config))
48
+ return config;
49
+ }
50
+ catch {
51
+ // Follow the existing local credential lookup when a file is unreadable.
52
+ }
53
+ }
54
+ return {};
55
+ }
56
+ function stringValue(value) {
57
+ return typeof value === 'string' && value ? value : undefined;
58
+ }
59
+ function activationBaseUrl(raw) {
60
+ try {
61
+ const url = new URL(raw);
62
+ if (!['http:', 'https:'].includes(url.protocol) ||
63
+ url.username ||
64
+ url.password ||
65
+ url.search ||
66
+ url.hash)
67
+ throw new Error();
68
+ url.pathname = url.pathname.replace(/\/+$/, '').replace(/\/api$/, '');
69
+ return url.toString().replace(/\/+$/, '');
70
+ }
71
+ catch {
72
+ throw new AccountActivationError('INVALID_ACTIVATION_TARGET', accountActivationMessage('invalidTarget'));
73
+ }
74
+ }
75
+ function savedTokenForTarget(config, rawUrl, target, environment) {
76
+ if (!rawUrl || (stringValue(config.env)?.trim() || '') !== environment)
77
+ return undefined;
78
+ try {
79
+ return activationBaseUrl(rawUrl) === target ? stringValue(config.token) : undefined;
80
+ }
81
+ catch {
82
+ return undefined;
83
+ }
84
+ }
85
+ function normalizedSavedUrl(raw) {
86
+ try {
87
+ return raw ? activationBaseUrl(raw) : undefined;
88
+ }
89
+ catch {
90
+ return undefined;
91
+ }
92
+ }
93
+ export async function activateAccount(options, defaultBaseUrl) {
94
+ const local = localActivationConfig();
95
+ const global = loadGlobalConfig();
96
+ const localUrl = stringValue(local.apiUrl);
97
+ const globalUrl = stringValue(global.backendUrl) || stringValue(global.url);
98
+ const explicitUrl = options.url || process.env.PLAYCRAFT_API_URL || process.env.PLAYCRAFT_URL;
99
+ const target = activationBaseUrl(explicitUrl || localUrl || globalUrl || defaultBaseUrl);
100
+ const explicitToken = options.token || process.env.PLAYCRAFT_TOKEN || process.env.PLAYCRAFT_SANDBOX_TOKEN;
101
+ const savedUrls = [normalizedSavedUrl(localUrl), normalizedSavedUrl(globalUrl)].filter(Boolean);
102
+ const savedTokens = [stringValue(local.token), stringValue(global.token)].filter(Boolean);
103
+ const environmentsConflict = savedUrls.length === 2 &&
104
+ savedUrls[0] === savedUrls[1] &&
105
+ (stringValue(local.env)?.trim() || '') !== (stringValue(global.env)?.trim() || '');
106
+ const environmentTokensConflict = process.env.PLAYCRAFT_TOKEN &&
107
+ process.env.PLAYCRAFT_SANDBOX_TOKEN &&
108
+ process.env.PLAYCRAFT_TOKEN !== process.env.PLAYCRAFT_SANDBOX_TOKEN;
109
+ const environmentUrlsConflict = process.env.PLAYCRAFT_API_URL &&
110
+ process.env.PLAYCRAFT_URL &&
111
+ normalizedSavedUrl(process.env.PLAYCRAFT_API_URL) !==
112
+ normalizedSavedUrl(process.env.PLAYCRAFT_URL);
113
+ if ((!explicitUrl && new Set(savedUrls).size > 1) ||
114
+ (!explicitToken && new Set(savedTokens).size > 1) ||
115
+ (environmentsConflict && !process.env.PLAYCRAFT_ENV) ||
116
+ (environmentTokensConflict && !options.token) ||
117
+ (environmentUrlsConflict && !options.url)) {
118
+ throw new AccountActivationError('AMBIGUOUS_ACTIVATION_TARGET', accountActivationMessage('ambiguous'));
119
+ }
120
+ const environment = (process.env.PLAYCRAFT_ENV ||
121
+ (!explicitUrl ? (localUrl ? stringValue(local.env) : stringValue(global.env)) : '') ||
122
+ '').trim();
123
+ const token = explicitToken ||
124
+ savedTokenForTarget(local, localUrl, target, environment) ||
125
+ savedTokenForTarget(global, globalUrl, target, environment);
126
+ if (!token)
127
+ throw new AccountActivationError('AUTH_REQUIRED', accountActivationMessage('missingToken'));
128
+ if (!/^playcraft_pat_[A-Za-z0-9_-]{32}$/.test(token)) {
129
+ throw new AccountActivationError('INVALID_ACTIVATION_TOKEN', accountActivationMessage('invalidToken'));
130
+ }
131
+ let response;
132
+ try {
133
+ response = await fetch(`${target}/api/settings/personal-access-tokens/activate`, {
134
+ method: 'POST',
135
+ redirect: 'error',
136
+ signal: AbortSignal.timeout(30_000),
137
+ headers: {
138
+ Authorization: `Bearer ${token}`,
139
+ ...(environment ? { 'playcraft-env': environment } : {}),
140
+ },
141
+ });
142
+ }
143
+ catch {
144
+ throw new AccountActivationError('ACTIVATION_UNCONFIRMED', accountActivationMessage('unavailable'));
145
+ }
146
+ if (!response.ok) {
147
+ await response.body?.cancel().catch(() => { });
148
+ throw new AccountActivationError('ACTIVATION_FAILED', accountActivationMessage('failed'), response.status);
149
+ }
150
+ const result = await response.json().catch(() => undefined);
151
+ if (!result ||
152
+ typeof result !== 'object' ||
153
+ result.accountStatus !== 'active') {
154
+ throw new AccountActivationError('ACTIVATION_UNCONFIRMED', accountActivationMessage('unavailable'), response.status);
155
+ }
156
+ console.log(accountActivationMessage('success'));
157
+ }
@@ -0,0 +1,30 @@
1
+ const messages = {
2
+ en: {
3
+ activateOption: 'Explicitly activate the account using the current personal access token',
4
+ tokenOption: 'Personal access token for --activate (or use PLAYCRAFT_TOKEN)',
5
+ pending: 'Account activation is required. Run `playcraft login --activate` with the same token and target environment, then rerun your command.',
6
+ success: 'Account activated. Rerun your original command to continue.',
7
+ missingToken: 'No personal access token matches this target environment. Provide PLAYCRAFT_TOKEN or log in to this environment first.',
8
+ invalidToken: 'Account activation requires a personal access token. A sandbox token cannot activate an account.',
9
+ ambiguous: 'Activation credentials or target environments conflict. Specify --url, PLAYCRAFT_ENV when needed, and an explicit personal access token using --token or PLAYCRAFT_TOKEN.',
10
+ invalidTarget: 'Use a web service base address (http:// or https://) without credentials, a query, or a fragment.',
11
+ failed: 'Account activation failed. Check the target environment and token before trying again.',
12
+ unavailable: 'Account activation could not be confirmed. Check your account status before explicitly trying again.',
13
+ },
14
+ zh: {
15
+ activateOption: '明确使用当前个人访问令牌激活账号',
16
+ tokenOption: '用于 --activate 的个人访问令牌(也可使用 PLAYCRAFT_TOKEN)',
17
+ pending: '账号需要激活。请使用同一令牌和目标环境主动运行 `playcraft login --activate`,然后重新执行原命令。',
18
+ success: '账号已激活,请重新执行原命令继续。',
19
+ missingToken: '没有与目标环境匹配的个人访问令牌。请提供 PLAYCRAFT_TOKEN,或先登录此环境。',
20
+ invalidToken: '激活账号需要个人访问令牌,沙箱令牌不能用于激活账号。',
21
+ ambiguous: '激活凭据或目标环境存在冲突。请明确指定 --url、所需的 PLAYCRAFT_ENV,并通过 --token 或 PLAYCRAFT_TOKEN 提供个人访问令牌。',
22
+ invalidTarget: '激活目标必须是网页服务基址(http:// 或 https://),不能包含凭据、查询参数或片段。',
23
+ failed: '账号激活失败,请检查目标环境和令牌后再尝试。',
24
+ unavailable: '无法确认账号是否已激活。请先检查账号状态,再主动决定是否重试。',
25
+ },
26
+ };
27
+ export function accountActivationMessage(key) {
28
+ const locale = process.env.PLAYCRAFT_LANGUAGE || process.env.LANG || 'en';
29
+ return messages[locale.startsWith('zh') ? 'zh' : 'en'][key];
30
+ }
@@ -5,8 +5,12 @@ export function getCliTopicsHelpText() {
5
5
  '',
6
6
  ' 本地开发 create, init, start, stop, status, logs, config, sync, fix-ids',
7
7
  ' 素材 tools generate-* | image <子命令> | audio <子命令> | prefab <子命令>',
8
+ ' 素材库 library list/search/facets/get/files/download',
9
+ ' 生成任务 assets estimate/generate/tasks/get/wait/cancel/download | assets animation',
10
+ ' 视频理解 video models | video understand | video jobs get/cancel',
8
11
  ' 平台 build, build-base, build-playable, build-all, analyze, inspect, upgrade',
9
12
  ' tools 除 generate-* 外(Git / 沙箱构建 / 发布 / 列表 / Prefab 等,需后端 API)',
13
+ ' 沙箱常驻 workspace-runtime serve(Cloud Workspace,由 Runtime 引导配置启动)',
10
14
  '',
11
15
  '也可运行: playcraft topics',
12
16
  '',
@@ -0,0 +1,123 @@
1
+ import { assetGenerationRequestSchema, assetGenerationEstimateInput, assetGenerationEstimateInputSchema, assetGenerationEstimateSchema, assetGenerationTaskSavedSchema, assetLibrarySaveRequestSchema, assetLibrarySaveJobSchema, assetLibrarySaveListSchema, assetLibrarySaveTargetsSchema, animationEditorStateSchema, animationEditorDraftUpdateSchema, animationEditorFrameUploadSchema, animationEditorFrameUploadResultSchema, animationEditorVersionCreateSchema, animationEditorVersionResultSchema, workspaceAssetToolWriteSchema, } from '@playcraft/common/cloud-workspace/runtime';
2
+ import { AgentApiClient } from '../utils/agent-api-client.js';
3
+ import { resolveAssetScope, readAssetRequest, readAssetTask, readAssetTasks, scopedAssetTask, waitForAssetTask, downloadAssetTask } from '../assets/client.js';
4
+ import { validateAssetWait } from '../assets/client.js';
5
+ import { assetMessage as t } from '../assets/messages.js';
6
+ function shared(command) {
7
+ return command.option('--workspace <id>', t('workspace')).option('--directory <name>', t('directory')).option('--json', t('json'));
8
+ }
9
+ function polling(command) {
10
+ return command.option('--timeout <seconds>', t('timeout'), '1800').option('--interval <seconds>', t('interval'), '3');
11
+ }
12
+ function identifier(value) {
13
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value))
14
+ throw new Error(t('invalidRequest'));
15
+ return value.toLowerCase();
16
+ }
17
+ async function document(path) { if (!path)
18
+ throw new Error(t('invalidRequest')); return readAssetRequest(path); }
19
+ async function run(command, options, action) {
20
+ try {
21
+ const scope = await resolveAssetScope(options);
22
+ const result = await action({ scope, client: new AgentApiClient() });
23
+ const record = result && typeof result === 'object' ? result : {};
24
+ const failed = ['failed', 'interrupted', ...(command === 'assets cancel' ? [] : ['cancelled'])];
25
+ const ok = !failed.includes(record.status ?? '');
26
+ process.stdout.write(`${JSON.stringify({ schemaVersion: 'playcraft.assets-cli.v1', command, ok, result })}\n`);
27
+ if (!ok)
28
+ process.exitCode = 1;
29
+ }
30
+ catch (error) {
31
+ const message = error instanceof Error ? error.message : String(error);
32
+ const timeout = message === t('timeoutReached');
33
+ process.stderr.write(`${t('failed')}: ${message}\n`);
34
+ process.stdout.write(`${JSON.stringify({ schemaVersion: 'playcraft.assets-cli.v1', command, ok: false,
35
+ error: { code: timeout ? 'asset_generation_wait_timeout' : 'asset_operation_failed', message } })}\n`);
36
+ process.exitCode = timeout ? 75 : 1;
37
+ }
38
+ }
39
+ function write(client, body) {
40
+ return client.post(body.action === 'animation-draft' ? '/workspace-assets/animation-draft' : '/workspace-assets', workspaceAssetToolWriteSchema.parse(body));
41
+ }
42
+ export function registerWorkspaceAssetCommands(program) {
43
+ const assets = program.command('assets').description(t('topic'));
44
+ shared(assets.command('estimate').description(t('estimate')))
45
+ .requiredOption('--request <path>', t('request'))
46
+ .action((options) => run('assets estimate', options, async ({ client, scope }) => {
47
+ const input = await document(options.request), full = assetGenerationRequestSchema.safeParse(input);
48
+ const request = full.success ? assetGenerationEstimateInput(full.data) : assetGenerationEstimateInputSchema.parse(input);
49
+ return assetGenerationEstimateSchema.parse(await write(client, { ...scope, action: 'estimate', request }));
50
+ }));
51
+ polling(shared(assets.command('generate').description(t('generate'))))
52
+ .requiredOption('--request <path>', t('request')).requiredOption('--client-request-id <id>', t('clientRequest'))
53
+ .option('--wait', t('waitOption')).option('--output <path>', t('output'))
54
+ .action((options) => run('assets generate', options, async ({ client, scope }) => {
55
+ if (options.output && !options.wait)
56
+ throw new Error(t('invalidRequest'));
57
+ if (options.wait)
58
+ validateAssetWait(Number(options.timeout), Number(options.interval));
59
+ const clientRequestId = options.clientRequestId.trim();
60
+ if (!clientRequestId)
61
+ throw new Error(t('invalidRequest'));
62
+ const request = assetGenerationRequestSchema.parse(await document(options.request));
63
+ let task = scopedAssetTask(scope, await write(client, { ...scope, action: 'create', clientRequestId, request }));
64
+ if (task.clientRequestId !== clientRequestId)
65
+ throw new Error(t('scopeMismatch'));
66
+ // The identity is printed before polling so a disconnected caller can recover without creating a task.
67
+ if (options.wait) {
68
+ process.stderr.write(`${JSON.stringify({ taskId: task.taskId, clientRequestId: task.clientRequestId, status: task.status })}\n`);
69
+ task = await waitForAssetTask(client, scope, task.taskId, Number(options.timeout), Number(options.interval));
70
+ }
71
+ if (options.output && ['awaiting_adoption', 'saved'].includes(task.status))
72
+ return downloadAssetTask(client, scope, task.taskId, options.output);
73
+ return task;
74
+ }));
75
+ shared(assets.command('tasks').description(t('tasks')))
76
+ .action((options) => run('assets tasks', options, ({ client, scope }) => readAssetTasks(client, scope)));
77
+ shared(assets.command('get <task-id>').description(t('get')))
78
+ .action((taskId, options) => run('assets get', options, ({ client, scope }) => readAssetTask(client, scope, identifier(taskId))));
79
+ shared(assets.command('cancel <task-id>').description(t('cancel')))
80
+ .action((taskId, options) => run('assets cancel', options, async ({ client, scope }) => scopedAssetTask(scope, await write(client, { ...scope, action: 'cancel', taskId: identifier(taskId) }))));
81
+ polling(shared(assets.command('wait <task-id>').description(t('wait'))))
82
+ .action((taskId, options) => run('assets wait', options, ({ client, scope }) => waitForAssetTask(client, scope, identifier(taskId), Number(options.timeout), Number(options.interval))));
83
+ shared(assets.command('download <task-id>').description(t('download')))
84
+ .requiredOption('--output <path>', t('output')).option('--version <id>', t('version'))
85
+ .action((taskId, options) => run('assets download', options, ({ client, scope }) => downloadAssetTask(client, scope, identifier(taskId), options.output, options.version ? identifier(options.version) : undefined)));
86
+ shared(assets.command('saved <task-id>').description(t('saved')))
87
+ .requiredOption('--receipt <path>', t('receipt'))
88
+ .action((taskId, options) => run('assets saved', options, async ({ client, scope }) => scopedAssetTask(scope, await write(client, { ...scope, action: 'saved', taskId: identifier(taskId), proof: assetGenerationTaskSavedSchema.parse(await document(options.receipt)) }))));
89
+ shared(assets.command('library-targets').description(t('libraryTargets')))
90
+ .action((options) => run('assets library-targets', options, async ({ client, scope }) => assetLibrarySaveTargetsSchema.parse(await client.get('/workspace-assets', { ...scope, action: 'library-targets' }))));
91
+ shared(assets.command('library-saves <task-id>').description(t('librarySaves')))
92
+ .action((taskId, options) => run('assets library-saves', options, async ({ client, scope }) => assetLibrarySaveListSchema.parse(await client.get('/workspace-assets', { ...scope, action: 'library-saves', taskId: identifier(taskId) }))));
93
+ shared(assets.command('library-save <task-id>').description(t('librarySave')))
94
+ .requiredOption('--request <path>', t('request'))
95
+ .action((taskId, options) => run('assets library-save', options, async ({ client, scope }) => assetLibrarySaveJobSchema.parse(await write(client, { ...scope, action: 'library-save', taskId: identifier(taskId), request: assetLibrarySaveRequestSchema.parse(await document(options.request)) }))));
96
+ shared(assets.command('library-retry <task-id>').description(t('libraryRetry')))
97
+ .requiredOption('--save-id <id>', t('saveId')).option('--start-without-workspace', t('release'))
98
+ .action((taskId, options) => run('assets library-retry', options, async ({ client, scope }) => assetLibrarySaveJobSchema.parse(await write(client, { ...scope, action: 'library-retry', taskId: identifier(taskId), saveId: identifier(options.saveId),
99
+ ...(options.startWithoutWorkspace ? { startWithoutWorkspace: true } : {}) }))));
100
+ const animation = assets.command('animation').description(t('animation'));
101
+ shared(animation.command('get <task-id>').description(t('animationGet')))
102
+ .action((taskId, options) => run('assets animation get', options, async ({ client, scope }) => {
103
+ const result = animationEditorStateSchema.parse(await client.get('/workspace-assets', { ...scope, action: 'animation', taskId: identifier(taskId) }));
104
+ if (result.taskId !== identifier(taskId))
105
+ throw new Error(t('scopeMismatch'));
106
+ return result;
107
+ }));
108
+ for (const [name, action, description, schema, response] of [
109
+ ['draft', 'animation-draft', 'animationDraft', animationEditorDraftUpdateSchema, animationEditorStateSchema],
110
+ ['upload-frame', 'animation-frame', 'animationFrame', animationEditorFrameUploadSchema, animationEditorFrameUploadResultSchema],
111
+ ['version', 'animation-version', 'animationVersion', animationEditorVersionCreateSchema, animationEditorVersionResultSchema],
112
+ ]) {
113
+ shared(animation.command(`${name} <task-id>`).description(t(description))).requiredOption('--request <path>', t('request'))
114
+ .action((taskId, options) => run(`assets animation ${name}`, options, async ({ client, scope }) => {
115
+ const body = workspaceAssetToolWriteSchema.parse({ ...scope, action, taskId: identifier(taskId), request: schema.parse(await document(options.request)) });
116
+ return response.parse(await write(client, body));
117
+ }));
118
+ }
119
+ shared(animation.command('saved <task-id>').description(t('animationSaved')))
120
+ .requiredOption('--version <id>', t('version')).requiredOption('--receipt <path>', t('receipt'))
121
+ .action((taskId, options) => run('assets animation saved', options, async ({ client, scope }) => animationEditorVersionResultSchema.parse(await write(client, { ...scope, action: 'animation-saved', taskId: identifier(taskId), versionId: identifier(options.version),
122
+ proof: assetGenerationTaskSavedSchema.parse(await document(options.receipt)) }))));
123
+ }
@@ -4,6 +4,7 @@ import pc from 'picocolors';
4
4
  import ora from 'ora';
5
5
  import { BaseBuilder, ViteBuilder, PlayableBuilder, EngineDetector, detectAmmoUsage, } from '@playcraft/build';
6
6
  import { loadBuildConfig } from '../build-config.js';
7
+ import { cleanupBuildTempDirectory, createBuildTempDirectory } from './build-temp.js';
7
8
  import inquirer from 'inquirer';
8
9
  /**
9
10
  * 所有可用的渠道平台
@@ -141,6 +142,7 @@ export async function buildAllCommand(projectPath, options) {
141
142
  const spinner = ora(pc.cyan('🚀 批量打渠道包...')).start();
142
143
  let isBaseBuild = false;
143
144
  let baseBuildDir;
145
+ let tempBuildDir;
144
146
  try {
145
147
  // 1. 确定要构建的平台列表
146
148
  let targetPlatforms;
@@ -415,9 +417,9 @@ export async function buildAllCommand(projectPath, options) {
415
417
  }
416
418
  else {
417
419
  spinner.text = pc.cyan('执行阶段1: 基础构建(仅一次)...');
418
- const tempDir = path.join(resolvedProjectPath, '.playcraft-temp', `base-build-${Date.now()}`);
420
+ tempBuildDir = await createBuildTempDirectory(resolvedProjectPath);
419
421
  const baseBuilder = new BaseBuilder(resolvedProjectPath, {
420
- outputDir: tempDir,
422
+ outputDir: tempBuildDir,
421
423
  selectedScenes,
422
424
  analyze: options.analyze,
423
425
  });
@@ -593,6 +595,7 @@ export async function buildAllCommand(projectPath, options) {
593
595
  if (failCount > 0) {
594
596
  process.exit(1);
595
597
  }
598
+ await cleanupBuildTempDirectory(tempBuildDir);
596
599
  }
597
600
  catch (error) {
598
601
  spinner.fail(pc.red('批量构建失败'));
@@ -602,21 +605,4 @@ export async function buildAllCommand(projectPath, options) {
602
605
  }
603
606
  process.exit(1);
604
607
  }
605
- finally {
606
- // 清理临时目录,避免磁盘空间浪费
607
- if (!isBaseBuild && baseBuildDir && baseBuildDir.includes('.playcraft-temp')) {
608
- try {
609
- await fs.rm(baseBuildDir, { recursive: true, force: true });
610
- // 如果 .playcraft-temp 父目录为空,也一并清理
611
- const tempParent = path.dirname(baseBuildDir);
612
- const remaining = await fs.readdir(tempParent);
613
- if (remaining.length === 0) {
614
- await fs.rm(tempParent, { recursive: true, force: true });
615
- }
616
- }
617
- catch {
618
- // 清理失败不影响构建结果
619
- }
620
- }
621
- }
622
608
  }
@@ -0,0 +1,26 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, rm } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ export async function createBuildTempDirectory(projectPath) {
5
+ const parent = path.join(projectPath, '.playcraft-temp');
6
+ await mkdir(parent, { recursive: true });
7
+ const directory = path.join(parent, `base-build-${randomUUID()}`);
8
+ // mkdir 继承工程的共享组和权限掩码;mkdtemp 固定使用 0700。
9
+ await mkdir(directory);
10
+ return directory;
11
+ }
12
+ export async function cleanupBuildTempDirectory(directory) {
13
+ if (!directory)
14
+ return;
15
+ if (process.env.PLAYCRAFT_KEEP_BUILD_TEMP === '1') {
16
+ console.log(`构建临时目录保留在: ${directory}`);
17
+ return;
18
+ }
19
+ try {
20
+ // 只删除本次创建的目录,保留并发构建与用户输入;父目录不做递归清理。
21
+ await rm(directory, { recursive: true, force: true });
22
+ }
23
+ catch (error) {
24
+ console.warn(`清理构建临时目录失败: ${error instanceof Error ? error.message : String(error)}`);
25
+ }
26
+ }
@@ -4,6 +4,7 @@ import pc from 'picocolors';
4
4
  import ora from 'ora';
5
5
  import { BaseBuilder, ViteBuilder, PlayableBuilder, PlayableAnalyzer, EngineDetector, detectAmmoUsage } from '@playcraft/build';
6
6
  import { loadBuildConfig } from '../build-config.js';
7
+ import { cleanupBuildTempDirectory, createBuildTempDirectory } from './build-temp.js';
7
8
  import inquirer from 'inquirer';
8
9
  /**
9
10
  * 类型守卫:检查对象是否符合 PlayableScriptsConfig 类型
@@ -250,6 +251,7 @@ export async function buildCommand(projectPath, options) {
250
251
  const spinner = ora(pc.cyan('🔨 开始打包 Playable Ad...')).start();
251
252
  // 清理选项(默认为 false,使用覆盖模式)
252
253
  const shouldClean = options.clean === true;
254
+ let tempBuildDir;
253
255
  try {
254
256
  // ====== 引擎 + 构建工具检测 ======
255
257
  spinner.text = pc.cyan('检测项目引擎类型...');
@@ -450,6 +452,7 @@ export async function buildCommand(projectPath, options) {
450
452
  const shouldRunPlayableOnly = options.mode === 'playable';
451
453
  // 验证平台
452
454
  const validPlatforms = [
455
+ 'playcraft',
453
456
  'facebook',
454
457
  'snapchat',
455
458
  'ironsource',
@@ -473,6 +476,7 @@ export async function buildCommand(projectPath, options) {
473
476
  // 注:Facebook 在 Phaser(playable-scripts devkit)下的产物格式由其 devkit 输入配置决定(恒为 ZIP),
474
477
  // 平台侧不在此处做引擎判断。
475
478
  const platformFormatConfig = {
479
+ playcraft: { formats: ['html'], default: 'html' },
476
480
  facebook: { formats: ['html', 'zip'], default: 'html' },
477
481
  applovin: { formats: ['html'], default: 'html' },
478
482
  ironsource: { formats: ['html'], default: 'html' },
@@ -584,8 +588,11 @@ export async function buildCommand(projectPath, options) {
584
588
  console.log(pc.dim(' 无主题目录,跳过主题选择'));
585
589
  }
586
590
  }
587
- // 输入商店跳转地址(CTA)- 如果配置文件中没有则必填
588
- if (!options.storeUrls) {
591
+ // 输入商店跳转地址(CTA)- 如果配置文件中没有则必填;通用预览(playcraft)不面向渠道,可不填
592
+ if (selectedPlatform === 'playcraft' && !options.storeUrls) {
593
+ console.log(pc.dim('\nℹ️ 通用预览不需要商店地址'));
594
+ }
595
+ else if (!options.storeUrls) {
589
596
  console.log(pc.cyan('\n🔗 商店跳转地址(CTA 按钮目标)'));
590
597
  console.log(pc.dim(' iOS 和 Android 地址均为必填'));
591
598
  const storeUrlAnswer = await inquirer.prompt([
@@ -636,8 +643,8 @@ export async function buildCommand(projectPath, options) {
636
643
  // 未指定格式,使用默认值
637
644
  options.format = formatConfig.default;
638
645
  }
639
- // 如果命令行未传入 storeUrls,交互式输入(必填)
640
- if (!options.storeUrls) {
646
+ // 如果命令行未传入 storeUrls,交互式输入(必填);通用预览(playcraft)不面向渠道,可不填
647
+ if (!options.storeUrls && options.platform !== 'playcraft') {
641
648
  spinner.stop();
642
649
  console.log(pc.cyan('\n🔗 商店跳转地址(CTA 按钮目标)'));
643
650
  console.log(pc.dim(' iOS 和 Android 地址均为必填'));
@@ -742,7 +749,7 @@ export async function buildCommand(projectPath, options) {
742
749
  // 输入是源代码或官方构建,先执行阶段1
743
750
  spinner.text = pc.cyan('执行阶段1: 基础构建...');
744
751
  // 将临时目录放在项目所在目录下,避免跨盘符路径问题(Windows 上 C:\Temp 和 D:\project 会导致 Vite 路径计算错误)
745
- const tempDir = path.join(resolvedProjectPath, '.playcraft-temp', `base-build-${Date.now()}`);
752
+ tempBuildDir = await createBuildTempDirectory(resolvedProjectPath);
746
753
  // 构建 playableScriptsConfig,合并 CLI 选择的参数
747
754
  const playableScriptsConfig = buildPlayableScriptsConfig(fileConfig?.playableScripts, {
748
755
  platform: options.platform,
@@ -750,7 +757,7 @@ export async function buildCommand(projectPath, options) {
750
757
  selectedThemes,
751
758
  });
752
759
  const baseBuilder = new BaseBuilder(resolvedProjectPath, {
753
- outputDir: tempDir,
760
+ outputDir: tempBuildDir,
754
761
  selectedScenes,
755
762
  analyze: buildOptions.analyze,
756
763
  analyzeReportPath: buildOptions.analyze ? 'base-bundle-report.html' : undefined,
@@ -795,16 +802,7 @@ export async function buildCommand(projectPath, options) {
795
802
  }
796
803
  console.log('\n' + pc.green(`输出目录: ${finalOutputDir}`));
797
804
  console.log(pc.dim('💡 产物已包含渠道适配、MRAID 注入、代码混淆和 fflate 压缩'));
798
- // 清理临时目录
799
- try {
800
- const tempBaseDir = path.join(resolvedProjectPath, '.playcraft-temp');
801
- await fs.rm(tempBaseDir, { recursive: true, force: true });
802
- console.log(pc.dim(`\n🗑️ 已清理临时目录`));
803
- }
804
- catch (error) {
805
- // 记录清理错误信息
806
- console.log(pc.dim(`\n⚠️ 清理临时目录失败: ${error instanceof Error ? error.message : String(error)}`));
807
- }
805
+ await cleanupBuildTempDirectory(tempBuildDir);
808
806
  return;
809
807
  }
810
808
  spinner.text = pc.cyan('✅ 阶段1完成,开始阶段2...');
@@ -976,18 +974,7 @@ export async function buildCommand(projectPath, options) {
976
974
  console.log(pc.yellow(`\n⚠️ 检测到 Ammo.js,建议替换为 ${analysis.suggestedEngine}`));
977
975
  }
978
976
  }
979
- // 清理临时目录(调试时注释掉)
980
- if (!isBaseBuild && baseBuildDir.includes('.playcraft-temp')) {
981
- // 调试:暂时保留临时目录
982
- console.log(pc.yellow(`[DEBUG] 临时目录保留在: ${baseBuildDir}`));
983
- // try {
984
- // // 清理整个 .playcraft-temp 目录
985
- // const tempBaseDir = path.join(resolvedProjectPath, '.playcraft-temp');
986
- // await fs.rm(tempBaseDir, { recursive: true, force: true });
987
- // } catch (error) {
988
- // // 忽略清理错误
989
- // }
990
- }
977
+ await cleanupBuildTempDirectory(tempBuildDir);
991
978
  }
992
979
  catch (error) {
993
980
  spinner.fail(pc.red('打包失败'));
@@ -1,3 +1,4 @@
1
+ import { prepareLocalSkillLifecycle } from '../project-skills/lifecycle.js';
1
2
  import { execFileSync, execSync } from 'child_process';
2
3
  import inquirer from 'inquirer';
3
4
  import fs from 'fs/promises';
@@ -6,8 +7,11 @@ import { fileURLToPath } from 'url';
6
7
  import pc from 'picocolors';
7
8
  import ora from 'ora';
8
9
  import { resolveCreateTemplate, resolveCreateTemplateDir, } from '../scaffold/templates.js';
10
+ import { PLATFORM_SKILL_DIRS } from './platform-skills.generated.js';
9
11
  const __filename = fileURLToPath(import.meta.url);
10
12
  const __dirname = path.dirname(__filename);
13
+ /** `@playcraft/skills` 包内 Platform Skill 的目录名(与 Atom Skill 的 `skills/` 区分)。 */
14
+ const PLATFORM_SKILLS_DIRNAME = 'playcraft-skills';
11
15
  /** 生成一个本地占位 Project ID(99xxxxxx),后续可通过 playcraft config set 更新为真实 ID */
12
16
  function generateMockProjectId() {
13
17
  const suffix = Math.floor(Math.random() * 90_000_000) + 10_000_000;
@@ -849,7 +853,7 @@ function extractSkillBodyForCursor(content) {
849
853
  * @param cliCommandsDir CLI 命令所在目录(用于解析 skills 包位置)
850
854
  * @param configDir 配置目录名(如 '.claude' 或 '.codebuddy')
851
855
  */
852
- async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir) {
856
+ export async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir) {
853
857
  const skillsLinkDir = path.join(targetDir, configDir, 'skills');
854
858
  await fs.mkdir(skillsLinkDir, { recursive: true });
855
859
  // 以下 Skill 在项目模板中以静态目录形式存在,不创建软连接覆盖它们。
@@ -868,11 +872,12 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
868
872
  'playcraft-image-generation',
869
873
  'playcraft-audio-generation',
870
874
  ]);
871
- // 尝试从 CLI 安装包的位置定位 @playcraft/skills/skills 目录
875
+ // Platform Skill 住在 playcraft-skills/,与 Atom Skill 的 skills/ 是两个目录。
876
+ // 尝试从 CLI 安装包的位置定位它(monorepo 内或与 CLI 平级安装时可解析)。
872
877
  const candidateDirs = [
873
- path.resolve(cliCommandsDir, '..', '..', '..', '..', 'skills', 'skills'),
874
- path.resolve(cliCommandsDir, '..', '..', '..', 'skills', 'skills'),
875
- path.resolve(cliCommandsDir, '..', '..', 'skills', 'skills'),
878
+ path.resolve(cliCommandsDir, '..', '..', '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
879
+ path.resolve(cliCommandsDir, '..', '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
880
+ path.resolve(cliCommandsDir, '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
876
881
  ];
877
882
  let resolvedSkillsDir = null;
878
883
  for (const dir of candidateDirs) {
@@ -885,18 +890,24 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
885
890
  // 继续下一个候选
886
891
  }
887
892
  }
888
- // 相对路径(指向 npm install 后的 node_modules)始终创建,作为安装后激活的备用
889
- const relativeSkillsBase = path.join('..', '..', 'node_modules', '@playcraft', 'skills', 'skills');
893
+ // 相对路径(指向 npm install 后的 node_modules)作为安装后激活的备用
894
+ const relativeSkillsBase = path.join('..', '..', 'node_modules', '@playcraft', 'skills', PLATFORM_SKILLS_DIRNAME);
890
895
  if (resolvedSkillsDir) {
891
- // 能立即解析 → 创建指向绝对路径的软连接,当下即可使用
896
+ // 能立即解析 → 以真实目录为准创建绝对路径软连接,当下即可使用。
897
+ // 按「是否含 SKILL.md」判定而非 playcraft- 前缀:sound-effects 无前缀但同样是平台技能。
892
898
  const entries = await fs.readdir(resolvedSkillsDir, { withFileTypes: true });
893
899
  for (const entry of entries) {
894
- if (!entry.name.startsWith('playcraft-') || staticSkills.has(entry.name))
900
+ if (!entry.isDirectory() || staticSkills.has(entry.name))
895
901
  continue;
896
- const linkPath = path.join(skillsLinkDir, entry.name);
897
902
  const targetPath = path.join(resolvedSkillsDir, entry.name);
898
903
  try {
899
- await fs.symlink(targetPath, linkPath, 'dir');
904
+ await fs.access(path.join(targetPath, 'SKILL.md'));
905
+ }
906
+ catch {
907
+ continue;
908
+ }
909
+ try {
910
+ await fs.symlink(targetPath, path.join(skillsLinkDir, entry.name), 'dir');
900
911
  }
901
912
  catch {
902
913
  // 已存在则跳过
@@ -904,28 +915,9 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
904
915
  }
905
916
  }
906
917
  else {
907
- // 无法立即解析 → 创建指向 node_modules 的相对路径软连接,npm install 后自动激活
908
- const knownPlatformTools = [
909
- 'playcraft-asset-management',
910
- 'playcraft-audio-generation',
911
- 'playcraft-build',
912
- 'playcraft-code-editor',
913
- 'playcraft-create-remix',
914
- 'playcraft-deploy',
915
- 'playcraft-image-generation',
916
- 'playcraft-image-processing',
917
- 'playcraft-platform-intro',
918
- 'playcraft-prefab',
919
- 'playcraft-project-management',
920
- 'playcraft-remix-workflow',
921
- 'playcraft-save',
922
- 'playcraft-skill-recommender',
923
- 'playcraft-sprite-generation',
924
- 'playcraft-sprite-remix',
925
- 'playcraft-sprite-sheet',
926
- 'playcraft-3d-flip-sprite',
927
- ];
928
- for (const name of knownPlatformTools) {
918
+ // 无法立即解析 → 指向 node_modules 的相对路径软连接,npm install 后自动激活。
919
+ // 清单由 scripts/generate-platform-skills.mjs 从真实目录生成并由 CI 校验,不要手写。
920
+ for (const name of PLATFORM_SKILL_DIRS) {
929
921
  if (staticSkills.has(name))
930
922
  continue;
931
923
  const linkPath = path.join(skillsLinkDir, name);
@@ -1289,6 +1281,7 @@ export async function createCommand(projectName, options) {
1289
1281
  smokeSpinner.warn(`Harness 自检跳过: ${message}`);
1290
1282
  }
1291
1283
  }
1284
+ await prepareLocalSkillLifecycle(targetDir, 'create');
1292
1285
  const gitSpinner = ora(isWorktreeMode ? '提交项目分支...' : '初始化 Git 仓库...').start();
1293
1286
  try {
1294
1287
  if (isWorktreeMode) {