maestro-flow 0.5.41 → 0.5.43
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/.agents/skills/domain-add/SKILL.md +3 -0
- package/.agents/skills/learn-decompose/SKILL.md +7 -4
- package/.agents/skills/learn-follow/SKILL.md +4 -2
- package/.agents/skills/learn-investigate/SKILL.md +8 -6
- package/.agents/skills/learn-second-opinion/SKILL.md +6 -3
- package/.agents/skills/maestro/SKILL.md +1 -1
- package/.agents/skills/maestro-amend/SKILL.md +1 -1
- package/.agents/skills/maestro-analyze/SKILL.md +1 -43
- package/.agents/skills/maestro-blueprint/SKILL.md +1 -23
- package/.agents/skills/maestro-brainstorm/SKILL.md +8 -25
- package/.agents/skills/maestro-collab/SKILL.md +6 -2
- package/.agents/skills/maestro-companion/SKILL.md +4 -1
- package/.agents/skills/maestro-composer/SKILL.md +4 -2
- package/.agents/skills/maestro-execute/SKILL.md +27 -9
- package/.agents/skills/maestro-fork/SKILL.md +4 -3
- package/.agents/skills/maestro-grill/SKILL.md +1 -17
- package/.agents/skills/maestro-guard/SKILL.md +2 -2
- package/.agents/skills/maestro-impeccable/SKILL.md +2 -1
- package/.agents/skills/maestro-init/SKILL.md +1 -1
- package/.agents/skills/maestro-merge/SKILL.md +12 -1
- package/.agents/skills/maestro-milestone-audit/SKILL.md +1 -15
- package/.agents/skills/maestro-milestone-complete/SKILL.md +8 -3
- package/.agents/skills/maestro-milestone-release/SKILL.md +8 -4
- package/.agents/skills/maestro-overlay/SKILL.md +9 -0
- package/.agents/skills/maestro-plan/SKILL.md +6 -62
- package/.agents/skills/maestro-player/SKILL.md +2 -2
- package/.agents/skills/maestro-quick/SKILL.md +5 -3
- package/.agents/skills/maestro-ralph/SKILL.md +8 -8
- package/.agents/skills/maestro-ralph-cli/SKILL.md +665 -0
- package/.agents/skills/maestro-ralph-cli-execute/SKILL.md +239 -0
- package/.agents/skills/maestro-ralph-execute/SKILL.md +127 -11
- package/.agents/skills/maestro-roadmap/SKILL.md +1 -9
- package/.agents/skills/maestro-swarm-workflow/SKILL.md +16 -14
- package/.agents/skills/maestro-tools-register/SKILL.md +16 -1
- package/.agents/skills/maestro-ui-codify/SKILL.md +11 -1
- package/.agents/skills/maestro-universal-workflow/SKILL.md +28 -5
- package/.agents/skills/maestro-update/SKILL.md +10 -7
- package/.agents/skills/manage-codebase-rebuild/SKILL.md +5 -1
- package/.agents/skills/manage-drift-realign/SKILL.md +6 -2
- package/.agents/skills/manage-harvest/SKILL.md +4 -1
- package/.agents/skills/manage-issue-discover/SKILL.md +1 -0
- package/.agents/skills/manage-kg-extractors/SKILL.md +5 -1
- package/.agents/skills/manage-knowhow-capture/SKILL.md +1 -0
- package/.agents/skills/manage-knowledge-audit/SKILL.md +3 -0
- package/.agents/skills/manage-wiki/SKILL.md +1 -0
- package/.agents/skills/odyssey-debug/SKILL.md +2 -1
- package/.agents/skills/odyssey-improve/SKILL.md +2 -2
- package/.agents/skills/odyssey-planex/SKILL.md +8 -7
- package/.agents/skills/odyssey-review-test-fix/SKILL.md +4 -1
- package/.agents/skills/odyssey-ui/SKILL.md +4 -4
- package/.agents/skills/quality-auto-test/SKILL.md +11 -1
- package/.agents/skills/quality-debug/SKILL.md +16 -2
- package/.agents/skills/quality-retrospective/SKILL.md +9 -1
- package/.agents/skills/quality-review/SKILL.md +8 -0
- package/.agents/skills/quality-sync/SKILL.md +2 -2
- package/.agents/skills/quality-test/SKILL.md +9 -1
- package/.agents/skills/security-audit/SKILL.md +14 -4
- package/.agents/skills/spec-add/SKILL.md +5 -2
- package/.agents/skills/spec-load/SKILL.md +1 -1
- package/.agents/skills/spec-remove/SKILL.md +1 -1
- package/.agents/skills/spec-setup/SKILL.md +3 -0
- package/.agents/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -248
- package/.agents/skills/team-coordinate/specs/role-spec-template.md +197 -198
- package/.agents/skills/team-roadmap-dev/SKILL.md +164 -164
- package/.agents/skills/team-roadmap-dev/specs/team-config.json +1 -1
- package/.agents/skills/team-swarm/roles/analyst/role.md +172 -176
- package/.agy/skills/domain-add/SKILL.md +3 -0
- package/.agy/skills/learn-decompose/SKILL.md +7 -4
- package/.agy/skills/learn-follow/SKILL.md +4 -2
- package/.agy/skills/learn-investigate/SKILL.md +8 -6
- package/.agy/skills/learn-second-opinion/SKILL.md +6 -3
- package/.agy/skills/maestro/SKILL.md +1 -1
- package/.agy/skills/maestro-amend/SKILL.md +1 -1
- package/.agy/skills/maestro-analyze/SKILL.md +1 -43
- package/.agy/skills/maestro-blueprint/SKILL.md +1 -23
- package/.agy/skills/maestro-brainstorm/SKILL.md +8 -25
- package/.agy/skills/maestro-collab/SKILL.md +6 -2
- package/.agy/skills/maestro-companion/SKILL.md +4 -1
- package/.agy/skills/maestro-composer/SKILL.md +4 -2
- package/.agy/skills/maestro-execute/SKILL.md +27 -9
- package/.agy/skills/maestro-fork/SKILL.md +4 -3
- package/.agy/skills/maestro-grill/SKILL.md +1 -17
- package/.agy/skills/maestro-guard/SKILL.md +2 -2
- package/.agy/skills/maestro-impeccable/SKILL.md +2 -1
- package/.agy/skills/maestro-init/SKILL.md +1 -1
- package/.agy/skills/maestro-merge/SKILL.md +12 -1
- package/.agy/skills/maestro-milestone-audit/SKILL.md +1 -15
- package/.agy/skills/maestro-milestone-complete/SKILL.md +8 -3
- package/.agy/skills/maestro-milestone-release/SKILL.md +8 -4
- package/.agy/skills/maestro-overlay/SKILL.md +9 -0
- package/.agy/skills/maestro-plan/SKILL.md +6 -62
- package/.agy/skills/maestro-player/SKILL.md +2 -2
- package/.agy/skills/maestro-quick/SKILL.md +5 -3
- package/.agy/skills/maestro-ralph/SKILL.md +8 -8
- package/.agy/skills/maestro-ralph-cli/SKILL.md +661 -0
- package/.agy/skills/maestro-ralph-cli-execute/SKILL.md +235 -0
- package/.agy/skills/maestro-ralph-execute/SKILL.md +127 -11
- package/.agy/skills/maestro-roadmap/SKILL.md +1 -9
- package/.agy/skills/maestro-swarm-workflow/SKILL.md +16 -14
- package/.agy/skills/maestro-tools-register/SKILL.md +16 -1
- package/.agy/skills/maestro-ui-codify/SKILL.md +11 -1
- package/.agy/skills/maestro-universal-workflow/SKILL.md +28 -5
- package/.agy/skills/maestro-update/SKILL.md +10 -7
- package/.agy/skills/manage-codebase-rebuild/SKILL.md +5 -1
- package/.agy/skills/manage-drift-realign/SKILL.md +6 -2
- package/.agy/skills/manage-harvest/SKILL.md +4 -1
- package/.agy/skills/manage-issue-discover/SKILL.md +1 -0
- package/.agy/skills/manage-kg-extractors/SKILL.md +5 -1
- package/.agy/skills/manage-knowhow-capture/SKILL.md +1 -0
- package/.agy/skills/manage-knowledge-audit/SKILL.md +3 -0
- package/.agy/skills/manage-wiki/SKILL.md +1 -0
- package/.agy/skills/odyssey-debug/SKILL.md +2 -1
- package/.agy/skills/odyssey-improve/SKILL.md +2 -2
- package/.agy/skills/odyssey-planex/SKILL.md +8 -7
- package/.agy/skills/odyssey-review-test-fix/SKILL.md +4 -1
- package/.agy/skills/odyssey-ui/SKILL.md +4 -4
- package/.agy/skills/quality-auto-test/SKILL.md +11 -1
- package/.agy/skills/quality-debug/SKILL.md +16 -2
- package/.agy/skills/quality-retrospective/SKILL.md +9 -1
- package/.agy/skills/quality-review/SKILL.md +8 -0
- package/.agy/skills/quality-sync/SKILL.md +2 -2
- package/.agy/skills/quality-test/SKILL.md +9 -1
- package/.agy/skills/security-audit/SKILL.md +14 -4
- package/.agy/skills/spec-add/SKILL.md +5 -2
- package/.agy/skills/spec-load/SKILL.md +1 -1
- package/.agy/skills/spec-remove/SKILL.md +1 -1
- package/.agy/skills/spec-setup/SKILL.md +3 -0
- package/.agy/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -248
- package/.agy/skills/team-coordinate/specs/role-spec-template.md +197 -198
- package/.agy/skills/team-roadmap-dev/SKILL.md +141 -153
- package/.agy/skills/team-roadmap-dev/specs/team-config.json +1 -1
- package/.agy/skills/team-swarm/roles/analyst/role.md +172 -176
- package/.claude/commands/domain-add.md +3 -0
- package/.claude/commands/learn-decompose.md +7 -4
- package/.claude/commands/learn-follow.md +4 -2
- package/.claude/commands/learn-investigate.md +8 -6
- package/.claude/commands/learn-second-opinion.md +6 -3
- package/.claude/commands/maestro-amend.md +1 -1
- package/.claude/commands/maestro-analyze.md +1 -43
- package/.claude/commands/maestro-blueprint.md +1 -23
- package/.claude/commands/maestro-brainstorm.md +8 -25
- package/.claude/commands/maestro-collab.md +6 -2
- package/.claude/commands/maestro-companion.md +4 -1
- package/.claude/commands/maestro-composer.md +4 -2
- package/.claude/commands/maestro-execute.md +27 -9
- package/.claude/commands/maestro-fork.md +4 -3
- package/.claude/commands/maestro-grill.md +1 -17
- package/.claude/commands/maestro-guard.md +2 -2
- package/.claude/commands/maestro-impeccable.md +2 -1
- package/.claude/commands/maestro-init.md +1 -1
- package/.claude/commands/maestro-merge.md +12 -1
- package/.claude/commands/maestro-milestone-audit.md +1 -15
- package/.claude/commands/maestro-milestone-complete.md +8 -3
- package/.claude/commands/maestro-milestone-release.md +8 -4
- package/.claude/commands/maestro-overlay.md +9 -0
- package/.claude/commands/maestro-plan.md +6 -62
- package/.claude/commands/maestro-player.md +2 -2
- package/.claude/commands/maestro-quick.md +5 -3
- package/.claude/commands/maestro-ralph-cli-execute.md +237 -0
- package/.claude/commands/maestro-ralph-cli.md +663 -0
- package/.claude/commands/maestro-ralph-execute.md +127 -11
- package/.claude/commands/maestro-ralph.md +8 -8
- package/.claude/commands/maestro-roadmap.md +1 -9
- package/.claude/commands/maestro-swarm-workflow.md +16 -14
- package/.claude/commands/maestro-tools-register.md +16 -1
- package/.claude/commands/maestro-ui-codify.md +11 -1
- package/.claude/commands/maestro-universal-workflow.md +28 -5
- package/.claude/commands/maestro-update.md +10 -7
- package/.claude/commands/maestro.md +1 -1
- package/.claude/commands/manage-codebase-rebuild.md +5 -1
- package/.claude/commands/manage-drift-realign.md +6 -2
- package/.claude/commands/manage-harvest.md +4 -1
- package/.claude/commands/manage-issue-discover.md +1 -0
- package/.claude/commands/manage-kg-extractors.md +5 -1
- package/.claude/commands/manage-knowhow-capture.md +1 -0
- package/.claude/commands/manage-knowledge-audit.md +3 -0
- package/.claude/commands/manage-wiki.md +1 -0
- package/.claude/commands/odyssey-debug.md +2 -1
- package/.claude/commands/odyssey-improve.md +2 -2
- package/.claude/commands/odyssey-planex.md +8 -7
- package/.claude/commands/odyssey-review-test-fix.md +4 -1
- package/.claude/commands/odyssey-ui.md +4 -4
- package/.claude/commands/quality-auto-test.md +11 -1
- package/.claude/commands/quality-debug.md +16 -2
- package/.claude/commands/quality-retrospective.md +9 -1
- package/.claude/commands/quality-review.md +8 -0
- package/.claude/commands/quality-sync.md +2 -2
- package/.claude/commands/quality-test.md +9 -1
- package/.claude/commands/security-audit.md +14 -4
- package/.claude/commands/spec-add.md +5 -2
- package/.claude/commands/spec-load.md +1 -1
- package/.claude/commands/spec-remove.md +1 -1
- package/.claude/commands/spec-setup.md +3 -0
- package/.claude/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -248
- package/.claude/skills/team-coordinate/specs/role-spec-template.md +197 -198
- package/.claude/skills/team-roadmap-dev/SKILL.md +169 -169
- package/.claude/skills/team-roadmap-dev/specs/team-config.json +1 -1
- package/.claude/skills/team-swarm/roles/analyst/role.md +181 -185
- package/.codex/skills/codify-to-knowhow/SKILL.md +27 -15
- package/.codex/skills/domain-add/SKILL.md +5 -3
- package/.codex/skills/learn-decompose/SKILL.md +22 -4
- package/.codex/skills/learn-follow/SKILL.md +12 -6
- package/.codex/skills/learn-investigate/SKILL.md +11 -6
- package/.codex/skills/learn-retro/SKILL.md +12 -6
- package/.codex/skills/learn-second-opinion/SKILL.md +11 -3
- package/.codex/skills/maestro/SKILL.md +19 -13
- package/.codex/skills/maestro-amend/SKILL.md +10 -2
- package/.codex/skills/maestro-analyze/SKILL.md +7 -1
- package/.codex/skills/maestro-blueprint/SKILL.md +1 -1
- package/.codex/skills/maestro-brainstorm/SKILL.md +11 -8
- package/.codex/skills/maestro-collab/SKILL.md +5 -5
- package/.codex/skills/maestro-companion/SKILL.md +4 -1
- package/.codex/skills/maestro-composer/SKILL.md +6 -3
- package/.codex/skills/maestro-execute/SKILL.md +11 -8
- package/.codex/skills/maestro-fork/SKILL.md +4 -3
- package/.codex/skills/maestro-grill/SKILL.md +1 -1
- package/.codex/skills/maestro-guard/SKILL.md +1 -1
- package/.codex/skills/maestro-impeccable/SKILL.md +5 -5
- package/.codex/skills/maestro-init/SKILL.md +3 -2
- package/.codex/skills/maestro-milestone-audit/SKILL.md +21 -9
- package/.codex/skills/maestro-milestone-complete/SKILL.md +3 -3
- package/.codex/skills/maestro-milestone-release/SKILL.md +18 -1
- package/.codex/skills/maestro-next/SKILL.md +11 -10
- package/.codex/skills/maestro-overlay/SKILL.md +16 -6
- package/.codex/skills/maestro-player/SKILL.md +11 -5
- package/.codex/skills/maestro-quick/SKILL.md +2 -2
- package/.codex/skills/maestro-ralph/SKILL.md +44 -31
- package/.codex/skills/maestro-ralph-cli/SKILL.md +394 -0
- package/.codex/skills/maestro-ralph-cli-execute/SKILL.md +146 -0
- package/.codex/skills/maestro-ralph-execute/SKILL.md +105 -24
- package/.codex/skills/maestro-roadmap/SKILL.md +8 -2
- package/.codex/skills/maestro-tools-execute/SKILL.md +8 -4
- package/.codex/skills/maestro-tools-register/SKILL.md +10 -6
- package/.codex/skills/maestro-ui-codify/SKILL.md +14 -9
- package/.codex/skills/manage-codebase-rebuild/SKILL.md +36 -14
- package/.codex/skills/manage-codebase-refresh/SKILL.md +1 -1
- package/.codex/skills/manage-drift-realign/SKILL.md +15 -12
- package/.codex/skills/manage-harvest/SKILL.md +1 -1
- package/.codex/skills/manage-issue/SKILL.md +8 -4
- package/.codex/skills/manage-issue-discover/SKILL.md +15 -14
- package/.codex/skills/manage-knowhow/SKILL.md +3 -2
- package/.codex/skills/manage-knowhow-capture/SKILL.md +4 -3
- package/.codex/skills/manage-learn/SKILL.md +2 -2
- package/.codex/skills/odyssey-debug/SKILL.md +12 -7
- package/.codex/skills/odyssey-improve/SKILL.md +11 -6
- package/.codex/skills/odyssey-planex/SKILL.md +14 -8
- package/.codex/skills/odyssey-review-test-fix/SKILL.md +12 -7
- package/.codex/skills/odyssey-ui/SKILL.md +10 -5
- package/.codex/skills/quality-auto-test/SKILL.md +13 -5
- package/.codex/skills/quality-debug/SKILL.md +18 -11
- package/.codex/skills/quality-refactor/SKILL.md +4 -4
- package/.codex/skills/quality-retrospective/SKILL.md +5 -6
- package/.codex/skills/quality-review/SKILL.md +18 -11
- package/.codex/skills/quality-sync/SKILL.md +2 -2
- package/.codex/skills/quality-test/SKILL.md +7 -5
- package/.codex/skills/security-audit/SKILL.md +7 -5
- package/.codex/skills/spec-add/SKILL.md +9 -7
- package/.codex/skills/spec-load/SKILL.md +3 -2
- package/.codex/skills/spec-map/SKILL.md +10 -1
- package/.codex/skills/spec-remove/SKILL.md +3 -2
- package/.codex/skills/team-coordinate/SKILL.md +10 -4
- package/.codex/skills/team-lifecycle-v4/SKILL.md +33 -26
- package/.codex/skills/team-quality-assurance/SKILL.md +43 -0
- package/.codex/skills/team-review/SKILL.md +50 -6
- package/.codex/skills/team-tech-debt/SKILL.md +53 -7
- package/.codex/skills/team-testing/SKILL.md +50 -2
- package/.codex/skills/wiki-connect/SKILL.md +3 -1
- package/.codex/skills/wiki-digest/SKILL.md +6 -4
- package/dashboard/dist-server/dashboard/src/server/wiki/embedding.d.ts +16 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/embedding.js +419 -44
- package/dashboard/dist-server/dashboard/src/server/wiki/embedding.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js +43 -5
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js.map +1 -1
- package/dashboard/dist-server/src/commands/install-backend.js +31 -16
- package/dashboard/dist-server/src/commands/install-backend.js.map +1 -1
- package/dashboard/dist-server/src/core/component-defs.js +25 -0
- package/dashboard/dist-server/src/core/component-defs.js.map +1 -1
- package/dashboard/dist-server/src/graph/kg/db/types.d.ts +3 -0
- package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.d.ts +46 -0
- package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.js +329 -0
- package/dashboard/dist-server/src/graph/kg/embedding/code-embedding.js.map +1 -0
- package/dashboard/dist-server/src/graph/kg/embedding/index.d.ts +2 -0
- package/dashboard/dist-server/src/graph/kg/embedding/index.js +3 -0
- package/dashboard/dist-server/src/graph/kg/embedding/index.js.map +1 -0
- package/dashboard/dist-server/src/graph/kg/engine.d.ts +19 -1
- package/dashboard/dist-server/src/graph/kg/engine.js +71 -1
- package/dashboard/dist-server/src/graph/kg/engine.js.map +1 -1
- package/dashboard/dist-server/src/graph/kg/query/scoring.d.ts +5 -0
- package/dashboard/dist-server/src/graph/kg/query/scoring.js +85 -1
- package/dashboard/dist-server/src/graph/kg/query/scoring.js.map +1 -1
- package/dashboard/dist-server/src/graph/kg/query/search.d.ts +7 -0
- package/dashboard/dist-server/src/graph/kg/query/search.js +117 -1
- package/dashboard/dist-server/src/graph/kg/query/search.js.map +1 -1
- package/dashboard/dist-server/src/graph/kg/surface/mcp-tools.js +49 -0
- package/dashboard/dist-server/src/graph/kg/surface/mcp-tools.js.map +1 -1
- package/dashboard/dist-server/src/hooks/kg-sync-hook.js +3 -0
- package/dashboard/dist-server/src/hooks/kg-sync-hook.js.map +1 -1
- package/dashboard/dist-server/src/tools/spec-loader.js +7 -3
- package/dashboard/dist-server/src/tools/spec-loader.js.map +1 -1
- package/dist/src/commands/install-backend.d.ts.map +1 -1
- package/dist/src/commands/install-backend.js +31 -16
- package/dist/src/commands/install-backend.js.map +1 -1
- package/dist/src/core/component-defs.d.ts.map +1 -1
- package/dist/src/core/component-defs.js +25 -0
- package/dist/src/core/component-defs.js.map +1 -1
- package/dist/src/core/plugin-bridge.d.ts.map +1 -1
- package/dist/src/core/plugin-bridge.js +17 -0
- package/dist/src/core/plugin-bridge.js.map +1 -1
- package/dist/src/graph/kg/db/types.d.ts +3 -0
- package/dist/src/graph/kg/db/types.d.ts.map +1 -1
- package/dist/src/graph/kg/embedding/code-embedding.d.ts +47 -0
- package/dist/src/graph/kg/embedding/code-embedding.d.ts.map +1 -0
- package/dist/src/graph/kg/embedding/code-embedding.js +329 -0
- package/dist/src/graph/kg/embedding/code-embedding.js.map +1 -0
- package/dist/src/graph/kg/embedding/index.d.ts +3 -0
- package/dist/src/graph/kg/embedding/index.d.ts.map +1 -0
- package/dist/src/graph/kg/embedding/index.js +3 -0
- package/dist/src/graph/kg/embedding/index.js.map +1 -0
- package/dist/src/graph/kg/engine.d.ts +19 -1
- package/dist/src/graph/kg/engine.d.ts.map +1 -1
- package/dist/src/graph/kg/engine.js +71 -1
- package/dist/src/graph/kg/engine.js.map +1 -1
- package/dist/src/graph/kg/query/scoring.d.ts +5 -0
- package/dist/src/graph/kg/query/scoring.d.ts.map +1 -1
- package/dist/src/graph/kg/query/scoring.js +85 -1
- package/dist/src/graph/kg/query/scoring.js.map +1 -1
- package/dist/src/graph/kg/query/search.d.ts +7 -0
- package/dist/src/graph/kg/query/search.d.ts.map +1 -1
- package/dist/src/graph/kg/query/search.js +117 -1
- package/dist/src/graph/kg/query/search.js.map +1 -1
- package/dist/src/graph/kg/surface/mcp-tools.d.ts.map +1 -1
- package/dist/src/graph/kg/surface/mcp-tools.js +49 -0
- package/dist/src/graph/kg/surface/mcp-tools.js.map +1 -1
- package/dist/src/hooks/kg-sync-hook.d.ts.map +1 -1
- package/dist/src/hooks/kg-sync-hook.js +3 -0
- package/dist/src/hooks/kg-sync-hook.js.map +1 -1
- package/dist/src/tools/code-semantic-search.d.ts +10 -0
- package/dist/src/tools/code-semantic-search.d.ts.map +1 -0
- package/dist/src/tools/code-semantic-search.js +81 -0
- package/dist/src/tools/code-semantic-search.js.map +1 -0
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +4 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/spec-loader.d.ts.map +1 -1
- package/dist/src/tools/spec-loader.js +7 -3
- package/dist/src/tools/spec-loader.js.map +1 -1
- package/dist/src/tools/wiki-search.d.ts +13 -0
- package/dist/src/tools/wiki-search.d.ts.map +1 -0
- package/dist/src/tools/wiki-search.js +114 -0
- package/dist/src/tools/wiki-search.js.map +1 -0
- package/dist/src/utils/update-notices.js +23 -0
- package/dist/src/utils/update-notices.js.map +1 -1
- package/package.json +4 -1
- package/workflows/agy-instructions.md +147 -161
- package/workflows/claude-instructions.md +100 -48
- package/workflows/codex-instructions.md +147 -161
- package/workflows/execute.md +4 -3
- package/workflows/explore-usage.md +41 -81
- package/workflows/grill.md +11 -0
- package/workflows/milestone-audit.md +8 -0
- package/workflows/odyssey-base-codex.md +115 -116
- package/workflows/odyssey-base.md +89 -91
- package/workflows/plan.md +6 -0
|
@@ -11,6 +11,19 @@ import { join } from 'node:path';
|
|
|
11
11
|
import { homedir } from 'node:os';
|
|
12
12
|
import { createHash } from 'node:crypto';
|
|
13
13
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, renameSync } from 'node:fs';
|
|
14
|
+
let _zvecModule;
|
|
15
|
+
async function getZvec() {
|
|
16
|
+
if (_zvecModule !== undefined)
|
|
17
|
+
return _zvecModule;
|
|
18
|
+
try {
|
|
19
|
+
_zvecModule = await import('@zvec/zvec');
|
|
20
|
+
return _zvecModule;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
_zvecModule = null;
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
14
27
|
const API_CONFIG_PATH = join(homedir(), '.maestro', 'api-embedding.json');
|
|
15
28
|
let _apiConfig;
|
|
16
29
|
export function loadEmbeddingApiConfig() {
|
|
@@ -265,17 +278,18 @@ export async function detectDevice() {
|
|
|
265
278
|
return _detectedConfig;
|
|
266
279
|
const backends = await listBackends();
|
|
267
280
|
const hasGpu = backends.some(b => b.name === 'dml' || b.name === 'cuda');
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
281
|
+
const envDevice = process.env.MAESTRO_EMBEDDING_DEVICE;
|
|
282
|
+
const envBatch = process.env.MAESTRO_EMBEDDING_BATCH_SIZE;
|
|
283
|
+
const useGpu = envDevice === 'cpu' ? false : hasGpu;
|
|
271
284
|
_detectedConfig = {
|
|
272
|
-
device: 'cpu',
|
|
273
|
-
dtype: 'fp32',
|
|
274
|
-
batchSize: 32,
|
|
285
|
+
device: useGpu ? 'gpu' : 'cpu',
|
|
286
|
+
dtype: useGpu ? 'fp16' : 'fp32',
|
|
287
|
+
batchSize: useGpu ? 128 : (hasGpu ? 64 : 32),
|
|
275
288
|
};
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
|
|
289
|
+
if (envBatch) {
|
|
290
|
+
const parsed = parseInt(envBatch, 10);
|
|
291
|
+
if (parsed > 0)
|
|
292
|
+
_detectedConfig.batchSize = parsed;
|
|
279
293
|
}
|
|
280
294
|
return _detectedConfig;
|
|
281
295
|
}
|
|
@@ -290,13 +304,21 @@ export async function getHardwareInfo() {
|
|
|
290
304
|
const backends = await listBackends();
|
|
291
305
|
const hasGpu = backends.some(b => b.name === 'dml' || b.name === 'cuda');
|
|
292
306
|
const config = await detectDevice();
|
|
307
|
+
let reason;
|
|
308
|
+
if (!hasGpu) {
|
|
309
|
+
reason = 'CPU only — no GPU backend detected';
|
|
310
|
+
}
|
|
311
|
+
else if (config.device === 'gpu') {
|
|
312
|
+
reason = 'GPU auto-selected (DML/CUDA detected) — set MAESTRO_EMBEDDING_DEVICE=cpu to force CPU';
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
reason = 'GPU available but CPU forced via MAESTRO_EMBEDDING_DEVICE=cpu';
|
|
316
|
+
}
|
|
293
317
|
return {
|
|
294
318
|
backends,
|
|
295
319
|
gpuAvailable: hasGpu,
|
|
296
320
|
selectedDevice: config,
|
|
297
|
-
reason
|
|
298
|
-
? 'GPU available (DML/CUDA) but CPU selected — small model (22M params) runs faster on CPU due to transfer overhead'
|
|
299
|
-
: 'CPU only — no GPU backend detected',
|
|
321
|
+
reason,
|
|
300
322
|
};
|
|
301
323
|
}
|
|
302
324
|
// ---------------------------------------------------------------------------
|
|
@@ -405,9 +427,55 @@ export async function embedQuery(query) {
|
|
|
405
427
|
return new Float32Array(output.data);
|
|
406
428
|
}
|
|
407
429
|
// ---------------------------------------------------------------------------
|
|
408
|
-
// Vector search
|
|
430
|
+
// Vector search — zvec backend (default) with flat cosine fallback
|
|
409
431
|
// ---------------------------------------------------------------------------
|
|
432
|
+
const ZVEC_DIR = 'embedding.zvec';
|
|
410
433
|
export function vectorSearch(queryVector, index, limit) {
|
|
434
|
+
// Feature flag: force flat cosine scan (bypass zvec)
|
|
435
|
+
if (process.env.MAESTRO_EMBEDDING_FLAT_SCAN) {
|
|
436
|
+
return flatCosineSearch(queryVector, index, limit);
|
|
437
|
+
}
|
|
438
|
+
// Sync path — zvec requires async setup, so use flat scan here.
|
|
439
|
+
// For zvec-accelerated search, callers should use vectorSearchZvec.
|
|
440
|
+
return flatCosineSearch(queryVector, index, limit);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Async vector search using zvec collection.
|
|
444
|
+
* Falls back to flat cosine scan when zvec is unavailable or feature flag is set.
|
|
445
|
+
*/
|
|
446
|
+
export async function vectorSearchZvec(queryVector, dir, limit) {
|
|
447
|
+
if (process.env.MAESTRO_EMBEDDING_FLAT_SCAN) {
|
|
448
|
+
return []; // caller handles fallback via sync vectorSearch
|
|
449
|
+
}
|
|
450
|
+
const zvec = await getZvec();
|
|
451
|
+
if (!zvec)
|
|
452
|
+
return []; // zvec not installed, caller handles fallback
|
|
453
|
+
const collectionPath = join(dir, ZVEC_DIR);
|
|
454
|
+
if (!existsSync(collectionPath))
|
|
455
|
+
return []; // no zvec collection yet
|
|
456
|
+
try {
|
|
457
|
+
const collection = zvec.ZVecOpen(collectionPath, { readOnly: true });
|
|
458
|
+
try {
|
|
459
|
+
const docs = collection.querySync({
|
|
460
|
+
fieldName: 'embedding',
|
|
461
|
+
vector: queryVector,
|
|
462
|
+
topk: limit,
|
|
463
|
+
outputFields: ['docId'],
|
|
464
|
+
});
|
|
465
|
+
return docs.map(d => ({
|
|
466
|
+
docId: d.fields.docId ?? d.id,
|
|
467
|
+
score: 1 - d.score,
|
|
468
|
+
}));
|
|
469
|
+
}
|
|
470
|
+
finally {
|
|
471
|
+
collection.closeSync();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
return []; // zvec query failed, caller handles fallback
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function flatCosineSearch(queryVector, index, limit) {
|
|
411
479
|
const scored = [];
|
|
412
480
|
for (let i = 0; i < index.docIds.length; i++) {
|
|
413
481
|
const sim = cosineSimilarity(queryVector, index.vectors[i]);
|
|
@@ -418,7 +486,7 @@ export function vectorSearch(queryVector, index, limit) {
|
|
|
418
486
|
return scored.slice(0, limit);
|
|
419
487
|
}
|
|
420
488
|
// ---------------------------------------------------------------------------
|
|
421
|
-
// Persistence —
|
|
489
|
+
// Persistence — zvec collection (primary) + binary fallback + legacy migration
|
|
422
490
|
// ---------------------------------------------------------------------------
|
|
423
491
|
const SQLITE_FILE = 'embedding-index.db';
|
|
424
492
|
import { createRequire } from 'node:module';
|
|
@@ -426,6 +494,7 @@ const _require = createRequire(import.meta.url);
|
|
|
426
494
|
const BINARY_FILE = 'embedding-index.bin';
|
|
427
495
|
export function saveEmbeddingIndex(index, dir) {
|
|
428
496
|
mkdirSync(dir, { recursive: true });
|
|
497
|
+
// --- Binary format (kept for backward compat and feature flag fallback) ---
|
|
429
498
|
const dim = index.dimension;
|
|
430
499
|
const n = index.docIds.length;
|
|
431
500
|
const docIdsJson = JSON.stringify(index.docIds);
|
|
@@ -438,6 +507,7 @@ export function saveEmbeddingIndex(index, dir) {
|
|
|
438
507
|
deviceUsed: index.deviceUsed,
|
|
439
508
|
buildTimeMs: index.buildTimeMs,
|
|
440
509
|
contentHashes: index.contentHashes,
|
|
510
|
+
chunkDocIds: index.chunkDocIds,
|
|
441
511
|
});
|
|
442
512
|
const metaBytes = Buffer.from(metaJson, 'utf-8');
|
|
443
513
|
// Format: [metaLen:4][meta][docIdsLen:4][docIds][packedVectors:n*dim*4]
|
|
@@ -462,6 +532,10 @@ export function saveEmbeddingIndex(index, dir) {
|
|
|
462
532
|
const tmpPath = join(dir, BINARY_FILE + '.tmp');
|
|
463
533
|
writeFileSync(tmpPath, buf);
|
|
464
534
|
renameSync(tmpPath, join(dir, BINARY_FILE));
|
|
535
|
+
// --- zvec collection save (async, best-effort) ---
|
|
536
|
+
saveZvecIndex(index, dir).catch(() => {
|
|
537
|
+
// zvec save failed — binary format still available as fallback
|
|
538
|
+
});
|
|
465
539
|
// Remove legacy files
|
|
466
540
|
for (const f of [CACHE_FILE, SQLITE_FILE, SQLITE_FILE + '-shm', SQLITE_FILE + '-wal', SQLITE_FILE + '-journal']) {
|
|
467
541
|
try {
|
|
@@ -471,8 +545,95 @@ export function saveEmbeddingIndex(index, dir) {
|
|
|
471
545
|
catch { /* ignore */ }
|
|
472
546
|
}
|
|
473
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Save embedding index to zvec collection format.
|
|
550
|
+
* Creates/replaces a zvec collection at `dir/embedding.zvec`.
|
|
551
|
+
*/
|
|
552
|
+
async function saveZvecIndex(index, dir) {
|
|
553
|
+
const zvec = await getZvec();
|
|
554
|
+
if (!zvec)
|
|
555
|
+
return;
|
|
556
|
+
const collectionPath = join(dir, ZVEC_DIR);
|
|
557
|
+
const dim = index.dimension;
|
|
558
|
+
// Remove existing collection directory if present
|
|
559
|
+
if (existsSync(collectionPath)) {
|
|
560
|
+
try {
|
|
561
|
+
const existing = zvec.ZVecOpen(collectionPath);
|
|
562
|
+
existing.destroySync();
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
// If we can't open it, try to remove the directory manually
|
|
566
|
+
try {
|
|
567
|
+
const { rmSync } = await import('node:fs');
|
|
568
|
+
rmSync(collectionPath, { recursive: true, force: true });
|
|
569
|
+
}
|
|
570
|
+
catch { /* ignore */ }
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const schema = new zvec.ZVecCollectionSchema({
|
|
574
|
+
name: 'embedding',
|
|
575
|
+
vectors: {
|
|
576
|
+
name: 'embedding',
|
|
577
|
+
dataType: zvec.ZVecDataType.VECTOR_FP32,
|
|
578
|
+
dimension: dim,
|
|
579
|
+
indexParams: {
|
|
580
|
+
indexType: zvec.ZVecIndexType.FLAT,
|
|
581
|
+
metricType: zvec.ZVecMetricType.COSINE,
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
fields: [
|
|
585
|
+
{ name: 'docId', dataType: zvec.ZVecDataType.STRING },
|
|
586
|
+
],
|
|
587
|
+
});
|
|
588
|
+
const collection = zvec.ZVecCreateAndOpen(collectionPath, schema);
|
|
589
|
+
try {
|
|
590
|
+
// Batch upsert all vectors
|
|
591
|
+
const BATCH_SIZE = 500;
|
|
592
|
+
for (let i = 0; i < index.docIds.length; i += BATCH_SIZE) {
|
|
593
|
+
const batch = [];
|
|
594
|
+
const end = Math.min(i + BATCH_SIZE, index.docIds.length);
|
|
595
|
+
for (let j = i; j < end; j++) {
|
|
596
|
+
batch.push({
|
|
597
|
+
id: index.docIds[j],
|
|
598
|
+
vectors: { embedding: index.vectors[j] },
|
|
599
|
+
fields: { docId: index.docIds[j] },
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
collection.upsertSync(batch);
|
|
603
|
+
}
|
|
604
|
+
// Save metadata as JSON sidecar (zvec doesn't store arbitrary metadata)
|
|
605
|
+
const metaSidecar = {
|
|
606
|
+
modelId: index.modelId,
|
|
607
|
+
dimension: dim,
|
|
608
|
+
builtAt: index.builtAt,
|
|
609
|
+
deviceUsed: index.deviceUsed,
|
|
610
|
+
buildTimeMs: index.buildTimeMs,
|
|
611
|
+
contentHashes: index.contentHashes,
|
|
612
|
+
chunkDocIds: index.chunkDocIds,
|
|
613
|
+
docIds: index.docIds,
|
|
614
|
+
};
|
|
615
|
+
writeFileSync(join(dir, ZVEC_DIR + '.meta.json'), JSON.stringify(metaSidecar));
|
|
616
|
+
}
|
|
617
|
+
finally {
|
|
618
|
+
collection.closeSync();
|
|
619
|
+
}
|
|
620
|
+
}
|
|
474
621
|
export function loadEmbeddingIndex(dir) {
|
|
475
|
-
// Primary:
|
|
622
|
+
// Primary: zvec collection + metadata sidecar
|
|
623
|
+
const zvecMetaPath = join(dir, ZVEC_DIR + '.meta.json');
|
|
624
|
+
const zvecCollPath = join(dir, ZVEC_DIR);
|
|
625
|
+
if (existsSync(zvecMetaPath) && existsSync(zvecCollPath)) {
|
|
626
|
+
try {
|
|
627
|
+
return loadFromZvecMeta(zvecMetaPath, zvecCollPath);
|
|
628
|
+
}
|
|
629
|
+
catch (e) {
|
|
630
|
+
if (process.env.DEBUG || process.env.MAESTRO_DEBUG) {
|
|
631
|
+
console.warn(`[embedding] zvec index load failed, falling back: ${e instanceof Error ? e.message : e}`);
|
|
632
|
+
}
|
|
633
|
+
// Fall through to binary
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// Fallback: packed binary
|
|
476
637
|
const binPath = join(dir, BINARY_FILE);
|
|
477
638
|
if (existsSync(binPath)) {
|
|
478
639
|
try {
|
|
@@ -509,6 +670,62 @@ export function loadEmbeddingIndex(dir) {
|
|
|
509
670
|
}
|
|
510
671
|
return null;
|
|
511
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Load EmbeddingIndex from zvec metadata sidecar.
|
|
675
|
+
* The sidecar stores everything needed to reconstruct the in-memory index;
|
|
676
|
+
* the actual zvec collection is used for vectorSearchZvec queries.
|
|
677
|
+
*/
|
|
678
|
+
function loadFromZvecMeta(metaPath, _collectionPath) {
|
|
679
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
680
|
+
// Use cached zvec module if available, otherwise try sync require
|
|
681
|
+
let zvec = _zvecModule ?? null;
|
|
682
|
+
if (!zvec) {
|
|
683
|
+
try {
|
|
684
|
+
zvec = _require('@zvec/zvec');
|
|
685
|
+
_zvecModule = zvec;
|
|
686
|
+
}
|
|
687
|
+
catch {
|
|
688
|
+
throw new Error('zvec not available for loading collection');
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const collection = zvec.ZVecOpen(_collectionPath, { readOnly: true });
|
|
692
|
+
try {
|
|
693
|
+
const vectors = new Array(meta.docIds.length);
|
|
694
|
+
// Fetch vectors in batches by ID
|
|
695
|
+
const BATCH_SIZE = 500;
|
|
696
|
+
for (let i = 0; i < meta.docIds.length; i += BATCH_SIZE) {
|
|
697
|
+
const batchIds = meta.docIds.slice(i, Math.min(i + BATCH_SIZE, meta.docIds.length));
|
|
698
|
+
const fetched = collection.fetchSync({ ids: batchIds, includeVector: true, outputFields: [] });
|
|
699
|
+
const fetchedMap = Array.isArray(fetched)
|
|
700
|
+
? Object.fromEntries(fetched.map((d) => [d.id, d]))
|
|
701
|
+
: fetched;
|
|
702
|
+
for (let j = 0; j < batchIds.length; j++) {
|
|
703
|
+
const doc = fetchedMap[batchIds[j]];
|
|
704
|
+
if (doc?.vectors?.embedding) {
|
|
705
|
+
const v = doc.vectors.embedding;
|
|
706
|
+
vectors[i + j] = v instanceof Float32Array ? v : new Float32Array(v);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
vectors[i + j] = new Float32Array(meta.dimension);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
modelId: meta.modelId,
|
|
715
|
+
dimension: meta.dimension,
|
|
716
|
+
docIds: meta.docIds,
|
|
717
|
+
vectors,
|
|
718
|
+
contentHashes: meta.contentHashes,
|
|
719
|
+
chunkDocIds: meta.chunkDocIds,
|
|
720
|
+
builtAt: meta.builtAt,
|
|
721
|
+
deviceUsed: meta.deviceUsed,
|
|
722
|
+
buildTimeMs: meta.buildTimeMs,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
finally {
|
|
726
|
+
collection.closeSync();
|
|
727
|
+
}
|
|
728
|
+
}
|
|
512
729
|
function loadFromBinary(filePath) {
|
|
513
730
|
const raw = readFileSync(filePath);
|
|
514
731
|
let offset = 0;
|
|
@@ -543,6 +760,7 @@ function loadFromBinary(filePath) {
|
|
|
543
760
|
docIds,
|
|
544
761
|
vectors,
|
|
545
762
|
contentHashes: meta.contentHashes,
|
|
763
|
+
chunkDocIds: meta.chunkDocIds,
|
|
546
764
|
builtAt: meta.builtAt,
|
|
547
765
|
deviceUsed: meta.deviceUsed,
|
|
548
766
|
buildTimeMs: meta.buildTimeMs,
|
|
@@ -590,68 +808,225 @@ function loadFromLegacyJson(filePath) {
|
|
|
590
808
|
};
|
|
591
809
|
}
|
|
592
810
|
export function hashDocContent(d) {
|
|
593
|
-
const text = [d.title, d.summary, d.tags.join(','), d.body
|
|
811
|
+
const text = [d.title, d.summary, d.tags.join(','), d.body ?? ''].join('|');
|
|
594
812
|
return createHash('md5').update(text).digest('hex');
|
|
595
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* Extract meaningful content from a markdown body: first paragraph + heading lines,
|
|
816
|
+
* up to `maxLen` characters.
|
|
817
|
+
*/
|
|
818
|
+
function extractMeaningfulContent(body, maxLen) {
|
|
819
|
+
const lines = body.split('\n');
|
|
820
|
+
const parts = [];
|
|
821
|
+
let len = 0;
|
|
822
|
+
let firstParaDone = false;
|
|
823
|
+
for (const line of lines) {
|
|
824
|
+
if (len >= maxLen)
|
|
825
|
+
break;
|
|
826
|
+
const trimmed = line.trim();
|
|
827
|
+
// Always include heading lines
|
|
828
|
+
if (/^#{1,3}\s/.test(trimmed)) {
|
|
829
|
+
parts.push(trimmed);
|
|
830
|
+
len += trimmed.length + 1;
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
// Include non-empty lines until we hit the first blank line (first paragraph)
|
|
834
|
+
if (!firstParaDone) {
|
|
835
|
+
if (trimmed === '') {
|
|
836
|
+
if (parts.length > 0)
|
|
837
|
+
firstParaDone = true;
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
parts.push(trimmed);
|
|
841
|
+
len += trimmed.length + 1;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const result = parts.join('\n');
|
|
845
|
+
return result.length > maxLen ? result.slice(0, maxLen) : result;
|
|
846
|
+
}
|
|
596
847
|
function docToText(d) {
|
|
597
|
-
const parts = [d.title];
|
|
848
|
+
const parts = [`title: ${d.title}`];
|
|
598
849
|
if (d.summary)
|
|
599
|
-
parts.push(d.summary);
|
|
850
|
+
parts.push(`summary: ${d.summary}`);
|
|
600
851
|
if (d.tags.length > 0)
|
|
601
|
-
parts.push(d.tags.join(' '));
|
|
602
|
-
if (d.body)
|
|
603
|
-
|
|
604
|
-
|
|
852
|
+
parts.push(`tags: ${d.tags.join(', ')}`);
|
|
853
|
+
if (d.body) {
|
|
854
|
+
const body = d.body.length > 500 ? extractMeaningfulContent(d.body, 450) : d.body;
|
|
855
|
+
parts.push(`content: ${body}`);
|
|
856
|
+
}
|
|
857
|
+
parts.push(`title: ${d.title}`);
|
|
858
|
+
const text = parts.join('\n');
|
|
605
859
|
return isApiMode() ? text : 'passage: ' + text;
|
|
606
860
|
}
|
|
861
|
+
/**
|
|
862
|
+
* Split a document into multiple chunks for embedding.
|
|
863
|
+
* Short docs (<500 chars body) produce a single chunk.
|
|
864
|
+
* Long docs are split by markdown heading regex /^#{1,3}\s/m, max 5 chunks.
|
|
865
|
+
* Each chunk inherits title+summary as context prefix.
|
|
866
|
+
*/
|
|
867
|
+
export function splitDocToChunks(d) {
|
|
868
|
+
const contextPrefix = [`title: ${d.title}`];
|
|
869
|
+
if (d.summary)
|
|
870
|
+
contextPrefix.push(`summary: ${d.summary}`);
|
|
871
|
+
if (d.tags.length > 0)
|
|
872
|
+
contextPrefix.push(`tags: ${d.tags.join(', ')}`);
|
|
873
|
+
const prefix = contextPrefix.join('\n');
|
|
874
|
+
// Short or empty body — single chunk using docToText
|
|
875
|
+
if (!d.body || d.body.length < 500) {
|
|
876
|
+
return [{ chunkId: `${d.id}#0`, text: docToText(d) }];
|
|
877
|
+
}
|
|
878
|
+
// Split body by markdown headings
|
|
879
|
+
const sections = d.body.split(/^(?=#{1,3}\s)/m).filter(s => s.trim().length > 0);
|
|
880
|
+
// If splitting produced only one section, single chunk
|
|
881
|
+
if (sections.length <= 1) {
|
|
882
|
+
return [{ chunkId: `${d.id}#0`, text: docToText(d) }];
|
|
883
|
+
}
|
|
884
|
+
// Cap at 5 chunks
|
|
885
|
+
const capped = sections.slice(0, 5);
|
|
886
|
+
const apiMode = isApiMode();
|
|
887
|
+
return capped.map((section, i) => {
|
|
888
|
+
const parts = [prefix, `content: ${section.trim()}`, `title: ${d.title}`];
|
|
889
|
+
const text = parts.join('\n');
|
|
890
|
+
return {
|
|
891
|
+
chunkId: `${d.id}#${i}`,
|
|
892
|
+
text: apiMode ? text : 'passage: ' + text,
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
}
|
|
607
896
|
export async function buildEmbeddingIndex(docs, existingIndex, precomputedHashes) {
|
|
608
897
|
const apiMode = isApiMode();
|
|
609
898
|
const config = apiMode ? null : await detectDevice();
|
|
610
899
|
const t0 = Date.now();
|
|
611
900
|
const currentHashes = precomputedHashes ?? docs.map(hashDocContent);
|
|
901
|
+
// Split all docs into chunks (1:N doc-to-chunk mapping)
|
|
902
|
+
const allChunkIds = [];
|
|
903
|
+
const allChunkDocIds = [];
|
|
904
|
+
const allChunkTexts = [];
|
|
905
|
+
// Track which doc index each chunk group belongs to (for incremental rebuild)
|
|
906
|
+
const docChunkRanges = [];
|
|
907
|
+
for (let i = 0; i < docs.length; i++) {
|
|
908
|
+
const chunks = splitDocToChunks(docs[i]);
|
|
909
|
+
const startSlot = allChunkIds.length;
|
|
910
|
+
for (const chunk of chunks) {
|
|
911
|
+
allChunkIds.push(chunk.chunkId);
|
|
912
|
+
allChunkDocIds.push(docs[i].id);
|
|
913
|
+
allChunkTexts.push(chunk.text);
|
|
914
|
+
}
|
|
915
|
+
docChunkRanges.push({ docIndex: i, startSlot, count: chunks.length });
|
|
916
|
+
}
|
|
612
917
|
let vectors;
|
|
613
918
|
const activeModel = getModelId();
|
|
614
919
|
// Model changed → discard all cached vectors, force full rebuild
|
|
615
920
|
const modelMatch = existingIndex && existingIndex.modelId === activeModel;
|
|
616
921
|
if (modelMatch && existingIndex.docIds.length > 0) {
|
|
617
|
-
//
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
922
|
+
// Build existing chunk cache: chunkId → { vector, parentDocId }
|
|
923
|
+
const existingChunkMap = new Map();
|
|
924
|
+
const existingDocHashes = new Map();
|
|
925
|
+
// Reconstruct per-doc hashes from existing index
|
|
926
|
+
if (existingIndex.chunkDocIds && existingIndex.contentHashes) {
|
|
927
|
+
for (let i = 0; i < existingIndex.docIds.length; i++) {
|
|
928
|
+
existingChunkMap.set(existingIndex.docIds[i], existingIndex.vectors[i]);
|
|
929
|
+
}
|
|
930
|
+
// contentHashes are per-doc; find unique doc→hash mapping
|
|
931
|
+
const seen = new Set();
|
|
932
|
+
for (let i = 0; i < existingIndex.chunkDocIds.length; i++) {
|
|
933
|
+
const parentId = existingIndex.chunkDocIds[i];
|
|
934
|
+
if (!seen.has(parentId) && existingIndex.contentHashes[i] !== undefined) {
|
|
935
|
+
// contentHashes in chunk-based index: stored per-doc in the order of docChunkRanges
|
|
936
|
+
seen.add(parentId);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
// Legacy index without chunkDocIds — docIds are direct doc IDs
|
|
942
|
+
for (let i = 0; i < existingIndex.docIds.length; i++) {
|
|
943
|
+
existingChunkMap.set(existingIndex.docIds[i], existingIndex.vectors[i]);
|
|
944
|
+
if (existingIndex.contentHashes?.[i]) {
|
|
945
|
+
existingDocHashes.set(existingIndex.docIds[i], existingIndex.contentHashes[i]);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
624
948
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
if (
|
|
630
|
-
|
|
949
|
+
// Determine which docs changed (hash comparison at doc level)
|
|
950
|
+
// Rebuild per-doc hash from existing contentHashes
|
|
951
|
+
const existingPerDocHash = new Map();
|
|
952
|
+
if (existingIndex.contentHashes) {
|
|
953
|
+
if (existingIndex.chunkDocIds) {
|
|
954
|
+
// Chunk-based: contentHashes[i] corresponds to the doc that produced chunk i
|
|
955
|
+
// Each doc's hash is stored on its first chunk
|
|
956
|
+
const docSeen = new Set();
|
|
957
|
+
for (let i = 0; i < existingIndex.chunkDocIds.length; i++) {
|
|
958
|
+
const pid = existingIndex.chunkDocIds[i];
|
|
959
|
+
if (!docSeen.has(pid)) {
|
|
960
|
+
docSeen.add(pid);
|
|
961
|
+
existingPerDocHash.set(pid, existingIndex.contentHashes[i] ?? '');
|
|
962
|
+
}
|
|
963
|
+
}
|
|
631
964
|
}
|
|
632
965
|
else {
|
|
633
|
-
|
|
966
|
+
// Legacy: docIds are 1:1 with docs
|
|
967
|
+
for (let i = 0; i < existingIndex.docIds.length; i++) {
|
|
968
|
+
existingPerDocHash.set(existingIndex.docIds[i], existingIndex.contentHashes[i] ?? '');
|
|
969
|
+
}
|
|
634
970
|
}
|
|
635
971
|
}
|
|
636
|
-
|
|
637
|
-
|
|
972
|
+
vectors = new Array(allChunkIds.length);
|
|
973
|
+
const chunksToEmbed = [];
|
|
974
|
+
for (const range of docChunkRanges) {
|
|
975
|
+
const docId = docs[range.docIndex].id;
|
|
976
|
+
const cachedHash = existingPerDocHash.get(docId);
|
|
977
|
+
const currentHash = currentHashes[range.docIndex];
|
|
978
|
+
if (cachedHash && cachedHash === currentHash) {
|
|
979
|
+
// Doc unchanged — try to reuse cached chunk vectors
|
|
980
|
+
let allReused = true;
|
|
981
|
+
for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
|
|
982
|
+
const cachedVec = existingChunkMap.get(allChunkIds[s]);
|
|
983
|
+
if (cachedVec) {
|
|
984
|
+
vectors[s] = cachedVec;
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
allReused = false;
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (!allReused) {
|
|
992
|
+
// Chunk structure changed (e.g., headings added/removed) — re-embed all chunks
|
|
993
|
+
for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
|
|
994
|
+
chunksToEmbed.push({ slot: s, text: allChunkTexts[s] });
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
// Doc changed — re-embed all its chunks
|
|
1000
|
+
for (let s = range.startSlot; s < range.startSlot + range.count; s++) {
|
|
1001
|
+
chunksToEmbed.push({ slot: s, text: allChunkTexts[s] });
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (chunksToEmbed.length > 0) {
|
|
1006
|
+
const texts = chunksToEmbed.map(c => c.text);
|
|
638
1007
|
const newVectors = await embedTexts(texts);
|
|
639
|
-
for (let j = 0; j <
|
|
640
|
-
vectors[
|
|
1008
|
+
for (let j = 0; j < chunksToEmbed.length; j++) {
|
|
1009
|
+
vectors[chunksToEmbed[j].slot] = newVectors[j];
|
|
641
1010
|
}
|
|
642
1011
|
}
|
|
643
1012
|
}
|
|
644
1013
|
else {
|
|
645
1014
|
// Full rebuild
|
|
646
|
-
|
|
647
|
-
|
|
1015
|
+
vectors = await embedTexts(allChunkTexts);
|
|
1016
|
+
}
|
|
1017
|
+
// Build per-chunk contentHashes (each chunk gets its parent doc's hash)
|
|
1018
|
+
const parentToHash = new Map();
|
|
1019
|
+
for (const range of docChunkRanges) {
|
|
1020
|
+
parentToHash.set(docs[range.docIndex].id, currentHashes[range.docIndex]);
|
|
648
1021
|
}
|
|
1022
|
+
const chunkContentHashes = allChunkDocIds.map(parentId => parentToHash.get(parentId) ?? '');
|
|
649
1023
|
return {
|
|
650
1024
|
modelId: activeModel,
|
|
651
1025
|
dimension: vectors[0]?.length ?? 384,
|
|
652
|
-
docIds:
|
|
1026
|
+
docIds: allChunkIds,
|
|
653
1027
|
vectors,
|
|
654
|
-
contentHashes:
|
|
1028
|
+
contentHashes: chunkContentHashes,
|
|
1029
|
+
chunkDocIds: allChunkDocIds,
|
|
655
1030
|
builtAt: Date.now(),
|
|
656
1031
|
deviceUsed: apiMode ? 'api' : `${config.device}/${config.dtype}`,
|
|
657
1032
|
buildTimeMs: Date.now() - t0,
|