@playcraft/cli 0.1.50-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 (406) 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 -283
  133. package/dist/workspace-runtime/previews/runtime-preview.js +0 -177
  134. package/dist/workspace-runtime/previews/single-file.js +0 -43
  135. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  136. package/dist/workspace-runtime/serve.js +0 -441
  137. package/dist/workspace-runtime/server/accept-operation.js +0 -61
  138. package/dist/workspace-runtime/server/asset-transfers.js +0 -63
  139. package/dist/workspace-runtime/server/auth.js +0 -21
  140. package/dist/workspace-runtime/server/connectivity.js +0 -209
  141. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  142. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  143. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  144. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  145. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  146. package/dist/workspace-runtime/server/dispatch.js +0 -1632
  147. package/dist/workspace-runtime/server/endpoints.js +0 -21
  148. package/dist/workspace-runtime/server/execution-group.js +0 -90
  149. package/dist/workspace-runtime/server/http.js +0 -1340
  150. package/dist/workspace-runtime/server/lock.js +0 -53
  151. package/dist/workspace-runtime/server/operation-record.js +0 -33
  152. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  153. package/dist/workspace-runtime/server/session-restore.js +0 -84
  154. package/dist/workspace-runtime/server/source-uploader.js +0 -138
  155. package/dist/workspace-runtime/server/submit-operation.js +0 -41
  156. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  157. package/dist/workspace-runtime/server/types.js +0 -1
  158. package/dist/workspace-runtime/server/workspace-transfer.js +0 -168
  159. package/dist/workspace-runtime/verify-artifact.js +0 -59
  160. package/dist/workspace-runtime/workspaces/append-only-log.js +0 -62
  161. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  162. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  163. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -199
  164. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  165. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  166. package/dist/workspace-runtime/workspaces/asset-library-import.js +0 -366
  167. package/dist/workspace-runtime/workspaces/asset-transfer-dependencies.js +0 -81
  168. package/dist/workspace-runtime/workspaces/asset-transfer-publish.js +0 -434
  169. package/dist/workspace-runtime/workspaces/asset-transfer-storage.js +0 -389
  170. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -73
  171. package/dist/workspace-runtime/workspaces/attachments.js +0 -185
  172. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  173. package/dist/workspace-runtime/workspaces/binary-content.js +0 -65
  174. package/dist/workspace-runtime/workspaces/binary-write.js +0 -112
  175. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  176. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -115
  177. package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
  178. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  179. package/dist/workspace-runtime/workspaces/delivery-build.js +0 -331
  180. package/dist/workspace-runtime/workspaces/delivery-store.js +0 -168
  181. package/dist/workspace-runtime/workspaces/delivery.js +0 -64
  182. package/dist/workspace-runtime/workspaces/dependencies.js +0 -279
  183. package/dist/workspace-runtime/workspaces/developer-command.js +0 -98
  184. package/dist/workspace-runtime/workspaces/directories.js +0 -132
  185. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  186. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  187. package/dist/workspace-runtime/workspaces/directory-create.js +0 -57
  188. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  189. package/dist/workspace-runtime/workspaces/directory-mutations.js +0 -238
  190. package/dist/workspace-runtime/workspaces/directory-revisions.js +0 -56
  191. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  192. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  193. package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
  194. package/dist/workspace-runtime/workspaces/file-content.js +0 -48
  195. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  196. package/dist/workspace-runtime/workspaces/files.js +0 -150
  197. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  198. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  199. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  200. package/dist/workspace-runtime/workspaces/git.js +0 -670
  201. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  202. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -313
  203. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  204. package/dist/workspace-runtime/workspaces/operation-log.js +0 -23
  205. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
  206. package/dist/workspace-runtime/workspaces/parameter-agent-inputs.js +0 -87
  207. package/dist/workspace-runtime/workspaces/parameter-agent-protocol.js +0 -29
  208. package/dist/workspace-runtime/workspaces/parameter-agent-store.js +0 -58
  209. package/dist/workspace-runtime/workspaces/parameter-agent.js +0 -282
  210. package/dist/workspace-runtime/workspaces/parameters.js +0 -295
  211. package/dist/workspace-runtime/workspaces/prepare.js +0 -278
  212. package/dist/workspace-runtime/workspaces/registry.js +0 -251
  213. package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
  214. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  215. package/dist/workspace-runtime/workspaces/session-image.js +0 -104
  216. package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
  217. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
  218. package/dist/workspace-runtime/workspaces/skills.js +0 -191
  219. package/dist/workspace-runtime/workspaces/transfer-quota.js +0 -69
  220. package/dist/workspace-runtime/workspaces/transfer.js +0 -471
  221. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
  222. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  223. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  224. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  225. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  226. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  227. package/project-template-v2/.claude/agents/artist.md +0 -82
  228. package/project-template-v2/.claude/agents/developer.md +0 -153
  229. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  230. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  231. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  232. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  233. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  234. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  235. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  236. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  237. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  238. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  239. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  240. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  241. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  242. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  243. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  244. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  245. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  246. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  247. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  248. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  249. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  250. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  251. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  252. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  253. package/project-template-v2/.claude/settings.json +0 -33
  254. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  255. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  256. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  257. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  258. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  259. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  260. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  261. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  262. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  263. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  264. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  265. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  266. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  267. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  268. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  269. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  270. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  271. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  272. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  273. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  274. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  275. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  276. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  277. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  278. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  279. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  280. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  281. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  282. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  283. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  284. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  285. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  286. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  287. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  288. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  289. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  290. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  291. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  292. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  293. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  294. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  295. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  296. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  297. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  298. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  299. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  300. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  301. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  302. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  303. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  304. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  305. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  306. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  307. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  308. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  309. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  310. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  311. package/project-template-v2/.claude/snapshot.mjs +0 -263
  312. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  313. package/project-template-v2/CLAUDE.md +0 -146
  314. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  315. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  316. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  317. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  318. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  319. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  320. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  321. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  322. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  323. package/project-template-v2/assets/models/.gitkeep +0 -0
  324. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  325. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  326. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  327. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  328. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  329. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  330. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  331. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  332. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  333. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  334. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  335. package/project-template-v2/docs/project-state.json +0 -60
  336. package/project-template-v2/docs/project-state.md +0 -72
  337. package/project-template-v2/docs/standards/README.md +0 -225
  338. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  339. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  340. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  341. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  342. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  343. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  344. package/project-template-v2/game/index.ts +0 -18
  345. package/project-template-v2/globals.d.ts +0 -51
  346. package/project-template-v2/index.css +0 -34
  347. package/project-template-v2/index.html +0 -18
  348. package/project-template-v2/main.ts +0 -9
  349. package/project-template-v2/package.json +0 -46
  350. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  351. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  352. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  353. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  354. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  355. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  356. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  357. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  358. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  359. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  360. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  361. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  362. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  363. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  364. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  365. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  366. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  367. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  368. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  369. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  370. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  371. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  372. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  373. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  374. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  375. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  376. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  377. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  378. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  379. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  380. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  381. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  382. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  383. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  384. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  385. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  386. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  387. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  388. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  389. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  390. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  391. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  392. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  393. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  394. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  395. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  396. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  397. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  398. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  399. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  400. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  401. package/project-template-v2/tsconfig.json +0 -20
  402. package/project-template-v2/vite.config.ts +0 -27
  403. package/project-templates/batch-locks/phaser.yaml +0 -922
  404. package/project-templates/batch-locks/threejs.yaml +0 -978
  405. package/project-templates/empty/AGENTS.md +0 -41
  406. 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) {