@playcraft/cli 0.1.53-beta → 0.1.54

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