@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,173 +0,0 @@
1
- import { constants } from 'node:fs';
2
- import { lstat, open } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { hashOperationPayload, sandboxBatchMemberDeliverSchema, } from '@playcraft/common/cloud-workspace/runtime';
5
- import { workspaceRoot } from '../workspaces/registry.js';
6
- import { groupExited, runProcessGroup, stopProcessGroup } from './processes.js';
7
- import { memberStatus, readMember, readStopMarker, serializeRun, writeMember, } from './records.js';
8
- /** Base build writes dist/index.html. Channel packaging stays on export playable (`--mode full`). */
9
- function buildCommand() {
10
- return (process.env.PLAYCRAFT_BATCH_BUILD_COMMAND ?? 'CI=1 playcraft build --mode base --output dist .');
11
- }
12
- async function readBuiltHtml(root) {
13
- const htmlPath = join(root, 'dist', 'index.html');
14
- const info = await lstat(htmlPath).catch(() => undefined);
15
- if (!info?.isFile() || info.isSymbolicLink())
16
- throw new Error('batch_build_failed');
17
- const handle = await open(htmlPath, constants.O_RDONLY | constants.O_NOFOLLOW).catch(() => {
18
- throw new Error('batch_build_failed');
19
- });
20
- await handle.close();
21
- }
22
- async function prove(record) {
23
- let stopped = true;
24
- for (const process of record.processes) {
25
- if (!(process.stopped || groupExited(process.pid))) {
26
- process.stopped = await stopProcessGroup(process);
27
- if (!process.stopped)
28
- stopped = false;
29
- }
30
- else
31
- process.stopped = true;
32
- }
33
- return stopped;
34
- }
35
- export async function deliverBatchMember(state, body) {
36
- if (!body ||
37
- typeof body !== 'object' ||
38
- !('occupancyId' in body) ||
39
- !body.occupancyId)
40
- throw new Error('occupancy_required');
41
- const parsed = sandboxBatchMemberDeliverSchema.safeParse(body);
42
- if (!parsed.success)
43
- throw new Error('invalid_batch_request');
44
- const command = parsed.data;
45
- const hash = hashOperationPayload(command);
46
- return serializeRun(command.runId, async () => {
47
- const existing = await readMember(state, command.runId);
48
- if (existing && command.ownerFence < existing.ownerFence)
49
- throw new Error('stale_owner');
50
- if (existing?.state === 'completed' &&
51
- existing.phase === 'deliver' &&
52
- existing.evidence &&
53
- existing.commandHash?.deliver === hash &&
54
- existing.ownerFence === command.ownerFence) {
55
- return memberStatus(existing);
56
- }
57
- if ((await readStopMarker(state, command.runId)) &&
58
- existing?.state === 'completed' &&
59
- existing.evidence)
60
- return memberStatus(existing);
61
- if (await readStopMarker(state, command.runId))
62
- return memberStatus(await markStopped(state, command, existing));
63
- if (existing &&
64
- existing.ownerFence === command.ownerFence &&
65
- existing.commandHash?.deliver &&
66
- existing.commandHash.deliver !== hash &&
67
- existing.state === 'completed') {
68
- throw new Error('batch_command_conflict');
69
- }
70
- const root = await workspaceRoot(state, command.workspaceId, command.directoryName);
71
- let record = await writeMember(state, {
72
- runId: command.runId,
73
- ownerFence: command.ownerFence,
74
- occupancyId: command.occupancyId,
75
- workspaceId: command.workspaceId,
76
- directoryName: command.directoryName,
77
- phase: 'deliver',
78
- state: 'running',
79
- writersStopped: false,
80
- holding: true,
81
- stopRequested: false,
82
- processes: existing?.processes ?? [],
83
- sessionId: existing?.sessionId,
84
- operationId: existing?.operationId,
85
- commandHash: { ...existing?.commandHash, deliver: hash },
86
- snapshotDigest: existing?.snapshotDigest,
87
- branchName: existing?.branchName,
88
- updatedAt: new Date().toISOString(),
89
- sourceCommit: existing?.sourceCommit ??
90
- state.journal
91
- .getWorkspace(command.workspaceId)
92
- ?.directories?.find((directory) => directory.directoryName === command.directoryName)
93
- ?.sourceCommit,
94
- beforeTree: existing?.beforeTree,
95
- });
96
- try {
97
- if (await readStopMarker(state, command.runId))
98
- return memberStatus(await markStopped(state, command, record));
99
- const built = await runProcessGroup(root, buildCommand(), 'build', async (process) => {
100
- record = await writeMember(state, { ...record, processes: [...record.processes, process] });
101
- });
102
- record = await writeMember(state, {
103
- ...record,
104
- processes: record.processes.map((process) => process.pid === built.process.pid ? built.process : process),
105
- });
106
- if (await readStopMarker(state, command.runId))
107
- return memberStatus(await markStopped(state, command, record));
108
- if (built.code !== 0)
109
- throw new Error('batch_build_failed');
110
- await readBuiltHtml(root);
111
- const writersStopped = await prove(record);
112
- if (!writersStopped)
113
- return memberStatus(await writeMember(state, {
114
- ...record,
115
- state: 'stopping',
116
- writersStopped: false,
117
- holding: true,
118
- }));
119
- if (await readStopMarker(state, command.runId))
120
- return memberStatus(await markStopped(state, command, record));
121
- record = await writeMember(state, {
122
- ...record,
123
- state: 'completed',
124
- writersStopped: true,
125
- holding: false,
126
- error: undefined,
127
- evidence: { verified: true },
128
- });
129
- return memberStatus(record);
130
- }
131
- catch (error) {
132
- const code = error instanceof Error && /^[a-z0-9_]+$/.test(error.message)
133
- ? error.message
134
- : 'batch_deliver_failed';
135
- const writersStopped = await prove(record);
136
- record = await writeMember(state, {
137
- ...record,
138
- state: writersStopped ? 'failed' : 'stopping',
139
- writersStopped,
140
- holding: !writersStopped,
141
- error: code,
142
- });
143
- return memberStatus(record);
144
- }
145
- });
146
- }
147
- async function markStopped(state, command, existing) {
148
- if (existing)
149
- await prove(existing);
150
- return writeMember(state, {
151
- runId: command.runId,
152
- ownerFence: command.ownerFence,
153
- occupancyId: existing?.occupancyId ?? command.occupancyId,
154
- workspaceId: command.workspaceId,
155
- directoryName: command.directoryName,
156
- phase: 'deliver',
157
- state: 'stopped',
158
- writersStopped: true,
159
- holding: false,
160
- stopRequested: true,
161
- processes: existing?.processes ?? [],
162
- sessionId: existing?.sessionId,
163
- operationId: existing?.operationId,
164
- headCommit: existing?.headCommit,
165
- evidence: existing?.evidence,
166
- commandHash: existing?.commandHash,
167
- snapshotDigest: existing?.snapshotDigest,
168
- branchName: existing?.branchName,
169
- updatedAt: new Date().toISOString(),
170
- sourceCommit: existing?.sourceCommit,
171
- beforeTree: existing?.beforeTree,
172
- });
173
- }
@@ -1,101 +0,0 @@
1
- import { rm, writeFile } from 'node:fs/promises';
2
- import { statfs } from 'node:fs/promises';
3
- import { batchSourceFreezeResultSchema, batchSourceRemoteRef, sandboxBatchSourceFreezeRequestSchema, workspaceDiskAdmission, } from '@playcraft/common/cloud-workspace/runtime';
4
- import { stopBackgroundWriter } from '../processes/managed-writes.js';
5
- import { workspaceRoot } from '../workspaces/registry.js';
6
- import { gitRead } from './git.js';
7
- import { captureIndependentSource } from './source-capture.js';
8
- import { filesystemObjectStore, readSnapshot, serializeFreeze, sourceCacheDir, writeSnapshot, } from './records.js';
9
- import { assertSourceIdentity, readSourceCandidate, writeSourceCandidate } from './source-candidate.js';
10
- import { BatchSourceFreezeError, sourceFreezeError } from './source-failure.js';
11
- import { publishSourceCandidate } from './source-publish.js';
12
- async function usagePercent(path) {
13
- const disk = await statfs(path);
14
- if (disk.blocks <= 0)
15
- throw new Error('disk_usage_unavailable');
16
- return ((disk.blocks - disk.bfree) / disk.blocks) * 100;
17
- }
18
- /** Dependency installs are keyed `workspaceId:directoryName`. A bare workspace id is not this directory. */
19
- async function stopManagedWriters(state, workspaceId, directoryName) {
20
- const scope = `${workspaceId}:${directoryName}`;
21
- for (const write of state.journal.listManagedWrites()) {
22
- if (write.stoppedAt || write.workspaceId !== scope)
23
- continue;
24
- if (write.pid !== undefined) {
25
- const stopped = await stopBackgroundWriter(write.pid);
26
- if (!stopped)
27
- continue;
28
- }
29
- await state.journal.putManagedWrite({ ...write, stoppedAt: new Date().toISOString() });
30
- }
31
- }
32
- export async function freezeBatchSource(state, body, options) {
33
- const parsed = sandboxBatchSourceFreezeRequestSchema.safeParse(body);
34
- if (!parsed.success)
35
- throw new Error('invalid_batch_request');
36
- const request = parsed.data;
37
- return serializeFreeze(async () => {
38
- let candidate;
39
- let source;
40
- try {
41
- const pending = await readSourceCandidate(state, request.batchId);
42
- const existing = await readSnapshot(state, request.batchId);
43
- if (existing) {
44
- assertSourceIdentity(state, request, existing, pending);
45
- return batchSourceFreezeResultSchema.parse({ status: 'frozen', snapshot: existing });
46
- }
47
- if (!pending && 'resumeOnly' in request && request.resumeOnly === true) {
48
- throw await sourceFreezeError(state, request.batchId, { code: 'batch_source_candidate_lost', stage: 'capture', retryable: false, outcome: 'unknown' });
49
- }
50
- if (pending)
51
- assertSourceIdentity(state, request, pending.snapshot, pending);
52
- source = await workspaceRoot(state, request.workspaceId, request.sourceDirectoryName);
53
- if (pending)
54
- candidate = pending;
55
- else {
56
- const percent = Math.min(100, Math.max(0, options?.usagePercent ?? await usagePercent(source)));
57
- if (workspaceDiskAdmission(percent) === 'paused')
58
- throw new Error('disk_admission_paused');
59
- await stopManagedWriters(state, request.workspaceId, request.sourceDirectoryName);
60
- const cache = sourceCacheDir(state, request.batchId);
61
- await rm(cache, { recursive: true, force: true });
62
- const captured = await captureIndependentSource(source, cache);
63
- await writeFile(`${cache}.digest`, captured.digest, { mode: 0o600 });
64
- const binding = state.journal.getWorkspace(request.workspaceId);
65
- const snapshot = {
66
- batchId: request.batchId, commitHash: captured.commitHash, digest: captured.digest,
67
- sourceWorkspaceId: request.workspaceId, sourceDirectoryName: request.sourceDirectoryName,
68
- frozenAt: new Date((await gitRead(cache, ['show', '-s', '--format=%cI', 'HEAD'])).trim()).toISOString(),
69
- ...(request.persist === 'remote_ref' ? { remoteRef: batchSourceRemoteRef(request.batchId) }
70
- : { artifactKey: `workspaces/${request.workspaceId}/batches/${request.batchId}/source/${captured.digest}.json.gz` }),
71
- };
72
- candidate = {
73
- version: 1, persist: request.persist, repositoryUrl: binding?.repositoryUrl ?? undefined, projectId: binding?.projectId,
74
- branchName: request.sourceDirectoryName === 'basic' ? binding?.branchName ?? undefined
75
- : binding?.directories?.find(directory => directory.directoryName === request.sourceDirectoryName)?.branchName ?? undefined,
76
- snapshot,
77
- };
78
- await writeSourceCandidate(state, candidate);
79
- }
80
- }
81
- catch (error) {
82
- if (error instanceof BatchSourceFreezeError)
83
- throw error;
84
- const known = new Set(['disk_admission_paused', 'disk_usage_unavailable', 'batch_source_changed', 'batch_source_path_invalid',
85
- 'workspace_not_registered', 'batch_source_identity_mismatch', 'batch_source_snapshot_mismatch']);
86
- const code = error instanceof Error && known.has(error.message) ? error.message : 'batch_source_capture_failed';
87
- throw await sourceFreezeError(state, request.batchId, {
88
- code, stage: 'capture', retryable: !['batch_source_path_invalid', 'batch_source_identity_mismatch', 'batch_source_snapshot_mismatch'].includes(code),
89
- outcome: code === 'batch_source_identity_mismatch' || code === 'batch_source_snapshot_mismatch' ? 'unknown' : 'not_published',
90
- }, error);
91
- }
92
- await publishSourceCandidate(state, candidate, source, options?.objectStore ?? filesystemObjectStore(state));
93
- try {
94
- await writeSnapshot(state, candidate.snapshot);
95
- }
96
- catch (error) {
97
- throw await sourceFreezeError(state, request.batchId, { code: 'batch_source_verification_failed', stage: 'verify', retryable: true, outcome: 'unknown' }, error);
98
- }
99
- return batchSourceFreezeResultSchema.parse({ status: 'frozen', snapshot: candidate.snapshot });
100
- });
101
- }
@@ -1,249 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { mkdir } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { setTimeout as delay } from 'node:timers/promises';
5
- import { hashOperationPayload, operationScopeKey, sandboxBatchMemberGenerateSchema, } from '@playcraft/common/cloud-workspace/runtime';
6
- import { attachNativeCollector, executeOperation } from '../server/dispatch.js';
7
- import { workspaceRoot } from '../workspaces/registry.js';
8
- import { snapshotWorkspaceTree } from '../workspaces/git.js';
9
- import { requireBatchContentChanges } from './content-changes.js';
10
- import { bindMemberPolicy, memberExecutionPolicy } from './policy.js';
11
- import { groupExited, stopProcessGroup } from './processes.js';
12
- import { memberStatus, readMember, readStopMarker, serializeRun, writeMember } from './records.js';
13
- function hashCommand(value) {
14
- return hashOperationPayload(value);
15
- }
16
- function operation(state, input) {
17
- const now = new Date().toISOString();
18
- const record = {
19
- operationId: randomUUID(), environment: state.config.environment, userId: state.config.userId,
20
- clientRequestId: input.clientRequestId, kind: input.kind, status: 'queued', payloadHash: hashOperationPayload(input.payload),
21
- workspaceId: input.workspaceId, directoryName: input.directoryName, sessionId: input.sessionId,
22
- generation: state.config.generation, runtimeEpoch: state.runtimeEpoch, leaseFence: state.acceptedLeaseFence,
23
- createdAt: now, updatedAt: now,
24
- };
25
- return { scopeKey: operationScopeKey(record), record };
26
- }
27
- function turnTerminal(event) {
28
- if (event.kind === 'approval_request')
29
- return 'needs_user';
30
- if (event.method !== 'turn/completed' && event.method !== 'turn.completed' && event.method !== 'turn.failed' && event.method !== 'turn.interrupted')
31
- return undefined;
32
- const turn = event.params && typeof event.params === 'object' ? event.params.turn : undefined;
33
- if (event.method === 'turn.failed' || turn?.status === 'failed')
34
- return 'failed';
35
- if (event.method === 'turn.interrupted' || turn?.status === 'interrupted')
36
- return 'interrupted';
37
- return 'completed';
38
- }
39
- function threadIdOf(event) {
40
- const params = event.params && typeof event.params === 'object' ? event.params : undefined;
41
- return typeof params?.threadId === 'string' ? params.threadId : undefined;
42
- }
43
- async function proveStopped(record) {
44
- let stopped = true;
45
- for (const process of record.processes) {
46
- if (process.stopped || groupExited(process.pid))
47
- process.stopped = true;
48
- else {
49
- const did = await stopProcessGroup(process);
50
- process.stopped = did;
51
- if (!did)
52
- stopped = false;
53
- }
54
- }
55
- return stopped;
56
- }
57
- export async function generateBatchMember(state, body) {
58
- if (!body || typeof body !== 'object' || !('occupancyId' in body) || !body.occupancyId)
59
- throw new Error('occupancy_required');
60
- const parsed = sandboxBatchMemberGenerateSchema.safeParse(body);
61
- if (!parsed.success)
62
- throw new Error('invalid_batch_request');
63
- const command = parsed.data;
64
- const hash = hashCommand(command);
65
- return serializeRun(command.runId, async () => {
66
- attachNativeCollector(state);
67
- const existing = await readMember(state, command.runId);
68
- if (existing && command.ownerFence < existing.ownerFence)
69
- throw new Error('stale_owner');
70
- if (await readStopMarker(state, command.runId))
71
- return memberStatus(await stoppedRecord(state, command, existing));
72
- if (existing && existing.ownerFence === command.ownerFence && existing.commandHash?.generate === hash && existing.phase === 'generate' && existing.state !== 'running') {
73
- return memberStatus(await reconcileGenerate(state, existing));
74
- }
75
- if (existing && existing.ownerFence === command.ownerFence && existing.commandHash?.generate && existing.commandHash.generate !== hash)
76
- throw new Error('batch_command_conflict');
77
- const root = await workspaceRoot(state, command.workspaceId, command.directoryName);
78
- const sessionId = command.sessionId ?? existing?.sessionId ?? `member-${command.runId}`;
79
- const tempDir = join(state.config.stateDir, 'batch-temp', command.runId);
80
- await mkdir(tempDir, { recursive: true, mode: 0o700 });
81
- const policy = memberExecutionPolicy(root, tempDir);
82
- await bindMemberPolicy(state, sessionId, policy);
83
- const modelConfigId = command.model && /^[0-9a-f-]{36}$/i.test(command.model) ? command.model : undefined;
84
- const turnPayload = { text: command.prompt, permissionMode: 'auto', ...(modelConfigId ? { modelConfigId } : {}) };
85
- const turnKey = operation(state, { kind: 'session.turn', clientRequestId: `batch-turn:${command.runId}`, sessionId, workspaceId: command.workspaceId, directoryName: command.directoryName, payload: turnPayload });
86
- const prior = state.journal.getOperation(turnKey.scopeKey);
87
- if (prior && prior.payloadHash !== turnKey.record.payloadHash)
88
- throw new Error('batch_command_conflict');
89
- const sourceCommit = existing?.sourceCommit ?? state.journal.getWorkspace(command.workspaceId)?.directories?.find(directory => directory.directoryName === command.directoryName)?.sourceCommit;
90
- const beforeTree = existing?.beforeTree ?? (prior ? sourceCommit : await snapshotWorkspaceTree(root));
91
- let record = await writeMember(state, {
92
- runId: command.runId, ownerFence: command.ownerFence, occupancyId: command.occupancyId, workspaceId: command.workspaceId,
93
- directoryName: command.directoryName, phase: 'generate', state: prior ? (prior.status === 'uncertain' ? 'unknown' : prior.status === 'completed' ? 'completed' : 'running') : 'running',
94
- writersStopped: false, holding: true, stopRequested: false, processes: existing?.processes ?? [], sessionId,
95
- operationId: prior?.operationId, commandHash: { ...existing?.commandHash, generate: hash },
96
- snapshotDigest: existing?.snapshotDigest, branchName: existing?.branchName, headCommit: existing?.headCommit,
97
- sourceCommit, beforeTree,
98
- updatedAt: new Date().toISOString(),
99
- });
100
- if (prior)
101
- return memberStatus(await finishGenerate(state, record, prior, root));
102
- if (!state.native?.ready()) {
103
- record = await writeMember(state, { ...record, state: 'failed', writersStopped: true, holding: false, error: 'capability_unavailable' });
104
- return memberStatus(record);
105
- }
106
- const terminals = new Map();
107
- const unsubscribe = state.native.onCollected?.((event) => {
108
- const threadId = threadIdOf(event);
109
- const terminal = turnTerminal(event);
110
- if (!threadId || !terminal)
111
- return;
112
- if (terminals.get(threadId) === 'needs_user')
113
- return;
114
- terminals.set(threadId, terminal);
115
- });
116
- try {
117
- if (!state.journal.getSession(sessionId)) {
118
- const created = operation(state, { kind: 'session.create', clientRequestId: `batch-create:${command.runId}`, sessionId, workspaceId: command.workspaceId, directoryName: command.directoryName, payload: { permissionMode: 'auto', ...(modelConfigId ? { modelConfigId } : {}) } });
119
- if (!state.journal.getOperation(created.scopeKey))
120
- await executeOperation(state, created.scopeKey, created.record, { permissionMode: 'auto', ...(modelConfigId ? { modelConfigId } : {}) });
121
- }
122
- if (await readStopMarker(state, command.runId))
123
- return memberStatus(await stoppedRecord(state, command, record));
124
- const started = await executeOperation(state, turnKey.scopeKey, turnKey.record, turnPayload);
125
- record = await writeMember(state, { ...record, operationId: started.operationId, sessionId });
126
- return memberStatus(await finishGenerate(state, record, started, root, () => {
127
- const threadId = state.journal.getSession(sessionId)?.threadId;
128
- return threadId ? terminals.get(threadId) : undefined;
129
- }));
130
- }
131
- finally {
132
- unsubscribe?.();
133
- }
134
- });
135
- }
136
- async function finishGenerate(state, record, started, root, early) {
137
- if (await readStopMarker(state, record.runId))
138
- return stoppedRecord(state, { ...record, occupancyId: record.occupancyId }, record);
139
- const sessionId = record.sessionId;
140
- let terminal = early?.();
141
- if (!terminal && (started.status === 'uncertain' || started.error === 'native_receipt_lost')) {
142
- return writeMember(state, { ...record, state: 'unknown', writersStopped: false, holding: true, operationId: started.operationId, error: 'native_receipt_lost' });
143
- }
144
- if (!terminal && started.status === 'failed') {
145
- const writersStopped = await proveStopped(record);
146
- return writeMember(state, { ...record, state: writersStopped ? 'failed' : 'stopping', writersStopped, holding: !writersStopped, operationId: started.operationId, error: started.error ?? 'batch_turn_failed' });
147
- }
148
- const deadline = Date.now() + 5_000;
149
- while (!terminal && Date.now() < deadline) {
150
- terminal = early?.();
151
- const session = state.journal.getSession(sessionId);
152
- if (session?.turnStatus === 'waiting_for_user')
153
- terminal = 'needs_user';
154
- else if (session?.turnStatus === 'completed')
155
- terminal = 'completed';
156
- else if (session?.turnStatus === 'failed')
157
- terminal = 'failed';
158
- else if (session?.turnStatus === 'interrupted')
159
- terminal = 'interrupted';
160
- if (!terminal)
161
- await delay(15);
162
- }
163
- if (terminal === 'needs_user') {
164
- const session = state.journal.getSession(sessionId);
165
- if (session?.threadId)
166
- await state.native?.interrupt?.({ sessionId, threadId: session.threadId }).catch(() => undefined);
167
- const writersStopped = await proveStopped(record);
168
- if (await readStopMarker(state, record.runId))
169
- return stoppedRecord(state, record, record);
170
- return writeMember(state, {
171
- ...record, state: writersStopped ? 'needs_user' : 'stopping', writersStopped, holding: writersStopped ? false : true,
172
- operationId: started.operationId, error: writersStopped ? 'needs_user' : undefined,
173
- });
174
- }
175
- if (terminal === 'completed') {
176
- const writersStopped = await proveStopped(record);
177
- if (!writersStopped)
178
- return writeMember(state, { ...record, state: 'stopping', writersStopped: false, holding: true, operationId: started.operationId });
179
- if (await readStopMarker(state, record.runId))
180
- return stoppedRecord(state, record, record);
181
- return completeGeneration(state, { ...record, operationId: started.operationId }, root);
182
- }
183
- if (!terminal) {
184
- return writeMember(state, {
185
- ...record, state: 'running', writersStopped: false, holding: true, operationId: started.operationId, error: undefined,
186
- });
187
- }
188
- const writersStopped = await proveStopped(record);
189
- return writeMember(state, {
190
- ...record, state: writersStopped ? (terminal === 'interrupted' ? 'stopped' : 'failed') : 'unknown',
191
- writersStopped, holding: !writersStopped, operationId: started.operationId,
192
- error: writersStopped ? (terminal === 'interrupted' ? undefined : 'batch_turn_failed') : 'native_receipt_lost',
193
- });
194
- }
195
- /** A later status read finishes a generate turn that was still running when dispatch returned. */
196
- export async function settleObservedGenerate(state, record) {
197
- if (record.phase !== 'generate' || record.state !== 'running' || record.stopRequested)
198
- return record;
199
- const session = record.sessionId ? state.journal.getSession(record.sessionId) : undefined;
200
- if (!session || session.turnBlock === 'uncertain' || session.turnStatus === 'starting' || session.turnStatus === 'running')
201
- return record;
202
- const terminal = session.turnStatus === 'completed' ? 'completed'
203
- : session.turnStatus === 'failed' ? 'failed'
204
- : session.turnStatus === 'interrupted' ? 'interrupted'
205
- : session.turnStatus === 'waiting_for_user' ? 'needs_user'
206
- : undefined;
207
- if (!terminal)
208
- return record;
209
- const root = await workspaceRoot(state, record.workspaceId, record.directoryName);
210
- return finishGenerate(state, record, { operationId: record.operationId, status: 'accepted' }, root, () => terminal);
211
- }
212
- async function reconcileGenerate(state, record) {
213
- const session = record.sessionId ? state.journal.getSession(record.sessionId) : undefined;
214
- if (record.state === 'unknown' && session?.turnStatus === 'completed') {
215
- const writersStopped = await proveStopped(record);
216
- if (writersStopped && !await readStopMarker(state, record.runId)) {
217
- const root = await workspaceRoot(state, record.workspaceId, record.directoryName);
218
- return completeGeneration(state, record, root);
219
- }
220
- }
221
- return record;
222
- }
223
- async function completeGeneration(state, record, root) {
224
- try {
225
- const afterTree = await snapshotWorkspaceTree(root);
226
- await requireBatchContentChanges(root, record.beforeTree ?? '', afterTree);
227
- await requireBatchContentChanges(root, record.sourceCommit ?? '', afterTree);
228
- }
229
- catch (error) {
230
- const code = error instanceof Error && /^[a-z0-9_]+$/.test(error.message) ? error.message : 'batch_generation_failed';
231
- return writeMember(state, { ...record, state: 'failed', writersStopped: true, holding: false, error: code });
232
- }
233
- if (await readStopMarker(state, record.runId))
234
- return stoppedRecord(state, record, record);
235
- const head = await import('./git.js').then(git => git.gitRead(root, ['rev-parse', 'HEAD'])).then(value => value.trim()).catch(() => record.headCommit);
236
- return writeMember(state, { ...record, state: 'completed', writersStopped: true, holding: true, headCommit: head, error: undefined });
237
- }
238
- async function stoppedRecord(state, command, existing) {
239
- if (existing)
240
- await proveStopped(existing);
241
- return writeMember(state, {
242
- runId: command.runId, ownerFence: command.ownerFence, occupancyId: command.occupancyId, workspaceId: command.workspaceId,
243
- directoryName: command.directoryName, phase: existing?.phase ?? 'generate', state: 'stopped', writersStopped: true, holding: false,
244
- stopRequested: true, processes: existing?.processes ?? [], sessionId: existing?.sessionId, operationId: existing?.operationId,
245
- headCommit: existing?.headCommit, evidence: existing?.evidence, commandHash: existing?.commandHash, snapshotDigest: existing?.snapshotDigest,
246
- branchName: existing?.branchName, updatedAt: new Date().toISOString(),
247
- sourceCommit: existing?.sourceCommit, beforeTree: existing?.beforeTree,
248
- });
249
- }
@@ -1,40 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import { dirname } from 'node:path';
4
- const execute = promisify(execFile);
5
- /** Read-only git. An empty credential helper keeps the source checkout from authenticating or writing. */
6
- export async function gitRead(root, args) {
7
- return runGit(root, ['-c', 'credential.helper=', ...args]);
8
- }
9
- /** Push and fetch. Local credential helpers copied onto this repo stay in effect. */
10
- export async function gitWrite(root, args) {
11
- return runGit(root, args);
12
- }
13
- async function runGit(root, args) {
14
- const { stdout } = await execute('git', [
15
- '-c', 'core.hooksPath=/dev/null', '-c', 'init.templateDir=', '-c', 'core.fsmonitor=false', '-C', root, ...args,
16
- ], {
17
- timeout: 90_000, maxBuffer: 64 * 1024 * 1024,
18
- env: {
19
- PATH: process.env.PATH, HOME: dirname(root), GIT_OPTIONAL_LOCKS: '0',
20
- GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_NOSYSTEM: '1', GIT_TERMINAL_PROMPT: '0',
21
- },
22
- });
23
- return stdout;
24
- }
25
- /** Copies URL credential helpers onto a snapshot repo without reading or writing the source config. */
26
- export async function copyCredentialHelpers(sourceRoot, destinationRoot) {
27
- const listed = await gitRead(sourceRoot, ['config', '--local', '--get-regexp', '^(credential\\.|http\\.|url\\.)']).catch(() => '');
28
- for (const line of listed.split('\n')) {
29
- if (!line)
30
- continue;
31
- const space = line.indexOf(' ');
32
- if (space < 1)
33
- continue;
34
- const key = line.slice(0, space);
35
- const value = line.slice(space + 1);
36
- if (!/^(credential\.|http\.|url\.)/.test(key) || /[\r\n]/.test(value))
37
- continue;
38
- await gitWrite(destinationRoot, ['config', '--local', key, value]);
39
- }
40
- }
@@ -1,8 +0,0 @@
1
- import { listMembers } from './records.js';
2
- /** True while a member Run still holds the directory. Other sandbox write entries must refuse it. */
3
- export async function batchDirectoryHeld(state, workspaceId, directoryName = 'basic') {
4
- if (!workspaceId)
5
- return false;
6
- const members = await listMembers(state);
7
- return members.some(record => record.holding && record.workspaceId === workspaceId && record.directoryName === directoryName);
8
- }
@@ -1,70 +0,0 @@
1
- import { readFileSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
2
- import { randomUUID } from 'node:crypto';
3
- import { dirname, join } from 'node:path';
4
- const memory = new WeakMap();
5
- /** Unattended member execution: workspace-write to the member directory and one controlled temp dir. */
6
- export function memberExecutionPolicy(cwd, tempDir) {
7
- return {
8
- cwd,
9
- approvalPolicy: 'never',
10
- sandboxPolicy: {
11
- type: 'workspaceWrite',
12
- writableRoots: [cwd, tempDir],
13
- networkAccess: true,
14
- excludeTmpdirEnvVar: true,
15
- excludeSlashTmp: true,
16
- },
17
- };
18
- }
19
- function policyPath(state, sessionId) {
20
- return join(state.config.stateDir, 'batch-sessions', `${sessionId.replace(/[^a-zA-Z0-9._-]/g, '_')}.json`);
21
- }
22
- function parsePolicy(raw) {
23
- const value = JSON.parse(raw);
24
- if (value?.approvalPolicy !== 'never' || value.sandboxPolicy?.type !== 'workspaceWrite')
25
- return undefined;
26
- if (!value.cwd || !Array.isArray(value.sandboxPolicy.writableRoots) || value.sandboxPolicy.writableRoots.length === 0)
27
- return undefined;
28
- if (!value.sandboxPolicy.excludeSlashTmp || !value.sandboxPolicy.excludeTmpdirEnvVar)
29
- return undefined;
30
- return value;
31
- }
32
- export async function bindMemberPolicy(state, sessionId, policy) {
33
- const path = policyPath(state, sessionId);
34
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
35
- const temporary = `${path}.${randomUUID()}.tmp`;
36
- writeFileSync(temporary, JSON.stringify(policy), { mode: 0o600 });
37
- renameSync(temporary, path);
38
- const map = memory.get(state) ?? new Map();
39
- map.set(sessionId, policy);
40
- memory.set(state, map);
41
- }
42
- /** Synchronous: the shared session adapter reapplies this on every thread start and resume. */
43
- export function trustedMemberPolicy(state, sessionId) {
44
- const cached = memory.get(state)?.get(sessionId);
45
- if (cached)
46
- return cached;
47
- try {
48
- const parsed = parsePolicy(readFileSync(policyPath(state, sessionId), 'utf8'));
49
- if (!parsed) {
50
- return {
51
- cwd: state.config.workspaceRoot,
52
- approvalPolicy: 'never',
53
- sandboxPolicy: { type: 'readOnly', networkAccess: false },
54
- };
55
- }
56
- const map = memory.get(state) ?? new Map();
57
- map.set(sessionId, parsed);
58
- memory.set(state, map);
59
- return parsed;
60
- }
61
- catch (error) {
62
- if (error.code === 'ENOENT')
63
- return undefined;
64
- return {
65
- cwd: state.config.workspaceRoot,
66
- approvalPolicy: 'never',
67
- sandboxPolicy: { type: 'readOnly', networkAccess: false },
68
- };
69
- }
70
- }