summer-engine 3.0.0 → 3.2.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 +2 -2
- package/.claude-plugin/plugin.json +27 -5
- package/.codex-plugin/plugin.json +28 -6
- package/.cursor-plugin/plugin.json +27 -5
- package/.factory-plugin/plugin.json +27 -5
- package/.opencode/plugins/summer.js +1 -1
- package/CHANGELOG.md +120 -0
- package/README.md +22 -7
- package/assets/audit/scene_audit.gd +4136 -0
- package/assets/seeing/seeing_probe.gd +1873 -0
- package/dist/cli/commands/setup.js +6 -19
- package/dist/cli/commands/skills.js +57 -32
- package/dist/core/api-client.d.ts +9 -1
- package/dist/core/api-client.js +21 -4
- package/dist/core/capabilities/agent-playbook.js +46 -0
- package/dist/core/capabilities/audit/accept.d.ts +55 -0
- package/dist/core/capabilities/audit/accept.js +147 -0
- package/dist/core/capabilities/audit/args.d.ts +95 -0
- package/dist/core/capabilities/audit/args.js +89 -0
- package/dist/core/capabilities/audit/audit.d.ts +56 -0
- package/dist/core/capabilities/audit/audit.js +287 -0
- package/dist/core/capabilities/audit/frame.d.ts +14 -0
- package/dist/core/capabilities/audit/frame.js +35 -0
- package/dist/core/capabilities/audit/gaps.d.ts +96 -0
- package/dist/core/capabilities/audit/gaps.js +257 -0
- package/dist/core/capabilities/audit/judge.d.ts +162 -0
- package/dist/core/capabilities/audit/judge.js +1134 -0
- package/dist/core/capabilities/audit/math.d.ts +110 -0
- package/dist/core/capabilities/audit/math.js +263 -0
- package/dist/core/capabilities/audit/summary.d.ts +74 -0
- package/dist/core/capabilities/audit/summary.js +212 -0
- package/dist/core/capabilities/board.d.ts +31 -0
- package/dist/core/capabilities/board.js +43 -0
- package/dist/core/capabilities/camera-view.d.ts +4 -2
- package/dist/core/capabilities/camera-view.js +6 -3
- package/dist/core/capabilities/connect-signal.d.ts +85 -0
- package/dist/core/capabilities/connect-signal.js +285 -0
- package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
- package/dist/core/capabilities/engine-fallbacks.js +5 -0
- package/dist/core/capabilities/engine-ops.d.ts +5 -1
- package/dist/core/capabilities/engine-ops.js +0 -3
- package/dist/core/capabilities/engine-receipt.d.ts +12 -0
- package/dist/core/capabilities/engine-receipt.js +26 -0
- package/dist/core/capabilities/file-read.d.ts +64 -0
- package/dist/core/capabilities/file-read.js +325 -0
- package/dist/core/capabilities/game-task-plan.js +4 -2
- package/dist/core/capabilities/grep.d.ts +60 -0
- package/dist/core/capabilities/grep.js +190 -0
- package/dist/core/capabilities/inspect-node.d.ts +56 -0
- package/dist/core/capabilities/inspect-node.js +225 -0
- package/dist/core/capabilities/inspect-resource.d.ts +61 -0
- package/dist/core/capabilities/inspect-resource.js +376 -0
- package/dist/core/capabilities/math3d.d.ts +28 -0
- package/dist/core/capabilities/math3d.js +88 -0
- package/dist/core/capabilities/motion-generation.d.ts +62 -0
- package/dist/core/capabilities/motion-generation.js +138 -0
- package/dist/core/capabilities/placement-batch.d.ts +102 -0
- package/dist/core/capabilities/placement-batch.js +483 -0
- package/dist/core/capabilities/placement-math.d.ts +70 -0
- package/dist/core/capabilities/placement-math.js +209 -0
- package/dist/core/capabilities/placement-script.d.ts +42 -0
- package/dist/core/capabilities/placement-script.js +1096 -0
- package/dist/core/capabilities/placement.d.ts +485 -0
- package/dist/core/capabilities/placement.js +1731 -0
- package/dist/core/capabilities/project-context.d.ts +33 -2
- package/dist/core/capabilities/project-context.js +87 -4
- package/dist/core/capabilities/replace-node.d.ts +91 -0
- package/dist/core/capabilities/replace-node.js +423 -0
- package/dist/core/capabilities/runtime-control.d.ts +20 -4
- package/dist/core/capabilities/runtime-control.js +67 -2
- package/dist/core/capabilities/scene-batch.d.ts +63 -0
- package/dist/core/capabilities/scene-batch.js +394 -0
- package/dist/core/capabilities/scene-readback.d.ts +36 -0
- package/dist/core/capabilities/scene-readback.js +54 -0
- package/dist/core/capabilities/seeing/args.d.ts +348 -0
- package/dist/core/capabilities/seeing/args.js +178 -0
- package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
- package/dist/core/capabilities/seeing/candidates.js +282 -0
- package/dist/core/capabilities/seeing/math.d.ts +134 -0
- package/dist/core/capabilities/seeing/math.js +269 -0
- package/dist/core/capabilities/seeing/probe.d.ts +62 -0
- package/dist/core/capabilities/seeing/probe.js +188 -0
- package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
- package/dist/core/capabilities/seeing/scoring.js +639 -0
- package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
- package/dist/core/capabilities/seeing/seeing.js +1341 -0
- package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
- package/dist/core/capabilities/seeing/shot-store.js +204 -0
- package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
- package/dist/core/capabilities/surface-snap-mesh.js +425 -0
- package/dist/core/capabilities/surface-snap.d.ts +77 -0
- package/dist/core/capabilities/surface-snap.js +461 -0
- package/dist/core/capabilities/tool-dispatch.js +231 -72
- package/dist/core/capabilities/tscn.d.ts +85 -0
- package/dist/core/capabilities/tscn.js +391 -0
- package/dist/core/capabilities/world-snapshot.d.ts +58 -0
- package/dist/core/capabilities/world-snapshot.js +150 -0
- package/dist/core/capability-skew.d.ts +5 -5
- package/dist/core/capability-skew.js +14 -6
- package/dist/core/headless/worker-engine-client.d.ts +1 -1
- package/dist/core/headless/worker-engine-client.js +2 -2
- package/dist/core/library-read.d.ts +37 -5
- package/dist/core/library-read.js +264 -33
- package/dist/core/library-search.d.ts +2 -2
- package/dist/core/skills-registry.d.ts +9 -1
- package/dist/core/skills-registry.js +25 -2
- package/dist/installer/agent-config.d.ts +9 -4
- package/dist/installer/agent-config.js +194 -392
- package/dist/installer/agent-table.d.ts +119 -0
- package/dist/installer/agent-table.js +619 -0
- package/dist/installer/setup.js +4 -2
- package/dist/installer/skill-locations.d.ts +8 -17
- package/dist/installer/skill-locations.js +22 -101
- package/dist/installer/version-check.d.ts +5 -1
- package/dist/installer/version-check.js +38 -28
- package/dist/mcp/server.js +9 -3
- package/dist/mcp/tools/asset-tools.js +21 -3
- package/dist/mcp/tools/audit-tools.d.ts +23 -0
- package/dist/mcp/tools/audit-tools.js +60 -0
- package/dist/mcp/tools/debug-tools.js +3 -1
- package/dist/mcp/tools/file-tools.js +17 -4
- package/dist/mcp/tools/generate-tools.js +74 -66
- package/dist/mcp/tools/library-tools.js +2 -0
- package/dist/mcp/tools/perception-tools.js +6 -19
- package/dist/mcp/tools/placement-tools.d.ts +24 -0
- package/dist/mcp/tools/placement-tools.js +91 -0
- package/dist/mcp/tools/project-tools.js +18 -15
- package/dist/mcp/tools/scene-tools.js +71 -83
- package/dist/mcp/tools/seeing-tools.d.ts +24 -0
- package/dist/mcp/tools/seeing-tools.js +64 -0
- package/dist/mcp/tools/spatial-tools.js +17 -9
- package/dist/mcp/tools/visual-tools.js +59 -7
- package/gemini-extension.json +26 -4
- package/integrations/README.md +48 -19
- 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-desktop/README.md +12 -0
- package/integrations/claude-desktop/manifest-target.json +3 -0
- package/integrations/cline/README.md +8 -9
- package/integrations/cline-cli/README.md +12 -0
- package/integrations/cline-cli/manifest-target.json +3 -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/github-copilot/README.md +8 -8
- 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 +6 -10
- 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 +8 -8
- package/integrations/mistral-vibe/README.md +12 -0
- package/integrations/mistral-vibe/manifest-target.json +3 -0
- package/integrations/opencode/README.md +9 -12
- 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 +8 -7
- 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 +9 -9
- package/integrations/warp/README.md +12 -0
- package/integrations/warp/manifest-target.json +3 -0
- package/integrations/windsurf/README.md +8 -9
- package/integrations/zed/README.md +12 -0
- package/integrations/zed/manifest-target.json +3 -0
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
- package/library/references/mcp-tools-reference/resource.yaml +1 -1
- package/library/references/summer-folder/resource.yaml +1 -1
- package/library/references/summer-folder/summer-folder.md +1 -1
- package/library/skills/3d-lighting/SKILL.md +1 -1
- package/library/skills/README.md +264 -0
- package/library/skills/adaptive-music/SKILL.md +1 -1
- package/library/skills/agent-playtesting/SKILL.md +1 -1
- package/library/skills/ai-characters-in-games/SKILL.md +220 -0
- package/library/skills/ai-characters-in-games/resource.yaml +30 -0
- package/library/skills/ambient-bed/SKILL.md +1 -1
- package/library/skills/animated-loop/SKILL.md +1 -1
- package/library/skills/animation-tree/SKILL.md +1 -1
- package/library/skills/art-direction/SKILL.md +1 -1
- package/library/skills/asset-strategy/SKILL.md +2 -1
- package/library/skills/asset-strategy/resource.yaml +2 -1
- package/library/skills/audio-direction/SKILL.md +1 -1
- package/library/skills/auto-fire-targeting/SKILL.md +1 -1
- package/library/skills/brainstorm-game/SKILL.md +1 -1
- package/library/skills/brainstorming/SKILL.md +1 -1
- package/library/skills/browse-templates/SKILL.md +3 -3
- package/library/skills/browse-templates/resource.yaml +1 -1
- package/library/skills/camera-rigs/SKILL.md +128 -0
- package/library/skills/camera-rigs/resource.yaml +29 -0
- package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
- package/library/skills/character-animation-wiring/SKILL.md +1 -1
- package/library/skills/character-model/SKILL.md +1 -1
- package/library/skills/character-movement/SKILL.md +326 -0
- package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
- package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
- package/library/skills/character-movement/references/movement-3d.md +136 -0
- package/library/skills/character-movement/references/platformer-feel.md +83 -0
- package/library/skills/character-movement/resource.yaml +40 -0
- package/library/skills/character-portrait/SKILL.md +1 -1
- package/library/skills/cinematic-cutscene/SKILL.md +1 -1
- package/library/skills/combat-basics/SKILL.md +159 -0
- package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
- package/library/skills/combat-basics/resource.yaml +34 -0
- package/library/skills/concept-art/SKILL.md +1 -1
- package/library/skills/create-asset-sheet/SKILL.md +1 -1
- package/library/skills/debug/SKILL.md +1 -1
- package/library/skills/debugging-game-feel/SKILL.md +1 -1
- package/library/skills/design-level/SKILL.md +1 -1
- package/library/skills/design-mechanic/SKILL.md +1 -1
- package/library/skills/design-npc/SKILL.md +1 -1
- package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
- package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
- package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
- package/library/skills/environment-kit/SKILL.md +1 -1
- package/library/skills/export-and-ship/SKILL.md +1 -1
- package/library/skills/fabricating-assets/SKILL.md +1 -1
- package/library/skills/facial-and-lipsync/SKILL.md +1 -1
- package/library/skills/fps-controller/SKILL.md +9 -7
- package/library/skills/fps-controller/resource.yaml +4 -1
- package/library/skills/game-feel/SKILL.md +1 -1
- package/library/skills/gameskill/SKILL.md +1 -1
- package/library/skills/gdscript-patterns/SKILL.md +1 -1
- package/library/skills/generate-motion/SKILL.md +9 -9
- package/library/skills/generate-motion/resource.yaml +2 -1
- package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
- package/library/skills/headless-scripting/SKILL.md +1 -1
- package/library/skills/in-game-purchases/SKILL.md +254 -0
- package/library/skills/in-game-purchases/resource.yaml +29 -0
- package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
- package/library/skills/investigating-bugs/SKILL.md +1 -1
- package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
- package/library/skills/make-game/SKILL.md +25 -3
- package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
- package/library/skills/make-game/references/2d-platformer.md +117 -0
- package/library/skills/make-game/references/2d-rpg-content.md +234 -0
- package/library/skills/make-game/references/2d-rpg.md +241 -0
- package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
- package/library/skills/make-game/references/2d-survivors.md +237 -0
- package/library/skills/make-game/references/3d-fps-systems.md +216 -0
- package/library/skills/make-game/references/3d-fps.md +177 -0
- package/library/skills/make-game/references/3d-horror-systems.md +186 -0
- package/library/skills/make-game/references/3d-horror.md +201 -0
- package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
- package/library/skills/make-game/references/3d-third-person.md +215 -0
- package/library/skills/make-game/resource.yaml +6 -1
- package/library/skills/multiplayer/SKILL.md +150 -0
- package/library/skills/multiplayer/resource.yaml +33 -0
- package/library/skills/multiplayer-movement/SKILL.md +510 -0
- package/library/skills/multiplayer-movement/files.md +501 -0
- package/library/skills/multiplayer-movement/resource.yaml +30 -0
- package/library/skills/multiplayer-project/SKILL.md +521 -0
- package/library/skills/multiplayer-project/files.md +448 -0
- package/library/skills/multiplayer-project/resource.yaml +36 -0
- package/library/skills/multiplayer-publish/SKILL.md +229 -0
- package/library/skills/multiplayer-publish/export-errors.md +89 -0
- package/library/skills/multiplayer-publish/resource.yaml +28 -0
- package/library/skills/multiplayer-state/SKILL.md +438 -0
- package/library/skills/multiplayer-state/files.md +592 -0
- package/library/skills/multiplayer-state/resource.yaml +35 -0
- package/library/skills/multiplayer-testing/SKILL.md +236 -0
- package/library/skills/multiplayer-testing/resource.yaml +39 -0
- package/library/skills/music-track/SKILL.md +1 -1
- package/library/skills/navigate-summer/SKILL.md +1 -1
- package/library/skills/new-project/SKILL.md +1 -1
- package/library/skills/organic-model/SKILL.md +1 -1
- package/library/skills/pixel-art/SKILL.md +1 -1
- package/library/skills/play/SKILL.md +1 -1
- package/library/skills/playtesting-a-feature/SKILL.md +1 -1
- package/library/skills/procedural-animation/SKILL.md +2 -2
- package/library/skills/procedural-animation/resource.yaml +1 -1
- package/library/skills/prop-model/SKILL.md +1 -1
- package/library/skills/psx-retro-rendering/SKILL.md +1 -1
- package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
- package/library/skills/remote-deploy/SKILL.md +1 -1
- package/library/skills/retarget/SKILL.md +1 -1
- package/library/skills/running-in-the-cloud/SKILL.md +1 -1
- package/library/skills/save-load/SKILL.md +156 -0
- package/library/skills/save-load/resource.yaml +27 -0
- package/library/skills/scene-composition/SKILL.md +1 -1
- package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
- package/library/skills/scene-scripting/SKILL.md +1 -1
- package/library/skills/scene-to-level/SKILL.md +1 -1
- package/library/skills/skill-create/SKILL.md +1 -1
- package/library/skills/skill-improve/SKILL.md +1 -1
- package/library/skills/skill-test/SKILL.md +1 -1
- package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
- package/library/skills/skybox-panorama/SKILL.md +1 -1
- package/library/skills/sound-effect/SKILL.md +1 -1
- package/library/skills/spatial-placement/SKILL.md +134 -3
- package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
- package/library/skills/spatial-placement/resource.yaml +16 -2
- package/library/skills/sprite-sheet/SKILL.md +1 -1
- package/library/skills/summer-analytics/SKILL.md +147 -0
- package/library/skills/summer-analytics/resource.yaml +28 -0
- package/library/skills/summer-friends/SKILL.md +226 -0
- package/library/skills/summer-friends/resource.yaml +28 -0
- package/library/skills/summer-leaderboards/SKILL.md +231 -0
- package/library/skills/summer-leaderboards/resource.yaml +30 -0
- package/library/skills/summer-match-results/SKILL.md +286 -0
- package/library/skills/summer-match-results/resource.yaml +32 -0
- package/library/skills/summer-matchmaking/SKILL.md +301 -0
- package/library/skills/summer-matchmaking/resource.yaml +32 -0
- package/library/skills/summer-parties/SKILL.md +253 -0
- package/library/skills/summer-parties/resource.yaml +30 -0
- package/library/skills/summer-player-data/SKILL.md +322 -0
- package/library/skills/summer-player-data/resource.yaml +30 -0
- package/library/skills/summer-store/SKILL.md +271 -0
- package/library/skills/summer-store/resource.yaml +29 -0
- package/library/skills/summer-world-chat/SKILL.md +195 -0
- package/library/skills/summer-world-chat/resource.yaml +30 -0
- package/library/skills/summer-world-saves/SKILL.md +284 -0
- package/library/skills/summer-world-saves/resource.yaml +29 -0
- package/library/skills/text-to-motion/SKILL.md +99 -0
- package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
- package/library/skills/text-to-motion/resource.yaml +41 -0
- package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
- package/library/skills/tileable-texture/SKILL.md +1 -1
- package/library/skills/trailer-shot/SKILL.md +1 -1
- package/library/skills/tune-performance/SKILL.md +1 -1
- package/library/skills/ui-basics/SKILL.md +10 -1
- package/library/skills/ui-graphics/SKILL.md +1 -1
- package/library/skills/use-widget-asset/SKILL.md +1 -1
- package/library/skills/using-summer/SKILL.md +2 -2
- package/library/skills/using-summer/resource.yaml +2 -2
- package/library/skills/vehicle-model/SKILL.md +1 -1
- package/library/skills/verification-before-completion/SKILL.md +1 -1
- package/library/skills/verifying-scenes/SKILL.md +76 -2
- package/library/skills/verifying-scenes/resource.yaml +13 -2
- package/library/skills/vfx-dissolve/SKILL.md +1 -1
- package/library/skills/vfx-fire/SKILL.md +1 -1
- package/library/skills/vfx-hit-spark/SKILL.md +1 -1
- package/library/skills/vfx-lightning/SKILL.md +1 -1
- package/library/skills/vfx-magic-glow/SKILL.md +1 -1
- package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
- package/library/skills/vfx-smoke/SKILL.md +1 -1
- package/library/skills/vfx-water-ripple/SKILL.md +1 -1
- package/library/skills/voice-line/SKILL.md +1 -1
- package/library/skills/web-and-touch-input/SKILL.md +38 -0
- package/library/skills/web-and-touch-input/resource.yaml +28 -0
- package/library/skills/web-compatibility-look/SKILL.md +62 -0
- package/library/skills/web-compatibility-look/resource.yaml +30 -0
- package/library/skills/world-building-3d/SKILL.md +8 -1
- package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
- package/library/skills/world-building-3d/resource.yaml +2 -1
- package/library/skills/writing-plans/SKILL.md +1 -1
- package/library/skills/writing-skills/SKILL.md +1 -1
- package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
- package/library/tools/attach-to-surface/resource.yaml +142 -0
- package/library/tools/batch/resource.yaml +9 -3
- package/library/tools/connect-ports/resource.yaml +120 -0
- package/library/tools/connect-signal/resource.yaml +3 -2
- package/library/tools/debug-views/resource.yaml +94 -0
- package/library/tools/frame-nodes/resource.yaml +104 -0
- package/library/tools/frame-shot/resource.yaml +134 -0
- package/library/tools/generate-motion/resource.yaml +44 -9
- package/library/tools/get-board/resource.yaml +50 -0
- package/library/tools/get-project-context/resource.yaml +13 -2
- package/library/tools/grep/resource.yaml +77 -0
- package/library/tools/inspect-asset/resource.yaml +71 -0
- package/library/tools/inspect-node/resource.yaml +9 -2
- package/library/tools/inspect-resource/resource.yaml +16 -5
- package/library/tools/instantiate-scene/resource.yaml +27 -2
- package/library/tools/measure/resource.yaml +96 -0
- package/library/tools/place-adjacent/resource.yaml +113 -0
- package/library/tools/play/resource.yaml +15 -2
- package/library/tools/raycast/resource.yaml +101 -0
- package/library/tools/read-file/resource.yaml +36 -2
- package/library/tools/read-library/resource.yaml +2 -2
- package/library/tools/repeat-along/resource.yaml +129 -0
- package/library/tools/replace-node/resource.yaml +11 -5
- package/library/tools/scene-audit/resource.yaml +144 -0
- package/library/tools/screenshot/resource.yaml +13 -2
- package/library/tools/search-assets/resource.yaml +18 -0
- package/library/tools/shot-sheet/resource.yaml +110 -0
- package/library/tools/snap-to-surface/resource.yaml +4 -1
- package/library/tools/world-snapshot/resource.yaml +24 -3
- package/library/tools/zoom/resource.yaml +105 -0
- package/package.json +3 -3
- package/registry/generated/aliases.json +17 -3
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +26 -4
- package/registry/generated/index.json +2154 -469
- package/registry/generated/marketplace.claude.json +2 -2
- package/registry/generated/plugin.claude.json +27 -5
- package/registry/generated/plugin.codex.json +28 -6
- package/registry/generated/plugin.cursor.json +27 -5
- package/registry/generated/plugin.factory.json +27 -5
- package/registry/generated/skills-index.md +264 -0
- package/registry/generated/skills-registry.json +901 -206
- package/registry/generated/templates-registry.json +2 -2
- package/library/skills/host-authoritative-state/SKILL.md +0 -332
- package/library/skills/host-authoritative-state/resource.yaml +0 -28
- package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
- package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
- package/library/skills/setup-multiplayer/SKILL.md +0 -336
- package/library/skills/setup-multiplayer/resource.yaml +0 -28
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument shape for summer_scene_audit — ONE copy for both faces (the MCP
|
|
3
|
+
* registration in src/mcp/tools/audit-tools.ts and `summer tool scene-audit`
|
|
4
|
+
* in tool-dispatch.ts). The descriptions are the docs agents read.
|
|
5
|
+
*
|
|
6
|
+
* Strings that name scene content are validated again in audit.ts with the
|
|
7
|
+
* seeing tools' strict patterns before anything is sent; they reach the
|
|
8
|
+
* engine only as JSON data in config.json, never as source.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export declare const AUDIT_CHECKS: readonly ["through_hole", "floor_gap", "floating", "sunken", "interpenetration", "exposed_edge", "open_fixture_end", "orientation", "uv_stretch", "duplicate", "z_fight", "depth_step", "lights", "transform", "resource"];
|
|
12
|
+
export type AuditCheck = (typeof AUDIT_CHECKS)[number];
|
|
13
|
+
export declare const SEVERITIES: readonly ["error", "warn", "look"];
|
|
14
|
+
export type Severity = (typeof SEVERITIES)[number];
|
|
15
|
+
export declare const AUDIT_DEFAULT_LIMIT = 15;
|
|
16
|
+
export declare const AUDIT_MAX_LIMIT = 50;
|
|
17
|
+
/** Editor time the checks may take before the slow ones stop early (partial). */
|
|
18
|
+
export declare const AUDIT_DEFAULT_BUDGET_MS = 3000;
|
|
19
|
+
export declare const AUDIT_MIN_BUDGET_MS = 250;
|
|
20
|
+
export declare const AUDIT_MAX_BUDGET_MS = 60000;
|
|
21
|
+
export declare const AUDIT_MAX_ACCEPT = 50;
|
|
22
|
+
/** An issue key: check:node path@x,y,z (world position rounded to 0.1 m;
|
|
23
|
+
* node names never contain ":" or "@"). */
|
|
24
|
+
export declare const ISSUE_KEY_PATTERN: RegExp;
|
|
25
|
+
export declare const sceneAuditShape: {
|
|
26
|
+
scenePath: z.ZodOptional<z.ZodString>;
|
|
27
|
+
checks: z.ZodOptional<z.ZodArray<z.ZodEnum<["through_hole", "floor_gap", "floating", "sunken", "interpenetration", "exposed_edge", "open_fixture_end", "orientation", "uv_stretch", "duplicate", "z_fight", "depth_step", "lights", "transform", "resource"]>, "many">>;
|
|
28
|
+
root: z.ZodOptional<z.ZodString>;
|
|
29
|
+
min_severity: z.ZodOptional<z.ZodEnum<["error", "warn", "look"]>>;
|
|
30
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
budget_ms: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
accept: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
34
|
+
key: z.ZodString;
|
|
35
|
+
reason: z.ZodString;
|
|
36
|
+
}, "strict", z.ZodTypeAny, {
|
|
37
|
+
reason: string;
|
|
38
|
+
key: string;
|
|
39
|
+
}, {
|
|
40
|
+
reason: string;
|
|
41
|
+
key: string;
|
|
42
|
+
}>, "many">>;
|
|
43
|
+
show_accepted: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
render: z.ZodOptional<z.ZodEnum<["sheet", "none"]>>;
|
|
45
|
+
};
|
|
46
|
+
export declare const sceneAuditArgsSchema: z.ZodObject<{
|
|
47
|
+
scenePath: z.ZodOptional<z.ZodString>;
|
|
48
|
+
checks: z.ZodOptional<z.ZodArray<z.ZodEnum<["through_hole", "floor_gap", "floating", "sunken", "interpenetration", "exposed_edge", "open_fixture_end", "orientation", "uv_stretch", "duplicate", "z_fight", "depth_step", "lights", "transform", "resource"]>, "many">>;
|
|
49
|
+
root: z.ZodOptional<z.ZodString>;
|
|
50
|
+
min_severity: z.ZodOptional<z.ZodEnum<["error", "warn", "look"]>>;
|
|
51
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
budget_ms: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
accept: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
55
|
+
key: z.ZodString;
|
|
56
|
+
reason: z.ZodString;
|
|
57
|
+
}, "strict", z.ZodTypeAny, {
|
|
58
|
+
reason: string;
|
|
59
|
+
key: string;
|
|
60
|
+
}, {
|
|
61
|
+
reason: string;
|
|
62
|
+
key: string;
|
|
63
|
+
}>, "many">>;
|
|
64
|
+
show_accepted: z.ZodOptional<z.ZodBoolean>;
|
|
65
|
+
render: z.ZodOptional<z.ZodEnum<["sheet", "none"]>>;
|
|
66
|
+
}, "strict", z.ZodTypeAny, {
|
|
67
|
+
limit?: number | undefined;
|
|
68
|
+
root?: string | undefined;
|
|
69
|
+
scenePath?: string | undefined;
|
|
70
|
+
accept?: {
|
|
71
|
+
reason: string;
|
|
72
|
+
key: string;
|
|
73
|
+
}[] | undefined;
|
|
74
|
+
render?: "none" | "sheet" | undefined;
|
|
75
|
+
checks?: ("through_hole" | "floor_gap" | "floating" | "sunken" | "interpenetration" | "exposed_edge" | "open_fixture_end" | "orientation" | "uv_stretch" | "duplicate" | "z_fight" | "depth_step" | "lights" | "transform" | "resource")[] | undefined;
|
|
76
|
+
min_severity?: "error" | "warn" | "look" | undefined;
|
|
77
|
+
offset?: number | undefined;
|
|
78
|
+
budget_ms?: number | undefined;
|
|
79
|
+
show_accepted?: boolean | undefined;
|
|
80
|
+
}, {
|
|
81
|
+
limit?: number | undefined;
|
|
82
|
+
root?: string | undefined;
|
|
83
|
+
scenePath?: string | undefined;
|
|
84
|
+
accept?: {
|
|
85
|
+
reason: string;
|
|
86
|
+
key: string;
|
|
87
|
+
}[] | undefined;
|
|
88
|
+
render?: "none" | "sheet" | undefined;
|
|
89
|
+
checks?: ("through_hole" | "floor_gap" | "floating" | "sunken" | "interpenetration" | "exposed_edge" | "open_fixture_end" | "orientation" | "uv_stretch" | "duplicate" | "z_fight" | "depth_step" | "lights" | "transform" | "resource")[] | undefined;
|
|
90
|
+
min_severity?: "error" | "warn" | "look" | undefined;
|
|
91
|
+
offset?: number | undefined;
|
|
92
|
+
budget_ms?: number | undefined;
|
|
93
|
+
show_accepted?: boolean | undefined;
|
|
94
|
+
}>;
|
|
95
|
+
export type SceneAuditArgs = z.output<typeof sceneAuditArgsSchema>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument shape for summer_scene_audit — ONE copy for both faces (the MCP
|
|
3
|
+
* registration in src/mcp/tools/audit-tools.ts and `summer tool scene-audit`
|
|
4
|
+
* in tool-dispatch.ts). The descriptions are the docs agents read.
|
|
5
|
+
*
|
|
6
|
+
* Strings that name scene content are validated again in audit.ts with the
|
|
7
|
+
* seeing tools' strict patterns before anything is sent; they reach the
|
|
8
|
+
* engine only as JSON data in config.json, never as source.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export const AUDIT_CHECKS = [
|
|
12
|
+
"through_hole",
|
|
13
|
+
"floor_gap",
|
|
14
|
+
"floating",
|
|
15
|
+
"sunken",
|
|
16
|
+
"interpenetration",
|
|
17
|
+
"exposed_edge",
|
|
18
|
+
"open_fixture_end",
|
|
19
|
+
"orientation",
|
|
20
|
+
"uv_stretch",
|
|
21
|
+
"duplicate",
|
|
22
|
+
"z_fight",
|
|
23
|
+
"depth_step",
|
|
24
|
+
"lights",
|
|
25
|
+
"transform",
|
|
26
|
+
"resource",
|
|
27
|
+
];
|
|
28
|
+
export const SEVERITIES = ["error", "warn", "look"];
|
|
29
|
+
export const AUDIT_DEFAULT_LIMIT = 15;
|
|
30
|
+
export const AUDIT_MAX_LIMIT = 50;
|
|
31
|
+
/** Editor time the checks may take before the slow ones stop early (partial). */
|
|
32
|
+
export const AUDIT_DEFAULT_BUDGET_MS = 3000;
|
|
33
|
+
export const AUDIT_MIN_BUDGET_MS = 250;
|
|
34
|
+
export const AUDIT_MAX_BUDGET_MS = 60000;
|
|
35
|
+
export const AUDIT_MAX_ACCEPT = 50;
|
|
36
|
+
/** An issue key: check:node path@x,y,z (world position rounded to 0.1 m;
|
|
37
|
+
* node names never contain ":" or "@"). */
|
|
38
|
+
export const ISSUE_KEY_PATTERN = /^[a-z_]{3,24}:[^:@\n\r"\\]{1,300}@-?\d+(?:\.\d)?,-?\d+(?:\.\d)?,-?\d+(?:\.\d)?$/;
|
|
39
|
+
export const sceneAuditShape = {
|
|
40
|
+
scenePath: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Scene to audit, e.g. "res://levels/town.tscn" (the SAVED file). Omit for the scene open in the editor.'),
|
|
44
|
+
checks: z
|
|
45
|
+
.array(z.enum(AUDIT_CHECKS))
|
|
46
|
+
.min(1)
|
|
47
|
+
.max(AUDIT_CHECKS.length)
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Only these checks (default: all 15). through_hole, floor_gap, floating, sunken, interpenetration, exposed_edge, open_fixture_end, orientation, uv_stretch, duplicate, z_fight, depth_step, lights, transform, resource. Fewer checks run faster (duplicate, lights, transform and resource need no physics); rerun a check budget_ms left partial on its own."),
|
|
50
|
+
root: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Report only issues under this node (subtree), e.g. "Block3". The whole scene is still loaded so walls and floors outside it count as surroundings.'),
|
|
54
|
+
min_severity: z
|
|
55
|
+
.enum(SEVERITIES)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('"error" (only errors), "warn" (errors and warnings) or "look" (default: everything, including look items that only ask you to look).'),
|
|
58
|
+
offset: z.number().int().min(0).max(100000).optional().describe("Skip this many issues of the sorted, filtered list (paging; the result names the next offset)."),
|
|
59
|
+
limit: z
|
|
60
|
+
.number()
|
|
61
|
+
.int()
|
|
62
|
+
.min(1)
|
|
63
|
+
.max(AUDIT_MAX_LIMIT)
|
|
64
|
+
.optional()
|
|
65
|
+
.describe(`Issues per page (default ${AUDIT_DEFAULT_LIMIT}, max ${AUDIT_MAX_LIMIT}). The result is capped at 5 KB; a page that does not fit is cut and says so.`),
|
|
66
|
+
budget_ms: z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.min(AUDIT_MIN_BUDGET_MS)
|
|
70
|
+
.max(AUDIT_MAX_BUDGET_MS)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe(`Editor time for the whole audit (default ${AUDIT_DEFAULT_BUDGET_MS} ms, ${AUDIT_MIN_BUDGET_MS}-${AUDIT_MAX_BUDGET_MS}). Each check gets a share weighted by its usual cost (unused time passes on); a check past its share stops and counts.<check>.partial gives the share it covered. Under load, rerun the partial checks with checks:[...] or a larger budget.`),
|
|
73
|
+
accept: z
|
|
74
|
+
.array(z
|
|
75
|
+
.object({
|
|
76
|
+
key: z.string().min(8).max(360).describe("The issue's key from a previous result (issues[].key)."),
|
|
77
|
+
reason: z.string().min(3).max(200).describe("Why it is fine, e.g. \"coplanar faces hidden behind a sign\"."),
|
|
78
|
+
})
|
|
79
|
+
.strict())
|
|
80
|
+
.max(AUDIT_MAX_ACCEPT)
|
|
81
|
+
.optional()
|
|
82
|
+
.describe(`Accept look or warn items you judged fine (up to ${AUDIT_MAX_ACCEPT} per call): [{key, reason}] with keys from this scene's issues. They are written to res://.summer/audit-accept.json (the only file the audit writes), then counted (counts.<check>.accepted) but hidden on every later audit, until their evidence changes materially (severity rises, or the measured size moves by over 25%): then they show again with accept_stale. Errors cannot be accepted.`),
|
|
83
|
+
show_accepted: z.boolean().optional().describe("List accepted items too (each with its accepted reason). Default false: hidden, only counted."),
|
|
84
|
+
render: z
|
|
85
|
+
.enum(["sheet", "none"])
|
|
86
|
+
.optional()
|
|
87
|
+
.describe('"sheet": also return ONE inline image of the first 6 issues of this page framed up close from their open side, each tile labelled with its issue number. Default "none" (no image).'),
|
|
88
|
+
};
|
|
89
|
+
export const sceneAuditArgsSchema = z.object(sceneAuditShape).strict();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type CapabilityAdvertisingClient } from "../../capability-skew.js";
|
|
2
|
+
import { type SeeingImage } from "../seeing/seeing.js";
|
|
3
|
+
import { type ProbeClient } from "../seeing/probe.js";
|
|
4
|
+
import { type AuditCheck, type SceneAuditArgs, type Severity } from "./args.js";
|
|
5
|
+
import { type AuditIssue, type KernelResult } from "./judge.js";
|
|
6
|
+
export declare const AUDIT_KERNEL_PATH: string;
|
|
7
|
+
export declare function loadAuditKernel(): string;
|
|
8
|
+
export declare const AUDIT_FALLBACK = "read the scene with summer_world_snapshot and look with summer_frame_nodes / summer_shot_sheet; cast single rays with summer_raycast";
|
|
9
|
+
export interface AuditClient extends ProbeClient, CapabilityAdvertisingClient {
|
|
10
|
+
getSceneState(scenePath?: string, options?: {
|
|
11
|
+
depth?: number;
|
|
12
|
+
limit?: number;
|
|
13
|
+
}): Promise<unknown>;
|
|
14
|
+
getProjectRoot?(): string | undefined;
|
|
15
|
+
}
|
|
16
|
+
export interface AuditSuccess {
|
|
17
|
+
ok: true;
|
|
18
|
+
/** The page: at most 5 KB of JSON. */
|
|
19
|
+
summary: Record<string, unknown>;
|
|
20
|
+
image: SeeingImage | null;
|
|
21
|
+
}
|
|
22
|
+
export interface AuditFailure {
|
|
23
|
+
ok: false;
|
|
24
|
+
failure_reason: string;
|
|
25
|
+
error: string;
|
|
26
|
+
hint?: string;
|
|
27
|
+
detail?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
export type AuditResult = AuditSuccess | AuditFailure;
|
|
30
|
+
export interface ValidatedAuditArgs {
|
|
31
|
+
scenePath?: string;
|
|
32
|
+
checks: AuditCheck[];
|
|
33
|
+
root?: string;
|
|
34
|
+
minSeverity: Severity;
|
|
35
|
+
offset: number;
|
|
36
|
+
limit: number;
|
|
37
|
+
render: "sheet" | "none";
|
|
38
|
+
budgetMs: number;
|
|
39
|
+
accept: Array<{
|
|
40
|
+
key: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
}>;
|
|
43
|
+
showAccepted: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Strict validation; throws ToolInputError (nothing is sent). */
|
|
46
|
+
export declare function validateAuditArgs(args: SceneAuditArgs): ValidatedAuditArgs;
|
|
47
|
+
/** Raw kernel measurements -> sorted issues (all checks that ran). */
|
|
48
|
+
export declare function judgeAll(result: KernelResult, checks: readonly AuditCheck[]): AuditIssue[];
|
|
49
|
+
export interface JudgedAudit {
|
|
50
|
+
issues: AuditIssue[];
|
|
51
|
+
notes: string[];
|
|
52
|
+
/** Checks that ran but could measure nothing (never listed clean). */
|
|
53
|
+
unmeasured: AuditCheck[];
|
|
54
|
+
}
|
|
55
|
+
export declare function judgeAllDetailed(result: KernelResult, checks: readonly AuditCheck[]): JudgedAudit;
|
|
56
|
+
export declare function sceneAudit(client: AuditClient, rawArgs: SceneAuditArgs): Promise<AuditResult>;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* summer_scene_audit — ONE implementation for both faces (MCP:
|
|
3
|
+
* src/mcp/tools/audit-tools.ts; CLI: `summer tool scene-audit`).
|
|
4
|
+
*
|
|
5
|
+
* One fast, read-only pass over every node of a 3D scene that reports likely
|
|
6
|
+
* visual and placement problems, so a build agent knows exactly where to look.
|
|
7
|
+
*
|
|
8
|
+
* How (no new engine op): the seeing tools' private-copy path. A throwaway
|
|
9
|
+
* wrapper scene in a private OS temp directory instances the SAVED scene and
|
|
10
|
+
* carries the audit kernel (assets/audit/scene_audit.gd) as a built-in @tool
|
|
11
|
+
* script; the existing ScenePreview op instantiates it in an offscreen
|
|
12
|
+
* SubViewport with its own World3D. The kernel works on that copy: the open
|
|
13
|
+
* tab, its unsaved state, its undo history and every project file stay
|
|
14
|
+
* untouched (RunSceneScript would mark the tab unsaved after every run).
|
|
15
|
+
*
|
|
16
|
+
* The kernel measures (capped ray grids and probes against a physics space
|
|
17
|
+
* built from the visible meshes, shapes cached per mesh resource); judge.ts
|
|
18
|
+
* decides; summary.ts pages the result under 5 KB. render:"sheet" renders the
|
|
19
|
+
* first 6 issues of the page through the seeing kernel in one more call.
|
|
20
|
+
*/
|
|
21
|
+
import { readFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { PACKAGE_ROOT } from "../../package-root.js";
|
|
24
|
+
import { missingEngineOpResult } from "../../capability-skew.js";
|
|
25
|
+
import { ToolInputError } from "../../tool-errors.js";
|
|
26
|
+
import { resolveCurrentScene } from "../project-context.js";
|
|
27
|
+
import { layoutGrid, validateNodePath, validateScenePath } from "../seeing/seeing.js";
|
|
28
|
+
import { runProbe } from "../seeing/probe.js";
|
|
29
|
+
import { AUDIT_CHECKS, AUDIT_DEFAULT_BUDGET_MS, AUDIT_DEFAULT_LIMIT, AUDIT_MAX_ACCEPT, AUDIT_MAX_BUDGET_MS, AUDIT_MAX_LIMIT, AUDIT_MIN_BUDGET_MS, } from "./args.js";
|
|
30
|
+
import { AcceptStoreError, applyAccepts, mergeAccepts, parseAcceptFile, validIssueKey, writeAcceptFile } from "./accept.js";
|
|
31
|
+
import { judgeGaps } from "./gaps.js";
|
|
32
|
+
import { groupRepeats, judgeDuplicates, judgeFloorGaps, judgeLights, judgeLongProps, judgeOverlaps, judgeResources, judgeSupport, judgeThroughHoles, judgeTransforms, judgeUv, judgeZFight, judgeZFightGeometry, } from "./judge.js";
|
|
33
|
+
import { buildPage, countIssues, filterIssues, partialChecks, sortIssues, timingPerCheck } from "./summary.js";
|
|
34
|
+
import { choosePose, SHEET_TILES } from "./frame.js";
|
|
35
|
+
export const AUDIT_KERNEL_PATH = join(PACKAGE_ROOT, "assets", "audit", "scene_audit.gd");
|
|
36
|
+
let kernelCache = null;
|
|
37
|
+
export function loadAuditKernel() {
|
|
38
|
+
if (kernelCache === null)
|
|
39
|
+
kernelCache = readFileSync(AUDIT_KERNEL_PATH, "utf-8");
|
|
40
|
+
return kernelCache;
|
|
41
|
+
}
|
|
42
|
+
export const AUDIT_FALLBACK = "read the scene with summer_world_snapshot and look with summer_frame_nodes / summer_shot_sheet; cast single rays with summer_raycast";
|
|
43
|
+
function fail(failure_reason, error, hint, detail) {
|
|
44
|
+
return { ok: false, failure_reason, error, ...(hint ? { hint } : {}), ...(detail ? { detail } : {}) };
|
|
45
|
+
}
|
|
46
|
+
/** Strict validation; throws ToolInputError (nothing is sent). */
|
|
47
|
+
export function validateAuditArgs(args) {
|
|
48
|
+
const checks = args.checks?.length ? [...new Set(args.checks)] : [...AUDIT_CHECKS];
|
|
49
|
+
for (const c of checks) {
|
|
50
|
+
if (!AUDIT_CHECKS.includes(c))
|
|
51
|
+
throw new ToolInputError(`checks: unknown check ${JSON.stringify(c)}. Nothing was sent.`);
|
|
52
|
+
}
|
|
53
|
+
const offset = args.offset ?? 0;
|
|
54
|
+
const limit = args.limit ?? AUDIT_DEFAULT_LIMIT;
|
|
55
|
+
if (!Number.isInteger(offset) || offset < 0)
|
|
56
|
+
throw new ToolInputError("offset must be a non-negative integer. Nothing was sent.");
|
|
57
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > AUDIT_MAX_LIMIT)
|
|
58
|
+
throw new ToolInputError(`limit must be 1-${AUDIT_MAX_LIMIT}. Nothing was sent.`);
|
|
59
|
+
const budgetMs = args.budget_ms ?? AUDIT_DEFAULT_BUDGET_MS;
|
|
60
|
+
if (!Number.isInteger(budgetMs) || budgetMs < AUDIT_MIN_BUDGET_MS || budgetMs > AUDIT_MAX_BUDGET_MS) {
|
|
61
|
+
throw new ToolInputError(`budget_ms must be an integer ${AUDIT_MIN_BUDGET_MS}-${AUDIT_MAX_BUDGET_MS}. Nothing was sent.`);
|
|
62
|
+
}
|
|
63
|
+
const root = args.root !== undefined && args.root.trim() !== "" && args.root.trim() !== "." ? validateNodePath(args.root.trim(), "root") : undefined;
|
|
64
|
+
const accept = (args.accept ?? []).map((a) => {
|
|
65
|
+
if (!a || typeof a.key !== "string" || !validIssueKey(a.key)) {
|
|
66
|
+
throw new ToolInputError(`accept: ${JSON.stringify(a?.key ?? a).slice(0, 80)} is not an issue key (check:path@x,y,z, from issues[].key). Nothing was sent.`);
|
|
67
|
+
}
|
|
68
|
+
const reason = typeof a.reason === "string" ? a.reason.trim() : "";
|
|
69
|
+
if (reason.length < 3 || reason.length > 200 || /[\r\n]/.test(reason))
|
|
70
|
+
throw new ToolInputError("accept: each reason must be one line of 3-200 characters. Nothing was sent.");
|
|
71
|
+
return { key: a.key, reason };
|
|
72
|
+
});
|
|
73
|
+
if (accept.length > AUDIT_MAX_ACCEPT)
|
|
74
|
+
throw new ToolInputError(`accept: at most ${AUDIT_MAX_ACCEPT} per call. Nothing was sent.`);
|
|
75
|
+
return {
|
|
76
|
+
...(args.scenePath !== undefined ? { scenePath: validateScenePath(args.scenePath) } : {}),
|
|
77
|
+
checks: AUDIT_CHECKS.filter((c) => checks.includes(c)),
|
|
78
|
+
...(root ? { root } : {}),
|
|
79
|
+
minSeverity: args.min_severity ?? "look",
|
|
80
|
+
offset,
|
|
81
|
+
limit,
|
|
82
|
+
render: args.render ?? "none",
|
|
83
|
+
budgetMs,
|
|
84
|
+
accept,
|
|
85
|
+
showAccepted: args.show_accepted === true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Raw kernel measurements -> sorted issues (all checks that ran). */
|
|
89
|
+
export function judgeAll(result, checks) {
|
|
90
|
+
return judgeAllDetailed(result, checks).issues;
|
|
91
|
+
}
|
|
92
|
+
export function judgeAllDetailed(result, checks) {
|
|
93
|
+
const inst = (Array.isArray(result.instances) ? result.instances : []);
|
|
94
|
+
const want = new Set(checks);
|
|
95
|
+
const lines = Array.isArray(result.lines) ? result.lines : [];
|
|
96
|
+
const issues = [];
|
|
97
|
+
const holes = want.has("through_hole") ? judgeThroughHoles(lines, inst) : [];
|
|
98
|
+
issues.push(...holes);
|
|
99
|
+
const gaps = judgeGaps(result, inst, want, holes);
|
|
100
|
+
issues.push(...gaps.issues);
|
|
101
|
+
if (want.has("floor_gap"))
|
|
102
|
+
issues.push(...judgeFloorGaps(result.floors, inst));
|
|
103
|
+
if (want.has("floating") || want.has("sunken")) {
|
|
104
|
+
issues.push(...judgeSupport(Array.isArray(result.support) ? result.support : [], inst).filter((i) => want.has(i.check)));
|
|
105
|
+
}
|
|
106
|
+
if (want.has("interpenetration"))
|
|
107
|
+
issues.push(...judgeOverlaps(Array.isArray(result.overlaps) ? result.overlaps : [], inst));
|
|
108
|
+
if (want.has("orientation"))
|
|
109
|
+
issues.push(...judgeLongProps(Array.isArray(result.long_props) ? result.long_props : [], inst));
|
|
110
|
+
if (want.has("uv_stretch"))
|
|
111
|
+
issues.push(...judgeUv(Array.isArray(result.uv) ? result.uv : [], inst));
|
|
112
|
+
const dup = judgeDuplicates(inst);
|
|
113
|
+
if (want.has("duplicate"))
|
|
114
|
+
issues.push(...dup.issues);
|
|
115
|
+
if (want.has("z_fight")) {
|
|
116
|
+
const geo = judgeZFightGeometry(result.zfight_geo, inst, dup.pairs);
|
|
117
|
+
issues.push(...geo.issues, ...judgeZFight(lines, result.floors, inst, dup.pairs, geo.pairs));
|
|
118
|
+
}
|
|
119
|
+
if (want.has("lights"))
|
|
120
|
+
issues.push(...judgeLights(result.lights, inst));
|
|
121
|
+
if (want.has("transform"))
|
|
122
|
+
issues.push(...judgeTransforms(inst));
|
|
123
|
+
if (want.has("resource"))
|
|
124
|
+
issues.push(...judgeResources(result.resources, inst));
|
|
125
|
+
return { issues: sortIssues(groupRepeats(issues, inst)), notes: gaps.notes, unmeasured: gaps.unmeasured };
|
|
126
|
+
}
|
|
127
|
+
function sceneStats(result) {
|
|
128
|
+
const s = (result.stats ?? {});
|
|
129
|
+
const pick = (k) => (typeof s[k] === "number" ? s[k] : undefined);
|
|
130
|
+
return {
|
|
131
|
+
nodes: pick("nodes"),
|
|
132
|
+
instances: pick("instances"),
|
|
133
|
+
meshes: pick("mesh_instances"),
|
|
134
|
+
unique_meshes: pick("unique_meshes"),
|
|
135
|
+
tris_unique: pick("tris_unique"),
|
|
136
|
+
rays: pick("rays"),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function lightStats(result) {
|
|
140
|
+
const l = result.lights;
|
|
141
|
+
if (!l)
|
|
142
|
+
return undefined;
|
|
143
|
+
const c = (l.counts ?? {});
|
|
144
|
+
const sh = (l.shadowed ?? {});
|
|
145
|
+
const n = (v) => (typeof v === "number" ? v : 0);
|
|
146
|
+
return { renderer: l.renderer, omni: n(c.omni), spot: n(c.spot), directional: n(c.directional), shadowed: n(sh.omni) + n(sh.spot) + n(sh.directional), per_object_limit: l.limit };
|
|
147
|
+
}
|
|
148
|
+
export async function sceneAudit(client, rawArgs) {
|
|
149
|
+
const args = validateAuditArgs(rawArgs);
|
|
150
|
+
let scenePath = args.scenePath;
|
|
151
|
+
if (!scenePath) {
|
|
152
|
+
const current = resolveCurrentScene(undefined, await client.getSceneState(), undefined);
|
|
153
|
+
if (!current)
|
|
154
|
+
throw new ToolInputError('No scenePath given and no scene is open in the editor. Pass scenePath ("res://...tscn"). Nothing was sent.');
|
|
155
|
+
scenePath = validateScenePath(current);
|
|
156
|
+
}
|
|
157
|
+
const missing = missingEngineOpResult(client, "ScenePreview", AUDIT_FALLBACK);
|
|
158
|
+
if (missing)
|
|
159
|
+
return fail(missing.failure_reason, missing.error, missing.hint, { op: "ScenePreview", engine_version: missing.engine_version });
|
|
160
|
+
const config = {
|
|
161
|
+
mode: "audit",
|
|
162
|
+
checks: args.checks,
|
|
163
|
+
...(args.root ? { root: args.root } : {}),
|
|
164
|
+
poses: args.render === "sheet",
|
|
165
|
+
budget_ms: args.budgetMs,
|
|
166
|
+
};
|
|
167
|
+
const started = Date.now();
|
|
168
|
+
const run = await runProbe(client, { scenePath, config, size: [16, 16], kernel: loadAuditKernel(), timeoutMs: 120_000 });
|
|
169
|
+
const roundtrip = Date.now() - started;
|
|
170
|
+
try {
|
|
171
|
+
if (!run.ok || !run.result) {
|
|
172
|
+
if (run.failureReason === "probe_did_not_run") {
|
|
173
|
+
return fail("audit_did_not_run", "The audit kernel never wrote its result: the wrapper scene loaded but the built-in @tool script did not run (a script error, or the scene failed to load). Read summer_get_console for the engine's error.", undefined, { stage: run.result?.stage ?? null });
|
|
174
|
+
}
|
|
175
|
+
return fail(run.failureReason ?? "audit_failed", run.error ?? "The audit failed.", undefined, run.result ? { stage: run.result.stage ?? null, errors: run.result.errors ?? [] } : undefined);
|
|
176
|
+
}
|
|
177
|
+
const result = run.result;
|
|
178
|
+
const judgeStarted = Date.now();
|
|
179
|
+
const judged = judgeAllDetailed(result, args.checks);
|
|
180
|
+
const judgeMs = Date.now() - judgeStarted;
|
|
181
|
+
const partial = partialChecks(result.partial, args.checks);
|
|
182
|
+
for (const c of judged.unmeasured)
|
|
183
|
+
partial.checks[c] = 0;
|
|
184
|
+
// Accepted items: merge this call's accept list into the file, then hide
|
|
185
|
+
// what is accepted (stale entries show again).
|
|
186
|
+
let acceptEntries = parseAcceptFile(result.accept);
|
|
187
|
+
let acceptResult;
|
|
188
|
+
if (args.accept.length) {
|
|
189
|
+
const merged = mergeAccepts(acceptEntries, args.accept, judged.issues, scenePath);
|
|
190
|
+
acceptResult = { added: merged.added.length, ...(merged.refused.length ? { refused: merged.refused.slice(0, 5) } : {}) };
|
|
191
|
+
if (merged.entries) {
|
|
192
|
+
try {
|
|
193
|
+
await writeAcceptFile(client.getProjectRoot?.(), merged.entries);
|
|
194
|
+
acceptEntries = merged.entries;
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
const reason = err instanceof AcceptStoreError ? err.reason : "write_failed";
|
|
198
|
+
return fail(`accept_${reason}`, `Accepted items were not saved: ${err instanceof Error ? err.message : String(err)}`, "Run the audit without accept, or connect to the project's editor so its folder is known.");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const split = applyAccepts(judged.issues, acceptEntries, scenePath);
|
|
203
|
+
for (const st of split.stale)
|
|
204
|
+
st.issue.acceptStale = st.why;
|
|
205
|
+
for (const a of split.accepted)
|
|
206
|
+
a.issue.accepted = a.entry.reason;
|
|
207
|
+
const all = args.showAccepted ? judged.issues : split.shown;
|
|
208
|
+
const accepted = split.accepted.map((a) => a.issue);
|
|
209
|
+
const { counts, clean } = countIssues(split.shown, args.checks, partial.checks, accepted);
|
|
210
|
+
const matching = filterIssues(all, args.minSeverity);
|
|
211
|
+
const notes = ["Read-only: audited the SAVED file in a private copy (open tab, undo and file untouched); save first."];
|
|
212
|
+
if (accepted.length)
|
|
213
|
+
notes.push(`${accepted.length} accepted item(s) ${args.showAccepted ? "listed (show_accepted)" : "hidden (counts.<check>.accepted; show_accepted:true lists them)"}${split.stale.length ? `; ${split.stale.length} shown again because their evidence changed (accept_stale)` : ""}.`);
|
|
214
|
+
else if (split.stale.length)
|
|
215
|
+
notes.push(`${split.stale.length} accepted item(s) shown again because their evidence changed (accept_stale).`);
|
|
216
|
+
notes.push(...judged.notes);
|
|
217
|
+
if (args.minSeverity !== "look")
|
|
218
|
+
notes.push(`min_severity ${args.minSeverity}: ${all.length - matching.length} lower-severity issue(s) hidden.`);
|
|
219
|
+
const lights = lightStats(result);
|
|
220
|
+
if (lights && args.checks.includes("lights") && lights.renderer === "forward_plus")
|
|
221
|
+
notes.push("lights: forward_plus has no per-object light limit; only spot rims were checked.");
|
|
222
|
+
const stopped = Object.entries(partial.checks).map(([c, share]) => `${c} ${Math.round(share * 100)}%`);
|
|
223
|
+
if (stopped.length)
|
|
224
|
+
notes.push(`budget_ms ${args.budgetMs}: stopped early (editor time): ${stopped.join(", ")} covered; rerun those with checks:[...] or a larger budget_ms.`);
|
|
225
|
+
if (partial.other.poses !== undefined)
|
|
226
|
+
notes.push(`framing: views measured for ${Math.round(partial.other.poses * 100)}% of the pieces (budget); the rest have no sheet tile.`);
|
|
227
|
+
for (const w of Array.isArray(result.warnings) ? result.warnings.slice(0, 3) : [])
|
|
228
|
+
notes.push(String(w).slice(0, 160));
|
|
229
|
+
const base = {
|
|
230
|
+
ok: true,
|
|
231
|
+
tool: "summer_scene_audit",
|
|
232
|
+
scenePath,
|
|
233
|
+
...(args.root ? { root: args.root } : {}),
|
|
234
|
+
budget_ms: args.budgetMs,
|
|
235
|
+
scene: sceneStats(result),
|
|
236
|
+
counts,
|
|
237
|
+
clean,
|
|
238
|
+
ms: timingPerCheck(result.ms, { judge: judgeMs, roundtrip }),
|
|
239
|
+
...(lights ? { lights } : {}),
|
|
240
|
+
total: all.length,
|
|
241
|
+
...(accepted.length || split.stale.length ? { accepted: { hidden: args.showAccepted ? 0 : accepted.length, stale: split.stale.length } } : {}),
|
|
242
|
+
...(acceptResult ? { accept_result: acceptResult } : {}),
|
|
243
|
+
notes,
|
|
244
|
+
};
|
|
245
|
+
let page = buildPage({ base, issues: matching, offset: args.offset, limit: args.limit });
|
|
246
|
+
// The sheet (one more engine call): the first issues of THIS page.
|
|
247
|
+
let image = null;
|
|
248
|
+
if (args.render === "sheet") {
|
|
249
|
+
const first = page.shown.slice(0, SHEET_TILES).map((c) => ({ n: c.n, issue: matching[c.n - 1] }));
|
|
250
|
+
const posed = first.map((f) => ({ ...f, pose: choosePose(f.issue.frame) })).filter((p) => p.pose !== null);
|
|
251
|
+
const unposed = first.filter((f) => !posed.some((p) => p.n === f.n)).map((f) => f.n);
|
|
252
|
+
let sheet;
|
|
253
|
+
if (!posed.length) {
|
|
254
|
+
sheet = { tiles: [], ...(unposed.length ? { no_clear_view: unposed } : {}) };
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const layout = layoutGrid(posed.length, 16 / 9, 1536);
|
|
258
|
+
const tiles = posed.map((p, k) => ({
|
|
259
|
+
kind: "shot",
|
|
260
|
+
rect: layout.rects[k],
|
|
261
|
+
label: `#${p.n} ${p.issue.check}`,
|
|
262
|
+
view: "beauty",
|
|
263
|
+
pose: { position: [...p.pose.position], look_at: [...p.pose.look_at], fov: p.pose.fov },
|
|
264
|
+
}));
|
|
265
|
+
const renderStarted = Date.now();
|
|
266
|
+
const render = await runProbe(client, { scenePath, size: layout.canvas, config: { mode: "render", canvas: layout.canvas, tiles }, timeoutMs: 120_000 });
|
|
267
|
+
try {
|
|
268
|
+
if (render.ok && render.image) {
|
|
269
|
+
image = { ...render.image };
|
|
270
|
+
sheet = { tiles: posed.map((p) => p.n), ...(unposed.length ? { no_clear_view: unposed } : {}), render_ms: Date.now() - renderStarted };
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
sheet = { error: render.failureReason ?? "render_failed", detail: (render.error ?? "").slice(0, 160) };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
await render.dispose();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
page = buildPage({ base: { ...base, sheet }, issues: matching, offset: args.offset, limit: args.limit });
|
|
281
|
+
}
|
|
282
|
+
return { ok: true, summary: page.body, image };
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
await run.dispose();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framing for render:"sheet": a camera per issue, on the OPEN side of the
|
|
3
|
+
* problem. Each issue carries directions the kernel measured with two-sided
|
|
4
|
+
* rays (any surface counts, front or back face), so a camera placed within
|
|
5
|
+
* the measured clear distance is never behind a wall or inside geometry:
|
|
6
|
+
* walls render one-sided, and a camera behind one sees straight through it.
|
|
7
|
+
*/
|
|
8
|
+
import { type CameraPose } from "../seeing/math.js";
|
|
9
|
+
import type { FrameHint } from "./judge.js";
|
|
10
|
+
export declare const SHEET_FOV = 50;
|
|
11
|
+
export declare const SHEET_TILES = 6;
|
|
12
|
+
/** The pose from the best measured direction: preference x share of the
|
|
13
|
+
* wanted distance that is actually clear. Null when nothing is clear. */
|
|
14
|
+
export declare function choosePose(hint: FrameHint | undefined, fov?: number): CameraPose | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framing for render:"sheet": a camera per issue, on the OPEN side of the
|
|
3
|
+
* problem. Each issue carries directions the kernel measured with two-sided
|
|
4
|
+
* rays (any surface counts, front or back face), so a camera placed within
|
|
5
|
+
* the measured clear distance is never behind a wall or inside geometry:
|
|
6
|
+
* walls render one-sided, and a camera behind one sees straight through it.
|
|
7
|
+
*/
|
|
8
|
+
import { add, clamp, scale } from "../seeing/math.js";
|
|
9
|
+
import { fitCameraDistance } from "./math.js";
|
|
10
|
+
export const SHEET_FOV = 50;
|
|
11
|
+
export const SHEET_TILES = 6;
|
|
12
|
+
const MIN_DISTANCE = 0.7;
|
|
13
|
+
const CLEARANCE_MARGIN = 0.3;
|
|
14
|
+
/** The pose from the best measured direction: preference x share of the
|
|
15
|
+
* wanted distance that is actually clear. Null when nothing is clear. */
|
|
16
|
+
export function choosePose(hint, fov = SHEET_FOV) {
|
|
17
|
+
if (!hint)
|
|
18
|
+
return null;
|
|
19
|
+
if (hint.viewer)
|
|
20
|
+
return { position: hint.viewer, look_at: hint.focus, fov };
|
|
21
|
+
const want = clamp(fitCameraDistance(hint.size, fov), 1.5, 9);
|
|
22
|
+
let best = null;
|
|
23
|
+
for (const d of hint.dirs) {
|
|
24
|
+
const available = d.clear - CLEARANCE_MARGIN;
|
|
25
|
+
if (available < MIN_DISTANCE || d.pref <= 0)
|
|
26
|
+
continue;
|
|
27
|
+
const dist = Math.min(want, available);
|
|
28
|
+
const score = d.pref * (dist / want);
|
|
29
|
+
if (!best || score > best.score)
|
|
30
|
+
best = { dir: d.dir, dist, score };
|
|
31
|
+
}
|
|
32
|
+
if (!best)
|
|
33
|
+
return null;
|
|
34
|
+
return { position: add(hint.focus, scale(best.dir, best.dist)), look_at: hint.focus, fov };
|
|
35
|
+
}
|