summer-engine 3.1.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 +102 -0
- package/README.md +18 -3
- package/assets/audit/scene_audit.gd +4136 -0
- package/assets/seeing/seeing_probe.gd +1873 -0
- package/dist/cli/commands/skills.js +20 -2
- 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 +18 -2
- 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/installer/agent-config.js +5 -3
- package/dist/installer/agent-table.d.ts +16 -0
- package/dist/installer/agent-table.js +52 -17
- 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/amp/README.md +1 -1
- package/integrations/crush/README.md +1 -1
- package/integrations/grok-build/README.md +1 -1
- package/integrations/hermes/README.md +1 -1
- package/integrations/kimi-code/README.md +1 -1
- package/integrations/mistral-vibe/README.md +1 -1
- package/integrations/opencode/README.md +1 -1
- package/integrations/rovo-dev/README.md +1 -1
- package/integrations/vscode-copilot/README.md +1 -1
- package/integrations/warp/README.md +1 -1
- package/integrations/windsurf/README.md +1 -1
- 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 +36 -14
- 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 +1 -1
- 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 +36 -14
- package/registry/generated/skills-registry.json +421 -124
- 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
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { type LibrarySearchDeps } from "./library-search.js";
|
|
2
|
+
import { type LibraryIndexEntry, type LibrarySearchDeps } from "./library-search.js";
|
|
3
3
|
import { type TemplateEntry } from "./templates.js";
|
|
4
4
|
export declare const READ_PARTS: readonly ["skill", "resource", "all"];
|
|
5
5
|
export type ReadPart = (typeof READ_PARTS)[number];
|
|
6
6
|
/** How many content_hash hex chars the footer's entry_id carries. */
|
|
7
7
|
export declare const FOOTER_HASH_LENGTH = 12;
|
|
8
8
|
export declare const FOOTER_SUFFIX = "If this entry is wrong, stale, or you deviate from it, report via summer_library_feedback.";
|
|
9
|
+
/** Text files read_library loads when an entry links them. */
|
|
10
|
+
export declare const LINKED_FILE_EXTENSIONS: ReadonlySet<string>;
|
|
11
|
+
/** A linked file larger than this is refused rather than dumped. */
|
|
12
|
+
export declare const LINKED_FILE_MAX_BYTES: number;
|
|
9
13
|
export declare const readLibraryInputShape: {
|
|
10
14
|
id: z.ZodString;
|
|
11
15
|
part: z.ZodOptional<z.ZodEnum<["skill", "resource", "all"]>>;
|
|
@@ -15,10 +19,10 @@ export declare const readLibraryInputSchema: z.ZodObject<{
|
|
|
15
19
|
part: z.ZodOptional<z.ZodEnum<["skill", "resource", "all"]>>;
|
|
16
20
|
}, "strict", z.ZodTypeAny, {
|
|
17
21
|
id: string;
|
|
18
|
-
part?: "all" | "
|
|
22
|
+
part?: "all" | "resource" | "skill" | undefined;
|
|
19
23
|
}, {
|
|
20
24
|
id: string;
|
|
21
|
-
part?: "all" | "
|
|
25
|
+
part?: "all" | "resource" | "skill" | undefined;
|
|
22
26
|
}>;
|
|
23
27
|
export type ReadLibraryArgs = z.infer<typeof readLibraryInputSchema>;
|
|
24
28
|
export interface LibraryReadDeps extends LibrarySearchDeps {
|
|
@@ -44,6 +48,15 @@ export interface LibraryReadOk {
|
|
|
44
48
|
files: string[];
|
|
45
49
|
/** The file the body came from, when the body is a file. */
|
|
46
50
|
body_file?: string;
|
|
51
|
+
/** Set when the load is a file the entry ships rather than the entry body:
|
|
52
|
+
* its path inside the entry directory, e.g. "references/kit-placement-tools.md". */
|
|
53
|
+
linked_file?: string;
|
|
54
|
+
/** Relative links in the body and the summer_read_library id that loads
|
|
55
|
+
* each (null: the target is not shipped with this package). */
|
|
56
|
+
links?: Array<{
|
|
57
|
+
target: string;
|
|
58
|
+
id: string | null;
|
|
59
|
+
}>;
|
|
47
60
|
/** Tool records: how to reach it. */
|
|
48
61
|
mcp_tool_name?: string;
|
|
49
62
|
cli_command?: string;
|
|
@@ -67,7 +80,26 @@ export type LibraryReadResult = LibraryReadOk | LibraryReadNotFound;
|
|
|
67
80
|
export declare function feedbackFooter(id: string, contentHash: string | undefined): string;
|
|
68
81
|
export declare function entryIdWithHash(id: string, contentHash: string | undefined): string;
|
|
69
82
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
83
|
+
* Relative link targets in a markdown body: markdown links outside code
|
|
84
|
+
* (`[x](references/y.md)`, fragment dropped) and inline code spans that name a
|
|
85
|
+
* library file by a relative path (`../../references/gd-style/gd-style.md`,
|
|
86
|
+
* `references/y.md`; a `./scripts/x.gd` span is a project path and is not
|
|
87
|
+
* one). URLs, anchors, absolute paths and fenced code blocks are skipped.
|
|
88
|
+
* Exported for the every-link-resolves test.
|
|
89
|
+
*/
|
|
90
|
+
export declare function relativeLinkTargets(markdown: string): string[];
|
|
91
|
+
/**
|
|
92
|
+
* Where a link written in `fromFile` (a path inside `entry`'s directory, ""
|
|
93
|
+
* or "SKILL.md" for the body) points, as the id summer_read_library loads it
|
|
94
|
+
* by; null when the target is not shipped inside library/.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolveLibraryLink(entry: LibraryIndexEntry, fromFile: string, link: string, deps: {
|
|
97
|
+
entries: LibraryIndexEntry[];
|
|
98
|
+
packageRoot?: string;
|
|
99
|
+
}): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Read one entry, or a file an entry links. `deps.entries`/`deps.packageRoot`/
|
|
102
|
+
* `deps.templates` let tests point at a fixture; production reads the
|
|
103
|
+
* installed package.
|
|
72
104
|
*/
|
|
73
105
|
export declare function readLibraryEntry(requestedId: string, part?: ReadPart, deps?: LibraryReadDeps): Promise<LibraryReadResult>;
|
|
@@ -23,9 +23,18 @@
|
|
|
23
23
|
* Metadata comes from registry/generated/index.json (no YAML parser at
|
|
24
24
|
* runtime); resource.yaml is returned as text. Unknown id -> not_found with
|
|
25
25
|
* the three nearest ids from searchLibrary.
|
|
26
|
+
*
|
|
27
|
+
* Linked files: a body links files its entry ships (a skill's
|
|
28
|
+
* `references/kit-placement-tools.md`) and other entries
|
|
29
|
+
* (`../multiplayer-project/SKILL.md`, `../../references/gd-style/gd-style.md`).
|
|
30
|
+
* Each loads by `<entry id>/<link as written>`, resolved inside library/ only
|
|
31
|
+
* and for text files only; by the relative path alone when exactly one entry
|
|
32
|
+
* ships it; and `reference/<slug>` that is no entry falls back to the one
|
|
33
|
+
* `references/<slug>.md` an entry ships. A body render ends with its links and
|
|
34
|
+
* the id that loads each. A linked file's footer names its entry.
|
|
26
35
|
*/
|
|
27
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
28
|
-
import { join } from "node:path";
|
|
36
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
37
|
+
import { join, posix, sep } from "node:path";
|
|
29
38
|
import { z } from "zod";
|
|
30
39
|
import { LIBRARY_KIND_DIRS, loadLibraryIndex, searchLibrary, } from "./library-search.js";
|
|
31
40
|
import { PACKAGE_ROOT } from "./package-root.js";
|
|
@@ -34,12 +43,30 @@ export const READ_PARTS = ["skill", "resource", "all"];
|
|
|
34
43
|
/** How many content_hash hex chars the footer's entry_id carries. */
|
|
35
44
|
export const FOOTER_HASH_LENGTH = 12;
|
|
36
45
|
export const FOOTER_SUFFIX = "If this entry is wrong, stale, or you deviate from it, report via summer_library_feedback.";
|
|
46
|
+
/** Text files read_library loads when an entry links them. */
|
|
47
|
+
export const LINKED_FILE_EXTENSIONS = new Set([
|
|
48
|
+
".md",
|
|
49
|
+
".markdown",
|
|
50
|
+
".txt",
|
|
51
|
+
".yaml",
|
|
52
|
+
".yml",
|
|
53
|
+
".json",
|
|
54
|
+
".gd",
|
|
55
|
+
".gdshader",
|
|
56
|
+
".shader",
|
|
57
|
+
".cfg",
|
|
58
|
+
".tscn",
|
|
59
|
+
".tres",
|
|
60
|
+
".csv",
|
|
61
|
+
]);
|
|
62
|
+
/** A linked file larger than this is refused rather than dumped. */
|
|
63
|
+
export const LINKED_FILE_MAX_BYTES = 256 * 1024;
|
|
37
64
|
export const readLibraryInputShape = {
|
|
38
65
|
id: z
|
|
39
66
|
.string()
|
|
40
67
|
.min(1)
|
|
41
68
|
.max(200)
|
|
42
|
-
.describe("The entry id as returned by summer_search_library: <kind>/<slug>, e.g. skill/vfx-water-ripple or tool/screenshot."),
|
|
69
|
+
.describe("The entry id as returned by summer_search_library: <kind>/<slug>, e.g. skill/vfx-water-ripple or tool/screenshot. A file an entry links loads by <entry id>/<link as written>, e.g. skill/spatial-placement/references/kit-placement-tools.md; the 'linked files' list at the end of a body gives each id."),
|
|
43
70
|
part: z
|
|
44
71
|
.enum(READ_PARTS)
|
|
45
72
|
.optional()
|
|
@@ -71,6 +98,111 @@ function resolveEntry(requested, entries) {
|
|
|
71
98
|
}
|
|
72
99
|
return null;
|
|
73
100
|
}
|
|
101
|
+
const KIND_BY_DIR = new Map(Object.entries(LIBRARY_KIND_DIRS).map(([kind, dir]) => [dir, kind]));
|
|
102
|
+
const ENTRY_PATH_ID = /^(tool|skill|example|template|collection|reference)\/([a-z0-9]+(?:-[a-z0-9]+)*)\/(.+)$/;
|
|
103
|
+
function entryDirOf(entry) {
|
|
104
|
+
const kind = entry.kind;
|
|
105
|
+
return `library/${LIBRARY_KIND_DIRS[kind] ?? `${kind}s`}/${entry.id.split("/").pop()}`;
|
|
106
|
+
}
|
|
107
|
+
/** Join a link onto a package-relative directory; null when it is absolute,
|
|
108
|
+
* malformed, or leaves library/. */
|
|
109
|
+
function joinInsideLibrary(baseDir, link) {
|
|
110
|
+
let decoded;
|
|
111
|
+
try {
|
|
112
|
+
decoded = decodeURIComponent(link.trim());
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
if (!decoded || /[\u0000-\u001f\\]/.test(decoded) || decoded.startsWith("/") || /^[a-z][a-z0-9+.-]*:/i.test(decoded))
|
|
118
|
+
return null;
|
|
119
|
+
const joined = posix.normalize(posix.join(baseDir, decoded)).replace(/\/+$/, "");
|
|
120
|
+
return joined === "library" || joined.startsWith("library/") ? joined : null;
|
|
121
|
+
}
|
|
122
|
+
/** library/<dir>/<slug>[/<file>] -> the entry and the file inside it. */
|
|
123
|
+
function targetFromLibraryPath(libPath, entries) {
|
|
124
|
+
const parts = libPath.split("/");
|
|
125
|
+
if (parts.length < 3 || parts[0] !== "library")
|
|
126
|
+
return null;
|
|
127
|
+
const kind = KIND_BY_DIR.get(parts[1]);
|
|
128
|
+
if (!kind)
|
|
129
|
+
return null;
|
|
130
|
+
const entry = entries.find((e) => e.id === `${kind}/${parts[2]}`);
|
|
131
|
+
return entry ? { entry, file: parts.slice(3).join("/") } : null;
|
|
132
|
+
}
|
|
133
|
+
function isFileInsideLibrary(root, libPath) {
|
|
134
|
+
const abs = join(root, ...libPath.split("/"));
|
|
135
|
+
try {
|
|
136
|
+
if (!statSync(abs).isFile())
|
|
137
|
+
return false;
|
|
138
|
+
const libraryRoot = realpathSync(join(root, "library"));
|
|
139
|
+
return realpathSync(abs).startsWith(libraryRoot + sep);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Resolve an id that names a file an entry ships (see the module comment). */
|
|
146
|
+
function resolveLinkedFile(requested, entries, root) {
|
|
147
|
+
const bare = requested.trim();
|
|
148
|
+
const qualified = ENTRY_PATH_ID.exec(bare);
|
|
149
|
+
if (qualified) {
|
|
150
|
+
const entry = entries.find((e) => e.id === `${qualified[1]}/${qualified[2]}`);
|
|
151
|
+
if (entry) {
|
|
152
|
+
const libPath = joinInsideLibrary(entryDirOf(entry), qualified[3]);
|
|
153
|
+
const target = libPath ? targetFromLibraryPath(libPath, entries) : null;
|
|
154
|
+
if (!target || (target.file !== "" && !isFileInsideLibrary(root, libPath)))
|
|
155
|
+
return null;
|
|
156
|
+
return target;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const shipping = (relative) => entries
|
|
160
|
+
.map((entry) => ({ entry, libPath: joinInsideLibrary(entryDirOf(entry), relative) }))
|
|
161
|
+
.filter((c) => !!c.libPath && c.libPath.startsWith(`${entryDirOf(c.entry)}/`))
|
|
162
|
+
.filter((c) => isFileInsideLibrary(root, c.libPath))
|
|
163
|
+
.map((c) => ({ entry: c.entry, file: c.libPath.slice(entryDirOf(c.entry).length + 1) }));
|
|
164
|
+
// A relative path alone, when exactly one entry ships that file.
|
|
165
|
+
if ((bare.includes("/") || /\.[a-z0-9]+$/i.test(bare)) && !bare.startsWith("../")) {
|
|
166
|
+
const found = shipping(bare.replace(/^\.\//, ""));
|
|
167
|
+
if (found.length === 1)
|
|
168
|
+
return found[0];
|
|
169
|
+
}
|
|
170
|
+
// reference/<slug> that is no entry: the references/<slug>.md one entry ships.
|
|
171
|
+
const asReference = /^references?\/([a-z0-9]+(?:[-_][a-z0-9]+)*)(?:\.md)?$/.exec(bare);
|
|
172
|
+
if (asReference) {
|
|
173
|
+
const found = shipping(`references/${asReference[1]}.md`);
|
|
174
|
+
if (found.length === 1)
|
|
175
|
+
return found[0];
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Relative link targets in a markdown body: markdown links outside code
|
|
181
|
+
* (`[x](references/y.md)`, fragment dropped) and inline code spans that name a
|
|
182
|
+
* library file by a relative path (`../../references/gd-style/gd-style.md`,
|
|
183
|
+
* `references/y.md`; a `./scripts/x.gd` span is a project path and is not
|
|
184
|
+
* one). URLs, anchors, absolute paths and fenced code blocks are skipped.
|
|
185
|
+
* Exported for the every-link-resolves test.
|
|
186
|
+
*/
|
|
187
|
+
export function relativeLinkTargets(markdown) {
|
|
188
|
+
const out = new Set();
|
|
189
|
+
const text = markdown.replace(/^(```|~~~)[^\n]*\n[\s\S]*?^\1[^\n]*$/gm, "");
|
|
190
|
+
for (const match of text.matchAll(/`([^`\n]+)`/g)) {
|
|
191
|
+
const span = match[1].trim();
|
|
192
|
+
if (/^((\.\.\/)+|(\.\/)?references\/)[^\s*?<>|]+\.[A-Za-z0-9]+$/.test(span))
|
|
193
|
+
out.add(span);
|
|
194
|
+
}
|
|
195
|
+
const prose = text.replace(/`[^`\n]*`/g, "");
|
|
196
|
+
for (const match of prose.matchAll(/\]\(\s*<?([^)\s>]+)>?(?:\s+"[^"]*")?\s*\)/g)) {
|
|
197
|
+
const target = match[1];
|
|
198
|
+
if (target.startsWith("#") || target.startsWith("/") || /^[a-z][a-z0-9+.-]*:/i.test(target))
|
|
199
|
+
continue;
|
|
200
|
+
const path = target.split("#")[0];
|
|
201
|
+
if (path)
|
|
202
|
+
out.add(path);
|
|
203
|
+
}
|
|
204
|
+
return [...out];
|
|
205
|
+
}
|
|
74
206
|
// ── Rendering ──────────────────────────────────────────────────────────────
|
|
75
207
|
function readText(file) {
|
|
76
208
|
try {
|
|
@@ -109,6 +241,41 @@ function pickBodyFile(kind, slug, dir) {
|
|
|
109
241
|
return null;
|
|
110
242
|
}
|
|
111
243
|
}
|
|
244
|
+
/** The summer_read_library id that loads a target: the entry id for the
|
|
245
|
+
* entry itself or its body file, else <entry id>/<file>. */
|
|
246
|
+
function canonicalId(target, root) {
|
|
247
|
+
if (target.file === "")
|
|
248
|
+
return target.entry.id;
|
|
249
|
+
const slug = target.entry.id.split("/").pop();
|
|
250
|
+
const body = pickBodyFile(target.entry.kind, slug, join(root, ...entryDirOf(target.entry).split("/")));
|
|
251
|
+
return target.file === body ? target.entry.id : `${target.entry.id}/${target.file}`;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Where a link written in `fromFile` (a path inside `entry`'s directory, ""
|
|
255
|
+
* or "SKILL.md" for the body) points, as the id summer_read_library loads it
|
|
256
|
+
* by; null when the target is not shipped inside library/.
|
|
257
|
+
*/
|
|
258
|
+
export function resolveLibraryLink(entry, fromFile, link, deps) {
|
|
259
|
+
const root = deps.packageRoot ?? PACKAGE_ROOT;
|
|
260
|
+
const libPath = joinInsideLibrary(posix.dirname(posix.join(entryDirOf(entry), fromFile || "_")), link);
|
|
261
|
+
if (!libPath)
|
|
262
|
+
return null;
|
|
263
|
+
const target = targetFromLibraryPath(libPath, deps.entries);
|
|
264
|
+
if (!target)
|
|
265
|
+
return null;
|
|
266
|
+
if (target.file !== "" && !isFileInsideLibrary(root, libPath))
|
|
267
|
+
return null;
|
|
268
|
+
return canonicalId(target, root);
|
|
269
|
+
}
|
|
270
|
+
function linksOf(body, entry, fromFile, entries, root) {
|
|
271
|
+
return relativeLinkTargets(body).map((target) => ({ target, id: resolveLibraryLink(entry, fromFile, target, { entries, packageRoot: root }) }));
|
|
272
|
+
}
|
|
273
|
+
function linksSection(links) {
|
|
274
|
+
const lines = ["--- linked files (load each with summer_read_library and the id after the arrow) ---"];
|
|
275
|
+
for (const link of links)
|
|
276
|
+
lines.push(`${link.target} -> ${link.id ?? "(not shipped with this package)"}`);
|
|
277
|
+
return lines.join("\n");
|
|
278
|
+
}
|
|
112
279
|
function toolBody(entry, slug) {
|
|
113
280
|
const lines = [];
|
|
114
281
|
const mcpName = entry.mcp_tool_name ?? `summer_${slug.replace(/-/g, "_")}`;
|
|
@@ -179,36 +346,112 @@ function header(entry, slug, related) {
|
|
|
179
346
|
}
|
|
180
347
|
// ── Entry point ────────────────────────────────────────────────────────────
|
|
181
348
|
/**
|
|
182
|
-
* Read one entry. `deps.entries`/`deps.packageRoot
|
|
183
|
-
* tests point at a fixture; production reads the
|
|
349
|
+
* Read one entry, or a file an entry links. `deps.entries`/`deps.packageRoot`/
|
|
350
|
+
* `deps.templates` let tests point at a fixture; production reads the
|
|
351
|
+
* installed package.
|
|
184
352
|
*/
|
|
185
353
|
export async function readLibraryEntry(requestedId, part = "all", deps = {}) {
|
|
186
354
|
const entries = deps.entries ?? loadLibraryIndex();
|
|
187
355
|
const root = deps.packageRoot ?? PACKAGE_ROOT;
|
|
188
|
-
|
|
356
|
+
let entry = resolveEntry(requestedId, entries);
|
|
357
|
+
let linkedFile;
|
|
189
358
|
if (!entry) {
|
|
190
|
-
const
|
|
359
|
+
const target = resolveLinkedFile(requestedId, entries, root);
|
|
360
|
+
if (target) {
|
|
361
|
+
entry = target.entry;
|
|
362
|
+
const canonical = canonicalId(target, root);
|
|
363
|
+
// The entry's own body file and resource.yaml render as the entry.
|
|
364
|
+
if (target.file === "resource.yaml")
|
|
365
|
+
part = "resource";
|
|
366
|
+
else if (canonical !== entry.id)
|
|
367
|
+
linkedFile = target.file;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (!entry) {
|
|
371
|
+
const query = requestedId.replace(/[/@_.-]+/g, " ").replace(/[a-f0-9]{8,}/gi, " ").replace(/\bmd\b/g, " ").trim() || requestedId;
|
|
191
372
|
const nearest = (await searchLibrary(query, { limit: 3 }, deps)).map((hit) => hit.id);
|
|
192
373
|
return {
|
|
193
374
|
ok: false,
|
|
194
375
|
error: "not_found",
|
|
195
376
|
id: requestedId,
|
|
196
377
|
nearest,
|
|
197
|
-
hint: nearest.length > 0
|
|
378
|
+
hint: (nearest.length > 0
|
|
198
379
|
? `No library entry has id "${requestedId}". Nearest by search: ${nearest.join(", ")}. Ids are <kind>/<slug>; use summer_search_library to find the right one.`
|
|
199
|
-
: `No library entry has id "${requestedId}" and nothing similar was found. Ids are <kind>/<slug>; use summer_search_library
|
|
380
|
+
: `No library entry has id "${requestedId}" and nothing similar was found. Ids are <kind>/<slug>; use summer_search_library.`) +
|
|
381
|
+
" A file an entry links loads by <entry id>/<link as written> (inside library/ only).",
|
|
200
382
|
};
|
|
201
383
|
}
|
|
202
384
|
const kind = entry.kind;
|
|
203
385
|
const slug = entry.id.split("/").pop();
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const dir = join(root, "library", kindDir, slug);
|
|
386
|
+
const relPath = entryDirOf(entry);
|
|
387
|
+
const dir = join(root, ...relPath.split("/"));
|
|
207
388
|
const files = listFiles(dir);
|
|
208
389
|
const related = relatedMap(entry);
|
|
390
|
+
const footer = feedbackFooter(entry.id, entry.content_hash);
|
|
391
|
+
const resourceYaml = readText(join(dir, "resource.yaml"))?.replace(/\s+$/, "") ?? "(resource.yaml not found in this install)";
|
|
392
|
+
const base = {
|
|
393
|
+
ok: true,
|
|
394
|
+
id: entry.id,
|
|
395
|
+
kind: entry.kind,
|
|
396
|
+
slug,
|
|
397
|
+
version: entry.version ?? "",
|
|
398
|
+
status: entry.status ?? "stable",
|
|
399
|
+
content_hash: entry.content_hash ?? "",
|
|
400
|
+
summary: entry.summary ?? "",
|
|
401
|
+
use_when: Array.isArray(entry.use_when) ? entry.use_when : [],
|
|
402
|
+
related,
|
|
403
|
+
part,
|
|
404
|
+
path: relPath,
|
|
405
|
+
files,
|
|
406
|
+
entry_id: entryIdWithHash(entry.id, entry.content_hash),
|
|
407
|
+
footer,
|
|
408
|
+
};
|
|
409
|
+
if (linkedFile !== undefined) {
|
|
410
|
+
const libPath = `${relPath}/${linkedFile}`;
|
|
411
|
+
const extension = posix.extname(linkedFile).toLowerCase();
|
|
412
|
+
const size = (() => {
|
|
413
|
+
try {
|
|
414
|
+
return statSync(join(root, ...libPath.split("/"))).size;
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
return Number.POSITIVE_INFINITY;
|
|
418
|
+
}
|
|
419
|
+
})();
|
|
420
|
+
const sections = [
|
|
421
|
+
`${entry.id}/${linkedFile} — a file shipped with ${entry.id} (${entry.kind} v${entry.version ?? "?"}, ${entry.status ?? "stable"}). The entry itself: summer_read_library id "${entry.id}".`,
|
|
422
|
+
];
|
|
423
|
+
let links = [];
|
|
424
|
+
if (part === "resource") {
|
|
425
|
+
sections.push(`--- ${relPath}/resource.yaml ---\n${resourceYaml}`);
|
|
426
|
+
}
|
|
427
|
+
else if (!LINKED_FILE_EXTENSIONS.has(extension)) {
|
|
428
|
+
sections.push(`--- ${libPath} ---\n(not a text file read_library loads: ${extension || "no extension"}; it ships at ${libPath} in the package)`);
|
|
429
|
+
}
|
|
430
|
+
else if (size > LINKED_FILE_MAX_BYTES) {
|
|
431
|
+
sections.push(`--- ${libPath} ---\n(${size} bytes, over the ${LINKED_FILE_MAX_BYTES}-byte limit for a linked file; it ships at ${libPath} in the package)`);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
const text = readText(join(root, ...libPath.split("/")))?.replace(/\s+$/, "") ?? "(file could not be read)";
|
|
435
|
+
sections.push(`--- ${libPath} ---\n${text}`);
|
|
436
|
+
if (extension === ".md" || extension === ".markdown") {
|
|
437
|
+
links = linksOf(text, entry, linkedFile, entries, root);
|
|
438
|
+
if (links.length > 0)
|
|
439
|
+
sections.push(linksSection(links));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
sections.push(footer);
|
|
443
|
+
return {
|
|
444
|
+
...base,
|
|
445
|
+
body_file: linkedFile,
|
|
446
|
+
linked_file: linkedFile,
|
|
447
|
+
...(links.length > 0 ? { links } : {}),
|
|
448
|
+
text: sections.join("\n\n"),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
209
451
|
let bodyFile;
|
|
210
452
|
let bodyTitle;
|
|
211
453
|
let body;
|
|
454
|
+
let links = [];
|
|
212
455
|
if (kind === "tool") {
|
|
213
456
|
bodyTitle = "how to call";
|
|
214
457
|
body = toolBody(entry, slug);
|
|
@@ -224,40 +467,28 @@ export async function readLibraryEntry(requestedId, part = "all", deps = {}) {
|
|
|
224
467
|
bodyFile = picked;
|
|
225
468
|
bodyTitle = `${relPath}/${picked}`;
|
|
226
469
|
body = text.replace(/\s+$/, "");
|
|
470
|
+
if (picked.toLowerCase().endsWith(".md"))
|
|
471
|
+
links = linksOf(body, entry, picked, entries, root);
|
|
227
472
|
}
|
|
228
473
|
else {
|
|
229
474
|
bodyTitle = "body";
|
|
230
475
|
body = `(no body file shipped for this ${kind}; the descriptor below is all there is)`;
|
|
231
476
|
}
|
|
232
477
|
}
|
|
233
|
-
const resourceYaml = readText(join(dir, "resource.yaml"))?.replace(/\s+$/, "") ?? "(resource.yaml not found in this install)";
|
|
234
|
-
const footer = feedbackFooter(entry.id, entry.content_hash);
|
|
235
478
|
const sections = [header(entry, slug, related)];
|
|
236
|
-
if (part === "skill" || part === "all")
|
|
479
|
+
if (part === "skill" || part === "all") {
|
|
237
480
|
sections.push(`--- ${bodyTitle} ---\n${body}`);
|
|
481
|
+
if (links.length > 0)
|
|
482
|
+
sections.push(linksSection(links));
|
|
483
|
+
}
|
|
238
484
|
if (part === "resource" || part === "all")
|
|
239
485
|
sections.push(`--- ${relPath}/resource.yaml ---\n${resourceYaml}`);
|
|
240
486
|
sections.push(footer);
|
|
241
|
-
const result = {
|
|
242
|
-
ok: true,
|
|
243
|
-
id: entry.id,
|
|
244
|
-
kind: entry.kind,
|
|
245
|
-
slug,
|
|
246
|
-
version: entry.version ?? "",
|
|
247
|
-
status: entry.status ?? "stable",
|
|
248
|
-
content_hash: entry.content_hash ?? "",
|
|
249
|
-
summary: entry.summary ?? "",
|
|
250
|
-
use_when: Array.isArray(entry.use_when) ? entry.use_when : [],
|
|
251
|
-
related,
|
|
252
|
-
part,
|
|
253
|
-
path: relPath,
|
|
254
|
-
files,
|
|
255
|
-
entry_id: entryIdWithHash(entry.id, entry.content_hash),
|
|
256
|
-
footer,
|
|
257
|
-
text: sections.join("\n\n"),
|
|
258
|
-
};
|
|
487
|
+
const result = { ...base, text: sections.join("\n\n") };
|
|
259
488
|
if (bodyFile)
|
|
260
489
|
result.body_file = bodyFile;
|
|
490
|
+
if (links.length > 0 && part !== "resource")
|
|
491
|
+
result.links = links;
|
|
261
492
|
if (kind === "tool") {
|
|
262
493
|
if (entry.mcp_tool_name)
|
|
263
494
|
result.mcp_tool_name = entry.mcp_tool_name;
|
|
@@ -96,12 +96,12 @@ export declare const searchLibraryInputSchema: z.ZodObject<{
|
|
|
96
96
|
include_preview: z.ZodOptional<z.ZodBoolean>;
|
|
97
97
|
}, "strict", z.ZodTypeAny, {
|
|
98
98
|
query: string;
|
|
99
|
-
kinds?: ("template" | "tool" | "
|
|
99
|
+
kinds?: ("template" | "tool" | "reference" | "skill" | "example" | "collection")[] | undefined;
|
|
100
100
|
limit?: number | undefined;
|
|
101
101
|
include_preview?: boolean | undefined;
|
|
102
102
|
}, {
|
|
103
103
|
query: string;
|
|
104
|
-
kinds?: ("template" | "tool" | "
|
|
104
|
+
kinds?: ("template" | "tool" | "reference" | "skill" | "example" | "collection")[] | undefined;
|
|
105
105
|
limit?: number | undefined;
|
|
106
106
|
include_preview?: boolean | undefined;
|
|
107
107
|
}>;
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "fs";
|
|
|
2
2
|
import { copyFile, mkdir, readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname, join, resolve } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
-
import { isMap, parseDocument } from "yaml";
|
|
5
|
+
import { Document, isMap, parseDocument } from "yaml";
|
|
6
6
|
import { PACKAGE_ROOT } from "../core/package-root.js";
|
|
7
7
|
import { agentAliasMap, agentSpec, defaultPathContext, resolveMcpPath, supportedAgents, } from "./agent-table.js";
|
|
8
8
|
export { supportedAgents } from "./agent-table.js";
|
|
@@ -135,7 +135,7 @@ export function renderConfigSnippet(agent, server) {
|
|
|
135
135
|
return renderJsonFile(geminiExtensionManifest(server, readBundledGeminiManifestSync()));
|
|
136
136
|
}
|
|
137
137
|
if (format === "yaml-goose" || format === "yaml-hermes") {
|
|
138
|
-
const doc =
|
|
138
|
+
const doc = new Document({});
|
|
139
139
|
doc.setIn([topLevelKey(format), SUMMER_MCP_SERVER_NAME], doc.createNode(mcpEntry(format, server)));
|
|
140
140
|
return doc.toString();
|
|
141
141
|
}
|
|
@@ -250,7 +250,9 @@ async function upsertJsonEntry(path, format, server, write) {
|
|
|
250
250
|
*/
|
|
251
251
|
async function upsertYamlConfig(path, keyPath, entry, write) {
|
|
252
252
|
const current = await readTextFileIfExists(path);
|
|
253
|
-
|
|
253
|
+
// An empty file starts from a fresh block-style document; parseDocument("{}")
|
|
254
|
+
// would make the root a flow mapping and the whole file would render as {}.
|
|
255
|
+
const doc = current.trim() === "" ? new Document({}) : parseDocument(current);
|
|
254
256
|
if (doc.errors.length > 0) {
|
|
255
257
|
throw new Error(`Could not parse YAML in ${path}: ${doc.errors[0].message}`);
|
|
256
258
|
}
|
|
@@ -48,6 +48,16 @@ export interface SkillHome {
|
|
|
48
48
|
project: ((ctx: PathContext) => string) | null;
|
|
49
49
|
suffix: string;
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Skill folders Summer 3.1.0 wrote for this agent before it moved to the
|
|
53
|
+
* shared agentskills.io folder (~/.agents/skills). `skills install --force`
|
|
54
|
+
* removes Summer's own skill dirs there so the agent does not load the same
|
|
55
|
+
* skill twice.
|
|
56
|
+
*/
|
|
57
|
+
legacyDirs?: {
|
|
58
|
+
user: (ctx: PathContext) => string;
|
|
59
|
+
project: ((ctx: PathContext) => string) | null;
|
|
60
|
+
};
|
|
51
61
|
}
|
|
52
62
|
export interface AgentSpec {
|
|
53
63
|
id: SupportedAgent;
|
|
@@ -74,6 +84,10 @@ export interface AgentSpec {
|
|
|
74
84
|
skills: SkillHome | null;
|
|
75
85
|
noSkillsNote?: string;
|
|
76
86
|
}
|
|
87
|
+
/** True when this location is the shared agentskills.io folder. */
|
|
88
|
+
export declare function isSharedSkillsPath(path: string): boolean;
|
|
89
|
+
/** Agents that read the shared folder at the given scope (for the install summary). */
|
|
90
|
+
export declare function agentsSharingSkills(scope: ConfigScope, ctx: PathContext): AgentSpec[];
|
|
77
91
|
export declare function agentSpec(id: SupportedAgent): AgentSpec;
|
|
78
92
|
export declare function allAgentSpecs(): readonly AgentSpec[];
|
|
79
93
|
/** Ids shown in help and error messages (legacy ids still parse). */
|
|
@@ -94,6 +108,8 @@ export interface ResolvedMcpPath {
|
|
|
94
108
|
export declare function resolveMcpPath(spec: AgentSpec, scope: ConfigScope, ctx: PathContext): ResolvedMcpPath;
|
|
95
109
|
/** Rule files a pre-3.1 Summer wrote for this agent at this scope; `null` when the agent never had any. */
|
|
96
110
|
export declare function legacyRuleFiles(spec: AgentSpec, scope: ConfigScope, ctx: PathContext, skillNames: Iterable<string>): string[] | null;
|
|
111
|
+
/** Skill dirs a Summer 3.1.0 install may have written at this agent's old native location; `null` when it never moved. */
|
|
112
|
+
export declare function legacySkillDirs(spec: AgentSpec, scope: ConfigScope, ctx: PathContext, skillNames: Iterable<string>): string[] | null;
|
|
97
113
|
export interface ResolvedSkillPath {
|
|
98
114
|
kind: SkillLocationKind;
|
|
99
115
|
path: string;
|