@playcraft/cli 0.1.38-beta → 0.1.39-prod

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 (367) hide show
  1. package/README.md +3 -58
  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 +126 -68
  12. package/dist/commands/tools-image-context.js +23 -0
  13. package/dist/commands/tools.js +2 -2
  14. package/dist/config.js +4 -59
  15. package/dist/index.js +3 -40
  16. package/dist/remix/clone.js +0 -2
  17. package/dist/remix/init-template.js +0 -2
  18. package/dist/remix/pull.js +0 -2
  19. package/dist/remix/push.js +1 -21
  20. package/dist/utils/agent-api-client.js +30 -185
  21. package/dist/utils/image-asset-context.js +106 -0
  22. package/dist/utils/playcraft-http-client.js +4 -6
  23. package/package.json +3 -13
  24. package/project-template/.claude/agents/refs/ta-image-generation-detail.md +67 -123
  25. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  26. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  27. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  28. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  29. package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  30. package/project-templates/phaser/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  31. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  32. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  33. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  34. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  35. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  36. package/project-templates/threejs/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  37. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  38. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  39. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  40. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  41. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  42. package/SKILLS_REGISTRY.md +0 -149
  43. package/dist/auth/account-activation.js +0 -157
  44. package/dist/auth/messages.js +0 -30
  45. package/dist/commands/build-temp.js +0 -26
  46. package/dist/commands/platform-skills.generated.js +0 -19
  47. package/dist/commands/playable.js +0 -53
  48. package/dist/commands/tools-batch.js +0 -87
  49. package/dist/commands/video.js +0 -111
  50. package/dist/commands/workspace-runtime.js +0 -54
  51. package/dist/commands/workspace.js +0 -35
  52. package/dist/project-skills/builtin-import.js +0 -225
  53. package/dist/project-skills/commands.js +0 -77
  54. package/dist/project-skills/lifecycle.js +0 -28
  55. package/dist/project-skills/local-run.js +0 -112
  56. package/dist/project-skills/local-store.js +0 -221
  57. package/dist/project-skills/messages.js +0 -80
  58. package/dist/project-skills/reconcile.js +0 -62
  59. package/dist/project-skills/remote-cache.js +0 -51
  60. package/dist/project-skills/validation.js +0 -19
  61. package/dist/recording/messages.js +0 -40
  62. package/dist/recording/project-digest.js +0 -85
  63. package/dist/recording/recorder.js +0 -293
  64. package/dist/recording/scenario.js +0 -50
  65. package/dist/skill-registry/client.js +0 -345
  66. package/dist/skill-registry/commands.js +0 -180
  67. package/dist/skill-registry/evaluation-client.js +0 -156
  68. package/dist/skill-registry/evaluation-commands.js +0 -174
  69. package/dist/skill-registry/messages.js +0 -177
  70. package/dist/skill-registry/package.js +0 -275
  71. package/dist/skill-registry/platform-package.js +0 -100
  72. package/dist/utils/environment-endpoints.js +0 -17
  73. package/dist/utils/tool-operation-journal.js +0 -124
  74. package/dist/utils/video-evidence-git.js +0 -81
  75. package/dist/video-replication/client.js +0 -222
  76. package/dist/video-replication/comparison-evidence.js +0 -149
  77. package/dist/video-replication/comparison-files.js +0 -57
  78. package/dist/video-replication/comparison-log.js +0 -72
  79. package/dist/video-replication/comparison-messages.js +0 -104
  80. package/dist/video-replication/comparison-output.js +0 -63
  81. package/dist/video-replication/comparison-preflight.js +0 -66
  82. package/dist/video-replication/comparison.js +0 -216
  83. package/dist/video-replication/evidence.js +0 -165
  84. package/dist/video-replication/media.js +0 -111
  85. package/dist/video-replication/messages.js +0 -89
  86. package/dist/workspace/messages.js +0 -35
  87. package/dist/workspace/transfer-client.js +0 -174
  88. package/dist/workspace-runtime/codex/app-server.js +0 -1040
  89. package/dist/workspace-runtime/codex/compact.js +0 -46
  90. package/dist/workspace-runtime/codex/config-toml.js +0 -107
  91. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
  92. package/dist/workspace-runtime/codex/launcher-client.js +0 -177
  93. package/dist/workspace-runtime/codex/loopback.js +0 -146
  94. package/dist/workspace-runtime/codex/mcp-config.js +0 -39
  95. package/dist/workspace-runtime/codex/model-broker.js +0 -263
  96. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  97. package/dist/workspace-runtime/codex/permissions.js +0 -70
  98. package/dist/workspace-runtime/codex/thread-image.js +0 -38
  99. package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
  100. package/dist/workspace-runtime/codex/ui-tools.js +0 -183
  101. package/dist/workspace-runtime/codex/work-mode.js +0 -15
  102. package/dist/workspace-runtime/main.js +0 -10
  103. package/dist/workspace-runtime/persistence/journal.js +0 -365
  104. package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
  105. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
  106. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1161
  107. package/dist/workspace-runtime/persistence/stopped-execution.js +0 -77
  108. package/dist/workspace-runtime/previews/output.js +0 -36
  109. package/dist/workspace-runtime/previews/publish.js +0 -262
  110. package/dist/workspace-runtime/previews/single-file.js +0 -43
  111. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  112. package/dist/workspace-runtime/production/content-changes.js +0 -36
  113. package/dist/workspace-runtime/production/contracts.js +0 -19
  114. package/dist/workspace-runtime/production/controller.js +0 -218
  115. package/dist/workspace-runtime/production/dependencies.js +0 -60
  116. package/dist/workspace-runtime/production/native.js +0 -212
  117. package/dist/workspace-runtime/production/processes.js +0 -102
  118. package/dist/workspace-runtime/production/save-command.js +0 -35
  119. package/dist/workspace-runtime/production/source-archive.js +0 -137
  120. package/dist/workspace-runtime/production/source-copy.js +0 -91
  121. package/dist/workspace-runtime/production/stages.js +0 -334
  122. package/dist/workspace-runtime/production/storage.js +0 -75
  123. package/dist/workspace-runtime/serve.js +0 -214
  124. package/dist/workspace-runtime/server/auth.js +0 -21
  125. package/dist/workspace-runtime/server/connectivity.js +0 -201
  126. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  127. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  128. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  129. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  130. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  131. package/dist/workspace-runtime/server/dispatch.js +0 -1217
  132. package/dist/workspace-runtime/server/endpoints.js +0 -21
  133. package/dist/workspace-runtime/server/execution-group.js +0 -90
  134. package/dist/workspace-runtime/server/http.js +0 -1243
  135. package/dist/workspace-runtime/server/lock.js +0 -53
  136. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  137. package/dist/workspace-runtime/server/source-uploader.js +0 -138
  138. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  139. package/dist/workspace-runtime/server/types.js +0 -1
  140. package/dist/workspace-runtime/server/workspace-transfer.js +0 -99
  141. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  142. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  143. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -197
  144. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  145. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  146. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -123
  147. package/dist/workspace-runtime/workspaces/attachments.js +0 -185
  148. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  149. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  150. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -111
  151. package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
  152. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  153. package/dist/workspace-runtime/workspaces/dependencies.js +0 -264
  154. package/dist/workspace-runtime/workspaces/developer-command.js +0 -64
  155. package/dist/workspace-runtime/workspaces/directories.js +0 -133
  156. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  157. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  158. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  159. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  160. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  161. package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
  162. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  163. package/dist/workspace-runtime/workspaces/files.js +0 -120
  164. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  165. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  166. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  167. package/dist/workspace-runtime/workspaces/git.js +0 -670
  168. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  169. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -170
  170. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  171. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
  172. package/dist/workspace-runtime/workspaces/parameters.js +0 -272
  173. package/dist/workspace-runtime/workspaces/prepare.js +0 -278
  174. package/dist/workspace-runtime/workspaces/registry.js +0 -251
  175. package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
  176. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  177. package/dist/workspace-runtime/workspaces/session-image.js +0 -104
  178. package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
  179. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
  180. package/dist/workspace-runtime/workspaces/skills.js +0 -191
  181. package/dist/workspace-runtime/workspaces/transfer.js +0 -288
  182. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
  183. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  184. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  185. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  186. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  187. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  188. package/project-template-v2/.claude/agents/artist.md +0 -82
  189. package/project-template-v2/.claude/agents/developer.md +0 -153
  190. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  191. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  192. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  193. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  194. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  195. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  196. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  197. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  198. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  199. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  200. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  201. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  202. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  203. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  204. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  205. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  206. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  207. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  208. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  209. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  210. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  211. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  212. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  213. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  214. package/project-template-v2/.claude/settings.json +0 -33
  215. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  216. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  217. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  218. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  219. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  220. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  221. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  222. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  223. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  224. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  225. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  226. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  227. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  228. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  229. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  230. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  231. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  232. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  233. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  234. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  235. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  236. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  237. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  238. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  239. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  240. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  241. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  242. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  243. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  244. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  245. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  246. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  247. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  248. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  249. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  250. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  251. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  252. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  253. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  254. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  255. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  256. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  257. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  258. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  259. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  260. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  261. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  262. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  263. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  264. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  265. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  266. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  267. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  268. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  269. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  270. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  271. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  272. package/project-template-v2/.claude/snapshot.mjs +0 -263
  273. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  274. package/project-template-v2/CLAUDE.md +0 -146
  275. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  276. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  277. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  278. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  279. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  280. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  281. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  282. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  283. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  284. package/project-template-v2/assets/models/.gitkeep +0 -0
  285. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  286. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  287. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  288. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  289. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  290. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  291. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  292. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  293. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  294. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  295. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  296. package/project-template-v2/docs/project-state.json +0 -60
  297. package/project-template-v2/docs/project-state.md +0 -72
  298. package/project-template-v2/docs/standards/README.md +0 -225
  299. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  300. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  301. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  302. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  303. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  304. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  305. package/project-template-v2/game/index.ts +0 -18
  306. package/project-template-v2/globals.d.ts +0 -51
  307. package/project-template-v2/index.css +0 -34
  308. package/project-template-v2/index.html +0 -18
  309. package/project-template-v2/main.ts +0 -9
  310. package/project-template-v2/package.json +0 -46
  311. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  312. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  313. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  314. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  315. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  316. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  317. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  318. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  319. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  320. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  321. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  322. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  323. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  324. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  325. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  326. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  327. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  328. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  329. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  330. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  331. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  332. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  333. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  334. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  335. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  336. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  337. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  338. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  339. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  340. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  341. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  342. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  343. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  344. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  345. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  346. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  347. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  348. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  349. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  350. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  351. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  352. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  353. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  354. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  355. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  356. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  357. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  358. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  359. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  360. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  361. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  362. package/project-template-v2/tsconfig.json +0 -20
  363. package/project-template-v2/vite.config.ts +0 -27
  364. package/project-templates/batch-locks/phaser.yaml +0 -922
  365. package/project-templates/batch-locks/threejs.yaml +0 -978
  366. package/project-templates/empty/AGENTS.md +0 -41
  367. 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,7 +1,9 @@
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 { readImageAssetContext } from '../utils/image-asset-context.js';
5
7
  import { AgentApiClient } from '../utils/agent-api-client.js';
