@playcraft/cli 0.1.50-beta → 0.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (406) hide show
  1. package/README.md +3 -62
  2. package/dist/agent/local-backend.js +1 -1
  3. package/dist/cli-root-help.js +0 -2
  4. package/dist/commands/build-all.js +19 -5
  5. package/dist/commands/build.js +28 -15
  6. package/dist/commands/create.js +33 -26
  7. package/dist/commands/image.js +6 -2
  8. package/dist/commands/login.js +42 -84
  9. package/dist/commands/skills.js +0 -4
  10. package/dist/commands/tools-3d.js +0 -11
  11. package/dist/commands/tools-generation.js +137 -69
  12. package/dist/commands/tools-image-context.js +29 -0
  13. package/dist/commands/tools-utils.js +12 -0
  14. package/dist/commands/tools.js +2 -2
  15. package/dist/config.js +4 -59
  16. package/dist/index.js +3 -40
  17. package/dist/remix/clone.js +0 -2
  18. package/dist/remix/init-template.js +0 -2
  19. package/dist/remix/pull.js +0 -2
  20. package/dist/remix/push.js +1 -21
  21. package/dist/utils/agent-api-client.js +30 -210
  22. package/dist/utils/image-asset-context.js +228 -0
  23. package/dist/utils/playcraft-http-client.js +4 -6
  24. package/package.json +5 -15
  25. package/project-template/.claude/agents/refs/ta-image-generation-detail.md +67 -123
  26. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  27. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  28. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  29. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  30. package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  31. package/project-templates/phaser/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  32. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  33. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  34. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  35. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  36. package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  37. package/project-templates/threejs/.claude/agents/refs/ta-image-generation-detail.md +59 -59
  38. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
  39. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
  40. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
  41. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
  42. package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
  43. package/SKILLS_REGISTRY.md +0 -149
  44. package/dist/auth/account-activation.js +0 -157
  45. package/dist/auth/messages.js +0 -30
  46. package/dist/commands/build-temp.js +0 -26
  47. package/dist/commands/platform-skills.generated.js +0 -19
  48. package/dist/commands/playable.js +0 -53
  49. package/dist/commands/tools-batch.js +0 -113
  50. package/dist/commands/video.js +0 -122
  51. package/dist/commands/workspace-runtime.js +0 -54
  52. package/dist/commands/workspace.js +0 -40
  53. package/dist/project-skills/builtin-import.js +0 -225
  54. package/dist/project-skills/commands.js +0 -77
  55. package/dist/project-skills/lifecycle.js +0 -28
  56. package/dist/project-skills/local-run.js +0 -112
  57. package/dist/project-skills/local-store.js +0 -221
  58. package/dist/project-skills/messages.js +0 -80
  59. package/dist/project-skills/reconcile.js +0 -62
  60. package/dist/project-skills/remote-cache.js +0 -51
  61. package/dist/project-skills/validation.js +0 -19
  62. package/dist/recording/messages.js +0 -40
  63. package/dist/recording/project-digest.js +0 -85
  64. package/dist/recording/recorder.js +0 -293
  65. package/dist/recording/scenario.js +0 -50
  66. package/dist/skill-registry/client.js +0 -345
  67. package/dist/skill-registry/commands.js +0 -180
  68. package/dist/skill-registry/evaluation-client.js +0 -156
  69. package/dist/skill-registry/evaluation-commands.js +0 -174
  70. package/dist/skill-registry/messages.js +0 -177
  71. package/dist/skill-registry/package.js +0 -275
  72. package/dist/skill-registry/platform-package.js +0 -100
  73. package/dist/utils/environment-endpoints.js +0 -17
  74. package/dist/utils/error-diagnostics.js +0 -20
  75. package/dist/utils/tool-operation-journal.js +0 -124
  76. package/dist/utils/video-evidence-git.js +0 -81
  77. package/dist/video-replication/client.js +0 -234
  78. package/dist/video-replication/comparison-evidence.js +0 -149
  79. package/dist/video-replication/comparison-files.js +0 -57
  80. package/dist/video-replication/comparison-log.js +0 -72
  81. package/dist/video-replication/comparison-messages.js +0 -104
  82. package/dist/video-replication/comparison-output.js +0 -63
  83. package/dist/video-replication/comparison-preflight.js +0 -66
  84. package/dist/video-replication/comparison.js +0 -230
  85. package/dist/video-replication/diagnostics.js +0 -41
  86. package/dist/video-replication/evidence.js +0 -165
  87. package/dist/video-replication/media.js +0 -112
  88. package/dist/video-replication/messages.js +0 -97
  89. package/dist/workspace/messages.js +0 -67
  90. package/dist/workspace/transfer-client.js +0 -233
  91. package/dist/workspace/transfer-errors.js +0 -48
  92. package/dist/workspace-runtime/batch/content-changes.js +0 -30
  93. package/dist/workspace-runtime/batch/control.js +0 -86
  94. package/dist/workspace-runtime/batch/deliver.js +0 -173
  95. package/dist/workspace-runtime/batch/freeze.js +0 -101
  96. package/dist/workspace-runtime/batch/generate.js +0 -249
  97. package/dist/workspace-runtime/batch/git.js +0 -40
  98. package/dist/workspace-runtime/batch/occupancy.js +0 -8
  99. package/dist/workspace-runtime/batch/policy.js +0 -70
  100. package/dist/workspace-runtime/batch/prepare.js +0 -317
  101. package/dist/workspace-runtime/batch/processes.js +0 -72
  102. package/dist/workspace-runtime/batch/records.js +0 -113
  103. package/dist/workspace-runtime/batch/routes.js +0 -61
  104. package/dist/workspace-runtime/batch/source-candidate.js +0 -86
  105. package/dist/workspace-runtime/batch/source-capture.js +0 -146
  106. package/dist/workspace-runtime/batch/source-failure.js +0 -43
  107. package/dist/workspace-runtime/batch/source-publish.js +0 -130
  108. package/dist/workspace-runtime/codex/app-server.js +0 -1065
  109. package/dist/workspace-runtime/codex/compact.js +0 -46
  110. package/dist/workspace-runtime/codex/config-toml.js +0 -107
  111. package/dist/workspace-runtime/codex/delivery-tools.js +0 -144
  112. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
  113. package/dist/workspace-runtime/codex/launcher-client.js +0 -177
  114. package/dist/workspace-runtime/codex/loopback.js +0 -146
  115. package/dist/workspace-runtime/codex/mcp-config.js +0 -39
  116. package/dist/workspace-runtime/codex/model-broker.js +0 -263
  117. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  118. package/dist/workspace-runtime/codex/permissions.js +0 -79
  119. package/dist/workspace-runtime/codex/thread-image.js +0 -38
  120. package/dist/workspace-runtime/codex/tool-response.js +0 -10
  121. package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
  122. package/dist/workspace-runtime/codex/ui-tools.js +0 -203
  123. package/dist/workspace-runtime/codex/work-mode.js +0 -15
  124. package/dist/workspace-runtime/main.js +0 -10
  125. package/dist/workspace-runtime/persistence/journal.js +0 -365
  126. package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
  127. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
  128. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1161
  129. package/dist/workspace-runtime/persistence/stopped-execution.js +0 -77
  130. package/dist/workspace-runtime/previews/diagnostics.js +0 -44
  131. package/dist/workspace-runtime/previews/output.js +0 -36
  132. package/dist/workspace-runtime/previews/publish.js +0 -283
  133. package/dist/workspace-runtime/previews/runtime-preview.js +0 -177
  134. package/dist/workspace-runtime/previews/single-file.js +0 -43
  135. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  136. package/dist/workspace-runtime/serve.js +0 -441
  137. package/dist/workspace-runtime/server/accept-operation.js +0 -61
  138. package/dist/workspace-runtime/server/asset-transfers.js +0 -63
  139. package/dist/workspace-runtime/server/auth.js +0 -21
  140. package/dist/workspace-runtime/server/connectivity.js +0 -209
  141. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  142. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  143. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  144. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  145. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  146. package/dist/workspace-runtime/server/dispatch.js +0 -1632
  147. package/dist/workspace-runtime/server/endpoints.js +0 -21
  148. package/dist/workspace-runtime/server/execution-group.js +0 -90
  149. package/dist/workspace-runtime/server/http.js +0 -1340
  150. package/dist/workspace-runtime/server/lock.js +0 -53
  151. package/dist/workspace-runtime/server/operation-record.js +0 -33
  152. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  153. package/dist/workspace-runtime/server/session-restore.js +0 -84
  154. package/dist/workspace-runtime/server/source-uploader.js +0 -138
  155. package/dist/workspace-runtime/server/submit-operation.js +0 -41
  156. package/dist/workspace-runtime/server/terminal-host.js +0 -366
  157. package/dist/workspace-runtime/server/types.js +0 -1
  158. package/dist/workspace-runtime/server/workspace-transfer.js +0 -168
  159. package/dist/workspace-runtime/verify-artifact.js +0 -59
  160. package/dist/workspace-runtime/workspaces/append-only-log.js +0 -62
  161. package/dist/workspace-runtime/workspaces/archive.js +0 -207
  162. package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
  163. package/dist/workspace-runtime/workspaces/artifact-files.js +0 -199
  164. package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
  165. package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
  166. package/dist/workspace-runtime/workspaces/asset-library-import.js +0 -366
  167. package/dist/workspace-runtime/workspaces/asset-transfer-dependencies.js +0 -81
  168. package/dist/workspace-runtime/workspaces/asset-transfer-publish.js +0 -434
  169. package/dist/workspace-runtime/workspaces/asset-transfer-storage.js +0 -389
  170. package/dist/workspace-runtime/workspaces/attachment-content.js +0 -73
  171. package/dist/workspace-runtime/workspaces/attachments.js +0 -185
  172. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  173. package/dist/workspace-runtime/workspaces/binary-content.js +0 -65
  174. package/dist/workspace-runtime/workspaces/binary-write.js +0 -112
  175. package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
  176. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -115
  177. package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
  178. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  179. package/dist/workspace-runtime/workspaces/delivery-build.js +0 -331
  180. package/dist/workspace-runtime/workspaces/delivery-store.js +0 -168
  181. package/dist/workspace-runtime/workspaces/delivery.js +0 -64
  182. package/dist/workspace-runtime/workspaces/dependencies.js +0 -279
  183. package/dist/workspace-runtime/workspaces/developer-command.js +0 -98
  184. package/dist/workspace-runtime/workspaces/directories.js +0 -132
  185. package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
  186. package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
  187. package/dist/workspace-runtime/workspaces/directory-create.js +0 -57
  188. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  189. package/dist/workspace-runtime/workspaces/directory-mutations.js +0 -238
  190. package/dist/workspace-runtime/workspaces/directory-revisions.js +0 -56
  191. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  192. package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
  193. package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
  194. package/dist/workspace-runtime/workspaces/file-content.js +0 -48
  195. package/dist/workspace-runtime/workspaces/files-search.js +0 -116
  196. package/dist/workspace-runtime/workspaces/files.js +0 -150
  197. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  198. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  199. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  200. package/dist/workspace-runtime/workspaces/git.js +0 -670
  201. package/dist/workspace-runtime/workspaces/instructions.js +0 -56
  202. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -313
  203. package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
  204. package/dist/workspace-runtime/workspaces/operation-log.js +0 -23
  205. package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
  206. package/dist/workspace-runtime/workspaces/parameter-agent-inputs.js +0 -87
  207. package/dist/workspace-runtime/workspaces/parameter-agent-protocol.js +0 -29
  208. package/dist/workspace-runtime/workspaces/parameter-agent-store.js +0 -58
  209. package/dist/workspace-runtime/workspaces/parameter-agent.js +0 -282
  210. package/dist/workspace-runtime/workspaces/parameters.js +0 -295
  211. package/dist/workspace-runtime/workspaces/prepare.js +0 -278
  212. package/dist/workspace-runtime/workspaces/registry.js +0 -251
  213. package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
  214. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  215. package/dist/workspace-runtime/workspaces/session-image.js +0 -104
  216. package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
  217. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
  218. package/dist/workspace-runtime/workspaces/skills.js +0 -191
  219. package/dist/workspace-runtime/workspaces/transfer-quota.js +0 -69
  220. package/dist/workspace-runtime/workspaces/transfer.js +0 -471
  221. package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
  222. package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
  223. package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
  224. package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
  225. package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
  226. package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
  227. package/project-template-v2/.claude/agents/artist.md +0 -82
  228. package/project-template-v2/.claude/agents/developer.md +0 -153
  229. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  230. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  231. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  232. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  233. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  234. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  235. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  236. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  237. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  238. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  239. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  240. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  241. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  242. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  243. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  244. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  245. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  246. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  247. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  248. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  249. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  250. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  251. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  252. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  253. package/project-template-v2/.claude/settings.json +0 -33
  254. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  255. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  256. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  257. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  258. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  259. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  260. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  261. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  262. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  263. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  264. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  265. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  266. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  267. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  268. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  269. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  270. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  271. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  272. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  273. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  274. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  275. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  276. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  277. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  278. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  279. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  280. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  281. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  282. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  283. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  284. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  285. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  286. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  287. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  288. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  289. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  290. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  291. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  292. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  293. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  294. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  295. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  296. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  297. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  298. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  299. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  300. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  301. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  302. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  303. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  304. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  305. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  306. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  307. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  308. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  309. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  310. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  311. package/project-template-v2/.claude/snapshot.mjs +0 -263
  312. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  313. package/project-template-v2/CLAUDE.md +0 -146
  314. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  315. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  316. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  317. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  318. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  319. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  320. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  321. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  322. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  323. package/project-template-v2/assets/models/.gitkeep +0 -0
  324. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  325. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  326. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  327. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  328. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  329. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  330. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  331. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  332. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  333. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  334. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  335. package/project-template-v2/docs/project-state.json +0 -60
  336. package/project-template-v2/docs/project-state.md +0 -72
  337. package/project-template-v2/docs/standards/README.md +0 -225
  338. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  339. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  340. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  341. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  342. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  343. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  344. package/project-template-v2/game/index.ts +0 -18
  345. package/project-template-v2/globals.d.ts +0 -51
  346. package/project-template-v2/index.css +0 -34
  347. package/project-template-v2/index.html +0 -18
  348. package/project-template-v2/main.ts +0 -9
  349. package/project-template-v2/package.json +0 -46
  350. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  351. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  352. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  353. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  354. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  355. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  356. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  357. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  358. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  359. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  360. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  361. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  362. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  363. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  364. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  365. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  366. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  367. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  368. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  369. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  370. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  371. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  372. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  373. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  374. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  375. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  376. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  377. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  378. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  379. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  380. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  381. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  382. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  383. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  384. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  385. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  386. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  387. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  388. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  389. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  390. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  391. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  392. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  393. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  394. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  395. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  396. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  397. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  398. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  399. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  400. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  401. package/project-template-v2/tsconfig.json +0 -20
  402. package/project-template-v2/vite.config.ts +0 -27
  403. package/project-templates/batch-locks/phaser.yaml +0 -922
  404. package/project-templates/batch-locks/threejs.yaml +0 -978
  405. package/project-templates/empty/AGENTS.md +0 -41
  406. package/project-templates/empty/gitignore +0 -33
