@playcraft/cli 0.1.33 → 0.1.35-prod

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +3 -56
  2. package/dist/agent/local-backend.js +1 -1
  3. package/dist/cli-root-help.js +0 -2
  4. package/dist/commands/build.js +4 -9
  5. package/dist/commands/create.js +33 -26
  6. package/dist/commands/image.js +6 -2
  7. package/dist/commands/login.js +42 -84
  8. package/dist/commands/skills.js +0 -2
  9. package/dist/commands/tools-3d.js +0 -11
  10. package/dist/commands/tools-generation.js +109 -68
  11. package/dist/commands/tools-image-context.js +23 -0
  12. package/dist/commands/tools.js +2 -2
  13. package/dist/config.js +4 -59
  14. package/dist/index.js +3 -36
  15. package/dist/remix/clone.js +0 -2
  16. package/dist/remix/init-template.js +0 -2
  17. package/dist/remix/pull.js +0 -2
  18. package/dist/remix/push.js +1 -21
  19. package/dist/utils/agent-api-client.js +30 -185
  20. package/dist/utils/image-asset-context.js +105 -0
  21. package/dist/utils/playcraft-http-client.js +4 -6
  22. package/package.json +5 -14
  23. package/project-template/.claude/agents/refs/ta-image-generation-detail.md +67 -123
  24. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +105 -44
  25. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  26. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  27. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  28. package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +36 -39
  29. package/project-templates/phaser/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  30. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +105 -44
  31. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  32. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  33. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  34. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +36 -39
  35. package/project-templates/threejs/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  36. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +105 -44
  37. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  38. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  39. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  40. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +36 -39
  41. package/dist/auth/account-activation.js +0 -157
  42. package/dist/auth/messages.js +0 -30
  43. package/dist/commands/platform-skills.generated.js +0 -19
  44. package/dist/commands/playable.js +0 -53
  45. package/dist/commands/tools-batch.js +0 -87
  46. package/dist/commands/video.js +0 -111
  47. package/dist/commands/workspace-runtime.js +0 -54
  48. package/dist/commands/workspace.js +0 -35
  49. package/dist/project-skills/builtin-import.js +0 -225
  50. package/dist/project-skills/commands.js +0 -77
  51. package/dist/project-skills/lifecycle.js +0 -28
  52. package/dist/project-skills/local-run.js +0 -112
  53. package/dist/project-skills/local-store.js +0 -221
  54. package/dist/project-skills/messages.js +0 -80
  55. package/dist/project-skills/reconcile.js +0 -62
  56. package/dist/project-skills/remote-cache.js +0 -51
  57. package/dist/project-skills/validation.js +0 -19
  58. package/dist/recording/messages.js +0 -40
  59. package/dist/recording/project-digest.js +0 -85
  60. package/dist/recording/recorder.js +0 -293
  61. package/dist/recording/scenario.js +0 -50
  62. package/dist/utils/environment-endpoints.js +0 -17
  63. package/dist/utils/tool-operation-journal.js +0 -124
  64. package/dist/utils/video-evidence-git.js +0 -81
  65. package/dist/video-replication/client.js +0 -222
  66. package/dist/video-replication/comparison-evidence.js +0 -149
  67. package/dist/video-replication/comparison-files.js +0 -57
  68. package/dist/video-replication/comparison-log.js +0 -72
  69. package/dist/video-replication/comparison-messages.js +0 -104
  70. package/dist/video-replication/comparison-output.js +0 -63
  71. package/dist/video-replication/comparison-preflight.js +0 -66
  72. package/dist/video-replication/comparison.js +0 -216
  73. package/dist/video-replication/evidence.js +0 -165
  74. package/dist/video-replication/media.js +0 -111
  75. package/dist/video-replication/messages.js +0 -89
  76. package/dist/workspace/messages.js +0 -35
  77. package/dist/workspace/transfer-client.js +0 -174
  78. package/dist/workspace-runtime/codex/app-server.js +0 -965
  79. package/dist/workspace-runtime/codex/compact.js +0 -46
  80. package/dist/workspace-runtime/codex/config-toml.js +0 -107
  81. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
  82. package/dist/workspace-runtime/codex/launcher-client.js +0 -177
  83. package/dist/workspace-runtime/codex/loopback.js +0 -146
  84. package/dist/workspace-runtime/codex/mcp-config.js +0 -39
  85. package/dist/workspace-runtime/codex/model-broker.js +0 -263
  86. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  87. package/dist/workspace-runtime/codex/permissions.js +0 -70
  88. package/dist/workspace-runtime/codex/work-mode.js +0 -15
  89. package/dist/workspace-runtime/main.js +0 -10
  90. package/dist/workspace-runtime/persistence/journal.js +0 -355
  91. package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
  92. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
  93. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1096
  94. package/dist/workspace-runtime/previews/output.js +0 -36
  95. package/dist/workspace-runtime/previews/publish.js +0 -262
  96. package/dist/workspace-runtime/previews/single-file.js +0 -43
  97. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  98. package/dist/workspace-runtime/production/contracts.js +0 -17
  99. package/dist/workspace-runtime/production/controller.js +0 -207
  100. package/dist/workspace-runtime/production/dependencies.js +0 -60
  101. package/dist/workspace-runtime/production/native.js +0 -203
  102. package/dist/workspace-runtime/production/processes.js +0 -86
  103. package/dist/workspace-runtime/production/save-command.js +0 -35
  104. package/dist/workspace-runtime/production/source-copy.js +0 -91
  105. package/dist/workspace-runtime/production/stages.js +0 -205
  106. package/dist/workspace-runtime/production/storage.js +0 -60
  107. package/dist/workspace-runtime/serve.js +0 -207
  108. package/dist/workspace-runtime/server/auth.js +0 -21
  109. package/dist/workspace-runtime/server/connectivity.js +0 -201
  110. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  111. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  112. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  113. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  114. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  115. package/dist/workspace-runtime/server/dispatch.js +0 -1174
  116. package/dist/workspace-runtime/server/endpoints.js +0 -19
  117. package/dist/workspace-runtime/server/execution-group.js +0 -85
  118. package/dist/workspace-runtime/server/http.js +0 -1127
  119. package/dist/workspace-runtime/server/lock.js +0 -53
  120. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  121. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  122. package/dist/workspace-runtime/server/types.js +0 -1
  123. package/dist/workspace-runtime/server/workspace-transfer.js +0 -99
  124. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  125. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  126. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -197
  127. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  128. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  129. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -123
  130. package/dist/workspace-runtime/workspaces/attachments.js +0 -181
  131. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  132. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  133. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -111
  134. package/dist/workspace-runtime/workspaces/composer-context.js +0 -125
  135. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  136. package/dist/workspace-runtime/workspaces/dependencies.js +0 -264
  137. package/dist/workspace-runtime/workspaces/developer-command.js +0 -64
  138. package/dist/workspace-runtime/workspaces/directories.js +0 -123
  139. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  140. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  141. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  142. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  143. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  144. package/dist/workspace-runtime/workspaces/empty-template.js +0 -40
  145. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  146. package/dist/workspace-runtime/workspaces/files.js +0 -120
  147. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  148. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  149. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  150. package/dist/workspace-runtime/workspaces/git.js +0 -658
  151. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  152. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -170
  153. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  154. package/dist/workspace-runtime/workspaces/parameters.js +0 -272
  155. package/dist/workspace-runtime/workspaces/prepare.js +0 -264
  156. package/dist/workspace-runtime/workspaces/registry.js +0 -236
  157. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  158. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -91
  159. package/dist/workspace-runtime/workspaces/skills.js +0 -189
  160. package/dist/workspace-runtime/workspaces/transfer.js +0 -288
  161. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -72
  162. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  163. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  164. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  165. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  166. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  167. package/project-template-v2/.claude/agents/artist.md +0 -82
  168. package/project-template-v2/.claude/agents/developer.md +0 -153
  169. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  170. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  171. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  172. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  173. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  174. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  175. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  176. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  177. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  178. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  179. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  180. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  181. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  182. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  183. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  184. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  185. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  186. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  187. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  188. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  189. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  190. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  191. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  192. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  193. package/project-template-v2/.claude/settings.json +0 -33
  194. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  195. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  196. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  197. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  198. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  199. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  200. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  201. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  202. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  203. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  204. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  205. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  206. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  207. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  208. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  209. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  210. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  211. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  212. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  213. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  214. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  215. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  216. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  217. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  218. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  219. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  220. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  221. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  222. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  223. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  224. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  225. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  226. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  227. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  228. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  229. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  230. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  231. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  232. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  233. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  234. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  235. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  236. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  237. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  238. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  239. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  240. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  241. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  242. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  243. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  244. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  245. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  246. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  247. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  248. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  249. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  250. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  251. package/project-template-v2/.claude/snapshot.mjs +0 -263
  252. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  253. package/project-template-v2/CLAUDE.md +0 -146
  254. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  255. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  256. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  257. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  258. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  259. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  260. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  261. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  262. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  263. package/project-template-v2/assets/models/.gitkeep +0 -0
  264. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  265. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  266. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  267. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  268. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  269. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  270. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  271. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  272. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  273. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  274. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  275. package/project-template-v2/docs/project-state.json +0 -60
  276. package/project-template-v2/docs/project-state.md +0 -72
  277. package/project-template-v2/docs/standards/README.md +0 -225
  278. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  279. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  280. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  281. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  282. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  283. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  284. package/project-template-v2/game/index.ts +0 -18
  285. package/project-template-v2/globals.d.ts +0 -51
  286. package/project-template-v2/index.css +0 -34
  287. package/project-template-v2/index.html +0 -18
  288. package/project-template-v2/main.ts +0 -9
  289. package/project-template-v2/package.json +0 -46
  290. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  291. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  292. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  293. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  294. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  295. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  296. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  297. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  298. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  299. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  300. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  301. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  302. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  303. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  304. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  305. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  306. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  307. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  308. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  309. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  310. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  311. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  312. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  313. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  314. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  315. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  316. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  317. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  318. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  319. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  320. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  321. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  322. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  323. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  324. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  325. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  326. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  327. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  328. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  329. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  330. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  331. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  332. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  333. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  334. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  335. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  336. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  337. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  338. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  339. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  340. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  341. package/project-template-v2/tsconfig.json +0 -20
  342. package/project-template-v2/vite.config.ts +0 -27
  343. package/project-templates/batch-locks/phaser.yaml +0 -922
  344. package/project-templates/batch-locks/threejs.yaml +0 -978
  345. package/project-templates/empty/AGENTS.md +0 -39
  346. package/project-templates/empty/gitignore +0 -33
