@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.
- package/README.md +3 -62
- package/dist/agent/local-backend.js +1 -1
- package/dist/cli-root-help.js +0 -2
- package/dist/commands/build-all.js +19 -5
- package/dist/commands/build.js +28 -15
- package/dist/commands/create.js +33 -26
- package/dist/commands/login.js +42 -84
- package/dist/commands/skills.js +0 -4
- package/dist/commands/tools-3d.js +0 -11
- package/dist/commands/tools-generation.js +0 -6
- package/dist/commands/tools.js +0 -2
- package/dist/config.js +4 -59
- package/dist/index.js +3 -42
- package/dist/remix/clone.js +0 -2
- package/dist/remix/init-template.js +0 -2
- package/dist/remix/pull.js +0 -2
- package/dist/remix/push.js +1 -21
- package/dist/utils/agent-api-client.js +30 -210
- package/dist/utils/playcraft-http-client.js +4 -6
- package/package.json +5 -15
- package/SKILLS_REGISTRY.md +0 -149
- package/dist/auth/account-activation.js +0 -157
- package/dist/auth/messages.js +0 -30
- package/dist/commands/build-temp.js +0 -26
- package/dist/commands/platform-skills.generated.js +0 -19
- package/dist/commands/playable.js +0 -53
- package/dist/commands/preview-runtime.js +0 -21
- package/dist/commands/tools-batch.js +0 -113
- package/dist/commands/video.js +0 -122
- package/dist/commands/workspace-runtime.js +0 -54
- package/dist/commands/workspace.js +0 -40
- package/dist/preview-runtime/distribution.js +0 -77
- package/dist/project-skills/builtin-import.js +0 -225
- package/dist/project-skills/commands.js +0 -77
- package/dist/project-skills/lifecycle.js +0 -28
- package/dist/project-skills/local-run.js +0 -112
- package/dist/project-skills/local-store.js +0 -221
- package/dist/project-skills/messages.js +0 -80
- package/dist/project-skills/reconcile.js +0 -62
- package/dist/project-skills/remote-cache.js +0 -51
- package/dist/project-skills/validation.js +0 -19
- package/dist/recording/messages.js +0 -40
- package/dist/recording/project-digest.js +0 -85
- package/dist/recording/recorder.js +0 -293
- package/dist/recording/scenario.js +0 -50
- package/dist/skill-registry/client.js +0 -345
- package/dist/skill-registry/commands.js +0 -180
- package/dist/skill-registry/evaluation-client.js +0 -156
- package/dist/skill-registry/evaluation-commands.js +0 -174
- package/dist/skill-registry/messages.js +0 -177
- package/dist/skill-registry/package.js +0 -275
- package/dist/skill-registry/platform-package.js +0 -100
- package/dist/utils/environment-endpoints.js +0 -17
- package/dist/utils/error-diagnostics.js +0 -20
- package/dist/utils/tool-operation-journal.js +0 -124
- package/dist/utils/video-evidence-git.js +0 -81
- package/dist/video-replication/client.js +0 -234
- package/dist/video-replication/comparison-evidence.js +0 -149
- package/dist/video-replication/comparison-files.js +0 -57
- package/dist/video-replication/comparison-log.js +0 -72
- package/dist/video-replication/comparison-messages.js +0 -104
- package/dist/video-replication/comparison-output.js +0 -63
- package/dist/video-replication/comparison-preflight.js +0 -66
- package/dist/video-replication/comparison.js +0 -230
- package/dist/video-replication/diagnostics.js +0 -41
- package/dist/video-replication/evidence.js +0 -165
- package/dist/video-replication/media.js +0 -112
- package/dist/video-replication/messages.js +0 -97
- package/dist/workspace/messages.js +0 -67
- package/dist/workspace/transfer-client.js +0 -237
- package/dist/workspace/transfer-errors.js +0 -48
- package/dist/workspace-runtime/batch/content-changes.js +0 -30
- package/dist/workspace-runtime/batch/control.js +0 -86
- package/dist/workspace-runtime/batch/deliver.js +0 -173
- package/dist/workspace-runtime/batch/freeze.js +0 -101
- package/dist/workspace-runtime/batch/generate.js +0 -249
- package/dist/workspace-runtime/batch/git.js +0 -40
- package/dist/workspace-runtime/batch/occupancy.js +0 -8
- package/dist/workspace-runtime/batch/policy.js +0 -70
- package/dist/workspace-runtime/batch/prepare.js +0 -317
- package/dist/workspace-runtime/batch/processes.js +0 -72
- package/dist/workspace-runtime/batch/records.js +0 -113
- package/dist/workspace-runtime/batch/routes.js +0 -61
- package/dist/workspace-runtime/batch/source-candidate.js +0 -86
- package/dist/workspace-runtime/batch/source-capture.js +0 -146
- package/dist/workspace-runtime/batch/source-failure.js +0 -43
- package/dist/workspace-runtime/batch/source-publish.js +0 -130
- package/dist/workspace-runtime/codex/app-server.js +0 -1065
- package/dist/workspace-runtime/codex/compact.js +0 -46
- package/dist/workspace-runtime/codex/config-toml.js +0 -107
- package/dist/workspace-runtime/codex/delivery-tools.js +0 -144
- package/dist/workspace-runtime/codex/jsonrpc-stdio.js +0 -145
- package/dist/workspace-runtime/codex/launcher-client.js +0 -177
- package/dist/workspace-runtime/codex/loopback.js +0 -146
- package/dist/workspace-runtime/codex/mcp-config.js +0 -39
- package/dist/workspace-runtime/codex/model-broker.js +0 -263
- package/dist/workspace-runtime/codex/native-adapter.js +0 -9
- package/dist/workspace-runtime/codex/permissions.js +0 -79
- package/dist/workspace-runtime/codex/thread-image.js +0 -38
- package/dist/workspace-runtime/codex/tool-response.js +0 -10
- package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
- package/dist/workspace-runtime/codex/ui-tools.js +0 -203
- package/dist/workspace-runtime/codex/work-mode.js +0 -15
- package/dist/workspace-runtime/main.js +0 -10
- package/dist/workspace-runtime/persistence/journal.js +0 -365
- package/dist/workspace-runtime/persistence/native-subagents.js +0 -162
- package/dist/workspace-runtime/persistence/sqlite-client.js +0 -77
- package/dist/workspace-runtime/persistence/sqlite-worker.js +0 -1161
- package/dist/workspace-runtime/persistence/stopped-execution.js +0 -77
- package/dist/workspace-runtime/previews/diagnostics.js +0 -44
- package/dist/workspace-runtime/previews/output.js +0 -36
- package/dist/workspace-runtime/previews/publish.js +0 -283
- package/dist/workspace-runtime/previews/runtime-preview.js +0 -251
- package/dist/workspace-runtime/previews/single-file.js +0 -43
- package/dist/workspace-runtime/processes/managed-writes.js +0 -69
- package/dist/workspace-runtime/serve.js +0 -441
- package/dist/workspace-runtime/server/accept-operation.js +0 -61
- package/dist/workspace-runtime/server/asset-transfers.js +0 -63
- package/dist/workspace-runtime/server/auth.js +0 -21
- package/dist/workspace-runtime/server/connectivity.js +0 -211
- package/dist/workspace-runtime/server/desktop-host.js +0 -429
- package/dist/workspace-runtime/server/desktop-preview-config.js +0 -81
- package/dist/workspace-runtime/server/desktop-preview-service.js +0 -157
- package/dist/workspace-runtime/server/desktop-preview-static.js +0 -53
- package/dist/workspace-runtime/server/desktop-preview.js +0 -189
- package/dist/workspace-runtime/server/dispatch.js +0 -1655
- package/dist/workspace-runtime/server/endpoints.js +0 -21
- package/dist/workspace-runtime/server/execution-group.js +0 -90
- package/dist/workspace-runtime/server/http.js +0 -1339
- package/dist/workspace-runtime/server/lock.js +0 -53
- package/dist/workspace-runtime/server/operation-record.js +0 -33
- package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
- package/dist/workspace-runtime/server/session-restore.js +0 -84
- package/dist/workspace-runtime/server/source-uploader.js +0 -138
- package/dist/workspace-runtime/server/submit-operation.js +0 -41
- package/dist/workspace-runtime/server/terminal-host.js +0 -366
- package/dist/workspace-runtime/server/types.js +0 -1
- package/dist/workspace-runtime/server/workspace-transfer.js +0 -168
- package/dist/workspace-runtime/verify-artifact.js +0 -59
- package/dist/workspace-runtime/workspaces/append-only-log.js +0 -62
- package/dist/workspace-runtime/workspaces/archive.js +0 -207
- package/dist/workspace-runtime/workspaces/artifact-events.js +0 -55
- package/dist/workspace-runtime/workspaces/artifact-files.js +0 -199
- package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
- package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
- package/dist/workspace-runtime/workspaces/asset-library-import.js +0 -387
- package/dist/workspace-runtime/workspaces/asset-publication-access.js +0 -25
- package/dist/workspace-runtime/workspaces/asset-transfer-dependencies.js +0 -81
- package/dist/workspace-runtime/workspaces/asset-transfer-publish.js +0 -438
- package/dist/workspace-runtime/workspaces/asset-transfer-storage.js +0 -389
- package/dist/workspace-runtime/workspaces/attachment-content.js +0 -73
- package/dist/workspace-runtime/workspaces/attachments.js +0 -185
- package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
- package/dist/workspace-runtime/workspaces/binary-content.js +0 -65
- package/dist/workspace-runtime/workspaces/binary-write.js +0 -117
- package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
- package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -115
- package/dist/workspace-runtime/workspaces/composer-context.js +0 -147
- package/dist/workspace-runtime/workspaces/context-error.js +0 -2
- package/dist/workspace-runtime/workspaces/delivery-build.js +0 -331
- package/dist/workspace-runtime/workspaces/delivery-store.js +0 -168
- package/dist/workspace-runtime/workspaces/delivery.js +0 -64
- package/dist/workspace-runtime/workspaces/dependencies.js +0 -279
- package/dist/workspace-runtime/workspaces/developer-command.js +0 -98
- package/dist/workspace-runtime/workspaces/directories.js +0 -132
- package/dist/workspace-runtime/workspaces/directory-access.js +0 -37
- package/dist/workspace-runtime/workspaces/directory-attachments.js +0 -245
- package/dist/workspace-runtime/workspaces/directory-create.js +0 -57
- package/dist/workspace-runtime/workspaces/directory-maintenance.js +0 -111
- package/dist/workspace-runtime/workspaces/directory-mutations.js +0 -238
- package/dist/workspace-runtime/workspaces/directory-revisions.js +0 -56
- package/dist/workspace-runtime/workspaces/directory-stats.js +0 -49
- package/dist/workspace-runtime/workspaces/disk-snapshot.js +0 -31
- package/dist/workspace-runtime/workspaces/empty-template.js +0 -42
- package/dist/workspace-runtime/workspaces/file-content.js +0 -48
- package/dist/workspace-runtime/workspaces/files-search.js +0 -116
- package/dist/workspace-runtime/workspaces/files.js +0 -150
- package/dist/workspace-runtime/workspaces/git-credential-broker.js +0 -312
- package/dist/workspace-runtime/workspaces/git-credential-helper.js +0 -68
- package/dist/workspace-runtime/workspaces/git-direct-store.js +0 -155
- package/dist/workspace-runtime/workspaces/git.js +0 -670
- package/dist/workspace-runtime/workspaces/instructions.js +0 -56
- package/dist/workspace-runtime/workspaces/json5-edit.js +0 -313
- package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
- package/dist/workspace-runtime/workspaces/operation-log.js +0 -23
- package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
- package/dist/workspace-runtime/workspaces/parameter-agent-inputs.js +0 -97
- package/dist/workspace-runtime/workspaces/parameter-agent-protocol.js +0 -40
- package/dist/workspace-runtime/workspaces/parameter-agent-store.js +0 -58
- package/dist/workspace-runtime/workspaces/parameter-agent.js +0 -284
- package/dist/workspace-runtime/workspaces/parameter-assets.js +0 -189
- package/dist/workspace-runtime/workspaces/parameters.js +0 -329
- package/dist/workspace-runtime/workspaces/prepare.js +0 -278
- package/dist/workspace-runtime/workspaces/registry.js +0 -251
- package/dist/workspace-runtime/workspaces/remix-references.js +0 -301
- package/dist/workspace-runtime/workspaces/revisions.js +0 -31
- package/dist/workspace-runtime/workspaces/session-image.js +0 -104
- package/dist/workspace-runtime/workspaces/shared-git.js +0 -40
- package/dist/workspace-runtime/workspaces/skill-artifact-loader.js +0 -95
- package/dist/workspace-runtime/workspaces/skills.js +0 -191
- package/dist/workspace-runtime/workspaces/theme-asset-index.js +0 -157
- package/dist/workspace-runtime/workspaces/transfer-quota.js +0 -69
- package/dist/workspace-runtime/workspaces/transfer.js +0 -471
- package/dist/workspace-runtime/workspaces/turn-changes.js +0 -75
- package/dist/workspace-runtime/workspaces/video-attachments.js +0 -49
- package/project-template/.claude/skills/playcraft-replica-validation/SKILL.md +0 -25
- package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md +0 -79
- package/project-template/.claude/skills/playcraft-video-understanding/SKILL.md +0 -29
- package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md +0 -37
- package/project-template-v2/.claude/agents/artist.md +0 -82
- package/project-template-v2/.claude/agents/developer.md +0 -153
- package/project-template-v2/.claude/agents/game-designer.md +0 -264
- package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +0 -533
- package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +0 -153
- package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +0 -27
- package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +0 -208
- package/project-template-v2/.claude/agents/refs/atom-skill-library.md +0 -81
- package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +0 -432
- package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +0 -252
- package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +0 -266
- package/project-template-v2/.claude/agents/refs/framework-mda.md +0 -147
- package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +0 -123
- package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +0 -88
- package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +0 -67
- package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +0 -120
- package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +0 -300
- package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +0 -495
- package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +0 -1141
- package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +0 -111
- package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +0 -365
- package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +0 -412
- package/project-template-v2/.claude/agents/reviewer.md +0 -75
- package/project-template-v2/.claude/agents/technical-artist.md +0 -86
- package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +0 -243
- package/project-template-v2/.claude/hooks/user-prompt.mjs +0 -133
- package/project-template-v2/.claude/settings.json +0 -33
- package/project-template-v2/.claude/skills/brainstorming/SKILL.md +0 -161
- package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +0 -270
- package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +0 -177
- package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +0 -354
- package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +0 -148
- package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +0 -56
- package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +0 -62
- package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
- package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +0 -309
- package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +0 -182
- package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +0 -123
- package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +0 -205
- package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +0 -280
- package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +0 -184
- package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +0 -306
- package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +0 -370
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +0 -123
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +0 -254
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +0 -333
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -95
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +0 -118
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +0 -136
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +0 -397
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +0 -296
- package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +0 -122
- package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +0 -219
- package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +0 -373
- package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +0 -161
- package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +0 -215
- package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +0 -382
- package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +0 -423
- package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +0 -158
- package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +0 -100
- package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +0 -167
- package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +0 -270
- package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +0 -236
- package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +0 -130
- package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +0 -390
- package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +0 -23
- package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +0 -39
- package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +0 -87
- package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +0 -240
- package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +0 -226
- package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +0 -308
- package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +0 -275
- package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +0 -134
- package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +0 -142
- package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +0 -153
- package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +0 -386
- package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +0 -182
- package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +0 -72
- package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +0 -121
- package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -102
- package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +0 -127
- package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +0 -106
- package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +0 -128
- package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +0 -67
- package/project-template-v2/.claude/snapshot.mjs +0 -263
- package/project-template-v2/.playcraft/skills.lock.json +0 -152
- package/project-template-v2/CLAUDE.md +0 -146
- package/project-template-v2/assets/audio/bgm/.gitkeep +0 -0
- package/project-template-v2/assets/audio/sfx/.gitkeep +0 -0
- package/project-template-v2/assets/bundles/.gitkeep +0 -0
- package/project-template-v2/assets/images/bg/.gitkeep +0 -0
- package/project-template-v2/assets/images/reference/.gitkeep +0 -0
- package/project-template-v2/assets/images/storyboard/.gitkeep +0 -0
- package/project-template-v2/assets/images/tiles/.gitkeep +0 -0
- package/project-template-v2/assets/images/ui/.gitkeep +0 -0
- package/project-template-v2/assets/images/vfx/.gitkeep +0 -0
- package/project-template-v2/assets/models/.gitkeep +0 -0
- package/project-template-v2/docs/harness/iteration-1/context-flow.md +0 -254
- package/project-template-v2/docs/harness/iteration-1/generate-flow.md +0 -91
- package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +0 -214
- package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +0 -75
- package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +0 -63
- package/project-template-v2/docs/harness/iteration-2/context-flow.md +0 -223
- package/project-template-v2/docs/harness/iteration-2/generate-flow.md +0 -129
- package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +0 -267
- package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +0 -164
- package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +0 -115
- package/project-template-v2/docs/harness/orchestrator-flow.md +0 -364
- package/project-template-v2/docs/project-state.json +0 -60
- package/project-template-v2/docs/project-state.md +0 -72
- package/project-template-v2/docs/standards/README.md +0 -225
- package/project-template-v2/docs/standards/agent-behavior-standards.md +0 -174
- package/project-template-v2/docs/standards/artifacts/design-brief.md +0 -19
- package/project-template-v2/docs/standards/artifacts/design.md +0 -22
- package/project-template-v2/docs/standards/artifacts/game-code.md +0 -41
- package/project-template-v2/docs/standards/artifacts/todo-list.md +0 -41
- package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +0 -343
- package/project-template-v2/game/index.ts +0 -18
- package/project-template-v2/globals.d.ts +0 -51
- package/project-template-v2/index.css +0 -34
- package/project-template-v2/index.html +0 -18
- package/project-template-v2/main.ts +0 -9
- package/project-template-v2/package.json +0 -46
- package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +0 -31
- package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +0 -86
- package/project-template-v2/skills/_shared/scripts/dod-check.mjs +0 -153
- package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +0 -70
- package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +0 -91
- package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +0 -131
- package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +0 -80
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +0 -90
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +0 -93
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +0 -23
- package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +0 -230
- package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +0 -58
- package/project-template-v2/skills/_shared/scripts/state-get.mjs +0 -339
- package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +0 -39
- package/project-template-v2/skills/_shared/scripts/state-set.mjs +0 -94
- package/project-template-v2/skills/_shared/scripts/state-store.mjs +0 -783
- package/project-template-v2/skills/_shared/scripts/todo-add.mjs +0 -88
- package/project-template-v2/skills/_shared/scripts/todo-get.mjs +0 -130
- package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +0 -33
- package/project-template-v2/skills/_shared/scripts/todo-set.mjs +0 -47
- package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +0 -268
- package/project-template-v2/skills/_shared/scripts/verify-env.mjs +0 -285
- package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +0 -161
- package/project-template-v2/skills/playable-autoplay/SKILL.md +0 -176
- package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +0 -4
- package/project-template-v2/skills/playable-debug/SKILL.md +0 -116
- package/project-template-v2/skills/playable-debug/agents/openai.yaml +0 -4
- package/project-template-v2/skills/playable-debug/references/debug-config.md +0 -40
- package/project-template-v2/skills/playable-record/SKILL.md +0 -140
- package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +0 -104
- package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +0 -141
- package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +0 -425
- package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +0 -261
- package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +0 -398
- package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +0 -322
- package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +0 -105
- package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +0 -230
- package/project-template-v2/skills/playable-validate/SKILL.md +0 -61
- package/project-template-v2/skills/playable-validate/validation-rules.md +0 -14
- package/project-template-v2/skills/playable-verify-ui/SKILL.md +0 -63
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +0 -1
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +0 -218
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +0 -51
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +0 -59
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +0 -106
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +0 -116
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +0 -59
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +0 -64
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +0 -58
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +0 -333
- package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
- package/project-template-v2/tsconfig.json +0 -20
- package/project-template-v2/vite.config.ts +0 -27
- package/project-templates/batch-locks/phaser.yaml +0 -922
- package/project-templates/batch-locks/threejs.yaml +0 -978
- package/project-templates/empty/AGENTS.md +0 -41
- package/project-templates/empty/gitignore +0 -33
- package/templates/preview-runtime/v1/README.md +0 -71
- package/templates/preview-runtime/v1/build-preview.mjs +0 -1324
- package/templates/preview-runtime/v1/manifest.json +0 -17
- package/templates/preview-runtime/v1/release-guard.mjs +0 -87
- package/templates/preview-runtime/v1/runtime.d.mts +0 -3
- package/templates/preview-runtime/v1/runtime.d.ts +0 -3
- package/templates/preview-runtime/v1/runtime.mjs +0 -1121
- package/templates/preview-runtime/v1/types/adapters.d.ts +0 -26
- package/templates/preview-runtime/v1/types/preview.d.ts +0 -23
- package/templates/preview-runtime/v1/types/protocol.d.ts +0 -94
- 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
|
-
}
|