@playcraft/cli 0.1.40-beta → 0.1.42

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 (368) 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 +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 -185
  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 -87
  50. package/dist/commands/video.js +0 -111
  51. package/dist/commands/workspace-runtime.js +0 -54
  52. package/dist/commands/workspace.js +0 -35
  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/tool-operation-journal.js +0 -124
  75. package/dist/utils/video-evidence-git.js +0 -81
  76. package/dist/video-replication/client.js +0 -222
  77. package/dist/video-replication/comparison-evidence.js +0 -149
  78. package/dist/video-replication/comparison-files.js +0 -57
  79. package/dist/video-replication/comparison-log.js +0 -72
  80. package/dist/video-replication/comparison-messages.js +0 -104
  81. package/dist/video-replication/comparison-output.js +0 -63
  82. package/dist/video-replication/comparison-preflight.js +0 -66
  83. package/dist/video-replication/comparison.js +0 -216
  84. package/dist/video-replication/evidence.js +0 -165
  85. package/dist/video-replication/media.js +0 -111
  86. package/dist/video-replication/messages.js +0 -89
  87. package/dist/workspace/messages.js +0 -35
  88. package/dist/workspace/transfer-client.js +0 -174
  89. package/dist/workspace-runtime/codex/app-server.js +0 -1040
  90. package/dist/workspace-runtime/codex/compact.js +0 -46
  91. package/dist/workspace-runtime/codex/config-toml.js +0 -107
  92. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
  93. package/dist/workspace-runtime/codex/launcher-client.js +0 -177
  94. package/dist/workspace-runtime/codex/loopback.js +0 -146
  95. package/dist/workspace-runtime/codex/mcp-config.js +0 -39
  96. package/dist/workspace-runtime/codex/model-broker.js +0 -263
  97. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  98. package/dist/workspace-runtime/codex/permissions.js +0 -70
  99. package/dist/workspace-runtime/codex/thread-image.js +0 -38
  100. package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
  101. package/dist/workspace-runtime/codex/ui-tools.js +0 -183
  102. package/dist/workspace-runtime/codex/work-mode.js +0 -15
  103. package/dist/workspace-runtime/main.js +0 -10
  104. package/dist/workspace-runtime/persistence/journal.js +0 -365
  105. package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
  106. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
  107. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1161
  108. package/dist/workspace-runtime/persistence/stopped-execution.js +0 -77
  109. package/dist/workspace-runtime/previews/output.js +0 -36
  110. package/dist/workspace-runtime/previews/publish.js +0 -262
  111. package/dist/workspace-runtime/previews/single-file.js +0 -43
  112. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  113. package/dist/workspace-runtime/production/content-changes.js +0 -36
  114. package/dist/workspace-runtime/production/contracts.js +0 -19
  115. package/dist/workspace-runtime/production/controller.js +0 -218
  116. package/dist/workspace-runtime/production/dependencies.js +0 -60
  117. package/dist/workspace-runtime/production/native.js +0 -212
  118. package/dist/workspace-runtime/production/processes.js +0 -102
  119. package/dist/workspace-runtime/production/save-command.js +0 -35
  120. package/dist/workspace-runtime/production/source-archive.js +0 -137
  121. package/dist/workspace-runtime/production/source-copy.js +0 -91
  122. package/dist/workspace-runtime/production/stages.js +0 -334
  123. package/dist/workspace-runtime/production/storage.js +0 -75
  124. package/dist/workspace-runtime/serve.js +0 -214
  125. package/dist/workspace-runtime/server/auth.js +0 -21
  126. package/dist/workspace-runtime/server/connectivity.js +0 -201
  127. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  128. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  129. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  130. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  131. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  132. package/dist/workspace-runtime/server/dispatch.js +0 -1217
  133. package/dist/workspace-runtime/server/endpoints.js +0 -21
  134. package/dist/workspace-runtime/server/execution-group.js +0 -90
  135. package/dist/workspace-runtime/server/http.js +0 -1243
  136. package/dist/workspace-runtime/server/lock.js +0 -53
  137. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  138. package/dist/workspace-runtime/server/source-uploader.js +0 -138
  139. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  140. package/dist/workspace-runtime/server/types.js +0 -1
  141. package/dist/workspace-runtime/server/workspace-transfer.js +0 -99
  142. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  143. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  144. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -197
  145. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  146. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  147. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -123
  148. package/dist/workspace-runtime/workspaces/attachments.js +0 -185
  149. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  150. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  151. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -111
  152. package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
  153. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  154. package/dist/workspace-runtime/workspaces/dependencies.js +0 -264
  155. package/dist/workspace-runtime/workspaces/developer-command.js +0 -64
  156. package/dist/workspace-runtime/workspaces/directories.js +0 -133
  157. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  158. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  159. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  160. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  161. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  162. package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
  163. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  164. package/dist/workspace-runtime/workspaces/files.js +0 -138
  165. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  166. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  167. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  168. package/dist/workspace-runtime/workspaces/git.js +0 -670
  169. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  170. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -170
  171. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  172. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
  173. package/dist/workspace-runtime/workspaces/parameters.js +0 -272
  174. package/dist/workspace-runtime/workspaces/prepare.js +0 -278
  175. package/dist/workspace-runtime/workspaces/registry.js +0 -251
  176. package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
  177. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  178. package/dist/workspace-runtime/workspaces/session-image.js +0 -104
  179. package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
  180. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
  181. package/dist/workspace-runtime/workspaces/skills.js +0 -191
  182. package/dist/workspace-runtime/workspaces/transfer.js +0 -288
  183. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
  184. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  185. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  186. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  187. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  188. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  189. package/project-template-v2/.claude/agents/artist.md +0 -82
  190. package/project-template-v2/.claude/agents/developer.md +0 -153
  191. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  192. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  193. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  194. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  195. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  196. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  197. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  198. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  199. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  200. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  201. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  202. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  203. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  204. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  205. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  206. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  207. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  208. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  209. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  210. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  211. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  212. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  213. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  214. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  215. package/project-template-v2/.claude/settings.json +0 -33
  216. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  217. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  218. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  219. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  220. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  221. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  222. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  223. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  224. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  225. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  226. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  227. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  228. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  229. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  230. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  231. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  232. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  233. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  234. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  235. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  236. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  237. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  238. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  239. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  240. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  241. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  242. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  243. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  244. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  245. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  246. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  247. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  248. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  249. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  250. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  251. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  252. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  253. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  254. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  255. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  256. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  257. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  258. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  259. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  260. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  261. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  262. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  263. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  264. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  265. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  266. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  267. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  268. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  269. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  270. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  271. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  272. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  273. package/project-template-v2/.claude/snapshot.mjs +0 -263
  274. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  275. package/project-template-v2/CLAUDE.md +0 -146
  276. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  277. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  278. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  279. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  280. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  281. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  282. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  283. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  284. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  285. package/project-template-v2/assets/models/.gitkeep +0 -0
  286. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  287. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  288. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  289. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  290. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  291. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  292. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  293. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  294. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  295. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  296. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  297. package/project-template-v2/docs/project-state.json +0 -60
  298. package/project-template-v2/docs/project-state.md +0 -72
  299. package/project-template-v2/docs/standards/README.md +0 -225
  300. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  301. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  302. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  303. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  304. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  305. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  306. package/project-template-v2/game/index.ts +0 -18
  307. package/project-template-v2/globals.d.ts +0 -51
  308. package/project-template-v2/index.css +0 -34
  309. package/project-template-v2/index.html +0 -18
  310. package/project-template-v2/main.ts +0 -9
  311. package/project-template-v2/package.json +0 -46
  312. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  313. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  314. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  315. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  316. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  317. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  318. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  319. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  320. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  321. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  322. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  323. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  324. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  325. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  326. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  327. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  328. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  329. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  330. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  331. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  332. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  333. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  334. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  335. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  336. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  337. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  338. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  339. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  340. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  341. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  342. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  343. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  344. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  345. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  346. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  347. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  348. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  349. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  350. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  351. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  352. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  353. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  354. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  355. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  356. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  357. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  358. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  359. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  360. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  361. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  362. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  363. package/project-template-v2/tsconfig.json +0 -20
  364. package/project-template-v2/vite.config.ts +0 -27
  365. package/project-templates/batch-locks/phaser.yaml +0 -922
  366. package/project-templates/batch-locks/threejs.yaml +0 -978
  367. package/project-templates/empty/AGENTS.md +0 -41
  368. package/project-templates/empty/gitignore +0 -33
