summer-engine 2.8.2 → 3.1.0
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/.claude-plugin/marketplace.json +27 -7
- package/.claude-plugin/plugin.json +99 -83
- package/.codex-plugin/plugin.json +112 -82
- package/.cursor-plugin/plugin.json +119 -83
- package/.factory-plugin/plugin.json +100 -3
- package/.mcp.json +6 -1
- package/.opencode/INSTALL.md +7 -4
- package/.opencode/plugins/summer.js +31 -18
- package/AGENTS.md +107 -34
- package/CHANGELOG.md +149 -44
- package/CLAUDE.md +4 -2
- package/GEMINI.md +7 -53
- package/NOTICE +31 -0
- package/README.md +161 -393
- package/assets/api-docs.json.gz +0 -0
- package/assets/autopilot/README.md +20 -6
- package/assets/autopilot/autopilot.gd +80 -26
- package/assets/autopilot/run.sh +132 -7
- package/assets/navigation/web-routes.json +719 -0
- package/commands/gameskill.md +10 -108
- package/commands/summer.md +72 -4
- package/dist/bin/summer.js +6 -87
- package/dist/cli/banner.d.ts +1 -0
- package/dist/cli/banner.js +33 -0
- package/dist/{commands → cli/commands}/config.js +1 -1
- package/dist/cli/commands/create.d.ts +30 -0
- package/dist/cli/commands/create.js +212 -0
- package/dist/{commands → cli/commands}/debug.js +2 -2
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.js +18 -0
- package/dist/cli/commands/events.d.ts +57 -0
- package/dist/cli/commands/events.js +158 -0
- package/dist/cli/commands/install.d.ts +50 -0
- package/dist/cli/commands/install.js +447 -0
- package/dist/cli/commands/list.js +72 -0
- package/dist/{commands → cli/commands}/login.js +33 -17
- package/dist/{commands → cli/commands}/logout.d.ts +1 -0
- package/dist/cli/commands/logout.js +19 -0
- package/dist/{commands → cli/commands}/memory.d.ts +1 -8
- package/dist/{commands → cli/commands}/memory.js +20 -11
- package/dist/cli/commands/open.d.ts +45 -0
- package/dist/cli/commands/open.js +216 -0
- package/dist/{commands → cli/commands}/plan.js +2 -2
- package/dist/{commands → cli/commands}/publish.js +1 -1
- package/dist/{commands → cli/commands}/releases.js +1 -1
- package/dist/cli/commands/run.d.ts +19 -0
- package/dist/cli/commands/run.js +255 -0
- package/dist/cli/commands/setup.js +158 -0
- package/dist/{commands → cli/commands}/skills.js +121 -251
- package/dist/{commands → cli/commands}/status.d.ts +1 -0
- package/dist/cli/commands/status.js +62 -0
- package/dist/cli/commands/tool.d.ts +11 -0
- package/dist/cli/commands/tool.js +121 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +89 -0
- package/dist/cli/root-action.d.ts +7 -0
- package/dist/cli/root-action.js +15 -0
- package/dist/{lib → core}/api-client.d.ts +106 -15
- package/dist/{lib → core}/api-client.js +267 -75
- package/dist/{lib → core}/async-op-lifecycle.d.ts +3 -4
- package/dist/{lib → core}/async-op-lifecycle.js +3 -4
- package/dist/{lib → core}/auth.d.ts +14 -6
- package/dist/{lib → core}/auth.js +56 -40
- package/dist/core/capabilities/agent-playbook.d.ts +20 -0
- package/dist/core/capabilities/agent-playbook.js +218 -0
- package/dist/core/capabilities/api-docs.d.ts +36 -0
- package/dist/core/capabilities/api-docs.js +118 -0
- package/dist/core/capabilities/asset-import.d.ts +49 -0
- package/dist/core/capabilities/asset-import.js +134 -0
- package/dist/core/capabilities/camera-view.d.ts +98 -0
- package/dist/core/capabilities/camera-view.js +222 -0
- package/dist/core/capabilities/capture.d.ts +63 -0
- package/dist/core/capabilities/capture.js +67 -0
- package/dist/core/capabilities/console-read.d.ts +17 -0
- package/dist/core/capabilities/console-read.js +21 -0
- package/dist/{lib → core/capabilities}/creator.d.ts +1 -29
- package/dist/{lib → core/capabilities}/creator.js +14 -33
- package/dist/{lib → core/capabilities}/debug-report.d.ts +1 -1
- package/dist/{lib → core/capabilities}/debug-report.js +12 -31
- package/dist/{commands → core/capabilities}/doctor.d.ts +7 -2
- package/dist/{commands → core/capabilities}/doctor.js +47 -73
- package/dist/core/capabilities/engine-fallbacks.d.ts +26 -0
- package/dist/core/capabilities/engine-fallbacks.js +36 -0
- package/dist/core/capabilities/engine-ops.d.ts +33 -0
- package/dist/core/capabilities/engine-ops.js +145 -0
- package/dist/core/capabilities/engine-receipt.d.ts +53 -0
- package/dist/core/capabilities/engine-receipt.js +134 -0
- package/dist/core/capabilities/events.d.ts +200 -0
- package/dist/core/capabilities/events.js +383 -0
- package/dist/core/capabilities/fabricate-mesh.d.ts +111 -0
- package/dist/core/capabilities/fabricate-mesh.js +165 -0
- package/dist/core/capabilities/frame-quality.d.ts +71 -0
- package/dist/core/capabilities/frame-quality.js +449 -0
- package/dist/core/capabilities/game-task-plan.d.ts +66 -0
- package/dist/{lib → core/capabilities}/game-task-plan.js +59 -8
- package/dist/core/capabilities/hdri-import.d.ts +90 -0
- package/dist/core/capabilities/hdri-import.js +250 -0
- package/dist/core/capabilities/image-generation.d.ts +24 -0
- package/dist/core/capabilities/image-generation.js +22 -0
- package/dist/core/capabilities/navigation/open.d.ts +156 -0
- package/dist/core/capabilities/navigation/open.js +567 -0
- package/dist/core/capabilities/navigation/render-product-map.d.ts +1 -0
- package/dist/core/capabilities/navigation/render-product-map.js +84 -0
- package/dist/core/capabilities/navigation/targets.d.ts +87 -0
- package/dist/core/capabilities/navigation/targets.js +250 -0
- package/dist/core/capabilities/play-determinism.d.ts +35 -0
- package/dist/core/capabilities/play-determinism.js +86 -0
- package/dist/core/capabilities/project-context.d.ts +114 -0
- package/dist/core/capabilities/project-context.js +249 -0
- package/dist/core/capabilities/runtime-control.d.ts +540 -0
- package/dist/core/capabilities/runtime-control.js +1011 -0
- package/dist/core/capabilities/scene-kind.d.ts +19 -0
- package/dist/core/capabilities/scene-kind.js +137 -0
- package/dist/core/capabilities/scene-script.d.ts +38 -0
- package/dist/core/capabilities/scene-script.js +45 -0
- package/dist/core/capabilities/tool-dispatch.d.ts +42 -0
- package/dist/core/capabilities/tool-dispatch.js +1490 -0
- package/dist/core/capabilities/ui-control.d.ts +179 -0
- package/dist/core/capabilities/ui-control.js +423 -0
- package/dist/core/capabilities/variant-types.d.ts +22 -0
- package/dist/core/capabilities/variant-types.js +101 -0
- package/dist/core/capability-skew.d.ts +205 -0
- package/dist/core/capability-skew.js +386 -0
- package/dist/{lib → core}/config.d.ts +11 -1
- package/dist/{lib → core}/config.js +13 -2
- package/dist/core/embeddings.d.ts +78 -0
- package/dist/core/embeddings.js +166 -0
- package/dist/core/engine-install.d.ts +105 -0
- package/dist/core/engine-install.js +190 -0
- package/dist/core/engine.d.ts +94 -0
- package/dist/{lib → core}/engine.js +74 -28
- package/dist/core/feedback/client.d.ts +88 -0
- package/dist/core/feedback/client.js +182 -0
- package/dist/{lib → core}/format.d.ts +0 -1
- package/dist/{lib → core}/format.js +1 -1
- package/dist/core/headless/connection.d.ts +86 -0
- package/dist/core/headless/connection.js +97 -0
- package/dist/core/headless/editor-connection.d.ts +26 -0
- package/dist/core/headless/editor-connection.js +81 -0
- package/dist/core/headless/mcp-routing.d.ts +38 -0
- package/dist/core/headless/mcp-routing.js +83 -0
- package/dist/core/headless/registry.d.ts +91 -0
- package/dist/core/headless/registry.js +226 -0
- package/dist/core/headless/resolve.d.ts +46 -0
- package/dist/core/headless/resolve.js +75 -0
- package/dist/core/headless/spawn.d.ts +46 -0
- package/dist/core/headless/spawn.js +205 -0
- package/dist/core/headless/worker-connection.d.ts +96 -0
- package/dist/core/headless/worker-connection.js +353 -0
- package/dist/core/headless/worker-engine-client.d.ts +58 -0
- package/dist/core/headless/worker-engine-client.js +246 -0
- package/dist/core/launch-posture.d.ts +170 -0
- package/dist/core/launch-posture.js +317 -0
- package/dist/core/library-read.d.ts +73 -0
- package/dist/core/library-read.js +279 -0
- package/dist/core/library-search.d.ts +143 -0
- package/dist/core/library-search.js +301 -0
- package/dist/{lib → core}/log-filters.js +4 -2
- package/dist/{lib → core}/mcp-log.js +2 -17
- package/dist/core/package-root.d.ts +9 -0
- package/dist/core/package-root.js +11 -0
- package/dist/core/redact.d.ts +20 -0
- package/dist/core/redact.js +64 -0
- package/dist/core/registry-search.d.ts +167 -0
- package/dist/core/registry-search.js +358 -0
- package/dist/core/skills-registry.d.ts +55 -0
- package/dist/core/skills-registry.js +106 -0
- package/dist/{lib → core}/store.js +11 -7
- package/dist/{lib → core}/summer-compatibility.js +3 -3
- package/dist/{lib → core}/telemetry.js +5 -2
- package/dist/core/templates.d.ts +98 -0
- package/dist/core/templates.js +241 -0
- package/dist/core/tool-errors.d.ts +30 -0
- package/dist/core/tool-errors.js +40 -0
- package/dist/core/trajectory.d.ts +80 -0
- package/dist/core/trajectory.js +307 -0
- package/dist/core/util/http.d.ts +13 -0
- package/dist/core/util/http.js +28 -0
- package/dist/core/util/json.d.ts +12 -0
- package/dist/core/util/json.js +21 -0
- package/dist/core/util/process.d.ts +3 -0
- package/dist/core/util/process.js +13 -0
- package/dist/core/util/sleep.d.ts +1 -0
- package/dist/core/util/sleep.js +3 -0
- package/dist/core/version.d.ts +3 -0
- package/dist/core/version.js +5 -0
- package/dist/installer/agent-config.d.ts +63 -0
- package/dist/installer/agent-config.js +540 -0
- package/dist/installer/agent-table.d.ts +103 -0
- package/dist/installer/agent-table.js +584 -0
- package/dist/installer/legacy-skills.d.ts +26 -0
- package/dist/installer/legacy-skills.js +53 -0
- package/dist/installer/setup.d.ts +76 -0
- package/dist/installer/setup.js +148 -0
- package/dist/installer/skill-locations.d.ts +36 -0
- package/dist/installer/skill-locations.js +91 -0
- package/dist/installer/version-check.d.ts +178 -0
- package/dist/installer/version-check.js +479 -0
- package/dist/{lib/mcp-boot-notice.d.ts → mcp/boot-notice.d.ts} +1 -1
- package/dist/{commands/mcp.js → mcp/command.js} +18 -6
- package/dist/mcp/server.d.ts +23 -3
- package/dist/mcp/server.js +122 -28
- package/dist/mcp/tools/asset-tools.js +62 -142
- package/dist/mcp/tools/creator-tools.js +5 -23
- package/dist/mcp/tools/debug-tools.js +61 -18
- package/dist/mcp/tools/event-tools.d.ts +14 -0
- package/dist/mcp/tools/event-tools.js +41 -0
- package/dist/mcp/tools/fabricate-tools.d.ts +2 -0
- package/dist/mcp/tools/fabricate-tools.js +28 -0
- package/dist/mcp/tools/feedback-tools.d.ts +77 -0
- package/dist/mcp/tools/feedback-tools.js +88 -0
- package/dist/mcp/tools/file-tools.js +6 -53
- package/dist/mcp/tools/generate-tools.js +37 -63
- package/dist/mcp/tools/library-tools.d.ts +11 -0
- package/dist/mcp/tools/library-tools.js +42 -0
- package/dist/mcp/tools/navigation-tools.d.ts +7 -0
- package/dist/mcp/tools/navigation-tools.js +37 -0
- package/dist/mcp/tools/perception-tools.d.ts +20 -0
- package/dist/mcp/tools/perception-tools.js +146 -0
- package/dist/mcp/tools/project-tools.d.ts +14 -0
- package/dist/mcp/tools/project-tools.js +72 -281
- package/dist/mcp/tools/runtime-tools.d.ts +2 -0
- package/dist/mcp/tools/runtime-tools.js +92 -0
- package/dist/mcp/tools/scene-tools.d.ts +3 -0
- package/dist/mcp/tools/scene-tools.js +68 -119
- package/dist/mcp/tools/script-tools.d.ts +3 -0
- package/dist/mcp/tools/script-tools.js +118 -0
- package/dist/mcp/tools/spatial-tools.d.ts +2 -0
- package/dist/mcp/tools/spatial-tools.js +485 -0
- package/dist/mcp/tools/text-json.d.ts +8 -0
- package/dist/mcp/tools/text-json.js +12 -0
- package/dist/mcp/tools/{cloud-tools.d.ts → ui-tools.d.ts} +1 -1
- package/dist/mcp/tools/ui-tools.js +82 -0
- package/dist/mcp/tools/visual-tools.d.ts +2 -7
- package/dist/mcp/tools/visual-tools.js +383 -101
- package/dist/mcp/tools/with-engine.d.ts +9 -15
- package/dist/mcp/tools/with-engine.js +60 -96
- package/dist/project-memory/project-manifest.d.ts +36 -0
- package/dist/project-memory/project-manifest.js +50 -0
- package/dist/project-memory/project-memory.d.ts +57 -0
- package/dist/{lib → project-memory}/project-memory.js +46 -0
- package/gemini-extension.json +103 -2
- package/hooks/hooks-cursor.json +2 -2
- package/hooks/hooks.json +2 -1
- package/hooks/pre-commit-doctor.sh +45 -39
- package/hooks/run-hook.cmd +30 -23
- package/hooks/run-hook.sh +20 -0
- package/hooks/session-start.sh +18 -7
- package/integrations/README.md +99 -0
- package/integrations/amp/README.md +12 -0
- package/integrations/amp/manifest-target.json +3 -0
- package/integrations/antigravity/README.md +12 -0
- package/integrations/antigravity/manifest-target.json +3 -0
- package/integrations/claude/README.md +19 -0
- package/integrations/claude/manifest-target.json +16 -0
- package/integrations/claude-desktop/README.md +12 -0
- package/integrations/claude-desktop/manifest-target.json +3 -0
- package/integrations/cline/README.md +12 -0
- package/integrations/cline/manifest-target.json +3 -0
- package/integrations/cline-cli/README.md +12 -0
- package/integrations/cline-cli/manifest-target.json +3 -0
- package/integrations/codex/README.md +15 -0
- package/integrations/codex/manifest-target.json +5 -0
- package/integrations/copilot-jetbrains/README.md +12 -0
- package/integrations/copilot-jetbrains/manifest-target.json +3 -0
- package/integrations/crush/README.md +12 -0
- package/integrations/crush/manifest-target.json +3 -0
- package/integrations/cursor/README.md +16 -0
- package/integrations/cursor/manifest-target.json +5 -0
- package/integrations/factory/README.md +26 -0
- package/integrations/factory/manifest-target.json +5 -0
- package/integrations/gemini/README.md +26 -0
- package/integrations/gemini/manifest-target.json +5 -0
- package/integrations/github-copilot/README.md +12 -0
- package/integrations/github-copilot/manifest-target.json +3 -0
- package/integrations/goose/README.md +12 -0
- package/integrations/goose/manifest-target.json +3 -0
- package/integrations/grok-build/README.md +12 -0
- package/integrations/grok-build/manifest-target.json +3 -0
- package/integrations/hermes/README.md +12 -0
- package/integrations/hermes/manifest-target.json +3 -0
- package/integrations/junie/README.md +12 -0
- package/integrations/junie/manifest-target.json +3 -0
- package/integrations/kilo-code/README.md +12 -0
- package/integrations/kilo-code/manifest-target.json +3 -0
- package/integrations/kimi-code/README.md +12 -0
- package/integrations/kimi-code/manifest-target.json +3 -0
- package/integrations/kiro/README.md +12 -0
- package/integrations/kiro/manifest-target.json +3 -0
- package/integrations/lm-studio/README.md +12 -0
- package/integrations/lm-studio/manifest-target.json +3 -0
- package/integrations/mistral-vibe/README.md +12 -0
- package/integrations/mistral-vibe/manifest-target.json +3 -0
- package/integrations/opencode/README.md +12 -0
- package/integrations/opencode/manifest-target.json +3 -0
- package/integrations/qoder/README.md +12 -0
- package/integrations/qoder/manifest-target.json +3 -0
- package/integrations/qwen-code/README.md +12 -0
- package/integrations/qwen-code/manifest-target.json +3 -0
- package/integrations/roo-code/README.md +14 -0
- package/integrations/roo-code/manifest-target.json +3 -0
- package/integrations/rovo-dev/README.md +12 -0
- package/integrations/rovo-dev/manifest-target.json +3 -0
- package/integrations/trae/README.md +12 -0
- package/integrations/trae/manifest-target.json +3 -0
- package/integrations/visual-studio/README.md +12 -0
- package/integrations/visual-studio/manifest-target.json +3 -0
- package/integrations/vscode-copilot/README.md +12 -0
- package/integrations/vscode-copilot/manifest-target.json +3 -0
- package/integrations/warp/README.md +12 -0
- package/integrations/warp/manifest-target.json +3 -0
- package/integrations/windsurf/README.md +12 -0
- package/integrations/windsurf/manifest-target.json +3 -0
- package/integrations/zed/README.md +12 -0
- package/integrations/zed/manifest-target.json +3 -0
- package/library/references/collaborative-protocol/resource.yaml +24 -0
- package/library/references/gd-style/resource.yaml +24 -0
- package/{references → library/references/godot-version}/godot-version.md +6 -6
- package/library/references/godot-version/resource.yaml +22 -0
- package/library/references/headless-routing/headless-routing.md +46 -0
- package/library/references/headless-routing/resource.yaml +24 -0
- package/library/references/mcp-fresh-chat-playbook/mcp-fresh-chat-playbook.md +49 -0
- package/library/references/mcp-fresh-chat-playbook/resource.yaml +23 -0
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +271 -0
- package/library/references/mcp-tools-reference/resource.yaml +17 -0
- package/library/references/product-map/product-map.md +103 -0
- package/library/references/product-map/resource.yaml +33 -0
- package/{references → library/references/public-surface-language}/public-surface-language.md +5 -7
- package/library/references/public-surface-language/resource.yaml +17 -0
- package/library/references/summer-folder/resource.yaml +20 -0
- package/{references → library/references/summer-folder}/summer-folder.md +22 -21
- package/{skills/rendering-and-lighting → library/skills}/3d-lighting/SKILL.md +15 -11
- package/library/skills/3d-lighting/resource.yaml +27 -0
- package/library/skills/README.md +242 -0
- package/{skills/audio → library/skills}/adaptive-music/SKILL.md +1 -1
- package/library/skills/adaptive-music/resource.yaml +28 -0
- package/library/skills/agent-playtesting/SKILL.md +148 -0
- package/library/skills/agent-playtesting/resource.yaml +52 -0
- package/library/skills/ambient-bed/resource.yaml +24 -0
- package/{skills/video → library/skills}/animated-loop/SKILL.md +1 -1
- package/library/skills/animated-loop/resource.yaml +27 -0
- package/{skills/animation → library/skills}/animation-tree/SKILL.md +29 -14
- package/library/skills/animation-tree/resource.yaml +33 -0
- package/{skills/rendering-and-lighting → library/skills}/art-direction/SKILL.md +3 -3
- package/library/skills/art-direction/resource.yaml +29 -0
- package/{skills/asset-pipeline → library/skills}/asset-strategy/SKILL.md +44 -44
- package/library/skills/asset-strategy/resource.yaml +63 -0
- package/{skills/audio → library/skills}/audio-direction/SKILL.md +7 -7
- package/library/skills/audio-direction/resource.yaml +32 -0
- package/library/skills/auto-fire-targeting/resource.yaml +22 -0
- package/{skills/scene-and-project → library/skills}/brainstorm-game/SKILL.md +8 -8
- package/library/skills/brainstorm-game/resource.yaml +30 -0
- package/{skills/workflow → library/skills}/brainstorming/SKILL.md +2 -22
- package/library/skills/brainstorming/resource.yaml +23 -0
- package/{skills/workflow → library/skills}/brainstorming/spec-document-reviewer-prompt.md +1 -1
- package/{skills/scene-and-project → library/skills}/browse-templates/SKILL.md +18 -18
- package/library/skills/browse-templates/resource.yaml +23 -0
- package/library/skills/celeste-momentum-platforming/SKILL.md +366 -0
- package/library/skills/celeste-momentum-platforming/resource.yaml +33 -0
- package/library/skills/character-animation-wiring/SKILL.md +249 -0
- package/library/skills/character-animation-wiring/resource.yaml +39 -0
- package/{skills/3d-assets → library/skills}/character-model/SKILL.md +25 -25
- package/library/skills/character-model/resource.yaml +36 -0
- package/{skills/2d-assets → library/skills}/character-portrait/SKILL.md +14 -14
- package/library/skills/character-portrait/resource.yaml +30 -0
- package/{skills/video → library/skills}/cinematic-cutscene/SKILL.md +2 -2
- package/library/skills/cinematic-cutscene/resource.yaml +29 -0
- package/{skills/2d-assets → library/skills}/concept-art/SKILL.md +15 -15
- package/library/skills/concept-art/resource.yaml +34 -0
- package/{skills/2d-assets → library/skills}/create-asset-sheet/SKILL.md +8 -8
- package/library/skills/create-asset-sheet/resource.yaml +33 -0
- package/{skills/debugging → library/skills}/debug/SKILL.md +3 -3
- package/library/skills/debug/resource.yaml +31 -0
- package/{skills/workflow → library/skills}/debugging-game-feel/SKILL.md +11 -11
- package/library/skills/debugging-game-feel/resource.yaml +25 -0
- package/{skills/level-design → library/skills}/design-level/SKILL.md +6 -6
- package/library/skills/design-level/resource.yaml +31 -0
- package/{skills/gameplay-mechanics → library/skills}/design-mechanic/SKILL.md +3 -3
- package/library/skills/design-mechanic/resource.yaml +31 -0
- package/{skills/ai-and-npcs → library/skills}/design-npc/SKILL.md +7 -3
- package/library/skills/design-npc/resource.yaml +29 -0
- package/{skills/workflow → library/skills}/diagnosing-perf-regressions/SKILL.md +10 -10
- package/library/skills/diagnosing-perf-regressions/resource.yaml +25 -0
- package/{skills/workflow → library/skills}/dispatching-parallel-agents/SKILL.md +8 -8
- package/library/skills/dispatching-parallel-agents/resource.yaml +23 -0
- package/library/skills/driving-the-editor-ui/SKILL.md +85 -0
- package/library/skills/driving-the-editor-ui/resource.yaml +46 -0
- package/{skills/3d-assets → library/skills}/environment-kit/SKILL.md +11 -11
- package/library/skills/environment-kit/resource.yaml +29 -0
- package/{skills/deployment → library/skills}/export-and-ship/SKILL.md +5 -5
- package/library/skills/export-and-ship/resource.yaml +32 -0
- package/library/skills/fabricating-assets/SKILL.md +195 -0
- package/library/skills/fabricating-assets/resource.yaml +52 -0
- package/{skills/animation → library/skills}/facial-and-lipsync/SKILL.md +23 -11
- package/library/skills/facial-and-lipsync/resource.yaml +36 -0
- package/{skills/character-controllers → library/skills}/fps-controller/SKILL.md +8 -4
- package/library/skills/fps-controller/resource.yaml +29 -0
- package/{skills/visual-effects → library/skills}/game-feel/SKILL.md +7 -7
- package/library/skills/game-feel/resource.yaml +27 -0
- package/library/skills/gameskill/SKILL.md +64 -0
- package/library/skills/gameskill/resource.yaml +22 -0
- package/library/skills/gdscript-patterns/resource.yaml +23 -0
- package/{skills/animation → library/skills}/generate-motion/SKILL.md +16 -16
- package/library/skills/generate-motion/resource.yaml +34 -0
- package/library/skills/godogen-visual-proof-game-generation/SKILL.md +223 -0
- package/library/skills/godogen-visual-proof-game-generation/resource.yaml +33 -0
- package/{skills/workflow → library/skills}/headless-scripting/SKILL.md +14 -7
- package/library/skills/headless-scripting/resource.yaml +26 -0
- package/library/skills/host-authoritative-state/resource.yaml +28 -0
- package/{skills/2d-assets → library/skills}/instantiate-asset-pack/SKILL.md +10 -12
- package/library/skills/instantiate-asset-pack/resource.yaml +29 -0
- package/{skills/workflow → library/skills}/investigating-bugs/SKILL.md +4 -4
- package/{skills/workflow → library/skills}/investigating-bugs/condition-based-waiting.md +8 -8
- package/library/skills/investigating-bugs/resource.yaml +24 -0
- package/{skills/workflow → library/skills}/investigating-bugs/root-cause-tracing.md +1 -7
- package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +164 -0
- package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +35 -0
- package/{skills/scene-and-project → library/skills}/make-game/SKILL.md +22 -22
- package/library/skills/make-game/resource.yaml +35 -0
- package/library/skills/music-track/resource.yaml +28 -0
- package/library/skills/navigate-summer/SKILL.md +61 -0
- package/library/skills/navigate-summer/resource.yaml +35 -0
- package/{skills/scene-and-project → library/skills}/new-project/SKILL.md +10 -10
- package/library/skills/new-project/resource.yaml +28 -0
- package/{skills/3d-assets → library/skills}/organic-model/SKILL.md +16 -16
- package/library/skills/organic-model/resource.yaml +32 -0
- package/{skills/multiplayer-and-networking → library/skills}/peer-to-peer-multiplayer/SKILL.md +2 -2
- package/library/skills/peer-to-peer-multiplayer/resource.yaml +28 -0
- package/{skills/2d-assets → library/skills}/pixel-art/SKILL.md +13 -13
- package/library/skills/pixel-art/resource.yaml +31 -0
- package/library/skills/play/resource.yaml +26 -0
- package/{skills/workflow → library/skills}/playtesting-a-feature/SKILL.md +41 -22
- package/library/skills/playtesting-a-feature/resource.yaml +31 -0
- package/{skills/animation → library/skills}/procedural-animation/SKILL.md +25 -10
- package/library/skills/procedural-animation/resource.yaml +33 -0
- package/{skills/3d-assets → library/skills}/prop-model/SKILL.md +13 -13
- package/library/skills/prop-model/resource.yaml +33 -0
- package/library/skills/psx-retro-rendering/SKILL.md +416 -0
- package/library/skills/psx-retro-rendering/resource.yaml +36 -0
- package/library/skills/realtime-wet-surfaces/SKILL.md +189 -0
- package/library/skills/realtime-wet-surfaces/resource.yaml +31 -0
- package/{skills/deployment → library/skills}/remote-deploy/SKILL.md +3 -3
- package/library/skills/remote-deploy/resource.yaml +23 -0
- package/{skills/animation → library/skills}/retarget/SKILL.md +15 -14
- package/library/skills/retarget/resource.yaml +33 -0
- package/library/skills/running-in-the-cloud/SKILL.md +103 -0
- package/library/skills/running-in-the-cloud/resource.yaml +33 -0
- package/{skills/scene-and-project → library/skills}/scene-composition/SKILL.md +8 -0
- package/library/skills/scene-composition/resource.yaml +27 -0
- package/library/skills/scene-hierarchy-design/SKILL.md +102 -0
- package/library/skills/scene-hierarchy-design/resource.yaml +31 -0
- package/library/skills/scene-scripting/SKILL.md +764 -0
- package/library/skills/scene-scripting/resource.yaml +58 -0
- package/{skills/level-design → library/skills}/scene-to-level/SKILL.md +16 -17
- package/library/skills/scene-to-level/resource.yaml +33 -0
- package/library/skills/setup-multiplayer/resource.yaml +28 -0
- package/library/skills/skill-create/SKILL.md +138 -0
- package/library/skills/skill-create/resource.yaml +25 -0
- package/{skills/workflow → library/skills}/skill-improve/SKILL.md +2 -2
- package/library/skills/skill-improve/resource.yaml +25 -0
- package/{skills/workflow → library/skills}/skill-test/SKILL.md +4 -4
- package/library/skills/skill-test/resource.yaml +26 -0
- package/library/skills/skintokens-auto-rigging/SKILL.md +200 -0
- package/library/skills/skintokens-auto-rigging/resource.yaml +38 -0
- package/{skills/2d-assets → library/skills}/skybox-panorama/SKILL.md +8 -8
- package/library/skills/skybox-panorama/resource.yaml +28 -0
- package/{skills/audio → library/skills}/sound-effect/SKILL.md +2 -2
- package/library/skills/sound-effect/resource.yaml +27 -0
- package/library/skills/spatial-placement/SKILL.md +74 -0
- package/library/skills/spatial-placement/resource.yaml +42 -0
- package/library/skills/spatial-placement/tests/spec.md +65 -0
- package/{skills/2d-assets → library/skills}/sprite-sheet/SKILL.md +12 -12
- package/library/skills/sprite-sheet/resource.yaml +32 -0
- package/{skills/2d-assets → library/skills}/tileable-texture/SKILL.md +9 -9
- package/library/skills/tileable-texture/resource.yaml +31 -0
- package/{skills/video → library/skills}/trailer-shot/SKILL.md +1 -1
- package/library/skills/trailer-shot/resource.yaml +27 -0
- package/{skills/performance → library/skills}/tune-performance/SKILL.md +6 -6
- package/library/skills/tune-performance/resource.yaml +31 -0
- package/library/skills/ui-basics/resource.yaml +25 -0
- package/{skills/2d-assets → library/skills}/ui-graphics/SKILL.md +11 -11
- package/library/skills/ui-graphics/resource.yaml +29 -0
- package/{skills/2d-assets → library/skills}/use-widget-asset/SKILL.md +4 -4
- package/library/skills/use-widget-asset/resource.yaml +29 -0
- package/{skills/workflow → library/skills}/using-summer/SKILL.md +12 -9
- package/library/skills/using-summer/resource.yaml +41 -0
- package/{skills/3d-assets → library/skills}/vehicle-model/SKILL.md +18 -18
- package/library/skills/vehicle-model/resource.yaml +34 -0
- package/{skills/workflow → library/skills}/verification-before-completion/SKILL.md +10 -10
- package/library/skills/verification-before-completion/resource.yaml +23 -0
- package/library/skills/verifying-scenes/SKILL.md +98 -0
- package/library/skills/verifying-scenes/resource.yaml +42 -0
- package/{skills/visual-effects/recipes/dissolve → library/skills/vfx-dissolve}/SKILL.md +31 -11
- package/library/skills/vfx-dissolve/resource.yaml +33 -0
- package/{skills/visual-effects/recipes/fire → library/skills/vfx-fire}/SKILL.md +43 -12
- package/library/skills/vfx-fire/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
- package/library/skills/vfx-fire/resource.yaml +35 -0
- package/{skills/visual-effects/recipes/hit-spark → library/skills/vfx-hit-spark}/SKILL.md +16 -10
- package/library/skills/vfx-hit-spark/_building-blocks/additive-billboard-particles.md +37 -0
- package/library/skills/vfx-hit-spark/resource.yaml +34 -0
- package/{skills/visual-effects/recipes/lightning → library/skills/vfx-lightning}/SKILL.md +24 -11
- package/library/skills/vfx-lightning/_building-blocks/additive-billboard-particles.md +37 -0
- package/library/skills/vfx-lightning/resource.yaml +33 -0
- package/{skills/visual-effects/recipes/magic-glow → library/skills/vfx-magic-glow}/SKILL.md +31 -11
- package/library/skills/vfx-magic-glow/_building-blocks/additive-billboard-particles.md +37 -0
- package/library/skills/vfx-magic-glow/resource.yaml +34 -0
- package/{skills/visual-effects/recipes/muzzle-flash → library/skills/vfx-muzzle-flash}/SKILL.md +29 -9
- package/library/skills/vfx-muzzle-flash/_building-blocks/additive-billboard-particles.md +37 -0
- package/library/skills/vfx-muzzle-flash/_building-blocks/trauma-shake-snippet.md +53 -0
- package/library/skills/vfx-muzzle-flash/resource.yaml +35 -0
- package/{skills/visual-effects/recipes/smoke → library/skills/vfx-smoke}/SKILL.md +35 -9
- package/library/skills/vfx-smoke/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
- package/library/skills/vfx-smoke/resource.yaml +32 -0
- package/{skills/visual-effects/recipes/water-ripple → library/skills/vfx-water-ripple}/SKILL.md +31 -9
- package/library/skills/vfx-water-ripple/_building-blocks/additive-billboard-particles.md +37 -0
- package/library/skills/vfx-water-ripple/resource.yaml +31 -0
- package/library/skills/voice-line/resource.yaml +27 -0
- package/library/skills/world-building-3d/SKILL.md +105 -0
- package/library/skills/world-building-3d/references/spatial-tools.md +50 -0
- package/library/skills/world-building-3d/resource.yaml +44 -0
- package/library/skills/world-building-3d/tests/spec.md +48 -0
- package/{skills/workflow → library/skills}/writing-plans/SKILL.md +19 -14
- package/library/skills/writing-plans/resource.yaml +23 -0
- package/{skills/workflow → library/skills}/writing-skills/SKILL.md +38 -44
- package/library/skills/writing-skills/resource.yaml +29 -0
- package/{skills/workflow → library/skills}/writing-skills/testing-skills-with-subagents.md +13 -14
- package/library/templates/2d-brario-platformer/resource.yaml +21 -0
- package/library/templates/2d-dungeon-roguelike/resource.yaml +23 -0
- package/library/templates/2d-grid-puzzle/resource.yaml +21 -0
- package/library/templates/2d-plants-and-zombies-tower-defense/resource.yaml +21 -0
- package/library/templates/2d-platformer/resource.yaml +24 -0
- package/library/templates/2d-rpg/resource.yaml +21 -0
- package/library/templates/2d-vampire-survivor-roguelike/resource.yaml +21 -0
- package/library/templates/3d-basic/resource.yaml +16 -0
- package/library/templates/3d-city-kit/resource.yaml +24 -0
- package/library/templates/3d-fps-old-school/resource.yaml +21 -0
- package/library/templates/3d-fps-simple-animated-npc/resource.yaml +21 -0
- package/library/templates/3d-lan-multiplayer-starter/resource.yaml +22 -0
- package/library/templates/3d-open-world-explore-tps/resource.yaml +21 -0
- package/library/templates/3d-procedural-road-world/resource.yaml +21 -0
- package/library/templates/3d-racing-game/resource.yaml +21 -0
- package/library/templates/3d-royale-clash-type/resource.yaml +21 -0
- package/library/templates/3d-third-person-controller/resource.yaml +21 -0
- package/library/templates/3d-voxel-sandbox/resource.yaml +24 -0
- package/library/templates/README.md +94 -0
- package/library/templates/empty/resource.yaml +16 -0
- package/library/tools/add-node/resource.yaml +60 -0
- package/library/tools/align-distribute-3d/resource.yaml +87 -0
- package/library/tools/api-docs/resource.yaml +57 -0
- package/library/tools/batch/resource.yaml +52 -0
- package/library/tools/camera-bookmark/resource.yaml +73 -0
- package/library/tools/check-job/resource.yaml +45 -0
- package/library/tools/clear-console/resource.yaml +40 -0
- package/library/tools/connect-signal/resource.yaml +63 -0
- package/library/tools/create-debug-report/resource.yaml +67 -0
- package/library/tools/create-scene/resource.yaml +59 -0
- package/library/tools/creator-config/resource.yaml +63 -0
- package/library/tools/creator-publish/resource.yaml +73 -0
- package/library/tools/creator-releases/resource.yaml +53 -0
- package/library/tools/fabricate-3d/resource.yaml +108 -0
- package/library/tools/game-control/resource.yaml +84 -0
- package/library/tools/game-input/resource.yaml +159 -0
- package/library/tools/game-probe/resource.yaml +90 -0
- package/library/tools/generate-3d/resource.yaml +112 -0
- package/library/tools/generate-audio/resource.yaml +80 -0
- package/library/tools/generate-image/resource.yaml +62 -0
- package/library/tools/generate-motion/resource.yaml +66 -0
- package/library/tools/generate-video/resource.yaml +66 -0
- package/library/tools/get-agent-playbook/resource.yaml +40 -0
- package/library/tools/get-asset/resource.yaml +42 -0
- package/library/tools/get-asset-download-url/resource.yaml +52 -0
- package/library/tools/get-console/resource.yaml +69 -0
- package/library/tools/get-debugger-errors/resource.yaml +56 -0
- package/library/tools/get-debugger-warnings/resource.yaml +52 -0
- package/library/tools/get-diagnostics/resource.yaml +42 -0
- package/library/tools/get-project-context/resource.yaml +45 -0
- package/library/tools/get-runtime-tree/resource.yaml +62 -0
- package/library/tools/get-scene-tree/resource.yaml +52 -0
- package/library/tools/get-script-errors/resource.yaml +45 -0
- package/library/tools/get-studio-workflow/resource.yaml +43 -0
- package/library/tools/import-asset/resource.yaml +73 -0
- package/library/tools/import-asset-by-id/resource.yaml +56 -0
- package/library/tools/import-from-url/resource.yaml +51 -0
- package/library/tools/import-from-url-batch/resource.yaml +60 -0
- package/library/tools/import-hdri/resource.yaml +69 -0
- package/library/tools/input-map-bind/resource.yaml +52 -0
- package/library/tools/inspect-node/resource.yaml +46 -0
- package/library/tools/inspect-resource/resource.yaml +45 -0
- package/library/tools/inspect-runtime-node/resource.yaml +54 -0
- package/library/tools/instantiate-scene/resource.yaml +62 -0
- package/library/tools/is-running/resource.yaml +40 -0
- package/library/tools/library-feedback/resource.yaml +89 -0
- package/library/tools/list-my-assets/resource.yaml +56 -0
- package/library/tools/navigation-probe/resource.yaml +85 -0
- package/library/tools/open/resource.yaml +80 -0
- package/library/tools/open-main-scene/resource.yaml +40 -0
- package/library/tools/open-scene/resource.yaml +46 -0
- package/library/tools/play/resource.yaml +91 -0
- package/library/tools/project-setting/resource.yaml +53 -0
- package/library/tools/read-file/resource.yaml +47 -0
- package/library/tools/read-library/resource.yaml +67 -0
- package/library/tools/recent-events/resource.yaml +71 -0
- package/library/tools/remove-node/resource.yaml +51 -0
- package/library/tools/replace-node/resource.yaml +57 -0
- package/library/tools/replace-text/resource.yaml +61 -0
- package/library/tools/run-editor-script/resource.yaml +61 -0
- package/library/tools/run-script/resource.yaml +73 -0
- package/library/tools/runtime-animate/resource.yaml +140 -0
- package/library/tools/runtime-call/resource.yaml +74 -0
- package/library/tools/runtime-set/resource.yaml +80 -0
- package/library/tools/runtime-spawn/resource.yaml +95 -0
- package/library/tools/save-scene/resource.yaml +50 -0
- package/library/tools/screenshot/resource.yaml +112 -0
- package/library/tools/search-assets/resource.yaml +67 -0
- package/library/tools/search-library/resource.yaml +81 -0
- package/library/tools/select-node/resource.yaml +48 -0
- package/library/tools/set-prop/resource.yaml +64 -0
- package/library/tools/set-resource-property/resource.yaml +66 -0
- package/library/tools/slice-asset-sheet/resource.yaml +47 -0
- package/library/tools/snap-to-surface/resource.yaml +90 -0
- package/library/tools/snapshot-diff/resource.yaml +58 -0
- package/library/tools/starcast/resource.yaml +120 -0
- package/library/tools/start-game-task/resource.yaml +91 -0
- package/library/tools/stop/resource.yaml +51 -0
- package/library/tools/test-placement/resource.yaml +109 -0
- package/library/tools/ui-actions/resource.yaml +77 -0
- package/library/tools/ui-activate/resource.yaml +88 -0
- package/library/tools/ui-screenshot/resource.yaml +63 -0
- package/library/tools/ui-tree/resource.yaml +69 -0
- package/library/tools/wait-for-event/resource.yaml +84 -0
- package/library/tools/world-snapshot/resource.yaml +60 -0
- package/library/tools/write-file/resource.yaml +54 -0
- package/package.json +21 -15
- package/registry/generated/aliases.json +207 -0
- package/registry/generated/counts.json +12 -0
- package/registry/generated/gemini-extension.json +122 -0
- package/registry/generated/index.json +7709 -0
- package/registry/generated/marketplace.claude.json +44 -0
- package/registry/generated/mcp.json +13 -0
- package/registry/generated/plugin.claude.json +135 -0
- package/registry/generated/plugin.codex.json +144 -0
- package/registry/generated/plugin.cursor.json +134 -0
- package/registry/generated/plugin.factory.json +117 -0
- package/registry/generated/skills-index.md +242 -0
- package/registry/generated/skills-registry.json +1249 -0
- package/registry/generated/templates-registry.json +455 -0
- package/registry/schemas/allowed-hosts.json +19 -0
- package/registry/schemas/collection.schema.json +68 -0
- package/registry/schemas/domains.json +96 -0
- package/registry/schemas/example.schema.json +11 -0
- package/registry/schemas/reference.schema.json +10 -0
- package/registry/schemas/resource.schema.json +154 -0
- package/registry/schemas/skill.schema.json +14 -0
- package/registry/schemas/template.schema.json +46 -0
- package/registry/schemas/tool.schema.json +61 -0
- package/_persona/summer/SKILL.md +0 -113
- package/dist/bin/postinstall.d.ts +0 -2
- package/dist/bin/postinstall.js +0 -3
- package/dist/commands/cloud.d.ts +0 -2
- package/dist/commands/cloud.js +0 -80
- package/dist/commands/create.d.ts +0 -3
- package/dist/commands/create.js +0 -171
- package/dist/commands/install.d.ts +0 -19
- package/dist/commands/install.js +0 -194
- package/dist/commands/list.js +0 -67
- package/dist/commands/logout.js +0 -13
- package/dist/commands/logs.d.ts +0 -2
- package/dist/commands/logs.js +0 -19
- package/dist/commands/open.d.ts +0 -2
- package/dist/commands/open.js +0 -32
- package/dist/commands/orchestrator.d.ts +0 -8
- package/dist/commands/orchestrator.js +0 -143
- package/dist/commands/run.d.ts +0 -2
- package/dist/commands/run.js +0 -167
- package/dist/commands/setup.js +0 -217
- package/dist/commands/status.js +0 -46
- package/dist/lib/agent-config.d.ts +0 -39
- package/dist/lib/agent-config.js +0 -626
- package/dist/lib/banner.d.ts +0 -4
- package/dist/lib/banner.js +0 -122
- package/dist/lib/cloud/api.d.ts +0 -79
- package/dist/lib/cloud/api.js +0 -107
- package/dist/lib/cloud/apply.d.ts +0 -32
- package/dist/lib/cloud/apply.js +0 -294
- package/dist/lib/cloud/checkpoint.d.ts +0 -26
- package/dist/lib/cloud/checkpoint.js +0 -142
- package/dist/lib/cloud/conflicts.d.ts +0 -55
- package/dist/lib/cloud/conflicts.js +0 -131
- package/dist/lib/cloud/containment.d.ts +0 -8
- package/dist/lib/cloud/containment.js +0 -52
- package/dist/lib/cloud/diff.d.ts +0 -39
- package/dist/lib/cloud/diff.js +0 -138
- package/dist/lib/cloud/engine-bridge.d.ts +0 -34
- package/dist/lib/cloud/engine-bridge.js +0 -139
- package/dist/lib/cloud/hash-cache.d.ts +0 -23
- package/dist/lib/cloud/hash-cache.js +0 -44
- package/dist/lib/cloud/hash.d.ts +0 -10
- package/dist/lib/cloud/hash.js +0 -111
- package/dist/lib/cloud/http.d.ts +0 -17
- package/dist/lib/cloud/http.js +0 -47
- package/dist/lib/cloud/lock-path.d.ts +0 -1
- package/dist/lib/cloud/lock-path.js +0 -5
- package/dist/lib/cloud/lock.d.ts +0 -14
- package/dist/lib/cloud/lock.js +0 -143
- package/dist/lib/cloud/manifest.d.ts +0 -6
- package/dist/lib/cloud/manifest.js +0 -41
- package/dist/lib/cloud/paths.d.ts +0 -20
- package/dist/lib/cloud/paths.js +0 -90
- package/dist/lib/cloud/project-godot-merge.d.ts +0 -32
- package/dist/lib/cloud/project-godot-merge.js +0 -185
- package/dist/lib/cloud/rules.d.ts +0 -39
- package/dist/lib/cloud/rules.js +0 -159
- package/dist/lib/cloud/sync.d.ts +0 -21
- package/dist/lib/cloud/sync.js +0 -518
- package/dist/lib/cloud/transfer.d.ts +0 -23
- package/dist/lib/cloud/transfer.js +0 -184
- package/dist/lib/cloud/types.d.ts +0 -62
- package/dist/lib/cloud/types.js +0 -1
- package/dist/lib/cloud/validate-path.d.ts +0 -23
- package/dist/lib/cloud/validate-path.js +0 -103
- package/dist/lib/engine.d.ts +0 -51
- package/dist/lib/game-task-plan.d.ts +0 -42
- package/dist/lib/project-memory.d.ts +0 -33
- package/dist/lib/public-surface-paths.d.ts +0 -13
- package/dist/lib/public-surface-paths.js +0 -42
- package/dist/lib/remote-templates.d.ts +0 -25
- package/dist/lib/remote-templates.js +0 -86
- package/dist/lib/skills-registry.d.ts +0 -572
- package/dist/lib/skills-registry.js +0 -1061
- package/dist/lib/version-check.d.ts +0 -106
- package/dist/lib/version-check.js +0 -338
- package/dist/mcp/tools/cloud-tools.js +0 -42
- package/references/mcp-tools-reference.md +0 -199
- package/references/template-registry.md +0 -73
- package/skills/README.md +0 -103
- package/skills/scene-and-project/summer-cloud/SKILL.md +0 -92
- package/skills/workflow/brainstorming/scripts/frame-template.html +0 -214
- package/skills/workflow/brainstorming/scripts/helper.js +0 -88
- package/skills/workflow/brainstorming/scripts/server.cjs +0 -354
- package/skills/workflow/brainstorming/scripts/start-server.sh +0 -148
- package/skills/workflow/brainstorming/scripts/stop-server.sh +0 -56
- package/skills/workflow/brainstorming/visual-companion.md +0 -287
- package/skills/workflow/gameskill/SKILL.md +0 -120
- package/skills/workflow/investigating-bugs/CREATION-LOG.md +0 -119
- package/skills/workflow/investigating-bugs/condition-based-waiting-example.ts +0 -158
- package/skills/workflow/investigating-bugs/find-polluter.sh +0 -63
- package/skills/workflow/investigating-bugs/test-academic.md +0 -14
- package/skills/workflow/investigating-bugs/test-pressure-1.md +0 -58
- package/skills/workflow/investigating-bugs/test-pressure-2.md +0 -68
- package/skills/workflow/investigating-bugs/test-pressure-3.md +0 -69
- package/skills/workflow/mcpupdate/SKILL.md +0 -134
- package/skills/workflow/skill-create/SKILL.md +0 -153
- package/skills/workflow/writing-skills/anthropic-best-practices.md +0 -1150
- package/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
- package/skills/workflow/writing-skills/graphviz-conventions.dot +0 -172
- package/skills/workflow/writing-skills/persuasion-principles.md +0 -187
- package/skills/workflow/writing-skills/render-graphs.js +0 -168
- /package/dist/{commands → cli/commands}/config.d.ts +0 -0
- /package/dist/{commands → cli/commands}/debug.d.ts +0 -0
- /package/dist/{commands → cli/commands}/list.d.ts +0 -0
- /package/dist/{commands → cli/commands}/login.d.ts +0 -0
- /package/dist/{commands → cli/commands}/plan.d.ts +0 -0
- /package/dist/{commands → cli/commands}/publish.d.ts +0 -0
- /package/dist/{commands → cli/commands}/releases.d.ts +0 -0
- /package/dist/{commands → cli/commands}/setup.d.ts +0 -0
- /package/dist/{commands → cli/commands}/skills.d.ts +0 -0
- /package/dist/{lib → core}/log-filters.d.ts +0 -0
- /package/dist/{lib → core}/mcp-log.d.ts +0 -0
- /package/dist/{lib → core}/store.d.ts +0 -0
- /package/dist/{lib → core}/summer-compatibility.d.ts +0 -0
- /package/dist/{lib → core}/telemetry.d.ts +0 -0
- /package/dist/{lib/mcp-boot-notice.js → mcp/boot-notice.js} +0 -0
- /package/dist/{commands/mcp.d.ts → mcp/command.d.ts} +0 -0
- /package/{references → library/references/collaborative-protocol}/collaborative-protocol.md +0 -0
- /package/{references → library/references/gd-style}/gd-style.md +0 -0
- /package/{skills/audio → library/skills}/ambient-bed/SKILL.md +0 -0
- /package/{skills/gameplay-mechanics → library/skills}/auto-fire-targeting/SKILL.md +0 -0
- /package/{skills/scripting-patterns → library/skills}/gdscript-patterns/SKILL.md +0 -0
- /package/{skills/scripting-patterns → library/skills}/gdscript-patterns/reference.md +0 -0
- /package/{skills/multiplayer-and-networking → library/skills}/host-authoritative-state/SKILL.md +0 -0
- /package/{skills/workflow → library/skills}/investigating-bugs/defense-in-depth.md +0 -0
- /package/{skills/audio → library/skills}/music-track/SKILL.md +0 -0
- /package/{skills/scene-and-project → library/skills}/play/SKILL.md +0 -0
- /package/{skills/multiplayer-and-networking → library/skills}/setup-multiplayer/SKILL.md +0 -0
- /package/{skills/ui-and-ux → library/skills}/ui-basics/SKILL.md +0 -0
- /package/{skills/visual-effects → library/skills/vfx-dissolve}/_building-blocks/noise-3d-fbm.gdshaderinc +0 -0
- /package/{skills/visual-effects → library/skills/vfx-fire}/_building-blocks/additive-billboard-particles.md +0 -0
- /package/{skills/visual-effects → library/skills/vfx-lightning}/_building-blocks/trauma-shake-snippet.md +0 -0
- /package/{skills/audio → library/skills}/voice-line/SKILL.md +0 -0
- /package/{skills/workflow → library/skills}/writing-plans/plan-document-reviewer-prompt.md +0 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from "child_process";
|
|
2
|
+
import { closeSync, existsSync, fstatSync, openSync, readSync } from "fs";
|
|
3
|
+
import { mkdir } from "fs/promises";
|
|
4
|
+
import { platform, tmpdir } from "os";
|
|
5
|
+
import { join, resolve } from "path";
|
|
6
|
+
import { findEngineBinary as findInstalledEngineBinary } from "../engine-install.js";
|
|
7
|
+
import { sleep } from "../util/sleep.js";
|
|
8
|
+
import { envMs, HeadlessTimeoutError, scrubSecrets } from "./connection.js";
|
|
9
|
+
import { findWorkerEntry, normalizeProjectPath, } from "./registry.js";
|
|
10
|
+
/**
|
|
11
|
+
* On-demand worker spawning: <engine binary> --summer-worker --path <project>
|
|
12
|
+
* then poll the process registry until the worker registers itself.
|
|
13
|
+
*
|
|
14
|
+
* Process model (zombie hygiene):
|
|
15
|
+
* - The worker is spawned DETACHED (own process group) and unref()ed, so it
|
|
16
|
+
* deliberately outlives this CLI process — an MCP session ending must not
|
|
17
|
+
* kill a worker another session may be using. It stays discoverable via
|
|
18
|
+
* the registry; dead entries are pruned by pid liveness on every read.
|
|
19
|
+
* - While this process is alive, node's child_process reaps the child on
|
|
20
|
+
* exit (no zombie), and the exit is used to fail fast (see below).
|
|
21
|
+
* - stderr goes to a per-spawn log FILE (never a pipe): a pipe would EPIPE
|
|
22
|
+
* the worker if the CLI exits first. On exit-before-ready the log tail is
|
|
23
|
+
* read back and surfaced in the error.
|
|
24
|
+
* - argv array only — no shell, no interpolation.
|
|
25
|
+
*
|
|
26
|
+
* Engine-binary discovery: SUMMER_ENGINE_BIN (this layer's documented
|
|
27
|
+
* override — set-but-missing means "no binary", never a silent fallback),
|
|
28
|
+
* then the canonical resolver in src/core/engine-install.ts (its own
|
|
29
|
+
* SUMMER_ENGINE_BINARY override + the platform install locations shared with
|
|
30
|
+
* `summer install` / `summer run` / `summer doctor`). No install-path list
|
|
31
|
+
* is duplicated here.
|
|
32
|
+
*
|
|
33
|
+
* Single-flight: concurrent spawn requests for the SAME project share one
|
|
34
|
+
* spawn (module-level in-flight promise map keyed by canonical project
|
|
35
|
+
* path). The first caller's options win for the shared attempt.
|
|
36
|
+
*/
|
|
37
|
+
const STDERR_TAIL_BYTES = 4096;
|
|
38
|
+
export function findEngineBinary(env = process.env) {
|
|
39
|
+
const override = env.SUMMER_ENGINE_BIN?.trim();
|
|
40
|
+
if (override)
|
|
41
|
+
return existsSync(override) ? override : null;
|
|
42
|
+
return findInstalledEngineBinary(platform(), env);
|
|
43
|
+
}
|
|
44
|
+
/** Read ONLY the last STDERR_TAIL_BYTES of a file (open + seek — never the
|
|
45
|
+
* whole file, which could be huge for a long-lived chatty worker). */
|
|
46
|
+
function readFileTail(path) {
|
|
47
|
+
try {
|
|
48
|
+
const fd = openSync(path, "r");
|
|
49
|
+
try {
|
|
50
|
+
const size = fstatSync(fd).size;
|
|
51
|
+
const length = Math.min(size, STDERR_TAIL_BYTES);
|
|
52
|
+
if (length === 0)
|
|
53
|
+
return "";
|
|
54
|
+
const buffer = Buffer.alloc(length);
|
|
55
|
+
readSync(fd, buffer, 0, length, size - length);
|
|
56
|
+
return buffer.toString("utf-8");
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
closeSync(fd);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function defaultLaunch(binary, args) {
|
|
67
|
+
// stderr -> file (see module doc). Directory creation (mode 0700) is done
|
|
68
|
+
// in spawnWorker before the launcher runs; the log itself is 0600 — worker
|
|
69
|
+
// stderr can quote project content and must not be world-readable.
|
|
70
|
+
const logPath = join(workerLogDir(), `worker-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.log`);
|
|
71
|
+
const fd = openSync(logPath, "a", 0o600);
|
|
72
|
+
let exit = null;
|
|
73
|
+
let launchError = "";
|
|
74
|
+
// The child inherits process.env wholesale, which already carries
|
|
75
|
+
// SUMMER_CACHE_DIR when set — so the spawned worker writes its registry
|
|
76
|
+
// entry to the same overridden cache dir this CLI polls. (An earlier
|
|
77
|
+
// explicit re-assignment of the same value was a no-op.)
|
|
78
|
+
const child = nodeSpawn(binary, args, {
|
|
79
|
+
detached: true,
|
|
80
|
+
// detached on Windows opens a new console window for the child unless
|
|
81
|
+
// hidden; a no-op elsewhere.
|
|
82
|
+
windowsHide: true,
|
|
83
|
+
stdio: ["ignore", "ignore", fd],
|
|
84
|
+
env: process.env,
|
|
85
|
+
});
|
|
86
|
+
closeSync(fd);
|
|
87
|
+
child.once("exit", (code, signal) => {
|
|
88
|
+
exit = { code, signal };
|
|
89
|
+
});
|
|
90
|
+
// A spawn failure (ENOENT, EACCES) arrives as an 'error' event, not an
|
|
91
|
+
// exit — without a listener it would crash the process. Treat it as an
|
|
92
|
+
// immediate exit whose "stderr" is the launch error.
|
|
93
|
+
child.once("error", (error) => {
|
|
94
|
+
launchError = error.message;
|
|
95
|
+
exit = exit ?? { code: null, signal: null };
|
|
96
|
+
});
|
|
97
|
+
child.unref();
|
|
98
|
+
return {
|
|
99
|
+
exit: () => exit,
|
|
100
|
+
stderrTail: () => (launchError ? launchError : readFileTail(logPath)),
|
|
101
|
+
kill: () => {
|
|
102
|
+
if (exit)
|
|
103
|
+
return;
|
|
104
|
+
try {
|
|
105
|
+
child.kill("SIGTERM");
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return; // already gone
|
|
109
|
+
}
|
|
110
|
+
const escalate = setTimeout(() => {
|
|
111
|
+
if (!exit) {
|
|
112
|
+
try {
|
|
113
|
+
child.kill("SIGKILL");
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
/* already gone */
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}, 5_000);
|
|
120
|
+
// Never keep the CLI alive just to escalate a kill.
|
|
121
|
+
escalate.unref();
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function workerLogDir() {
|
|
126
|
+
return join(tmpdir(), "summer-engine", "worker-logs");
|
|
127
|
+
}
|
|
128
|
+
// Single-flight: canonical project path -> in-flight spawn attempt.
|
|
129
|
+
const inFlightSpawns = new Map();
|
|
130
|
+
/**
|
|
131
|
+
* Spawn a headless worker for `projectPath` and wait for its registry entry.
|
|
132
|
+
* Resolves with the live entry; rejects on missing binary, early exit
|
|
133
|
+
* (surfacing the exit code and a stderr tail), or registration timeout.
|
|
134
|
+
* Concurrent calls for the same project share ONE spawn.
|
|
135
|
+
*/
|
|
136
|
+
export function spawnWorker(projectPath, options = {}) {
|
|
137
|
+
const target = resolve(projectPath);
|
|
138
|
+
const flightKey = normalizeProjectPath(projectPath);
|
|
139
|
+
const existing = inFlightSpawns.get(flightKey);
|
|
140
|
+
if (existing)
|
|
141
|
+
return existing;
|
|
142
|
+
const attempt = spawnWorkerOnce(target, options).finally(() => {
|
|
143
|
+
inFlightSpawns.delete(flightKey);
|
|
144
|
+
});
|
|
145
|
+
inFlightSpawns.set(flightKey, attempt);
|
|
146
|
+
return attempt;
|
|
147
|
+
}
|
|
148
|
+
async function spawnWorkerOnce(target, options) {
|
|
149
|
+
const binary = options.binary ?? findEngineBinary();
|
|
150
|
+
if (!binary) {
|
|
151
|
+
throw new Error("Summer Engine binary not found (checked the standard install locations and SUMMER_ENGINE_BIN). " +
|
|
152
|
+
"Install it first: npx summer-engine install");
|
|
153
|
+
}
|
|
154
|
+
// Baseline snapshot (stale-entry defense): a registry entry that already
|
|
155
|
+
// exists for this project — even one whose pid probe still answers — must
|
|
156
|
+
// NEVER satisfy the post-spawn poll. Only an entry that differs from the
|
|
157
|
+
// baseline (new pid/port/token or a newer started_ts) counts as the worker
|
|
158
|
+
// we just launched. This closes the "connect failed to a stale live-pid
|
|
159
|
+
// entry, spawn, then immediately re-adopt the same stale entry" loop.
|
|
160
|
+
const baseline = await findWorkerEntry(target, options.registry);
|
|
161
|
+
const launch = options.launch ?? defaultLaunch;
|
|
162
|
+
if (launch === defaultLaunch) {
|
|
163
|
+
await mkdir(workerLogDir(), { recursive: true, mode: 0o700 });
|
|
164
|
+
}
|
|
165
|
+
const handle = launch(binary, ["--summer-worker", "--path", target]);
|
|
166
|
+
const timeoutMs = options.timeoutMs ?? envMs("SUMMER_WORKER_SPAWN_TIMEOUT_MS", 120_000);
|
|
167
|
+
const pollIntervalMs = options.pollIntervalMs ?? 500;
|
|
168
|
+
const startedAt = Date.now();
|
|
169
|
+
const isFreshEntry = (entry) => {
|
|
170
|
+
if (!baseline)
|
|
171
|
+
return true;
|
|
172
|
+
return (entry.pid !== baseline.pid ||
|
|
173
|
+
entry.port !== baseline.port ||
|
|
174
|
+
entry.token !== baseline.token ||
|
|
175
|
+
(entry.startedTs ?? 0) > (baseline.startedTs ?? 0));
|
|
176
|
+
};
|
|
177
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
178
|
+
const entry = await findWorkerEntry(target, options.registry);
|
|
179
|
+
if (entry && isFreshEntry(entry))
|
|
180
|
+
return entry;
|
|
181
|
+
// Registry checked first, exit second: a worker that registers and then
|
|
182
|
+
// exits still surfaces its (now dead) entry to the pruning reader, while
|
|
183
|
+
// a crash-before-register fails fast here instead of burning the budget.
|
|
184
|
+
const exit = handle.exit();
|
|
185
|
+
if (exit) {
|
|
186
|
+
// Scrub any token material out of the surfaced tail (defense in depth;
|
|
187
|
+
// the tail is worker stderr and could quote its own environment).
|
|
188
|
+
const tail = scrubSecrets(handle.stderrTail(), [baseline?.token]).trim();
|
|
189
|
+
throw new Error(`Headless worker for ${target} exited before registering ` +
|
|
190
|
+
`(code ${exit.code ?? "null"}${exit.signal ? `, signal ${exit.signal}` : ""}).` +
|
|
191
|
+
(tail ? `\nWorker stderr (tail):\n${tail}` : ""));
|
|
192
|
+
}
|
|
193
|
+
options.onProgress?.({
|
|
194
|
+
phase: "waiting_for_worker_registration",
|
|
195
|
+
elapsedMs: Date.now() - startedAt,
|
|
196
|
+
});
|
|
197
|
+
await sleep(pollIntervalMs);
|
|
198
|
+
}
|
|
199
|
+
// Abandoning the attempt: never leak the just-spawned child. Kill it so a
|
|
200
|
+
// worker nobody adopted (and whose registry entry never appeared) does not
|
|
201
|
+
// run forever.
|
|
202
|
+
handle.kill?.();
|
|
203
|
+
throw new HeadlessTimeoutError("spawn", `Spawned a headless worker for ${target}, but it did not register within ${Math.round(timeoutMs / 1000)}s (the spawned process has been terminated). First imports of large projects can be ` +
|
|
204
|
+
"slow — raise SUMMER_WORKER_SPAWN_TIMEOUT_MS and retry, or open the project in the Summer editor instead.");
|
|
205
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type CallOptions, type ProjectConnection } from "./connection.js";
|
|
2
|
+
/**
|
|
3
|
+
* TCP client for a headless Summer worker — protocol v1.1.
|
|
4
|
+
*
|
|
5
|
+
* Wire protocol (pinned v1.1; the worker implements the same):
|
|
6
|
+
* - connect to 127.0.0.1:<port>
|
|
7
|
+
* - WORKER sends first (within 3s):
|
|
8
|
+
* {"hello":{"pid":<int>,"nonce":"<32 hex>","proof":"<hex sha256(nonce + ':' + token)>"}}
|
|
9
|
+
* - client verifies `proof` against the REGISTRY token (proves the worker
|
|
10
|
+
* holds the token without it crossing the wire) AND `hello.pid` against
|
|
11
|
+
* the REGISTRY pid (pid-reuse / port-squat detection), then answers:
|
|
12
|
+
* {"auth":"<hex sha256('client:' + nonce + ':' + token)>"}
|
|
13
|
+
* The raw token NEVER crosses the wire in either direction.
|
|
14
|
+
* - then requests: {"id": "...", "op": "...", "params": {...}}
|
|
15
|
+
* - responses: {"id": "...", "ok": true, "result": ...}
|
|
16
|
+
* or {"id": "...", "ok": false, "error": "..."}
|
|
17
|
+
* - interim progress: {"id": "...", "event": "progress", "progress": ...}
|
|
18
|
+
* All lines are newline-delimited JSON, one document per \n. Framing is done
|
|
19
|
+
* on BYTES (split on 0x0a before utf-8 decoding) so a multibyte codepoint
|
|
20
|
+
* split across TCP chunks is never corrupted. An un-terminated frame is
|
|
21
|
+
* capped at 8MiB — beyond that the connection is destroyed with a clear
|
|
22
|
+
* error.
|
|
23
|
+
*
|
|
24
|
+
* Timeouts (env-overridable; every timeout is a HeadlessTimeoutError naming
|
|
25
|
+
* its stage):
|
|
26
|
+
* - connect: SUMMER_WORKER_CONNECT_TIMEOUT_MS (default 5s) stage "connect"
|
|
27
|
+
* - hello: SUMMER_WORKER_HELLO_TIMEOUT_MS (default 3s) stage "auth"
|
|
28
|
+
* - per-op INACTIVITY: SUMMER_WORKER_OP_TIMEOUT_MS (30s) or
|
|
29
|
+
* SUMMER_WORKER_LONG_OP_TIMEOUT_MS (300s) for LONG_RUNNING_OPS. Progress
|
|
30
|
+
* lines RESTART the timer; the timer only STARTS once the request has
|
|
31
|
+
* flushed to the socket (write backpressure never eats the budget).
|
|
32
|
+
*
|
|
33
|
+
* Quarantine: when a MUTATING op (MUTATING_OPS) times out, the mutation's
|
|
34
|
+
* outcome is UNKNOWN — the connection is destroyed and reports drift via
|
|
35
|
+
* credentialsChanged()/isAlive() so caches evict it. The surfaced error says
|
|
36
|
+
* so explicitly; callers must inspect the target before retrying. Read-only
|
|
37
|
+
* timeouts leave the connection usable.
|
|
38
|
+
*
|
|
39
|
+
* Security: no token material ever appears in an error, log line, or thrown
|
|
40
|
+
* value. Auth-phase failures surface FIXED messages (never worker-supplied
|
|
41
|
+
* text); op errors from the worker are scrubbed of the token as defense in
|
|
42
|
+
* depth.
|
|
43
|
+
*
|
|
44
|
+
* Failure model: a dropped socket fails ALL pending calls with a clean error
|
|
45
|
+
* and marks the connection permanently dead. No transparent reconnect — the
|
|
46
|
+
* worker may have died mid-mutation and this client sends no idempotency
|
|
47
|
+
* keys, so a blind retry could double-apply (same reasoning as withEngine's
|
|
48
|
+
* narrow retry policy). Callers evict and re-resolve.
|
|
49
|
+
*/
|
|
50
|
+
export declare const MAX_FRAME_BYTES: number;
|
|
51
|
+
export interface WorkerConnectOptions {
|
|
52
|
+
host?: string;
|
|
53
|
+
port: number;
|
|
54
|
+
token: string;
|
|
55
|
+
/** Registry pid for this worker — verified against hello.pid. */
|
|
56
|
+
pid: number;
|
|
57
|
+
projectPath: string;
|
|
58
|
+
/** TCP connect budget. Default: SUMMER_WORKER_CONNECT_TIMEOUT_MS or 5s. */
|
|
59
|
+
connectTimeoutMs?: number;
|
|
60
|
+
/** Budget for the worker's hello line.
|
|
61
|
+
* Default: SUMMER_WORKER_HELLO_TIMEOUT_MS or 3s. */
|
|
62
|
+
helloTimeoutMs?: number;
|
|
63
|
+
/** Verify the channel with a `ping` op after the handshake. Default true. */
|
|
64
|
+
verifyWithPing?: boolean;
|
|
65
|
+
/** Un-terminated frame cap in bytes (test seam). Default MAX_FRAME_BYTES. */
|
|
66
|
+
maxFrameBytes?: number;
|
|
67
|
+
}
|
|
68
|
+
/** v1.1: what the WORKER must present in hello.proof. */
|
|
69
|
+
export declare function helloProof(nonce: string, token: string): string;
|
|
70
|
+
/** v1.1: what the CLIENT answers with in the auth line. */
|
|
71
|
+
export declare function clientAuthProof(nonce: string, token: string): string;
|
|
72
|
+
export declare function defaultOpTimeoutMs(op: string): number;
|
|
73
|
+
export declare class WorkerConnection implements ProjectConnection {
|
|
74
|
+
readonly kind: "worker";
|
|
75
|
+
readonly projectPath: string;
|
|
76
|
+
private socket;
|
|
77
|
+
private buffer;
|
|
78
|
+
private nextId;
|
|
79
|
+
private pending;
|
|
80
|
+
private alive;
|
|
81
|
+
private closeReason;
|
|
82
|
+
private readonly token;
|
|
83
|
+
private readonly maxFrameBytes;
|
|
84
|
+
private constructor();
|
|
85
|
+
static connect(options: WorkerConnectOptions): Promise<WorkerConnection>;
|
|
86
|
+
isAlive(): boolean;
|
|
87
|
+
call(op: string, params?: Record<string, unknown>, options?: CallOptions): Promise<unknown>;
|
|
88
|
+
close(): void;
|
|
89
|
+
private scrub;
|
|
90
|
+
private onData;
|
|
91
|
+
/** Byte-exact framing: split on 0x0a BEFORE utf-8 decoding, so a multibyte
|
|
92
|
+
* codepoint split across TCP chunks is reassembled correctly. */
|
|
93
|
+
private drainFrames;
|
|
94
|
+
private dispatch;
|
|
95
|
+
private failAll;
|
|
96
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { asRecord } from "../util/json.js";
|
|
3
|
+
import { createConnection } from "node:net";
|
|
4
|
+
import { envMs, HeadlessTimeoutError, LONG_RUNNING_OPS, MUTATING_OPS, scrubSecrets, WorkerOpError, } from "./connection.js";
|
|
5
|
+
/**
|
|
6
|
+
* TCP client for a headless Summer worker — protocol v1.1.
|
|
7
|
+
*
|
|
8
|
+
* Wire protocol (pinned v1.1; the worker implements the same):
|
|
9
|
+
* - connect to 127.0.0.1:<port>
|
|
10
|
+
* - WORKER sends first (within 3s):
|
|
11
|
+
* {"hello":{"pid":<int>,"nonce":"<32 hex>","proof":"<hex sha256(nonce + ':' + token)>"}}
|
|
12
|
+
* - client verifies `proof` against the REGISTRY token (proves the worker
|
|
13
|
+
* holds the token without it crossing the wire) AND `hello.pid` against
|
|
14
|
+
* the REGISTRY pid (pid-reuse / port-squat detection), then answers:
|
|
15
|
+
* {"auth":"<hex sha256('client:' + nonce + ':' + token)>"}
|
|
16
|
+
* The raw token NEVER crosses the wire in either direction.
|
|
17
|
+
* - then requests: {"id": "...", "op": "...", "params": {...}}
|
|
18
|
+
* - responses: {"id": "...", "ok": true, "result": ...}
|
|
19
|
+
* or {"id": "...", "ok": false, "error": "..."}
|
|
20
|
+
* - interim progress: {"id": "...", "event": "progress", "progress": ...}
|
|
21
|
+
* All lines are newline-delimited JSON, one document per \n. Framing is done
|
|
22
|
+
* on BYTES (split on 0x0a before utf-8 decoding) so a multibyte codepoint
|
|
23
|
+
* split across TCP chunks is never corrupted. An un-terminated frame is
|
|
24
|
+
* capped at 8MiB — beyond that the connection is destroyed with a clear
|
|
25
|
+
* error.
|
|
26
|
+
*
|
|
27
|
+
* Timeouts (env-overridable; every timeout is a HeadlessTimeoutError naming
|
|
28
|
+
* its stage):
|
|
29
|
+
* - connect: SUMMER_WORKER_CONNECT_TIMEOUT_MS (default 5s) stage "connect"
|
|
30
|
+
* - hello: SUMMER_WORKER_HELLO_TIMEOUT_MS (default 3s) stage "auth"
|
|
31
|
+
* - per-op INACTIVITY: SUMMER_WORKER_OP_TIMEOUT_MS (30s) or
|
|
32
|
+
* SUMMER_WORKER_LONG_OP_TIMEOUT_MS (300s) for LONG_RUNNING_OPS. Progress
|
|
33
|
+
* lines RESTART the timer; the timer only STARTS once the request has
|
|
34
|
+
* flushed to the socket (write backpressure never eats the budget).
|
|
35
|
+
*
|
|
36
|
+
* Quarantine: when a MUTATING op (MUTATING_OPS) times out, the mutation's
|
|
37
|
+
* outcome is UNKNOWN — the connection is destroyed and reports drift via
|
|
38
|
+
* credentialsChanged()/isAlive() so caches evict it. The surfaced error says
|
|
39
|
+
* so explicitly; callers must inspect the target before retrying. Read-only
|
|
40
|
+
* timeouts leave the connection usable.
|
|
41
|
+
*
|
|
42
|
+
* Security: no token material ever appears in an error, log line, or thrown
|
|
43
|
+
* value. Auth-phase failures surface FIXED messages (never worker-supplied
|
|
44
|
+
* text); op errors from the worker are scrubbed of the token as defense in
|
|
45
|
+
* depth.
|
|
46
|
+
*
|
|
47
|
+
* Failure model: a dropped socket fails ALL pending calls with a clean error
|
|
48
|
+
* and marks the connection permanently dead. No transparent reconnect — the
|
|
49
|
+
* worker may have died mid-mutation and this client sends no idempotency
|
|
50
|
+
* keys, so a blind retry could double-apply (same reasoning as withEngine's
|
|
51
|
+
* narrow retry policy). Callers evict and re-resolve.
|
|
52
|
+
*/
|
|
53
|
+
export const MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
54
|
+
const MAX_HELLO_BYTES = 64 * 1024;
|
|
55
|
+
const NEWLINE = 0x0a;
|
|
56
|
+
function sha256Hex(text) {
|
|
57
|
+
return createHash("sha256").update(text, "utf-8").digest("hex");
|
|
58
|
+
}
|
|
59
|
+
/** v1.1: what the WORKER must present in hello.proof. */
|
|
60
|
+
export function helloProof(nonce, token) {
|
|
61
|
+
return sha256Hex(`${nonce}:${token}`);
|
|
62
|
+
}
|
|
63
|
+
/** v1.1: what the CLIENT answers with in the auth line. */
|
|
64
|
+
export function clientAuthProof(nonce, token) {
|
|
65
|
+
return sha256Hex(`client:${nonce}:${token}`);
|
|
66
|
+
}
|
|
67
|
+
export function defaultOpTimeoutMs(op) {
|
|
68
|
+
return LONG_RUNNING_OPS.has(op)
|
|
69
|
+
? envMs("SUMMER_WORKER_LONG_OP_TIMEOUT_MS", 300_000)
|
|
70
|
+
: envMs("SUMMER_WORKER_OP_TIMEOUT_MS", 30_000);
|
|
71
|
+
}
|
|
72
|
+
/** Read the first \n-terminated line off a raw socket (byte-exact; the
|
|
73
|
+
* remainder after the newline is returned untouched for the connection's
|
|
74
|
+
* frame buffer). Fixed error messages only — this runs pre-auth. */
|
|
75
|
+
function readFirstLine(socket, timeoutMs) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
let buffer = Buffer.alloc(0);
|
|
78
|
+
let settled = false;
|
|
79
|
+
const fail = (error) => {
|
|
80
|
+
if (settled)
|
|
81
|
+
return;
|
|
82
|
+
settled = true;
|
|
83
|
+
cleanup();
|
|
84
|
+
socket.destroy();
|
|
85
|
+
reject(error);
|
|
86
|
+
};
|
|
87
|
+
const onData = (chunk) => {
|
|
88
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
89
|
+
const newline = buffer.indexOf(NEWLINE);
|
|
90
|
+
if (newline >= 0) {
|
|
91
|
+
const line = buffer.subarray(0, newline).toString("utf-8");
|
|
92
|
+
const rest = Buffer.from(buffer.subarray(newline + 1));
|
|
93
|
+
settled = true;
|
|
94
|
+
cleanup();
|
|
95
|
+
resolve({ line, rest });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (buffer.length > MAX_HELLO_BYTES) {
|
|
99
|
+
fail(new HeadlessTimeoutError("auth", "Headless worker handshake failed: oversized hello frame."));
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const onClose = () => fail(new HeadlessTimeoutError("auth", "Headless worker handshake failed: connection closed before hello."));
|
|
103
|
+
const timer = setTimeout(() => fail(new HeadlessTimeoutError("auth", `Headless worker handshake failed: no hello within ${timeoutMs}ms.`)), timeoutMs);
|
|
104
|
+
const cleanup = () => {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
socket.off("data", onData);
|
|
107
|
+
socket.off("close", onClose);
|
|
108
|
+
socket.off("error", onClose);
|
|
109
|
+
};
|
|
110
|
+
socket.on("data", onData);
|
|
111
|
+
socket.once("close", onClose);
|
|
112
|
+
socket.once("error", onClose);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
export class WorkerConnection {
|
|
116
|
+
kind = "worker";
|
|
117
|
+
projectPath;
|
|
118
|
+
socket;
|
|
119
|
+
buffer;
|
|
120
|
+
// ID CONTRACT (pinned): request ids are POSITIVE JSON INTEGERS, monotonic
|
|
121
|
+
// per connection. String ids are coerced to -1 by the worker's engine-side
|
|
122
|
+
// String->int conversion and every op would time out.
|
|
123
|
+
nextId = 1;
|
|
124
|
+
pending = new Map();
|
|
125
|
+
alive = true;
|
|
126
|
+
closeReason = null;
|
|
127
|
+
token;
|
|
128
|
+
maxFrameBytes;
|
|
129
|
+
constructor(socket, projectPath, token, initialBuffer, maxFrameBytes) {
|
|
130
|
+
this.socket = socket;
|
|
131
|
+
this.projectPath = projectPath;
|
|
132
|
+
this.token = token;
|
|
133
|
+
this.buffer = initialBuffer;
|
|
134
|
+
this.maxFrameBytes = maxFrameBytes;
|
|
135
|
+
socket.on("data", (chunk) => this.onData(chunk));
|
|
136
|
+
socket.on("error", (error) =>
|
|
137
|
+
// error.message comes from the OS (ECONNRESET etc.); scrubbed anyway.
|
|
138
|
+
this.failAll(`Headless worker connection error: ${this.scrub(error.message)}`));
|
|
139
|
+
socket.on("close", () => this.failAll("Headless worker connection closed."));
|
|
140
|
+
// Process any bytes that arrived in the same chunk as the hello frame.
|
|
141
|
+
if (this.buffer.length > 0)
|
|
142
|
+
this.drainFrames();
|
|
143
|
+
}
|
|
144
|
+
static async connect(options) {
|
|
145
|
+
const host = options.host ?? "127.0.0.1";
|
|
146
|
+
const connectTimeoutMs = options.connectTimeoutMs ?? envMs("SUMMER_WORKER_CONNECT_TIMEOUT_MS", 5_000);
|
|
147
|
+
const helloTimeoutMs = options.helloTimeoutMs ?? envMs("SUMMER_WORKER_HELLO_TIMEOUT_MS", 3_000);
|
|
148
|
+
const socket = await new Promise((resolvePromise, rejectPromise) => {
|
|
149
|
+
const sock = createConnection({ host, port: options.port });
|
|
150
|
+
const timer = setTimeout(() => {
|
|
151
|
+
sock.destroy();
|
|
152
|
+
rejectPromise(new HeadlessTimeoutError("connect", `Timed out after ${connectTimeoutMs}ms connecting to headless worker at ${host}:${options.port}.`));
|
|
153
|
+
}, connectTimeoutMs);
|
|
154
|
+
sock.once("connect", () => {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
resolvePromise(sock);
|
|
157
|
+
});
|
|
158
|
+
sock.once("error", (error) => {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
rejectPromise(new HeadlessTimeoutError("connect", `Could not connect to headless worker at ${host}:${options.port}: ${scrubSecrets(error.message, [options.token])}`));
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
socket.setNoDelay(true);
|
|
164
|
+
// --- v1.1 mutual auth. FIXED messages only in this phase: nothing
|
|
165
|
+
// worker-supplied and no token material may reach an error string.
|
|
166
|
+
const authFail = (reason) => {
|
|
167
|
+
socket.destroy();
|
|
168
|
+
throw new HeadlessTimeoutError("auth", `Headless worker handshake failed at ${host}:${options.port}: ${reason} ` +
|
|
169
|
+
"(stale registry entry, pid reuse, or another process squatting the port).");
|
|
170
|
+
};
|
|
171
|
+
const { line, rest } = await readFirstLine(socket, helloTimeoutMs);
|
|
172
|
+
let hello = null;
|
|
173
|
+
try {
|
|
174
|
+
hello = asRecord(asRecord(JSON.parse(line))?.hello);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
hello = null;
|
|
178
|
+
}
|
|
179
|
+
const nonce = typeof hello?.nonce === "string" ? hello.nonce : null;
|
|
180
|
+
const proof = typeof hello?.proof === "string" ? hello.proof : null;
|
|
181
|
+
const pid = typeof hello?.pid === "number" ? hello.pid : null;
|
|
182
|
+
if (!hello || nonce === null || proof === null || pid === null) {
|
|
183
|
+
authFail("malformed hello");
|
|
184
|
+
}
|
|
185
|
+
if (!/^[0-9a-f]{32}$/.test(nonce)) {
|
|
186
|
+
authFail("malformed hello nonce");
|
|
187
|
+
}
|
|
188
|
+
if (proof.toLowerCase() !== helloProof(nonce, options.token)) {
|
|
189
|
+
authFail("worker proof mismatch");
|
|
190
|
+
}
|
|
191
|
+
if (pid !== options.pid) {
|
|
192
|
+
authFail("worker pid mismatch");
|
|
193
|
+
}
|
|
194
|
+
socket.write(JSON.stringify({ auth: clientAuthProof(nonce, options.token) }) + "\n");
|
|
195
|
+
const connection = new WorkerConnection(socket, options.projectPath, options.token, rest, options.maxFrameBytes ?? MAX_FRAME_BYTES);
|
|
196
|
+
if (options.verifyWithPing !== false) {
|
|
197
|
+
try {
|
|
198
|
+
await connection.call("ping", {}, { timeoutMs: helloTimeoutMs });
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
connection.close();
|
|
202
|
+
// Fixed message — the ping failure detail could be worker-supplied.
|
|
203
|
+
throw new HeadlessTimeoutError("auth", `Headless worker at ${host}:${options.port} completed the handshake but did not answer ping ` +
|
|
204
|
+
"(worker rejected the client auth or died during startup).");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return connection;
|
|
208
|
+
}
|
|
209
|
+
isAlive() {
|
|
210
|
+
return this.alive;
|
|
211
|
+
}
|
|
212
|
+
call(op, params = {}, options = {}) {
|
|
213
|
+
if (!this.alive) {
|
|
214
|
+
return Promise.reject(new Error(this.closeReason ??
|
|
215
|
+
"Headless worker connection is closed. Re-resolve the project connection and retry if safe."));
|
|
216
|
+
}
|
|
217
|
+
const id = this.nextId++;
|
|
218
|
+
const timeoutMs = options.timeoutMs ?? defaultOpTimeoutMs(op);
|
|
219
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
220
|
+
const onTimeout = () => {
|
|
221
|
+
this.pending.delete(id);
|
|
222
|
+
if (MUTATING_OPS.has(op)) {
|
|
223
|
+
// The mutation may or may not have applied — quarantine the whole
|
|
224
|
+
// connection so nothing (including caller-side retries) can
|
|
225
|
+
// silently reuse it and double-apply.
|
|
226
|
+
rejectPromise(new HeadlessTimeoutError("op", `Mutating worker op "${op}" produced no response or progress for ${timeoutMs}ms ` +
|
|
227
|
+
`(request ${id}). The mutation's outcome is UNKNOWN. This connection has been ` +
|
|
228
|
+
"quarantined (closed) to block blind retries; re-resolve and INSPECT the target " +
|
|
229
|
+
"before retrying."));
|
|
230
|
+
this.failAll("Headless worker connection quarantined: a mutating op timed out with unknown outcome.");
|
|
231
|
+
this.socket.destroy();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
rejectPromise(new HeadlessTimeoutError("op", `Worker op "${op}" produced no response or progress for ${timeoutMs}ms ` +
|
|
235
|
+
`(request ${id}). Its final state is unknown; inspect the target before retrying.`));
|
|
236
|
+
};
|
|
237
|
+
const entry = {
|
|
238
|
+
op,
|
|
239
|
+
resolve: resolvePromise,
|
|
240
|
+
reject: rejectPromise,
|
|
241
|
+
onProgress: options.onProgress,
|
|
242
|
+
timer: null,
|
|
243
|
+
restartTimer: () => {
|
|
244
|
+
if (entry.timer)
|
|
245
|
+
clearTimeout(entry.timer);
|
|
246
|
+
entry.timer = setTimeout(onTimeout, timeoutMs);
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
this.pending.set(id, entry);
|
|
250
|
+
// The inactivity timer starts only once the request has actually
|
|
251
|
+
// FLUSHED to the socket — write backpressure must not eat the budget.
|
|
252
|
+
this.socket.write(JSON.stringify({ id, op, params }) + "\n", (error) => {
|
|
253
|
+
if (!this.pending.has(id))
|
|
254
|
+
return; // already settled (drop/response)
|
|
255
|
+
if (error) {
|
|
256
|
+
this.pending.delete(id);
|
|
257
|
+
rejectPromise(new Error(`Headless worker request could not be sent: ${this.scrub(error.message)}. ` +
|
|
258
|
+
"Nothing was submitted."));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
entry.restartTimer();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
close() {
|
|
266
|
+
this.failAll("Headless worker connection closed by client.");
|
|
267
|
+
this.socket.destroy();
|
|
268
|
+
}
|
|
269
|
+
scrub(text) {
|
|
270
|
+
return scrubSecrets(text, [this.token]);
|
|
271
|
+
}
|
|
272
|
+
onData(chunk) {
|
|
273
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
274
|
+
this.drainFrames();
|
|
275
|
+
}
|
|
276
|
+
/** Byte-exact framing: split on 0x0a BEFORE utf-8 decoding, so a multibyte
|
|
277
|
+
* codepoint split across TCP chunks is reassembled correctly. */
|
|
278
|
+
drainFrames() {
|
|
279
|
+
let newline;
|
|
280
|
+
while ((newline = this.buffer.indexOf(NEWLINE)) >= 0) {
|
|
281
|
+
const line = this.buffer.subarray(0, newline).toString("utf-8").trim();
|
|
282
|
+
this.buffer = Buffer.from(this.buffer.subarray(newline + 1));
|
|
283
|
+
if (!line)
|
|
284
|
+
continue;
|
|
285
|
+
let message;
|
|
286
|
+
try {
|
|
287
|
+
message = asRecord(JSON.parse(line));
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// A malformed line must not kill unrelated in-flight requests.
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!message)
|
|
294
|
+
continue;
|
|
295
|
+
this.dispatch(message);
|
|
296
|
+
}
|
|
297
|
+
if (this.buffer.length > this.maxFrameBytes) {
|
|
298
|
+
this.failAll(`Headless worker sent an un-terminated frame larger than ${this.maxFrameBytes} bytes; ` +
|
|
299
|
+
"closing the connection.");
|
|
300
|
+
this.socket.destroy();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
dispatch(message) {
|
|
304
|
+
const id = typeof message.id === "number" && Number.isInteger(message.id)
|
|
305
|
+
? message.id
|
|
306
|
+
: null;
|
|
307
|
+
if (!id)
|
|
308
|
+
return;
|
|
309
|
+
const pending = this.pending.get(id);
|
|
310
|
+
if (!pending)
|
|
311
|
+
return;
|
|
312
|
+
if (message.event === "progress") {
|
|
313
|
+
// Liveness: progress restarts the inactivity timer, so a long op that
|
|
314
|
+
// keeps reporting never times out spuriously.
|
|
315
|
+
pending.restartTimer();
|
|
316
|
+
try {
|
|
317
|
+
pending.onProgress?.(message.progress);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// A progress observer must never break the request itself.
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
this.pending.delete(id);
|
|
325
|
+
if (pending.timer)
|
|
326
|
+
clearTimeout(pending.timer);
|
|
327
|
+
if (message.ok === true) {
|
|
328
|
+
pending.resolve(message.result);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
const error = typeof message.error === "string" && message.error.length > 0
|
|
332
|
+
? this.scrub(message.error)
|
|
333
|
+
: "Headless worker reported an unspecified error.";
|
|
334
|
+
// WorkerOpError carries a `.code` (sha256_mismatch / already_exists /
|
|
335
|
+
// needs_display / ...) when the worker sent a structured classifier,
|
|
336
|
+
// so guard failures are distinguishable from transport throws.
|
|
337
|
+
pending.reject(new WorkerOpError(error));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
failAll(reason) {
|
|
341
|
+
if (!this.alive)
|
|
342
|
+
return;
|
|
343
|
+
this.alive = false;
|
|
344
|
+
this.closeReason = this.scrub(reason);
|
|
345
|
+
const failures = [...this.pending.values()];
|
|
346
|
+
this.pending.clear();
|
|
347
|
+
for (const pending of failures) {
|
|
348
|
+
if (pending.timer)
|
|
349
|
+
clearTimeout(pending.timer);
|
|
350
|
+
pending.reject(new Error(`${this.closeReason} The in-flight operation's final state is unknown; do not retry blindly.`));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|