@@ -1,471 +0,0 @@
1
- import { spawn, spawnSync } from 'node:child_process';
2
- import { createHash, randomUUID } from 'node:crypto';
3
- import { constants, createWriteStream } from 'node:fs';
4
- import { chmod, copyFile, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, rmdir, stat, writeFile } from 'node:fs/promises';
5
- import { tmpdir } from 'node:os';
6
- import { dirname, join, resolve, sep } from 'node:path';
7
- import { Transform } from 'node:stream';
8
- import { pipeline } from 'node:stream/promises';
9
- import { isCredentialFile } from './git.js';
10
- const EXCLUDED = new Set(['.git', 'node_modules', '.playcraft-workspace.json', '.playcraft.json']);
11
- const GIT_TIMEOUT_MS = 15 * 60_000;
12
- const GIT_OPTIONS = ['-c', 'core.hooksPath=/dev/null', '-c', 'commit.gpgsign=false', '-c', 'core.autocrlf=false',
13
- '-c', 'user.name=PlayCraft Workspace', '-c', 'user.email=workspace@playcraft.local'];
14
- const SNAPSHOT_MESSAGE = 'PlayCraft workspace snapshot v1';
15
- export const RAW_ATTRIBUTES = '* -text -eol -working-tree-encoding -filter -ident\n';
16
- export class WorkspaceTransferError extends Error {
17
- code;
18
- details;
19
- constructor(code, details) {
20
- super(code);
21
- this.code = code;
22
- this.details = details;
23
- }
24
- }
25
- function gitEnvironment() {
26
- return { PATH: process.env.PATH, HOME: tmpdir(), GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: '/dev/null',
27
- GIT_TERMINAL_PROMPT: '0', GIT_ALLOW_PROTOCOL: 'file', GIT_AUTHOR_NAME: 'PlayCraft Workspace',
28
- GIT_AUTHOR_EMAIL: 'workspace@playcraft.local', GIT_COMMITTER_NAME: 'PlayCraft Workspace',
29
- GIT_COMMITTER_EMAIL: 'workspace@playcraft.local', GIT_AUTHOR_DATE: '2000-01-01T00:00:00Z',
30
- GIT_COMMITTER_DATE: '2000-01-01T00:00:00Z' };
31
- }
32
- function excluded(path) {
33
- const parts = path.split('/');
34
- return parts.some(part => EXCLUDED.has(part.toLowerCase()) || /^\.playcraft-(?:credential|transfer)-.*\.tmp$/i.test(part)) ||
35
- parts.some((part, index) => part === '.playcraft' && /^(?:workspace-context(?:\..*)?|video-replication)$/.test(parts[index + 1] ?? '')) ||
36
- isCredentialFile(path);
37
- }
38
- export function transferGit(root, args) {
39
- const result = spawnSync('git', [...GIT_OPTIONS, ...args], { cwd: root, encoding: 'utf8', env: gitEnvironment(), timeout: GIT_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024 });
40
- if (result.status !== 0) {
41
- const code = result.error?.code;
42
- throw new WorkspaceTransferError(code === 'ETIMEDOUT' ? 'workspace_transfer_git_timeout'
43
- : code === 'ENOENT' ? 'workspace_transfer_git_missing' : 'workspace_transfer_git_failed');
44
- }
45
- return result.stdout.trim();
46
- }
47
- /** Large object operations write directly to disk and remain cancellable. */
48
- export async function runTransferGit(root, args, options = {}) {
49
- options.signal?.throwIfAborted();
50
- return new Promise((resolveResult, reject) => {
51
- const child = spawn('git', [...GIT_OPTIONS, ...args], { cwd: root, env: gitEnvironment(), stdio: ['ignore', 'pipe', 'pipe'] });
52
- let stdout = '', stderr = '', failure, timedOut = false;
53
- const abort = () => { failure = options.signal?.reason ?? new Error('workspace_transfer_cancelled'); child.kill('SIGKILL'); };
54
- const timeout = setTimeout(() => { timedOut = true; child.kill('SIGKILL'); }, GIT_TIMEOUT_MS);
55
- options.signal?.addEventListener('abort', abort, { once: true });
56
- child.stdout.setEncoding('utf8');
57
- child.stderr.setEncoding('utf8');
58
- child.stdout.on('data', (chunk) => {
59
- try {
60
- if (options.onStdout)
61
- options.onStdout(chunk);
62
- else {
63
- stdout += chunk;
64
- if (stdout.length > 8 * 1024 * 1024)
65
- throw new WorkspaceTransferError('workspace_transfer_git_output_too_large');
66
- }
67
- }
68
- catch (error) {
69
- failure = error;
70
- child.kill('SIGKILL');
71
- }
72
- });
73
- child.stderr.on('data', (chunk) => { if (stderr.length < 4096)
74
- stderr += chunk.slice(0, 4096 - stderr.length); });
75
- child.once('error', error => {
76
- failure = new WorkspaceTransferError(error.code === 'ENOENT'
77
- ? 'workspace_transfer_git_missing' : 'workspace_transfer_git_failed');
78
- });
79
- child.once('close', code => {
80
- clearTimeout(timeout);
81
- options.signal?.removeEventListener('abort', abort);
82
- if (failure)
83
- reject(failure);
84
- else if (timedOut)
85
- reject(new WorkspaceTransferError('workspace_transfer_git_timeout', { operation: args[0] }));
86
- else if (code !== 0)
87
- reject(new WorkspaceTransferError(/no space left|disk full/i.test(stderr)
88
- ? 'workspace_transfer_disk_full' : 'workspace_transfer_git_failed', { operation: args[0], exitCode: code }));
89
- else
90
- resolveResult(stdout.trim());
91
- });
92
- });
93
- }
94
- async function copySnapshot(source, target, signal, hashOnly = false) {
95
- let bytes = 0, files = 0;
96
- async function copy(directory, prefix) {
97
- signal?.throwIfAborted();
98
- const treeParts = [];
99
- const directoryInfo = await lstat(directory);
100
- const directoryReal = await realpath(directory);
101
- if (!directoryInfo.isDirectory() || directoryInfo.isSymbolicLink() ||
102
- (directoryReal !== source && !directoryReal.startsWith(`${source}${sep}`)))
103
- throw new WorkspaceTransferError('workspace_transfer_conflict');
104
- for (const entry of await readdir(directory, { withFileTypes: true })) {
105
- const path = prefix ? `${prefix}/${entry.name}` : entry.name;
106
- if (excluded(path))
107
- continue;
108
- signal?.throwIfAborted();
109
- const from = join(directory, entry.name), to = target ? join(target, path) : undefined;
110
- const info = await lstat(from);
111
- if (info.isSymbolicLink())
112
- continue;
113
- if (info.isDirectory()) {
114
- if (to)
115
- await mkdir(to, { recursive: true });
116
- const child = await copy(from, path);
117
- if (child && child !== EMPTY_TREE)
118
- treeParts.push({ name: entry.name, directory: true,
119
- value: Buffer.concat([Buffer.from(`40000 ${entry.name}\0`), Buffer.from(child, 'hex')]) });
120
- }
121
- else if (info.isFile()) {
122
- bytes += info.size;
123
- files++;
124
- if (!(await realpath(from)).startsWith(`${source}${sep}`))
125
- throw new WorkspaceTransferError('workspace_transfer_conflict');
126
- if (!to && !hashOnly)
127
- continue;
128
- const handle = await open(from, constants.O_RDONLY | constants.O_NOFOLLOW);
129
- try {
130
- const before = await handle.stat();
131
- if (!before.isFile() || before.dev !== info.dev || before.ino !== info.ino || before.size !== info.size ||
132
- before.mtimeMs !== info.mtimeMs || before.ctimeMs !== info.ctimeMs)
133
- throw new WorkspaceTransferError('workspace_transfer_conflict');
134
- let size = 0;
135
- const hash = hashOnly ? createHash('sha1').update(`blob ${before.size}\0`) : undefined;
136
- if (to) {
137
- const guard = new Transform({ transform(chunk, _encoding, callback) {
138
- size += chunk.length;
139
- callback(size > before.size ? new WorkspaceTransferError('workspace_transfer_conflict') : null, chunk);
140
- } });
141
- await pipeline(handle.createReadStream({ autoClose: false }), guard, createWriteStream(to, { flags: 'wx', mode: 0o600 }), { signal });
142
- }
143
- else {
144
- for await (const chunk of handle.createReadStream({ autoClose: false })) {
145
- signal?.throwIfAborted();
146
- size += chunk.length;
147
- if (size > before.size)
148
- throw new WorkspaceTransferError('workspace_transfer_conflict');
149
- hash.update(chunk);
150
- }
151
- }
152
- const after = await handle.stat();
153
- if (size !== before.size || after.size !== before.size || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)
154
- throw new WorkspaceTransferError('workspace_transfer_conflict');
155
- if (hash)
156
- treeParts.push({ name: entry.name, directory: false,
157
- value: Buffer.concat([Buffer.from(`${info.mode & 0o111 ? '100755' : '100644'} ${entry.name}\0`), hash.digest()]) });
158
- }
159
- finally {
160
- await handle.close();
161
- }
162
- if (to)
163
- await chmod(to, info.mode & 0o111 ? 0o755 : 0o644);
164
- }
165
- }
166
- const after = await lstat(directory);
167
- if (after.dev !== directoryInfo.dev || after.ino !== directoryInfo.ino || after.mtimeMs !== directoryInfo.mtimeMs || after.ctimeMs !== directoryInfo.ctimeMs)
168
- throw new WorkspaceTransferError('workspace_transfer_conflict');
169
- if (hashOnly) {
170
- treeParts.sort((left, right) => Buffer.compare(Buffer.from(left.name + (left.directory ? '/' : '\0')), Buffer.from(right.name + (right.directory ? '/' : '\0'))));
171
- const length = treeParts.reduce((total, part) => total + part.value.length, 0);
172
- const hash = createHash('sha1').update(`tree ${length}\0`);
173
- for (const part of treeParts)
174
- hash.update(part.value);
175
- return hash.digest('hex');
176
- }
177
- }
178
- const tree = await copy(source, '');
179
- return { bytes, files, ...(tree ? { tree } : {}) };
180
- }
181
- const EMPTY_TREE = createHash('sha1').update('tree 0\0').digest('hex');
182
- export async function inspectWorkspaceTransfer(root, options = {}) {
183
- return copySnapshot(await realpath(root), undefined, options.signal);
184
- }
185
- export async function inspectWorkspaceTree(root, options = {}) {
186
- const snapshot = await copySnapshot(await realpath(root), undefined, options.signal, true);
187
- return { bytes: snapshot.bytes, files: snapshot.files, tree: snapshot.tree };
188
- }
189
- async function matchesFile(root, path, expected) {
190
- const target = await safeTarget(root, path);
191
- const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
192
- return undefined; throw error; });
193
- if (!expected)
194
- return !info || info.isDirectory();
195
- if (!info?.isFile() || Boolean(info.mode & 0o111) !== expected.executable)
196
- return false;
197
- const handle = await open(target, constants.O_RDONLY | constants.O_NOFOLLOW);
198
- try {
199
- const stat = await handle.stat();
200
- const hash = createHash(expected.sha.length === 64 ? 'sha256' : 'sha1');
201
- hash.update(`blob ${stat.size}\0`);
202
- for await (const chunk of handle.createReadStream({ autoClose: false }))
203
- hash.update(chunk);
204
- return hash.digest('hex') === expected.sha;
205
- }
206
- finally {
207
- await handle.close();
208
- }
209
- }
210
- async function removeEmptyParents(root, target) {
211
- let parent = dirname(target);
212
- while (parent !== root) {
213
- if ((await readdir(parent)).length > 0)
214
- break;
215
- await rmdir(parent);
216
- parent = dirname(parent);
217
- }
218
- }
219
- async function installFile(root, path, source, executable) {
220
- const target = await safeTarget(root, path);
221
- const existing = await lstat(target).catch(error => { if (error.code === 'ENOENT')
222
- return undefined; throw error; });
223
- if (existing?.isDirectory())
224
- await rmdir(target);
225
- await mkdir(dirname(target), { recursive: true });
226
- const stage = join(dirname(target), `.playcraft-transfer-${randomUUID()}.tmp`);
227
- try {
228
- await copyFile(source, stage);
229
- await chmod(stage, executable ? 0o755 : 0o644);
230
- await rename(stage, target);
231
- }
232
- catch (error) {
233
- await rm(stage, { force: true }).catch(() => undefined);
234
- await removeEmptyParents(root, target).catch(() => undefined);
235
- throw error;
236
- }
237
- finally {
238
- await rm(stage, { force: true }).catch(() => undefined);
239
- }
240
- }
241
- /** A fresh history contains only the current portable files, including uncommitted changes. */
242
- export async function createWorkspaceTransfer(root, options = {}) {
243
- const temporary = await mkdtemp(join(tmpdir(), 'playcraft-transfer-'));
244
- const cleanup = () => rm(temporary, { recursive: true, force: true });
245
- try {
246
- const checkout = join(temporary, 'checkout');
247
- await mkdir(checkout);
248
- const stats = await copySnapshot(await realpath(root), checkout, options.signal);
249
- await runTransferGit(checkout, ['init', '--initial-branch=main'], options);
250
- // Portable snapshots preserve bytes even when project attributes request content conversion.
251
- await writeFile(join(checkout, '.git', 'info', 'attributes'), RAW_ATTRIBUTES);
252
- await runTransferGit(checkout, ['add', '--force', '--all'], options);
253
- const tree = await runTransferGit(checkout, ['write-tree'], options);
254
- const head = await canonicalCommit(checkout, tree, options.signal);
255
- await runTransferGit(checkout, ['update-ref', 'refs/heads/main', head], options);
256
- const bundlePath = join(temporary, 'workspace.bundle');
257
- if (!options.skipBundle)
258
- await runTransferGit(checkout, ['bundle', 'create', bundlePath, 'HEAD'], options);
259
- return { bundlePath, tree, head, stats, cleanup };
260
- }
261
- catch (error) {
262
- await cleanup();
263
- throw error;
264
- }
265
- }
266
- async function canonicalCommit(root, tree, signal) {
267
- return runTransferGit(root, ['commit-tree', tree, '-m', SNAPSHOT_MESSAGE], { signal });
268
- }
269
- /** Only objects introduced since the last cloud snapshot are packed; local history stays local. */
270
- export async function createWorkspacePushTransfer(root, expectedTree, options = {}) {
271
- if (!/^[a-f0-9]{40,64}$/.test(expectedTree))
272
- throw new WorkspaceTransferError('invalid_workspace_transfer');
273
- const temporary = await mkdtemp(join(tmpdir(), 'playcraft-push-'));
274
- const cleanup = () => rm(temporary, { recursive: true, force: true });
275
- try {
276
- const checkout = join(temporary, 'checkout');
277
- await runTransferGit(temporary, ['clone', '--shared', '--no-checkout', '--', await realpath(root), checkout], options);
278
- const tree = await runTransferGit(checkout, ['rev-parse', '--verify', 'HEAD^{tree}'], options);
279
- const stats = summarizeEntries(await treeEntries(checkout, tree, options.signal));
280
- try {
281
- await runTransferGit(checkout, ['cat-file', '-e', `${expectedTree}^{tree}`], options);
282
- }
283
- catch (error) {
284
- if (error instanceof WorkspaceTransferError && error.code === 'workspace_transfer_git_failed')
285
- throw new WorkspaceTransferError('workspace_transfer_base_missing');
286
- throw error;
287
- }
288
- const base = await canonicalCommit(checkout, expectedTree, options.signal);
289
- const head = await runTransferGit(checkout, ['commit-tree', tree, '-p', base, '-m', SNAPSHOT_MESSAGE], options);
290
- const transferRef = `refs/heads/playcraft-transfer-${tree}`;
291
- await runTransferGit(checkout, ['update-ref', transferRef, head], options);
292
- await runTransferGit(checkout, ['symbolic-ref', 'HEAD', transferRef], options);
293
- const bundlePath = join(temporary, 'workspace.bundle');
294
- await runTransferGit(checkout, ['bundle', 'create', bundlePath, 'HEAD', transferRef, `^${base}`], options);
295
- return { bundlePath, tree, head, stats, cleanup };
296
- }
297
- catch (error) {
298
- await cleanup();
299
- throw error;
300
- }
301
- }
302
- async function treeEntries(root, ref = 'HEAD', signal) {
303
- const entries = [];
304
- const normalized = new Set();
305
- let pending = '';
306
- const parse = (line) => {
307
- const match = /^(100644|100755) blob ([a-f0-9]{40,64})\s+(\d+)\t(.+)$/s.exec(line);
308
- if (!match)
309
- throw new WorkspaceTransferError('invalid_workspace_transfer');
310
- const path = match[4];
311
- if (path.length > 1024 || path.includes('\\') || path.startsWith('/') || /[\x00-\x1f\x7f]/.test(path) ||
312
- path.split('/').some(part => !part || part === '.' || part === '..') || excluded(path))
313
- throw new WorkspaceTransferError('invalid_workspace_transfer');
314
- const size = Number(match[3]);
315
- if (!Number.isSafeInteger(size) || normalized.has(path.toLowerCase()))
316
- throw new WorkspaceTransferError('invalid_workspace_transfer');
317
- normalized.add(path.toLowerCase());
318
- entries.push({ path, sha: match[2], executable: match[1] === '100755', size });
319
- };
320
- await runTransferGit(root, ['ls-tree', '-r', '-z', '-l', ref], { signal, onStdout(chunk) {
321
- pending += chunk;
322
- let end;
323
- while ((end = pending.indexOf('\0')) !== -1) {
324
- parse(pending.slice(0, end));
325
- pending = pending.slice(end + 1);
326
- }
327
- if (pending.length > 1200)
328
- throw new WorkspaceTransferError('invalid_workspace_transfer');
329
- } });
330
- if (pending)
331
- throw new WorkspaceTransferError('invalid_workspace_transfer');
332
- return entries;
333
- }
334
- function summarizeEntries(entries) {
335
- const bytes = entries.reduce((total, entry) => total + entry.size, 0);
336
- if (!Number.isSafeInteger(bytes))
337
- throw new WorkspaceTransferError('invalid_workspace_transfer');
338
- return { bytes, files: entries.length };
339
- }
340
- export async function inspectWorkspaceCommit(root, ref = 'HEAD', options = {}) {
341
- const tree = await runTransferGit(root, ['rev-parse', '--verify', '--end-of-options', `${ref}^{tree}`], options);
342
- return summarizeEntries(await treeEntries(root, tree, options.signal));
343
- }
344
- async function safeTarget(root, path) {
345
- const target = resolve(root, path);
346
- if (!target.startsWith(`${root}${sep}`))
347
- throw new WorkspaceTransferError('invalid_workspace_transfer');
348
- let current = root;
349
- for (const segment of path.split('/')) {
350
- current = join(current, segment);
351
- const info = await lstat(current).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
352
- return undefined; throw error; });
353
- if (info?.isSymbolicLink())
354
- throw new WorkspaceTransferError('workspace_transfer_symlink');
355
- }
356
- return target;
357
- }
358
- /** Compare the entire checkout before applying local commits, so cloud edits are never overwritten. */
359
- export async function applyWorkspaceTransfer(root, bundle, expectedTree, options = {}) {
360
- if (!/^[a-f0-9]{40,64}$/.test(expectedTree))
361
- throw new WorkspaceTransferError('invalid_workspace_transfer');
362
- options.signal?.throwIfAborted();
363
- const rootReal = await realpath(root);
364
- const temporary = await mkdtemp(join(tmpdir(), 'playcraft-import-'));
365
- let current;
366
- try {
367
- const bundlePath = typeof bundle === 'string' ? resolve(bundle) : join(temporary, 'incoming.bundle');
368
- const incoming = join(temporary, 'checkout');
369
- if (typeof bundle !== 'string')
370
- await writeFile(bundlePath, bundle, { mode: 0o600 });
371
- const bundleInfo = await stat(bundlePath);
372
- if (!bundleInfo.isFile() || !bundleInfo.size)
373
- throw new WorkspaceTransferError('invalid_workspace_transfer');
374
- const advertised = await runTransferGit(temporary, ['bundle', 'list-heads', bundlePath], options);
375
- const targets = advertised.split('\n').map(line => /^[a-f0-9]{40,64} refs\/heads\/playcraft-transfer-([a-f0-9]{40,64})$/.exec(line)?.[1]).filter(Boolean);
376
- if (targets.length > 1)
377
- throw new WorkspaceTransferError('invalid_workspace_transfer');
378
- const targetTree = targets[0];
379
- current = await createWorkspaceTransfer(rootReal, { ...options, skipBundle: true });
380
- // A lost response can be retried after the original prerequisite has left the cloud snapshot.
381
- if (targetTree === current.tree) {
382
- await options.validateSnapshot?.(current.stats, current.stats, bundleInfo.size);
383
- return { tree: current.tree, head: current.head, changedPaths: [] };
384
- }
385
- const baseline = join(dirname(current.bundlePath), 'checkout');
386
- await runTransferGit(temporary, ['clone', '--shared', '--no-checkout', '--', baseline, incoming], options);
387
- await writeFile(join(incoming, '.git', 'info', 'attributes'), RAW_ATTRIBUTES);
388
- try {
389
- await runTransferGit(incoming, ['fetch', '--no-tags', '--', bundlePath, 'HEAD'], options);
390
- }
391
- catch (error) {
392
- if (current.tree !== expectedTree)
393
- throw new WorkspaceTransferError('workspace_transfer_conflict');
394
- if (error instanceof WorkspaceTransferError && error.code === 'workspace_transfer_git_failed')
395
- throw new WorkspaceTransferError('invalid_workspace_transfer');
396
- throw error;
397
- }
398
- const entries = await treeEntries(incoming, 'FETCH_HEAD', options.signal);
399
- const tree = await runTransferGit(incoming, ['rev-parse', 'FETCH_HEAD^{tree}'], options);
400
- const head = await runTransferGit(incoming, ['rev-parse', 'FETCH_HEAD'], options);
401
- if (targetTree && targetTree !== tree)
402
- throw new WorkspaceTransferError('invalid_workspace_transfer');
403
- await options.validateSnapshot?.(summarizeEntries(entries), current.stats, bundleInfo.size);
404
- if (current.tree === tree)
405
- return { tree, head, changedPaths: [] };
406
- if (current.tree !== expectedTree)
407
- throw new WorkspaceTransferError('workspace_transfer_conflict');
408
- const previous = new Map((await treeEntries(baseline, 'HEAD', options.signal)).map(entry => [entry.path, entry]));
409
- const next = new Map(entries.map(entry => [entry.path, entry]));
410
- const changedPaths = [...new Set([...previous.keys(), ...next.keys()])]
411
- .filter(path => previous.get(path)?.sha !== next.get(path)?.sha || previous.get(path)?.executable !== next.get(path)?.executable);
412
- for (const path of changedPaths) {
413
- const target = await safeTarget(rootReal, path);
414
- const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
415
- return undefined; throw error; });
416
- if (next.has(path) && info?.isDirectory()) {
417
- const children = await readdir(target, { recursive: true });
418
- for (const child of children) {
419
- const childPath = `${path}/${child.split(sep).join('/')}`;
420
- const childInfo = await lstat(join(target, child));
421
- if (!childInfo.isDirectory() && (!previous.has(childPath) || next.has(childPath)))
422
- throw new WorkspaceTransferError('workspace_transfer_conflict');
423
- }
424
- }
425
- }
426
- await runTransferGit(incoming, ['checkout', '--force', '--detach', head], options);
427
- const recheck = await copySnapshot(rootReal, undefined, options.signal, true);
428
- if (recheck.tree !== expectedTree)
429
- throw new WorkspaceTransferError('workspace_transfer_conflict');
430
- const applied = [];
431
- try {
432
- // Deleting files first also permits a file to become a directory, or the reverse.
433
- for (const path of changedPaths.filter(path => !next.has(path)).sort((a, b) => b.length - a.length)) {
434
- options.signal?.throwIfAborted();
435
- if (!await matchesFile(rootReal, path, previous.get(path)))
436
- throw new WorkspaceTransferError('workspace_transfer_conflict');
437
- await rm(await safeTarget(rootReal, path), { force: true });
438
- applied.push(path);
439
- await removeEmptyParents(rootReal, join(rootReal, path));
440
- }
441
- for (const path of changedPaths.filter(path => next.has(path))) {
442
- options.signal?.throwIfAborted();
443
- if (!await matchesFile(rootReal, path, previous.get(path)))
444
- throw new WorkspaceTransferError('workspace_transfer_conflict');
445
- const entry = next.get(path);
446
- await installFile(rootReal, path, join(incoming, path), entry.executable);
447
- applied.push(path);
448
- }
449
- }
450
- catch (error) {
451
- // Roll back only our writes; never replace another writer's intervening content.
452
- for (const path of applied.reverse()) {
453
- if (!await matchesFile(rootReal, path, next.get(path)))
454
- throw new WorkspaceTransferError('workspace_transfer_rollback_conflict');
455
- const old = previous.get(path);
456
- if (old)
457
- await installFile(rootReal, path, join(baseline, path), old.executable);
458
- else {
459
- await rm(await safeTarget(rootReal, path), { force: true });
460
- await removeEmptyParents(rootReal, join(rootReal, path));
461
- }
462
- }
463
- throw error;
464
- }
465
- return { tree, head, changedPaths };
466
- }
467
- finally {
468
- await current?.cleanup();
469
- await rm(temporary, { recursive: true, force: true });
470
- }
471
- }
@@ -1,75 +0,0 @@
1
- import { TURN_FILES_CHANGED_EVENT, } from '@playcraft/common/cloud-workspace/runtime';
2
- import { diffWorkspaceTrees, retainTurnSnapshots, snapshotWorkspaceTree } from './git.js';
3
- import { shareWorkspaceGit } from './shared-git.js';
4
- const TURN_ENDS = new Set(['turn/completed', 'turn.completed', 'turn.interrupted', 'turn.failed']);
5
- /**
6
- * Snapshots taken when a session's turn starts, until that turn ends. Kept in memory only: a
7
- * restart ends the native turn as well, and that turn then simply reports no changes.
8
- */
9
- const started = new WeakMap();
10
- function turnsOf(state) {
11
- let turns = started.get(state);
12
- if (!turns)
13
- started.set(state, turns = new Map());
14
- return turns;
15
- }
16
- /**
17
- * Records the work tree before a turn is sent. A directory that cannot be snapshotted (no
18
- * repository, Git failure) gets no change summary; the turn itself is never held back by it.
19
- */
20
- export async function beginTurnChanges(state, sessionId, input) {
21
- turnsOf(state).delete(sessionId);
22
- if (input.directoryName === 'root')
23
- return;
24
- await shareWorkspaceGit(state, input.root).catch(() => undefined);
25
- const before = await snapshotWorkspaceTree(input.root).catch(() => undefined);
26
- if (before)
27
- turnsOf(state).set(sessionId, { ...input, before });
28
- }
29
- /** A turn that never started has nothing to compare. */
30
- export function abandonTurnChanges(state, sessionId) {
31
- turnsOf(state).delete(sessionId);
32
- }
33
- /**
34
- * When a session's turn ends, compares the work tree with its start and records the files that
35
- * changed for that session's conversation. Returns no event when nothing changed.
36
- */
37
- export async function finishTurnChanges(state, event) {
38
- const { threadId, turnId } = event;
39
- if (!TURN_ENDS.has(event.method) || !threadId || !turnId)
40
- return [];
41
- const session = state.journal.listSessions().find((item) => item.threadId === threadId);
42
- const start = session && turnsOf(state).get(session.sessionId);
43
- if (!session || !start)
44
- return [];
45
- turnsOf(state).delete(session.sessionId);
46
- try {
47
- await shareWorkspaceGit(state, start.root);
48
- const after = await snapshotWorkspaceTree(start.root);
49
- const { files, truncated } = await diffWorkspaceTrees(start.root, start.before, after);
50
- if (!files.length)
51
- return [];
52
- await retainTurnSnapshots(start.root, turnId, start.before, after);
53
- const changes = { threadId, turnId, before: start.before, after, files, truncated };
54
- return [await state.journal.allocateSourceEvent({
55
- runtimeId: state.config.runtimeId,
56
- generation: state.config.generation,
57
- runtimeEpoch: state.runtimeEpoch,
58
- type: TURN_FILES_CHANGED_EVENT,
59
- payload: {
60
- ...changes,
61
- sessionId: session.sessionId,
62
- ...(start.workspaceId ? { workspaceId: start.workspaceId } : {}),
63
- ...(start.directoryName ? { directoryName: start.directoryName } : {}),
64
- },
65
- occurredAt: new Date().toISOString(),
66
- sessionId: session.sessionId,
67
- workspaceId: start.workspaceId,
68
- threadId,
69
- turnId,
70
- })];
71
- }
72
- catch {
73
- return [];
74
- }
75
- }
@@ -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.