6
8
  import { MAX_REFERENCE_IMAGES, collectReferenceImagePaths, collectReferenceImagePayloads, sniffImageExtension, extensionForImageMime, resolveImageOutputPath, handleError, raceWithTimeout, } from './tools-utils.js';
7
9
  function isMasterCompositeStripRequest(opts) {
@@ -151,86 +153,132 @@ 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('--no-target-reference', 'Generate without the existing asset reference only when explicitly requested')
158
+ .option('--output-format <format>', 'Final format: png, webp or jpeg')
159
+ .option('--fit-mode <mode>', 'Canvas fitting: contain, cover or fill')
160
+ .option('--padding-color <color>', 'Canvas padding color (transparent by default)')
161
+ .addOption(new Option('--background <mode>', 'Agent background decision from conversation context').choices(['transparent', 'opaque']))
162
+ .option('--remove-background', 'Require a verified transparent image')
163
+ .option('--no-remove-background', 'Keep the generated background')
154
164
  .option('--image-size <size>', '图片尺寸 (1K|2K|4K)')
155
165
  .option('--width <n>', '精确宽度(像素;MC 横排 5×9:16 推荐 3600 或 4096)', (v) => parseInt(v, 10))
156
166
  .option('--height <n>', '精确高度(像素;MC 推荐 1280 或 1455)', (v) => parseInt(v, 10))
157
167
  .option('--reference-image <path>', '参考图路径(可重复多次,最多 8 张),支持 PNG/JPG/WEBP', collectReferenceImagePaths, [])
158
168
  .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)
