@playcraft/cli 0.1.49-beta → 0.1.51

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 (395) hide show
  1. package/README.md +3 -62
  2. package/dist/agent/local-backend.js +1 -1
  3. package/dist/cli-root-help.js +0 -2
  4. package/dist/commands/build-all.js +19 -5
  5. package/dist/commands/build.js +28 -15
  6. package/dist/commands/create.js +33 -26
  7. package/dist/commands/image.js +6 -2
  8. package/dist/commands/login.js +42 -84
  9. package/dist/commands/skills.js +0 -4
  10. package/dist/commands/tools-3d.js +0 -11
  11. package/dist/commands/tools-generation.js +137 -69
  12. package/dist/commands/tools-image-context.js +29 -0
  13. package/dist/commands/tools-utils.js +12 -0
  14. package/dist/commands/tools.js +2 -2
  15. package/dist/config.js +4 -59
  16. package/dist/index.js +3 -40
  17. package/dist/remix/clone.js +0 -2
  18. package/dist/remix/init-template.js +0 -2
  19. package/dist/remix/pull.js +0 -2
  20. package/dist/remix/push.js +1 -21
  21. package/dist/utils/agent-api-client.js +30 -210
  22. package/dist/utils/image-asset-context.js +228 -0
  23. package/dist/utils/playcraft-http-client.js +4 -6
  24. package/package.json +5 -15
  25. package/project-template/.claude/agents/refs/ta-image-generation-detail.md +67 -123
  26. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  27. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  28. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  29. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  30. package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  31. package/project-templates/phaser/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  32. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  33. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  34. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  35. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  36. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  37. package/project-templates/threejs/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  38. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  39. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  40. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  41. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  42. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  43. package/SKILLS_REGISTRY.md +0 -149
  44. package/dist/auth/account-activation.js +0 -157
  45. package/dist/auth/messages.js +0 -30
  46. package/dist/commands/build-temp.js +0 -26
  47. package/dist/commands/platform-skills.generated.js +0 -19
  48. package/dist/commands/playable.js +0 -53
  49. package/dist/commands/tools-batch.js +0 -113
  50. package/dist/commands/video.js +0 -122
  51. package/dist/commands/workspace-runtime.js +0 -54
  52. package/dist/commands/workspace.js +0 -40
  53. package/dist/project-skills/builtin-import.js +0 -225
  54. package/dist/project-skills/commands.js +0 -77
  55. package/dist/project-skills/lifecycle.js +0 -28
  56. package/dist/project-skills/local-run.js +0 -112
  57. package/dist/project-skills/local-store.js +0 -221
  58. package/dist/project-skills/messages.js +0 -80
  59. package/dist/project-skills/reconcile.js +0 -62
  60. package/dist/project-skills/remote-cache.js +0 -51
  61. package/dist/project-skills/validation.js +0 -19
  62. package/dist/recording/messages.js +0 -40
  63. package/dist/recording/project-digest.js +0 -85
  64. package/dist/recording/recorder.js +0 -293
  65. package/dist/recording/scenario.js +0 -50
  66. package/dist/skill-registry/client.js +0 -345
  67. package/dist/skill-registry/commands.js +0 -180
  68. package/dist/skill-registry/evaluation-client.js +0 -156
  69. package/dist/skill-registry/evaluation-commands.js +0 -174
  70. package/dist/skill-registry/messages.js +0 -177
  71. package/dist/skill-registry/package.js +0 -275
  72. package/dist/skill-registry/platform-package.js +0 -100
  73. package/dist/utils/environment-endpoints.js +0 -17
  74. package/dist/utils/error-diagnostics.js +0 -20
  75. package/dist/utils/tool-operation-journal.js +0 -124
  76. package/dist/utils/video-evidence-git.js +0 -81
  77. package/dist/video-replication/client.js +0 -234
  78. package/dist/video-replication/comparison-evidence.js +0 -149
  79. package/dist/video-replication/comparison-files.js +0 -57
  80. package/dist/video-replication/comparison-log.js +0 -72
  81. package/dist/video-replication/comparison-messages.js +0 -104
  82. package/dist/video-replication/comparison-output.js +0 -63
  83. package/dist/video-replication/comparison-preflight.js +0 -66
  84. package/dist/video-replication/comparison.js +0 -230
  85. package/dist/video-replication/diagnostics.js +0 -41
  86. package/dist/video-replication/evidence.js +0 -165
  87. package/dist/video-replication/media.js +0 -112
  88. package/dist/video-replication/messages.js +0 -97
  89. package/dist/workspace/messages.js +0 -67
  90. package/dist/workspace/transfer-client.js +0 -233
  91. package/dist/workspace/transfer-errors.js +0 -48
  92. package/dist/workspace-runtime/batch/content-changes.js +0 -30
  93. package/dist/workspace-runtime/batch/control.js +0 -86
  94. package/dist/workspace-runtime/batch/deliver.js +0 -173
  95. package/dist/workspace-runtime/batch/freeze.js +0 -101
  96. package/dist/workspace-runtime/batch/generate.js +0 -249
  97. package/dist/workspace-runtime/batch/git.js +0 -40
  98. package/dist/workspace-runtime/batch/occupancy.js +0 -8
  99. package/dist/workspace-runtime/batch/policy.js +0 -70
  100. package/dist/workspace-runtime/batch/prepare.js +0 -317
  101. package/dist/workspace-runtime/batch/processes.js +0 -72
  102. package/dist/workspace-runtime/batch/records.js +0 -113
  103. package/dist/workspace-runtime/batch/routes.js +0 -61
  104. package/dist/workspace-runtime/batch/source-candidate.js +0 -86
  105. package/dist/workspace-runtime/batch/source-capture.js +0 -146
  106. package/dist/workspace-runtime/batch/source-failure.js +0 -43
  107. package/dist/workspace-runtime/batch/source-publish.js +0 -130
  108. package/dist/workspace-runtime/codex/app-server.js +0 -1065
  109. package/dist/workspace-runtime/codex/compact.js +0 -46
  110. package/dist/workspace-runtime/codex/config-toml.js +0 -107
  111. package/dist/workspace-runtime/codex/delivery-tools.js +0 -144
  112. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
  113. package/dist/workspace-runtime/codex/launcher-client.js +0 -177
  114. package/dist/workspace-runtime/codex/loopback.js +0 -146
  115. package/dist/workspace-runtime/codex/mcp-config.js +0 -39
  116. package/dist/workspace-runtime/codex/model-broker.js +0 -263
  117. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  118. package/dist/workspace-runtime/codex/permissions.js +0 -79
  119. package/dist/workspace-runtime/codex/thread-image.js +0 -38
  120. package/dist/workspace-runtime/codex/tool-response.js +0 -10
  121. package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
  122. package/dist/workspace-runtime/codex/ui-tools.js +0 -203
  123. package/dist/workspace-runtime/codex/work-mode.js +0 -15
  124. package/dist/workspace-runtime/main.js +0 -10
  125. package/dist/workspace-runtime/persistence/journal.js +0 -365
  126. package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
  127. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
  128. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1161
  129. package/dist/workspace-runtime/persistence/stopped-execution.js +0 -77
  130. package/dist/workspace-runtime/previews/diagnostics.js +0 -44
  131. package/dist/workspace-runtime/previews/output.js +0 -36
  132. package/dist/workspace-runtime/previews/publish.js +0 -274
  133. package/dist/workspace-runtime/previews/single-file.js +0 -43
  134. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  135. package/dist/workspace-runtime/serve.js +0 -343
  136. package/dist/workspace-runtime/server/accept-operation.js +0 -61
  137. package/dist/workspace-runtime/server/auth.js +0 -21
  138. package/dist/workspace-runtime/server/connectivity.js +0 -209
  139. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  140. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  141. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  142. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  143. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  144. package/dist/workspace-runtime/server/dispatch.js +0 -1393
  145. package/dist/workspace-runtime/server/endpoints.js +0 -21
  146. package/dist/workspace-runtime/server/execution-group.js +0 -90
  147. package/dist/workspace-runtime/server/http.js +0 -1316
  148. package/dist/workspace-runtime/server/lock.js +0 -53
  149. package/dist/workspace-runtime/server/operation-record.js +0 -33
  150. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  151. package/dist/workspace-runtime/server/session-restore.js +0 -84
  152. package/dist/workspace-runtime/server/source-uploader.js +0 -138
  153. package/dist/workspace-runtime/server/submit-operation.js +0 -41
  154. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  155. package/dist/workspace-runtime/server/types.js +0 -1
  156. package/dist/workspace-runtime/server/workspace-transfer.js +0 -168
  157. package/dist/workspace-runtime/verify-artifact.js +0 -59
  158. package/dist/workspace-runtime/workspaces/append-only-log.js +0 -62
  159. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  160. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  161. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -199
  162. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  163. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  164. package/dist/workspace-runtime/workspaces/asset-library-import.js +0 -366
  165. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -73
  166. package/dist/workspace-runtime/workspaces/attachments.js +0 -185
  167. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  168. package/dist/workspace-runtime/workspaces/binary-content.js +0 -65
  169. package/dist/workspace-runtime/workspaces/binary-write.js +0 -112
  170. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  171. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -115
  172. package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
  173. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  174. package/dist/workspace-runtime/workspaces/delivery-build.js +0 -331
  175. package/dist/workspace-runtime/workspaces/delivery-store.js +0 -168
  176. package/dist/workspace-runtime/workspaces/delivery.js +0 -64
  177. package/dist/workspace-runtime/workspaces/dependencies.js +0 -279
  178. package/dist/workspace-runtime/workspaces/developer-command.js +0 -98
  179. package/dist/workspace-runtime/workspaces/directories.js +0 -132
  180. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  181. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  182. package/dist/workspace-runtime/workspaces/directory-create.js +0 -57
  183. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  184. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  185. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  186. package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
  187. package/dist/workspace-runtime/workspaces/file-content.js +0 -48
  188. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  189. package/dist/workspace-runtime/workspaces/files.js +0 -150
  190. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  191. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  192. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  193. package/dist/workspace-runtime/workspaces/git.js +0 -670
  194. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  195. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -170
  196. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  197. package/dist/workspace-runtime/workspaces/operation-log.js +0 -23
  198. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
  199. package/dist/workspace-runtime/workspaces/parameters.js +0 -272
  200. package/dist/workspace-runtime/workspaces/prepare.js +0 -278
  201. package/dist/workspace-runtime/workspaces/registry.js +0 -251
  202. package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
  203. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  204. package/dist/workspace-runtime/workspaces/session-image.js +0 -104
  205. package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
  206. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
  207. package/dist/workspace-runtime/workspaces/skills.js +0 -191
  208. package/dist/workspace-runtime/workspaces/transfer-quota.js +0 -69
  209. package/dist/workspace-runtime/workspaces/transfer.js +0 -471
  210. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
  211. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  212. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  213. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  214. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  215. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  216. package/project-template-v2/.claude/agents/artist.md +0 -82
  217. package/project-template-v2/.claude/agents/developer.md +0 -153
  218. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  219. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  220. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  221. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  222. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  223. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  224. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  225. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  226. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  227. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  228. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  229. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  230. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  231. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  232. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  233. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  234. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  235. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  236. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  237. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  238. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  239. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  240. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  241. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  242. package/project-template-v2/.claude/settings.json +0 -33
  243. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  244. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  245. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  246. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  247. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  248. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  249. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  250. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  251. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  252. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  253. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  254. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  255. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  256. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  257. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  258. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  259. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  260. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  261. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  262. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  263. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  264. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  265. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  266. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  267. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  268. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  269. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  270. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  271. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  272. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  273. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  274. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  275. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  276. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  277. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  278. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  279. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  280. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  281. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  282. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  283. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  284. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  285. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  286. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  287. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  288. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  289. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  290. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  291. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  292. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  293. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  294. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  295. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  296. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  297. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  298. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  299. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  300. package/project-template-v2/.claude/snapshot.mjs +0 -263
  301. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  302. package/project-template-v2/CLAUDE.md +0 -146
  303. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  304. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  305. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  306. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  307. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  308. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  309. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  310. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  311. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  312. package/project-template-v2/assets/models/.gitkeep +0 -0
  313. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  314. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  315. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  316. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  317. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  318. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  319. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  320. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  321. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  322. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  323. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  324. package/project-template-v2/docs/project-state.json +0 -60
  325. package/project-template-v2/docs/project-state.md +0 -72
  326. package/project-template-v2/docs/standards/README.md +0 -225
  327. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  328. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  329. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  330. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  331. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  332. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  333. package/project-template-v2/game/index.ts +0 -18
  334. package/project-template-v2/globals.d.ts +0 -51
  335. package/project-template-v2/index.css +0 -34
  336. package/project-template-v2/index.html +0 -18
  337. package/project-template-v2/main.ts +0 -9
  338. package/project-template-v2/package.json +0 -46
  339. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  340. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  341. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  342. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  343. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  344. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  345. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  346. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  347. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  348. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  349. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  350. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  351. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  352. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  353. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  354. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  355. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  356. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  357. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  358. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  359. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  360. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  361. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  362. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  363. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  364. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  365. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  366. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  367. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  368. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  369. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  370. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  371. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  372. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  373. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  374. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  375. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  376. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  377. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  378. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  379. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  380. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  381. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  382. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  383. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  384. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  385. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  386. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  387. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  388. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  389. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  390. package/project-template-v2/tsconfig.json +0 -20
  391. package/project-template-v2/vite.config.ts +0 -27
  392. package/project-templates/batch-locks/phaser.yaml +0 -922
  393. package/project-templates/batch-locks/threejs.yaml +0 -978
  394. package/project-templates/empty/AGENTS.md +0 -41
  395. package/project-templates/empty/gitignore +0 -33
