spectra-cli 4.2.0 → 4.3.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/README.md +12 -5
- package/dist/.spectra-build-meta.json +9 -0
- package/dist/adapters/language-adapter.d.ts +7 -12
- package/dist/adapters/language-adapter.d.ts.map +1 -1
- package/dist/adapters/python-adapter.d.ts.map +1 -1
- package/dist/adapters/python-adapter.js +11 -2
- package/dist/adapters/python-adapter.js.map +1 -1
- package/dist/batch/batch-orchestrator.d.ts +44 -1
- package/dist/batch/batch-orchestrator.d.ts.map +1 -1
- package/dist/batch/batch-orchestrator.js +312 -76
- package/dist/batch/batch-orchestrator.js.map +1 -1
- package/dist/batch/delta-regenerator.d.ts.map +1 -1
- package/dist/batch/delta-regenerator.js +21 -28
- package/dist/batch/delta-regenerator.js.map +1 -1
- package/dist/batch/module-grouper.d.ts +7 -0
- package/dist/batch/module-grouper.d.ts.map +1 -1
- package/dist/batch/module-grouper.js +2 -0
- package/dist/batch/module-grouper.js.map +1 -1
- package/dist/batch/regen-plan.d.ts +78 -0
- package/dist/batch/regen-plan.d.ts.map +1 -0
- package/dist/batch/regen-plan.js +93 -0
- package/dist/batch/regen-plan.js.map +1 -0
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +36 -8
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/scaffold-kb.d.ts +9 -0
- package/dist/cli/commands/scaffold-kb.d.ts.map +1 -0
- package/dist/cli/commands/scaffold-kb.js +179 -0
- package/dist/cli/commands/scaffold-kb.js.map +1 -0
- package/dist/cli/index.js +24 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/error-handler.d.ts +0 -6
- package/dist/cli/utils/error-handler.d.ts.map +1 -1
- package/dist/cli/utils/error-handler.js +0 -13
- package/dist/cli/utils/error-handler.js.map +1 -1
- package/dist/cli/utils/parse-args.d.ts +43 -3
- package/dist/cli/utils/parse-args.d.ts.map +1 -1
- package/dist/cli/utils/parse-args.js +98 -12
- package/dist/cli/utils/parse-args.js.map +1 -1
- package/dist/cli/version-meta.d.ts +16 -0
- package/dist/cli/version-meta.d.ts.map +1 -0
- package/dist/cli/version-meta.js +28 -0
- package/dist/cli/version-meta.js.map +1 -0
- package/dist/core/ast-analyzer.d.ts.map +1 -1
- package/dist/core/ast-analyzer.js +7 -11
- package/dist/core/ast-analyzer.js.map +1 -1
- package/dist/core/import-resolver.d.ts +70 -67
- package/dist/core/import-resolver.d.ts.map +1 -1
- package/dist/core/import-resolver.js +341 -200
- package/dist/core/import-resolver.js.map +1 -1
- package/dist/core/single-spec-orchestrator.d.ts +21 -0
- package/dist/core/single-spec-orchestrator.d.ts.map +1 -1
- package/dist/core/single-spec-orchestrator.js +41 -14
- package/dist/core/single-spec-orchestrator.js.map +1 -1
- package/dist/core/skeleton-hash.d.ts +33 -0
- package/dist/core/skeleton-hash.d.ts.map +1 -0
- package/dist/core/skeleton-hash.js +76 -0
- package/dist/core/skeleton-hash.js.map +1 -0
- package/dist/core/tree-sitter-analyzer.d.ts +3 -2
- package/dist/core/tree-sitter-analyzer.d.ts.map +1 -1
- package/dist/core/tree-sitter-analyzer.js +5 -6
- package/dist/core/tree-sitter-analyzer.js.map +1 -1
- package/dist/core/tree-sitter-fallback.d.ts +7 -2
- package/dist/core/tree-sitter-fallback.d.ts.map +1 -1
- package/dist/core/tree-sitter-fallback.js +18 -15
- package/dist/core/tree-sitter-fallback.js.map +1 -1
- package/dist/extraction/image-extractor.d.ts.map +1 -1
- package/dist/extraction/image-extractor.js +3 -1
- package/dist/extraction/image-extractor.js.map +1 -1
- package/dist/extraction/markdown-extractor.d.ts.map +1 -1
- package/dist/extraction/markdown-extractor.js +3 -1
- package/dist/extraction/markdown-extractor.js.map +1 -1
- package/dist/generator/frontmatter.d.ts +5 -0
- package/dist/generator/frontmatter.d.ts.map +1 -1
- package/dist/generator/frontmatter.js +4 -0
- package/dist/generator/frontmatter.js.map +1 -1
- package/dist/kb-mcp/index.d.ts +14 -0
- package/dist/kb-mcp/index.d.ts.map +1 -0
- package/dist/kb-mcp/index.js +24 -0
- package/dist/kb-mcp/index.js.map +1 -0
- package/dist/kb-mcp/lib/kb-error.d.ts +21 -0
- package/dist/kb-mcp/lib/kb-error.d.ts.map +1 -0
- package/dist/kb-mcp/lib/kb-error.js +28 -0
- package/dist/kb-mcp/lib/kb-error.js.map +1 -0
- package/dist/kb-mcp/lib/kb-locator.d.ts +58 -0
- package/dist/kb-mcp/lib/kb-locator.d.ts.map +1 -0
- package/dist/kb-mcp/lib/kb-locator.js +85 -0
- package/dist/kb-mcp/lib/kb-locator.js.map +1 -0
- package/dist/kb-mcp/lib/result-merger.d.ts +35 -0
- package/dist/kb-mcp/lib/result-merger.d.ts.map +1 -0
- package/dist/kb-mcp/lib/result-merger.js +64 -0
- package/dist/kb-mcp/lib/result-merger.js.map +1 -0
- package/dist/kb-mcp/server.d.ts +12 -0
- package/dist/kb-mcp/server.d.ts.map +1 -0
- package/dist/kb-mcp/server.js +29 -0
- package/dist/kb-mcp/server.js.map +1 -0
- package/dist/kb-mcp/tools/kb-api-lookup.d.ts +28 -0
- package/dist/kb-mcp/tools/kb-api-lookup.d.ts.map +1 -0
- package/dist/kb-mcp/tools/kb-api-lookup.js +237 -0
- package/dist/kb-mcp/tools/kb-api-lookup.js.map +1 -0
- package/dist/kb-mcp/tools/kb-doc-lookup.d.ts +20 -0
- package/dist/kb-mcp/tools/kb-doc-lookup.d.ts.map +1 -0
- package/dist/kb-mcp/tools/kb-doc-lookup.js +92 -0
- package/dist/kb-mcp/tools/kb-doc-lookup.js.map +1 -0
- package/dist/kb-mcp/tools/kb-search.d.ts +23 -0
- package/dist/kb-mcp/tools/kb-search.d.ts.map +1 -0
- package/dist/kb-mcp/tools/kb-search.js +126 -0
- package/dist/kb-mcp/tools/kb-search.js.map +1 -0
- package/dist/knowledge-graph/import-resolver.d.ts +11 -86
- package/dist/knowledge-graph/import-resolver.d.ts.map +1 -1
- package/dist/knowledge-graph/import-resolver.js +10 -333
- package/dist/knowledge-graph/import-resolver.js.map +1 -1
- package/dist/knowledge-graph/incremental.d.ts +25 -4
- package/dist/knowledge-graph/incremental.d.ts.map +1 -1
- package/dist/knowledge-graph/incremental.js +37 -15
- package/dist/knowledge-graph/incremental.js.map +1 -1
- package/dist/knowledge-graph/index.d.ts +11 -0
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph/index.js +43 -1
- package/dist/knowledge-graph/index.js.map +1 -1
- package/dist/knowledge-graph/module-derivation.d.ts +14 -0
- package/dist/knowledge-graph/module-derivation.d.ts.map +1 -1
- package/dist/knowledge-graph/module-derivation.js +44 -44
- package/dist/knowledge-graph/module-derivation.js.map +1 -1
- package/dist/knowledge-graph/persistence.d.ts +56 -16
- package/dist/knowledge-graph/persistence.d.ts.map +1 -1
- package/dist/knowledge-graph/persistence.js +86 -32
- package/dist/knowledge-graph/persistence.js.map +1 -1
- package/dist/knowledge-graph/query-helpers.d.ts +39 -12
- package/dist/knowledge-graph/query-helpers.d.ts.map +1 -1
- package/dist/knowledge-graph/query-helpers.js +199 -34
- package/dist/knowledge-graph/query-helpers.js.map +1 -1
- package/dist/knowledge-graph/relativize.d.ts +51 -0
- package/dist/knowledge-graph/relativize.d.ts.map +1 -0
- package/dist/knowledge-graph/relativize.js +104 -0
- package/dist/knowledge-graph/relativize.js.map +1 -0
- package/dist/mcp/agent-context-tools.d.ts +3 -54
- package/dist/mcp/agent-context-tools.d.ts.map +1 -1
- package/dist/mcp/agent-context-tools.js +141 -189
- package/dist/mcp/agent-context-tools.js.map +1 -1
- package/dist/mcp/file-nav-tools.d.ts +42 -0
- package/dist/mcp/file-nav-tools.d.ts.map +1 -0
- package/dist/mcp/file-nav-tools.js +318 -0
- package/dist/mcp/file-nav-tools.js.map +1 -0
- package/dist/mcp/graph-tools.d.ts +2 -0
- package/dist/mcp/graph-tools.d.ts.map +1 -1
- package/dist/mcp/graph-tools.js +134 -123
- package/dist/mcp/graph-tools.js.map +1 -1
- package/dist/mcp/lib/file-nav-helpers.d.ts +128 -0
- package/dist/mcp/lib/file-nav-helpers.d.ts.map +1 -0
- package/dist/mcp/lib/file-nav-helpers.js +305 -0
- package/dist/mcp/lib/file-nav-helpers.js.map +1 -0
- package/dist/mcp/lib/telemetry.d.ts +69 -0
- package/dist/mcp/lib/telemetry.d.ts.map +1 -0
- package/dist/mcp/lib/telemetry.js +113 -0
- package/dist/mcp/lib/telemetry.js.map +1 -0
- package/dist/mcp/lib/tool-response.d.ts +46 -0
- package/dist/mcp/lib/tool-response.d.ts.map +1 -0
- package/dist/mcp/lib/tool-response.js +83 -0
- package/dist/mcp/lib/tool-response.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +209 -150
- package/dist/mcp/server.js.map +1 -1
- package/dist/models/code-skeleton.d.ts +4 -2
- package/dist/models/code-skeleton.d.ts.map +1 -1
- package/dist/models/code-skeleton.js +2 -1
- package/dist/models/code-skeleton.js.map +1 -1
- package/dist/models/module-spec.d.ts +18 -0
- package/dist/models/module-spec.d.ts.map +1 -1
- package/dist/models/module-spec.js +6 -0
- package/dist/models/module-spec.js.map +1 -1
- package/dist/panoramic/builders/doc-graph-builder.d.ts +13 -0
- package/dist/panoramic/builders/doc-graph-builder.d.ts.map +1 -1
- package/dist/panoramic/builders/doc-graph-builder.js +20 -0
- package/dist/panoramic/builders/doc-graph-builder.js.map +1 -1
- package/dist/panoramic/graph/graph-builder.d.ts +72 -2
- package/dist/panoramic/graph/graph-builder.d.ts.map +1 -1
- package/dist/panoramic/graph/graph-builder.js +257 -51
- package/dist/panoramic/graph/graph-builder.js.map +1 -1
- package/dist/panoramic/graph/graph-query.d.ts +16 -0
- package/dist/panoramic/graph/graph-query.d.ts.map +1 -1
- package/dist/panoramic/graph/graph-query.js +49 -1
- package/dist/panoramic/graph/graph-query.js.map +1 -1
- package/dist/panoramic/graph/index.d.ts +2 -1
- package/dist/panoramic/graph/index.d.ts.map +1 -1
- package/dist/panoramic/graph/index.js +1 -1
- package/dist/panoramic/graph/index.js.map +1 -1
- package/dist/panoramic/pipelines/adr-evidence-verifier.d.ts.map +1 -1
- package/dist/panoramic/pipelines/adr-evidence-verifier.js +1 -29
- package/dist/panoramic/pipelines/adr-evidence-verifier.js.map +1 -1
- package/dist/panoramic/query.d.ts +1 -0
- package/dist/panoramic/query.d.ts.map +1 -1
- package/dist/panoramic/query.js +5 -0
- package/dist/panoramic/query.js.map +1 -1
- package/dist/scaffold-kb/api-entities-serializer.d.ts +12 -0
- package/dist/scaffold-kb/api-entities-serializer.d.ts.map +1 -0
- package/dist/scaffold-kb/api-entities-serializer.js +144 -0
- package/dist/scaffold-kb/api-entities-serializer.js.map +1 -0
- package/dist/scaffold-kb/arbitration.d.ts +44 -0
- package/dist/scaffold-kb/arbitration.d.ts.map +1 -0
- package/dist/scaffold-kb/arbitration.js +144 -0
- package/dist/scaffold-kb/arbitration.js.map +1 -0
- package/dist/scaffold-kb/chunk-splitter.d.ts +20 -0
- package/dist/scaffold-kb/chunk-splitter.d.ts.map +1 -0
- package/dist/scaffold-kb/chunk-splitter.js +309 -0
- package/dist/scaffold-kb/chunk-splitter.js.map +1 -0
- package/dist/scaffold-kb/doc-graph-builder.d.ts +26 -0
- package/dist/scaffold-kb/doc-graph-builder.d.ts.map +1 -0
- package/dist/scaffold-kb/doc-graph-builder.js +72 -0
- package/dist/scaffold-kb/doc-graph-builder.js.map +1 -0
- package/dist/scaffold-kb/entity-extractor.d.ts +40 -0
- package/dist/scaffold-kb/entity-extractor.d.ts.map +1 -0
- package/dist/scaffold-kb/entity-extractor.js +0 -0
- package/dist/scaffold-kb/entity-extractor.js.map +1 -0
- package/dist/scaffold-kb/entity-heuristic.d.ts +14 -0
- package/dist/scaffold-kb/entity-heuristic.d.ts.map +1 -0
- package/dist/scaffold-kb/entity-heuristic.js +107 -0
- package/dist/scaffold-kb/entity-heuristic.js.map +1 -0
- package/dist/scaffold-kb/entity-matcher.d.ts +20 -0
- package/dist/scaffold-kb/entity-matcher.d.ts.map +1 -0
- package/dist/scaffold-kb/entity-matcher.js +53 -0
- package/dist/scaffold-kb/entity-matcher.js.map +1 -0
- package/dist/scaffold-kb/entity-util.d.ts +11 -0
- package/dist/scaffold-kb/entity-util.d.ts.map +1 -0
- package/dist/scaffold-kb/entity-util.js +23 -0
- package/dist/scaffold-kb/entity-util.js.map +1 -0
- package/dist/scaffold-kb/evidence-envelope.d.ts +17 -0
- package/dist/scaffold-kb/evidence-envelope.d.ts.map +1 -0
- package/dist/scaffold-kb/evidence-envelope.js +32 -0
- package/dist/scaffold-kb/evidence-envelope.js.map +1 -0
- package/dist/scaffold-kb/index.d.ts +20 -0
- package/dist/scaffold-kb/index.d.ts.map +1 -0
- package/dist/scaffold-kb/index.js +102 -0
- package/dist/scaffold-kb/index.js.map +1 -0
- package/dist/scaffold-kb/ingest/ingest-core.d.ts +47 -0
- package/dist/scaffold-kb/ingest/ingest-core.d.ts.map +1 -0
- package/dist/scaffold-kb/ingest/ingest-core.js +231 -0
- package/dist/scaffold-kb/ingest/ingest-core.js.map +1 -0
- package/dist/scaffold-kb/ingest/office-parser.d.ts +33 -0
- package/dist/scaffold-kb/ingest/office-parser.d.ts.map +1 -0
- package/dist/scaffold-kb/ingest/office-parser.js +187 -0
- package/dist/scaffold-kb/ingest/office-parser.js.map +1 -0
- package/dist/scaffold-kb/ingest/url-fetcher.d.ts +43 -0
- package/dist/scaffold-kb/ingest/url-fetcher.d.ts.map +1 -0
- package/dist/scaffold-kb/ingest/url-fetcher.js +245 -0
- package/dist/scaffold-kb/ingest/url-fetcher.js.map +1 -0
- package/dist/scaffold-kb/ingester.d.ts +38 -0
- package/dist/scaffold-kb/ingester.d.ts.map +1 -0
- package/dist/scaffold-kb/ingester.js +261 -0
- package/dist/scaffold-kb/ingester.js.map +1 -0
- package/dist/scaffold-kb/injection-format.d.ts +25 -0
- package/dist/scaffold-kb/injection-format.d.ts.map +1 -0
- package/dist/scaffold-kb/injection-format.js +55 -0
- package/dist/scaffold-kb/injection-format.js.map +1 -0
- package/dist/scaffold-kb/kb-writer.d.ts +13 -0
- package/dist/scaffold-kb/kb-writer.d.ts.map +1 -0
- package/dist/scaffold-kb/kb-writer.js +69 -0
- package/dist/scaffold-kb/kb-writer.js.map +1 -0
- package/dist/scaffold-kb/keyword-extract.d.ts +16 -0
- package/dist/scaffold-kb/keyword-extract.d.ts.map +1 -0
- package/dist/scaffold-kb/keyword-extract.js +49 -0
- package/dist/scaffold-kb/keyword-extract.js.map +1 -0
- package/dist/scaffold-kb/query-sanitizer.d.ts +28 -0
- package/dist/scaffold-kb/query-sanitizer.d.ts.map +1 -0
- package/dist/scaffold-kb/query-sanitizer.js +38 -0
- package/dist/scaffold-kb/query-sanitizer.js.map +1 -0
- package/dist/scaffold-kb/recall-eval.d.ts +48 -0
- package/dist/scaffold-kb/recall-eval.d.ts.map +1 -0
- package/dist/scaffold-kb/recall-eval.js +55 -0
- package/dist/scaffold-kb/recall-eval.js.map +1 -0
- package/dist/scaffold-kb/schema-compat.d.ts +22 -0
- package/dist/scaffold-kb/schema-compat.d.ts.map +1 -0
- package/dist/scaffold-kb/schema-compat.js +32 -0
- package/dist/scaffold-kb/schema-compat.js.map +1 -0
- package/dist/scaffold-kb/search-core.d.ts +42 -0
- package/dist/scaffold-kb/search-core.d.ts.map +1 -0
- package/dist/scaffold-kb/search-core.js +89 -0
- package/dist/scaffold-kb/search-core.js.map +1 -0
- package/dist/scaffold-kb/sqlite-engine.d.ts +58 -0
- package/dist/scaffold-kb/sqlite-engine.d.ts.map +1 -0
- package/dist/scaffold-kb/sqlite-engine.js +61 -0
- package/dist/scaffold-kb/sqlite-engine.js.map +1 -0
- package/dist/scaffold-kb/sqlite-writer.d.ts +18 -0
- package/dist/scaffold-kb/sqlite-writer.d.ts.map +1 -0
- package/dist/scaffold-kb/sqlite-writer.js +76 -0
- package/dist/scaffold-kb/sqlite-writer.js.map +1 -0
- package/dist/scaffold-kb/tokenizer.d.ts +26 -0
- package/dist/scaffold-kb/tokenizer.d.ts.map +1 -0
- package/dist/scaffold-kb/tokenizer.js +97 -0
- package/dist/scaffold-kb/tokenizer.js.map +1 -0
- package/dist/scaffold-kb/types.d.ts +157 -0
- package/dist/scaffold-kb/types.d.ts.map +1 -0
- package/dist/scaffold-kb/types.js +5 -0
- package/dist/scaffold-kb/types.js.map +1 -0
- package/dist/utils/file-scanner.d.ts +15 -0
- package/dist/utils/file-scanner.d.ts.map +1 -1
- package/dist/utils/file-scanner.js +17 -0
- package/dist/utils/file-scanner.js.map +1 -1
- package/dist/utils/string-distance.d.ts +20 -0
- package/dist/utils/string-distance.d.ts.map +1 -0
- package/dist/utils/string-distance.js +38 -0
- package/dist/utils/string-distance.js.map +1 -0
- package/package.json +11 -2
- package/plugins/demo-kb-en/.claude-plugin/plugin.json +11 -0
- package/plugins/demo-kb-en/.mcp.json +8 -0
- package/plugins/demo-kb-en/FIXTURE.json +23 -0
- package/plugins/demo-kb-en/FIXTURE.md +53 -0
- package/plugins/demo-kb-en/ingest-samples/meeting-notes.md +13 -0
- package/plugins/demo-kb-en/kb/api-entities.json +3445 -0
- package/plugins/demo-kb-en/kb/chunks.sqlite +0 -0
- package/plugins/demo-kb-en/kb/doc-graph.json +113 -0
- package/plugins/demo-kb-zh/.claude-plugin/plugin.json +11 -0
- package/plugins/demo-kb-zh/.mcp.json +8 -0
- package/plugins/demo-kb-zh/FIXTURE.json +23 -0
- package/plugins/demo-kb-zh/FIXTURE.md +63 -0
- package/plugins/demo-kb-zh/ingest-samples/meeting-notes.md +13 -0
- package/plugins/demo-kb-zh/kb/api-entities.json +990 -0
- package/plugins/demo-kb-zh/kb/chunks.sqlite +0 -0
- package/plugins/demo-kb-zh/kb/doc-graph.json +113 -0
- package/plugins/spec-driver/.claude-plugin/plugin.json +1 -1
- package/plugins/spec-driver/README.md +33 -1
- package/plugins/spec-driver/agents/verify.md +88 -0
- package/plugins/spec-driver/config/orchestration.yaml +39 -31
- package/plugins/spec-driver/contracts/orchestration-overrides-contract.yaml +27 -0
- package/plugins/spec-driver/contracts/orchestration-schema.mjs +272 -227
- package/plugins/spec-driver/contracts/wrapper-source-of-truth.yaml +3 -0
- package/plugins/spec-driver/hooks/hooks.json +9 -0
- package/plugins/spec-driver/hooks/stop-fix-compliance-check.sh +36 -0
- package/plugins/spec-driver/lib/delegation-contract.mjs +84 -0
- package/plugins/spec-driver/lib/orchestration-resolver.mjs +49 -0
- package/plugins/spec-driver/lib/orchestrator.mjs +29 -1
- package/plugins/spec-driver/scripts/codex-skills.sh +28 -28
- package/plugins/spec-driver/scripts/dev/spike-fix-compliance-e2e.mjs +130 -0
- package/plugins/spec-driver/scripts/fix-compliance-judge.mjs +415 -0
- package/plugins/spec-driver/scripts/generate-adoption-insights.mjs +48 -1
- package/plugins/spec-driver/scripts/goal-loop-cli.mjs +307 -0
- package/plugins/spec-driver/scripts/init-project.sh +56 -0
- package/plugins/spec-driver/scripts/kb-prequery.mjs +125 -0
- package/plugins/spec-driver/scripts/lib/config-schema.mjs +200 -94
- package/plugins/spec-driver/scripts/lib/ensure-gitignore.sh +277 -0
- package/plugins/spec-driver/scripts/lib/extract-wrapper-body.mjs +136 -0
- package/plugins/spec-driver/scripts/lib/fix-compliance-core.mjs +434 -0
- package/plugins/spec-driver/scripts/lib/fix-compliance-io.mjs +335 -0
- package/plugins/spec-driver/scripts/lib/goal-loop-core.mjs +783 -0
- package/plugins/spec-driver/scripts/lib/init-project-output.sh +28 -0
- package/plugins/spec-driver/scripts/lib/load-zod.mjs +62 -0
- package/plugins/spec-driver/scripts/lib/project-profile-resolver.mjs +141 -49
- package/plugins/spec-driver/scripts/lib/project-profile-schema.mjs +88 -54
- package/plugins/spec-driver/scripts/postinstall.sh +13 -1
- package/plugins/spec-driver/scripts/record-workflow-run.mjs +75 -0
- package/plugins/spec-driver/scripts/sync-delegation-contract.mjs +187 -0
- package/plugins/spec-driver/scripts/validate-orchestrator-models.mjs +156 -0
- package/plugins/spec-driver/scripts/validate-wrapper-sources.mjs +46 -1
- package/plugins/spec-driver/skills/spec-driver-feature/SKILL.md +292 -0
- package/plugins/spec-driver/skills/spec-driver-fix/SKILL.md +87 -8
- package/plugins/spec-driver/skills/spec-driver-implement/SKILL.md +8 -0
- package/plugins/spec-driver/skills/spec-driver-resume/SKILL.md +12 -1
- package/plugins/spec-driver/skills/spec-driver-story/SKILL.md +20 -0
- package/plugins/spec-driver/templates/delegation-contract.md +27 -0
- package/plugins/spec-driver/templates/goal-loop-override-template.yaml +284 -0
- package/plugins/spec-driver/templates/specify-base/project-context-template.yaml +10 -0
- package/plugins/spectra/.claude-plugin/plugin.json +1 -1
- package/plugins/spectra/README.md +1 -1
- package/templates/module-spec.hbs +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-heuristic.js","sourceRoot":"","sources":["../../src/scaffold-kb/entity-heuristic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 T007 — API 实体匹配(kb_api_lookup 用,FR-004 + W-2 消歧)
|
|
3
|
+
*
|
|
4
|
+
* 精确(name/qualified_name/末段 相等)优先,模糊(子串 / token 重叠)兜底;
|
|
5
|
+
* 支持 kind / container 过滤;多命中返回 top-N(不静默取一)。纯函数。
|
|
6
|
+
*/
|
|
7
|
+
import type { ApiEntity } from './types.js';
|
|
8
|
+
export interface MatchQuery {
|
|
9
|
+
apiName: string;
|
|
10
|
+
kind?: ApiEntity['kind'] | null;
|
|
11
|
+
/** 按所属 class/module 限定(消歧重载/同名) */
|
|
12
|
+
container?: string | null;
|
|
13
|
+
topN?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface EntityMatch extends ApiEntity {
|
|
16
|
+
matchType: 'exact' | 'fuzzy';
|
|
17
|
+
}
|
|
18
|
+
/** 在实体集中匹配查询,返回按相关度排序的 top-N(精确在前) */
|
|
19
|
+
export declare function matchEntities(entities: ApiEntity[], q: MatchQuery): EntityMatch[];
|
|
20
|
+
//# sourceMappingURL=entity-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-matcher.d.ts","sourceRoot":"","sources":["../../src/scaffold-kb/entity-matcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAChC,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC;CAC9B;AAUD,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,UAAU,GAAG,WAAW,EAAE,CAoCjF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 T007 — API 实体匹配(kb_api_lookup 用,FR-004 + W-2 消歧)
|
|
3
|
+
*
|
|
4
|
+
* 精确(name/qualified_name/末段 相等)优先,模糊(子串 / token 重叠)兜底;
|
|
5
|
+
* 支持 kind / container 过滤;多命中返回 top-N(不静默取一)。纯函数。
|
|
6
|
+
*/
|
|
7
|
+
import { tokenize } from './tokenizer.js';
|
|
8
|
+
function norm(s) {
|
|
9
|
+
return s.trim().toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
function lastSegment(qualified) {
|
|
12
|
+
return qualified.includes('.') ? (qualified.split('.').pop() ?? qualified) : qualified;
|
|
13
|
+
}
|
|
14
|
+
/** 在实体集中匹配查询,返回按相关度排序的 top-N(精确在前) */
|
|
15
|
+
export function matchEntities(entities, q) {
|
|
16
|
+
const topN = q.topN ?? 10;
|
|
17
|
+
const qn = norm(q.apiName);
|
|
18
|
+
if (!qn)
|
|
19
|
+
return [];
|
|
20
|
+
const qTokens = new Set(tokenize(q.apiName).map(norm));
|
|
21
|
+
const candidates = entities.filter((e) => {
|
|
22
|
+
if (q.kind && e.kind !== q.kind)
|
|
23
|
+
return false;
|
|
24
|
+
if (q.container && norm(e.container ?? '') !== norm(q.container))
|
|
25
|
+
return false;
|
|
26
|
+
return true;
|
|
27
|
+
});
|
|
28
|
+
const scored = [];
|
|
29
|
+
for (const e of candidates) {
|
|
30
|
+
const name = norm(e.name);
|
|
31
|
+
const qualified = norm(e.qualifiedName);
|
|
32
|
+
const last = norm(lastSegment(e.qualifiedName));
|
|
33
|
+
if (name === qn || qualified === qn || last === qn) {
|
|
34
|
+
scored.push({ e, matchType: 'exact', rank: 0 });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// qn.includes(name) 仅在 name 足够长时启用,避免短名(on/api/get)成为乱串查询的误命中
|
|
38
|
+
const substr = name.includes(qn) || qualified.includes(qn) || (name.length >= 4 && qn.includes(name));
|
|
39
|
+
const eTokens = new Set([...tokenize(e.name), ...tokenize(e.qualifiedName)].map(norm));
|
|
40
|
+
let overlap = 0;
|
|
41
|
+
for (const t of qTokens)
|
|
42
|
+
if (t.length > 0 && eTokens.has(t))
|
|
43
|
+
overlap++;
|
|
44
|
+
if (substr || overlap > 0) {
|
|
45
|
+
// rank: 子串(1.0) < token 重叠(1 + 缺口比例)
|
|
46
|
+
const rank = substr ? 1.0 : 2.0 - overlap / Math.max(1, qTokens.size);
|
|
47
|
+
scored.push({ e, matchType: 'fuzzy', rank });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
scored.sort((a, b) => a.rank - b.rank);
|
|
51
|
+
return scored.slice(0, topN).map(({ e, matchType }) => ({ ...e, matchType }));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=entity-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-matcher.js","sourceRoot":"","sources":["../../src/scaffold-kb/entity-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 — 实体共享工具(id 归一 + confidence clamp),供 heuristic/LLM 抽取 + matcher 复用
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 实体稳定唯一 id:qualified_name + kind (+ overload_key) 归一。
|
|
6
|
+
* 同名重载靠 overload_key 区分(W-2)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function makeEntityId(qualifiedName: string, kind: string, overloadKey?: string | null): string;
|
|
9
|
+
/** confidence clamp 到 [0,1];非数值 → fallback(I-1) */
|
|
10
|
+
export declare function clampConfidence(v: unknown, fallback?: number): number;
|
|
11
|
+
//# sourceMappingURL=entity-util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-util.d.ts","sourceRoot":"","sources":["../../src/scaffold-kb/entity-util.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,MAAM,CAGR;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,SAAI,GAAG,MAAM,CAIhE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 — 实体共享工具(id 归一 + confidence clamp),供 heuristic/LLM 抽取 + matcher 复用
|
|
3
|
+
*/
|
|
4
|
+
/** 归一字符串:trim + 小写 + 折叠空白 */
|
|
5
|
+
function norm(s) {
|
|
6
|
+
return s.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 实体稳定唯一 id:qualified_name + kind (+ overload_key) 归一。
|
|
10
|
+
* 同名重载靠 overload_key 区分(W-2)。
|
|
11
|
+
*/
|
|
12
|
+
export function makeEntityId(qualifiedName, kind, overloadKey) {
|
|
13
|
+
const base = `${norm(qualifiedName)}#${kind}`;
|
|
14
|
+
return overloadKey && overloadKey.trim() ? `${base}#${norm(overloadKey)}` : base;
|
|
15
|
+
}
|
|
16
|
+
/** confidence clamp 到 [0,1];非数值 → fallback(I-1) */
|
|
17
|
+
export function clampConfidence(v, fallback = 0) {
|
|
18
|
+
const n = typeof v === 'number' ? v : Number(v);
|
|
19
|
+
if (!Number.isFinite(n))
|
|
20
|
+
return fallback;
|
|
21
|
+
return Math.max(0, Math.min(1, n));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=entity-util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-util.js","sourceRoot":"","sources":["../../src/scaffold-kb/entity-util.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6BAA6B;AAC7B,SAAS,IAAI,CAAC,CAAS;IACrB,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,aAAqB,EACrB,IAAY,EACZ,WAA2B;IAE3B,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,CAAC;IAC9C,OAAO,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,CAAU,EAAE,QAAQ,GAAG,CAAC;IACtD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F190/F191 — untrusted-evidence envelope 共享工具(从 kb-search 抽出,kb-search + injection-format 同源)
|
|
3
|
+
*
|
|
4
|
+
* 信任边界(F190 FR-011 / SC-010):把 KB 检索内容包成定界 evidence 区,
|
|
5
|
+
* 中和内嵌 sentinel(防提前闭合逃逸)、编码属性值、surrogate-safe 截断。
|
|
6
|
+
* 依赖方向:本模块在 scaffold-kb,不 import kb-mcp(SourceKind 取自 ./types)。
|
|
7
|
+
*/
|
|
8
|
+
import type { SourceKind } from './types.js';
|
|
9
|
+
/** envelope 属性值编码:去除可破坏头部的 `]` `"` 换行(防注入逃逸) */
|
|
10
|
+
export declare function safeAttr(v: string): string;
|
|
11
|
+
/** 中和正文内的 envelope sentinel,防止提前闭合把注入文本放到 envelope 外(trust boundary) */
|
|
12
|
+
export declare function defangSentinel(content: string): string;
|
|
13
|
+
/** 按 UTF-16 code unit 截断但不切开代理对(避免孤立 surrogate) */
|
|
14
|
+
export declare function safeTruncate(s: string, max: number): string;
|
|
15
|
+
/** 把单条内容包成 `[KB-EVIDENCE …]…[/KB-EVIDENCE]` evidence 块 */
|
|
16
|
+
export declare function buildEvidenceEnvelope(content: string, docId: string, src: SourceKind, builtAt: string): string;
|
|
17
|
+
//# sourceMappingURL=evidence-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-envelope.d.ts","sourceRoot":"","sources":["../../src/scaffold-kb/evidence-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,GACd,MAAM,CAER"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F190/F191 — untrusted-evidence envelope 共享工具(从 kb-search 抽出,kb-search + injection-format 同源)
|
|
3
|
+
*
|
|
4
|
+
* 信任边界(F190 FR-011 / SC-010):把 KB 检索内容包成定界 evidence 区,
|
|
5
|
+
* 中和内嵌 sentinel(防提前闭合逃逸)、编码属性值、surrogate-safe 截断。
|
|
6
|
+
* 依赖方向:本模块在 scaffold-kb,不 import kb-mcp(SourceKind 取自 ./types)。
|
|
7
|
+
*/
|
|
8
|
+
/** envelope 属性值编码:去除可破坏头部的 `]` `"` 换行(防注入逃逸) */
|
|
9
|
+
export function safeAttr(v) {
|
|
10
|
+
return v.replace(/[\]"\r\n]/g, ' ');
|
|
11
|
+
}
|
|
12
|
+
/** 中和正文内的 envelope sentinel,防止提前闭合把注入文本放到 envelope 外(trust boundary) */
|
|
13
|
+
export function defangSentinel(content) {
|
|
14
|
+
return content
|
|
15
|
+
.replace(/\[\s*\/\s*KB-EVIDENCE\s*\]/gi, '[ /KB-EVIDENCE ]')
|
|
16
|
+
.replace(/\[\s*KB-EVIDENCE/gi, '[ KB-EVIDENCE');
|
|
17
|
+
}
|
|
18
|
+
/** 按 UTF-16 code unit 截断但不切开代理对(避免孤立 surrogate) */
|
|
19
|
+
export function safeTruncate(s, max) {
|
|
20
|
+
if (s.length <= max)
|
|
21
|
+
return s;
|
|
22
|
+
let end = max;
|
|
23
|
+
const code = s.charCodeAt(end - 1);
|
|
24
|
+
if (code >= 0xd800 && code <= 0xdbff)
|
|
25
|
+
end -= 1; // 末位是高代理 → 回退一位
|
|
26
|
+
return s.slice(0, end);
|
|
27
|
+
}
|
|
28
|
+
/** 把单条内容包成 `[KB-EVIDENCE …]…[/KB-EVIDENCE]` evidence 块 */
|
|
29
|
+
export function buildEvidenceEnvelope(content, docId, src, builtAt) {
|
|
30
|
+
return `[KB-EVIDENCE doc_id="${safeAttr(docId)}" src="${src}" built_at="${safeAttr(builtAt)}"]\n${defangSentinel(content)}\n[/KB-EVIDENCE]`;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=evidence-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-envelope.js","sourceRoot":"","sources":["../../src/scaffold-kb/evidence-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,OAAO;SACX,OAAO,CAAC,8BAA8B,EAAE,kBAAkB,CAAC;SAC3D,OAAO,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;AACpD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,GAAW;IACjD,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB;IAChE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,KAAa,EACb,GAAe,EACf,OAAe;IAEf,OAAO,wBAAwB,QAAQ,CAAC,KAAK,CAAC,UAAU,GAAG,eAAe,QAAQ,CAAC,OAAO,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,kBAAkB,CAAC;AAC9I,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F190 scaffold-kb — buildKb 主流程编排
|
|
3
|
+
*
|
|
4
|
+
* ingest → split → doc-graph + chunks → 落盘 kb/{doc-graph.json, chunks.sqlite}
|
|
5
|
+
* 原子性:ingest 失败前未写任何文件;所有产物在内存算好后再一次性落盘
|
|
6
|
+
* (EC-008:不留中间态残片)。
|
|
7
|
+
*
|
|
8
|
+
* 同一 CLI 指向项目路径即写项目库(FR-016:`--output <project>/.{tool}/kb`)。
|
|
9
|
+
*/
|
|
10
|
+
import type { BuildKbOptions } from './types.js';
|
|
11
|
+
export interface BuildKbResult {
|
|
12
|
+
docCount: number;
|
|
13
|
+
chunkCount: number;
|
|
14
|
+
entityCount: number;
|
|
15
|
+
extractionMethod: 'llm' | 'heuristic' | 'mixed';
|
|
16
|
+
outputPath: string;
|
|
17
|
+
builtAt: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildKb(opts: BuildKbOptions): Promise<BuildKbResult>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold-kb/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAiB,cAAc,EAA8B,MAAM,YAAY,CAAC;AAS5F,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,KAAK,GAAG,WAAW,GAAG,OAAO,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAqE1E"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F190 scaffold-kb — buildKb 主流程编排
|
|
3
|
+
*
|
|
4
|
+
* ingest → split → doc-graph + chunks → 落盘 kb/{doc-graph.json, chunks.sqlite}
|
|
5
|
+
* 原子性:ingest 失败前未写任何文件;所有产物在内存算好后再一次性落盘
|
|
6
|
+
* (EC-008:不留中间态残片)。
|
|
7
|
+
*
|
|
8
|
+
* 同一 CLI 指向项目路径即写项目库(FR-016:`--output <project>/.{tool}/kb`)。
|
|
9
|
+
*/
|
|
10
|
+
import { ingestDocuments } from './ingester.js';
|
|
11
|
+
import { splitDocument } from './chunk-splitter.js';
|
|
12
|
+
import { buildDocGraph } from './doc-graph-builder.js';
|
|
13
|
+
import { buildChunksDbBytes } from './sqlite-writer.js';
|
|
14
|
+
import { aggregateSections, extractEntities } from './entity-extractor.js';
|
|
15
|
+
import { serializeApiEntities } from './api-entities-serializer.js';
|
|
16
|
+
import { writeKbArtifactsAtomic } from './kb-writer.js';
|
|
17
|
+
/** 把内存 DocGraph 序列化为 spec §3.2 的 on-disk JSON(snake_case,含 schema_version 供 EC-009) */
|
|
18
|
+
function serializeDocGraph(g) {
|
|
19
|
+
return {
|
|
20
|
+
schema_version: g.schemaVersion,
|
|
21
|
+
source: g.source,
|
|
22
|
+
built_at: g.builtAt,
|
|
23
|
+
sdk_version: g.sdkVersion,
|
|
24
|
+
nodes: g.nodes.map((n) => ({
|
|
25
|
+
id: n.id,
|
|
26
|
+
title: n.title,
|
|
27
|
+
summary: n.summary ?? null,
|
|
28
|
+
tags: n.tags ?? [],
|
|
29
|
+
lang: n.lang,
|
|
30
|
+
source_url: n.sourceUrl,
|
|
31
|
+
})),
|
|
32
|
+
edges: g.edges.map((e) => ({ source: e.source, target: e.target, relation: e.relation })),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export async function buildKb(opts) {
|
|
36
|
+
const outputPath = opts.outputPath ?? './kb';
|
|
37
|
+
const builtAt = opts.builtAt ?? new Date().toISOString();
|
|
38
|
+
const sdkVersion = opts.sdkVersion ?? null;
|
|
39
|
+
const source = opts.llmsTxtUrl ? 'llms.txt' : 'directory';
|
|
40
|
+
// 1. ingest(参数校验 + 抓取/扫描;失败抛错,此前未落盘 → 原子性)
|
|
41
|
+
const ingestOpts = {};
|
|
42
|
+
if (opts.dirPath !== undefined)
|
|
43
|
+
ingestOpts.dirPath = opts.dirPath;
|
|
44
|
+
if (opts.llmsTxtUrl !== undefined)
|
|
45
|
+
ingestOpts.llmsTxtUrl = opts.llmsTxtUrl;
|
|
46
|
+
if (opts.lang !== undefined)
|
|
47
|
+
ingestOpts.lang = opts.lang;
|
|
48
|
+
const docs = await ingestDocuments(ingestOpts);
|
|
49
|
+
// 2. 切分 + 组装 chunk_meta(doc_title/source_url 冗余自 doc,R-003)
|
|
50
|
+
const chunks = [];
|
|
51
|
+
const meta = [];
|
|
52
|
+
for (const doc of docs) {
|
|
53
|
+
for (const c of splitDocument(doc)) {
|
|
54
|
+
chunks.push(c);
|
|
55
|
+
meta.push({
|
|
56
|
+
chunkId: c.chunkId,
|
|
57
|
+
docId: c.docId,
|
|
58
|
+
docTitle: doc.title,
|
|
59
|
+
sourceUrl: doc.sourceUrl,
|
|
60
|
+
anchor: c.anchor,
|
|
61
|
+
sdkVersion,
|
|
62
|
+
builtAt,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// 3. doc-graph
|
|
67
|
+
const graph = buildDocGraph(docs, { source, sdkVersion, builtAt });
|
|
68
|
+
// 4. API 实体抽取(FR-001:LLM 提质 + heuristic 兜底;--no-llm 跳过 LLM)
|
|
69
|
+
const docLang = new Map(docs.map((d) => [d.id, d.lang]));
|
|
70
|
+
const sections = aggregateSections(chunks, docLang);
|
|
71
|
+
const extractOpts = {};
|
|
72
|
+
if (opts.noLlm === true)
|
|
73
|
+
extractOpts.noLlm = true;
|
|
74
|
+
const extraction = await extractEntities(sections, extractOpts);
|
|
75
|
+
const entityFile = {
|
|
76
|
+
schemaVersion: '1.0',
|
|
77
|
+
builtAt,
|
|
78
|
+
sdkVersion,
|
|
79
|
+
sourceKind: opts.sourceKind ?? 'vendor',
|
|
80
|
+
entities: extraction.entities,
|
|
81
|
+
coverage: extraction.coverage,
|
|
82
|
+
};
|
|
83
|
+
// 5. 内存算好全部产物,再一次性原子落盘(三文件:doc-graph + chunks + api-entities,EC-008)
|
|
84
|
+
const sqliteBytes = await buildChunksDbBytes(chunks, meta);
|
|
85
|
+
const graphJson = JSON.stringify(serializeDocGraph(graph), null, 2);
|
|
86
|
+
const entitiesJson = JSON.stringify(serializeApiEntities(entityFile), null, 2);
|
|
87
|
+
// 三文件近似原子落盘(C-5),build 与 ingest 共用 kb-writer
|
|
88
|
+
writeKbArtifactsAtomic(outputPath, [
|
|
89
|
+
{ name: 'doc-graph.json', data: graphJson },
|
|
90
|
+
{ name: 'chunks.sqlite', data: sqliteBytes },
|
|
91
|
+
{ name: 'api-entities.json', data: entitiesJson },
|
|
92
|
+
]);
|
|
93
|
+
return {
|
|
94
|
+
docCount: docs.length,
|
|
95
|
+
chunkCount: chunks.length,
|
|
96
|
+
entityCount: extraction.entities.length,
|
|
97
|
+
extractionMethod: extraction.method,
|
|
98
|
+
outputPath,
|
|
99
|
+
builtAt,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold-kb/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 T016 — 三方导入核心(FR-009/014/015)
|
|
3
|
+
*
|
|
4
|
+
* 源(url/office/minutes)→ ParsedDoc(+provenance) → splitDocument → 抽实体 →
|
|
5
|
+
* 与现有项目库**合并去重**(内容级 dedup chunk + merge key 覆盖 entity)→ 三件套原子写项目库。
|
|
6
|
+
* 默认网络实现 = SSRF 安全 fetcher(禁 F190 默认 fetch)。单源失败不阻断其他源。
|
|
7
|
+
* 导入内容全 untrusted:入库即落 provenance,检索经 envelope(复用既有路径)。
|
|
8
|
+
*/
|
|
9
|
+
import type { IngestSourceType } from '../types.js';
|
|
10
|
+
import { safeFetchUrl } from './url-fetcher.js';
|
|
11
|
+
export declare class IngestError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
export interface IngestSource {
|
|
15
|
+
kind: 'url' | 'file' | 'minutes';
|
|
16
|
+
value: string;
|
|
17
|
+
}
|
|
18
|
+
export interface IngestSourceResult {
|
|
19
|
+
origin: string;
|
|
20
|
+
type: IngestSourceType | null;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface IngestPlan {
|
|
25
|
+
newDocs: number;
|
|
26
|
+
newChunks: number;
|
|
27
|
+
newEntities: number;
|
|
28
|
+
totalChunks: number;
|
|
29
|
+
totalEntities: number;
|
|
30
|
+
sources: IngestSourceResult[];
|
|
31
|
+
artifacts: {
|
|
32
|
+
graphJson: string;
|
|
33
|
+
sqliteBytes: Uint8Array;
|
|
34
|
+
entitiesJson: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface IngestOptions {
|
|
38
|
+
noLlm?: boolean;
|
|
39
|
+
builtAt?: string;
|
|
40
|
+
/** 注入安全 fetcher(测试用),缺省 safeFetchUrl */
|
|
41
|
+
fetchUrl?: typeof safeFetchUrl;
|
|
42
|
+
}
|
|
43
|
+
/** 准备导入(处理所有源 + 合并去重,不落盘);commitIngest 才写 */
|
|
44
|
+
export declare function prepareIngest(sources: IngestSource[], projectKbPath: string, opts?: IngestOptions): Promise<IngestPlan>;
|
|
45
|
+
/** 落盘项目库三件套(原子) */
|
|
46
|
+
export declare function commitIngest(projectKbPath: string, plan: IngestPlan): void;
|
|
47
|
+
//# sourceMappingURL=ingest-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-core.d.ts","sourceRoot":"","sources":["../../../src/scaffold-kb/ingest/ingest-core.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACoD,gBAAgB,EAC/E,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,YAAY,CAAC;CAChC;AAwID,6CAA6C;AAC7C,wBAAsB,aAAa,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,UAAU,CAAC,CA+ErB;AAED,mBAAmB;AACnB,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAM1E"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F192 T016 — 三方导入核心(FR-009/014/015)
|
|
3
|
+
*
|
|
4
|
+
* 源(url/office/minutes)→ ParsedDoc(+provenance) → splitDocument → 抽实体 →
|
|
5
|
+
* 与现有项目库**合并去重**(内容级 dedup chunk + merge key 覆盖 entity)→ 三件套原子写项目库。
|
|
6
|
+
* 默认网络实现 = SSRF 安全 fetcher(禁 F190 默认 fetch)。单源失败不阻断其他源。
|
|
7
|
+
* 导入内容全 untrusted:入库即落 provenance,检索经 envelope(复用既有路径)。
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { basename, join } from 'node:path';
|
|
11
|
+
import { splitDocument } from '../chunk-splitter.js';
|
|
12
|
+
import { aggregateSections, extractEntities } from '../entity-extractor.js';
|
|
13
|
+
import { buildChunksDbBytes } from '../sqlite-writer.js';
|
|
14
|
+
import { serializeApiEntities, deserializeApiEntities } from '../api-entities-serializer.js';
|
|
15
|
+
import { provenanceSelectFragment } from '../schema-compat.js';
|
|
16
|
+
import { writeKbArtifactsAtomic } from '../kb-writer.js';
|
|
17
|
+
import { loadDbFromBytes, queryRows } from '../sqlite-engine.js';
|
|
18
|
+
import { safeFetchUrl } from './url-fetcher.js';
|
|
19
|
+
import { parseOfficeFile, detectOfficeFormat } from './office-parser.js';
|
|
20
|
+
export class IngestError extends Error {
|
|
21
|
+
constructor(message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = 'IngestError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const HAN = /\p{Script=Han}/u;
|
|
27
|
+
function detectLang(text) {
|
|
28
|
+
return HAN.test(text) ? 'zh' : 'en';
|
|
29
|
+
}
|
|
30
|
+
function firstH1(md) {
|
|
31
|
+
for (const line of md.split('\n')) {
|
|
32
|
+
const m = /^#\s+(.+)$/.exec(line.trim());
|
|
33
|
+
if (m)
|
|
34
|
+
return m[1].trim();
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
function urlToId(url) {
|
|
39
|
+
try {
|
|
40
|
+
const u = new URL(url);
|
|
41
|
+
return (u.host + u.pathname).replace(/\/$/, '');
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return url;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** 单源 → ParsedDoc + provenance;失败抛错(调用方记 reason,不阻断其他源) */
|
|
48
|
+
async function sourceToDoc(source, fetchUrl) {
|
|
49
|
+
if (source.kind === 'url') {
|
|
50
|
+
const { finalUrl, markdown } = await fetchUrl(source.value);
|
|
51
|
+
const id = urlToId(finalUrl);
|
|
52
|
+
return {
|
|
53
|
+
doc: { id, title: firstH1(markdown) ?? id, content: markdown, sourceUrl: finalUrl, lang: detectLang(markdown) },
|
|
54
|
+
type: 'url',
|
|
55
|
+
origin: finalUrl,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (source.kind === 'file') {
|
|
59
|
+
const fmt = detectOfficeFormat(source.value);
|
|
60
|
+
if (!fmt)
|
|
61
|
+
throw new Error(`不支持的文件类型: ${source.value}`);
|
|
62
|
+
const { text } = await parseOfficeFile(new Uint8Array(readFileSync(source.value)), fmt);
|
|
63
|
+
const id = basename(source.value);
|
|
64
|
+
const type = fmt === 'md' ? 'markdown-dir' : `office-${fmt}`;
|
|
65
|
+
return {
|
|
66
|
+
doc: { id, title: firstH1(text) ?? id, content: text, sourceUrl: source.value, lang: detectLang(text) },
|
|
67
|
+
type,
|
|
68
|
+
origin: id,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// minutes:自由文本/markdown
|
|
72
|
+
const text = readFileSync(source.value, 'utf-8');
|
|
73
|
+
const id = basename(source.value);
|
|
74
|
+
return {
|
|
75
|
+
doc: { id, title: firstH1(text) ?? id, content: text, sourceUrl: source.value, lang: detectLang(text) },
|
|
76
|
+
type: 'minutes',
|
|
77
|
+
origin: id,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 加载现有项目库三件套(不存在 → 空)。
|
|
82
|
+
* C-2 fail-closed:sqlite 存在但读取失败 → 抛 IngestError(拒绝导入,绝不静默覆盖丢数据)。
|
|
83
|
+
* 坏的 api-entities.json / doc-graph.json 隔离处理(按空,保留 sqlite 数据)。
|
|
84
|
+
*/
|
|
85
|
+
async function loadExisting(projectKbPath) {
|
|
86
|
+
const empty = { chunks: [], meta: [], entities: [], nodes: [], edges: [] };
|
|
87
|
+
const sqlitePath = join(projectKbPath, 'chunks.sqlite');
|
|
88
|
+
if (!existsSync(sqlitePath))
|
|
89
|
+
return empty; // 首次导入
|
|
90
|
+
const chunks = [];
|
|
91
|
+
const meta = [];
|
|
92
|
+
try {
|
|
93
|
+
const { db } = await loadDbFromBytes(readFileSync(sqlitePath));
|
|
94
|
+
const prov = provenanceSelectFragment(db);
|
|
95
|
+
const rows = queryRows(db, `SELECT chunks.chunk_id, chunks.doc_id, chunks.content_raw, chunk_meta.doc_title,
|
|
96
|
+
chunk_meta.source_url, chunk_meta.anchor, chunk_meta.sdk_version, chunk_meta.built_at${prov}
|
|
97
|
+
FROM chunks JOIN chunk_meta ON chunk_meta.chunk_id = chunks.chunk_id`, []);
|
|
98
|
+
for (const r of rows) {
|
|
99
|
+
const s = (v) => (v == null ? '' : String(v));
|
|
100
|
+
const sn = (v) => (v == null ? null : String(v));
|
|
101
|
+
chunks.push({ chunkId: s(r[0]), docId: s(r[1]), contentRaw: s(r[2]), anchor: sn(r[5]) });
|
|
102
|
+
meta.push({
|
|
103
|
+
chunkId: s(r[0]), docId: s(r[1]), docTitle: s(r[3]), sourceUrl: sn(r[4]), anchor: sn(r[5]),
|
|
104
|
+
sdkVersion: sn(r[6]), builtAt: s(r[7]),
|
|
105
|
+
ingestSourceType: sn(r[8]), ingestOrigin: sn(r[9]), ingestedAt: sn(r[10]),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
// fail-closed:现有 sqlite 损坏不可读 → 拒绝导入,避免 commit 覆盖丢数据(C-2)
|
|
111
|
+
throw new IngestError(`既有项目库 chunks.sqlite 读取失败,已拒绝导入以防数据丢失(请人工修复后重试): ${e.message}`);
|
|
112
|
+
}
|
|
113
|
+
// entities:坏文件隔离(按空,不阻断、不清空 sqlite)
|
|
114
|
+
let entities = [];
|
|
115
|
+
try {
|
|
116
|
+
const entPath = join(projectKbPath, 'api-entities.json');
|
|
117
|
+
if (existsSync(entPath)) {
|
|
118
|
+
const f = deserializeApiEntities(JSON.parse(readFileSync(entPath, 'utf-8')));
|
|
119
|
+
if (f)
|
|
120
|
+
entities = f.entities;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
entities = [];
|
|
125
|
+
}
|
|
126
|
+
// doc-graph:读取已有 nodes/edges 并保留(W-2,防覆盖丢旧 graph)
|
|
127
|
+
let nodes = [];
|
|
128
|
+
let edges = [];
|
|
129
|
+
try {
|
|
130
|
+
const graphPath = join(projectKbPath, 'doc-graph.json');
|
|
131
|
+
if (existsSync(graphPath)) {
|
|
132
|
+
const g = JSON.parse(readFileSync(graphPath, 'utf-8'));
|
|
133
|
+
nodes = (g.nodes ?? []).map((n) => ({ id: n.id, title: n.title ?? n.id, lang: n.lang ?? 'en', sourceUrl: n.source_url ?? '' }));
|
|
134
|
+
edges = Array.isArray(g.edges) ? g.edges : [];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
nodes = [];
|
|
139
|
+
edges = [];
|
|
140
|
+
}
|
|
141
|
+
return { chunks, meta, entities, nodes, edges };
|
|
142
|
+
}
|
|
143
|
+
/** 准备导入(处理所有源 + 合并去重,不落盘);commitIngest 才写 */
|
|
144
|
+
export async function prepareIngest(sources, projectKbPath, opts = {}) {
|
|
145
|
+
const builtAt = opts.builtAt ?? new Date().toISOString();
|
|
146
|
+
const fetchUrl = opts.fetchUrl ?? safeFetchUrl;
|
|
147
|
+
const results = [];
|
|
148
|
+
const newDocs = [];
|
|
149
|
+
for (const source of sources) {
|
|
150
|
+
try {
|
|
151
|
+
newDocs.push(await sourceToDoc(source, fetchUrl));
|
|
152
|
+
results.push({ origin: source.value, type: newDocs[newDocs.length - 1].type, ok: true });
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
results.push({ origin: source.value, type: null, ok: false, reason: e.message });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const existing = await loadExisting(projectKbPath);
|
|
159
|
+
const newDocIds = new Set(newDocs.map((d) => d.doc.id));
|
|
160
|
+
// W-3 doc-level replace:移除既有同 doc id 的 chunk/meta/entity/node(支持更新 + 防 chunk_id 撞 PRIMARY KEY)
|
|
161
|
+
const keptChunks = existing.chunks.filter((c) => !newDocIds.has(c.docId));
|
|
162
|
+
const keptMeta = existing.meta.filter((m) => !newDocIds.has(m.docId));
|
|
163
|
+
const keptEntities = existing.entities.filter((e) => !newDocIds.has(e.sourceDocId));
|
|
164
|
+
const keptNodes = existing.nodes.filter((n) => !newDocIds.has(n.id));
|
|
165
|
+
// 去重计数基准 = 导入前全集(使同内容 re-ingest 计 0,幂等)
|
|
166
|
+
const originalContent = new Set(existing.chunks.map((c) => c.contentRaw));
|
|
167
|
+
const originalEntityKeys = new Set(existing.entities.map((e) => e.id));
|
|
168
|
+
const seenContent = new Set(keptChunks.map((c) => c.contentRaw));
|
|
169
|
+
const newChunks = [];
|
|
170
|
+
const newMeta = [];
|
|
171
|
+
let newChunkCount = 0;
|
|
172
|
+
const nodes = [...keptNodes];
|
|
173
|
+
for (const { doc, type, origin } of newDocs) {
|
|
174
|
+
nodes.push({ id: doc.id, title: doc.title, lang: doc.lang, sourceUrl: doc.sourceUrl });
|
|
175
|
+
for (const c of splitDocument(doc)) {
|
|
176
|
+
if (c.contentRaw.trim().length < 20)
|
|
177
|
+
continue; // 过滤空/超短
|
|
178
|
+
if (seenContent.has(c.contentRaw))
|
|
179
|
+
continue; // 内容级 dedup(FR-014,防同内容重复存)
|
|
180
|
+
seenContent.add(c.contentRaw);
|
|
181
|
+
newChunks.push(c);
|
|
182
|
+
newMeta.push({
|
|
183
|
+
chunkId: c.chunkId, docId: c.docId, docTitle: doc.title, sourceUrl: doc.sourceUrl, anchor: c.anchor,
|
|
184
|
+
sdkVersion: null, builtAt, ingestSourceType: type, ingestOrigin: origin, ingestedAt: builtAt,
|
|
185
|
+
});
|
|
186
|
+
if (!originalContent.has(c.contentRaw))
|
|
187
|
+
newChunkCount++; // 仅统计导入前不存在的内容
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// 抽实体(仅新内容)→ merge key 覆盖
|
|
191
|
+
const extractOpts = {};
|
|
192
|
+
if (opts.noLlm === true)
|
|
193
|
+
extractOpts.noLlm = true;
|
|
194
|
+
const docLang = new Map(newDocs.map((d) => [d.doc.id, d.doc.lang]));
|
|
195
|
+
const extraction = await extractEntities(aggregateSections(newChunks, docLang), extractOpts);
|
|
196
|
+
const entityByKey = new Map();
|
|
197
|
+
for (const e of keptEntities)
|
|
198
|
+
entityByKey.set(e.id, e);
|
|
199
|
+
let newEntityCount = 0;
|
|
200
|
+
for (const e of extraction.entities) {
|
|
201
|
+
if (!originalEntityKeys.has(e.id))
|
|
202
|
+
newEntityCount++;
|
|
203
|
+
entityByKey.set(e.id, e);
|
|
204
|
+
}
|
|
205
|
+
const allChunks = [...keptChunks, ...newChunks];
|
|
206
|
+
const allMeta = [...keptMeta, ...newMeta];
|
|
207
|
+
const allEntities = [...entityByKey.values()];
|
|
208
|
+
const sqliteBytes = await buildChunksDbBytes(allChunks, allMeta);
|
|
209
|
+
const entityFile = {
|
|
210
|
+
schemaVersion: '1.0', builtAt, sdkVersion: null, sourceKind: 'project', entities: allEntities,
|
|
211
|
+
};
|
|
212
|
+
const graphJson = JSON.stringify({ schema_version: '1.0', source: 'directory', built_at: builtAt, sdk_version: null, nodes: nodes.map((n) => ({ id: n.id, title: n.title, summary: null, tags: [], lang: n.lang, source_url: n.sourceUrl })), edges: existing.edges }, null, 2);
|
|
213
|
+
return {
|
|
214
|
+
newDocs: newDocs.length,
|
|
215
|
+
newChunks: newChunkCount,
|
|
216
|
+
newEntities: newEntityCount,
|
|
217
|
+
totalChunks: allChunks.length,
|
|
218
|
+
totalEntities: allEntities.length,
|
|
219
|
+
sources: results,
|
|
220
|
+
artifacts: { graphJson, sqliteBytes, entitiesJson: JSON.stringify(serializeApiEntities(entityFile), null, 2) },
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/** 落盘项目库三件套(原子) */
|
|
224
|
+
export function commitIngest(projectKbPath, plan) {
|
|
225
|
+
writeKbArtifactsAtomic(projectKbPath, [
|
|
226
|
+
{ name: 'doc-graph.json', data: plan.artifacts.graphJson },
|
|
227
|
+
{ name: 'chunks.sqlite', data: plan.artifacts.sqliteBytes },
|
|
228
|
+
{ name: 'api-entities.json', data: plan.artifacts.entitiesJson },
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=ingest-core.js.map
|