@playcraft/cli 0.1.40-beta → 0.1.41-prod
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 +3 -13
- 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
package/dist/commands/login.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
|
-
import {
|
|
2
|
+
import { exec } from 'child_process';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
|
-
import {
|
|
5
|
-
import { activateAccount } from '../auth/account-activation.js';
|
|
4
|
+
import { saveGlobalConfig, loadGlobalConfig } from '../config.js';
|
|
6
5
|
/** 默认云端 Portal(Next.js `/cli-auth` 与 API 同源时的基址;可通过 --url 或 PLAYCRAFT_URL 覆盖) */
|
|
7
6
|
export const DEFAULT_PLAYCRAFT_CLOUD_BASE = 'https://playcraft.aix.intlgame.com';
|
|
8
7
|
const CALLBACK_PORT = 3456;
|
|
@@ -19,11 +18,10 @@ function openBrowser(url) {
|
|
|
19
18
|
const cmd = process.platform === 'darwin'
|
|
20
19
|
? 'open'
|
|
21
20
|
: process.platform === 'win32'
|
|
22
|
-
? '
|
|
21
|
+
? 'start'
|
|
23
22
|
: 'xdg-open';
|
|
24
23
|
try {
|
|
25
|
-
|
|
26
|
-
execFile(cmd, arguments_, (err, _stdout, stderr) => {
|
|
24
|
+
exec(`${cmd} "${url}"`, (err, _stdout, stderr) => {
|
|
27
25
|
if (err) {
|
|
28
26
|
console.error('Failed to open browser automatically:', err.message);
|
|
29
27
|
if (stderr?.trim()) {
|
|
@@ -46,18 +44,21 @@ function resolveLoginBaseUrl(options) {
|
|
|
46
44
|
globalConfig.url ||
|
|
47
45
|
globalConfig.backendUrl ||
|
|
48
46
|
DEFAULT_PLAYCRAFT_CLOUD_BASE;
|
|
49
|
-
|
|
50
|
-
if (!base)
|
|
51
|
-
throw new Error('Invalid environment address');
|
|
52
|
-
return base;
|
|
47
|
+
return raw.replace(/\/+$/, '');
|
|
53
48
|
}
|
|
54
49
|
function normalizeLoginEnvironmentUrl(raw) {
|
|
55
|
-
|
|
50
|
+
try {
|
|
51
|
+
const url = new URL(raw);
|
|
52
|
+
url.hash = '';
|
|
53
|
+
url.search = '';
|
|
54
|
+
url.pathname = url.pathname.replace(/\/+$/, '');
|
|
55
|
+
return url.toString().replace(/\/+$/, '');
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
56
60
|
}
|
|
57
61
|
export function resolveExistingTokenForLoginTarget(globalConfig, backendUrl) {
|
|
58
|
-
const profile = readEnvironmentProfile(globalConfig, backendUrl);
|
|
59
|
-
if (profile)
|
|
60
|
-
return profile.token;
|
|
61
62
|
const token = typeof globalConfig.token === 'string' ? globalConfig.token : undefined;
|
|
62
63
|
const storedBackendUrl = typeof globalConfig.backendUrl === 'string'
|
|
63
64
|
? globalConfig.backendUrl
|
|
@@ -73,17 +74,9 @@ export function resolveExistingTokenForLoginTarget(globalConfig, backendUrl) {
|
|
|
73
74
|
: undefined;
|
|
74
75
|
}
|
|
75
76
|
export function buildCliAuthUrl(options) {
|
|
76
|
-
const
|
|
77
|
-
if (!base)
|
|
78
|
-
throw new Error('Invalid environment address');
|
|
79
|
-
const url = new URL(`${base}/cli-auth`);
|
|
80
|
-
url.searchParams.set('callbackUrl', options.callbackUrl);
|
|
77
|
+
const url = new URL('/cli-auth', options.backendUrl);
|
|
81
78
|
url.searchParams.set('callback', options.callbackUrl);
|
|
82
79
|
url.searchParams.set('state', options.state);
|
|
83
|
-
if (options.codeChallenge) {
|
|
84
|
-
url.searchParams.set('codeChallenge', options.codeChallenge);
|
|
85
|
-
url.searchParams.set('codeChallengeMethod', 'S256');
|
|
86
|
-
}
|
|
87
80
|
return url.toString();
|
|
88
81
|
}
|
|
89
82
|
export async function renewExistingToken(options) {
|
|
@@ -94,20 +87,12 @@ export async function renewExistingToken(options) {
|
|
|
94
87
|
try {
|
|
95
88
|
const res = await fetchFn(`${options.backendUrl}/api/settings/personal-access-tokens/current/renew`, {
|
|
96
89
|
method: 'PATCH',
|
|
97
|
-
redirect: 'error',
|
|
98
|
-
signal: AbortSignal.timeout(10_000),
|
|
99
90
|
headers: {
|
|
100
91
|
Authorization: `Bearer ${options.token}`,
|
|
101
92
|
'Content-Type': 'application/json',
|
|
102
93
|
},
|
|
103
94
|
body: JSON.stringify({ expiresIn: '365d' }),
|
|
104
95
|
});
|
|
105
|
-
if (res.ok && res.json && options.onRenewed) {
|
|
106
|
-
const result = await res.json();
|
|
107
|
-
if (typeof result.expiresAt === 'string' && Date.parse(result.expiresAt) > Date.now()) {
|
|
108
|
-
options.onRenewed(result.expiresAt);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
96
|
return res.ok;
|
|
112
97
|
}
|
|
113
98
|
catch {
|
|
@@ -115,43 +100,29 @@ export async function renewExistingToken(options) {
|
|
|
115
100
|
}
|
|
116
101
|
}
|
|
117
102
|
export async function loginCommand(options) {
|
|
118
|
-
if (options.activate) {
|
|
119
|
-
await activateAccount(options, DEFAULT_PLAYCRAFT_CLOUD_BASE);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
103
|
const backendUrl = resolveLoginBaseUrl(options);
|
|
123
104
|
const callbackPort = options.callbackPort ?? CALLBACK_PORT;
|
|
124
105
|
const globalConfig = loadGlobalConfig();
|
|
125
106
|
const existingToken = resolveExistingTokenForLoginTarget(globalConfig, backendUrl);
|
|
126
107
|
if (existingToken) {
|
|
127
|
-
|
|
128
|
-
const renewed = await renewExistingToken({ backendUrl, token: existingToken,
|
|
129
|
-
onRenewed: (value) => { expiresAt = value; } });
|
|
108
|
+
const renewed = await renewExistingToken({ backendUrl, token: existingToken });
|
|
130
109
|
if (renewed) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
110
|
+
saveGlobalConfig({
|
|
111
|
+
token: existingToken,
|
|
112
|
+
url: backendUrl,
|
|
113
|
+
backendUrl,
|
|
114
|
+
});
|
|
135
115
|
console.log('Existing CLI token renewed. Token saved to ~/.playcraft/config.json');
|
|
136
116
|
return;
|
|
137
117
|
}
|
|
138
118
|
}
|
|
139
119
|
const state = crypto.randomBytes(16).toString('hex');
|
|
140
|
-
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
141
|
-
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
|
|
142
|
-
let callbackUrl = '';
|
|
143
|
-
let exchanging = false;
|
|
144
120
|
return new Promise((resolve, reject) => {
|
|
145
121
|
let timeout;
|
|
146
122
|
const server = http.createServer((req, res) => {
|
|
147
|
-
res.setHeader('Access-Control-Allow-Origin',
|
|
123
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
148
124
|
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
149
125
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
150
|
-
if (req.headers.origin && req.headers.origin !== new URL(backendUrl).origin) {
|
|
151
|
-
res.writeHead(403);
|
|
152
|
-
res.end();
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
126
|
if (req.method === 'OPTIONS') {
|
|
156
127
|
res.writeHead(204);
|
|
157
128
|
res.end();
|
|
@@ -159,9 +130,8 @@ export async function loginCommand(options) {
|
|
|
159
130
|
}
|
|
160
131
|
if (req.url === '/callback' && req.method === 'POST') {
|
|
161
132
|
let body = '';
|
|
162
|
-
req.on('data', (chunk) =>
|
|
163
|
-
|
|
164
|
-
req.on('end', async () => {
|
|
133
|
+
req.on('data', (chunk) => (body += chunk));
|
|
134
|
+
req.on('end', () => {
|
|
165
135
|
try {
|
|
166
136
|
const data = JSON.parse(body);
|
|
167
137
|
if (data.state !== state) {
|
|
@@ -169,36 +139,22 @@ export async function loginCommand(options) {
|
|
|
169
139
|
'Content-Type': 'text/html',
|
|
170
140
|
Connection: 'close',
|
|
171
141
|
});
|
|
172
|
-
res.end('<html><body><h1>Invalid state</h1></body></html>')
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
res.end();
|
|
142
|
+
res.end('<html><body><h1>Invalid state</h1></body></html>', () => {
|
|
143
|
+
closeServer(() => {
|
|
144
|
+
reject(new Error('State mismatch - possible CSRF attack'));
|
|
145
|
+
});
|
|
146
|
+
});
|
|
178
147
|
return;
|
|
179
148
|
}
|
|
180
|
-
|
|
181
|
-
|
|
149
|
+
const callbackToken = typeof data.token === 'string' ? data.token : undefined;
|
|
150
|
+
if (!callbackToken) {
|
|
151
|
+
throw new Error('Login callback did not include a token');
|
|
182
152
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const exchange = await fetch(`${base}/api/cloud-environments/exchange`, {
|
|
188
|
-
method: 'POST', redirect: 'error', signal: AbortSignal.timeout(10_000),
|
|
189
|
-
headers: { 'Content-Type': 'application/json' },
|
|
190
|
-
body: JSON.stringify({ code: data.code, state, callbackUrl, codeVerifier }),
|
|
153
|
+
saveGlobalConfig({
|
|
154
|
+
token: callbackToken,
|
|
155
|
+
url: backendUrl,
|
|
156
|
+
backendUrl,
|
|
191
157
|
});
|
|
192
|
-
if (!exchange.ok)
|
|
193
|
-
throw new Error('Authorization code exchange failed');
|
|
194
|
-
const credential = await exchange.json();
|
|
195
|
-
if (!credential.token || !/^playcraft_pat_[A-Za-z0-9_-]{32}$/.test(credential.token)
|
|
196
|
-
|| !credential.identity?.userId || !Array.isArray(credential.identity.identities)
|
|
197
|
-
|| !credential.expiresAt || Date.parse(credential.expiresAt) <= Date.now()) {
|
|
198
|
-
throw new Error('Invalid environment credential response');
|
|
199
|
-
}
|
|
200
|
-
saveEnvironmentProfile(base, { token: credential.token,
|
|
201
|
-
identity: credential.identity, expiresAt: credential.expiresAt });
|
|
202
158
|
res.writeHead(200, {
|
|
203
159
|
'Content-Type': 'text/html',
|
|
204
160
|
Connection: 'close',
|
|
@@ -218,6 +174,9 @@ export async function loginCommand(options) {
|
|
|
218
174
|
catch (err) {
|
|
219
175
|
const cause = err instanceof Error ? err : new Error(String(err));
|
|
220
176
|
console.error('[playcraft login] Callback handling failed:', cause.message);
|
|
177
|
+
if (cause.stack) {
|
|
178
|
+
console.error(cause.stack);
|
|
179
|
+
}
|
|
221
180
|
const userFacing = cause instanceof SyntaxError
|
|
222
181
|
? 'Invalid JSON in login callback.'
|
|
223
182
|
: `Login callback failed: ${cause.message}`;
|
|
@@ -262,15 +221,14 @@ export async function loginCommand(options) {
|
|
|
262
221
|
});
|
|
263
222
|
});
|
|
264
223
|
try {
|
|
265
|
-
server.listen(callbackPort,
|
|
224
|
+
server.listen(callbackPort, () => {
|
|
266
225
|
const address = server.address();
|
|
267
226
|
const listeningPort = typeof address === 'object' && address ? address.port : callbackPort;
|
|
268
|
-
callbackUrl = `http://
|
|
227
|
+
const callbackUrl = `http://localhost:${listeningPort}/callback`;
|
|
269
228
|
const authUrl = buildCliAuthUrl({
|
|
270
229
|
backendUrl,
|
|
271
230
|
callbackUrl,
|
|
272
231
|
state,
|
|
273
|
-
codeChallenge,
|
|
274
232
|
});
|
|
275
233
|
console.log('Opening browser for login...');
|
|
276
234
|
console.log(`If the browser does not open, visit this URL manually:\n ${authUrl}\n`);
|
package/dist/commands/skills.js
CHANGED
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
* 3. <cwd>/node_modules/@playcraft/skills/playcraft-skills(兼容旧路径 skills)
|
|
19
19
|
* 4. <CLI 自身>/../../skills/playcraft-skills(monorepo 开发时,兼容旧路径 skills)
|
|
20
20
|
*/
|
|
21
|
-
import { registerProjectSkillsCommands } from '../project-skills/commands.js';
|
|
22
|
-
import { registerRegistryCommands } from '../skill-registry/commands.js';
|
|
23
21
|
import * as fs from 'node:fs';
|
|
24
22
|
import * as path from 'node:path';
|
|
25
23
|
import { getFusionHintsForGameplayAtoms, } from '../atom-tree/fusion-hints.js';
|
|
@@ -1432,8 +1430,6 @@ export function registerSkillsCommands(program) {
|
|
|
1432
1430
|
const skills = program
|
|
1433
1431
|
.command('skills')
|
|
1434
1432
|
.description('开发时 Skill 发现与脚手架工具(按 engine/intent 推荐 skill 集合,或将 ref 文件复制到项目)');
|
|
1435
|
-
registerProjectSkillsCommands(skills);
|
|
1436
|
-
registerRegistryCommands(skills);
|
|
1437
1433
|
// 公共选项:skills 目录
|
|
1438
1434
|
const addSkillsDirOption = (cmd) => cmd.option('--skills-dir <path>', '指定 skills 目录路径(默认自动发现)');
|
|
1439
1435
|
// ── list ──────────────────────────────────────────────────────────────────
|
|
@@ -2,7 +2,6 @@ import { writeFileSync, mkdirSync, readFileSync } from 'fs';
|
|
|
2
2
|
import { dirname } from 'path';
|
|
3
3
|
import { AgentApiClient } from '../utils/agent-api-client.js';
|
|
4
4
|
import { mimeTypeForImagePath, handleError } from './tools-utils.js';
|
|
5
|
-
import { captureGeneratedArtifact } from '../workspace-runtime/workspaces/artifact-receipts.js';
|
|
6
5
|
const AVATAR_TEMPLATES = [
|
|
7
6
|
'basketball', 'badminton', 'pingpong', 'gymnastics', 'pilidance',
|
|
8
7
|
'tennis', 'athletics', 'footballboykicking1', 'footballboykicking2',
|
|
@@ -149,9 +148,6 @@ export function register3DCommands(tools) {
|
|
|
149
148
|
writeFileSync(opts.savePreview, previewBuf);
|
|
150
149
|
console.log(` Preview saved: ${opts.savePreview}`);
|
|
151
150
|
}
|
|
152
|
-
await captureGeneratedArtifact(opts.output, 'generate-3d', {
|
|
153
|
-
...(opts.savePreview && result.previewImageBase64 ? { thumbnailPath: opts.savePreview } : {}),
|
|
154
|
-
});
|
|
155
151
|
console.log(`\nNext steps:`);
|
|
156
152
|
console.log(` Inspect: playcraft 3d info ${opts.output}`);
|
|
157
153
|
console.log(` Apply texture: playcraft tools generate-texture --model-url <url> --reference-image <img> --output out.glb`);
|
|
@@ -213,7 +209,6 @@ export function register3DCommands(tools) {
|
|
|
213
209
|
const outDir = dirname(opts.output);
|
|
214
210
|
mkdirSync(outDir, { recursive: true });
|
|
215
211
|
writeFileSync(opts.output, buf);
|
|
216
|
-
await captureGeneratedArtifact(opts.output, 'generate-texture');
|
|
217
212
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
218
213
|
console.log(`\nTextured model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
219
214
|
if (result.resultUrl)
|
|
@@ -258,7 +253,6 @@ export function register3DCommands(tools) {
|
|
|
258
253
|
const outDir = dirname(opts.output);
|
|
259
254
|
mkdirSync(outDir, { recursive: true });
|
|
260
255
|
writeFileSync(opts.output, buf);
|
|
261
|
-
await captureGeneratedArtifact(opts.output, 'retopology');
|
|
262
256
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
263
257
|
console.log(`\nRetopologized model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
264
258
|
}
|
|
@@ -295,7 +289,6 @@ export function register3DCommands(tools) {
|
|
|
295
289
|
const outDir = dirname(opts.output);
|
|
296
290
|
mkdirSync(outDir, { recursive: true });
|
|
297
291
|
writeFileSync(opts.output, buf);
|
|
298
|
-
await captureGeneratedArtifact(opts.output, 'uv-unwrap');
|
|
299
292
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
300
293
|
console.log(`\nUV-unwrapped model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
301
294
|
}
|
|
@@ -331,7 +324,6 @@ export function register3DCommands(tools) {
|
|
|
331
324
|
const outDir = dirname(opts.output);
|
|
332
325
|
mkdirSync(outDir, { recursive: true });
|
|
333
326
|
writeFileSync(opts.output, buf);
|
|
334
|
-
await captureGeneratedArtifact(opts.output, 'convert-3d');
|
|
335
327
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
336
328
|
console.log(`\nConverted model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
337
329
|
console.log(` Format: ${result.format.toUpperCase()}`);
|
|
@@ -367,7 +359,6 @@ export function register3DCommands(tools) {
|
|
|
367
359
|
const outDir = dirname(opts.output);
|
|
368
360
|
mkdirSync(outDir, { recursive: true });
|
|
369
361
|
writeFileSync(opts.output, buf);
|
|
370
|
-
await captureGeneratedArtifact(opts.output, 'generate-3d-parts');
|
|
371
362
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
372
363
|
console.log(`\n3D parts model saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
373
364
|
}
|
|
@@ -411,7 +402,6 @@ export function register3DCommands(tools) {
|
|
|
411
402
|
const outDir = dirname(opts.output);
|
|
412
403
|
mkdirSync(outDir, { recursive: true });
|
|
413
404
|
writeFileSync(opts.output, buf);
|
|
414
|
-
await captureGeneratedArtifact(opts.output, 'generate-motion');
|
|
415
405
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
416
406
|
console.log(`\nMotion FBX saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
417
407
|
}
|
|
@@ -473,7 +463,6 @@ export function register3DCommands(tools) {
|
|
|
473
463
|
const outDir = dirname(opts.output);
|
|
474
464
|
mkdirSync(outDir, { recursive: true });
|
|
475
465
|
writeFileSync(opts.output, buf);
|
|
476
|
-
await captureGeneratedArtifact(opts.output, 'generate-avatar');
|
|
477
466
|
const sizeMB = (buf.length / 1024 / 1024).toFixed(2);
|
|
478
467
|
console.log(`\n3D avatar saved: ${opts.output} (${sizeMB}MB, ${elapsed}s)`);
|
|
479
468
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
import { writeFileSync, mkdirSync } from 'fs';
|
|
2
3
|
import { dirname, parse, join } from 'path';
|
|
3
4
|
import sharp from 'sharp';
|
|
4
|
-
import {
|
|
5
|
+
import { resolveImageBackgroundRequirement, validateImageDeliveryOptions } from '@playcraft/common/prefab';
|
|
6
|
+
import { assertImageAssetOutputPaths, readImageAssetContext } from '../utils/image-asset-context.js';
|
|
5
7
|
import { AgentApiClient } from '../utils/agent-api-client.js';
|
|
6
|
-
import { MAX_REFERENCE_IMAGES, collectReferenceImagePaths, collectReferenceImagePayloads, sniffImageExtension, extensionForImageMime, resolveImageOutputPath, handleError, raceWithTimeout, } from './tools-utils.js';
|
|
8
|
+
import { MAX_REFERENCE_IMAGES, collectReferenceImagePaths, parseImageTargetFieldPath, collectReferenceImagePayloads, sniffImageExtension, extensionForImageMime, resolveImageOutputPath, handleError, raceWithTimeout, } from './tools-utils.js';
|
|
7
9
|
function isMasterCompositeStripRequest(opts) {
|
|
8
10
|
if (opts.aspectRatio === '45:16')
|
|
9
11
|
return true;
|
|
@@ -151,86 +153,140 @@ export function registerGenerationCommands(tools) {
|
|
|
151
153
|
.requiredOption('--prompt <text>', '图片描述')
|
|
152
154
|
.option('--aspect-ratio <ratio>', '宽高比 (1:1|45:16|16:9|9:16|3:4|4:3|2:3|3:2|21:9)', '1:1')
|
|
153
155
|
.requiredOption('--output <path>', '保存路径(--count>1 时自动追加 _1/_2 等后缀)')
|
|
156
|
+
.option('--target-asset <path>', 'Existing asset to replace; read its schema references and delivery constraints')
|
|
157
|
+
.option('--target-field-path <path>', 'Target image field as an array of keys, e.g. ["endUI","playButton"]', parseImageTargetFieldPath)
|
|
158
|
+
.option('--no-target-reference', 'Generate without the existing asset reference only when explicitly requested')
|
|
159
|
+
.option('--output-format <format>', 'Final format: png, webp or jpeg')
|
|
160
|
+
.option('--fit-mode <mode>', 'Canvas fitting: contain, cover or fill')
|
|
161
|
+
.option('--padding-color <color>', 'Canvas padding color (transparent by default)')
|
|
162
|
+
.addOption(new Option('--background <mode>', 'Agent background decision from conversation context').choices(['transparent', 'opaque']))
|
|
163
|
+
.option('--remove-background', 'Require a verified transparent image')
|
|
164
|
+
.option('--no-remove-background', 'Keep the generated background')
|
|
154
165
|
.option('--image-size <size>', '图片尺寸 (1K|2K|4K)')
|
|
155
166
|
.option('--width <n>', '精确宽度(像素;MC 横排 5×9:16 推荐 3600 或 4096)', (v) => parseInt(v, 10))
|
|
156
167
|
.option('--height <n>', '精确高度(像素;MC 推荐 1280 或 1455)', (v) => parseInt(v, 10))
|
|
157
168
|
.option('--reference-image <path>', '参考图路径(可重复多次,最多 8 张),支持 PNG/JPG/WEBP', collectReferenceImagePaths, [])
|
|
158
169
|
.option('--image-model <model>', '模型名(如 gpt-image-2)或 provider/model(如 mulerouter/gpt-image-2)。传模型名时后端按优先级自动 fallback;传 provider/model 则直连指定 provider')
|
|
159
|
-
.option('--retry <n>', '
|
|
170
|
+
.option('--retry <n>', '额外重试轮数(默认 0;后端统一限制尝试,透明验证失败和超时不重试)', (v) => parseInt(v, 10), 0)
|
|
160
171
|
.option('--timeout <seconds>', '请求超时秒数(默认 1800,即 30 分钟;异步生图模型耗时较长,仅在后端明确报错时提前终止)', (v) => parseInt(v, 10), 1800)
|
|
161
172
|
.option('--count <n>', '一次 API 调用生成多少张图片(默认 1,最多 10;仅 gpt-image-2 实际支持批量)', (v) => parseInt(v, 10), 1)
|
|
162
173
|
.action(async (opts) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const hasReferenceImages = paths.length > 0;
|
|
170
|
-
const attemptGenerate = async (modelRef, attempt) => {
|
|
171
|
-
const label = modelRef ? `[${modelRef}]` : '[default model]';
|
|
172
|
-
if (attempt > 0) {
|
|
173
|
-
console.log(`Retry ${attempt}/${opts.retry} ${label}...`);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
console.log(`Generating image ${label}...`);
|
|
177
|
-
}
|
|
178
|
-
const referenceImages = await collectReferenceImagePayloads(paths);
|
|
179
|
-
const client = new AgentApiClient();
|
|
180
|
-
const imageCount = Math.min(Math.max(1, opts.count ?? 1), 10);
|
|
181
|
-
const requestPromise = client.post('/generate-image', {
|
|
182
|
-
prompt: opts.prompt,
|
|
183
|
-
aspectRatio: opts.aspectRatio,
|
|
184
|
-
imageSize: opts.imageSize,
|
|
185
|
-
...(opts.width && opts.height ? { width: opts.width, height: opts.height } : {}),
|
|
186
|
-
referenceImages,
|
|
187
|
-
...(modelRef ? { imageModelRef: modelRef } : {}),
|
|
188
|
-
...(imageCount > 1 ? { imageCount } : {}),
|
|
189
|
-
});
|
|
190
|
-
return raceWithTimeout(requestPromise, opts.timeout * 1000, `Request timed out after ${opts.timeout}s. The backend task may still be running — check admin panel before re-running.`);
|
|
191
|
-
};
|
|
192
|
-
const enrichError = (err, modelRef) => {
|
|
193
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
194
|
-
const lines = [`Error: ${msg}`];
|
|
195
|
-
if (msg.includes('500') || msg.includes('Internal server error')) {
|
|
196
|
-
lines.push('');
|
|
197
|
-
lines.push('Hint: API 500 error — the model may be temporarily unavailable.');
|
|
198
|
-
lines.push(' → If using a bare model name (e.g. gpt-image-2), all providers failed — try a different model');
|
|
199
|
-
if (modelRef?.includes('/')) {
|
|
200
|
-
lines.push(' → Or try without provider prefix to auto-fallback providers: --image-model gpt-image-2');
|
|
201
|
-
}
|
|
174
|
+
try {
|
|
175
|
+
const explicitBackground = opts.background === undefined ? opts.removeBackground : opts.background === 'transparent';
|
|
176
|
+
if (opts.background !== undefined && opts.removeBackground !== undefined && opts.removeBackground !== explicitBackground) {
|
|
177
|
+
throw new Error('Conflicting background options. Use --background transparent or --background opaque; no image request was sent.');
|
|
202
178
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
lines.push(' → Check the backend/admin panel for task status before re-running');
|
|
207
|
-
lines.push(' → Try --image-size 1K to reduce generation time');
|
|
208
|
-
lines.push(' → Or increase timeout with --timeout <seconds> (current default: 1800s)');
|
|
179
|
+
opts = { ...opts, removeBackground: explicitBackground };
|
|
180
|
+
if (opts.targetFieldPath && !opts.targetAsset) {
|
|
181
|
+
throw new Error('--target-field-path requires --target-asset; no image request was sent.');
|
|
209
182
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
183
|
+
const explicitOutputFormat = opts.outputFormat;
|
|
184
|
+
const { dir: outputDir, name: outputName, ext: outputExt } = parse(opts.output);
|
|
185
|
+
const outputCandidates = [opts.output, ...Array.from({ length: opts.count > 1 ? Math.min(opts.count, 10) : 0 }, (_, i) => join(outputDir, `${outputName}_${i + 1}${outputExt}`))];
|
|
186
|
+
const assetContext = opts.targetAsset ? await readImageAssetContext(opts.targetAsset, process.cwd(), {
|
|
187
|
+
referenceImagePaths: opts.referenceImage, useTargetReference: opts.targetReference,
|
|
188
|
+
...(opts.targetFieldPath ? { targetFieldPath: opts.targetFieldPath } : {}),
|
|
189
|
+
outputPaths: outputCandidates,
|
|
190
|
+
prompt: opts.prompt, removeBackground: opts.removeBackground,
|
|
191
|
+
}) : undefined;
|
|
192
|
+
opts = { ...opts,
|
|
193
|
+
aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
|
|
194
|
+
width: assetContext?.width ?? opts.width, height: assetContext?.height ?? opts.height,
|
|
195
|
+
outputFormat: assetContext?.outputFormatFromSchema ? assetContext.outputFormat : opts.outputFormat ?? assetContext?.outputFormat,
|
|
196
|
+
fitMode: assetContext?.fitMode ?? opts.fitMode,
|
|
197
|
+
removeBackground: resolveImageBackgroundRequirement({ prompt: opts.prompt,
|
|
198
|
+
schemaRemoveBackground: assetContext?.removeBackgroundFromSchema ? assetContext.removeBackground : undefined,
|
|
199
|
+
removeBackground: opts.removeBackground, fallbackRemoveBackground: assetContext?.removeBackground }),
|
|
200
|
+
paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
|
|
201
|
+
imageModel: opts.imageModel || assetContext?.imageModelRef,
|
|
202
|
+
};
|
|
203
|
+
const invalidDelivery = validateImageDeliveryOptions(opts);
|
|
204
|
+
if (invalidDelivery)
|
|
205
|
+
throw new Error(invalidDelivery);
|
|
206
|
+
const paths = opts.referenceImage?.length ? opts.referenceImage : assetContext?.referenceImagePaths ?? [];
|
|
207
|
+
if (paths.length > MAX_REFERENCE_IMAGES) {
|
|
208
|
+
console.error(`Error: Too many reference images: ${paths.length} paths given; maximum is ${MAX_REFERENCE_IMAGES}.`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
return;
|
|
215
211
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
212
|
+
const hasReferenceImages = paths.length > 0;
|
|
213
|
+
const attemptGenerate = async (modelRef, attempt) => {
|
|
214
|
+
const label = modelRef ? `[${modelRef}]` : '[default model]';
|
|
215
|
+
if (attempt > 0) {
|
|
216
|
+
console.log(`Retry ${attempt}/${opts.retry} ${label}...`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log(`Generating image ${label}...`);
|
|
220
|
+
}
|
|
221
|
+
const referenceImages = await collectReferenceImagePayloads(paths);
|
|
222
|
+
const client = new AgentApiClient();
|
|
223
|
+
const imageCount = Math.min(Math.max(1, opts.count ?? 1), 10);
|
|
224
|
+
const requestPromise = client.post('/generate-image', {
|
|
225
|
+
prompt: opts.prompt,
|
|
226
|
+
aspectRatio: assetContext?.aspectRatio ?? opts.aspectRatio,
|
|
227
|
+
imageSize: opts.imageSize,
|
|
228
|
+
width: assetContext?.width ?? opts.width,
|
|
229
|
+
height: assetContext?.height ?? opts.height,
|
|
230
|
+
outputFormat: opts.outputFormat,
|
|
231
|
+
outputFormatSource: assetContext?.outputFormatFromSchema ? 'schema'
|
|
232
|
+
: explicitOutputFormat ? 'explicit' : assetContext ? 'inferred' : undefined,
|
|
233
|
+
fitMode: assetContext?.fitMode ?? opts.fitMode,
|
|
234
|
+
paddingColor: assetContext?.paddingColor ?? opts.paddingColor,
|
|
235
|
+
background: opts.background === undefined ? undefined : opts.removeBackground ? 'transparent' : 'opaque',
|
|
236
|
+
removeBackground: opts.removeBackground,
|
|
237
|
+
backgroundRequirementSource: assetContext?.removeBackgroundFromSchema ? 'schema'
|
|
238
|
+
: explicitBackground !== undefined ? 'explicit' : 'inferred',
|
|
239
|
+
referenceImages,
|
|
240
|
+
...(modelRef ? { imageModelRef: modelRef } : {}),
|
|
241
|
+
...(imageCount > 1 ? { imageCount } : {}),
|
|
242
|
+
});
|
|
243
|
+
return raceWithTimeout(requestPromise, opts.timeout * 1000, `Request timed out after ${opts.timeout}s. The backend task may still be running — check admin panel before re-running.`);
|
|
244
|
+
};
|
|
245
|
+
const enrichError = (err, modelRef) => {
|
|
246
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
247
|
+
const lines = [`Error: ${msg}`];
|
|
248
|
+
if (/source_transparency_invalid|output_transparency_invalid|transparency_unsupported/.test(msg)) {
|
|
249
|
+
lines.push('Hint: Transparent output was not delivered. Preserve the requested transparency, references and model; use the request id and stage to investigate.');
|
|
250
|
+
}
|
|
251
|
+
else if (/API 500\b|Internal server error/.test(msg)) {
|
|
252
|
+
lines.push('');
|
|
253
|
+
lines.push('Hint: API 500 error — the model may be temporarily unavailable.');
|
|
254
|
+
lines.push(' → Inspect the request id and backend diagnostics before another generation attempt.');
|
|
255
|
+
if (modelRef?.includes('/') && opts.removeBackground !== true) {
|
|
256
|
+
lines.push(' → Or try without provider prefix to auto-fallback providers: --image-model gpt-image-2');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else if (msg.includes('timed out')) {
|
|
260
|
+
lines.push('');
|
|
261
|
+
lines.push('Hint: Request timed out. The backend task may still be running — retries were skipped to avoid creating duplicate tasks.');
|
|
262
|
+
lines.push(' → Check the backend/admin panel for task status before re-running');
|
|
263
|
+
lines.push(' → Try --image-size 1K to reduce generation time');
|
|
264
|
+
lines.push(' → Or increase timeout with --timeout <seconds> (current default: 1800s)');
|
|
265
|
+
}
|
|
266
|
+
else if (hasReferenceImages && (msg.includes('reference') || msg.includes('image input'))) {
|
|
267
|
+
lines.push('');
|
|
268
|
+
lines.push('Hint: Reference image error — the selected model may not support --reference-image.');
|
|
269
|
+
lines.push(' → Run: playcraft tools list-image-models');
|
|
270
|
+
lines.push(' → Models with CAPABILITY=text+image support --reference-image');
|
|
271
|
+
}
|
|
272
|
+
return lines.join('\n');
|
|
273
|
+
};
|
|
219
274
|
let result = null;
|
|
220
275
|
let lastError = null;
|
|
221
276
|
// 重试逻辑:超时不重试(后端任务可能仍在运行,重试会导致重复提交)
|
|
222
|
-
const maxAttempts = 1 + (opts.retry ??
|
|
277
|
+
const maxAttempts = 1 + (opts.retry ?? 0);
|
|
223
278
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
224
279
|
try {
|
|
225
|
-
result = await attemptGenerate(opts.imageModel, attempt);
|
|
280
|
+
result = await attemptGenerate(opts.imageModel || assetContext?.imageModelRef, attempt);
|
|
226
281
|
break;
|
|
227
282
|
}
|
|
228
283
|
catch (e) {
|
|
229
284
|
lastError = e;
|
|
230
285
|
const msg = e instanceof Error ? e.message : String(e);
|
|
231
286
|
const isTimeout = msg.includes('timed out');
|
|
232
|
-
|
|
233
|
-
|
|
287
|
+
const cannotRetry = /source_transparency_invalid|output_transparency_invalid|transparency_unsupported|"retryable"\s*:\s*false/.test(msg);
|
|
288
|
+
if (isTimeout || cannotRetry) {
|
|
289
|
+
console.error(`Attempt ${attempt + 1} stopped: ${msg}`);
|
|
234
290
|
break;
|
|
235
291
|
}
|
|
236
292
|
if (attempt < maxAttempts - 1) {
|
|
@@ -255,16 +311,18 @@ export function registerGenerationCommands(tools) {
|
|
|
255
311
|
}
|
|
256
312
|
// 收集所有待保存图片(第 1 张 + 批量额外图)
|
|
257
313
|
const allImages = [
|
|
258
|
-
{ imageBase64: result.imageBase64, mimeType: result.mimeType },
|
|
314
|
+
{ imageBase64: result.imageBase64, mimeType: result.mimeType, previewUrl: result.previewUrl },
|
|
259
315
|
...(result.additionalImages ?? []),
|
|
260
316
|
];
|
|
261
317
|
const isBatch = allImages.length > 1;
|
|
262
|
-
const modelPart =
|
|
318
|
+
const modelPart = result.model ? `model: ${result.model}` : '';
|
|
263
319
|
const providerPart = result.provider ? `provider: ${result.provider}` : '';
|
|
264
320
|
const labelParts = [modelPart, providerPart].filter(Boolean);
|
|
265
321
|
const modelLabel = labelParts.length > 0 ? ` (${labelParts.join(', ')})` : '';
|
|
266
322
|
const savedPaths = [];
|
|
267
|
-
|
|
323
|
+
if (result.transparencySource)
|
|
324
|
+
console.log(`Transparency source: ${result.transparencySource}`);
|
|
325
|
+
const stripTarget = opts.targetAsset || result.transparentBackground ? null : resolveStripTargetDimensions({
|
|
268
326
|
aspectRatio: opts.aspectRatio,
|
|
269
327
|
width: opts.width,
|
|
270
328
|
height: opts.height,
|
|
@@ -293,6 +351,8 @@ export function registerGenerationCommands(tools) {
|
|
|
293
351
|
console.log(`↑ Letterbox ${generatedWidth}×${generatedHeight} → ${stripTarget.width}×${stripTarget.height}(等比 + 白边,不拉伸)`);
|
|
294
352
|
}
|
|
295
353
|
}
|
|
354
|
+
if (assetContext)
|
|
355
|
+
assertImageAssetOutputPaths(assetContext, [resolvedPath]);
|
|
296
356
|
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
297
357
|
writeFileSync(resolvedPath, imgBuf);
|
|
298
358
|
let actualWidth = null;
|
|
@@ -309,11 +369,23 @@ export function registerGenerationCommands(tools) {
|
|
|
309
369
|
}
|
|
310
370
|
const sizeKB = Math.round(imgBuf.length / 1024);
|
|
311
371
|
console.log(`[${i + 1}/${allImages.length}] Image saved to ${resolvedPath} (${sizeKB}KB)${modelLabel}`);
|
|
372
|
+
if (img.previewUrl)
|
|
373
|
+
console.log(`Image preview: ${img.previewUrl}`);
|
|
312
374
|
savedPaths.push(resolvedPath);
|
|
313
375
|
const sidecar = {
|
|
314
376
|
prompt: opts.prompt,
|
|
315
|
-
model:
|
|
377
|
+
model: result.model ?? null,
|
|
378
|
+
requestedModel: opts.imageModel ?? null,
|
|
316
379
|
provider: result.provider ?? null,
|
|
380
|
+
transparentBackground: result.transparentBackground ?? null,
|
|
381
|
+
requestedBackground: opts.background ?? null,
|
|
382
|
+
transparencySource: result.transparencySource ?? null,
|
|
383
|
+
requestId: result.requestId ?? null,
|
|
384
|
+
attempts: result.attempts ?? null,
|
|
385
|
+
targetAssetPath: assetContext?.targetAssetPath ?? null,
|
|
386
|
+
outputFormat: opts.outputFormat ?? null,
|
|
387
|
+
fitMode: opts.fitMode ?? null,
|
|
388
|
+
paddingColor: opts.paddingColor ?? null,
|
|
317
389
|
aspectRatio: opts.aspectRatio,
|
|
318
390
|
imageSize: opts.imageSize ?? null,
|
|
319
391
|
requestedWidth: opts.width ?? stripTarget?.width ?? null,
|
|
@@ -326,14 +398,12 @@ export function registerGenerationCommands(tools) {
|
|
|
326
398
|
count: opts.count ?? 1,
|
|
327
399
|
batchIndex: isBatch ? i + 1 : null,
|
|
328
400
|
output: resolvedPath,
|
|
401
|
+
previewUrl: img.previewUrl ?? null,
|
|
329
402
|
referenceImageStatus: result.referenceImageStatus ?? null,
|
|
330
403
|
generatedAt: new Date().toISOString(),
|
|
331
404
|
};
|
|
332
405
|
const sidecarPath = resolvedPath.replace(/\.[^.]+$/, '.json');
|
|
333
406
|
writeFileSync(sidecarPath, JSON.stringify(sidecar, null, 2));
|
|
334
|
-
await captureGeneratedArtifact(resolvedPath, 'generate-image', {
|
|
335
|
-
...(actualWidth ? { width: actualWidth } : {}), ...(actualHeight ? { height: actualHeight } : {}),
|
|
336
|
-
});
|
|
337
407
|
console.log(` └─ Generation metadata: ${sidecarPath}`);
|
|
338
408
|
}
|
|
339
409
|
if (!isBatch && opts.output !== savedPaths[0] && savedPaths[0]) {
|
|
@@ -381,7 +451,6 @@ export function registerGenerationCommands(tools) {
|
|
|
381
451
|
output: opts.output, generatedAt: new Date().toISOString(),
|
|
382
452
|
};
|
|
383
453
|
writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(sfxSidecar, null, 2));
|
|
384
|
-
await captureGeneratedArtifact(opts.output, 'generate-sfx', { duration: result.duration });
|
|
385
454
|
console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
|
|
386
455
|
}
|
|
387
456
|
catch (e) {
|
|
@@ -414,7 +483,6 @@ export function registerGenerationCommands(tools) {
|
|
|
414
483
|
output: opts.output, generatedAt: new Date().toISOString(),
|
|
415
484
|
};
|
|
416
485
|
writeFileSync(opts.output.replace(/\.[^.]+$/, '.json'), JSON.stringify(bgmSidecar, null, 2));
|
|
417
|
-
await captureGeneratedArtifact(opts.output, 'generate-bgm', { duration: result.duration });
|
|
418
486
|
console.log(` └─ Generation metadata: ${opts.output.replace(/\.[^.]+$/, '.json')}`);
|
|
419
487
|
}
|
|
420
488
|
catch (e) {
|