@playcraft/cli 0.1.23 → 0.1.24

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 (278) hide show
  1. package/README.md +3 -38
  2. package/dist/agent/local-backend.js +1 -1
  3. package/dist/cli-root-help.js +0 -1
  4. package/dist/commands/build.js +4 -9
  5. package/dist/commands/create.js +33 -26
  6. package/dist/commands/image.js +6 -2
  7. package/dist/commands/login.js +42 -84
  8. package/dist/commands/skills.js +0 -2
  9. package/dist/commands/tools-generation.js +4 -2
  10. package/dist/commands/tools.js +0 -2
  11. package/dist/config.js +4 -59
  12. package/dist/index.js +1 -6
  13. package/dist/remix/clone.js +0 -2
  14. package/dist/remix/init-template.js +0 -2
  15. package/dist/remix/pull.js +0 -2
  16. package/dist/remix/push.js +1 -21
  17. package/dist/utils/agent-api-client.js +29 -148
  18. package/dist/utils/playcraft-http-client.js +4 -6
  19. package/package.json +2 -8
  20. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +61 -23
  21. package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +61 -23
  22. package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +61 -23
  23. package/dist/auth/account-activation.js +0 -157
  24. package/dist/auth/messages.js +0 -30
  25. package/dist/commands/platform-skills.generated.js +0 -19
  26. package/dist/commands/tools-batch.js +0 -59
  27. package/dist/commands/workspace-runtime.js +0 -54
  28. package/dist/project-skills/commands.js +0 -72
  29. package/dist/project-skills/lifecycle.js +0 -28
  30. package/dist/project-skills/local-run.js +0 -112
  31. package/dist/project-skills/local-store.js +0 -149
  32. package/dist/project-skills/messages.js +0 -72
  33. package/dist/project-skills/reconcile.js +0 -62
  34. package/dist/project-skills/remote-cache.js +0 -51
  35. package/dist/project-skills/validation.js +0 -19
  36. package/dist/utils/environment-endpoints.js +0 -17
  37. package/dist/utils/tool-operation-journal.js +0 -124
  38. package/dist/workspace-runtime/codex/app-server.js +0 -574
  39. package/dist/workspace-runtime/codex/config-toml.js +0 -108
  40. package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -123
  41. package/dist/workspace-runtime/codex/launcher-client.js +0 -163
  42. package/dist/workspace-runtime/codex/loopback.js +0 -143
  43. package/dist/workspace-runtime/codex/model-broker.js +0 -239
  44. package/dist/workspace-runtime/codex/native-adapter.js +0 -9
  45. package/dist/workspace-runtime/main.js +0 -10
  46. package/dist/workspace-runtime/persistence/journal.js +0 -355
  47. package/dist/workspace-runtime/persistence/sqlite-client.js +0 -61
  48. package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1015
  49. package/dist/workspace-runtime/previews/publish.js +0 -259
  50. package/dist/workspace-runtime/previews/single-file.js +0 -43
  51. package/dist/workspace-runtime/processes/managed-writes.js +0 -69
  52. package/dist/workspace-runtime/production/contracts.js +0 -17
  53. package/dist/workspace-runtime/production/controller.js +0 -207
  54. package/dist/workspace-runtime/production/dependencies.js +0 -60
  55. package/dist/workspace-runtime/production/native.js +0 -70
  56. package/dist/workspace-runtime/production/processes.js +0 -86
  57. package/dist/workspace-runtime/production/save-command.js +0 -20
  58. package/dist/workspace-runtime/production/stages.js +0 -175
  59. package/dist/workspace-runtime/production/storage.js +0 -32
  60. package/dist/workspace-runtime/serve.js +0 -199
  61. package/dist/workspace-runtime/server/auth.js +0 -21
  62. package/dist/workspace-runtime/server/connectivity.js +0 -201
  63. package/dist/workspace-runtime/server/desktop-host.js +0 -429
  64. package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
  65. package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
  66. package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
  67. package/dist/workspace-runtime/server/desktop-preview.js +0 -189
  68. package/dist/workspace-runtime/server/dispatch.js +0 -848
  69. package/dist/workspace-runtime/server/endpoints.js +0 -19
  70. package/dist/workspace-runtime/server/execution-group.js +0 -85
  71. package/dist/workspace-runtime/server/http.js +0 -919
  72. package/dist/workspace-runtime/server/lock.js +0 -53
  73. package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
  74. package/dist/workspace-runtime/server/terminal-host.js +0 -294
  75. package/dist/workspace-runtime/server/types.js +0 -1
  76. package/dist/workspace-runtime/workspaces/attachments.js +0 -109
  77. package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
  78. package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -111
  79. package/dist/workspace-runtime/workspaces/context-error.js +0 -2
  80. package/dist/workspace-runtime/workspaces/dependencies.js +0 -264
  81. package/dist/workspace-runtime/workspaces/developer-command.js +0 -64
  82. package/dist/workspace-runtime/workspaces/directories.js +0 -106
  83. package/dist/workspace-runtime/workspaces/directory-access.js +0 -20
  84. package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
  85. package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
  86. package/dist/workspace-runtime/workspaces/empty-template.js +0 -32
  87. package/dist/workspace-runtime/workspaces/files.js +0 -113
  88. package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
  89. package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
  90. package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
  91. package/dist/workspace-runtime/workspaces/git.js +0 -471
  92. package/dist/workspace-runtime/workspaces/json5-edit.js +0 -170
  93. package/dist/workspace-runtime/workspaces/parameters.js +0 -272
  94. package/dist/workspace-runtime/workspaces/prepare.js +0 -263
  95. package/dist/workspace-runtime/workspaces/registry.js +0 -192
  96. package/dist/workspace-runtime/workspaces/revisions.js +0 -31
  97. package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -46
  98. package/dist/workspace-runtime/workspaces/skills.js +0 -179
  99. package/project-template-v2/.claude/agents/artist.md +0 -82
  100. package/project-template-v2/.claude/agents/developer.md +0 -153
  101. package/project-template-v2/.claude/agents/game-designer.md +0 -264
  102. package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
  103. package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
  104. package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
  105. package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
  106. package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
  107. package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
  108. package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
  109. package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
  110. package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
  111. package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
  112. package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
  113. package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
  114. package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
  115. package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
  116. package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
  117. package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
  118. package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
  119. package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
  120. package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
  121. package/project-template-v2/.claude/agents/reviewer.md +0 -75
  122. package/project-template-v2/.claude/agents/technical-artist.md +0 -86
  123. package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
  124. package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
  125. package/project-template-v2/.claude/settings.json +0 -33
  126. package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
  127. package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
  128. package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
  129. package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
  130. package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
  131. package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
  132. package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
  133. package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  134. package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
  135. package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
  136. package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
  137. package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
  138. package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
  139. package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
  140. package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
  141. package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -298
  142. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
  143. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
  144. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -324
  145. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
  146. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
  147. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -137
  148. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
  149. package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
  150. package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
  151. package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
  152. package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
  153. package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
  154. package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
  155. package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
  156. package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
  157. package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
  158. package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
  159. package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
  160. package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
  161. package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
  162. package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
  163. package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
  164. package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
  165. package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
  166. package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
  167. package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
  168. package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
  169. package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
  170. package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
  171. package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
  172. package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
  173. package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
  174. package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
  175. package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
  176. package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
  177. package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
  178. package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
  179. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
  180. package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
  181. package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
  182. package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
  183. package/project-template-v2/.claude/snapshot.mjs +0 -263
  184. package/project-template-v2/.playcraft/skills.lock.json +0 -152
  185. package/project-template-v2/CLAUDE.md +0 -146
  186. package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
  187. package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
  188. package/project-template-v2/assets/bundles/.gitkeep +0 -0
  189. package/project-template-v2/assets/images/bg/.gitkeep +0 -0
  190. package/project-template-v2/assets/images/reference/.gitkeep +0 -0
  191. package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
  192. package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
  193. package/project-template-v2/assets/images/ui/.gitkeep +0 -0
  194. package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
  195. package/project-template-v2/assets/models/.gitkeep +0 -0
  196. package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
  197. package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
  198. package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
  199. package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
  200. package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
  201. package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
  202. package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
  203. package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
  204. package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
  205. package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
  206. package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
  207. package/project-template-v2/docs/project-state.json +0 -60
  208. package/project-template-v2/docs/project-state.md +0 -72
  209. package/project-template-v2/docs/standards/README.md +0 -225
  210. package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
  211. package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
  212. package/project-template-v2/docs/standards/artifacts/design.md +0 -22
  213. package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
  214. package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
  215. package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
  216. package/project-template-v2/game/index.ts +0 -18
  217. package/project-template-v2/globals.d.ts +0 -51
  218. package/project-template-v2/index.css +0 -34
  219. package/project-template-v2/index.html +0 -18
  220. package/project-template-v2/main.ts +0 -9
  221. package/project-template-v2/package.json +0 -46
  222. package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
  223. package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
  224. package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
  225. package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
  226. package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
  227. package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
  228. package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
  229. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
  230. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
  231. package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
  232. package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
  233. package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
  234. package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
  235. package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
  236. package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
  237. package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
  238. package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
  239. package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
  240. package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
  241. package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
  242. package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
  243. package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
  244. package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
  245. package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
  246. package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
  247. package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
  248. package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
  249. package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
  250. package/project-template-v2/skills/playable-record/SKILL.md +0 -140
  251. package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
  252. package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
  253. package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
  254. package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
  255. package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
  256. package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
  257. package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
  258. package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
  259. package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
  260. package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
  261. package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
  262. package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
  263. package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
  264. package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
  265. package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
  266. package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
  267. package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
  268. package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
  269. package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
  270. package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
  271. package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
  272. package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
  273. package/project-template-v2/tsconfig.json +0 -20
  274. package/project-template-v2/vite.config.ts +0 -27
  275. package/project-templates/batch-locks/phaser.yaml +0 -922
  276. package/project-templates/batch-locks/threejs.yaml +0 -978
  277. package/project-templates/empty/AGENTS.md +0 -23
  278. package/project-templates/empty/gitignore +0 -31