@@ -1,8 +1,7 @@
1
1
  import http from 'http';
2
- import { execFile } from 'child_process';
2
+ import { exec } from 'child_process';
3
3
  import crypto from 'crypto';
4
- import { loadGlobalConfig, normalizeEnvironmentBaseUrl, readEnvironmentProfile, saveEnvironmentProfile } from '../config.js';
5
- import { activateAccount } from '../auth/account-activation.js';
4
+ import { saveGlobalConfig, loadGlobalConfig } from '../config.js';
6
5
  /** 默认云端 Portal(Next.js `/cli-auth` 与 API 同源时的基址;可通过 --url 或 PLAYCRAFT_URL 覆盖) */
7
6
  export const DEFAULT_PLAYCRAFT_CLOUD_BASE = 'https://playcraft.aix.intlgame.com';
8
7
  const CALLBACK_PORT = 3456;
@@ -19,11 +18,10 @@ function openBrowser(url) {
19
18
  const cmd = process.platform === 'darwin'
20
19
  ? 'open'
21
20
  : process.platform === 'win32'
22
- ? 'rundll32'
21
+ ? 'start'
23
22
  : 'xdg-open';
24
23
  try {
25
- const arguments_ = process.platform === 'win32' ? ['url.dll,FileProtocolHandler', url] : [url];
26
- execFile(cmd, arguments_, (err, _stdout, stderr) => {
24
+ exec(`${cmd} "${url}"`, (err, _stdout, stderr) => {
27
25
  if (err) {
28
26
  console.error('Failed to open browser automatically:', err.message);
29
27
  if (stderr?.trim()) {
@@ -46,18 +44,21 @@ function resolveLoginBaseUrl(options) {
46
44
  globalConfig.url ||
47
45
  globalConfig.backendUrl ||
48
46
  DEFAULT_PLAYCRAFT_CLOUD_BASE;
49
- const base = normalizeEnvironmentBaseUrl(raw);
50
- if (!base)
51
- throw new Error('Invalid environment address');
52
- return base;
47
+ return raw.replace(/\/+$/, '');
53
48
  }
54
49
  function normalizeLoginEnvironmentUrl(raw) {
55
- return normalizeEnvironmentBaseUrl(raw);
50
+ try {
51
+ const url = new URL(raw);
52
+ url.hash = '';
53
+ url.search = '';
54
+ url.pathname = url.pathname.replace(/\/+$/, '');
55
+ return url.toString().replace(/\/+$/, '');
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
56
60
  }
57
61
  export function resolveExistingTokenForLoginTarget(globalConfig, backendUrl) {
58
- const profile = readEnvironmentProfile(globalConfig, backendUrl);
59
- if (profile)
60
- return profile.token;
61
62
  const token = typeof globalConfig.token === 'string' ? globalConfig.token : undefined;
62
63
  const storedBackendUrl = typeof globalConfig.backendUrl === 'string'
63
64
  ? globalConfig.backendUrl
@@ -73,17 +74,9 @@ export function resolveExistingTokenForLoginTarget(globalConfig, backendUrl) {
73
74
  : undefined;
74
75
  }
75
76
  export function buildCliAuthUrl(options) {
76
- const base = normalizeEnvironmentBaseUrl(options.backendUrl);
77
- if (!base)
78
- throw new Error('Invalid environment address');
79
- const url = new URL(`${base}/cli-auth`);
80
- url.searchParams.set('callbackUrl', options.callbackUrl);
77
+ const url = new URL('/cli-auth', options.backendUrl);
81
78
  url.searchParams.set('callback', options.callbackUrl);
82
79
  url.searchParams.set('state', options.state);
83
- if (options.codeChallenge) {
84
- url.searchParams.set('codeChallenge', options.codeChallenge);
85
- url.searchParams.set('codeChallengeMethod', 'S256');
86
- }
87
80
  return url.toString();
88
81
  }
89
82
  export async function renewExistingToken(options) {
@@ -94,20 +87,12 @@ export async function renewExistingToken(options) {
94
87
  try {
95
88
  const res = await fetchFn(`${options.backendUrl}/api/settings/personal-access-tokens/current/renew`, {
96
89
  method: 'PATCH',
97
- redirect: 'error',
98
- signal: AbortSignal.timeout(10_000),
99
90
  headers: {
100
91
  Authorization: `Bearer ${options.token}`,
101
92
  'Content-Type': 'application/json',
102
93
  },
103
94
  body: JSON.stringify({ expiresIn: '365d' }),
104
95
  });
105
- if (res.ok && res.json && options.onRenewed) {
106
- const result = await res.json();
107
- if (typeof result.expiresAt === 'string' && Date.parse(result.expiresAt) > Date.now()) {
108
- options.onRenewed(result.expiresAt);
109
- }
110
- }
111
96
  return res.ok;
112
97
  }
113
98
  catch {
@@ -115,43 +100,29 @@ export async function renewExistingToken(options) {
115
100
  }
116
101
  }
117
102
  export async function loginCommand(options) {
118
- if (options.activate) {
119
- await activateAccount(options, DEFAULT_PLAYCRAFT_CLOUD_BASE);
120
- return;
121
- }
122
103
  const backendUrl = resolveLoginBaseUrl(options);
123
104
  const callbackPort = options.callbackPort ?? CALLBACK_PORT;
124
105
  const globalConfig = loadGlobalConfig();
125
106
  const existingToken = resolveExistingTokenForLoginTarget(globalConfig, backendUrl);
126
107
  if (existingToken) {
127
- let expiresAt;
128
- const renewed = await renewExistingToken({ backendUrl, token: existingToken,
129
- onRenewed: (value) => { expiresAt = value; } });
108
+ const renewed = await renewExistingToken({ backendUrl, token: existingToken });
130
109
  if (renewed) {
131
- const previous = readEnvironmentProfile(globalConfig, backendUrl);
132
- saveEnvironmentProfile(backendUrl, { token: existingToken,
133
- ...(previous?.identity ? { identity: previous.identity } : {}),
134
- ...(expiresAt ? { expiresAt } : {}) });
110
+ saveGlobalConfig({
111
+ token: existingToken,
112
+ url: backendUrl,
113
+ backendUrl,
114
+ });
135
115
  console.log('Existing CLI token renewed. Token saved to ~/.playcraft/config.json');
136
116
  return;
137
117
  }
138
118
  }
139
119
  const state = crypto.randomBytes(16).toString('hex');
140
- const codeVerifier = crypto.randomBytes(32).toString('base64url');
141
- const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
142
- let callbackUrl = '';
143
- let exchanging = false;
144
120
  return new Promise((resolve, reject) => {
145
121
  let timeout;
146
122
  const server = http.createServer((req, res) => {
147
- res.setHeader('Access-Control-Allow-Origin', new URL(backendUrl).origin);
123
+ res.setHeader('Access-Control-Allow-Origin', '*');
148
124
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
149
125
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
150
- if (req.headers.origin && req.headers.origin !== new URL(backendUrl).origin) {
151
- res.writeHead(403);
152
- res.end();
153
- return;
154
- }
155
126
  if (req.method === 'OPTIONS') {
156
127
  res.writeHead(204);
157
128
  res.end();
@@ -159,9 +130,8 @@ export async function loginCommand(options) {
159
130
  }
160
131
  if (req.url === '/callback' && req.method === 'POST') {
161
132
  let body = '';
162
- req.on('data', (chunk) => { body += chunk; if (body.length > 16_384)
163
- req.destroy(); });
164
- req.on('end', async () => {
133
+ req.on('data', (chunk) => (body += chunk));
134
+ req.on('end', () => {
165
135
  try {
166
136
  const data = JSON.parse(body);
167
137
  if (data.state !== state) {
@@ -169,36 +139,22 @@ export async function loginCommand(options) {
169
139
  'Content-Type': 'text/html',
170
140
  Connection: 'close',
171
141
  });
172
- res.end('<html><body><h1>Invalid state</h1></body></html>');
173
- return;
174
- }
175
- if (exchanging) {
176
- res.writeHead(409);
177
- res.end();
142
+ res.end('<html><body><h1>Invalid state</h1></body></html>', () => {
143
+ closeServer(() => {
144
+ reject(new Error('State mismatch - possible CSRF attack'));
145
+ });
146
+ });
178
147
  return;
179
148
  }
180
- if (typeof data.code !== 'string' || !/^[A-Za-z0-9_-]{43}$/.test(data.code)) {
181
- throw new Error('Login callback did not include an authorization code');
149
+ const callbackToken = typeof data.token === 'string' ? data.token : undefined;
150
+ if (!callbackToken) {
151
+ throw new Error('Login callback did not include a token');
182
152
  }
183
- exchanging = true;
184
- const base = normalizeEnvironmentBaseUrl(backendUrl);
185
- if (!base)
186
- throw new Error('Invalid environment address');
187
- const exchange = await fetch(`${base}/api/cloud-environments/exchange`, {
188
- method: 'POST', redirect: 'error', signal: AbortSignal.timeout(10_000),
189
- headers: { 'Content-Type': 'application/json' },
190
- body: JSON.stringify({ code: data.code, state, callbackUrl, codeVerifier }),
153
+ saveGlobalConfig({
154
+ token: callbackToken,
155
+ url: backendUrl,
156
+ backendUrl,
191
157
  });
192
- if (!exchange.ok)
193
- throw new Error('Authorization code exchange failed');
194
- const credential = await exchange.json();
195
- if (!credential.token || !/^playcraft_pat_[A-Za-z0-9_-]{32}$/.test(credential.token)
196
- || !credential.identity?.userId || !Array.isArray(credential.identity.identities)
197
- || !credential.expiresAt || Date.parse(credential.expiresAt) <= Date.now()) {
198
- throw new Error('Invalid environment credential response');
199
- }
200
- saveEnvironmentProfile(base, { token: credential.token,
201
- identity: credential.identity, expiresAt: credential.expiresAt });
202
158
  res.writeHead(200, {
203
159
  'Content-Type': 'text/html',
204
160
  Connection: 'close',
@@ -218,6 +174,9 @@ export async function loginCommand(options) {
218
174
  catch (err) {
219
175
  const cause = err instanceof Error ? err : new Error(String(err));
220
176
  console.error('[playcraft login] Callback handling failed:', cause.message);
177
+ if (cause.stack) {
178
+ console.error(cause.stack);
179
+ }
221
180
  const userFacing = cause instanceof SyntaxError
222
181
  ? 'Invalid JSON in login callback.'
223
182
  : `Login callback failed: ${cause.message}`;
@@ -262,15 +221,14 @@ export async function loginCommand(options) {
262
221
  });
263
222
  });
264
223
  try {
265
- server.listen(callbackPort, '127.0.0.1', () => {
224
+ server.listen(callbackPort, () => {
266
225
  const address = server.address();
267
226
  const listeningPort = typeof address === 'object' && address ? address.port : callbackPort;
268
- callbackUrl = `http://127.0.0.1:${listeningPort}/callback`;
227
+ const callbackUrl = `http://localhost:${listeningPort}/callback`;
269
228
  const authUrl = buildCliAuthUrl({
270
229
  backendUrl,
271
230
  callbackUrl,
272
231
  state,
273
- codeChallenge,
274
232
  });
275
233
  console.log('Opening browser for login...');
276
234
  console.log(`If the browser does not open, visit this URL manually:\n ${authUrl}\n`);
@@ -18,8 +18,6 @@
18
18
  * 3. <cwd>/node_modules/@playcraft/skills/playcraft-skills(兼容旧路径 skills)
19
19
  * 4. <CLI 自身>/../../skills/playcraft-skills(monorepo 开发时,兼容旧路径 skills)
20
20
  */
21
- import { registerProjectSkillsCommands } from '../project-skills/commands.js';
22
- import { registerRegistryCommands } from '../skill-registry/commands.js';
23
21
  import * as fs from 'node:fs';
24
22
  import * as path from 'node:path';
25
23
  import { getFusionHintsForGameplayAtoms, } from '../atom-tree/fusion-hints.js';
@@ -1432,8 +1430,6 @@ export function registerSkillsCommands(program) {
1432
1430
  const skills = program
1433
1431
  .command('skills')
1434
1432
  .description('开发时 Skill 发现与脚手架工具(按 engine/intent 推荐 skill 集合,或将 ref 文件复制到项目)');
1435
- registerProjectSkillsCommands(skills);
1436
- registerRegistryCommands(skills);
1437
1433
  // 公共选项:skills 目录
1438
1434
  const addSkillsDirOption = (cmd) => cmd.option('--skills-dir <path>', '指定 skills 目录路径(默认自动发现)');
1439
1435
  // ── list ──────────────────────────────────────────────────────────────────
@@ -2,7 +2,6 @@ import { writeFileSync, mkdirSync, readFileSync } from 'fs';
2
2
  import { dirname } from 'path';
3
3
  import { AgentApiClient } from '../utils/agent-api-client.js';
4
4
  import { mimeTypeForImagePath, handleError } from './tools-utils.js';
5
- import { captureGeneratedArtifact } from '../workspace-runtime/workspaces/artifact-receipts.js';
6
5
  const AVATAR_TEMPLATES = [
7
6
  'basketball', 'badminton', 'pingpong', 'gymnastics', 'pilidance',
8
7
  'tennis', 'athletics', 'footballboykicking1', 'footballboykicking2',
@@ -149,9 +148,6 @@ export function register3DCommands(tools) {
149
148
  writeFileSync(opts.savePreview, previewBuf);
150
149
  console.log(` Preview saved: ${opts.savePreview}`);
151
150
  }
152
- await captureGeneratedArtifact(opts.output, 'generate-3d', {
153
- ...(opts.savePreview && result.previewImageBase64 ? { thumbnailPath: opts.savePreview } : {}),
154
- });
155
151
  console.log(`\nNext steps:`);
156
152
  console.log(` Inspect: playcraft 3d info ${opts.output}`);
157
153
  console.log(` Apply texture: playcraft tools generate-texture --model-url <url> --reference-image <img> --output out.glb`);
@@ -213,7 +209,6 @@ export function register3DCommands(tools) {
213
209
  const outDir = dirname(opts.output);
214
210
  mkdirSync(outDir, { recursive: true });
215
211
  writeFileSync(opts.output, buf);
216
- await captureGeneratedArtifact(opts.output, 'generate-texture');
217
212
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
218
213
  console.log(`\nTextured model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
219
214
  if (result.resultUrl)
@@ -258,7 +253,6 @@ export function register3DCommands(tools) {
258
253
  const outDir = dirname(opts.output);
259
254
  mkdirSync(outDir, { recursive: true });
260
255
  writeFileSync(opts.output, buf);
261
- await captureGeneratedArtifact(opts.output, 'retopology');
262
256
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
263
257
  console.log(`\nRetopologized model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
264
258
  }
@@ -295,7 +289,6 @@ export function register3DCommands(tools) {
295
289
  const outDir = dirname(opts.output);
296
290
  mkdirSync(outDir, { recursive: true });
297
291
  writeFileSync(opts.output, buf);
298
- await captureGeneratedArtifact(opts.output, 'uv-unwrap');
299
292
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
300
293
  console.log(`\nUV-unwrapped model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
301
294
  }
@@ -331,7 +324,6 @@ export function register3DCommands(tools) {
331
324
  const outDir = dirname(opts.output);
332
325
  mkdirSync(outDir, { recursive: true });
333
326
  writeFileSync(opts.output, buf);
334
- await captureGeneratedArtifact(opts.output, 'convert-3d');
335
327
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
336
328
  console.log(`\nConverted model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
337
329
  console.log(` Format: ${result.format.toUpperCase()}`);
@@ -367,7 +359,6 @@ export function register3DCommands(tools) {
367
359
  const outDir = dirname(opts.output);
368
360
  mkdirSync(outDir, { recursive: true });
369
361
  writeFileSync(opts.output, buf);
370
- await captureGeneratedArtifact(opts.output, 'generate-3d-parts');
371
362
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
372
363
  console.log(`\n3D parts model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
373
364
  }
@@ -411,7 +402,6 @@ export function register3DCommands(tools) {
411
402
  const outDir = dirname(opts.output);
412
403
  mkdirSync(outDir, { recursive: true });
413
404
  writeFileSync(opts.output, buf);
414
- await captureGeneratedArtifact(opts.output, 'generate-motion');
415
405
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
416
406
  console.log(`\nMotion FBX saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
417
407
  }
@@ -473,7 +463,6 @@ export function register3DCommands(tools) {
473
463
  const outDir = dirname(opts.output);
474
464
  mkdirSync(outDir, { recursive: true });
475
465
  writeFileSync(opts.output, buf);
476
- await captureGeneratedArtifact(opts.output, 'generate-avatar');
477
466
  const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
478
467
  console.log(`\n3D avatar saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
479
468
  }
@@ -1,9 +1,11 @@
1
+ import { Option } from 'commander';
1
2
  import { writeFileSync, mkdirSync } from 'fs';
2
3
  import { dirname, parse, join } from 'path';
3
4
  import sharp from 'sharp';
4
- import { captureGeneratedArtifact } from '../workspace-runtime/workspaces/artifact-receipts.js';
5
+ import { resolveImageBackgroundRequirement, validateImageDeliveryOptions } from '@playcraft/common/prefab';
6
+ import { assertImageAssetOutputPaths, readImageAssetContext } from '../utils/image-asset-context.js';
5
7
  import { AgentApiClient } from '../utils/agent-api-client.js';
6
- import { MAX_REFERENCE_IMAGES, collectReferenceImagePaths, collectReferenceImagePayloads, sniffImageExtension, extensionForImageMime, resolveImageOutputPath, handleError, raceWithTimeout, } from './tools-utils.js';
8
+ import { MAX_REFERENCE_IMAGES, collectReferenceImagePaths, parseImageTargetFieldPath, collectReferenceImagePayloads, sniffImageExtension, extensionForImageMime, resolveImageOutputPath, handleError, raceWithTimeout, } from './tools-utils.js';
7
9
  function isMasterCompositeStripRequest(opts) {
8
10
  if (opts.aspectRatio === '45:16')
9
11
  return true;
@@ -151,86 +153,140 @@ export function registerGenerationCommands(tools) {
151
153
  .requiredOption('--prompt <text>', '图片描述')
152
154
  .option('--aspect-ratio <ratio>', '宽高比 (1:1|45:16|16:9|9:16|3:4|4:3|2:3|3:2|21:9)', '1:1')
153
155
  .requiredOption('--output <path>', '保存路径(--count>1 时自动追加 _1/_2 等后缀)')
156
+ .option('--target-asset <path>', 'Existing asset to replace; read its schema references and delivery constraints')
157
+ .option('--target-field-path <path>', 'Target image field as an array of keys, e.g. ["endUI","playButton"]', parseImageTargetFieldPath)
158
+ .option('--no-target-reference', 'Generate without the existing asset reference only when explicitly requested')
159
+ .option('--output-format <format>', 'Final format: png, webp or jpeg')
160
+ .option('--fit-mode <mode>', 'Canvas fitting: contain, cover or fill')
161
+ .option('--padding-color <color>', 'Canvas padding color (transparent by default)')
162
+ .addOption(new Option('--background <mode>', 'Agent background decision from conversation context').choices(['transparent', 'opaque']))
163
+ .option('--remove-background', 'Require a verified transparent image')
164
+ .option('--no-remove-background', 'Keep the generated background')
154
165
  .option('--image-size <size>', '图片尺寸 (1K|2K|4K)')
155
166
  .option('--width <n>', '精确宽度(像素;MC 横排 5×9:16 推荐 3600 或 4096)', (v) => parseInt(v, 10))
156
167
  .option('--height <n>', '精确高度(像素;MC 推荐 1280 或 1455)', (v) => parseInt(v, 10))
157
168
  .option('--reference-image <path>', '参考图路径(可重复多次,最多 8 张),支持 PNG/JPG/WEBP', collectReferenceImagePaths, [])
158
169
  .option('--image-model <model>', '模型名(如 gpt-image-2)或 provider/model(如 mulerouter/gpt-image-2)。传模型名时后端按优先级自动 fallback;传 provider/model 则直连指定 provider')
159
- .option('--retry <n>', '全部 provider 都失败时的重试轮数(默认 1;超时不计为可重试错误)', (v) => parseInt(v, 10), 1)
170
+ .option('--retry <n>', '额外重试轮数(默认 0;后端统一限制尝试,透明验证失败和超时不重试)', (v) => parseInt(v, 10), 0)
160
171
  .option('--timeout <seconds>', '请求超时秒数(默认 1800,即 30 分钟;异步生图模型耗时较长,仅在后端明确报错时提前终止)', (v) => parseInt(v, 10), 1800)
161
172
  .option('--count <n>', '一次 API 调用生成多少张图片(默认 1,最多 10;仅 gpt-image-2 实际支持批量)', (v) => parseInt(v, 10), 1)
162
173
  .action(async (opts) => {
163
- const paths = opts.referenceImage ?? [];
164
- if (paths.length > MAX_REFERENCE_IMAGES) {
165
- console.error(`Error: Too many reference images: ${paths.length} paths given; maximum is ${MAX_REFERENCE_IMAGES}.`);
166
- process.exit(1);
167
- return;
168
- }
169
- const hasReferenceImages = paths.length > 0;
170
- const attemptGenerate = async (modelRef, attempt) => {
171
- const label = modelRef ? `[${modelRef}]` : '[default model]';
172
- if (attempt > 0) {
173
- console.log(`Retry ${attempt}/${opts.retry} ${label}...`);
174
- }
175
- else {
176
- console.log(`Generating image ${label}...`);
177
- }
178
- const referenceImages = await collectReferenceImagePayloads(paths);
179
- const client = new AgentApiClient();
180
- const imageCount = Math.min(Math.max(1, opts.count ?? 1), 10);
181
- const requestPromise = client.post('/generate-image', {
182
- prompt: opts.prompt,
183
- aspectRatio: opts.aspectRatio,
184
- imageSize: opts.imageSize,
185
- ...(opts.width && opts.height ? { width: opts.width, height: opts.height } : {}),
186
- referenceImages,
187
- ...(modelRef ? { imageModelRef: modelRef } : {}),
188
- ...(imageCount > 1 ? { imageCount } : {}),
189
- });
190
- return raceWithTimeout(requestPromise, opts.timeout * 1000, `Request timed out after ${opts.timeout}s. The backend task may still be running — check admin panel before re-running.`);
191
- };
192
- const enrichError = (err, modelRef) => {
193
- const msg = err instanceof Error ? err.message : String(err);
194
- const lines = [`Error: ${msg}`];
195
- if (msg.includes('500') || msg.includes('Internal server error')) {
196
- lines.push('');
197
- lines.push('Hint: API 500 error — the model may be temporarily unavailable.');
198
- lines.push(' → If using a bare model name (e.g. gpt-image-2), all providers failed — try a different model');
199
- if (modelRef?.includes('/')) {
200
- lines.push(' → Or try without provider prefix to auto-fallback providers: --image-model gpt-image-2');
201
- }
174
+ try {
175
+ const explicitBackground = opts.background === undefined ? opts.removeBackground : opts.background === 'transparent';
176
+ if (opts.background !== undefined && opts.removeBackground !== undefined && opts.removeBackground !== explicitBackground) {
177
+ throw new Error('Conflicting background options. Use --background transparent or --background opaque; no image request was sent.');
202
178
  }
203
- else if (msg.includes('timed out')) {
204
- lines.push('');
205
- lines.push('Hint: Request timed out. The backend task may still be running — retries were skipped to avoid creating duplicate tasks.');
206
- lines.push(' → Check the backend/admin panel for task status before re-running');
207
- lines.push(' → Try --image-size 1K to reduce generation time');
208
- lines.push(' → Or increase timeout with --timeout <seconds> (current default: 1800s)');
179
+ opts = { ...opts, removeBackground: explicitBackground };
180
+ if (opts.targetFieldPath && !opts.targetAsset) {
181
+ throw new Error('--target-field-path requires --target-asset; no image request was sent.');
209
182
  }
210
- else if (hasReferenceImages && (msg.includes('reference') || msg.includes('image input'))) {
211
- lines.push('');
212
- lines.push('Hint: Reference image error — the selected model may not support --reference-image.');
213
- lines.push(' → Run: playcraft tools list-image-models');
214
- lines.push(' → Models with CAPABILITY=text+image support --reference-image');
183
+ const explicitOutputFormat = opts.outputFormat;
184
+ const { dir: outputDir, name: outputName, ext: outputExt } = parse(opts.output);
185
+ const outputCandidates = [opts.output, ...Array.from({ length: opts.count > 1 ? Math.min(opts.count, 10) : 0 }, (_, i) => join(outputDir, `${outputName}_${i + 1}${outputExt}`))];
186
+ const assetContext = opts.targetAsset ? await readImageAssetContext(opts.targetAsset, process.cwd(), {
187
+ referenceImagePaths: opts.referenceImage, useTargetReference: opts.targetReference,
188
+ ...(opts.targetFieldPath ? { targetFieldPath: opts.targetFieldPath } : {}),
189
+ outputPaths: outputCandidates,
190
+ prompt: opts.prompt, removeBackground: opts.removeBackground,
191
+ }) : undefined;
192
+ opts = { ...opts,
193
+ aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
194
+ width: assetContext?.width ?? opts.width, height: assetContext?.height ?? opts.height,
195
+ outputFormat: assetContext?.outputFormatFromSchema ? assetContext.outputFormat : opts.outputFormat ?? assetContext?.outputFormat,
196
+ fitMode: assetContext?.fitMode ?? opts.fitMode,
197
+ removeBackground: resolveImageBackgroundRequirement({ prompt: opts.prompt,
198
+ schemaRemoveBackground: assetContext?.removeBackgroundFromSchema ? assetContext.removeBackground : undefined,
199
+ removeBackground: opts.removeBackground, fallbackRemoveBackground: assetContext?.removeBackground }),
200
+ paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
201
+ imageModel: opts.imageModel || assetContext?.imageModelRef,
202
+ };
203
+ const invalidDelivery = validateImageDeliveryOptions(opts);
204
+ if (invalidDelivery)
205
+ throw new Error(invalidDelivery);
206
+ const paths = opts.referenceImage?.length ? opts.referenceImage : assetContext?.referenceImagePaths ?? [];
207
+ if (paths.length > MAX_REFERENCE_IMAGES) {
208
+ console.error(`Error: Too many reference images: ${paths.length} paths given; maximum is ${MAX_REFERENCE_IMAGES}.`);
209
+ process.exit(1);
210
+ return;
215
211
  }
216
- return lines.join('\n');
217
- };
218
- try {
212
+ const hasReferenceImages = paths.length > 0;
213
+ const attemptGenerate = async (modelRef, attempt) => {
214
+ const label = modelRef ? `[${modelRef}]` : '[default model]';
215
+ if (attempt > 0) {
216
+ console.log(`Retry ${attempt}/${opts.retry} ${label}...`);
217
+ }
218
+ else {
219
+ console.log(`Generating image ${label}...`);
220
+ }
221
+ const referenceImages = await collectReferenceImagePayloads(paths);
222
+ const client = new AgentApiClient();
223
+ const imageCount = Math.min(Math.max(1, opts.count ?? 1), 10);
224
+ const requestPromise = client.post('/generate-image', {
225
+ prompt: opts.prompt,
226
+ aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
227
+ imageSize: opts.imageSize,
228
+ width: assetContext?.width ?? opts.width,
229
+ height: assetContext?.height ?? opts.height,
230
+ outputFormat: opts.outputFormat,
231
+ outputFormatSource: assetContext?.outputFormatFromSchema ? 'schema'
232
+ : explicitOutputFormat ? 'explicit' : assetContext ? 'inferred' : undefined,
233
+ fitMode: assetContext?.fitMode ?? opts.fitMode,
234
+ paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
235
+ background: opts.background === undefined ? undefined : opts.removeBackground ? 'transparent' : 'opaque',
236
+ removeBackground: opts.removeBackground,
237
+ backgroundRequirementSource: assetContext?.removeBackgroundFromSchema ? 'schema'
238
+ : explicitBackground !== undefined ? 'explicit' : 'inferred',
239
+ referenceImages,
240
+ ...(modelRef ? { imageModelRef: modelRef } : {}),
241
+ ...(imageCount > 1 ? { imageCount } : {}),
242
+ });
243
+ return raceWithTimeout(requestPromise, opts.timeout * 1000, `Request timed out after ${opts.timeout}s. The backend task may still be running — check admin panel before re-running.`);
244
+ };
245
+ const enrichError = (err, modelRef) => {
246
+ const msg = err instanceof Error ? err.message : String(err);
247
+ const lines = [`Error: ${msg}`];
248
+ if (/source_transparency_invalid|output_transparency_invalid|transparency_unsupported/.test(msg)) {
249
+ lines.push('Hint: Transparent output was not delivered. Preserve the requested transparency, references and model; use the request id and stage to investigate.');
250
+ }
251
+ else if (/API 500\b|Internal server error/.test(msg)) {
252
+ lines.push('');
253
+ lines.push('Hint: API 500 error — the model may be temporarily unavailable.');
254
+ lines.push(' → Inspect the request id and backend diagnostics before another generation attempt.');
255
+ if (modelRef?.includes('/') && opts.removeBackground !== true) {
256
+ lines.push(' → Or try without provider prefix to auto-fallback providers: --image-model gpt-image-2');
257
+ }
258
+ }
259
+ else if (msg.includes('timed out')) {
260
+ lines.push('');
261
+ lines.push('Hint: Request timed out. The backend task may still be running — retries were skipped to avoid creating duplicate tasks.');
262
+ lines.push(' → Check the backend/admin panel for task status before re-running');
263
+ lines.push(' → Try --image-size 1K to reduce generation time');
264
+ lines.push(' → Or increase timeout with --timeout <seconds> (current default: 1800s)');
265
+ }
266
+ else if (hasReferenceImages && (msg.includes('reference') || msg.includes('image input'))) {
267
+ lines.push('');
268
+ lines.push('Hint: Reference image error — the selected model may not support --reference-image.');
269
+ lines.push(' → Run: playcraft tools list-image-models');
270
+ lines.push(' → Models with CAPABILITY=text+image support --reference-image');
271
+ }
272
+ return lines.join('\n');
273
+ };
219
274
  let result = null;
220
275
  let lastError = null;
221
276
  // 重试逻辑:超时不重试(后端任务可能仍在运行,重试会导致重复提交)
222
- const maxAttempts = 1 + (opts.retry ?? 1);
277
+ const maxAttempts = 1 + (opts.retry ?? 0);
223
278
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
224
279
  try {
225
- result = await attemptGenerate(opts.imageModel, attempt);
280
+ result = await attemptGenerate(opts.imageModel || assetContext?.imageModelRef, attempt);
226
281
  break;
227
282
  }
228
283
  catch (e) {
229
284
  lastError = e;
230
285
  const msg = e instanceof Error ? e.message : String(e);
231
286
  const isTimeout = msg.includes('timed out');
232
- if (isTimeout) {
233
- console.error(`Attempt ${attempt + 1} timed out — not retrying (backend task may still be running).`);
287
+ const cannotRetry = /source_transparency_invalid|output_transparency_invalid|transparency_unsupported|"retryable"\s*:\s*false/.test(msg);
288
+ if (isTimeout || cannotRetry) {
289
+ console.error(`Attempt ${attempt + 1} stopped: ${msg}`);
234
290
  break;
235
291
  }
236
292
  if (attempt < maxAttempts - 1) {
@@ -255,16 +311,18 @@ export function registerGenerationCommands(tools) {
255
311
  }
256
312
  // 收集所有待保存图片(第 1 张 + 批量额外图)
257
313
  const allImages = [
258
- { imageBase64: result.imageBase64, mimeType: result.mimeType },
314
+ { imageBase64: result.imageBase64, mimeType: result.mimeType, previewUrl: result.previewUrl },
259
315
  ...(result.additionalImages ?? []),
260
316
  ];
261
317
  const isBatch = allImages.length > 1;
262
- const modelPart = opts.imageModel ? `model: ${opts.imageModel}` : '';
318
+ const modelPart = result.model ? `model: ${result.model}` : '';
263
319
  const providerPart = result.provider ? `provider: ${result.provider}` : '';
264
320
  const labelParts = [modelPart, providerPart].filter(Boolean);
265
321
  const modelLabel = labelParts.length > 0 ? ` (${labelParts.join(', ')})` : '';
266
322
  const savedPaths = [];
267
- const stripTarget = resolveStripTargetDimensions({
323
+ if (result.transparencySource)
324
+ console.log(`Transparency source: ${result.transparencySource}`);
325
+ const stripTarget = opts.targetAsset || result.transparentBackground ? null : resolveStripTargetDimensions({
268
326
  aspectRatio: opts.aspectRatio,
269
327
  width: opts.width,
270
328
  height: opts.height,
@@ -293,6 +351,8 @@ export function registerGenerationCommands(tools) {
293
351
  console.log(`↑ Letterbox ${generatedWidth}×${generatedHeight} → ${stripTarget.width}×${stripTarget.height}(等比 + 白边,不拉伸)`);
294
352
  }
295
353
  }
354
+ if (assetContext)
355
+ assertImageAssetOutputPaths(assetContext, [resolvedPath]);
296
356
  mkdirSync(dirname(resolvedPath), { recursive: true });
297
357
  writeFileSync(resolvedPath, imgBuf);
298
358
  let actualWidth = null;
@@ -309,11 +369,23 @@ export function registerGenerationCommands(tools) {
309
369
  }
310
370
  const sizeKB = Math.round(imgBuf.length / 1024);
311
371
  console.log(`[${i + 1}/${allImages.length}] Image saved to ${resolvedPath} (${sizeKB}KB)${modelLabel}`);
372
+ if (img.previewUrl)
373
+ console.log(`Image preview: ${img.previewUrl}`);
312
374
  savedPaths.push(resolvedPath);
313
375
  const sidecar = {
314
376
  prompt: opts.prompt,
315
- model: opts.imageModel ?? 'default',
377
+ model: result.model ?? null,
378
+ requestedModel: opts.imageModel ?? null,
316
379
  provider: result.provider ?? null,
380
+ transparentBackground: result.transparentBackground ?? null,
381
+ requestedBackground: opts.background ?? null,
382
+ transparencySource: result.transparencySource ?? null,
383
+ requestId: result.requestId ?? null,
384
+ attempts: result.attempts ?? null,
385
+ targetAssetPath: assetContext?.targetAssetPath ?? null,
386
+ outputFormat: opts.outputFormat ?? null,
387
+ fitMode: opts.fitMode ?? null,
388
+ paddingColor: opts.paddingColor ?? null,
317
389
  aspectRatio: opts.aspectRatio,
318
390
  imageSize: opts.imageSize ?? null,
319
391
  requestedWidth: opts.width ?? stripTarget?.width ?? null,
@@ -326,14 +398,12 @@ export function registerGenerationCommands(tools) {
326
398
  count: opts.count ?? 1,
327
399
  batchIndex: isBatch ? i + 1 : null,
328
400
  output: resolvedPath,
401
+ previewUrl: img.previewUrl ?? null,
329
402
  referenceImageStatus: result.referenceImageStatus ?? null,
330
403
  generatedAt: new Date().toISOString(),
331
404
  };
332
405
  const sidecarPath = resolvedPath.replace(/\.[^.]+$/, '.json');
333
406
  writeFileSync(sidecarPath, JSON.stringify(sidecar, null, 2));
334
- await captureGeneratedArtifact(resolvedPath, 'generate-image', {
335
- ...(actualWidth ? { width: actualWidth } : {}), ...(actualHeight ? { height: actualHeight } : {}),
336
- });
337
407
  console.log(` └─ Generation metadata: ${sidecarPath}`);
338
408
  }
339
409
  if (!isBatch && opts.output !== savedPaths[0] && savedPaths[0]) {
@@ -381,7 +451,6 @@ export function registerGenerationCommands(tools) {
381
451
  output: opts.output, generatedAt: new Date().toISOString(),
382
452
  };
383
453
  writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(sfxSidecar, null, 2));
384
- await captureGeneratedArtifact(opts.output, 'generate-sfx', { duration: result.duration });
385
454
  console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
386
455
  }
387
456
  catch (e) {
@@ -414,7 +483,6 @@ export function registerGenerationCommands(tools) {
414
483
  output: opts.output, generatedAt: new Date().toISOString(),
415
484
  };
416
485
  writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(bgmSidecar, null, 2));
417
- await captureGeneratedArtifact(opts.output, 'generate-bgm', { duration: result.duration });
418
486
  console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
419
487
  }
420
488
  catch (e) {