@playcraft/cli 0.0.57 → 0.0.58
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 +34 -16
- package/dist/cli-root-help.js +1 -0
- package/dist/commands/build-all.js +10 -9
- package/dist/commands/build.js +13 -12
- package/dist/commands/create.js +26 -33
- package/dist/commands/platform-skills.generated.js +19 -0
- package/dist/commands/skills.js +2 -0
- package/dist/commands/tools-generation.js +1 -1
- package/dist/commands/workspace-runtime.js +54 -0
- package/dist/index.js +3 -1
- package/dist/project-skills/commands.js +72 -0
- package/dist/project-skills/lifecycle.js +28 -0
- package/dist/project-skills/local-run.js +112 -0
- package/dist/project-skills/local-store.js +149 -0
- package/dist/project-skills/messages.js +72 -0
- package/dist/project-skills/reconcile.js +62 -0
- package/dist/project-skills/remote-cache.js +51 -0
- package/dist/project-skills/validation.js +19 -0
- package/dist/remix/clone.js +2 -0
- package/dist/remix/init-template.js +2 -0
- package/dist/remix/pull.js +2 -0
- package/dist/remix/push.js +21 -1
- package/dist/utils/agent-api-client.js +54 -17
- package/dist/utils/tool-operation-journal.js +54 -0
- package/dist/workspace-runtime/codex/app-server.js +395 -0
- package/dist/workspace-runtime/codex/config-toml.js +25 -0
- package/dist/workspace-runtime/codex/jsonrpc-stdio.js +106 -0
- package/dist/workspace-runtime/codex/loopback.js +59 -0
- package/dist/workspace-runtime/codex/native-adapter.js +3 -0
- package/dist/workspace-runtime/main.js +10 -0
- package/dist/workspace-runtime/persistence/journal.js +350 -0
- package/dist/workspace-runtime/processes/managed-writes.js +69 -0
- package/dist/workspace-runtime/serve.js +111 -0
- package/dist/workspace-runtime/server/auth.js +21 -0
- package/dist/workspace-runtime/server/dispatch.js +861 -0
- package/dist/workspace-runtime/server/execution-group.js +88 -0
- package/dist/workspace-runtime/server/http.js +561 -0
- package/dist/workspace-runtime/server/lock.js +53 -0
- package/dist/workspace-runtime/server/types.js +1 -0
- package/dist/workspace-runtime/workspaces/context-error.js +2 -0
- package/dist/workspace-runtime/workspaces/file-snapshot.js +213 -0
- package/dist/workspace-runtime/workspaces/files.js +143 -0
- package/dist/workspace-runtime/workspaces/git.js +242 -0
- package/dist/workspace-runtime/workspaces/json5-edit.js +170 -0
- package/dist/workspace-runtime/workspaces/parameters.js +272 -0
- package/dist/workspace-runtime/workspaces/prepare.js +364 -0
- package/dist/workspace-runtime/workspaces/registry.js +107 -0
- package/dist/workspace-runtime/workspaces/revisions.js +31 -0
- package/package.json +4 -1
- package/project-template-v2/.claude/agents/artist.md +82 -0
- package/project-template-v2/.claude/agents/developer.md +153 -0
- package/project-template-v2/.claude/agents/game-designer.md +264 -0
- package/project-template-v2/.claude/agents/refs/artist-art-style-catalog.md +533 -0
- package/project-template-v2/.claude/agents/refs/artist-color-audio-recipes.md +153 -0
- package/project-template-v2/.claude/agents/refs/artist-dimension-axis.md +27 -0
- package/project-template-v2/.claude/agents/refs/artist-master-composite-recipes.md +208 -0
- package/project-template-v2/.claude/agents/refs/atom-skill-library.md +81 -0
- package/project-template-v2/.claude/agents/refs/developer-impl-cookbook.md +432 -0
- package/project-template-v2/.claude/agents/refs/framework-5-component-filter.md +252 -0
- package/project-template-v2/.claude/agents/refs/framework-game-feel-juice.md +266 -0
- package/project-template-v2/.claude/agents/refs/framework-mda.md +147 -0
- package/project-template-v2/.claude/agents/refs/game-designer-gameplay-sufficiency.md +123 -0
- package/project-template-v2/.claude/agents/refs/ta-3d-flip-recipe.md +88 -0
- package/project-template-v2/.claude/agents/refs/ta-atlas-deliverable-standard.md +67 -0
- package/project-template-v2/.claude/agents/refs/ta-batch-pipeline-recipes.md +120 -0
- package/project-template-v2/.claude/agents/refs/ta-image-generation-detail.md +300 -0
- package/project-template-v2/.claude/agents/refs/ta-image-ops-reference.md +495 -0
- package/project-template-v2/.claude/agents/refs/ta-pipeline-cookbook.md +1141 -0
- package/project-template-v2/.claude/agents/refs/ta-tools-reference.md +111 -0
- package/project-template-v2/.claude/agents/refs/ta-vfx-preset-catalog.md +365 -0
- package/project-template-v2/.claude/agents/refs/threejs-cannon-pitfalls.md +412 -0
- package/project-template-v2/.claude/agents/reviewer.md +75 -0
- package/project-template-v2/.claude/agents/technical-artist.md +86 -0
- package/project-template-v2/.claude/hooks/snapshot-milestone.mjs +243 -0
- package/project-template-v2/.claude/hooks/user-prompt.mjs +133 -0
- package/project-template-v2/.claude/settings.json +33 -0
- package/project-template-v2/.claude/skills/brainstorming/SKILL.md +161 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/frame-template.html +270 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/helper.js +177 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/server.cjs +354 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/start-server.sh +148 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/stop-server.sh +56 -0
- package/project-template-v2/.claude/skills/brainstorming/scripts/wait-for-selection.sh +62 -0
- package/project-template-v2/.claude/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/project-template-v2/.claude/skills/brainstorming/visual-companion.md +309 -0
- package/project-template-v2/.claude/skills/playcraft-ad-psychology/SKILL.md +182 -0
- package/project-template-v2/.claude/skills/playcraft-art-style-guide/SKILL.md +123 -0
- package/project-template-v2/.claude/skills/playcraft-asset-state-sheet/SKILL.md +205 -0
- package/project-template-v2/.claude/skills/playcraft-audio-generation/SKILL.md +280 -0
- package/project-template-v2/.claude/skills/playcraft-batch-pipeline/SKILL.md +184 -0
- package/project-template-v2/.claude/skills/playcraft-build-optimizer/SKILL.md +306 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/SKILL.md +298 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +123 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +254 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +324 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +97 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +118 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +137 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +397 -0
- package/project-template-v2/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +296 -0
- package/project-template-v2/.claude/skills/playcraft-image-ops/SKILL.md +122 -0
- package/project-template-v2/.claude/skills/playcraft-image-processing/SKILL.md +219 -0
- package/project-template-v2/.claude/skills/playcraft-masking/SKILL.md +373 -0
- package/project-template-v2/.claude/skills/playcraft-playable-optimization/SKILL.md +161 -0
- package/project-template-v2/.claude/skills/playcraft-research/SKILL.md +215 -0
- package/project-template-v2/.claude/skills/playcraft-skill-recommender/SKILL.md +382 -0
- package/project-template-v2/.claude/skills/playcraft-sprite-generation/SKILL.md +423 -0
- package/project-template-v2/.claude/skills/playcraft-sprite-remix/SKILL.md +158 -0
- package/project-template-v2/.claude/skills/playcraft-sprite-sheet/SKILL.md +100 -0
- package/project-template-v2/.claude/skills/playcraft-storyboard/SKILL.md +167 -0
- package/project-template-v2/.claude/skills/playcraft-style-qa/SKILL.md +270 -0
- package/project-template-v2/.claude/skills/playcraft-text-rendering/SKILL.md +236 -0
- package/project-template-v2/.claude/skills/playcraft-vfx-animation/SKILL.md +130 -0
- package/project-template-v2/.claude/skills/playwright-cli/SKILL.md +390 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/element-attributes.md +23 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/request-mocking.md +87 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/running-code.md +240 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/session-management.md +226 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/spec-driven-testing.md +308 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/storage-state.md +275 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/test-generation.md +134 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/tracing.md +142 -0
- package/project-template-v2/.claude/skills/playwright-cli/references/video-recording.md +153 -0
- package/project-template-v2/.claude/skills/session-analyzer/SKILL.md +386 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/execution-breakdown.mjs +182 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/find-turns.mjs +72 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/heavy-output.mjs +121 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/resolve-session.mjs +102 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-stats.mjs +127 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/subagent-tool-timeline.mjs +106 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/time-gaps.mjs +128 -0
- package/project-template-v2/.claude/skills/session-analyzer/scripts/turn-timeline.mjs +67 -0
- package/project-template-v2/.claude/snapshot.mjs +263 -0
- package/project-template-v2/.playcraft/skills.lock.json +152 -0
- package/project-template-v2/CLAUDE.md +146 -0
- 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 +254 -0
- package/project-template-v2/docs/harness/iteration-1/generate-flow.md +91 -0
- package/project-template-v2/docs/harness/iteration-1/ideate-flow.md +214 -0
- package/project-template-v2/docs/harness/iteration-1/optimize-flow.md +75 -0
- package/project-template-v2/docs/harness/iteration-1/wrapup-flow.md +63 -0
- package/project-template-v2/docs/harness/iteration-2/context-flow.md +223 -0
- package/project-template-v2/docs/harness/iteration-2/generate-flow.md +129 -0
- package/project-template-v2/docs/harness/iteration-2/ideate-flow.md +267 -0
- package/project-template-v2/docs/harness/iteration-2/optimize-flow.md +164 -0
- package/project-template-v2/docs/harness/iteration-2/wrapup-flow.md +115 -0
- package/project-template-v2/docs/harness/orchestrator-flow.md +364 -0
- package/project-template-v2/docs/project-state.json +60 -0
- package/project-template-v2/docs/project-state.md +72 -0
- package/project-template-v2/docs/standards/README.md +225 -0
- package/project-template-v2/docs/standards/agent-behavior-standards.md +174 -0
- package/project-template-v2/docs/standards/artifacts/design-brief.md +19 -0
- package/project-template-v2/docs/standards/artifacts/design.md +22 -0
- package/project-template-v2/docs/standards/artifacts/game-code.md +41 -0
- package/project-template-v2/docs/standards/artifacts/todo-list.md +41 -0
- package/project-template-v2/docs/standards/iter1-agent-behavior-standards.md +343 -0
- package/project-template-v2/game/index.ts +18 -0
- package/project-template-v2/globals.d.ts +51 -0
- package/project-template-v2/index.css +34 -0
- package/project-template-v2/index.html +18 -0
- package/project-template-v2/main.ts +9 -0
- package/project-template-v2/package.json +46 -0
- package/project-template-v2/skills/_shared/scripts/dispatch-clear.mjs +31 -0
- package/project-template-v2/skills/_shared/scripts/dispatch-set.mjs +86 -0
- package/project-template-v2/skills/_shared/scripts/dod-check.mjs +153 -0
- package/project-template-v2/skills/_shared/scripts/handoff-append.mjs +70 -0
- package/project-template-v2/skills/_shared/scripts/lib/validator-artifacts.mjs +91 -0
- package/project-template-v2/skills/_shared/scripts/pipeline/dod-config.mjs +131 -0
- package/project-template-v2/skills/_shared/scripts/pipeline/index.mjs +80 -0
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-1-core.mjs +90 -0
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-2-wrap.mjs +93 -0
- package/project-template-v2/skills/_shared/scripts/pipeline/iteration-3-visual.mjs +23 -0
- package/project-template-v2/skills/_shared/scripts/render-project-state.mjs +230 -0
- package/project-template-v2/skills/_shared/scripts/state-advance-stage.mjs +58 -0
- package/project-template-v2/skills/_shared/scripts/state-get.mjs +339 -0
- package/project-template-v2/skills/_shared/scripts/state-handoff.mjs +39 -0
- package/project-template-v2/skills/_shared/scripts/state-set.mjs +94 -0
- package/project-template-v2/skills/_shared/scripts/state-store.mjs +783 -0
- package/project-template-v2/skills/_shared/scripts/todo-add.mjs +88 -0
- package/project-template-v2/skills/_shared/scripts/todo-get.mjs +130 -0
- package/project-template-v2/skills/_shared/scripts/todo-remove.mjs +33 -0
- package/project-template-v2/skills/_shared/scripts/todo-set.mjs +47 -0
- package/project-template-v2/skills/_shared/scripts/verify-asset-code-sync.mjs +268 -0
- package/project-template-v2/skills/_shared/scripts/verify-env.mjs +285 -0
- package/project-template-v2/skills/_shared/scripts/verify-placeholders.mjs +161 -0
- package/project-template-v2/skills/playable-autoplay/SKILL.md +176 -0
- package/project-template-v2/skills/playable-autoplay/agents/openai.yaml +4 -0
- package/project-template-v2/skills/playable-debug/SKILL.md +116 -0
- package/project-template-v2/skills/playable-debug/agents/openai.yaml +4 -0
- package/project-template-v2/skills/playable-debug/references/debug-config.md +40 -0
- package/project-template-v2/skills/playable-record/SKILL.md +140 -0
- package/project-template-v2/skills/playable-record/scripts/lib/dev-server.mjs +104 -0
- package/project-template-v2/skills/playable-record/scripts/lib/record-audio-bridge.js +141 -0
- package/project-template-v2/skills/playable-record/scripts/record-playable.mjs +425 -0
- package/project-template-v2/skills/playable-record/scripts/verify-contract.mjs +261 -0
- package/project-template-v2/skills/playable-record/scripts/verify-firstwin.mjs +398 -0
- package/project-template-v2/skills/playable-record/scripts/verify-fusion.mjs +322 -0
- package/project-template-v2/skills/playable-record/scripts/verify-lifecycle.mjs +105 -0
- package/project-template-v2/skills/playable-record/scripts/verify-vlm-video.mjs +230 -0
- package/project-template-v2/skills/playable-validate/SKILL.md +61 -0
- package/project-template-v2/skills/playable-validate/validation-rules.md +14 -0
- package/project-template-v2/skills/playable-verify-ui/SKILL.md +63 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/__init__.py +1 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/config_expr.js +218 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/node_utils.js +51 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/profile_loader.py +59 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/report.py +106 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/lib/runtime_contract.js +116 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_fetch_antipatterns.py +59 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_hardcoded_layout.js +64 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_runtime_contract.js +58 -0
- package/project-template-v2/skills/playable-verify-ui/scripts/verify_text_overlap.py +333 -0
- package/project-template-v2/ta-workspace/scripts/.gitkeep +0 -0
- package/project-template-v2/tsconfig.json +20 -0
- package/project-template-v2/vite.config.ts +27 -0
package/README.md
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@playcraft/cli)
|
|
6
6
|
[](https://www.npmjs.com/package/@playcraft/cli)
|
|
7
7
|
|
|
8
|
-
PlayCraft CLI
|
|
8
|
+
PlayCraft CLI(Command-Line Interface,命令行工具)支持本地代码与云端编辑器实时同步,以及将 PlayCanvas/PlayCraft 项目打包为多平台 Playable Ads。
|
|
9
|
+
|
|
10
|
+
## 云端工作台 Runtime
|
|
11
|
+
|
|
12
|
+
`playcraft workspace-runtime serve --config <json>` 已注册。它前台常驻、跳过升级检查,读取 Runtime Server 下发的引导配置,只绑定回环并校验 control token。`runtime.ensure` 会执行到终态;设置 `PLAYCRAFT_NATIVE_ADAPTER=loopback` 或测试注入 loopback 适配器后,可跑会话 create/turn/interrupt/审批,以及本地 journal 检查点/恢复/销毁。工作空间相对路径的 `file.write` 与文件检查点不依赖 loopback。相同幂等键上的 `uncertain` 操作不会新开 turn。这不是 Codex App Server。现有 `playcraft start` 仍用于单项目本地开发,二者不要混用。
|
|
13
|
+
|
|
14
|
+
实现与模块边界见 [Sandbox Agent Server](./src/workspace-runtime/README.md);契约见 [云端工作台后端架构方案](../../docs/architecture/backend/cloud-workspace/backend-architecture.md#cli-runtime)。
|
|
9
15
|
|
|
10
16
|
## ✨ 特性
|
|
11
17
|
|
|
@@ -75,7 +81,7 @@ npx @playcraft/cli start --project <project-id> --daemon
|
|
|
75
81
|
npx @playcraft/cli build
|
|
76
82
|
|
|
77
83
|
# 命令行打包
|
|
78
|
-
npx @playcraft/cli build --platform facebook --format
|
|
84
|
+
npx @playcraft/cli build --platform facebook --format zip --output ./dist
|
|
79
85
|
```
|
|
80
86
|
|
|
81
87
|
### 5. 创建并继续编辑 Remix
|
|
@@ -182,6 +188,18 @@ echo '{"token":"<sandbox-jwt>","apiUrl":"https://..."}' > .playcraft.json
|
|
|
182
188
|
| `recommend improvements` | Tag 改进建议 | `playcraft recommend improvements --channel Facebook` |
|
|
183
189
|
| `recommend random` | 随机 Tag 组合推荐 | `playcraft recommend random --channel Google` |
|
|
184
190
|
|
|
191
|
+
### 业务工具请求恢复
|
|
192
|
+
|
|
193
|
+
业务工具写请求要求服务支持持久操作协议。命令行先保存请求编号、路径和输入摘要到 `~/.playcraft/tool-requests/`,再发送请求;记录不包含凭证或请求正文。可用绝对路径环境变量 `PLAYCRAFT_TOOL_REQUEST_DIR` 指定可持久保留的目录。
|
|
194
|
+
|
|
195
|
+
如果请求超时或连接中断,错误会显示请求编号。使用相同参数重跑命令,并设置该编号,只查询原操作的确定结果:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
PLAYCRAFT_TOOL_REQUEST_ID=<错误中显示的请求编号> playcraft tools build-project --project-id <原项目编号>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
恢复不会重新构建。操作尚未完成、结果未知或没有回执时会明确失败;不要换编号或删除记录来强行重试。只有错误明确说明能力检查失败且尚未发送操作时,才可在服务恢复后发起新的正常命令。服务不兼容时命令会在发送业务请求前停止;沙箱命令行与 Business 须排空旧调用后同步升级。
|
|
202
|
+
|
|
185
203
|
### 构建相关
|
|
186
204
|
|
|
187
205
|
| 命令 | 说明 | 示例 |
|
|
@@ -195,18 +213,18 @@ echo '{"token":"<sandbox-jwt>","apiUrl":"https://..."}' > .playcraft.json
|
|
|
195
213
|
|
|
196
214
|
现已支持 **10 个主流广告平台**:
|
|
197
215
|
|
|
198
|
-
| 平台 | 格式 | 大小限制
|
|
199
|
-
| ----------------- | -------- |
|
|
200
|
-
| **Facebook** | HTML/ZIP | HTML: 5MB / ZIP: 5MB
|
|
201
|
-
| **Snapchat** | ZIP | 5MB
|
|
202
|
-
| **ironSource** | HTML | 5MB
|
|
203
|
-
| **AppLovin** | HTML | 5MB
|
|
204
|
-
| **Google Ads** | ZIP | 5MB
|
|
205
|
-
| **TikTok/Pangle** | ZIP | 5MB
|
|
206
|
-
| **Unity Ads** | HTML | 5MB
|
|
207
|
-
| **Liftoff** | ZIP | 5MB
|
|
208
|
-
| **Moloco** | HTML | 5MB
|
|
209
|
-
| **BIGO Ads** | ZIP | 5MB
|
|
216
|
+
| 平台 | 格式 | 大小限制 | SDK/API |
|
|
217
|
+
| ----------------- | -------- | -------------------- | ------------ |
|
|
218
|
+
| **Facebook** | HTML/ZIP | HTML: 5MB / ZIP: 5MB | FbPlayableAd |
|
|
219
|
+
| **Snapchat** | ZIP | 5MB | MRAID 2.0 |
|
|
220
|
+
| **ironSource** | HTML | 5MB | MRAID + dapi |
|
|
221
|
+
| **AppLovin** | HTML | 5MB | MRAID 2.0 |
|
|
222
|
+
| **Google Ads** | ZIP | 5MB | ExitApi |
|
|
223
|
+
| **TikTok/Pangle** | ZIP | 5MB | Pangle SDK |
|
|
224
|
+
| **Unity Ads** | HTML | 5MB | MRAID 2.0 |
|
|
225
|
+
| **Liftoff** | ZIP | 5MB | MRAID |
|
|
226
|
+
| **Moloco** | HTML | 5MB | FbPlayableAd |
|
|
227
|
+
| **BIGO Ads** | ZIP | 5MB | BIGO SDK |
|
|
210
228
|
|
|
211
229
|
## 💡 使用示例
|
|
212
230
|
|
|
@@ -225,8 +243,8 @@ playcraft start --project your-project-id
|
|
|
225
243
|
### 打包 Playable Ads
|
|
226
244
|
|
|
227
245
|
```bash
|
|
228
|
-
# Facebook
|
|
229
|
-
playcraft build --platform facebook --format
|
|
246
|
+
# Facebook 平台(ZIP,Phaser 产物格式)
|
|
247
|
+
playcraft build --platform facebook --format zip --output ./dist/facebook
|
|
230
248
|
|
|
231
249
|
# Snapchat 平台(ZIP)
|
|
232
250
|
playcraft build --platform snapchat --format zip --output ./dist/snapchat
|
package/dist/cli-root-help.js
CHANGED
|
@@ -7,6 +7,7 @@ export function getCliTopicsHelpText() {
|
|
|
7
7
|
' 素材 tools generate-* | image <子命令> | audio <子命令> | prefab <子命令>',
|
|
8
8
|
' 平台 build, build-base, build-playable, build-all, analyze, inspect, upgrade',
|
|
9
9
|
' tools 除 generate-* 外(Git / 沙箱构建 / 发布 / 列表 / Prefab 等,需后端 API)',
|
|
10
|
+
' 沙箱常驻 workspace-runtime serve(Cloud Workspace,由 Runtime 引导配置启动)',
|
|
10
11
|
'',
|
|
11
12
|
'也可运行: playcraft topics',
|
|
12
13
|
'',
|
|
@@ -33,12 +33,12 @@ const PLATFORM_GROUPS = {
|
|
|
33
33
|
platforms: [...ALL_PLATFORMS],
|
|
34
34
|
},
|
|
35
35
|
html: {
|
|
36
|
-
name: '仅 HTML 渠道 (applovin, ironsource, unity, moloco,
|
|
37
|
-
platforms: ['applovin', 'ironsource', 'unity', 'moloco', '
|
|
36
|
+
name: '仅 HTML 渠道 (applovin, ironsource, unity, moloco, adikteev)',
|
|
37
|
+
platforms: ['applovin', 'ironsource', 'unity', 'moloco', 'adikteev'],
|
|
38
38
|
},
|
|
39
39
|
zip: {
|
|
40
|
-
name: '仅 ZIP 渠道 (google, tiktok, liftoff, bigo, snapchat, inmobi, mintegral)',
|
|
41
|
-
platforms: ['google', 'tiktok', 'liftoff', 'bigo', 'snapchat', 'inmobi', 'mintegral'],
|
|
40
|
+
name: '仅 ZIP 渠道 (google, tiktok, liftoff, bigo, snapchat, inmobi, mintegral, remerge)',
|
|
41
|
+
platforms: ['google', 'tiktok', 'liftoff', 'bigo', 'snapchat', 'inmobi', 'mintegral', 'remerge'],
|
|
42
42
|
},
|
|
43
43
|
mainstream: {
|
|
44
44
|
name: '主流渠道 (facebook, google, tiktok, applovin, ironsource, unity)',
|
|
@@ -55,7 +55,7 @@ const platformFormatConfig = {
|
|
|
55
55
|
unity: { formats: ['html'], default: 'html' },
|
|
56
56
|
moloco: { formats: ['html'], default: 'html' },
|
|
57
57
|
adikteev: { formats: ['html', 'zip'], default: 'html', description: 'PlayCanvas/PlayCraft uses HTML, others use ZIP' },
|
|
58
|
-
remerge: { formats: ['
|
|
58
|
+
remerge: { formats: ['zip'], default: 'zip' },
|
|
59
59
|
google: { formats: ['html', 'zip'], default: 'html' },
|
|
60
60
|
tiktok: { formats: ['zip'], default: 'zip' },
|
|
61
61
|
liftoff: { formats: ['zip'], default: 'zip' },
|
|
@@ -164,10 +164,11 @@ export async function buildAllCommand(projectPath, options) {
|
|
|
164
164
|
name: 'selection',
|
|
165
165
|
message: '选择要批量构建的渠道:',
|
|
166
166
|
choices: [
|
|
167
|
-
{ name:
|
|
168
|
-
|
|
169
|
-
{ name:
|
|
170
|
-
{ name:
|
|
167
|
+
{ name: `🌐 全部渠道(${ALL_PLATFORMS.length}个)`, value: 'all' },
|
|
168
|
+
// 分组文案直接取自 PLATFORM_GROUPS,避免两处渠道清单各写一份导致漂移
|
|
169
|
+
{ name: `⭐ ${PLATFORM_GROUPS.mainstream.name}`, value: 'mainstream' },
|
|
170
|
+
{ name: `📄 ${PLATFORM_GROUPS.html.name}`, value: 'html' },
|
|
171
|
+
{ name: `📦 ${PLATFORM_GROUPS.zip.name}`, value: 'zip' },
|
|
171
172
|
{ name: '🔧 自定义选择', value: 'custom' },
|
|
172
173
|
],
|
|
173
174
|
},
|
package/dist/commands/build.js
CHANGED
|
@@ -466,21 +466,20 @@ export async function buildCommand(projectPath, options) {
|
|
|
466
466
|
'mintegral',
|
|
467
467
|
];
|
|
468
468
|
// 渠道输出格式配置(根据各渠道Playable规格对照表)
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
469
|
+
// 单格式(ZIP): bigo, snapchat, remerge
|
|
470
|
+
// 单格式(HTML): applovin, ironsource, unity, moloco
|
|
471
|
+
// 双格式: facebook, google, tiktok, liftoff, inmobi, mintegral
|
|
472
|
+
// adikteev: 由引擎决定(PlayCanvas/PlayCraft 用 HTML,其他引擎用 ZIP)
|
|
473
|
+
// 注:Facebook 在 Phaser(playable-scripts devkit)下的产物格式由其 devkit 输入配置决定(恒为 ZIP),
|
|
474
|
+
// 平台侧不在此处做引擎判断。
|
|
472
475
|
const platformFormatConfig = {
|
|
473
|
-
facebook: {
|
|
474
|
-
formats: ['html', 'zip'],
|
|
475
|
-
default: 'html',
|
|
476
|
-
description: 'Facebook 支持两种格式'
|
|
477
|
-
},
|
|
476
|
+
facebook: { formats: ['html', 'zip'], default: 'html' },
|
|
478
477
|
applovin: { formats: ['html'], default: 'html' },
|
|
479
478
|
ironsource: { formats: ['html'], default: 'html' },
|
|
480
479
|
unity: { formats: ['html'], default: 'html' },
|
|
481
480
|
moloco: { formats: ['html'], default: 'html' },
|
|
482
481
|
adikteev: { formats: ['html', 'zip'], default: 'html', description: 'PlayCanvas/PlayCraft uses HTML, others use ZIP' },
|
|
483
|
-
remerge: { formats: ['
|
|
482
|
+
remerge: { formats: ['zip'], default: 'zip' },
|
|
484
483
|
google: {
|
|
485
484
|
formats: ['html', 'zip'],
|
|
486
485
|
default: 'html',
|
|
@@ -532,9 +531,11 @@ export async function buildCommand(projectPath, options) {
|
|
|
532
531
|
? (selectedPlatform === 'facebook' || selectedPlatform === 'google'
|
|
533
532
|
? 'HTML(单文件,最大 5MB,所有资源内联)'
|
|
534
533
|
: 'HTML(单文件)')
|
|
535
|
-
: (selectedPlatform === '
|
|
536
|
-
? 'ZIP(多文件,最大 5MB,
|
|
537
|
-
: '
|
|
534
|
+
: (selectedPlatform === 'google'
|
|
535
|
+
? 'ZIP(多文件,最大 5MB,ZIP 内文件数 ≤ 512)'
|
|
536
|
+
: selectedPlatform === 'facebook'
|
|
537
|
+
? 'ZIP(多文件,最大 5MB)'
|
|
538
|
+
: 'ZIP(多文件)'),
|
|
538
539
|
value: f,
|
|
539
540
|
})),
|
|
540
541
|
default: formatConfig.default,
|
package/dist/commands/create.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { prepareLocalSkillLifecycle } from '../project-skills/lifecycle.js';
|
|
1
2
|
import { execFileSync, execSync } from 'child_process';
|
|
2
3
|
import inquirer from 'inquirer';
|
|
3
4
|
import fs from 'fs/promises';
|
|
@@ -6,8 +7,11 @@ import { fileURLToPath } from 'url';
|
|
|
6
7
|
import pc from 'picocolors';
|
|
7
8
|
import ora from 'ora';
|
|
8
9
|
import { resolveCreateTemplate, resolveCreateTemplateDir, } from '../scaffold/templates.js';
|
|
10
|
+
import { PLATFORM_SKILL_DIRS } from './platform-skills.generated.js';
|
|
9
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
12
|
const __dirname = path.dirname(__filename);
|
|
13
|
+
/** `@playcraft/skills` 包内 Platform Skill 的目录名(与 Atom Skill 的 `skills/` 区分)。 */
|
|
14
|
+
const PLATFORM_SKILLS_DIRNAME = 'playcraft-skills';
|
|
11
15
|
/** 生成一个本地占位 Project ID(99xxxxxx),后续可通过 playcraft config set 更新为真实 ID */
|
|
12
16
|
function generateMockProjectId() {
|
|
13
17
|
const suffix = Math.floor(Math.random() * 90_000_000) + 10_000_000;
|
|
@@ -849,7 +853,7 @@ function extractSkillBodyForCursor(content) {
|
|
|
849
853
|
* @param cliCommandsDir CLI 命令所在目录(用于解析 skills 包位置)
|
|
850
854
|
* @param configDir 配置目录名(如 '.claude' 或 '.codebuddy')
|
|
851
855
|
*/
|
|
852
|
-
async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir) {
|
|
856
|
+
export async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir) {
|
|
853
857
|
const skillsLinkDir = path.join(targetDir, configDir, 'skills');
|
|
854
858
|
await fs.mkdir(skillsLinkDir, { recursive: true });
|
|
855
859
|
// 以下 Skill 在项目模板中以静态目录形式存在,不创建软连接覆盖它们。
|
|
@@ -868,11 +872,12 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
|
|
|
868
872
|
'playcraft-image-generation',
|
|
869
873
|
'playcraft-audio-generation',
|
|
870
874
|
]);
|
|
871
|
-
//
|
|
875
|
+
// Platform Skill 住在 playcraft-skills/,与 Atom Skill 的 skills/ 是两个目录。
|
|
876
|
+
// 尝试从 CLI 安装包的位置定位它(monorepo 内或与 CLI 平级安装时可解析)。
|
|
872
877
|
const candidateDirs = [
|
|
873
|
-
path.resolve(cliCommandsDir, '..', '..', '..', '..', 'skills',
|
|
874
|
-
path.resolve(cliCommandsDir, '..', '..', '..', 'skills',
|
|
875
|
-
path.resolve(cliCommandsDir, '..', '..', 'skills',
|
|
878
|
+
path.resolve(cliCommandsDir, '..', '..', '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
|
|
879
|
+
path.resolve(cliCommandsDir, '..', '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
|
|
880
|
+
path.resolve(cliCommandsDir, '..', '..', 'skills', PLATFORM_SKILLS_DIRNAME),
|
|
876
881
|
];
|
|
877
882
|
let resolvedSkillsDir = null;
|
|
878
883
|
for (const dir of candidateDirs) {
|
|
@@ -885,18 +890,24 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
|
|
|
885
890
|
// 继续下一个候选
|
|
886
891
|
}
|
|
887
892
|
}
|
|
888
|
-
// 相对路径(指向 npm install 后的 node_modules
|
|
889
|
-
const relativeSkillsBase = path.join('..', '..', 'node_modules', '@playcraft', 'skills',
|
|
893
|
+
// 相对路径(指向 npm install 后的 node_modules)作为安装后激活的备用
|
|
894
|
+
const relativeSkillsBase = path.join('..', '..', 'node_modules', '@playcraft', 'skills', PLATFORM_SKILLS_DIRNAME);
|
|
890
895
|
if (resolvedSkillsDir) {
|
|
891
|
-
// 能立即解析 →
|
|
896
|
+
// 能立即解析 → 以真实目录为准创建绝对路径软连接,当下即可使用。
|
|
897
|
+
// 按「是否含 SKILL.md」判定而非 playcraft- 前缀:sound-effects 无前缀但同样是平台技能。
|
|
892
898
|
const entries = await fs.readdir(resolvedSkillsDir, { withFileTypes: true });
|
|
893
899
|
for (const entry of entries) {
|
|
894
|
-
if (!entry.
|
|
900
|
+
if (!entry.isDirectory() || staticSkills.has(entry.name))
|
|
895
901
|
continue;
|
|
896
|
-
const linkPath = path.join(skillsLinkDir, entry.name);
|
|
897
902
|
const targetPath = path.join(resolvedSkillsDir, entry.name);
|
|
898
903
|
try {
|
|
899
|
-
await fs.
|
|
904
|
+
await fs.access(path.join(targetPath, 'SKILL.md'));
|
|
905
|
+
}
|
|
906
|
+
catch {
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
try {
|
|
910
|
+
await fs.symlink(targetPath, path.join(skillsLinkDir, entry.name), 'dir');
|
|
900
911
|
}
|
|
901
912
|
catch {
|
|
902
913
|
// 已存在则跳过
|
|
@@ -904,28 +915,9 @@ async function setupPlatformSkillLinksInner(targetDir, cliCommandsDir, configDir
|
|
|
904
915
|
}
|
|
905
916
|
}
|
|
906
917
|
else {
|
|
907
|
-
// 无法立即解析 →
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
'playcraft-audio-generation',
|
|
911
|
-
'playcraft-build',
|
|
912
|
-
'playcraft-code-editor',
|
|
913
|
-
'playcraft-create-remix',
|
|
914
|
-
'playcraft-deploy',
|
|
915
|
-
'playcraft-image-generation',
|
|
916
|
-
'playcraft-image-processing',
|
|
917
|
-
'playcraft-platform-intro',
|
|
918
|
-
'playcraft-prefab',
|
|
919
|
-
'playcraft-project-management',
|
|
920
|
-
'playcraft-remix-workflow',
|
|
921
|
-
'playcraft-save',
|
|
922
|
-
'playcraft-skill-recommender',
|
|
923
|
-
'playcraft-sprite-generation',
|
|
924
|
-
'playcraft-sprite-remix',
|
|
925
|
-
'playcraft-sprite-sheet',
|
|
926
|
-
'playcraft-3d-flip-sprite',
|
|
927
|
-
];
|
|
928
|
-
for (const name of knownPlatformTools) {
|
|
918
|
+
// 无法立即解析 → 指向 node_modules 的相对路径软连接,npm install 后自动激活。
|
|
919
|
+
// 清单由 scripts/generate-platform-skills.mjs 从真实目录生成并由 CI 校验,不要手写。
|
|
920
|
+
for (const name of PLATFORM_SKILL_DIRS) {
|
|
929
921
|
if (staticSkills.has(name))
|
|
930
922
|
continue;
|
|
931
923
|
const linkPath = path.join(skillsLinkDir, name);
|
|
@@ -1289,6 +1281,7 @@ export async function createCommand(projectName, options) {
|
|
|
1289
1281
|
smokeSpinner.warn(`Harness 自检跳过: ${message}`);
|
|
1290
1282
|
}
|
|
1291
1283
|
}
|
|
1284
|
+
await prepareLocalSkillLifecycle(targetDir, 'create');
|
|
1292
1285
|
const gitSpinner = ora(isWorktreeMode ? '提交项目分支...' : '初始化 Git 仓库...').start();
|
|
1293
1286
|
try {
|
|
1294
1287
|
if (isWorktreeMode) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// 此文件由 scripts/generate-platform-skills.mjs 生成,请勿手改。
|
|
2
|
+
// 重新生成:pnpm --filter @playcraft/cli generate:platform-skills
|
|
3
|
+
/** `@playcraft/skills/playcraft-skills/` 下的 Platform Skill 目录名。 */
|
|
4
|
+
export const PLATFORM_SKILL_DIRS = [
|
|
5
|
+
'playcraft-3d-flip-sprite',
|
|
6
|
+
'playcraft-asset-management',
|
|
7
|
+
'playcraft-build',
|
|
8
|
+
'playcraft-code-editor',
|
|
9
|
+
'playcraft-create-remix',
|
|
10
|
+
'playcraft-deploy',
|
|
11
|
+
'playcraft-iteration-methodology',
|
|
12
|
+
'playcraft-platform-intro',
|
|
13
|
+
'playcraft-prefab',
|
|
14
|
+
'playcraft-project-management',
|
|
15
|
+
'playcraft-remix-workflow',
|
|
16
|
+
'playcraft-save',
|
|
17
|
+
'playcraft-template-upgrade-merge',
|
|
18
|
+
'sound-effects',
|
|
19
|
+
];
|
package/dist/commands/skills.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
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';
|
|
21
22
|
import * as fs from 'node:fs';
|
|
22
23
|
import * as path from 'node:path';
|
|
23
24
|
import { getFusionHintsForGameplayAtoms, } from '../atom-tree/fusion-hints.js';
|
|
@@ -1430,6 +1431,7 @@ export function registerSkillsCommands(program) {
|
|
|
1430
1431
|
const skills = program
|
|
1431
1432
|
.command('skills')
|
|
1432
1433
|
.description('开发时 Skill 发现与脚手架工具(按 engine/intent 推荐 skill 集合,或将 ref 文件复制到项目)');
|
|
1434
|
+
registerProjectSkillsCommands(skills);
|
|
1433
1435
|
// 公共选项:skills 目录
|
|
1434
1436
|
const addSkillsDirOption = (cmd) => cmd.option('--skills-dir <path>', '指定 skills 目录路径(默认自动发现)');
|
|
1435
1437
|
// ── list ──────────────────────────────────────────────────────────────────
|
|
@@ -125,7 +125,7 @@ export function registerGenerationCommands(tools) {
|
|
|
125
125
|
}
|
|
126
126
|
console.log('');
|
|
127
127
|
console.log('提示:传入模型名(如 gpt-image-2),后端按优先级依次 fallback 各 provider(gpt-image-2:iegg-litellm → mulerouter → 302)。');
|
|
128
|
-
console.log(' 也可传入 provider/model(如 mulerouter/gpt-image-2)直连指定 provider。');
|
|
128
|
+
console.log(' 也可传入 provider/model(如 mulerouter/gpt-image-2、gamepilot/dreamina/dola-seedream-5-0-pro-260628)直连指定 provider。');
|
|
129
129
|
console.log('');
|
|
130
130
|
console.log('CAPABILITY 说明:');
|
|
131
131
|
console.log(' text→image 仅支持文生图(不可传 --reference-image)');
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { INCOMPATIBLE_EXIT_CODE, parseSandboxRuntimeConfig, } from '@playcraft/common/cloud-workspace/runtime';
|
|
3
|
+
import { startWorkspaceRuntime } from '../workspace-runtime/serve.js';
|
|
4
|
+
export async function runWorkspaceRuntimeServe(configPath) {
|
|
5
|
+
process.env.PLAYCRAFT_SKIP_UPDATE_CHECK = '1';
|
|
6
|
+
let config;
|
|
7
|
+
try {
|
|
8
|
+
config = parseSandboxRuntimeConfig(JSON.parse(await readFile(configPath, 'utf8')));
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
console.error(`workspace-runtime config invalid: ${message}`);
|
|
13
|
+
process.exitCode = INCOMPATIBLE_EXIT_CODE;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const runtime = await startWorkspaceRuntime(config);
|
|
18
|
+
console.log(JSON.stringify({
|
|
19
|
+
status: 'listening',
|
|
20
|
+
url: runtime.url,
|
|
21
|
+
phase: 'awaiting_native',
|
|
22
|
+
protocolMajor: runtime.config.protocolMajor,
|
|
23
|
+
protocolMinor: runtime.config.protocolMinor,
|
|
24
|
+
}));
|
|
25
|
+
await new Promise((resolve) => {
|
|
26
|
+
const stop = () => {
|
|
27
|
+
void runtime.close().finally(resolve);
|
|
28
|
+
};
|
|
29
|
+
process.once('SIGINT', stop);
|
|
30
|
+
process.once('SIGTERM', stop);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const code = error.code;
|
|
35
|
+
if (code === 'protocol_incompatible' || code === 'duplicate_instance') {
|
|
36
|
+
console.error(error instanceof Error ? error.message : code);
|
|
37
|
+
process.exitCode = INCOMPATIBLE_EXIT_CODE;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function registerWorkspaceRuntimeCommands(program) {
|
|
44
|
+
const workspaceRuntime = program
|
|
45
|
+
.command('workspace-runtime')
|
|
46
|
+
.description('沙箱内 Sandbox Agent Server(Cloud Workspace 常驻运行入口)');
|
|
47
|
+
workspaceRuntime
|
|
48
|
+
.command('serve')
|
|
49
|
+
.description('前台常驻:读取 Runtime Server 下发的配置,不启动本地 backend 或旧同步')
|
|
50
|
+
.requiredOption('--config <path>', 'Runtime 引导配置 JSON')
|
|
51
|
+
.action(async (options) => {
|
|
52
|
+
await runWorkspaceRuntimeServe(options.config);
|
|
53
|
+
});
|
|
54
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import { registerLevelsCommands } from './commands/levels.js';
|
|
|
27
27
|
import { registerPatternsCommands } from './commands/patterns.js';
|
|
28
28
|
import { registerPradCommands } from './commands/prad.js';
|
|
29
29
|
import { register3DCommands } from './commands/3d.js';
|
|
30
|
+
import { registerWorkspaceRuntimeCommands } from './commands/workspace-runtime.js';
|
|
30
31
|
import { CLI_ROOT_DESCRIPTION, getCliTopicsHelpText, registerRootProgramHelp, } from './cli-root-help.js';
|
|
31
32
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
33
|
const __dirname = dirname(__filename);
|
|
@@ -36,7 +37,7 @@ program.name('playcraft').description(CLI_ROOT_DESCRIPTION).version(packageJson.
|
|
|
36
37
|
registerRootProgramHelp(program);
|
|
37
38
|
// 版本检查(非阻塞,后台执行)
|
|
38
39
|
// 只在非 upgrade 命令时检查,避免重复提示
|
|
39
|
-
if (!process.argv.includes('upgrade')) {
|
|
40
|
+
if (!process.argv.includes('upgrade') && !process.argv.includes('workspace-runtime')) {
|
|
40
41
|
checkForUpdates(packageJson);
|
|
41
42
|
}
|
|
42
43
|
// create 命令
|
|
@@ -368,4 +369,5 @@ registerPatternsCommands(program);
|
|
|
368
369
|
registerPradCommands(program);
|
|
369
370
|
// 3D model utilities (playcraft 3d <command>)
|
|
370
371
|
register3DCommands(program);
|
|
372
|
+
registerWorkspaceRuntimeCommands(program);
|
|
371
373
|
program.parse(process.argv);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { verifyLocalProjectSkills } from './validation.js';
|
|
2
|
+
export { verifyLocalProjectSkills } from './validation.js';
|
|
3
|
+
import { downloadLocalProjectSkillArtifacts } from './remote-cache.js';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { inspectProjectSkills, } from '@playcraft/common/project-skills';
|
|
6
|
+
import { syncLocalProjectSkills, enableLocalProjectSkill, installFrozenProjectSkills, explainLocalProjectSkills } from './local-store.js';
|
|
7
|
+
import { runLocalProjectSkills, localProjectSkillUsage } from './local-run.js';
|
|
8
|
+
import { projectSkillsMessage as t } from './messages.js';
|
|
9
|
+
import { reconcileLocalProjectSkills } from './reconcile.js';
|
|
10
|
+
export async function inspectLocalProjectSkills(directory) {
|
|
11
|
+
const inventory = await inspectProjectSkills(directory);
|
|
12
|
+
// Report metadata only; never print complete skill bytes or project test data.
|
|
13
|
+
return { declaration: inventory.declaration, discovered: inventory.discovered, issues: inventory.issues,
|
|
14
|
+
sources: inventory.sources.map((source) => ({ entryKey: source.entryKey, root: source.root,
|
|
15
|
+
sourceTreeHash: source.sourceTreeHash, files: source.files.map((file) => file.path) })) };
|
|
16
|
+
}
|
|
17
|
+
export function registerProjectSkillsCommands(skills) {
|
|
18
|
+
const project = skills.command('project').description(t('description'));
|
|
19
|
+
const output = async (action) => {
|
|
20
|
+
try {
|
|
21
|
+
process.stdout.write(`${JSON.stringify(await action(), null, 2)}\n`);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
process.stderr.write(`${t('failed')}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
project.command('run <prompt>').description(t('run')).requiredOption('--model <provider/model>', t('model'))
|
|
29
|
+
.option('--dir <path>', t('directory'), '.').action((prompt, options) => output(async () => {
|
|
30
|
+
const result = await runLocalProjectSkills(resolve(options.dir), { prompt, model: options.model });
|
|
31
|
+
if (result.exitCode !== 0)
|
|
32
|
+
process.exitCode = result.exitCode;
|
|
33
|
+
return result;
|
|
34
|
+
}));
|
|
35
|
+
project.command('usage').description(t('usage')).option('--dir <path>', t('directory'), '.')
|
|
36
|
+
.action((options) => output(() => localProjectSkillUsage(resolve(options.dir))));
|
|
37
|
+
project.command('sync').description(t('sync')).option('--dir <path>', t('directory'), '.')
|
|
38
|
+
.action((options) => output(() => syncLocalProjectSkills(resolve(options.dir))));
|
|
39
|
+
project.command('reconcile').description(t('reconcile')).option('--dir <path>', t('directory'), '.')
|
|
40
|
+
.action((options) => output(() => reconcileLocalProjectSkills(resolve(options.dir), { write: true })));
|
|
41
|
+
project.command('install').description(t('install')).requiredOption('--frozen', t('frozen')).option('--dir <path>', t('directory'), '.')
|
|
42
|
+
.option('--online', t('online')).action((options) => output(async () => {
|
|
43
|
+
const directory = resolve(options.dir);
|
|
44
|
+
if (options.online)
|
|
45
|
+
await downloadLocalProjectSkillArtifacts(directory);
|
|
46
|
+
return installFrozenProjectSkills(directory);
|
|
47
|
+
}));
|
|
48
|
+
for (const enabled of [true, false])
|
|
49
|
+
project.command(enabled ? 'enable <entryKey>' : 'disable <entryKey>')
|
|
50
|
+
.description(t(enabled ? 'enable' : 'disable')).option('--dir <path>', t('directory'), '.')
|
|
51
|
+
.action((entryKey, options) => output(() => enableLocalProjectSkill(resolve(options.dir), entryKey, enabled)));
|
|
52
|
+
project.command('explain').description(t('explain')).option('--dir <path>', t('directory'), '.')
|
|
53
|
+
.action((options) => output(() => explainLocalProjectSkills(resolve(options.dir))));
|
|
54
|
+
project.command('inspect').description(t('inspect')).option('--dir <path>', t('directory'), '.')
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
const result = await inspectLocalProjectSkills(resolve(options.dir));
|
|
57
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
58
|
+
if (result.issues.length)
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
});
|
|
61
|
+
project.command('verify').description(t('verify')).option('--dir <path>', t('directory'), '.')
|
|
62
|
+
.option('--json', t('json')).action(async (options) => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await verifyLocalProjectSkills(resolve(options.dir));
|
|
65
|
+
process.stdout.write(`${options.json ? JSON.stringify(result) : t('verified')}\n`);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
process.stderr.write(`${t('failed')}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { readProjectSkillsLockFile } from '@playcraft/common/project-skills';
|
|
3
|
+
import { syncLocalProjectSkills, readLocalProjectSkillSnapshot, installFrozenProjectSkills } from './local-store.js';
|
|
4
|
+
import { verifyLocalProjectSkills } from './validation.js';
|
|
5
|
+
import { projectSkillsMessage as t } from './messages.js';
|
|
6
|
+
/** Existing formats keep their legacy consumer; format 3 never silently downgrades. */
|
|
7
|
+
export async function prepareLocalSkillLifecycle(directory, action, cache) {
|
|
8
|
+
const raw = await readProjectSkillsLockFile(directory);
|
|
9
|
+
const managed = raw !== null && JSON.parse(raw).lockVersion === 3;
|
|
10
|
+
if (!managed && process.env.PROJECT_SKILLS_ADOPTION_ENABLED !== 'true')
|
|
11
|
+
return { managed: false };
|
|
12
|
+
if (raw !== null && !managed)
|
|
13
|
+
return { managed: false, legacy: true };
|
|
14
|
+
if (action === 'create' || action === 'push' || !managed)
|
|
15
|
+
await syncLocalProjectSkills(directory, cache);
|
|
16
|
+
await verifyLocalProjectSkills(directory);
|
|
17
|
+
const snapshot = await readLocalProjectSkillSnapshot(directory);
|
|
18
|
+
if (action === 'push') {
|
|
19
|
+
const paths = ['.playcraft/skills.json', '.playcraft/skills.lock.json', ...snapshot.declaration.entries.flatMap(entry => entry.source.kind === 'repository' ? [entry.source.root, ...(entry.projectFiles ?? [])] : [])];
|
|
20
|
+
const status = spawnSync('git', ['status', '--porcelain', '--', ...paths], { cwd: directory, encoding: 'utf8' });
|
|
21
|
+
if (status.status !== 0 || status.stdout.trim())
|
|
22
|
+
throw new Error(t('commitRequired'));
|
|
23
|
+
}
|
|
24
|
+
// Source-only checkouts work offline. Registry packages remain exact and require an authorized cache fill.
|
|
25
|
+
if (!snapshot.lock.entries.some(entry => entry.revision.kind === 'release'))
|
|
26
|
+
await installFrozenProjectSkills(directory, cache);
|
|
27
|
+
return { managed: true, declarationHash: snapshot.lock.declarationHash };
|
|
28
|
+
}
|