@playcraft/cli 0.1.40-beta → 0.1.42
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 -58
- 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/image.js +6 -2
- 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 +137 -69
- package/dist/commands/tools-image-context.js +29 -0
- package/dist/commands/tools-utils.js +12 -0
- package/dist/commands/tools.js +2 -2
- package/dist/config.js +4 -59
- package/dist/index.js +3 -40
- 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 -185
- package/dist/utils/image-asset-context.js +228 -0
- package/dist/utils/playcraft-http-client.js +4 -6
- package/package.json +5 -15
- package/project-template/.claude/agents/refs/ta-image-generation-detail.md +67 -123
- package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
- package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
- package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
- package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
- package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
- package/project-templates/phaser/.claude/agents/refs/ta-image-generation-detail.md +59 -59
- package/project-templates/phaser/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
- package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
- package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
- package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
- package/project-templates/phaser/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
- package/project-templates/threejs/.claude/agents/refs/ta-image-generation-detail.md +59 -59
- package/project-templates/threejs/.claude/skills/playcraft-image-generation/SKILL.md +135 -63
- package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +42 -33
- package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +18 -20
- package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +6 -7
- package/project-templates/threejs/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +39 -39
- 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/tools-batch.js +0 -87
- package/dist/commands/video.js +0 -111
- package/dist/commands/workspace-runtime.js +0 -54
- package/dist/commands/workspace.js +0 -35
- 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/tool-operation-journal.js +0 -124
- package/dist/utils/video-evidence-git.js +0 -81
- package/dist/video-replication/client.js +0 -222
- 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 -216
- package/dist/video-replication/evidence.js +0 -165
- package/dist/video-replication/media.js +0 -111
- package/dist/video-replication/messages.js +0 -89
- package/dist/workspace/messages.js +0 -35
- package/dist/workspace/transfer-client.js +0 -174
- package/dist/workspace-runtime/codex/app-server.js +0 -1040
- package/dist/workspace-runtime/codex/compact.js +0 -46
- package/dist/workspace-runtime/codex/config-toml.js +0 -107
- 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 -70
- package/dist/workspace-runtime/codex/thread-image.js +0 -38
- package/dist/workspace-runtime/codex/ui-instructions.js +0 -4
- package/dist/workspace-runtime/codex/ui-tools.js +0 -183
- 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/output.js +0 -36
- package/dist/workspace-runtime/previews/publish.js +0 -262
- package/dist/workspace-runtime/previews/single-file.js +0 -43
- package/dist/workspace-runtime/processes/managed-writes.js +0 -69
- package/dist/workspace-runtime/production/content-changes.js +0 -36
- package/dist/workspace-runtime/production/contracts.js +0 -19
- package/dist/workspace-runtime/production/controller.js +0 -218
- package/dist/workspace-runtime/production/dependencies.js +0 -60
- package/dist/workspace-runtime/production/native.js +0 -212
- package/dist/workspace-runtime/production/processes.js +0 -102
- package/dist/workspace-runtime/production/save-command.js +0 -35
- package/dist/workspace-runtime/production/source-archive.js +0 -137
- package/dist/workspace-runtime/production/source-copy.js +0 -91
- package/dist/workspace-runtime/production/stages.js +0 -334
- package/dist/workspace-runtime/production/storage.js +0 -75
- package/dist/workspace-runtime/serve.js +0 -214
- package/dist/workspace-runtime/server/auth.js +0 -21
- package/dist/workspace-runtime/server/connectivity.js +0 -201
- 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 -1217
- 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 -1243
- package/dist/workspace-runtime/server/lock.js +0 -53
- package/dist/workspace-runtime/server/rfb-watch-gate.js +0 -168
- package/dist/workspace-runtime/server/source-uploader.js +0 -138
- 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 -99
- 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 -197
- package/dist/workspace-runtime/workspaces/artifact-receipts.js +0 -89
- package/dist/workspace-runtime/workspaces/artifacts.js +0 -282
- package/dist/workspace-runtime/workspaces/attachment-content.js +0 -123
- package/dist/workspace-runtime/workspaces/attachments.js +0 -185
- package/dist/workspace-runtime/workspaces/batch-commit.js +0 -142
- package/dist/workspace-runtime/workspaces/cli-context.js +0 -23
- package/dist/workspace-runtime/workspaces/cli-credentials.js +0 -111
- 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/dependencies.js +0 -264
- package/dist/workspace-runtime/workspaces/developer-command.js +0 -64
- package/dist/workspace-runtime/workspaces/directories.js +0 -133
- 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-maintenance.js +0 -111
- 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/files-search.js +0 -116
- package/dist/workspace-runtime/workspaces/files.js +0 -138
- 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 -170
- package/dist/workspace-runtime/workspaces/library-attachments.js +0 -268
- package/dist/workspace-runtime/workspaces/optional-platform-skills.js +0 -14
- package/dist/workspace-runtime/workspaces/parameters.js +0 -272
- 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/transfer.js +0 -288
- 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 -298
- 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 -324
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +0 -97
- 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 -137
- 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
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
|
-
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
-
import { constants } from 'node:fs';
|
|
4
|
-
import { chmod, copyFile, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, rmdir, writeFile } from 'node:fs/promises';
|
|
5
|
-
import { tmpdir } from 'node:os';
|
|
6
|
-
import { dirname, join, resolve, sep } from 'node:path';
|
|
7
|
-
import { isCredentialFile } from './git.js';
|
|
8
|
-
export const WORKSPACE_TRANSFER_MAX_BYTES = 256 * 1024 * 1024;
|
|
9
|
-
const MAX_FILES = 20_000;
|
|
10
|
-
const EXCLUDED = new Set(['.git', 'node_modules', '.playcraft-workspace.json', '.playcraft.json']);
|
|
11
|
-
export class WorkspaceTransferError extends Error {
|
|
12
|
-
code;
|
|
13
|
-
constructor(code) {
|
|
14
|
-
super(code);
|
|
15
|
-
this.code = code;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function excluded(path) {
|
|
19
|
-
const parts = path.split('/');
|
|
20
|
-
return parts.some(part => EXCLUDED.has(part.toLowerCase()) || /^\.playcraft-(?:credential|transfer)-.*\.tmp$/i.test(part)) ||
|
|
21
|
-
parts.some((part, index) => part === '.playcraft' && /^(?:workspace-context(?:\..*)?|video-replication)$/.test(parts[index + 1] ?? '')) ||
|
|
22
|
-
isCredentialFile(path);
|
|
23
|
-
}
|
|
24
|
-
export function transferGit(root, args) {
|
|
25
|
-
const env = { PATH: process.env.PATH, HOME: tmpdir(),
|
|
26
|
-
GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: '/dev/null', GIT_TERMINAL_PROMPT: '0', GIT_ALLOW_PROTOCOL: 'file' };
|
|
27
|
-
const result = spawnSync('git', ['-c', 'core.hooksPath=/dev/null', '-c', 'commit.gpgsign=false',
|
|
28
|
-
'-c', 'core.autocrlf=false', '-c', 'user.name=PlayCraft Workspace', '-c', 'user.email=workspace@playcraft.local', ...args], { cwd: root, encoding: 'utf8', env, timeout: 120_000, maxBuffer: 8 * 1024 * 1024 });
|
|
29
|
-
if (result.status !== 0)
|
|
30
|
-
throw new WorkspaceTransferError('workspace_transfer_git_failed');
|
|
31
|
-
return result.stdout.trim();
|
|
32
|
-
}
|
|
33
|
-
async function copySnapshot(source, target) {
|
|
34
|
-
let bytes = 0, files = 0;
|
|
35
|
-
async function copy(directory, prefix) {
|
|
36
|
-
const directoryInfo = await lstat(directory);
|
|
37
|
-
const directoryReal = await realpath(directory);
|
|
38
|
-
if (!directoryInfo.isDirectory() || directoryInfo.isSymbolicLink() ||
|
|
39
|
-
(directoryReal !== source && !directoryReal.startsWith(`${source}${sep}`)))
|
|
40
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
41
|
-
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
42
|
-
const path = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
43
|
-
if (excluded(path))
|
|
44
|
-
continue;
|
|
45
|
-
const from = join(directory, entry.name), to = join(target, path);
|
|
46
|
-
const info = await lstat(from);
|
|
47
|
-
if (info.isSymbolicLink())
|
|
48
|
-
continue;
|
|
49
|
-
if (info.isDirectory()) {
|
|
50
|
-
await mkdir(to, { recursive: true });
|
|
51
|
-
await copy(from, path);
|
|
52
|
-
}
|
|
53
|
-
else if (info.isFile()) {
|
|
54
|
-
bytes += info.size;
|
|
55
|
-
files++;
|
|
56
|
-
if (bytes > WORKSPACE_TRANSFER_MAX_BYTES || files > MAX_FILES)
|
|
57
|
-
throw new WorkspaceTransferError('workspace_transfer_too_large');
|
|
58
|
-
if (!(await realpath(from)).startsWith(`${source}${sep}`))
|
|
59
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
60
|
-
const handle = await open(from, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
61
|
-
try {
|
|
62
|
-
const before = await handle.stat();
|
|
63
|
-
if (!before.isFile() || before.dev !== info.dev || before.ino !== info.ino || before.size !== info.size ||
|
|
64
|
-
before.mtimeMs !== info.mtimeMs || before.ctimeMs !== info.ctimeMs)
|
|
65
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
66
|
-
const chunks = [];
|
|
67
|
-
let size = 0;
|
|
68
|
-
for await (const chunk of handle.createReadStream({ autoClose: false })) {
|
|
69
|
-
size += chunk.length;
|
|
70
|
-
if (size > before.size)
|
|
71
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
72
|
-
chunks.push(chunk);
|
|
73
|
-
}
|
|
74
|
-
const after = await handle.stat();
|
|
75
|
-
if (size !== before.size || after.size !== before.size || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)
|
|
76
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
77
|
-
await writeFile(to, Buffer.concat(chunks));
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
await handle.close();
|
|
81
|
-
}
|
|
82
|
-
await chmod(to, info.mode & 0o111 ? 0o755 : 0o644);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
await copy(source, '');
|
|
87
|
-
}
|
|
88
|
-
async function matchesFile(root, path, expected) {
|
|
89
|
-
const target = await safeTarget(root, path);
|
|
90
|
-
const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
|
|
91
|
-
return undefined; throw error; });
|
|
92
|
-
if (!expected)
|
|
93
|
-
return !info || info.isDirectory();
|
|
94
|
-
if (!info?.isFile() || Boolean(info.mode & 0o111) !== expected.executable)
|
|
95
|
-
return false;
|
|
96
|
-
const handle = await open(target, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
97
|
-
try {
|
|
98
|
-
const stat = await handle.stat();
|
|
99
|
-
const hash = createHash(expected.sha.length === 64 ? 'sha256' : 'sha1');
|
|
100
|
-
hash.update(`blob ${stat.size}\0`);
|
|
101
|
-
for await (const chunk of handle.createReadStream({ autoClose: false }))
|
|
102
|
-
hash.update(chunk);
|
|
103
|
-
return hash.digest('hex') === expected.sha;
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
await handle.close();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
async function removeEmptyParents(root, target) {
|
|
110
|
-
let parent = dirname(target);
|
|
111
|
-
while (parent !== root) {
|
|
112
|
-
if ((await readdir(parent)).length > 0)
|
|
113
|
-
break;
|
|
114
|
-
await rmdir(parent);
|
|
115
|
-
parent = dirname(parent);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async function installFile(root, path, source, executable) {
|
|
119
|
-
const target = await safeTarget(root, path);
|
|
120
|
-
const existing = await lstat(target).catch(error => { if (error.code === 'ENOENT')
|
|
121
|
-
return undefined; throw error; });
|
|
122
|
-
if (existing?.isDirectory())
|
|
123
|
-
await rmdir(target);
|
|
124
|
-
await mkdir(dirname(target), { recursive: true });
|
|
125
|
-
const stage = join(dirname(target), `.playcraft-transfer-${randomUUID()}.tmp`);
|
|
126
|
-
try {
|
|
127
|
-
await copyFile(source, stage);
|
|
128
|
-
await chmod(stage, executable ? 0o755 : 0o644);
|
|
129
|
-
await rename(stage, target);
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
await rm(stage, { force: true }).catch(() => undefined);
|
|
133
|
-
await removeEmptyParents(root, target).catch(() => undefined);
|
|
134
|
-
throw error;
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
await rm(stage, { force: true }).catch(() => undefined);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/** A fresh history contains only the current portable files, including uncommitted changes. */
|
|
141
|
-
export async function createWorkspaceTransfer(root) {
|
|
142
|
-
const temporary = await mkdtemp(join(tmpdir(), 'playcraft-transfer-'));
|
|
143
|
-
const cleanup = () => rm(temporary, { recursive: true, force: true });
|
|
144
|
-
try {
|
|
145
|
-
const checkout = join(temporary, 'checkout');
|
|
146
|
-
await mkdir(checkout);
|
|
147
|
-
await copySnapshot(await realpath(root), checkout);
|
|
148
|
-
transferGit(checkout, ['init', '--initial-branch=main']);
|
|
149
|
-
transferGit(checkout, ['add', '--force', '--all']);
|
|
150
|
-
transferGit(checkout, ['commit', '--allow-empty', '-m', 'Workspace snapshot']);
|
|
151
|
-
const tree = transferGit(checkout, ['rev-parse', 'HEAD^{tree}']);
|
|
152
|
-
const head = transferGit(checkout, ['rev-parse', 'HEAD']);
|
|
153
|
-
const bundlePath = join(temporary, 'workspace.bundle');
|
|
154
|
-
transferGit(checkout, ['bundle', 'create', bundlePath, 'HEAD']);
|
|
155
|
-
return { bundlePath, tree, head, cleanup };
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
await cleanup();
|
|
159
|
-
throw error;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
function treeEntries(root) {
|
|
163
|
-
const entries = transferGit(root, ['ls-tree', '-r', '-z', 'HEAD']).split('\0').filter(Boolean).map(line => {
|
|
164
|
-
const match = /^(100644|100755) blob ([a-f0-9]{40,64})\t(.+)$/s.exec(line);
|
|
165
|
-
if (!match)
|
|
166
|
-
throw new WorkspaceTransferError('invalid_workspace_transfer');
|
|
167
|
-
const path = match[3];
|
|
168
|
-
if (path.length > 1024 || path.includes('\\') || path.startsWith('/') || /[\x00-\x1f\x7f]/.test(path) ||
|
|
169
|
-
path.split('/').some(part => !part || part === '.' || part === '..') || excluded(path))
|
|
170
|
-
throw new WorkspaceTransferError('invalid_workspace_transfer');
|
|
171
|
-
return { path, sha: match[2], executable: match[1] === '100755' };
|
|
172
|
-
});
|
|
173
|
-
if (entries.length > MAX_FILES)
|
|
174
|
-
throw new WorkspaceTransferError('workspace_transfer_too_large');
|
|
175
|
-
const normalized = entries.map(entry => entry.path.toLowerCase());
|
|
176
|
-
if (new Set(normalized).size !== entries.length)
|
|
177
|
-
throw new WorkspaceTransferError('invalid_workspace_transfer');
|
|
178
|
-
return entries;
|
|
179
|
-
}
|
|
180
|
-
async function safeTarget(root, path) {
|
|
181
|
-
const target = resolve(root, path);
|
|
182
|
-
if (!target.startsWith(`${root}${sep}`))
|
|
183
|
-
throw new WorkspaceTransferError('invalid_workspace_transfer');
|
|
184
|
-
let current = root;
|
|
185
|
-
for (const segment of path.split('/')) {
|
|
186
|
-
current = join(current, segment);
|
|
187
|
-
const info = await lstat(current).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
|
|
188
|
-
return undefined; throw error; });
|
|
189
|
-
if (info?.isSymbolicLink())
|
|
190
|
-
throw new WorkspaceTransferError('workspace_transfer_symlink');
|
|
191
|
-
}
|
|
192
|
-
return target;
|
|
193
|
-
}
|
|
194
|
-
/** Compare the entire checkout before applying local commits, so cloud edits are never overwritten. */
|
|
195
|
-
export async function applyWorkspaceTransfer(root, bundle, expectedTree) {
|
|
196
|
-
if (!/^[a-f0-9]{40,64}$/.test(expectedTree))
|
|
197
|
-
throw new WorkspaceTransferError('invalid_workspace_transfer');
|
|
198
|
-
if (!bundle.byteLength || bundle.byteLength > WORKSPACE_TRANSFER_MAX_BYTES)
|
|
199
|
-
throw new WorkspaceTransferError('workspace_transfer_too_large');
|
|
200
|
-
const rootReal = await realpath(root);
|
|
201
|
-
const temporary = await mkdtemp(join(tmpdir(), 'playcraft-import-'));
|
|
202
|
-
let current;
|
|
203
|
-
try {
|
|
204
|
-
const bundlePath = join(temporary, 'incoming.bundle'), incoming = join(temporary, 'checkout');
|
|
205
|
-
await writeFile(bundlePath, bundle, { mode: 0o600 });
|
|
206
|
-
transferGit(temporary, ['clone', '--no-checkout', '--', bundlePath, incoming]);
|
|
207
|
-
const entries = treeEntries(incoming);
|
|
208
|
-
const tree = transferGit(incoming, ['rev-parse', 'HEAD^{tree}']);
|
|
209
|
-
const head = transferGit(incoming, ['rev-parse', 'HEAD']);
|
|
210
|
-
let bytes = 0;
|
|
211
|
-
for (const entry of entries) {
|
|
212
|
-
bytes += Number(transferGit(incoming, ['cat-file', '-s', entry.sha]));
|
|
213
|
-
if (bytes > WORKSPACE_TRANSFER_MAX_BYTES)
|
|
214
|
-
throw new WorkspaceTransferError('workspace_transfer_too_large');
|
|
215
|
-
}
|
|
216
|
-
current = await createWorkspaceTransfer(rootReal);
|
|
217
|
-
if (current.tree === tree)
|
|
218
|
-
return { tree, head, changedPaths: [] };
|
|
219
|
-
if (current.tree !== expectedTree)
|
|
220
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
221
|
-
const baseline = join(dirname(current.bundlePath), 'checkout');
|
|
222
|
-
const previous = new Map(treeEntries(baseline).map(entry => [entry.path, entry]));
|
|
223
|
-
const next = new Map(entries.map(entry => [entry.path, entry]));
|
|
224
|
-
const changedPaths = [...new Set([...previous.keys(), ...next.keys()])]
|
|
225
|
-
.filter(path => previous.get(path)?.sha !== next.get(path)?.sha || previous.get(path)?.executable !== next.get(path)?.executable);
|
|
226
|
-
for (const path of changedPaths) {
|
|
227
|
-
const target = await safeTarget(rootReal, path);
|
|
228
|
-
const info = await lstat(target).catch(error => { if (['ENOENT', 'ENOTDIR'].includes(error.code))
|
|
229
|
-
return undefined; throw error; });
|
|
230
|
-
if (next.has(path) && info?.isDirectory()) {
|
|
231
|
-
const children = await readdir(target, { recursive: true });
|
|
232
|
-
for (const child of children) {
|
|
233
|
-
const childPath = `${path}/${child.split(sep).join('/')}`;
|
|
234
|
-
const childInfo = await lstat(join(target, child));
|
|
235
|
-
if (!childInfo.isDirectory() && (!previous.has(childPath) || next.has(childPath)))
|
|
236
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
transferGit(incoming, ['checkout', '--force']);
|
|
241
|
-
const recheck = await createWorkspaceTransfer(rootReal);
|
|
242
|
-
try {
|
|
243
|
-
if (recheck.tree !== expectedTree)
|
|
244
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
245
|
-
}
|
|
246
|
-
finally {
|
|
247
|
-
await recheck.cleanup();
|
|
248
|
-
}
|
|
249
|
-
const applied = [];
|
|
250
|
-
try {
|
|
251
|
-
// Deleting files first also permits a file to become a directory, or the reverse.
|
|
252
|
-
for (const path of changedPaths.filter(path => !next.has(path)).sort((a, b) => b.length - a.length)) {
|
|
253
|
-
if (!await matchesFile(rootReal, path, previous.get(path)))
|
|
254
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
255
|
-
await rm(await safeTarget(rootReal, path), { force: true });
|
|
256
|
-
applied.push(path);
|
|
257
|
-
await removeEmptyParents(rootReal, join(rootReal, path));
|
|
258
|
-
}
|
|
259
|
-
for (const path of changedPaths.filter(path => next.has(path))) {
|
|
260
|
-
if (!await matchesFile(rootReal, path, previous.get(path)))
|
|
261
|
-
throw new WorkspaceTransferError('workspace_transfer_conflict');
|
|
262
|
-
const entry = next.get(path);
|
|
263
|
-
await installFile(rootReal, path, join(incoming, path), entry.executable);
|
|
264
|
-
applied.push(path);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
// Roll back only our writes; never replace another writer's intervening content.
|
|
269
|
-
for (const path of applied.reverse()) {
|
|
270
|
-
if (!await matchesFile(rootReal, path, next.get(path)))
|
|
271
|
-
throw new WorkspaceTransferError('workspace_transfer_rollback_conflict');
|
|
272
|
-
const old = previous.get(path);
|
|
273
|
-
if (old)
|
|
274
|
-
await installFile(rootReal, path, join(baseline, path), old.executable);
|
|
275
|
-
else {
|
|
276
|
-
await rm(await safeTarget(rootReal, path), { force: true });
|
|
277
|
-
await removeEmptyParents(rootReal, join(rootReal, path));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
throw error;
|
|
281
|
-
}
|
|
282
|
-
return { tree, head, changedPaths };
|
|
283
|
-
}
|
|
284
|
-
finally {
|
|
285
|
-
await current?.cleanup();
|
|
286
|
-
await rm(temporary, { recursive: true, force: true });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { TURN_FILES_CHANGED_EVENT, } from '@playcraft/common/cloud-workspace/runtime';
|
|
2
|
-
import { diffWorkspaceTrees, retainTurnSnapshots, snapshotWorkspaceTree } from './git.js';
|
|
3
|
-
import { shareWorkspaceGit } from './shared-git.js';
|
|
4
|
-
const TURN_ENDS = new Set(['turn/completed', 'turn.completed', 'turn.interrupted', 'turn.failed']);
|
|
5
|
-
/**
|
|
6
|
-
* Snapshots taken when a session's turn starts, until that turn ends. Kept in memory only: a
|
|
7
|
-
* restart ends the native turn as well, and that turn then simply reports no changes.
|
|
8
|
-
*/
|
|
9
|
-
const started = new WeakMap();
|
|
10
|
-
function turnsOf(state) {
|
|
11
|
-
let turns = started.get(state);
|
|
12
|
-
if (!turns)
|
|
13
|
-
started.set(state, turns = new Map());
|
|
14
|
-
return turns;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Records the work tree before a turn is sent. A directory that cannot be snapshotted (no
|
|
18
|
-
* repository, Git failure) gets no change summary; the turn itself is never held back by it.
|
|
19
|
-
*/
|
|
20
|
-
export async function beginTurnChanges(state, sessionId, input) {
|
|
21
|
-
turnsOf(state).delete(sessionId);
|
|
22
|
-
if (input.directoryName === 'root')
|
|
23
|
-
return;
|
|
24
|
-
await shareWorkspaceGit(state, input.root).catch(() => undefined);
|
|
25
|
-
const before = await snapshotWorkspaceTree(input.root).catch(() => undefined);
|
|
26
|
-
if (before)
|
|
27
|
-
turnsOf(state).set(sessionId, { ...input, before });
|
|
28
|
-
}
|
|
29
|
-
/** A turn that never started has nothing to compare. */
|
|
30
|
-
export function abandonTurnChanges(state, sessionId) {
|
|
31
|
-
turnsOf(state).delete(sessionId);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* When a session's turn ends, compares the work tree with its start and records the files that
|
|
35
|
-
* changed for that session's conversation. Returns no event when nothing changed.
|
|
36
|
-
*/
|
|
37
|
-
export async function finishTurnChanges(state, event) {
|
|
38
|
-
const { threadId, turnId } = event;
|
|
39
|
-
if (!TURN_ENDS.has(event.method) || !threadId || !turnId)
|
|
40
|
-
return [];
|
|
41
|
-
const session = state.journal.listSessions().find((item) => item.threadId === threadId);
|
|
42
|
-
const start = session && turnsOf(state).get(session.sessionId);
|
|
43
|
-
if (!session || !start)
|
|
44
|
-
return [];
|
|
45
|
-
turnsOf(state).delete(session.sessionId);
|
|
46
|
-
try {
|
|
47
|
-
await shareWorkspaceGit(state, start.root);
|
|
48
|
-
const after = await snapshotWorkspaceTree(start.root);
|
|
49
|
-
const { files, truncated } = await diffWorkspaceTrees(start.root, start.before, after);
|
|
50
|
-
if (!files.length)
|
|
51
|
-
return [];
|
|
52
|
-
await retainTurnSnapshots(start.root, turnId, start.before, after);
|
|
53
|
-
const changes = { threadId, turnId, before: start.before, after, files, truncated };
|
|
54
|
-
return [await state.journal.allocateSourceEvent({
|
|
55
|
-
runtimeId: state.config.runtimeId,
|
|
56
|
-
generation: state.config.generation,
|
|
57
|
-
runtimeEpoch: state.runtimeEpoch,
|
|
58
|
-
type: TURN_FILES_CHANGED_EVENT,
|
|
59
|
-
payload: {
|
|
60
|
-
...changes,
|
|
61
|
-
sessionId: session.sessionId,
|
|
62
|
-
...(start.workspaceId ? { workspaceId: start.workspaceId } : {}),
|
|
63
|
-
...(start.directoryName ? { directoryName: start.directoryName } : {}),
|
|
64
|
-
},
|
|
65
|
-
occurredAt: new Date().toISOString(),
|
|
66
|
-
sessionId: session.sessionId,
|
|
67
|
-
workspaceId: start.workspaceId,
|
|
68
|
-
threadId,
|
|
69
|
-
turnId,
|
|
70
|
-
})];
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return [];
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
|
-
import { WORKSPACE_VIDEO_ATTACHMENT_MAX_DURATION_MS, WORKSPACE_VIDEO_ATTACHMENT_MAX_BYTES } from '@playcraft/common/cloud-workspace/runtime';
|
|
4
|
-
/** Probe the opened descriptor so replacing a pathname cannot redirect the media reader. */
|
|
5
|
-
export async function probeAttachmentVideo(handle) {
|
|
6
|
-
const output = await new Promise((resolve, reject) => {
|
|
7
|
-
const child = spawn(process.env.PLAYCRAFT_FFPROBE_PATH ?? 'ffprobe', [
|
|
8
|
-
'-v', 'error', '-protocol_whitelist', 'file,pipe', '-show_entries',
|
|
9
|
-
'format=format_name,duration:stream=codec_type,width,height', '-of', 'json',
|
|
10
|
-
process.platform === 'linux' ? '/proc/self/fd/3' : '/dev/fd/3',
|
|
11
|
-
], { stdio: ['ignore', 'pipe', 'ignore', handle.fd] });
|
|
12
|
-
let text = '';
|
|
13
|
-
const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error('invalid_attachment')); }, 15_000);
|
|
14
|
-
timer.unref();
|
|
15
|
-
child.stdout.on('data', (chunk) => {
|
|
16
|
-
text += chunk.toString('utf8');
|
|
17
|
-
if (text.length > 64 * 1024) {
|
|
18
|
-
child.kill('SIGKILL');
|
|
19
|
-
reject(new Error('invalid_attachment'));
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
child.once('error', () => { clearTimeout(timer); reject(new Error('video_probe_unavailable')); });
|
|
23
|
-
child.once('close', code => { clearTimeout(timer); code === 0 ? resolve(text) : reject(new Error('invalid_attachment')); });
|
|
24
|
-
});
|
|
25
|
-
const result = JSON.parse(output);
|
|
26
|
-
const stream = result.streams?.find(item => item.codec_type === 'video');
|
|
27
|
-
const durationMs = Math.round(Number(result.format?.duration) * 1000);
|
|
28
|
-
const formats = result.format?.format_name?.split(',') ?? [];
|
|
29
|
-
const mimeType = formats.includes('webm') ? 'video/webm' : formats.includes('mp4') ? 'video/mp4' : formats.includes('mov') ? 'video/quicktime' : undefined;
|
|
30
|
-
if (!stream || !mimeType || !Number.isFinite(durationMs) || durationMs <= 0 || durationMs > WORKSPACE_VIDEO_ATTACHMENT_MAX_DURATION_MS
|
|
31
|
-
|| !Number.isSafeInteger(stream.width) || !Number.isSafeInteger(stream.height) || stream.width <= 0 || stream.height <= 0
|
|
32
|
-
|| stream.width > 16384 || stream.height > 16384)
|
|
33
|
-
throw new Error('invalid_attachment');
|
|
34
|
-
return { mimeType, durationMs, width: stream.width, height: stream.height };
|
|
35
|
-
}
|
|
36
|
-
export async function hashAttachment(handle) {
|
|
37
|
-
const digest = createHash('sha256');
|
|
38
|
-
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
39
|
-
let position = 0;
|
|
40
|
-
for (;;) {
|
|
41
|
-
const { bytesRead } = await handle.read(chunk, 0, chunk.length, position);
|
|
42
|
-
if (!bytesRead)
|
|
43
|
-
return digest.digest('hex');
|
|
44
|
-
digest.update(chunk.subarray(0, bytesRead));
|
|
45
|
-
position += bytesRead;
|
|
46
|
-
if (position > WORKSPACE_VIDEO_ATTACHMENT_MAX_BYTES)
|
|
47
|
-
throw new Error('invalid_attachment');
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playcraft-replica-validation
|
|
3
|
-
description: Record a reconstructed browser playable with real inputs, compare it with its reference video, and use timestamped differences to improve the replica. Use after implementation or fixes; use video understanding first when the reference has not been analyzed.
|
|
4
|
-
version: 1.0.1
|
|
5
|
-
surfaces:
|
|
6
|
-
- sandbox-agent
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Replica validation
|
|
10
|
-
|
|
11
|
-
Use the PlayCraft CLI (Command-Line Interface,命令行接口) to record the running implementation and compare real video evidence. Codex chooses the scenario, reads the evidence, edits the playable, and repeats the checks. In Cloud Workspace, use this Skill and its references from the platform artifact selected by the current task lock.
|
|
12
|
-
|
|
13
|
-
Read [command and evidence contracts](references/contracts.md) before the first recording or comparison. Check `playcraft playable record --help`, `playcraft video compare --help`, and `playcraft video models --json`. If a required command is unavailable, report that the workspace CLI needs upgrading. Provider credentials and model requests belong to Model Proxy; do not call Gemini directly or copy a key into the project.
|
|
14
|
-
|
|
15
|
-
Use a completed reference `analysis.json` from `playcraft-video-understanding`. Inspect its original keyframes and distinguish observed actions from inferred controls. Run from the project root. Write an explicit, versioned scenario for the current implementation, using real browser coordinates and inputs. Include the initial view, first action and result, principal feedback, and ending when demonstrated. Keep hidden rules and unshown branches unknown. Start or restart the current project using its own development command; do not depend on internal auto-play hooks. Confirm that the supplied development address belongs to this process and serves this round's version. If that cannot be confirmed, do not claim validation of the current version. The project digest proves the recorded checkout stayed unchanged, but does not attest which source version an already-running server serves.
|
|
16
|
-
|
|
17
|
-
Record into a fresh directory under `.playcraft/video-replication/`. Keep the original recording, its input logs, scenario, control recordings, and project snapshot together. Do not edit the video or its manifest to repair a failing check. Match the reference viewport when practical and record enough time for every expected result. A completed recording proves capture succeeded; it does not prove the interaction worked.
|
|
18
|
-
|
|
19
|
-
Compare the original reference, its analysis, the candidate video, and its recording manifest. Inspect `comparison.md`, `comparison.json`, paired keyframes, contact sheets, input logs, and controls using available image and file-reading tools. Review event alignment before judging motion or feedback timing. The model can suggest differences; the CLI derives the final status from validated evidence and the comparison policy. A single similarity score is insufficient. Keep the default full comparison policy for delivery; an explicitly limited diagnostic must be reported as partial coverage. Do not loosen thresholds just to obtain a passing result.
|
|
20
|
-
|
|
21
|
-
For `fail`, address supported differences in priority order, then make a fresh recording from the changed project and compare again in a fresh output directory. For `inconclusive`, resolve missing controls, insufficient duration, unpaired required events, low confidence, or unknown input intent before declaring completion. Preserve valid differences even when other dimensions lack evidence. Report the tested path, unsupported branches, and unevaluated audio explicitly.
|
|
22
|
-
|
|
23
|
-
A timeout or uncertain submission must retain its run identifier and saved request. Resume the same comparison with `playcraft video compare --resume <runId> --out <same-directory>`; recovery reads the existing task and never creates another paid request. Explicit cancellation is separate from ending the local wait. Do not resubmit because the command exited early. Treat malformed model output, stale recordings, changed hashes, or missing frames as errors, never as a passing comparison.
|
|
24
|
-
|
|
25
|
-
Deliver the current project with links to the reference evidence, candidate recording, comparison report, and any remaining uncertainty. Keep validation evidence in workspace checkpoints and out of Git and deliverable builds.
|
package/project-template/.claude/skills/playcraft-replica-validation/references/contracts.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Commands and evidence contracts
|
|
2
|
-
|
|
3
|
-
The workspace CLI (Command-Line Interface,命令行接口) owns capture, upload, validation, frame extraction, and final status. The Skill supplies guidance only. Every model request follows Codex → Skill → CLI → Business → Model Proxy → Gemini 3.8 Flash.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
playcraft playable record --url '<development-url>' --scenario '<scenario.json>' \
|
|
7
|
-
--out .playcraft/video-replication/record-01
|
|
8
|
-
playcraft video compare --reference '<original-reference-video>' \
|
|
9
|
-
--analysis '<reference-analysis.json>' \
|
|
10
|
-
--candidate '.playcraft/video-replication/record-01/candidate.mp4' \
|
|
11
|
-
--recording '.playcraft/video-replication/record-01/metadata.json' \
|
|
12
|
-
--out .playcraft/video-replication/compare-01
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Scenario version is `playcraft.replica-scenario.v1`; positions are normalized to the declared `contentRect`. Replace event identifiers with actual IDs from `analysis.json` and coordinates/times with evidence from the running implementation:
|
|
16
|
-
|
|
17
|
-
```json
|
|
18
|
-
{
|
|
19
|
-
"schemaVersion": "playcraft.replica-scenario.v1",
|
|
20
|
-
"draft": false,
|
|
21
|
-
"referenceEventIds": ["initial", "first-result", "main-result", "ending"],
|
|
22
|
-
"requiredEffects": [
|
|
23
|
-
{ "stepId": "drag-one", "eventId": "first-result" },
|
|
24
|
-
{ "stepId": "tap-two", "eventId": "main-result" }
|
|
25
|
-
],
|
|
26
|
-
"controls": { "noInput": true, "omitRequiredSteps": true },
|
|
27
|
-
"viewport": { "width": 390, "height": 844, "deviceScaleFactor": 1 },
|
|
28
|
-
"contentRect": { "x": 0, "y": 0, "width": 1, "height": 1 },
|
|
29
|
-
"pointer": "touch",
|
|
30
|
-
"reset": { "kind": "fresh-context", "storage": "empty" },
|
|
31
|
-
"durationMs": 15000,
|
|
32
|
-
"steps": [
|
|
33
|
-
{
|
|
34
|
-
"id": "drag-one",
|
|
35
|
-
"atMs": 1000,
|
|
36
|
-
"type": "drag",
|
|
37
|
-
"path": [
|
|
38
|
-
{ "offsetMs": 0, "x": 0.3, "y": 0.6 },
|
|
39
|
-
{ "offsetMs": 600, "x": 0.7, "y": 0.6 }
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
|
-
{ "id": "tap-two", "atMs": 4000, "type": "tap", "x": 0.5, "y": 0.7 }
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
The first version records a requested seed as best effort; inspect `seedApplied` in the input log because the recorder does not inject a game seed. Fresh browser storage does not guarantee reset of server-side state.
|
|
48
|
-
|
|
49
|
-
Every required first/main action result needs its corresponding `requiredEffects` entry. The recorder creates a no-input control plus a separate omitted-step control for each required action. Maximum three distinct required steps yield at most four controls. Disabling controls leaves interaction acceptance inconclusive.
|
|
50
|
-
|
|
51
|
-
Use command help and the installed versioned schemas for recording fields. Do not guess manifest fields or synthesize a successful recording. Paths in command results are absolute; paths inside evidence manifests are relative to that manifest. Model output cannot provide artifact paths.
|
|
52
|
-
|
|
53
|
-
`video compare` accepts `--processing static|agentic`, static `--fps 1|2|4|8`, an authorized `--model-config`, optional `--policy`, `--workspace`, `--timeout`, and `--out`. Static sampling is the default. Agentic execution cannot be combined with fixed sampling. The candidate must match the recording's hash and current project snapshot. The reference hash must match the completed analysis. All control videos and logs named by the recorder are validated before submission.
|
|
54
|
-
|
|
55
|
-
The recording manifest version is `playcraft.replica-recording.v1`; the comparison result is `playcraft.replica-validation.v1`, and its evidence manifest is `playcraft.replica-evidence.v1`.
|
|
56
|
-
|
|
57
|
-
The final comparison includes aligned reference/candidate event times, similarities, differences, modification suggestions, uncertainty, dimension findings, control coverage, and a deterministic policy decision. Paired frames come from decoded original video timestamps. Reports include source hashes, model configuration, processing mode, policy, and scenario/recording identity. Audio similarity is unevaluated in the first version.
|
|
58
|
-
|
|
59
|
-
Read the final structured output once; progress is written separately. Exit codes:
|
|
60
|
-
|
|
61
|
-
| Code | Meaning |
|
|
62
|
-
| ---- | -------------------------------------------------------------------------------------------------- |
|
|
63
|
-
| 0 | Comparison passed for the covered scenario |
|
|
64
|
-
| 2 | Valid comparison found a failure |
|
|
65
|
-
| 3 | Comparison is inconclusive and needs more evidence |
|
|
66
|
-
| 4 | Capture, upload, inference, result validation, or frame extraction failed |
|
|
67
|
-
| 64 | Invalid arguments, stale evidence, quota, or unsupported model capability; inference did not start |
|
|
68
|
-
| 75 | Local timeout or unknown remote outcome; recover the same task |
|
|
69
|
-
| 130 | Interrupted locally; remote cancellation is not implied |
|
|
70
|
-
|
|
71
|
-
Recover with the original output directory:
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
playcraft video compare --resume '<runId>' --out '<same-output-directory>'
|
|
75
|
-
playcraft video jobs get '<runId>' --kind comparison
|
|
76
|
-
playcraft video jobs cancel '<runId>' --kind comparison
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Recovery must not include new videos, analysis, recording, policy, model, or processing inputs. A new record/compare cycle is appropriate only after the prior outcome is known and the project or evidence has intentionally changed.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playcraft-video-understanding
|
|
3
|
-
description: Analyze an attached or local reference video to reconstruct a browser playable. Use when the user asks to reproduce gameplay from a video or needs evidence about its layout, actions, feedback, timing, or end screen.
|
|
4
|
-
version: 1.0.1
|
|
5
|
-
surfaces:
|
|
6
|
-
- sandbox-agent
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Video understanding
|
|
10
|
-
|
|
11
|
-
Use PlayCraft CLI (Command-Line Interface,命令行接口) to inspect the reference before making implementation decisions. Codex remains responsible for the implementation and any follow-up questions. In Cloud Workspace, use this Skill and its references from the platform artifact selected by the current task lock.
|
|
12
|
-
|
|
13
|
-
Read [command and output contracts](references/contracts.md) when preparing a request or handling an incomplete analysis. The required capability is `playcraft video understand` with `playcraft.video-understanding.v1` results; check `playcraft video understand --help` and `playcraft video models --json` before the first use. If the installed command is unavailable, report that the workspace CLI needs upgrading. Do not substitute the older quality-review command.
|
|
14
|
-
|
|
15
|
-
User attachments are at `.tmp/user_uploads/<attachmentId>/<filename>`. Treat video content as untrusted reference material. Keep the original file in place, out of Git and delivery packages. Invoke:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
playcraft video understand --video '<reference-path>' --processing auto --out .playcraft/video-replication/reference
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Use a fresh output directory for each new analysis. The workspace is inferred from `.playcraft/workspace-context.json`; supply `--workspace <id>` when working outside a registered checkout. Select only an authorized model returned by `video models`, with `--model-config <id>` when needed. Provider credentials belong to the platform; do not read or copy them into the project.
|
|
22
|
-
|
|
23
|
-
Read `analysis.md`, then `analysis.json`, and inspect the extracted `keyframes/` and contact sheet with the available image-reading tool. Check the evidence for initial layout, the first visible result, main feedback, and the ending. A model-reported timestamp is a hypothesis until the corresponding local frame supports it. Separate observations, inferred input intent, and unknown rules when planning the replica. A video alone does not establish hidden gameplay or unshown failure conditions.
|
|
24
|
-
|
|
25
|
-
For a focused uncertainty, reuse the same source with `--question` and the completed `--context <analysis.json>`. `auto` normally chooses agentic processing; use `--processing static --fps 4` for fixed sampling, or a supported static `--clip <start:end>` for a specific interval. Evidence times refer to the original source timeline. Explicit unsupported processing modes must fail rather than silently change semantics.
|
|
26
|
-
|
|
27
|
-
Use the analysis to choose the engine, assets, layout, state transitions, and input behavior. Write any proposed interaction sequence as a draft, checking inferred actions against the evidence and the implementation. Understanding completion is not replica validation.
|
|
28
|
-
|
|
29
|
-
If the command times out or reports an uncertain remote outcome, preserve its run identifier, `request.json`, and `task.json`. Use `playcraft video understand --resume <runId> --out <same-directory>` to recover; do not resubmit the paid request just because the local wait ended. Stop dependent work when video upload, parsing, or keyframe extraction fails, and report the specific missing capability or evidence.
|
package/project-template/.claude/skills/playcraft-video-understanding/references/contracts.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Commands and evidence
|
|
2
|
-
|
|
3
|
-
The command uses the platform authorization already installed in Cloud Workspace. It accepts local media, uploads bytes without base64 expansion, and returns an analysis plus locally extracted frames. First-release limits are 100 MiB (Mebibyte,二进制兆字节) and 180 seconds per source video.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
playcraft video models --json
|
|
7
|
-
playcraft video understand --video '<path>' --processing auto --out '<fresh-directory>'
|
|
8
|
-
playcraft video understand --video '<same-path>' --question 'What indicates that the merge succeeded?' --context '<previous>/analysis.json' --processing static --fps 4 --clip 2:8 --out '<fresh-directory>'
|
|
9
|
-
playcraft video understand --resume '<runId>' --out '<original-directory>'
|
|
10
|
-
playcraft video jobs get '<runId>'
|
|
11
|
-
playcraft video jobs cancel '<runId>'
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
`--workspace <id>`, `--model-config <id>`, and `--timeout <seconds>` are optional. New-input parameters cannot accompany `--resume`. `--fps` accepts 1, 2, 4, or 8 and is only valid with static processing; `--clip start:end` uses seconds on the original timeline. A follow-up context must refer to the same source digest. Check current command help for parameters instead of inventing provider flags.
|
|
15
|
-
|
|
16
|
-
Standard output is one JSON (JavaScript Object Notation,JavaScript 对象表示法) envelope. Progress appears on standard error. The envelope has `schemaVersion: playcraft.video-cli.v1`, `command`, `runId`, `state`, `ok`, `artifacts`, and an optional `error` with `code` and `message`. Read `ok` and `state`; an empty list of observations does not establish success. Artifact paths returned by the command are absolute.
|
|
17
|
-
|
|
18
|
-
| Artifact | How to use it |
|
|
19
|
-
| ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
20
|
-
| `manifest.json` | Run identity, source digest, selected model, actual processing mode, and extracted frame paths and digests |
|
|
21
|
-
| `request.json`, `task.json` | Local request and remote task information used to resume an existing run |
|
|
22
|
-
| `analysis.json` | Versioned observations, events, evidence, inferences, unknowns, and reconstruction hints |
|
|
23
|
-
| `analysis.md` | Human-readable analysis with evidence references |
|
|
24
|
-
| `keyframes/<evidenceId>.png` | Frames extracted from the local source at range-checked timestamps |
|
|
25
|
-
| `contact-sheet.jpg` | Overview for inspecting the progression across evidence frames |
|
|
26
|
-
|
|
27
|
-
`analysis.json` uses `schemaVersion: playcraft.video-understanding.v1`. Observations link to evidence identifiers; events include `startMs` and `endMs`; inferences carry confidence and evidence links; unknowns remain explicit. Model text cannot create a real frame file. Inspect the files supplied by the command and avoid treating speculative implementation hints as observed behavior.
|
|
28
|
-
|
|
29
|
-
| Exit | Meaning and next action |
|
|
30
|
-
| ---- | ---------------------------------------------------------------------------------------- |
|
|
31
|
-
| 0 | Analysis and required artifacts completed; inspect evidence before implementing |
|
|
32
|
-
| 4 | Upload, model, parse, or extraction error; inspect `error` and preserve partial evidence |
|
|
33
|
-
| 64 | Invalid input, limit, or unsupported model capability; correct it before submitting |
|
|
34
|
-
| 75 | Wait expired or remote result unknown; resume the existing run |
|
|
35
|
-
| 130 | Interrupted; check whether remote cancellation was confirmed |
|
|
36
|
-
|
|
37
|
-
Changing source bytes, processing mode, or the question creates a new paid analysis. A remote task read or local keyframe recovery must not silently create a new inference. Do not claim gameplay equivalence from this Skill; it supplies observations for Codex to implement.
|