169
+ .option('--retry <n>', '额外重试轮数(默认 0;后端统一限制尝试,透明验证失败和超时不重试)', (v) => parseInt(v, 10), 0)
160
170
  .option('--timeout <seconds>', '请求超时秒数(默认 1800,即 30 分钟;异步生图模型耗时较长,仅在后端明确报错时提前终止)', (v) => parseInt(v, 10), 1800)
161
171
  .option('--count <n>', '一次 API 调用生成多少张图片(默认 1,最多 10;仅 gpt-image-2 实际支持批量)', (v) => parseInt(v, 10), 1)
162
172
  .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}...`);
173
+ try {
174
+ const explicitBackground = opts.background === undefined ? opts.removeBackground : opts.background === 'transparent';
175
+ if (opts.background !== undefined && opts.removeBackground !== undefined && opts.removeBackground !== explicitBackground) {
176
+ throw new Error('Conflicting background options. Use --background transparent or --background opaque; no image request was sent.');
174
177
  }
175
- else {
176
- console.log(`Generating image ${label}...`);
178
+ opts = { ...opts, removeBackground: explicitBackground };
179
+ const explicitOutputFormat = opts.outputFormat;
180
+ const assetContext = opts.targetAsset ? await readImageAssetContext(opts.targetAsset, process.cwd(), {
181
+ referenceImagePaths: opts.referenceImage, useTargetReference: opts.targetReference,
182
+ prompt: opts.prompt, removeBackground: opts.removeBackground,
183
+ }) : undefined;
184
+ opts = { ...opts,
185
+ aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
186
+ width: assetContext?.width ?? opts.width, height: assetContext?.height ?? opts.height,
187
+ outputFormat: assetContext?.outputFormatFromSchema ? assetContext.outputFormat : opts.outputFormat ?? assetContext?.outputFormat,
188
+ fitMode: assetContext?.fitMode ?? opts.fitMode,
189
+ removeBackground: resolveImageBackgroundRequirement({ prompt: opts.prompt,
190
+ schemaRemoveBackground: assetContext?.removeBackgroundFromSchema ? assetContext.removeBackground : undefined,
191
+ removeBackground: opts.removeBackground, fallbackRemoveBackground: assetContext?.removeBackground }),
192
+ paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
193
+ imageModel: opts.imageModel || assetContext?.imageModelRef,
194
+ };
195
+ const invalidDelivery = validateImageDeliveryOptions(opts);
196
+ if (invalidDelivery)
197
+ throw new Error(invalidDelivery);
198
+ const paths = opts.referenceImage?.length ? opts.referenceImage : assetContext?.referenceImagePaths ?? [];
199
+ if (paths.length > MAX_REFERENCE_IMAGES) {
200
+ console.error(`Error: Too many reference images: ${paths.length} paths given; maximum is ${MAX_REFERENCE_IMAGES}.`);
201
+ process.exit(1);
202
+ return;
177
203
  }
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');
204
+ const hasReferenceImages = paths.length > 0;
205
+ const attemptGenerate = async (modelRef, attempt) => {
206
+ const label = modelRef ? `[${modelRef}]` : '[default model]';
207
+ if (attempt > 0) {
208
+ console.log(`Retry ${attempt}/${opts.retry} ${label}...`);
201
209
  }
202
- }
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)');
209
- }
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');
215
- }
216
- return lines.join('\n');
217
- };
218
- try {
210
+ else {
211
+ console.log(`Generating image ${label}...`);
212
+ }
213
+ const referenceImages = await collectReferenceImagePayloads(paths);
214
+ const client = new AgentApiClient();
215
+ const imageCount = Math.min(Math.max(1, opts.count ?? 1), 10);
216
+ const requestPromise = client.post('/generate-image', {
217
+ prompt: opts.prompt,
218
+ aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
219
+ imageSize: opts.imageSize,
220
+ width: assetContext?.width ?? opts.width,
221
+ height: assetContext?.height ?? opts.height,
222
+ outputFormat: opts.outputFormat,
223
+ outputFormatSource: assetContext?.outputFormatFromSchema ? 'schema'
224
+ : explicitOutputFormat ? 'explicit' : assetContext ? 'inferred' : undefined,
225
+ fitMode: assetContext?.fitMode ?? opts.fitMode,
226
+ paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
227
+ background: opts.background === undefined ? undefined : opts.removeBackground ? 'transparent' : 'opaque',
228
+ removeBackground: opts.removeBackground,
229
+ backgroundRequirementSource: assetContext?.removeBackgroundFromSchema ? 'schema'
230
+ : explicitBackground !== undefined ? 'explicit' : 'inferred',
231
+ referenceImages,
232
+ ...(modelRef ? { imageModelRef: modelRef } : {}),
233
+ ...(imageCount > 1 ? { imageCount } : {}),
234
+ });
235
+ 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.`);
236
+ };
237
+ const enrichError = (err, modelRef) => {
238
+ const msg = err instanceof Error ? err.message : String(err);
239
+ const lines = [`Error: ${msg}`];
240
+ if (/source_transparency_invalid|output_transparency_invalid|transparency_unsupported/.test(msg)) {
241
+ lines.push('Hint: Transparent output was not delivered. Preserve the requested transparency, references and model; use the request id and stage to investigate.');
242
+ }
243
+ else if (/API 500\b|Internal server error/.test(msg)) {
244
+ lines.push('');
245
+ lines.push('Hint: API 500 error — the model may be temporarily unavailable.');
246
+ lines.push(' → Inspect the request id and backend diagnostics before another generation attempt.');
247
+ if (modelRef?.includes('/') && opts.removeBackground !== true) {
248
+ lines.push(' → Or try without provider prefix to auto-fallback providers: --image-model gpt-image-2');
249
+ }
250
+ }
251
+ else if (msg.includes('timed out')) {
252
+ lines.push('');
253
+ lines.push('Hint: Request timed out. The backend task may still be running — retries were skipped to avoid creating duplicate tasks.');
254
+ lines.push(' → Check the backend/admin panel for task status before re-running');
255
+ lines.push(' → Try --image-size 1K to reduce generation time');
256
+ lines.push(' → Or increase timeout with --timeout <seconds> (current default: 1800s)');
257
+ }
258
+ else if (hasReferenceImages && (msg.includes('reference') || msg.includes('image input'))) {
259
+ lines.push('');
260
+ lines.push('Hint: Reference image error — the selected model may not support --reference-image.');
261
+ lines.push(' → Run: playcraft tools list-image-models');
262
+ lines.push(' → Models with CAPABILITY=text+image support --reference-image');
263
+ }
264
+ return lines.join('\n');
265
+ };
219
266
  let result = null;