@@ -1,53 +0,0 @@
1
- import { recordPlayable } from '../recording/recorder.js';
2
- import { RecordingError, recordingMessage as t } from '../recording/messages.js';
3
- import { dirname, join } from 'node:path';
4
- import { captureGeneratedArtifact } from '../workspace-runtime/workspaces/artifact-receipts.js';
5
- export async function runPlayableRecord(options) {
6
- const interrupted = new AbortController();
7
- const deadline = new AbortController();
8
- const onInterrupt = () => interrupted.abort(new DOMException('Interrupted', 'AbortError'));
9
- process.once('SIGINT', onInterrupt);
10
- let timer;
11
- try {
12
- const seconds = options.timeout === undefined ? 1200 : Number(options.timeout);
13
- if (!Number.isFinite(seconds) || seconds <= 0 || seconds > 1800)
14
- throw new RecordingError('invalidArguments', 64);
15
- timer = setTimeout(() => deadline.abort(new DOMException('Timed out', 'TimeoutError')), seconds * 1000);
16
- const result = await recordPlayable(options, AbortSignal.any([interrupted.signal, deadline.signal]));
17
- const metadata = result.envelope.result;
18
- const output = result.envelope.artifacts;
19
- if (result.envelope.ok && metadata && output?.candidate) {
20
- const artifacts = [metadata.candidate, ...metadata.controls];
21
- const paths = [output.candidate, ...(output.controls ?? [])];
22
- for (let index = 0; index < artifacts.length; index++) {
23
- const artifact = artifacts[index], path = paths[index];
24
- if (!path)
25
- continue;
26
- const thumbnail = artifact.screenshots?.[0]?.path;
27
- await captureGeneratedArtifact(path, 'playable record', {
28
- width: artifact.video.source.width, height: artifact.video.source.height,
29
- duration: artifact.video.source.durationMs / 1000,
30
- ...(thumbnail ? { thumbnailPath: join(dirname(output.metadata), thumbnail) } : {}),
31
- });
32
- }
33
- }
34
- process.stdout.write(`${JSON.stringify(result.envelope)}\n`);
35
- process.exitCode = result.exitCode;
36
- }
37
- catch (error) {
38
- const code = error instanceof RecordingError ? error.code : 'recordingFailed';
39
- process.stdout.write(`${JSON.stringify({ schemaVersion: 'playcraft.video-cli.v1', command: 'playable record', state: 'failed', ok: false, error: { code, message: t(code) } })}\n`);
40
- process.exitCode = error instanceof RecordingError ? error.exitCode : 4;
41
- }
42
- finally {
43
- if (timer)
44
- clearTimeout(timer);
45
- process.removeListener('SIGINT', onInterrupt);
46
- }
47
- }
48
- export function registerPlayableCommands(program) {
49
- program.command('playable').description(t('topic')).command('record').description(t('record'))
50
- .option('--url <url>', t('url')).option('--scenario <file>', t('scenario')).option('--out <directory>', t('out'))
51
- .option('--browser-path <path>', t('browser')).option('--timeout <seconds>', t('timeout'))
52
- .action(runPlayableRecord);
53
- }
@@ -1,87 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { batchCreateSchema, batchPromptCreateSchema } from '@playcraft/common/cloud-workspace/runtime';
3
- import { AgentApiClient } from '../utils/agent-api-client.js';
4
- import { handleError } from './tools-utils.js';
5
- const messages = {
6
- en: {
7
- create: 'Create and automatically run independent Remix variants from one prompt',
8
- input: 'Path to the batch draft JSON (JavaScript Object Notation, 数据交换格式) file',
9
- status: 'Read a batch and its generation status',
10
- id: 'Batch identifier',
11
- created: 'Batch created',
12
- prompt: 'The complete batch generation request', workspace: 'Source workspace identifier',
13
- directory: 'Source engineering directory; defaults to basic', request: 'Stable batch creation identity for retries',
14
- team: 'Team identifier for a standalone workspace', invalidMode: 'Provide either --prompt with --workspace-id or --input, exclusively.',
15
- requestRequired: 'Prompt creation requires a stable --client-request-id; reuse it when retrying the same request.',
16
- help: '\nUse --prompt with --workspace-id and a stable --client-request-id. The platform plans and generates independent Remix directories while preserving the source. An omitted count defaults to 3; maximum 10. --input also accepts existing structured drafts.\n',
17
- confirmation: 'Generation is queued. Read the batch status to track its results.',
18
- review: 'This existing draft requires baseline approval in the browser.',
19
- },
20
- zh: {
21
- create: '用一个 prompt 创建并自动生成独立 Remix 变体',
22
- input: '批次草案 JSON (JavaScript Object Notation, 数据交换格式) 文件路径',
23
- status: '查询批次及生成状态',
24
- id: '批次标识',
25
- created: '批次已创建',
26
- prompt: '完整的批量生成需求', workspace: '来源 workspace 标识',
27
- directory: '来源工程目录,默认 basic', request: '用于重试的稳定批次创建标识',
28
- team: '独立工作区所属团队标识', invalidMode: '请选择 --prompt 配合 --workspace-id,或 --input,两种方式不能同时使用。',
29
- requestRequired: '使用 prompt 创建时必须提供稳定的 --client-request-id,重试同一请求时复用该标识。',
30
- help: '\n使用 --prompt、--workspace-id 和稳定的 --client-request-id。平台自动规划,在副本中生成独立 Remix,保持来源不变。未指定数量默认 3 个,最多 10 个。--input 也兼容现有结构化草案。\n',
31
- confirmation: '生成已排队,可查询批次状态追踪各项成果。',
32
- review: '此历史草案需要在浏览器确认基准。',
33
- },
34
- };
35
- const language = () => /^zh/i.test(process.env.PLAYCRAFT_LANG ?? process.env.LANG ?? '') ? messages.zh : messages.en;
36
- export async function createBatchDraft(path, client = new AgentApiClient()) {
37
- const draft = batchCreateSchema.parse(JSON.parse(await readFile(path, 'utf8')));
38
- return client.post('/create-batch', draft);
39
- }
40
- export async function createPromptBatch(input, client = new AgentApiClient()) {
41
- return client.post('/create-batch', batchPromptCreateSchema.parse(input));
42
- }
43
- export function registerBatchCommands(tools) {
44
- const t = language();
45
- tools.command('create-batch')
46
- .description(t.create)
47
- .option('--input <path>', t.input)
48
- .option('--prompt <text>', t.prompt)
49
- .option('--workspace-id <id>', t.workspace)
50
- .option('--source-directory <name>', t.directory, 'basic')
51
- .option('--client-request-id <id>', t.request)
52
- .option('--team-id <id>', t.team)
53
- .option('--json', 'JSON (JavaScript Object Notation, 数据交换格式)')
54
- .addHelpText('after', t.help)
55
- .action(async (opts) => {
56
- try {
57
- if (Boolean(opts.input) === Boolean(opts.prompt))
58
- throw new Error(t.invalidMode);
59
- if (opts.prompt && !opts.workspaceId)
60
- throw new Error(t.invalidMode);
61
- if (opts.prompt && !opts.clientRequestId)
62
- throw new Error(t.requestRequired);
63
- const result = opts.input ? await createBatchDraft(opts.input) : await createPromptBatch({
64
- clientRequestId: opts.clientRequestId, prompt: opts.prompt,
65
- sourceWorkspaceId: opts.workspaceId, sourceDirectoryName: opts.sourceDirectory,
66
- ...(opts.teamId ? { teamId: opts.teamId } : {}),
67
- });
68
- console.log(opts.json ? JSON.stringify(result, null, 2) : `${t.created}: ${result.batchId}\n${result.manifest.autoStart ? t.confirmation : t.review}`);
69
- }
70
- catch (error) {
71
- handleError(error);
72
- }
73
- });
74
- tools.command('get-batch')
75
- .description(t.status)
76
- .requiredOption('--batch-id <id>', t.id)
77
- .action(async (opts) => {
78
- try {
79
- const client = new AgentApiClient();
80
- const result = await client.get('/get-batch', { batchId: opts.batchId });
81
- console.log(JSON.stringify(result, null, 2));
82
- }
83
- catch (error) {
84
- handleError(error);
85
- }
86
- });
87
- }
@@ -1,111 +0,0 @@
1
- import { videoAnalysisRunSchema, videoModelCatalogSchema } from '@playcraft/common/agent-tools';
2
- import { AgentApiClient } from '../utils/agent-api-client.js';
3
- import { executeVideoUnderstanding, readVideoRun, requireVideoId, resolveVideoWorkspace, videoTimeout, } from '../video-replication/client.js';
4
- import { materializeVideoEvidence } from '../video-replication/evidence.js';
5
- import { probeVideo } from '../video-replication/media.js';
6
- import { VideoCliError, videoMessage as t } from '../video-replication/messages.js';
7
- import { comparisonMessage as c } from '../video-replication/comparison-messages.js';
8
- import { executeVideoComparison, readComparisonRun, comparisonRunResult } from '../video-replication/comparison.js';
9
- import { materializeComparisonEvidence } from '../video-replication/comparison-evidence.js';
10
- /** One final structured stdout record; progress and diagnostics stay on stderr. */
11
- export async function runVideoCliAction(command, options, action) {
12
- const interrupt = new AbortController();
13
- const onInterrupt = () => interrupt.abort(new DOMException('Interrupted', 'AbortError'));
14
- process.once('SIGINT', onInterrupt);
15
- let timer;
16
- const deadline = new AbortController();
17
- try {
18
- timer = setTimeout(() => deadline.abort(new DOMException('Timed out', 'TimeoutError')), videoTimeout(options));
19
- const result = await action(AbortSignal.any([interrupt.signal, deadline.signal]));
20
- process.stdout.write(`${JSON.stringify(result.envelope)}\n`);
21
- process.exitCode = result.exitCode;
22
- }
23
- catch (error) {
24
- const key = error instanceof VideoCliError ? error.code : interrupt.signal.aborted ? 'interrupted' : deadline.signal.aborted ? 'timeoutReached' : 'failed';
25
- const envelope = {
26
- schemaVersion: 'playcraft.video-cli.v1', command, state: interrupt.signal.aborted || deadline.signal.aborted ? 'uncertain' : 'failed', ok: false,
27
- error: { code: key, message: t(key) },
28
- };
29
- process.stdout.write(`${JSON.stringify(envelope)}\n`);
30
- process.exitCode = error instanceof VideoCliError ? error.exitCode : interrupt.signal.aborted ? 130 : deadline.signal.aborted ? 75 : 4;
31
- }
32
- finally {
33
- if (timer)
34
- clearTimeout(timer);
35
- process.removeListener('SIGINT', onInterrupt);
36
- }
37
- }
38
- function shared(command) {
39
- return command.option('--workspace <id>', t('workspace')).option('--timeout <seconds>', t('timeout'));
40
- }
41
- export function registerVideoCommands(program) {
42
- const video = program.command('video').description(t('topic'));
43
- shared(video.command('models').description(t('models')))
44
- .option('--json', t('json'))
45
- .action((options) => runVideoCliAction('video models', options, async (signal) => {
46
- const workspaceId = await resolveVideoWorkspace(options.workspace);
47
- const catalog = videoModelCatalogSchema.parse(await new AgentApiClient().get('/video-models', { workspaceId }, { signal }));
48
- return { exitCode: 0, envelope: { schemaVersion: 'playcraft.video-cli.v1', command: 'video models', state: 'completed', ok: true, result: catalog } };
49
- }));
50
- shared(video.command('understand').description(t('understand')))
51
- .option('--video <path>', t('video')).option('--question <text>', t('question'))
52
- .option('--context <path>', t('context')).option('--processing <mode>', t('processing'))
53
- .option('--fps <number>', t('fps')).option('--clip <start:end>', t('clip'))
54
- .option('--model-config <id>', t('model')).option('--out <directory>', t('out'))
55
- .option('--resume <runId>', t('resume'))
56
- .action((options) => runVideoCliAction('video understand', options, signal => executeVideoUnderstanding(options, signal, {
57
- client: new AgentApiClient(), probe: probeVideo, materialize: materializeVideoEvidence,
58
- progress: key => process.stderr.write(`[video] ${t(key)}\n`),
59
- })));
60
- shared(video.command('compare').description(c('compare')))
61
- .option('--reference <path>', c('reference')).option('--analysis <path>', c('analysis'))
62
- .option('--candidate <path>', c('candidate')).option('--recording <path>', c('recording'))
63
- .option('--policy <path>', c('policy')).option('--processing <mode>', c('processing'))
64
- .option('--fps <number>', t('fps')).option('--model-config <id>', t('model'))
65
- .option('--out <directory>', t('out')).option('--resume <runId>', t('resume'))
66
- .action((options) => runVideoCliAction('video compare', options, signal => executeVideoComparison(options, signal, {
67
- client: new AgentApiClient(), probe: probeVideo, materialize: materializeComparisonEvidence,
68
- progress: key => process.stderr.write(`[video] ${t(key)}\n`),
69
- })));
70
- const jobs = video.command('jobs').description(t('jobs'));
71
- shared(jobs.command('get <runId>').description(t('get')))
72
- .option('--kind <kind>', c('kind'))
73
- .action((runId, options) => runVideoCliAction('video jobs get', options, async (signal) => {
74
- const workspaceId = await resolveVideoWorkspace(options.workspace);
75
- if (options.kind !== undefined && !['understanding', 'comparison'].includes(options.kind))
76
- throw new VideoCliError('invalidArguments', 64);
77
- if (options.kind === 'comparison') {
78
- const run = await readComparisonRun(new AgentApiClient(), requireVideoId(runId), workspaceId, signal);
79
- return comparisonRunResult('video jobs get', run);
80
- }
81
- const run = await readVideoRun(new AgentApiClient(), requireVideoId(runId), workspaceId, signal);
82
- return { exitCode: run.state === 'uncertain' ? 75 : run.state === 'failed' || run.state === 'cancelled' ? 4 : 0, envelope: {
83
- schemaVersion: 'playcraft.video-cli.v1', command: 'video jobs get', runId: run.runId, state: run.state,
84
- ok: !['failed', 'uncertain', 'cancelled'].includes(run.state), result: run,
85
- } };
86
- }));
87
- shared(jobs.command('cancel <runId>').description(t('cancel')))
88
- .option('--kind <kind>', c('kind'))
89
- .action((identifier, options) => runVideoCliAction('video jobs cancel', options, async (signal) => {
90
- const workspaceId = await resolveVideoWorkspace(options.workspace);
91
- const runId = requireVideoId(identifier);
92
- if (options.kind !== undefined && !['understanding', 'comparison'].includes(options.kind))
93
- throw new VideoCliError('invalidArguments', 64);
94
- if (options.kind === 'comparison') {
95
- const run = await readComparisonRun(new AgentApiClient(), runId, workspaceId, signal, true);
96
- const confirmed = run.state === 'cancelled';
97
- return { exitCode: confirmed ? 0 : 75, envelope: {
98
- schemaVersion: 'playcraft.video-cli.v1', command: 'video jobs cancel', runId, state: run.state,
99
- ok: confirmed, result: { ...run, cancellationConfirmed: confirmed },
100
- } };
101
- }
102
- const run = videoAnalysisRunSchema.parse(await new AgentApiClient().post(`/video-analysis/${runId}/cancel`, { workspaceId, runId }, { signal }));
103
- if (run.runId !== runId || run.workspaceId !== workspaceId)
104
- throw new VideoCliError('invalidResult');
105
- const confirmed = run.state === 'cancelled';
106
- return { exitCode: confirmed ? 0 : 75, envelope: {
107
- schemaVersion: 'playcraft.video-cli.v1', command: 'video jobs cancel', runId, state: run.state,
108
- ok: confirmed, result: { ...run, cancellationConfirmed: confirmed },
109
- } };
110
- }));
111
- }
@@ -1,54 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { INCOMPATIBLE_EXIT_CODE, parseSandboxRuntimeConfig, } from '@playcraft/common/cloud-workspace/runtime';
3
- import { startWorkspaceRuntime } from '../workspace-runtime/serve.js';
4
- export async function runWorkspaceRuntimeServe(configPath) {
5
- process.env.PLAYCRAFT_SKIP_UPDATE_CHECK = '1';
6
- let config;
7
- try {
8
- config = parseSandboxRuntimeConfig(JSON.parse(await readFile(configPath, 'utf8')));
9
- }
10
- catch (error) {
11
- const message = error instanceof Error ? error.message : String(error);
12
- console.error(`workspace-runtime config invalid: ${message}`);
13
- process.exitCode = INCOMPATIBLE_EXIT_CODE;
14
- return;
15
- }
16
- try {
17
- const runtime = await startWorkspaceRuntime(config, { configPath });
18
- console.log(JSON.stringify({
19
- status: 'listening',
20
- url: runtime.url,
21
- phase: 'awaiting_native',
22
- protocolMajor: runtime.config.protocolMajor,
23
- protocolMinor: runtime.config.protocolMinor,
24
- }));
25
- await new Promise((resolve) => {
26
- const stop = () => {
27
- void runtime.close().finally(resolve);
28
- };
29
- process.once('SIGINT', stop);
30
- process.once('SIGTERM', stop);
31
- });
32
- }
33
- catch (error) {
34
- const code = error.code;
35
- if (code === 'protocol_incompatible' || code === 'duplicate_instance') {
36
- console.error(error instanceof Error ? error.message : code);
37
- process.exitCode = INCOMPATIBLE_EXIT_CODE;
38
- return;
39
- }
40
- throw error;
41
- }
42
- }
43
- export function registerWorkspaceRuntimeCommands(program) {
44
- const workspaceRuntime = program
45
- .command('workspace-runtime')
46
- .description('沙箱内 Sandbox Agent Server(Cloud Workspace 常驻运行入口)');
47
- workspaceRuntime
48
- .command('serve')
49
- .description('前台常驻:读取 Runtime Server 下发的配置,不启动本地 backend 或旧同步')
50
- .requiredOption('--config <path>', 'Runtime 引导配置 JSON')
51
- .action(async (options) => {
52
- await runWorkspaceRuntimeServe(options.config);
53
- });
54
- }
@@ -1,35 +0,0 @@
1
- import { workspaceClone, workspacePush } from '../workspace/transfer-client.js';
2
- import { workspaceMessage as message } from '../workspace/messages.js';
3
- export function registerWorkspaceCommands(program) {
4
- const run = async (command, options) => {
5
- try {
6
- if (command === 'clone')
7
- await workspaceClone({ ...options, workspaceId: options?.workspaceId ?? '' });
8
- else
9
- await workspacePush(options);
10
- }
11
- catch (error) {
12
- const detail = error instanceof Error ? error.message : String(error);
13
- if (options?.json)
14
- console.log(JSON.stringify({ ok: false, command: `workspace.${command}`, error: { message: detail } }));
15
- else
16
- console.error(detail);
17
- process.exitCode = 1;
18
- }
19
- };
20
- const workspace = program.command('workspace').description(message('description'));
21
- workspace.command('clone').description(message('clone'))
22
- .requiredOption('--workspace-id <id>', message('workspaceId'))
23
- .option('--directory <name>', message('directory'), 'basic')
24
- .option('--dir <path>', message('target'))
25
- .option('--url <url>', message('url'))
26
- .option('--token <token>', message('token'))
27
- .option('--json', message('json'))
28
- .action(options => run('clone', options));
29
- workspace.command('push').description(message('push'))
30
- .option('--dir <path>', message('target'))
31
- .option('--url <url>', message('url'))
32
- .option('--token <token>', message('token'))
33
- .option('--json', message('json'))
34
- .action(options => run('push', options));
35
- }
@@ -1,225 +0,0 @@
1
- import { createHash, randomUUID } from 'node:crypto';
2
- import { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
- import { basename, join } from 'node:path';
4
- import { canonicalProjectSkillsJson, declarationDigest, dependencyDigest, extractBundleArchive, readProjectSkillSource, readProjectSkillsLockFile, validateProjectSkillsSnapshot, PROJECT_SKILLS_DECLARATION_PATH, PROJECT_SKILLS_LOCK_PATH, } from '@playcraft/common/project-skills';
5
- import { LEGACY_VIDEO_SOURCE_HASHES } from '@playcraft/common/cloud-workspace/runtime';
6
- import { projectSkillsCache } from './local-store.js';
7
- export const IMPORTABLE_BUILTIN_SKILLS = ['playcraft-video-understanding', 'playcraft-replica-validation'];
8
- export const platformSkillRef = (name) => `remix/${name}`;
9
- const hash = (value) => createHash('sha256').update(canonicalProjectSkillsJson(value)).digest('hex');
10
- async function safeDirectory(root, path) {
11
- let current = root;
12
- for (const part of path.split('/')) {
13
- current = join(current, part);
14
- await mkdir(current, { mode: 0o755 }).catch(error => { if (error.code !== 'EEXIST')
15
- throw error; });
16
- const stat = await lstat(current);
17
- if (!stat.isDirectory() || stat.isSymbolicLink())
18
- throw new Error('workspace_skills_invalid');
19
- }
20
- return current;
21
- }
22
- /** Selects published platform revisions once; neither directory contents nor names authorize a replacement. */
23
- export async function selectPlatformSkillSnapshot(names, access) {
24
- if (!names.length || new Set(names).size !== names.length
25
- || names.some(name => !IMPORTABLE_BUILTIN_SKILLS.includes(name)))
26
- throw new Error('workspace_skills_builtin_unknown');
27
- if (!access)
28
- throw new Error('workspace_skills_platform_required');
29
- const requested = names.map(platformSkillRef);
30
- const response = await access.resolve(requested);
31
- const snapshot = validateProjectSkillsSnapshot(response?.declaration, response?.lock);
32
- if (snapshot.declaration.entries.length !== names.length || snapshot.lock.entries.length !== names.length)
33
- throw new Error('workspace_skills_invalid');
34
- for (const name of names) {
35
- const entry = snapshot.declaration.entries.find(item => item.entryKey === name);
36
- const locked = snapshot.lock.entries.find(item => item.entryKey === name);
37
- if (!entry || !locked || entry.source.kind !== 'registry' || entry.source.skillRef !== platformSkillRef(name)
38
- || entry.surface !== 'sandbox-agent' || !entry.enabled || locked.revision.kind !== 'release'
39
- || locked.dependencies.length !== 0 || locked.dependencyLockHash !== dependencyDigest([], []))
40
- throw new Error('workspace_skills_invalid');
41
- }
42
- const artifacts = await Promise.all(snapshot.lock.entries.map(async (entry) => {
43
- const archive = await access.loadArtifact(entry);
44
- if (archive.length > 80 * 1024 * 1024 || createHash('sha256').update(archive).digest('hex') !== entry.revision.artifactHash)
45
- throw new Error('workspace_skills_digest_mismatch');
46
- const extracted = extractBundleArchive(archive);
47
- if (extracted.issues.length || !extracted.files.some(file => file.path === 'SKILL.md'))
48
- throw new Error('workspace_skills_invalid_bundle');
49
- return { artifactHash: entry.revision.artifactHash, archive };
50
- }));
51
- return { ...snapshot, artifacts };
52
- }
53
- async function commitSnapshot(directory, snapshot, originalDeclaration, staged) {
54
- const declarationPath = join(directory, PROJECT_SKILLS_DECLARATION_PATH);
55
- const pending = [];
56
- for (const [path, value] of [[PROJECT_SKILLS_DECLARATION_PATH, snapshot.declaration], [PROJECT_SKILLS_LOCK_PATH, snapshot.lock]]) {
57
- const temporary = `${join(directory, path)}.${randomUUID()}.tmp`;
58
- staged.push(temporary);
59
- await writeFile(temporary, `${canonicalProjectSkillsJson(value)}\n`, { flag: 'wx', mode: 0o644 });
60
- pending.push(temporary);
61
- }
62
- await rename(pending[0], declarationPath);
63
- try {
64
- await rename(pending[1], join(directory, PROJECT_SKILLS_LOCK_PATH));
65
- }
66
- catch (error) {
67
- // The old lock still exists. Restore its exact declaration before releasing the writer lease.
68
- const restore = `${declarationPath}.${randomUUID()}.tmp`;
69
- staged.push(restore);
70
- await writeFile(restore, originalDeclaration, { flag: 'wx', mode: 0o644 });
71
- await rename(restore, declarationPath);
72
- throw error;
73
- }
74
- }
75
- async function cacheArtifacts(cache, selected) {
76
- await mkdir(cache, { recursive: true, mode: 0o700 });
77
- for (const artifact of selected.artifacts) {
78
- const path = join(cache, `${artifact.artifactHash}.tar.gz`);
79
- try {
80
- await writeFile(path, artifact.archive, { flag: 'wx', mode: 0o600 });
81
- }
82
- catch (error) {
83
- if (error.code !== 'EEXIST' || !(await readFile(path)).equals(artifact.archive))
84
- throw error;
85
- }
86
- }
87
- }
88
- /** Explicit imports keep prior locks and unsynced repository sources byte-for-byte. */
89
- export async function importBuiltinProjectSkills(directory, options, cache = projectSkillsCache(), access, selected, enabled = false) {
90
- if (!options.names.length || new Set(options.names).size !== options.names.length
91
- || options.names.some(name => !IMPORTABLE_BUILTIN_SKILLS.includes(name)))
92
- throw new Error('workspace_skills_builtin_unknown');
93
- const management = await safeDirectory(directory, '.playcraft');
94
- const lease = join(management, 'skills-write.lock');
95
- await writeFile(lease, `${process.pid}\n`, { flag: 'wx', mode: 0o600 });
96
- const staged = [];
97
- try {
98
- const declarationPath = join(directory, PROJECT_SKILLS_DECLARATION_PATH);
99
- const declarationStat = await lstat(declarationPath);
100
- if (!declarationStat.isFile() || declarationStat.isSymbolicLink() || declarationStat.size > 1024 * 1024)
101
- throw new Error('workspace_skills_invalid');
102
- const originalDeclaration = await readFile(declarationPath);
103
- const previous = validateProjectSkillsSnapshot(originalDeclaration.toString('utf8'), await readProjectSkillsLockFile(directory));
104
- if (options.expectedDeclarationHash !== previous.lock.declarationHash || options.expectedLockHash !== hash(previous.lock))
105
- throw new Error('skills_revision_conflict');
106
- const next = structuredClone(previous);
107
- const unchanged = [], missing = [];
108
- for (const name of options.names) {
109
- const existing = previous.declaration.entries.find(entry => entry.source.kind === 'registry' && entry.source.skillRef === platformSkillRef(name));
110
- if (existing) {
111
- unchanged.push(existing.entryKey);
112
- continue;
113
- }
114
- if (previous.declaration.entries.some(entry => entry.entryKey === name || entry.source.kind === 'repository' && basename(entry.source.root) === name))
115
- throw new Error('workspace_skills_builtin_conflict');
116
- for (const sourceRoot of ['.agents/skills', '.claude/skills', '.opencode/skills', '.opencode/skill']) {
117
- if (await lstat(join(directory, sourceRoot, name)).then(() => true, error => { if (error.code === 'ENOENT')
118
- return false; throw error; }))
119
- throw new Error('workspace_skills_builtin_conflict');
120
- }
121
- missing.push(name);
122
- }
123
- const imported = [];
124
- if (missing.length) {
125
- const resolved = selected ?? await selectPlatformSkillSnapshot(missing, access);
126
- await cacheArtifacts(cache, resolved);
127
- for (const name of missing) {
128
- const entry = resolved.declaration.entries.find(item => item.entryKey === name);
129
- const locked = resolved.lock.entries.find(item => item.entryKey === name);
130
- if (!entry || !locked)
131
- throw new Error('workspace_skills_invalid');
132
- next.declaration.entries.push({ ...entry, enabled });
133
- next.lock.entries.push(locked);
134
- imported.push(name);
135
- }
136
- next.lock.declarationHash = declarationDigest(next.declaration);
137
- validateProjectSkillsSnapshot(next.declaration, next.lock);
138
- await commitSnapshot(directory, next, originalDeclaration, staged);
139
- }
140
- return { ...next, imported, unchanged, lockHash: hash(next.lock) };
141
- }
142
- finally {
143
- for (const path of staged)
144
- await rm(path, { force: true });
145
- await rm(lease, { force: true });
146
- }
147
- }
148
- /** Only original bundled sources qualify; changed or forked skills require a separate explicit user decision. */
149
- export async function migrateVideoProjectSkills(directory, options, cache, access) {
150
- const management = await safeDirectory(directory, '.playcraft');
151
- const lease = join(management, 'skills-write.lock');
152
- await writeFile(lease, `${process.pid}\n`, { flag: 'wx', mode: 0o600 });
153
- const moved = [];
154
- const staged = [];
155
- let committed = false;
156
- try {
157
- const declarationPath = join(directory, PROJECT_SKILLS_DECLARATION_PATH);
158
- const declarationStat = await lstat(declarationPath);
159
- if (!declarationStat.isFile() || declarationStat.isSymbolicLink() || declarationStat.size > 1024 * 1024)
160
- throw new Error('workspace_skills_invalid');
161
- const originalDeclaration = await readFile(declarationPath);
162
- const previous = validateProjectSkillsSnapshot(originalDeclaration.toString('utf8'), await readProjectSkillsLockFile(directory));
163
- const oldLockHash = hash(previous.lock);
164
- if (options.expectedDeclarationHash !== previous.lock.declarationHash || options.expectedLockHash !== oldLockHash)
165
- throw new Error('skills_revision_conflict');
166
- if (!options.entryKeys.length || options.entryKeys.length > 2 || new Set(options.entryKeys).size !== options.entryKeys.length)
167
- throw new Error('workspace_skills_builtin_unknown');
168
- const replacements = [];
169
- for (const key of options.entryKeys) {
170
- const entry = previous.declaration.entries.find(item => item.entryKey === key);
171
- const locked = previous.lock.entries.find(item => item.entryKey === key);
172
- if (!entry || !locked || entry.source.kind !== 'repository' || locked.revision.kind !== 'source'
173
- || entry.surface !== 'sandbox-agent' || entry.projectFiles?.length || locked.dependencies.length
174
- || previous.lock.entries.some(item => item.entryKey !== key && item.dependencies.includes(key)))
175
- throw new Error('workspace_skills_builtin_conflict');
176
- const name = basename(entry.source.root);
177
- const known = LEGACY_VIDEO_SOURCE_HASHES[name];
178
- if (!known || locked.sourceTreeHash !== known || (await readProjectSkillSource(directory, entry)).sourceTreeHash !== known
179
- || previous.declaration.entries.some(item => item.entryKey !== key && (item.entryKey === name || item.source.kind === 'registry' && item.source.skillRef === platformSkillRef(name))))
180
- throw new Error('workspace_skills_builtin_conflict');
181
- replacements.push({ entry, name });
182
- }
183
- const selected = await selectPlatformSkillSnapshot(replacements.map(item => item.name), access);
184
- await cacheArtifacts(cache, selected);
185
- const next = structuredClone(previous);
186
- for (const { entry, name } of replacements) {
187
- const replacement = selected.declaration.entries.find(item => item.entryKey === name);
188
- const locked = selected.lock.entries.find(item => item.entryKey === name);
189
- next.declaration.entries[next.declaration.entries.findIndex(item => item.entryKey === entry.entryKey)] = { ...replacement, entryKey: entry.entryKey, enabled: entry.enabled };
190
- next.lock.entries[next.lock.entries.findIndex(item => item.entryKey === entry.entryKey)] = { ...locked, entryKey: entry.entryKey };
191
- }
192
- for (const locked of next.lock.entries)
193
- locked.dependencyLockHash = dependencyDigest(next.lock.entries, locked.dependencies);
194
- next.lock.declarationHash = declarationDigest(next.declaration);
195
- validateProjectSkillsSnapshot(next.declaration, next.lock);
196
- const history = await safeDirectory(directory, `.playcraft/skill-migrations/${oldLockHash}`);
197
- const receipt = { schemaVersion: 'playcraft.skill-migration.v1', previous, next, entryKeys: options.entryKeys };
198
- const historyFile = join(history, 'migration.json');
199
- try {
200
- await writeFile(historyFile, `${canonicalProjectSkillsJson(receipt)}\n`, { flag: 'wx', mode: 0o644 });
201
- }
202
- catch (error) {
203
- if (error.code !== 'EEXIST' || await readFile(historyFile, 'utf8') !== `${canonicalProjectSkillsJson(receipt)}\n`)
204
- throw error;
205
- }
206
- for (const { entry } of replacements) {
207
- if (entry.source.kind !== 'repository')
208
- throw new Error('workspace_skills_invalid');
209
- const from = join(directory, entry.source.root), to = join(history, entry.entryKey);
210
- await rename(from, to);
211
- moved.push({ from, to });
212
- }
213
- await commitSnapshot(directory, next, originalDeclaration, staged);
214
- committed = true;
215
- return { ...next, migrated: options.entryKeys, history: `.playcraft/skill-migrations/${oldLockHash}/migration.json`, lockHash: hash(next.lock) };
216
- }
217
- finally {
218
- if (!committed)
219
- for (const item of moved.reverse())
220
- await rename(item.to, item.from).catch(() => undefined);
221
- for (const path of staged)
222
- await rm(path, { force: true });
223
- await rm(lease, { force: true });
224
- }
225
- }
@@ -1,77 +0,0 @@
1
- import { verifyLocalProjectSkills } from './validation.js';
2
- export { verifyLocalProjectSkills } from './validation.js';
3
- import { downloadLocalProjectSkillArtifacts } from './remote-cache.js';
4
- import { resolve } from 'node:path';
5
- import { inspectProjectSkills, } from '@playcraft/common/project-skills';
6
- import { syncLocalProjectSkills, enableLocalProjectSkill, installFrozenProjectSkills, explainLocalProjectSkills } from './local-store.js';
7
- import { runLocalProjectSkills, localProjectSkillUsage } from './local-run.js';
8
- import { projectSkillsMessage as t } from './messages.js';
9
- import { reconcileLocalProjectSkills } from './reconcile.js';
10
- import { importBuiltinProjectSkills } from './builtin-import.js';
11
- export async function inspectLocalProjectSkills(directory) {
12
- const inventory = await inspectProjectSkills(directory);
13
- // Report metadata only; never print complete skill bytes or project test data.
14
- return { declaration: inventory.declaration, discovered: inventory.discovered, issues: inventory.issues,
15
- sources: inventory.sources.map((source) => ({ entryKey: source.entryKey, root: source.root,
16
- sourceTreeHash: source.sourceTreeHash, files: source.files.map((file) => file.path) })) };
17
- }
18
- export function registerProjectSkillsCommands(skills) {
19
- const project = skills.command('project').description(t('description'));
20
- const output = async (action) => {
21
- try {
22
- process.stdout.write(`${JSON.stringify(await action(), null, 2)}\n`);
23
- }
24
- catch (error) {
25
- process.stderr.write(`${t('failed')}: ${error instanceof Error && error.message === 'workspace_skills_platform_required' ? t('platformRequired') : error instanceof Error ? error.message : String(error)}\n`);
26
- process.exitCode = 1;
27
- }
28
- };
29
- project.command('run <prompt>').description(t('run')).requiredOption('--model <provider/model>', t('model'))
30
- .option('--dir <path>', t('directory'), '.').action((prompt, options) => output(async () => {
31
- const result = await runLocalProjectSkills(resolve(options.dir), { prompt, model: options.model });
32
- if (result.exitCode !== 0)
33
- process.exitCode = result.exitCode;
34
- return result;
35
- }));
36
- project.command('usage').description(t('usage')).option('--dir <path>', t('directory'), '.')
37
- .action((options) => output(() => localProjectSkillUsage(resolve(options.dir))));
38
- project.command('sync').description(t('sync')).option('--dir <path>', t('directory'), '.')
39
- .action((options) => output(() => syncLocalProjectSkills(resolve(options.dir))));
40
- project.command('import-builtins <names...>').description(t('importBuiltins')).option('--dir <path>', t('directory'), '.')
41
- .requiredOption('--expected-declaration-hash <hash>', t('expectedDeclarationHash'))
42
- .requiredOption('--expected-lock-hash <hash>', t('expectedLockHash'))
43
- .action((names, options) => output(() => importBuiltinProjectSkills(resolve(options.dir), { ...options, names })));
44
- project.command('reconcile').description(t('reconcile')).option('--dir <path>', t('directory'), '.')
45
- .action((options) => output(() => reconcileLocalProjectSkills(resolve(options.dir), { write: true })));
46
- project.command('install').description(t('install')).requiredOption('--frozen', t('frozen')).option('--dir <path>', t('directory'), '.')
47
- .option('--online', t('online')).action((options) => output(async () => {
48
- const directory = resolve(options.dir);
49
- if (options.online)
50
- await downloadLocalProjectSkillArtifacts(directory);
51
- return installFrozenProjectSkills(directory);
52
- }));
53
- for (const enabled of [true, false])
54
- project.command(enabled ? 'enable <entryKey>' : 'disable <entryKey>')
55
- .description(t(enabled ? 'enable' : 'disable')).option('--dir <path>', t('directory'), '.')
56
- .action((entryKey, options) => output(() => enableLocalProjectSkill(resolve(options.dir), entryKey, enabled)));
57
- project.command('explain').description(t('explain')).option('--dir <path>', t('directory'), '.')
58
- .action((options) => output(() => explainLocalProjectSkills(resolve(options.dir))));
59
- project.command('inspect').description(t('inspect')).option('--dir <path>', t('directory'), '.')
60
- .action(async (options) => {
61
- const result = await inspectLocalProjectSkills(resolve(options.dir));
62
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
63
- if (result.issues.length)
64
- process.exitCode = 1;
65
- });
66
- project.command('verify').description(t('verify')).option('--dir <path>', t('directory'), '.')
67
- .option('--json', t('json')).action(async (options) => {
68
- try {
69
- const result = await verifyLocalProjectSkills(resolve(options.dir));
70
- process.stdout.write(`${options.json ? JSON.stringify(result) : t('verified')}\n`);
71
- }
72
- catch (error) {
73
- process.stderr.write(`${t('failed')}: ${error instanceof Error ? error.message : String(error)}\n`);
74
- process.exitCode = 1;
75
- }
76
- });
77
- }