@@ -1,288 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { createHash, randomUUID } from 'node:crypto';
3
- import { constants } from 'node:fs';
4
- import { chmod, copyFile, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, rmdir, writeFile } from 'node:fs/promises';
5
- import { tmpdir } from 'node:os';
6
- import { dirname, join, resolve, sep } from 'node:path';
7
- import { isCredentialFile } from './git.js';
8
- export const WORKSPACE_TRANSFER_MAX_BYTES = 256 * 1024 * 1024;
9
- const MAX_FILES = 20_000;
10
- const EXCLUDED = new Set(['.git', 'node_modules', '.playcraft-workspace.json', '.playcraft.json']);
11
- export class WorkspaceTransferError extends Error {
12
- code;
13
- constructor(code) {
14
- super(code);
15
- this.code = code;
16
- }
17
- }
18
- function excluded(path) {
19
- const parts = path.split('/');
20
- return parts.some(part => EXCLUDED.has(part.toLowerCase()) || /^\.playcraft-(?:credential|transfer)-.*\.tmp$/i.test(part)) ||
21
- parts.some((part, index) => part === '.playcraft' && /^(?:workspace-context(?:\..*)?|video-replication)$/.test(parts[index + 1] ?? '')) ||
22
- isCredentialFile(path);
23
- }
24
- export function transferGit(root, args) {
25
- const env = { PATH: process.env.PATH, HOME: tmpdir(),
26
- GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: '/dev/null', GIT_TERMINAL_PROMPT: '0', GIT_ALLOW_PROTOCOL: 'file' };
27
- const result = spawnSync('git', ['-c', 'core.hooksPath=/dev/null', '-c', 'commit.gpgsign=false',
28
- '-c', 'core.autocrlf=false', '-c', 'user.name=PlayCraft Workspace', '-c', 'user.email=workspace@playcraft.local', ...args], { cwd: root, encoding: 'utf8', env, timeout: 120_000, maxBuffer: 8 * 1024 * 1024 });
29
- if (result.status !== 0)
30
- throw new WorkspaceTransferError('workspace_transfer_git_failed');
31
- return result.stdout.trim();
32
- }
33
- async function copySnapshot(source, target) {
34
- let bytes = 0, files = 0;
35
- async function copy(directory, prefix) {
36
- const directoryInfo = await lstat(directory);
37
- const directoryReal = await realpath(directory);
38
- if (!directoryInfo.isDirectory() || directoryInfo.isSymbolicLink() ||
39
- (directoryReal !== source && !directoryReal.startsWith(`${source}${sep}`)))
40
- throw new WorkspaceTransferError('workspace_transfer_conflict');
41
- for (const entry of await readdir(directory, { withFileTypes: true })) {
42
- const path = prefix ? `${prefix}/${entry.name}` : entry.name;
43
- if (excluded(path))
44
- continue;
45
- const from = join(directory, entry.name), to = join(target, path);
46
- const info = await lstat(from);
47
- if (info.isSymbolicLink())
48
- continue;
49
- if (info.isDirectory()) {
50
- await mkdir(to, { recursive: true });
51
- await copy(from, path);
52
- }
53
- else if (info.isFile()) {
54
- bytes += info.size;
55
- files++;
56
- if (bytes > WORKSPACE_TRANSFER_MAX_BYTES || files > MAX_FILES)
57
- throw new WorkspaceTransferError('workspace_transfer_too_large');
58
- if (!(await realpath(from)).startsWith(`${source}${sep}`))
59
- throw new WorkspaceTransferError('workspace_transfer_conflict');
60
- const handle = await open(from, constants.O_RDONLY | constants.O_NOFOLLOW);
61
- try {
62
- const before = await handle.stat();
63
- if (!before.isFile() || before.dev !== info.dev || before.ino !== info.ino || before.size !== info.size ||
64
- before.mtimeMs !== info.mtimeMs || before.ctimeMs !== info.ctimeMs)
65
- throw new WorkspaceTransferError('workspace_transfer_conflict');
66
- const chunks = [];
67
- let size = 0;
68
- for await (const chunk of handle.createReadStream({ autoClose: false })) {
69
- size += chunk.length;
70
- if (size > before.size)
71
- throw new WorkspaceTransferError('workspace_transfer_conflict');
72
- chunks.push(chunk);
73
- }
74
- const after = await handle.stat();
75
- if (size !== before.size || after.size !== before.size || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)
76
- throw new WorkspaceTransferError('workspace_transfer_conflict');
77
- await writeFile(to, Buffer.concat(chunks));
78
- }
79
- finally {
80
- await handle.close();
81
- }
82
- await chmod(to, info.mode & 0o111 ? 0o755 : 0o644);
83
- }
84
- }
85
- }
86
- await copy(source, '');
87
- }
88
- async function matchesFile(root, path, expected) {
89
- const target = await safeTarget(root, path);
90
- const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
91
- return undefined; throw error; });
92
- if (!expected)
93
- return !info || info.isDirectory();
94
- if (!info?.isFile() || Boolean(info.mode & 0o111) !== expected.executable)
95
- return false;
96
- const handle = await open(target, constants.O_RDONLY | constants.O_NOFOLLOW);
97
- try {
98
- const stat = await handle.stat();
99
- const hash = createHash(expected.sha.length === 64 ? 'sha256' : 'sha1');
100
- hash.update(`blob ${stat.size}\0`);
101
- for await (const chunk of handle.createReadStream({ autoClose: false }))
102
- hash.update(chunk);
103
- return hash.digest('hex') === expected.sha;
104
- }
105
- finally {
106
- await handle.close();
107
- }
108
- }
109
- async function removeEmptyParents(root, target) {
110
- let parent = dirname(target);
111
- while (parent !== root) {
112
- if ((await readdir(parent)).length > 0)
113
- break;
114
- await rmdir(parent);
115
- parent = dirname(parent);
116
- }
117
- }
118
- async function installFile(root, path, source, executable) {
119
- const target = await safeTarget(root, path);
120
- const existing = await lstat(target).catch(error => { if (error.code === 'ENOENT')
121
- return undefined; throw error; });
122
- if (existing?.isDirectory())
123
- await rmdir(target);
124
- await mkdir(dirname(target), { recursive: true });
125
- const stage = join(dirname(target), `.playcraft-transfer-${randomUUID()}.tmp`);
126
- try {
127
- await copyFile(source, stage);
128
- await chmod(stage, executable ? 0o755 : 0o644);
129
- await rename(stage, target);
130
- }
131
- catch (error) {
132
- await rm(stage, { force: true }).catch(() => undefined);
133
- await removeEmptyParents(root, target).catch(() => undefined);
134
- throw error;
135
- }
136
- finally {
137
- await rm(stage, { force: true }).catch(() => undefined);
138
- }
139
- }
140
- /** A fresh history contains only the current portable files, including uncommitted changes. */
141
- export async function createWorkspaceTransfer(root) {
142
- const temporary = await mkdtemp(join(tmpdir(), 'playcraft-transfer-'));
143
- const cleanup = () => rm(temporary, { recursive: true, force: true });
144
- try {
145
- const checkout = join(temporary, 'checkout');
146
- await mkdir(checkout);
147
- await copySnapshot(await realpath(root), checkout);
148
- transferGit(checkout, ['init', '--initial-branch=main']);
149
- transferGit(checkout, ['add', '--force', '--all']);
150
- transferGit(checkout, ['commit', '--allow-empty', '-m', 'Workspace snapshot']);
151
- const tree = transferGit(checkout, ['rev-parse', 'HEAD^{tree}']);
152
- const head = transferGit(checkout, ['rev-parse', 'HEAD']);
153
- const bundlePath = join(temporary, 'workspace.bundle');
154
- transferGit(checkout, ['bundle', 'create', bundlePath, 'HEAD']);
155
- return { bundlePath, tree, head, cleanup };
156
- }
157
- catch (error) {
158
- await cleanup();
159
- throw error;
160
- }
161
- }
162
- function treeEntries(root) {
163
- const entries = transferGit(root, ['ls-tree', '-r', '-z', 'HEAD']).split('\0').filter(Boolean).map(line => {
164
- const match = /^(100644|100755) blob ([a-f0-9]{40,64})\t(.+)$/s.exec(line);
165
- if (!match)
166
- throw new WorkspaceTransferError('invalid_workspace_transfer');
167
- const path = match[3];
168
- if (path.length > 1024 || path.includes('\\') || path.startsWith('/') || /[\x00-\x1f\x7f]/.test(path) ||
169
- path.split('/').some(part => !part || part === '.' || part === '..') || excluded(path))
170
- throw new WorkspaceTransferError('invalid_workspace_transfer');
171
- return { path, sha: match[2], executable: match[1] === '100755' };
172
- });
173
- if (entries.length > MAX_FILES)
174
- throw new WorkspaceTransferError('workspace_transfer_too_large');
175
- const normalized = entries.map(entry => entry.path.toLowerCase());
176
- if (new Set(normalized).size !== entries.length)
177
- throw new WorkspaceTransferError('invalid_workspace_transfer');
178
- return entries;
179
- }
180
- async function safeTarget(root, path) {
181
- const target = resolve(root, path);
182
- if (!target.startsWith(`${root}${sep}`))
183
- throw new WorkspaceTransferError('invalid_workspace_transfer');
184
- let current = root;
185
- for (const segment of path.split('/')) {
186
- current = join(current, segment);
187
- const info = await lstat(current).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
188
- return undefined; throw error; });
189
- if (info?.isSymbolicLink())
190
- throw new WorkspaceTransferError('workspace_transfer_symlink');
191
- }
192
- return target;
193
- }
194
- /** Compare the entire checkout before applying local commits, so cloud edits are never overwritten. */
195
- export async function applyWorkspaceTransfer(root, bundle, expectedTree) {
196
- if (!/^[a-f0-9]{40,64}$/.test(expectedTree))
197
- throw new WorkspaceTransferError('invalid_workspace_transfer');
198
- if (!bundle.byteLength || bundle.byteLength > WORKSPACE_TRANSFER_MAX_BYTES)
199
- throw new WorkspaceTransferError('workspace_transfer_too_large');
200
- const rootReal = await realpath(root);
201
- const temporary = await mkdtemp(join(tmpdir(), 'playcraft-import-'));
202
- let current;
203
- try {
204
- const bundlePath = join(temporary, 'incoming.bundle'), incoming = join(temporary, 'checkout');
205
- await writeFile(bundlePath, bundle, { mode: 0o600 });
206
- transferGit(temporary, ['clone', '--no-checkout', '--', bundlePath, incoming]);
207
- const entries = treeEntries(incoming);
208
- const tree = transferGit(incoming, ['rev-parse', 'HEAD^{tree}']);
209
- const head = transferGit(incoming, ['rev-parse', 'HEAD']);
210
- let bytes = 0;
211
- for (const entry of entries) {
212
- bytes += Number(transferGit(incoming, ['cat-file', '-s', entry.sha]));
213
- if (bytes > WORKSPACE_TRANSFER_MAX_BYTES)
214
- throw new WorkspaceTransferError('workspace_transfer_too_large');
215
- }
216
- current = await createWorkspaceTransfer(rootReal);
217
- if (current.tree === tree)
218
- return { tree, head, changedPaths: [] };
219
- if (current.tree !== expectedTree)
220
- throw new WorkspaceTransferError('workspace_transfer_conflict');
221
- const baseline = join(dirname(current.bundlePath), 'checkout');
222
- const previous = new Map(treeEntries(baseline).map(entry => [entry.path, entry]));
223
- const next = new Map(entries.map(entry => [entry.path, entry]));
224
- const changedPaths = [...new Set([...previous.keys(), ...next.keys()])]
225
- .filter(path => previous.get(path)?.sha !== next.get(path)?.sha || previous.get(path)?.executable !== next.get(path)?.executable);
226
- for (const path of changedPaths) {
227
- const target = await safeTarget(rootReal, path);
228
- const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
229
- return undefined; throw error; });
230
- if (next.has(path) && info?.isDirectory()) {
231
- const children = await readdir(target, { recursive: true });
232
- for (const child of children) {
233
- const childPath = `${path}/${child.split(sep).join('/')}`;
234
- const childInfo = await lstat(join(target, child));
235
- if (!childInfo.isDirectory() && (!previous.has(childPath) || next.has(childPath)))
236
- throw new WorkspaceTransferError('workspace_transfer_conflict');
237
- }
238
- }
239
- }
240
- transferGit(incoming, ['checkout', '--force']);
241
- const recheck = await createWorkspaceTransfer(rootReal);
242
- try {
243
- if (recheck.tree !== expectedTree)
244
- throw new WorkspaceTransferError('workspace_transfer_conflict');
245
- }
246
- finally {
247
- await recheck.cleanup();
248
- }
249
- const applied = [];
250
- try {
251
- // Deleting files first also permits a file to become a directory, or the reverse.
252
- for (const path of changedPaths.filter(path => !next.has(path)).sort((a, b) => b.length - a.length)) {
253
- if (!await matchesFile(rootReal, path, previous.get(path)))
254
- throw new WorkspaceTransferError('workspace_transfer_conflict');
255
- await rm(await safeTarget(rootReal, path), { force: true });
256
- applied.push(path);
257
- await removeEmptyParents(rootReal, join(rootReal, path));
258
- }
259
- for (const path of changedPaths.filter(path => next.has(path))) {
260
- if (!await matchesFile(rootReal, path, previous.get(path)))
261
- throw new WorkspaceTransferError('workspace_transfer_conflict');
262
- const entry = next.get(path);
263
- await installFile(rootReal, path, join(incoming, path), entry.executable);
264
- applied.push(path);
265
- }
266
- }
267
- catch (error) {
268
- // Roll back only our writes; never replace another writer's intervening content.
269
- for (const path of applied.reverse()) {
270
- if (!await matchesFile(rootReal, path, next.get(path)))
271
- throw new WorkspaceTransferError('workspace_transfer_rollback_conflict');
272
- const old = previous.get(path);
273
- if (old)
274
- await installFile(rootReal, path, join(baseline, path), old.executable);
275
- else {
276
- await rm(await safeTarget(rootReal, path), { force: true });
277
- await removeEmptyParents(rootReal, join(rootReal, path));
278
- }
279
- }
280
- throw error;
281
- }
282
- return { tree, head, changedPaths };
283
- }
284
- finally {
285
- await current?.cleanup();
286
- await rm(temporary, { recursive: true, force: true });
287
- }
288
- }
@@ -1,72 +0,0 @@
1
- import { TURN_FILES_CHANGED_EVENT, } from '@playcraft/common/cloud-workspace/runtime';
2
- import { diffWorkspaceTrees, retainTurnSnapshots, snapshotWorkspaceTree } from './git.js';
3
- const TURN_ENDS = new Set(['turn/completed', 'turn.completed', 'turn.interrupted', 'turn.failed']);
4
- /**
5
- * Snapshots taken when a session's turn starts, until that turn ends. Kept in memory only: a
6
- * restart ends the native turn as well, and that turn then simply reports no changes.
7
- */
8
- const started = new WeakMap();
9
- function turnsOf(state) {
10
- let turns = started.get(state);
11
- if (!turns)
12
- started.set(state, turns = new Map());
13
- return turns;
14
- }
15
- /**
16
- * Records the work tree before a turn is sent. A directory that cannot be snapshotted (no
17
- * repository, Git failure) gets no change summary; the turn itself is never held back by it.
18
- */
19
- export async function beginTurnChanges(state, sessionId, input) {
20
- turnsOf(state).delete(sessionId);
21
- if (input.directoryName === 'root')
22
- return;
23
- const before = await snapshotWorkspaceTree(input.root).catch(() => undefined);
24
- if (before)
25
- turnsOf(state).set(sessionId, { ...input, before });
26
- }
27
- /** A turn that never started has nothing to compare. */
28
- export function abandonTurnChanges(state, sessionId) {
29
- turnsOf(state).delete(sessionId);
30
- }
31
- /**
32
- * When a session's turn ends, compares the work tree with its start and records the files that
33
- * changed for that session's conversation. Returns no event when nothing changed.
34
- */
35
- export async function finishTurnChanges(state, event) {
36
- const { threadId, turnId } = event;
37
- if (!TURN_ENDS.has(event.method) || !threadId || !turnId)
38
- return [];
39
- const session = state.journal.listSessions().find((item) => item.threadId === threadId);
40
- const start = session && turnsOf(state).get(session.sessionId);
41
- if (!session || !start)
42
- return [];
43
- turnsOf(state).delete(session.sessionId);
44
- try {
45
- const after = await snapshotWorkspaceTree(start.root);
46
- const { files, truncated } = await diffWorkspaceTrees(start.root, start.before, after);
47
- if (!files.length)
48
- return [];
49
- await retainTurnSnapshots(start.root, turnId, start.before, after);
50
- const changes = { threadId, turnId, before: start.before, after, files, truncated };
51
- return [await state.journal.allocateSourceEvent({
52
- runtimeId: state.config.runtimeId,
53
- generation: state.config.generation,
54
- runtimeEpoch: state.runtimeEpoch,
55
- type: TURN_FILES_CHANGED_EVENT,
56
- payload: {
57
- ...changes,
58
- sessionId: session.sessionId,
59
- ...(start.workspaceId ? { workspaceId: start.workspaceId } : {}),
60
- ...(start.directoryName ? { directoryName: start.directoryName } : {}),
61
- },
62
- occurredAt: new Date().toISOString(),
63
- sessionId: session.sessionId,
64
- workspaceId: start.workspaceId,
65
- threadId,
66
- turnId,
67
- })];
68
- }
69
- catch {
70
- return [];
71
- }
72
- }
@@ -1,49 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { createHash } from 'node:crypto';
3
- import { WORKSPACE_VIDEO_ATTACHMENT_MAX_DURATION_MS, WORKSPACE_VIDEO_ATTACHMENT_MAX_BYTES } from '@playcraft/common/cloud-workspace/runtime';
4
- /** Probe the opened descriptor so replacing a pathname cannot redirect the media reader. */
5
- export async function probeAttachmentVideo(handle) {
6
- const output = await new Promise((resolve, reject) => {
7
- const child = spawn(process.env.PLAYCRAFT_FFPROBE_PATH ?? 'ffprobe', [
8
- '-v', 'error', '-protocol_whitelist', 'file,pipe', '-show_entries',
9
- 'format=format_name,duration:stream=codec_type,width,height', '-of', 'json',
10
- process.platform === 'linux' ? '/proc/self/fd/3' : '/dev/fd/3',
11
- ], { stdio: ['ignore', 'pipe', 'ignore', handle.fd] });
12
- let text = '';
13
- const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error('invalid_attachment')); }, 15_000);
14
- timer.unref();
15
- child.stdout.on('data', (chunk) => {
16
- text += chunk.toString('utf8');
17
- if (text.length > 64 * 1024) {
18
- child.kill('SIGKILL');
19
- reject(new Error('invalid_attachment'));
20
- }
21
- });
22
- child.once('error', () => { clearTimeout(timer); reject(new Error('video_probe_unavailable')); });
23
- child.once('close', code => { clearTimeout(timer); code === 0 ? resolve(text) : reject(new Error('invalid_attachment')); });
24
- });
25
- const result = JSON.parse(output);
26
- const stream = result.streams?.find(item => item.codec_type === 'video');
27
- const durationMs = Math.round(Number(result.format?.duration) * 1000);
28
- const formats = result.format?.format_name?.split(',') ?? [];
29
- const mimeType = formats.includes('webm') ? 'video/webm' : formats.includes('mp4') ? 'video/mp4' : formats.includes('mov') ? 'video/quicktime' : undefined;
30
- if (!stream || !mimeType || !Number.isFinite(durationMs) || durationMs <= 0 || durationMs > WORKSPACE_VIDEO_ATTACHMENT_MAX_DURATION_MS
31
- || !Number.isSafeInteger(stream.width) || !Number.isSafeInteger(stream.height) || stream.width <= 0 || stream.height <= 0
32
- || stream.width > 16384 || stream.height > 16384)
33
- throw new Error('invalid_attachment');
34
- return { mimeType, durationMs, width: stream.width, height: stream.height };
35
- }
36
- export async function hashAttachment(handle) {
37
- const digest = createHash('sha256');
38
- const chunk = Buffer.allocUnsafe(64 * 1024);
39
- let position = 0;
40
- for (;;) {
41
- const { bytesRead } = await handle.read(chunk, 0, chunk.length, position);
42
- if (!bytesRead)
43
- return digest.digest('hex');
44
- digest.update(chunk.subarray(0, bytesRead));
45
- position += bytesRead;
46
- if (position > WORKSPACE_VIDEO_ATTACHMENT_MAX_BYTES)
47
- throw new Error('invalid_attachment');
48
- }
49
- }
@@ -1,25 +0,0 @@
1
- ---
2
- name: playcraft-replica-validation
3
- description: Record a reconstructed browser playable with real inputs, compare it with its reference video, and use timestamped differences to improve the replica. Use after implementation or fixes; use video understanding first when the reference has not been analyzed.
4
- version: 1.0.1
5
- surfaces:
6
- - sandbox-agent
7
- ---
8
-
9
- # Replica validation
10
-
11
- Use the PlayCraft CLI (Command-Line Interface,命令行接口) to record the running implementation and compare real video evidence. Codex chooses the scenario, reads the evidence, edits the playable, and repeats the checks. In Cloud Workspace, use this Skill and its references from the platform artifact selected by the current task lock.
12
-
13
- Read [command and evidence contracts](references/contracts.md) before the first recording or comparison. Check `playcraft playable record --help`, `playcraft video compare --help`, and `playcraft video models --json`. If a required command is unavailable, report that the workspace CLI needs upgrading. Provider credentials and model requests belong to Model Proxy; do not call Gemini directly or copy a key into the project.
14
-
15
- Use a completed reference `analysis.json` from `playcraft-video-understanding`. Inspect its original keyframes and distinguish observed actions from inferred controls. Run from the project root. Write an explicit, versioned scenario for the current implementation, using real browser coordinates and inputs. Include the initial view, first action and result, principal feedback, and ending when demonstrated. Keep hidden rules and unshown branches unknown. Start or restart the current project using its own development command; do not depend on internal auto-play hooks. Confirm that the supplied development address belongs to this process and serves this round's version. If that cannot be confirmed, do not claim validation of the current version. The project digest proves the recorded checkout stayed unchanged, but does not attest which source version an already-running server serves.
16
-
17
- Record into a fresh directory under `.playcraft/video-replication/`. Keep the original recording, its input logs, scenario, control recordings, and project snapshot together. Do not edit the video or its manifest to repair a failing check. Match the reference viewport when practical and record enough time for every expected result. A completed recording proves capture succeeded; it does not prove the interaction worked.
18
-
19
- Compare the original reference, its analysis, the candidate video, and its recording manifest. Inspect `comparison.md`, `comparison.json`, paired keyframes, contact sheets, input logs, and controls using available image and file-reading tools. Review event alignment before judging motion or feedback timing. The model can suggest differences; the CLI derives the final status from validated evidence and the comparison policy. A single similarity score is insufficient. Keep the default full comparison policy for delivery; an explicitly limited diagnostic must be reported as partial coverage. Do not loosen thresholds just to obtain a passing result.
20
-
21
- For `fail`, address supported differences in priority order, then make a fresh recording from the changed project and compare again in a fresh output directory. For `inconclusive`, resolve missing controls, insufficient duration, unpaired required events, low confidence, or unknown input intent before declaring completion. Preserve valid differences even when other dimensions lack evidence. Report the tested path, unsupported branches, and unevaluated audio explicitly.
22
-
23
- A timeout or uncertain submission must retain its run identifier and saved request. Resume the same comparison with `playcraft video compare --resume <runId> --out <same-directory>`; recovery reads the existing task and never creates another paid request. Explicit cancellation is separate from ending the local wait. Do not resubmit because the command exited early. Treat malformed model output, stale recordings, changed hashes, or missing frames as errors, never as a passing comparison.
24
-
25
- Deliver the current project with links to the reference evidence, candidate recording, comparison report, and any remaining uncertainty. Keep validation evidence in workspace checkpoints and out of Git and deliverable builds.
@@ -1,79 +0,0 @@
1
- # Commands and evidence contracts
2
-
3
- The workspace CLI (Command-Line Interface,命令行接口) owns capture, upload, validation, frame extraction, and final status. The Skill supplies guidance only. Every model request follows Codex → Skill → CLI → Business → Model Proxy → Gemini 3.8 Flash.
4
-
5
- ```bash
6
- playcraft playable record --url '<development-url>' --scenario '<scenario.json>' \
7
- --out .playcraft/video-replication/record-01
8
- playcraft video compare --reference '<original-reference-video>' \
9
- --analysis '<reference-analysis.json>' \
10
- --candidate '.playcraft/video-replication/record-01/candidate.mp4' \
11
- --recording '.playcraft/video-replication/record-01/metadata.json' \
12
- --out .playcraft/video-replication/compare-01
13
- ```
14
-
15
- Scenario version is `playcraft.replica-scenario.v1`; positions are normalized to the declared `contentRect`. Replace event identifiers with actual IDs from `analysis.json` and coordinates/times with evidence from the running implementation:
16
-
17
- ```json
18
- {
19
- "schemaVersion": "playcraft.replica-scenario.v1",
20
- "draft": false,
21
- "referenceEventIds": ["initial", "first-result", "main-result", "ending"],
22
- "requiredEffects": [
23
- { "stepId": "drag-one", "eventId": "first-result" },
24
- { "stepId": "tap-two", "eventId": "main-result" }
25
- ],
26
- "controls": { "noInput": true, "omitRequiredSteps": true },
27
- "viewport": { "width": 390, "height": 844, "deviceScaleFactor": 1 },
28
- "contentRect": { "x": 0, "y": 0, "width": 1, "height": 1 },
29
- "pointer": "touch",
30
- "reset": { "kind": "fresh-context", "storage": "empty" },
31
- "durationMs": 15000,
32
- "steps": [
33
- {
34
- "id": "drag-one",
35
- "atMs": 1000,
36
- "type": "drag",
37
- "path": [
38
- { "offsetMs": 0, "x": 0.3, "y": 0.6 },
39
- { "offsetMs": 600, "x": 0.7, "y": 0.6 }
40
- ]
41
- },
42
- { "id": "tap-two", "atMs": 4000, "type": "tap", "x": 0.5, "y": 0.7 }
43
- ]
44
- }
45
- ```
46
-
47
- The first version records a requested seed as best effort; inspect `seedApplied` in the input log because the recorder does not inject a game seed. Fresh browser storage does not guarantee reset of server-side state.
48
-
49
- Every required first/main action result needs its corresponding `requiredEffects` entry. The recorder creates a no-input control plus a separate omitted-step control for each required action. Maximum three distinct required steps yield at most four controls. Disabling controls leaves interaction acceptance inconclusive.
50
-
51
- Use command help and the installed versioned schemas for recording fields. Do not guess manifest fields or synthesize a successful recording. Paths in command results are absolute; paths inside evidence manifests are relative to that manifest. Model output cannot provide artifact paths.
52
-
53
- `video compare` accepts `--processing static|agentic`, static `--fps 1|2|4|8`, an authorized `--model-config`, optional `--policy`, `--workspace`, `--timeout`, and `--out`. Static sampling is the default. Agentic execution cannot be combined with fixed sampling. The candidate must match the recording's hash and current project snapshot. The reference hash must match the completed analysis. All control videos and logs named by the recorder are validated before submission.
54
-
55
- The recording manifest version is `playcraft.replica-recording.v1`; the comparison result is `playcraft.replica-validation.v1`, and its evidence manifest is `playcraft.replica-evidence.v1`.
56
-
57
- The final comparison includes aligned reference/candidate event times, similarities, differences, modification suggestions, uncertainty, dimension findings, control coverage, and a deterministic policy decision. Paired frames come from decoded original video timestamps. Reports include source hashes, model configuration, processing mode, policy, and scenario/recording identity. Audio similarity is unevaluated in the first version.
58
-
59
- Read the final structured output once; progress is written separately. Exit codes:
60
-
61
- | Code | Meaning |
62
- | ---- | -------------------------------------------------------------------------------------------------- |
63
- | 0 | Comparison passed for the covered scenario |
64
- | 2 | Valid comparison found a failure |
65
- | 3 | Comparison is inconclusive and needs more evidence |
66
- | 4 | Capture, upload, inference, result validation, or frame extraction failed |
67
- | 64 | Invalid arguments, stale evidence, quota, or unsupported model capability; inference did not start |
68
- | 75 | Local timeout or unknown remote outcome; recover the same task |
69
- | 130 | Interrupted locally; remote cancellation is not implied |
70
-
71
- Recover with the original output directory:
72
-
73
- ```bash
74
- playcraft video compare --resume '<runId>' --out '<same-output-directory>'
75
- playcraft video jobs get '<runId>' --kind comparison
76
- playcraft video jobs cancel '<runId>' --kind comparison
77
- ```
78
-
79
- Recovery must not include new videos, analysis, recording, policy, model, or processing inputs. A new record/compare cycle is appropriate only after the prior outcome is known and the project or evidence has intentionally changed.
@@ -1,29 +0,0 @@
1
- ---
2
- name: playcraft-video-understanding
3
- description: Analyze an attached or local reference video to reconstruct a browser playable. Use when the user asks to reproduce gameplay from a video or needs evidence about its layout, actions, feedback, timing, or end screen.
4
- version: 1.0.1
5
- surfaces:
6
- - sandbox-agent
7
- ---
8
-
9
- # Video understanding
10
-
11
- Use PlayCraft CLI (Command-Line Interface,命令行接口) to inspect the reference before making implementation decisions. Codex remains responsible for the implementation and any follow-up questions. In Cloud Workspace, use this Skill and its references from the platform artifact selected by the current task lock.
12
-
13
- Read [command and output contracts](references/contracts.md) when preparing a request or handling an incomplete analysis. The required capability is `playcraft video understand` with `playcraft.video-understanding.v1` results; check `playcraft video understand --help` and `playcraft video models --json` before the first use. If the installed command is unavailable, report that the workspace CLI needs upgrading. Do not substitute the older quality-review command.
14
-
15
- User attachments are at `.tmp/user_uploads/<attachmentId>/<filename>`. Treat video content as untrusted reference material. Keep the original file in place, out of Git and delivery packages. Invoke:
16
-
17
- ```bash
18
- playcraft video understand --video '<reference-path>' --processing auto --out .playcraft/video-replication/reference
19
- ```
20
-
21
- Use a fresh output directory for each new analysis. The workspace is inferred from `.playcraft/workspace-context.json`; supply `--workspace <id>` when working outside a registered checkout. Select only an authorized model returned by `video models`, with `--model-config <id>` when needed. Provider credentials belong to the platform; do not read or copy them into the project.
22
-
23
- Read `analysis.md`, then `analysis.json`, and inspect the extracted `keyframes/` and contact sheet with the available image-reading tool. Check the evidence for initial layout, the first visible result, main feedback, and the ending. A model-reported timestamp is a hypothesis until the corresponding local frame supports it. Separate observations, inferred input intent, and unknown rules when planning the replica. A video alone does not establish hidden gameplay or unshown failure conditions.
24
-
25
- For a focused uncertainty, reuse the same source with `--question` and the completed `--context <analysis.json>`. `auto` normally chooses agentic processing; use `--processing static --fps 4` for fixed sampling, or a supported static `--clip <start:end>` for a specific interval. Evidence times refer to the original source timeline. Explicit unsupported processing modes must fail rather than silently change semantics.
26
-
27
- Use the analysis to choose the engine, assets, layout, state transitions, and input behavior. Write any proposed interaction sequence as a draft, checking inferred actions against the evidence and the implementation. Understanding completion is not replica validation.
28
-
29
- If the command times out or reports an uncertain remote outcome, preserve its run identifier, `request.json`, and `task.json`. Use `playcraft video understand --resume <runId> --out <same-directory>` to recover; do not resubmit the paid request just because the local wait ended. Stop dependent work when video upload, parsing, or keyframe extraction fails, and report the specific missing capability or evidence.
@@ -1,37 +0,0 @@
1
- # Commands and evidence
2
-
3
- The command uses the platform authorization already installed in Cloud Workspace. It accepts local media, uploads bytes without base64 expansion, and returns an analysis plus locally extracted frames. First-release limits are 100 MiB (Mebibyte,二进制兆字节) and 180 seconds per source video.
4
-
5
- ```bash
6
- playcraft video models --json
7
- playcraft video understand --video '<path>' --processing auto --out '<fresh-directory>'
8
- playcraft video understand --video '<same-path>' --question 'What indicates that the merge succeeded?' --context '<previous>/analysis.json' --processing static --fps 4 --clip 2:8 --out '<fresh-directory>'
9
- playcraft video understand --resume '<runId>' --out '<original-directory>'
10
- playcraft video jobs get '<runId>'
11
- playcraft video jobs cancel '<runId>'
12
- ```
13
-
14
- `--workspace <id>`, `--model-config <id>`, and `--timeout <seconds>` are optional. New-input parameters cannot accompany `--resume`. `--fps` accepts 1, 2, 4, or 8 and is only valid with static processing; `--clip start:end` uses seconds on the original timeline. A follow-up context must refer to the same source digest. Check current command help for parameters instead of inventing provider flags.
15
-
16
- Standard output is one JSON (JavaScript Object Notation,JavaScript 对象表示法) envelope. Progress appears on standard error. The envelope has `schemaVersion: playcraft.video-cli.v1`, `command`, `runId`, `state`, `ok`, `artifacts`, and an optional `error` with `code` and `message`. Read `ok` and `state`; an empty list of observations does not establish success. Artifact paths returned by the command are absolute.
17
-
18
- | Artifact | How to use it |
19
- | ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
20
- | `manifest.json` | Run identity, source digest, selected model, actual processing mode, and extracted frame paths and digests |
21
- | `request.json`, `task.json` | Local request and remote task information used to resume an existing run |
22
- | `analysis.json` | Versioned observations, events, evidence, inferences, unknowns, and reconstruction hints |
23
- | `analysis.md` | Human-readable analysis with evidence references |
24
- | `keyframes/<evidenceId>.png` | Frames extracted from the local source at range-checked timestamps |
25
- | `contact-sheet.jpg` | Overview for inspecting the progression across evidence frames |
26
-
27
- `analysis.json` uses `schemaVersion: playcraft.video-understanding.v1`. Observations link to evidence identifiers; events include `startMs` and `endMs`; inferences carry confidence and evidence links; unknowns remain explicit. Model text cannot create a real frame file. Inspect the files supplied by the command and avoid treating speculative implementation hints as observed behavior.
28
-
29
- | Exit | Meaning and next action |
30
- | ---- | ---------------------------------------------------------------------------------------- |
31
- | 0 | Analysis and required artifacts completed; inspect evidence before implementing |
32
- | 4 | Upload, model, parse, or extraction error; inspect `error` and preserve partial evidence |
33
- | 64 | Invalid input, limit, or unsupported model capability; correct it before submitting |
34
- | 75 | Wait expired or remote result unknown; resume the existing run |
35
- | 130 | Interrupted; check whether remote cancellation was confirmed |
36
-
37
- Changing source bytes, processing mode, or the question creates a new paid analysis. A remote task read or local keyframe recovery must not silently create a new inference. Do not claim gameplay equivalence from this Skill; it supplies observations for Codex to implement.