220
267
  let lastError = null;
221
268
  // 重试逻辑:超时不重试(后端任务可能仍在运行,重试会导致重复提交)
222
- const maxAttempts = 1 + (opts.retry ?? 1);
269
+ const maxAttempts = 1 + (opts.retry ?? 0);
223
270
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
224
271
  try {
225
- result = await attemptGenerate(opts.imageModel, attempt);
272
+ result = await attemptGenerate(opts.imageModel || assetContext?.imageModelRef, attempt);
226
273
  break;
227
274
  }
228
275
  catch (e) {
229
276
  lastError = e;
230
277
  const msg = e instanceof Error ? e.message : String(e);
231
278
  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).`);
279
+ const cannotRetry = /source_transparency_invalid|output_transparency_invalid|transparency_unsupported|"retryable"\s*:\s*false/.test(msg);
280
+ if (isTimeout || cannotRetry) {
281
+ console.error(`Attempt ${attempt + 1} stopped: ${msg}`);
234
282
  break;
235
283
  }
236
284
  if (attempt < maxAttempts - 1) {
@@ -255,16 +303,18 @@ export function registerGenerationCommands(tools) {
255
303
  }
256
304
  // 收集所有待保存图片(第 1 张 + 批量额外图)
257
305
  const allImages = [
258
- { imageBase64: result.imageBase64, mimeType: result.mimeType },
306
+ { imageBase64: result.imageBase64, mimeType: result.mimeType, previewUrl: result.previewUrl },
259
307
  ...(result.additionalImages ?? []),
260
308
  ];
261
309
  const isBatch = allImages.length > 1;
262
- const modelPart = opts.imageModel ? `model: ${opts.imageModel}` : '';
310
+ const modelPart = result.model ? `model: ${result.model}` : '';
263
311
  const providerPart = result.provider ? `provider: ${result.provider}` : '';
264
312
  const labelParts = [modelPart, providerPart].filter(Boolean);
265
313
  const modelLabel = labelParts.length > 0 ? ` (${labelParts.join(', ')})` : '';
266
314
  const savedPaths = [];
267
- const stripTarget = resolveStripTargetDimensions({
315
+ if (result.transparencySource)
316
+ console.log(`Transparency source: ${result.transparencySource}`);
317
+ const stripTarget = opts.targetAsset || result.transparentBackground ? null : resolveStripTargetDimensions({
268
318
  aspectRatio: opts.aspectRatio,
269
319
  width: opts.width,
270
320
  height: opts.height,
@@ -309,11 +359,23 @@ export function registerGenerationCommands(tools) {
309
359
  }
310
360
  const sizeKB = Math.round(imgBuf.length / 1024);
311
361
  console.log(`[${i + 1}/${allImages.length}] Image saved to ${resolvedPath} (${sizeKB}KB)${modelLabel}`);
362
+ if (img.previewUrl)
363
+ console.log(`Image preview: ${img.previewUrl}`);
312
364
  savedPaths.push(resolvedPath);
313
365
  const sidecar = {
314
366
  prompt: opts.prompt,
315
- model: opts.imageModel ?? 'default',
367
+ model: result.model ?? null,
368
+ requestedModel: opts.imageModel ?? null,
316
369
  provider: result.provider ?? null,
370
+ transparentBackground: result.transparentBackground ?? null,
371
+ requestedBackground: opts.background ?? null,
372
+ transparencySource: result.transparencySource ?? null,
373
+ requestId: result.requestId ?? null,
374
+ attempts: result.attempts ?? null,
375
+ targetAssetPath: assetContext?.targetAssetPath ?? null,
376
+ outputFormat: opts.outputFormat ?? null,
377
+ fitMode: opts.fitMode ?? null,
378
+ paddingColor: opts.paddingColor ?? null,
317
379
  aspectRatio: opts.aspectRatio,
318
380
  imageSize: opts.imageSize ?? null,
319
381
  requestedWidth: opts.width ?? stripTarget?.width ?? null,
@@ -326,14 +388,12 @@ export function registerGenerationCommands(tools) {
326
388
  count: opts.count ?? 1,
327
389
  batchIndex: isBatch ? i + 1 : null,
328
390
  output: resolvedPath,
391
+ previewUrl: img.previewUrl ?? null,
329
392
  referenceImageStatus: result.referenceImageStatus ?? null,
330
393
  generatedAt: new Date().toISOString(),
331
394
  };
332
395
  const sidecarPath = resolvedPath.replace(/\.[^.]+$/, '.json');
333
396
  writeFileSync(sidecarPath, JSON.stringify(sidecar, null, 2));
334
- await captureGeneratedArtifact(resolvedPath, 'generate-image', {
335
- ...(actualWidth ? { width: actualWidth } : {}), ...(actualHeight ? { height: actualHeight } : {}),
336
- });
337
397
  console.log(` └─ Generation metadata: ${sidecarPath}`);
338
398
  }
339
399
  if (!isBatch && opts.output !== savedPaths[0] && savedPaths[0]) {
@@ -381,7 +441,6 @@ export function registerGenerationCommands(tools) {
381
441
  output: opts.output, generatedAt: new Date().toISOString(),
382
442
  };
383
443
  writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(sfxSidecar, null, 2));
384
- await captureGeneratedArtifact(opts.output, 'generate-sfx', { duration: result.duration });
385
444
  console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
386
445
  }
387
446
  catch (e) {
@@ -414,7 +473,6 @@ export function registerGenerationCommands(tools) {
414
473
  output: opts.output, generatedAt: new Date().toISOString(),
415
474
  };
416
475
  writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(bgmSidecar, null, 2));
417
- await captureGeneratedArtifact(opts.output, 'generate-bgm', { duration: result.duration });
418
476
  console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
419
477
  }
420
478
  catch (e) {
@@ -0,0 +1,23 @@
1
+ import { readImageAssetContext } from '../utils/image-asset-context.js';
2
+ import { collectReferenceImagePaths, handleError } from './tools-utils.js';
3
+ export function registerImageContextCommand(tools) {
4
+ tools.command('image-context')
5
+ .description('Read image asset reference and delivery constraints locally; does not generate an image')
6
+ .requiredOption('--asset-path <path>', 'Existing image asset path relative to the project')
7
+ .option('--reference-image <path>', 'Explicit local reference; may be repeated', collectReferenceImagePaths, [])
8
+ .option('--no-target-reference', 'Do not use the target schema or current asset as a reference')
9
+ .option('--prompt <text>', 'Generation request used to resolve background intent')
10
+ .option('--remove-background', 'Explicitly request verified transparency')
11
+ .option('--no-remove-background', 'Explicitly keep an opaque background')
12
+ .action(async (opts) => {
13
+ try {
14
+ console.log(JSON.stringify(await readImageAssetContext(opts.assetPath, process.cwd(), {
15
+ referenceImagePaths: opts.referenceImage, useTargetReference: opts.targetReference,
16
+ prompt: opts.prompt, removeBackground: opts.removeBackground,
17
+ })));
18
+ }
19
+ catch (error) {
20
+ handleError(error);
21
+ }
22
+ });
23
+ }