@@ -1,157 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { loadGlobalConfig } from '../config.js';
5
- import { accountActivationMessage } from './messages.js';
6
- export const ACCOUNT_PENDING_ACTIVATION = 'account_pending_activation';
7
- export class AccountActivationError extends Error {
8
- code;
9
- status;
10
- retryable = false;
11
- constructor(code, message, status) {
12
- super(message);
13
- this.code = code;
14
- this.status = status;
15
- this.name = 'AccountActivationError';
16
- }
17
- }
18
- export function responseErrorCode(payload) {
19
- if (!payload || typeof payload !== 'object')
20
- return undefined;
21
- const { error, code } = payload;
22
- return typeof error?.code === 'string' ? error.code : typeof code === 'string' ? code : undefined;
23
- }
24
- export function pendingAccountActivationError(status, payload) {
25
- return status === 403 && responseErrorCode(payload) === ACCOUNT_PENDING_ACTIVATION
26
- ? new AccountActivationError(ACCOUNT_PENDING_ACTIVATION, `${ACCOUNT_PENDING_ACTIVATION}: ${accountActivationMessage('pending')}`, status)
27
- : undefined;
28
- }
29
- export function parseErrorPayload(text) {
30
- try {
31
- return JSON.parse(text);
32
- }
33
- catch {
34
- return undefined;
35
- }
36
- }
37
- function localActivationConfig() {
38
- for (const path of [
39
- join(process.cwd(), '.playcraft.json'),
40
- '/project/.playcraft.json',
41
- join(homedir(), '.playcraft.json'),
42
- ]) {
43
- if (!existsSync(path))
44
- continue;
45
- try {
46
- const config = JSON.parse(readFileSync(path, 'utf8'));
47
- if (config && typeof config === 'object' && !Array.isArray(config))
48
- return config;
49
- }
50
- catch {
51
- // Follow the existing local credential lookup when a file is unreadable.
52
- }
53
- }
54
- return {};
55
- }
56
- function stringValue(value) {
57
- return typeof value === 'string' && value ? value : undefined;
58
- }
59
- function activationBaseUrl(raw) {
60
- try {
61
- const url = new URL(raw);
62
- if (!['http:', 'https:'].includes(url.protocol) ||
63
- url.username ||
64
- url.password ||
65
- url.search ||
66
- url.hash)
67
- throw new Error();
68
- url.pathname = url.pathname.replace(/\/+$/, '').replace(/\/api$/, '');
69
- return url.toString().replace(/\/+$/, '');
70
- }
71
- catch {
72
- throw new AccountActivationError('INVALID_ACTIVATION_TARGET', accountActivationMessage('invalidTarget'));
73
- }
74
- }
75
- function savedTokenForTarget(config, rawUrl, target, environment) {
76
- if (!rawUrl || (stringValue(config.env)?.trim() || '') !== environment)
77
- return undefined;
78
- try {
79
- return activationBaseUrl(rawUrl) === target ? stringValue(config.token) : undefined;
80
- }
81
- catch {
82
- return undefined;
83
- }
84
- }
85
- function normalizedSavedUrl(raw) {
86
- try {
87
- return raw ? activationBaseUrl(raw) : undefined;
88
- }
89
- catch {
90
- return undefined;
91
- }
92
- }
93
- export async function activateAccount(options, defaultBaseUrl) {
94
- const local = localActivationConfig();
95
- const global = loadGlobalConfig();
96
- const localUrl = stringValue(local.apiUrl);
97
- const globalUrl = stringValue(global.backendUrl) || stringValue(global.url);
98
- const explicitUrl = options.url || process.env.PLAYCRAFT_API_URL || process.env.PLAYCRAFT_URL;
99
- const target = activationBaseUrl(explicitUrl || localUrl || globalUrl || defaultBaseUrl);
100
- const explicitToken = options.token || process.env.PLAYCRAFT_TOKEN || process.env.PLAYCRAFT_SANDBOX_TOKEN;
101
- const savedUrls = [normalizedSavedUrl(localUrl), normalizedSavedUrl(globalUrl)].filter(Boolean);
102
- const savedTokens = [stringValue(local.token), stringValue(global.token)].filter(Boolean);
103
- const environmentsConflict = savedUrls.length === 2 &&
104
- savedUrls[0] === savedUrls[1] &&
105
- (stringValue(local.env)?.trim() || '') !== (stringValue(global.env)?.trim() || '');
106
- const environmentTokensConflict = process.env.PLAYCRAFT_TOKEN &&
107
- process.env.PLAYCRAFT_SANDBOX_TOKEN &&
108
- process.env.PLAYCRAFT_TOKEN !== process.env.PLAYCRAFT_SANDBOX_TOKEN;
109
- const environmentUrlsConflict = process.env.PLAYCRAFT_API_URL &&
110
- process.env.PLAYCRAFT_URL &&
111
- normalizedSavedUrl(process.env.PLAYCRAFT_API_URL) !==
112
- normalizedSavedUrl(process.env.PLAYCRAFT_URL);
113
- if ((!explicitUrl && new Set(savedUrls).size > 1) ||
114
- (!explicitToken && new Set(savedTokens).size > 1) ||
115
- (environmentsConflict && !process.env.PLAYCRAFT_ENV) ||
116
- (environmentTokensConflict && !options.token) ||
117
- (environmentUrlsConflict && !options.url)) {
118
- throw new AccountActivationError('AMBIGUOUS_ACTIVATION_TARGET', accountActivationMessage('ambiguous'));
119
- }
120
- const environment = (process.env.PLAYCRAFT_ENV ||
121
- (!explicitUrl ? (localUrl ? stringValue(local.env) : stringValue(global.env)) : '') ||
122
- '').trim();
123
- const token = explicitToken ||
124
- savedTokenForTarget(local, localUrl, target, environment) ||
125
- savedTokenForTarget(global, globalUrl, target, environment);
126
- if (!token)
127
- throw new AccountActivationError('AUTH_REQUIRED', accountActivationMessage('missingToken'));
128
- if (!/^playcraft_pat_[A-Za-z0-9_-]{32}$/.test(token)) {
129
- throw new AccountActivationError('INVALID_ACTIVATION_TOKEN', accountActivationMessage('invalidToken'));
130
- }
131
- let response;
132
- try {
133
- response = await fetch(`${target}/api/settings/personal-access-tokens/activate`, {
134
- method: 'POST',
135
- redirect: 'error',
136
- signal: AbortSignal.timeout(30_000),
137
- headers: {
138
- Authorization: `Bearer ${token}`,
139
- ...(environment ? { 'playcraft-env': environment } : {}),
140
- },
141
- });
142
- }
143
- catch {
144
- throw new AccountActivationError('ACTIVATION_UNCONFIRMED', accountActivationMessage('unavailable'));
145
- }
146
- if (!response.ok) {
147
- await response.body?.cancel().catch(() => { });
148
- throw new AccountActivationError('ACTIVATION_FAILED', accountActivationMessage('failed'), response.status);
149
- }
150
- const result = await response.json().catch(() => undefined);
151
- if (!result ||
152
- typeof result !== 'object' ||
153
- result.accountStatus !== 'active') {
154
- throw new AccountActivationError('ACTIVATION_UNCONFIRMED', accountActivationMessage('unavailable'), response.status);
155
- }
156
- console.log(accountActivationMessage('success'));
157
- }
@@ -1,30 +0,0 @@
1
- const messages = {
2
- en: {
3
- activateOption: 'Explicitly activate the account using the current personal access token',
4
- tokenOption: 'Personal access token for --activate (or use PLAYCRAFT_TOKEN)',
5
- pending: 'Account activation is required. Run `playcraft login --activate` with the same token and target environment, then rerun your command.',
6
- success: 'Account activated. Rerun your original command to continue.',
7
- missingToken: 'No personal access token matches this target environment. Provide PLAYCRAFT_TOKEN or log in to this environment first.',
8
- invalidToken: 'Account activation requires a personal access token. A sandbox token cannot activate an account.',
9
- ambiguous: 'Activation credentials or target environments conflict. Specify --url, PLAYCRAFT_ENV when needed, and an explicit personal access token using --token or PLAYCRAFT_TOKEN.',
10
- invalidTarget: 'Use a web service base address (http:// or https://) without credentials, a query, or a fragment.',
11
- failed: 'Account activation failed. Check the target environment and token before trying again.',
12
- unavailable: 'Account activation could not be confirmed. Check your account status before explicitly trying again.',
13
- },
14
- zh: {
15
- activateOption: '明确使用当前个人访问令牌激活账号',
16
- tokenOption: '用于 --activate 的个人访问令牌(也可使用 PLAYCRAFT_TOKEN)',
17
- pending: '账号需要激活。请使用同一令牌和目标环境主动运行 `playcraft login --activate`,然后重新执行原命令。',
18
- success: '账号已激活,请重新执行原命令继续。',
19
- missingToken: '没有与目标环境匹配的个人访问令牌。请提供 PLAYCRAFT_TOKEN,或先登录此环境。',
20
- invalidToken: '激活账号需要个人访问令牌,沙箱令牌不能用于激活账号。',
21
- ambiguous: '激活凭据或目标环境存在冲突。请明确指定 --url、所需的 PLAYCRAFT_ENV,并通过 --token 或 PLAYCRAFT_TOKEN 提供个人访问令牌。',
22
- invalidTarget: '激活目标必须是网页服务基址(http:// 或 https://),不能包含凭据、查询参数或片段。',
23
- failed: '账号激活失败,请检查目标环境和令牌后再尝试。',
24
- unavailable: '无法确认账号是否已激活。请先检查账号状态,再主动决定是否重试。',
25
- },
26
- };
27
- export function accountActivationMessage(key) {
28
- const locale = process.env.PLAYCRAFT_LANGUAGE || process.env.LANG || 'en';
29
- return messages[locale.startsWith('zh') ? 'zh' : 'en'][key];
30
- }
@@ -1,19 +0,0 @@
1
- // 此文件由 scripts/generate-platform-skills.mjs 生成,请勿手改。
2
- // 重新生成:pnpm --filter @playcraft/cli generate:platform-skills
3
- /** `@playcraft/skills/playcraft-skills/` 下的 Platform Skill 目录名。 */
4
- export const PLATFORM_SKILL_DIRS = [
5
- 'playcraft-3d-flip-sprite',
6
- 'playcraft-asset-management',
7
- 'playcraft-build',
8
- 'playcraft-code-editor',
9
- 'playcraft-create-remix',
10
- 'playcraft-deploy',
11
- 'playcraft-iteration-methodology',
12
- 'playcraft-platform-intro',
13
- 'playcraft-prefab',
14
- 'playcraft-project-management',
15
- 'playcraft-remix-workflow',
16
- 'playcraft-save',
17
- 'playcraft-template-upgrade-merge',
18
- 'sound-effects',
19
- ];
@@ -1,59 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { batchCreateSchema } from '@playcraft/common/cloud-workspace/runtime';
3
- import { AgentApiClient } from '../utils/agent-api-client.js';
4
- import { handleError } from './tools-utils.js';
5
- const messages = {
6
- en: {
7
- create: 'Create a batch draft; confirm the whole batch in the browser',
8
- input: 'Path to the batch draft JSON (JavaScript Object Notation, 数据交换格式) file',
9
- status: 'Read a batch draft and its generation status',
10
- id: 'Batch identifier',
11
- created: 'Batch draft created',
12
- help: '\nDraft shape: { clientRequestId, title, commonGoal, sourceWorkspaceId, engine, variants: [{ variantId, name, changes, preserves }] }\nUse the current workspace identifier as sourceWorkspaceId and a stable clientRequestId for retries. Maximum 10 variants. Confirm the batch in the browser.\n',
13
- confirmation: 'Review the baseline and differences, then approve the whole batch in the browser.',
14
- },
15
- zh: {
16
- create: '创建批次草案;整批确认须在浏览器完成',
17
- input: '批次草案 JSON (JavaScript Object Notation, 数据交换格式) 文件路径',
18
- status: '查询批次草案及生成状态',
19
- id: '批次标识',
20
- created: '批次草案已创建',
21
- help: '\n草案格式:{ clientRequestId, title, commonGoal, sourceWorkspaceId, engine, variants: [{ variantId, name, changes, preserves }] }\nsourceWorkspaceId 填当前 workspace 标识,重试使用稳定的 clientRequestId。最多 10 个变体,整批在浏览器确认。\n',
22
- confirmation: '请在浏览器查看基准和差异清单,然后确认整批。',
23
- },
24
- };
25
- const language = () => /^zh/i.test(process.env.PLAYCRAFT_LANG ?? process.env.LANG ?? '') ? messages.zh : messages.en;
26
- export async function createBatchDraft(path, client = new AgentApiClient()) {
27
- const draft = batchCreateSchema.parse(JSON.parse(await readFile(path, 'utf8')));
28
- return client.post('/create-batch', draft);
29
- }
30
- export function registerBatchCommands(tools) {
31
- const t = language();
32
- tools.command('create-batch')
33
- .description(t.create)
34
- .requiredOption('--input <path>', t.input)
35
- .option('--json', 'JSON (JavaScript Object Notation, 数据交换格式)')
36
- .addHelpText('after', t.help)
37
- .action(async (opts) => {
38
- try {
39
- const result = await createBatchDraft(opts.input);
40
- console.log(opts.json ? JSON.stringify(result, null, 2) : `${t.created}: ${result.batchId}\n${t.confirmation}`);
41
- }
42
- catch (error) {
43
- handleError(error);
44
- }
45
- });
46
- tools.command('get-batch')
47
- .description(t.status)
48
- .requiredOption('--batch-id <id>', t.id)
49
- .action(async (opts) => {
50
- try {
51
- const client = new AgentApiClient();
52
- const result = await client.get('/get-batch', { batchId: opts.batchId });
53
- console.log(JSON.stringify(result, null, 2));
54
- }
55
- catch (error) {
56
- handleError(error);
57
- }
58
- });
59
- }
@@ -1,54 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { INCOMPATIBLE_EXIT_CODE, parseSandboxRuntimeConfig, } from '@playcraft/common/cloud-workspace/runtime';
3
- import { startWorkspaceRuntime } from '../workspace-runtime/serve.js';
4
- export async function runWorkspaceRuntimeServe(configPath) {
5
- process.env.PLAYCRAFT_SKIP_UPDATE_CHECK = '1';
6
- let config;
7
- try {
8
- config = parseSandboxRuntimeConfig(JSON.parse(await readFile(configPath, 'utf8')));
9
- }
10
- catch (error) {
11
- const message = error instanceof Error ? error.message : String(error);
12
- console.error(`workspace-runtime config invalid: ${message}`);
13
- process.exitCode = INCOMPATIBLE_EXIT_CODE;
14
- return;
15
- }
16
- try {
17
- const runtime = await startWorkspaceRuntime(config, { configPath });
18
- console.log(JSON.stringify({
19
- status: 'listening',
20
- url: runtime.url,
21
- phase: 'awaiting_native',
22
- protocolMajor: runtime.config.protocolMajor,
23
- protocolMinor: runtime.config.protocolMinor,
24
- }));
25
- await new Promise((resolve) => {
26
- const stop = () => {
27
- void runtime.close().finally(resolve);
28
- };
29
- process.once('SIGINT', stop);
30
- process.once('SIGTERM', stop);
31
- });
32
- }
33
- catch (error) {
34
- const code = error.code;
35
- if (code === 'protocol_incompatible' || code === 'duplicate_instance') {
36
- console.error(error instanceof Error ? error.message : code);
37
- process.exitCode = INCOMPATIBLE_EXIT_CODE;
38
- return;
39
- }
40
- throw error;
41
- }
42
- }
43
- export function registerWorkspaceRuntimeCommands(program) {
44
- const workspaceRuntime = program
45
- .command('workspace-runtime')
46
- .description('沙箱内 Sandbox Agent Server(Cloud Workspace 常驻运行入口)');
47
- workspaceRuntime
48
- .command('serve')
49
- .description('前台常驻:读取 Runtime Server 下发的配置,不启动本地 backend 或旧同步')
50
- .requiredOption('--config <path>', 'Runtime 引导配置 JSON')
51
- .action(async (options) => {
52
- await runWorkspaceRuntimeServe(options.config);
53
- });
54
- }
@@ -1,72 +0,0 @@
1
- import { verifyLocalProjectSkills } from './validation.js';
2
- export { verifyLocalProjectSkills } from './validation.js';
3
- import { downloadLocalProjectSkillArtifacts } from './remote-cache.js';
4
- import { resolve } from 'node:path';
5
- import { inspectProjectSkills, } from '@playcraft/common/project-skills';
6
- import { syncLocalProjectSkills, enableLocalProjectSkill, installFrozenProjectSkills, explainLocalProjectSkills } from './local-store.js';
7
- import { runLocalProjectSkills, localProjectSkillUsage } from './local-run.js';
8
- import { projectSkillsMessage as t } from './messages.js';
9
- import { reconcileLocalProjectSkills } from './reconcile.js';
10
- export async function inspectLocalProjectSkills(directory) {
11
- const inventory = await inspectProjectSkills(directory);
12
- // Report metadata only; never print complete skill bytes or project test data.
13
- return { declaration: inventory.declaration, discovered: inventory.discovered, issues: inventory.issues,
14
- sources: inventory.sources.map((source) => ({ entryKey: source.entryKey, root: source.root,
15
- sourceTreeHash: source.sourceTreeHash, files: source.files.map((file) => file.path) })) };
16
- }
17
- export function registerProjectSkillsCommands(skills) {
18
- const project = skills.command('project').description(t('description'));
19
- const output = async (action) => {
20
- try {
21
- process.stdout.write(`${JSON.stringify(await action(), null, 2)}\n`);
22
- }
23
- catch (error) {
24
- process.stderr.write(`${t('failed')}: ${error instanceof Error ? error.message : String(error)}\n`);
25
- process.exitCode = 1;
26
- }
27
- };
28
- project.command('run <prompt>').description(t('run')).requiredOption('--model <provider/model>', t('model'))
29
- .option('--dir <path>', t('directory'), '.').action((prompt, options) => output(async () => {
30
- const result = await runLocalProjectSkills(resolve(options.dir), { prompt, model: options.model });
31
- if (result.exitCode !== 0)
32
- process.exitCode = result.exitCode;
33
- return result;
34
- }));
35
- project.command('usage').description(t('usage')).option('--dir <path>', t('directory'), '.')
36
- .action((options) => output(() => localProjectSkillUsage(resolve(options.dir))));
37
- project.command('sync').description(t('sync')).option('--dir <path>', t('directory'), '.')
38
- .action((options) => output(() => syncLocalProjectSkills(resolve(options.dir))));
39
- project.command('reconcile').description(t('reconcile')).option('--dir <path>', t('directory'), '.')
40
- .action((options) => output(() => reconcileLocalProjectSkills(resolve(options.dir), { write: true })));
41
- project.command('install').description(t('install')).requiredOption('--frozen', t('frozen')).option('--dir <path>', t('directory'), '.')
42
- .option('--online', t('online')).action((options) => output(async () => {
43
- const directory = resolve(options.dir);
44
- if (options.online)
45
- await downloadLocalProjectSkillArtifacts(directory);
46
- return installFrozenProjectSkills(directory);
47
- }));
48
- for (const enabled of [true, false])
49
- project.command(enabled ? 'enable <entryKey>' : 'disable <entryKey>')
50
- .description(t(enabled ? 'enable' : 'disable')).option('--dir <path>', t('directory'), '.')
51
- .action((entryKey, options) => output(() => enableLocalProjectSkill(resolve(options.dir), entryKey, enabled)));
52
- project.command('explain').description(t('explain')).option('--dir <path>', t('directory'), '.')
53
- .action((options) => output(() => explainLocalProjectSkills(resolve(options.dir))));
54
- project.command('inspect').description(t('inspect')).option('--dir <path>', t('directory'), '.')
55
- .action(async (options) => {
56
- const result = await inspectLocalProjectSkills(resolve(options.dir));
57
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
58
- if (result.issues.length)
59
- process.exitCode = 1;
60
- });
61
- project.command('verify').description(t('verify')).option('--dir <path>', t('directory'), '.')
62
- .option('--json', t('json')).action(async (options) => {
63
- try {
64
- const result = await verifyLocalProjectSkills(resolve(options.dir));
65
- process.stdout.write(`${options.json ? JSON.stringify(result) : t('verified')}\n`);
66
- }
67
- catch (error) {
68
- process.stderr.write(`${t('failed')}: ${error instanceof Error ? error.message : String(error)}\n`);
69
- process.exitCode = 1;
70
- }
71
- });
72
- }
@@ -1,28 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { readProjectSkillsLockFile } from '@playcraft/common/project-skills';
3
- import { syncLocalProjectSkills, readLocalProjectSkillSnapshot, installFrozenProjectSkills } from './local-store.js';
4
- import { verifyLocalProjectSkills } from './validation.js';
5
- import { projectSkillsMessage as t } from './messages.js';
6
- /** Existing formats keep their legacy consumer; format 3 never silently downgrades. */
7
- export async function prepareLocalSkillLifecycle(directory, action, cache) {
8
- const raw = await readProjectSkillsLockFile(directory);
9
- const managed = raw !== null && JSON.parse(raw).lockVersion === 3;
10
- if (!managed && process.env.PROJECT_SKILLS_ADOPTION_ENABLED !== 'true')
11
- return { managed: false };
12
- if (raw !== null && !managed)
13
- return { managed: false, legacy: true };
14
- if (action === 'create' || action === 'push' || !managed)
15
- await syncLocalProjectSkills(directory, cache);
16
- await verifyLocalProjectSkills(directory);
17
- const snapshot = await readLocalProjectSkillSnapshot(directory);
18
- if (action === 'push') {
19
- const paths = ['.playcraft/skills.json', '.playcraft/skills.lock.json', ...snapshot.declaration.entries.flatMap(entry => entry.source.kind === 'repository' ? [entry.source.root, ...(entry.projectFiles ?? [])] : [])];
20
- const status = spawnSync('git', ['status', '--porcelain', '--', ...paths], { cwd: directory, encoding: 'utf8' });
21
- if (status.status !== 0 || status.stdout.trim())
22
- throw new Error(t('commitRequired'));
23
- }
24
- // Source-only checkouts work offline. Registry packages remain exact and require an authorized cache fill.
25
- if (!snapshot.lock.entries.some(entry => entry.revision.kind === 'release'))
26
- await installFrozenProjectSkills(directory, cache);
27
- return { managed: true, declarationHash: snapshot.lock.declarationHash };
28
- }
@@ -1,112 +0,0 @@
1
- import { spawn, execFileSync } from 'node:child_process';
2
- import { createHash, randomUUID } from 'node:crypto';
3
- import { createRequire } from 'node:module';
4
- import { readFile, writeFile, mkdir, readdir, realpath } from 'node:fs/promises';
5
- import { join } from 'node:path';
6
- import { pathToFileURL } from 'node:url';
7
- import { createInterface } from 'node:readline';
8
- import { effectiveProjectSkills, readManagedSkillEvidence } from '@playcraft/common/project-skills';
9
- import { installFrozenProjectSkills, readLocalProjectSkillSnapshot, projectSkillsCache } from './local-store.js';
10
- import { verifyLocalProjectSkills } from './validation.js';
11
- import { projectSkillsMessage as t } from './messages.js';
12
- const require = createRequire(import.meta.url);
13
- export async function localProjectSkillUsage(directory, cache = projectSkillsCache()) {
14
- const root = join(cache, 'usage', createHash('sha256').update(await realpath(directory)).digest('hex'));
15
- let files;
16
- try {
17
- files = await readdir(root);
18
- }
19
- catch (error) {
20
- if (error.code === 'ENOENT')
21
- return [];
22
- throw error;
23
- }
24
- return Promise.all(files.filter(file => /^[a-f0-9-]+\.json$/.test(file)).sort().map(async (file) => JSON.parse(await readFile(join(root, file), 'utf8'))));
25
- }
26
- /** Local evidence is explicitly client-reported; it never acts as a server evaluation or access grant. */
27
- export async function runLocalProjectSkills(directory, options, cache = projectSkillsCache()) {
28
- if (execFileSync('opencode', ['--version'], { encoding: 'utf8', timeout: 10000 }).trim() !== '1.18.31')
29
- throw new Error(t('runner'));
30
- const cwd = await realpath(directory);
31
- await verifyLocalProjectSkills(cwd);
32
- const snapshot = await readLocalProjectSkillSnapshot(cwd);
33
- const installed = await installFrozenProjectSkills(cwd, cache);
34
- const runId = randomUUID(), runtimeRoot = join(installed.generation, '.runtime');
35
- const home = join(runtimeRoot, 'home');
36
- await mkdir(home, { recursive: true, mode: 0o700 });
37
- const entries = await Promise.all(effectiveProjectSkills(snapshot.declaration, snapshot.lock, 'sandbox-agent').map(async (entry) => {
38
- const bodyFile = join(installed.generation, entry.entryKey, 'SKILL.md');
39
- return { name: entry.entryKey, skillRef: entry.revision.skillRef, revisionId: entry.revision.kind === 'source' ? entry.revision.sourceRevision : entry.revision.version,
40
- artifactHash: entry.revision.artifactHash, bodyFile, bodyHash: createHash('sha256').update(await readFile(bodyFile)).digest('hex'), description: entry.revision.skillRef };
41
- }));
42
- await writeFile(join(runtimeRoot, 'manifest.json'), JSON.stringify({ schemaVersion: 1, runtimeId: runId, lockId: snapshot.lock.declarationHash, entries }), { mode: 0o400 });
43
- await writeFile(join(runtimeRoot, 'opencode.json'), JSON.stringify({ model: options.model,
44
- plugin: [pathToFileURL(require.resolve('@playcraft/common/project-skills/runtime-plugin')).href] }), { mode: 0o400 });
45
- const usageRoot = join(cache, 'usage', createHash('sha256').update(cwd).digest('hex'));
46
- await mkdir(usageRoot, { recursive: true, mode: 0o700 });
47
- const evidence = new Map();
48
- const report = { schemaVersion: 1, runId, declarationHash: snapshot.lock.declarationHash, provenance: 'local-client-reported',
49
- runnerVersion: '1.18.31', model: options.model, startedAt: new Date().toISOString(), status: 'running', collectionStatus: 'collecting', loaded: [] };
50
- const reportPath = join(usageRoot, `${runId}.json`);
51
- await writeFile(reportPath, JSON.stringify(report), { mode: 0o600 });
52
- const environment = { ...process.env, HOME: home, XDG_CONFIG_HOME: join(home, '.config'), XDG_DATA_HOME: join(home, '.local/share'), XDG_STATE_HOME: join(home, '.local/state'), XDG_CACHE_HOME: join(home, '.cache'),
53
- OPENCODE_CONFIG: join(runtimeRoot, 'opencode.json'), OPENCODE_CONFIG_DIR: join(runtimeRoot, 'config'),
54
- OPENCODE_DISABLE_PROJECT_CONFIG: 'true', OPENCODE_DISABLE_CLAUDE_CODE: 'true', OPENCODE_DISABLE_DEFAULT_PLUGINS: 'true', OPENCODE_DISABLE_AUTOUPDATE: 'true',
55
- PLAYCRAFT_SKILL_RUNTIME_FILE: join(runtimeRoot, 'manifest.json') };
56
- delete environment.PLAYCRAFT_SKILL_RUNTIME_ROOT;
57
- delete environment.OPENCODE_CONFIG_CONTENT;
58
- let child;
59
- let cancelled = false, killTimer;
60
- const cancel = () => {
61
- cancelled = true;
62
- child?.kill('SIGTERM');
63
- killTimer ??= setTimeout(() => child?.kill('SIGKILL'), 5000);
64
- killTimer.unref();
65
- };
66
- process.once('SIGINT', cancel);
67
- process.once('SIGTERM', cancel);
68
- try {
69
- child = spawn('opencode', ['run', '--format', 'json', '--model', options.model, '--', options.prompt], { cwd, env: environment, stdio: ['ignore', 'pipe', 'inherit'] });
70
- // Resolve spawn failures so an early error cannot become an unhandled rejection while reading stdout.
71
- const finished = new Promise(resolve => {
72
- child.once('error', error => resolve({ code: 1, error }));
73
- child.once('close', code => resolve({ code: code ?? 1 }));
74
- });
75
- const lines = createInterface({ input: child.stdout });
76
- let partial = false;
77
- for await (const line of lines) {
78
- try {
79
- const event = JSON.parse(line);
80
- const parsed = readManagedSkillEvidence(event);
81
- if (parsed?.runtimeId === runId && parsed.lockId === report.declarationHash && entries.some(entry => entry.revisionId === parsed.skillVersionId && entry.artifactHash === parsed.artifactHash && entry.bodyHash === parsed.bodyHash)) {
82
- evidence.set(parsed.dedupeKey, parsed);
83
- report.loaded = [...evidence.values()];
84
- await writeFile(reportPath, JSON.stringify(report), { mode: 0o600 });
85
- }
86
- if (event.type === 'text' && typeof event.part?.text === 'string')
87
- process.stderr.write(event.part.text);
88
- }
89
- catch {
90
- partial = true;
91
- }
92
- }
93
- const result = await finished;
94
- if (result.error)
95
- throw result.error;
96
- const code = cancelled ? 130 : result.code;
97
- report.status = cancelled ? 'cancelled' : code === 0 ? 'completed' : 'failed';
98
- report.collectionStatus = code === 0 && !partial ? 'complete' : 'partial';
99
- return { ...report, reportPath, exitCode: code };
100
- }
101
- finally {
102
- if (killTimer)
103
- clearTimeout(killTimer);
104
- process.removeListener('SIGINT', cancel);
105
- process.removeListener('SIGTERM', cancel);
106
- if (report.status === 'running') {
107
- report.status = 'failed';
108
- report.collectionStatus = 'partial';
109
- }
110
- await writeFile(reportPath, JSON.stringify(report), { mode: 0o600 });
111
- }
112
- }