spectra-cli 4.1.1 → 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/go-adapter.d.ts.map +1 -1
- package/dist/adapters/go-adapter.js +2 -0
- package/dist/adapters/go-adapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/java-adapter.d.ts.map +1 -1
- package/dist/adapters/java-adapter.js +2 -0
- package/dist/adapters/java-adapter.js.map +1 -1
- package/dist/adapters/language-adapter.d.ts +42 -9
- package/dist/adapters/language-adapter.d.ts.map +1 -1
- package/dist/adapters/python-adapter.d.ts +34 -6
- package/dist/adapters/python-adapter.d.ts.map +1 -1
- package/dist/adapters/python-adapter.js +168 -61
- package/dist/adapters/python-adapter.js.map +1 -1
- package/dist/adapters/ts-js-adapter.d.ts +13 -5
- package/dist/adapters/ts-js-adapter.d.ts.map +1 -1
- package/dist/adapters/ts-js-adapter.js +55 -14
- package/dist/adapters/ts-js-adapter.js.map +1 -1
- package/dist/batch/batch-orchestrator.d.ts +74 -5
- package/dist/batch/batch-orchestrator.d.ts.map +1 -1
- package/dist/batch/batch-orchestrator.js +583 -70
- package/dist/batch/batch-orchestrator.js.map +1 -1
- package/dist/batch/delta-regenerator.d.ts +2 -2
- 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 +9 -2
- package/dist/batch/module-grouper.d.ts.map +1 -1
- package/dist/batch/module-grouper.js +3 -1
- 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/graph.js +1 -1
- package/dist/cli/commands/graph.js.map +1 -1
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +274 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/query.d.ts.map +1 -1
- package/dist/cli/commands/query.js +3 -1
- package/dist/cli/commands/query.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 +33 -14
- 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 +55 -3
- package/dist/cli/utils/parse-args.d.ts.map +1 -1
- package/dist/cli/utils/parse-args.js +176 -13
- 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 +75 -5
- package/dist/core/ast-analyzer.js.map +1 -1
- package/dist/core/import-resolver.d.ts +93 -0
- package/dist/core/import-resolver.d.ts.map +1 -0
- package/dist/core/import-resolver.js +414 -0
- package/dist/core/import-resolver.js.map +1 -0
- package/dist/core/query-mappers/base-mapper.d.ts +13 -0
- package/dist/core/query-mappers/base-mapper.d.ts.map +1 -1
- package/dist/core/query-mappers/go-mapper.d.ts +68 -0
- package/dist/core/query-mappers/go-mapper.d.ts.map +1 -1
- package/dist/core/query-mappers/go-mapper.js +421 -0
- package/dist/core/query-mappers/go-mapper.js.map +1 -1
- package/dist/core/query-mappers/java-mapper.d.ts +196 -0
- package/dist/core/query-mappers/java-mapper.d.ts.map +1 -1
- package/dist/core/query-mappers/java-mapper.js +600 -0
- package/dist/core/query-mappers/java-mapper.js.map +1 -1
- package/dist/core/query-mappers/python-mapper.d.ts +55 -0
- package/dist/core/query-mappers/python-mapper.d.ts.map +1 -1
- package/dist/core/query-mappers/python-mapper.js +273 -0
- package/dist/core/query-mappers/python-mapper.js.map +1 -1
- package/dist/core/query-mappers/typescript-mapper.d.ts +102 -0
- package/dist/core/query-mappers/typescript-mapper.d.ts.map +1 -1
- package/dist/core/query-mappers/typescript-mapper.js +470 -0
- package/dist/core/query-mappers/typescript-mapper.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 +187 -23
- 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 +7 -0
- package/dist/core/tree-sitter-analyzer.d.ts.map +1 -1
- package/dist/core/tree-sitter-analyzer.js +32 -1
- package/dist/core/tree-sitter-analyzer.js.map +1 -1
- package/dist/core/tree-sitter-fallback.d.ts +12 -4
- package/dist/core/tree-sitter-fallback.d.ts.map +1 -1
- package/dist/core/tree-sitter-fallback.js +160 -12
- package/dist/core/tree-sitter-fallback.js.map +1 -1
- package/dist/extraction/extraction-types.d.ts +25 -25
- 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/generator/index-generator.d.ts +3 -3
- package/dist/generator/index-generator.d.ts.map +1 -1
- package/dist/generator/index-generator.js +1 -1
- package/dist/generator/index-generator.js.map +1 -1
- package/dist/graph/directory-graph.d.ts +14 -4
- package/dist/graph/directory-graph.d.ts.map +1 -1
- package/dist/graph/directory-graph.js +71 -128
- package/dist/graph/directory-graph.js.map +1 -1
- package/dist/graph/mermaid-renderer.d.ts +8 -5
- package/dist/graph/mermaid-renderer.d.ts.map +1 -1
- package/dist/graph/mermaid-renderer.js +3 -3
- package/dist/graph/mermaid-renderer.js.map +1 -1
- package/dist/graph/topological-sort.d.ts +13 -6
- package/dist/graph/topological-sort.d.ts.map +1 -1
- package/dist/graph/topological-sort.js +2 -2
- package/dist/graph/topological-sort.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/call-resolver.d.ts +64 -0
- package/dist/knowledge-graph/call-resolver.d.ts.map +1 -0
- package/dist/knowledge-graph/call-resolver.js +323 -0
- package/dist/knowledge-graph/call-resolver.js.map +1 -0
- package/dist/knowledge-graph/import-resolver.d.ts +39 -0
- package/dist/knowledge-graph/import-resolver.d.ts.map +1 -0
- package/dist/knowledge-graph/import-resolver.js +214 -0
- package/dist/knowledge-graph/import-resolver.js.map +1 -0
- package/dist/knowledge-graph/incremental.d.ts +131 -0
- package/dist/knowledge-graph/incremental.d.ts.map +1 -0
- package/dist/knowledge-graph/incremental.js +432 -0
- package/dist/knowledge-graph/incremental.js.map +1 -0
- package/dist/knowledge-graph/index.d.ts +85 -0
- package/dist/knowledge-graph/index.d.ts.map +1 -0
- package/dist/knowledge-graph/index.js +198 -0
- package/dist/knowledge-graph/index.js.map +1 -0
- package/dist/knowledge-graph/module-derivation.d.ts +252 -0
- package/dist/knowledge-graph/module-derivation.d.ts.map +1 -0
- package/dist/knowledge-graph/module-derivation.js +418 -0
- package/dist/knowledge-graph/module-derivation.js.map +1 -0
- package/dist/knowledge-graph/persistence.d.ts +310 -0
- package/dist/knowledge-graph/persistence.d.ts.map +1 -0
- package/dist/knowledge-graph/persistence.js +280 -0
- package/dist/knowledge-graph/persistence.js.map +1 -0
- package/dist/knowledge-graph/query-helpers.d.ts +191 -0
- package/dist/knowledge-graph/query-helpers.d.ts.map +1 -0
- package/dist/knowledge-graph/query-helpers.js +559 -0
- package/dist/knowledge-graph/query-helpers.js.map +1 -0
- 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/knowledge-graph/unified-graph.d.ts +310 -0
- package/dist/knowledge-graph/unified-graph.d.ts.map +1 -0
- package/dist/knowledge-graph/unified-graph.js +182 -0
- package/dist/knowledge-graph/unified-graph.js.map +1 -0
- package/dist/mcp/agent-context-tools.d.ts +53 -0
- package/dist/mcp/agent-context-tools.d.ts.map +1 -0
- package/dist/mcp/agent-context-tools.js +806 -0
- package/dist/mcp/agent-context-tools.js.map +1 -0
- 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 +22 -0
- package/dist/mcp/graph-tools.d.ts.map +1 -1
- package/dist/mcp/graph-tools.js +204 -133
- 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/response-helpers.d.ts +67 -0
- package/dist/mcp/lib/response-helpers.d.ts.map +1 -0
- package/dist/mcp/lib/response-helpers.js +103 -0
- package/dist/mcp/lib/response-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 +14 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +216 -158
- package/dist/mcp/server.js.map +1 -1
- package/dist/models/call-site.d.ts +68 -0
- package/dist/models/call-site.d.ts.map +1 -0
- package/dist/models/call-site.js +60 -0
- package/dist/models/call-site.js.map +1 -0
- package/dist/models/code-skeleton.d.ts +80 -6
- package/dist/models/code-skeleton.d.ts.map +1 -1
- package/dist/models/code-skeleton.js +30 -0
- package/dist/models/code-skeleton.js.map +1 -1
- package/dist/models/drift-item.d.ts +4 -4
- package/dist/models/module-spec.d.ts +173 -94
- 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/adr-decision-pipeline.d.ts +53 -0
- package/dist/panoramic/adr-decision-pipeline.d.ts.map +1 -0
- package/dist/panoramic/adr-decision-pipeline.js +685 -0
- package/dist/panoramic/adr-decision-pipeline.js.map +1 -0
- package/dist/panoramic/api-surface-generator.d.ts +56 -0
- package/dist/panoramic/api-surface-generator.d.ts.map +1 -0
- package/dist/panoramic/api-surface-generator.js +1671 -0
- package/dist/panoramic/api-surface-generator.js.map +1 -0
- package/dist/panoramic/architecture-ir-builder.d.ts +19 -0
- package/dist/panoramic/architecture-ir-builder.d.ts.map +1 -0
- package/dist/panoramic/architecture-ir-builder.js +561 -0
- package/dist/panoramic/architecture-ir-builder.js.map +1 -0
- package/dist/panoramic/architecture-ir-exporters.d.ts +7 -0
- package/dist/panoramic/architecture-ir-exporters.d.ts.map +1 -0
- package/dist/panoramic/architecture-ir-exporters.js +183 -0
- package/dist/panoramic/architecture-ir-exporters.js.map +1 -0
- package/dist/panoramic/architecture-ir-generator.d.ts +36 -0
- package/dist/panoramic/architecture-ir-generator.d.ts.map +1 -0
- package/dist/panoramic/architecture-ir-generator.js +51 -0
- package/dist/panoramic/architecture-ir-generator.js.map +1 -0
- package/dist/panoramic/architecture-ir-mermaid-adapter.d.ts +6 -0
- package/dist/panoramic/architecture-ir-mermaid-adapter.d.ts.map +1 -0
- package/dist/panoramic/architecture-ir-mermaid-adapter.js +98 -0
- package/dist/panoramic/architecture-ir-mermaid-adapter.js.map +1 -0
- package/dist/panoramic/architecture-ir-model.d.ts +87 -0
- package/dist/panoramic/architecture-ir-model.d.ts.map +1 -0
- package/dist/panoramic/architecture-ir-model.js +20 -0
- package/dist/panoramic/architecture-ir-model.js.map +1 -0
- package/dist/panoramic/architecture-narrative.d.ts +68 -0
- package/dist/panoramic/architecture-narrative.d.ts.map +1 -0
- package/dist/panoramic/architecture-narrative.js +401 -0
- package/dist/panoramic/architecture-narrative.js.map +1 -0
- package/dist/panoramic/architecture-overview-generator.d.ts +31 -0
- package/dist/panoramic/architecture-overview-generator.d.ts.map +1 -0
- package/dist/panoramic/architecture-overview-generator.js +454 -0
- package/dist/panoramic/architecture-overview-generator.js.map +1 -0
- package/dist/panoramic/architecture-overview-model.d.ts +77 -0
- package/dist/panoramic/architecture-overview-model.d.ts.map +1 -0
- package/dist/panoramic/architecture-overview-model.js +31 -0
- package/dist/panoramic/architecture-overview-model.js.map +1 -0
- package/dist/panoramic/batch-project-docs.d.ts.map +1 -1
- package/dist/panoramic/batch-project-docs.js +4 -2
- package/dist/panoramic/batch-project-docs.js.map +1 -1
- package/dist/panoramic/builders/component-view-builder.d.ts +25 -1
- package/dist/panoramic/builders/component-view-builder.d.ts.map +1 -1
- package/dist/panoramic/builders/component-view-builder.js +83 -3
- package/dist/panoramic/builders/component-view-builder.js.map +1 -1
- package/dist/panoramic/builders/doc-graph-builder.d.ts +15 -2
- 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/component-view-builder.d.ts +17 -0
- package/dist/panoramic/component-view-builder.d.ts.map +1 -0
- package/dist/panoramic/component-view-builder.js +652 -0
- package/dist/panoramic/component-view-builder.js.map +1 -0
- package/dist/panoramic/component-view-model.d.ts +127 -0
- package/dist/panoramic/component-view-model.d.ts.map +1 -0
- package/dist/panoramic/component-view-model.js +65 -0
- package/dist/panoramic/component-view-model.js.map +1 -0
- package/dist/panoramic/config-reference-generator.d.ts +78 -0
- package/dist/panoramic/config-reference-generator.d.ts.map +1 -0
- package/dist/panoramic/config-reference-generator.js +199 -0
- package/dist/panoramic/config-reference-generator.js.map +1 -0
- package/dist/panoramic/coverage-auditor.d.ts +95 -0
- package/dist/panoramic/coverage-auditor.d.ts.map +1 -0
- package/dist/panoramic/coverage-auditor.js +290 -0
- package/dist/panoramic/coverage-auditor.js.map +1 -0
- package/dist/panoramic/cross-package-analyzer.d.ts +112 -0
- package/dist/panoramic/cross-package-analyzer.d.ts.map +1 -0
- package/dist/panoramic/cross-package-analyzer.js +258 -0
- package/dist/panoramic/cross-package-analyzer.js.map +1 -0
- package/dist/panoramic/data-model-generator.d.ts +528 -0
- package/dist/panoramic/data-model-generator.d.ts.map +1 -0
- package/dist/panoramic/data-model-generator.js +647 -0
- package/dist/panoramic/data-model-generator.js.map +1 -0
- package/dist/panoramic/doc-graph-builder.d.ts +80 -0
- package/dist/panoramic/doc-graph-builder.d.ts.map +1 -0
- package/dist/panoramic/doc-graph-builder.js +352 -0
- package/dist/panoramic/doc-graph-builder.js.map +1 -0
- package/dist/panoramic/docs-bundle-manifest-reader.d.ts +26 -0
- package/dist/panoramic/docs-bundle-manifest-reader.d.ts.map +1 -0
- package/dist/panoramic/docs-bundle-manifest-reader.js +106 -0
- package/dist/panoramic/docs-bundle-manifest-reader.js.map +1 -0
- package/dist/panoramic/docs-bundle-orchestrator.d.ts +14 -0
- package/dist/panoramic/docs-bundle-orchestrator.d.ts.map +1 -0
- package/dist/panoramic/docs-bundle-orchestrator.js +538 -0
- package/dist/panoramic/docs-bundle-orchestrator.js.map +1 -0
- package/dist/panoramic/docs-bundle-profiles.d.ts +4 -0
- package/dist/panoramic/docs-bundle-profiles.d.ts.map +1 -0
- package/dist/panoramic/docs-bundle-profiles.js +82 -0
- package/dist/panoramic/docs-bundle-profiles.js.map +1 -0
- package/dist/panoramic/docs-bundle-types.d.ts +94 -0
- package/dist/panoramic/docs-bundle-types.d.ts.map +1 -0
- package/dist/panoramic/docs-bundle-types.js +10 -0
- package/dist/panoramic/docs-bundle-types.js.map +1 -0
- package/dist/panoramic/docs-quality-evaluator.d.ts +31 -0
- package/dist/panoramic/docs-quality-evaluator.d.ts.map +1 -0
- package/dist/panoramic/docs-quality-evaluator.js +941 -0
- package/dist/panoramic/docs-quality-evaluator.js.map +1 -0
- package/dist/panoramic/docs-quality-model.d.ts +125 -0
- package/dist/panoramic/docs-quality-model.d.ts.map +1 -0
- package/dist/panoramic/docs-quality-model.js +166 -0
- package/dist/panoramic/docs-quality-model.js.map +1 -0
- package/dist/panoramic/dynamic-scenarios-builder.d.ts +18 -0
- package/dist/panoramic/dynamic-scenarios-builder.d.ts.map +1 -0
- package/dist/panoramic/dynamic-scenarios-builder.js +316 -0
- package/dist/panoramic/dynamic-scenarios-builder.js.map +1 -0
- package/dist/panoramic/event-surface-generator.d.ts +52 -0
- package/dist/panoramic/event-surface-generator.d.ts.map +1 -0
- package/dist/panoramic/event-surface-generator.js +507 -0
- package/dist/panoramic/event-surface-generator.js.map +1 -0
- package/dist/panoramic/generator-registry.d.ts +1 -1
- package/dist/panoramic/generator-registry.d.ts.map +1 -1
- package/dist/panoramic/generator-registry.js +5 -2
- package/dist/panoramic/generator-registry.js.map +1 -1
- package/dist/panoramic/generators/cross-package-analyzer.d.ts +5 -5
- package/dist/panoramic/generators/cross-package-analyzer.d.ts.map +1 -1
- package/dist/panoramic/generators/cross-package-analyzer.js +1 -1
- package/dist/panoramic/generators/cross-package-analyzer.js.map +1 -1
- package/dist/panoramic/generators/data-model-generator.d.ts +27 -27
- package/dist/panoramic/graph/confidence-mapper.d.ts +18 -0
- package/dist/panoramic/graph/confidence-mapper.d.ts.map +1 -1
- package/dist/panoramic/graph/confidence-mapper.js +26 -0
- package/dist/panoramic/graph/confidence-mapper.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 +330 -46
- package/dist/panoramic/graph/graph-builder.js.map +1 -1
- package/dist/panoramic/graph/graph-paths.d.ts +8 -0
- package/dist/panoramic/graph/graph-paths.d.ts.map +1 -1
- package/dist/panoramic/graph/graph-paths.js +10 -0
- package/dist/panoramic/graph/graph-paths.js.map +1 -1
- package/dist/panoramic/graph/graph-query.d.ts +49 -2
- package/dist/panoramic/graph/graph-query.d.ts.map +1 -1
- package/dist/panoramic/graph/graph-query.js +117 -19
- package/dist/panoramic/graph/graph-query.js.map +1 -1
- package/dist/panoramic/graph/graph-types.d.ts +32 -3
- package/dist/panoramic/graph/graph-types.d.ts.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/hyperedges/schema.d.ts +6 -6
- package/dist/panoramic/interface-surface-generator.d.ts +50 -0
- package/dist/panoramic/interface-surface-generator.d.ts.map +1 -0
- package/dist/panoramic/interface-surface-generator.js +388 -0
- package/dist/panoramic/interface-surface-generator.js.map +1 -0
- package/dist/panoramic/interfaces.d.ts +2 -2
- package/dist/panoramic/mock-readme-generator.d.ts +90 -0
- package/dist/panoramic/mock-readme-generator.d.ts.map +1 -0
- package/dist/panoramic/mock-readme-generator.js +111 -0
- package/dist/panoramic/mock-readme-generator.js.map +1 -0
- package/dist/panoramic/models/component-view-model.d.ts +1 -1
- package/dist/panoramic/models/component-view-model.d.ts.map +1 -1
- package/dist/panoramic/models/component-view-model.js.map +1 -1
- package/dist/panoramic/narrative-provenance-adapter.d.ts +8 -0
- package/dist/panoramic/narrative-provenance-adapter.d.ts.map +1 -0
- package/dist/panoramic/narrative-provenance-adapter.js +99 -0
- package/dist/panoramic/narrative-provenance-adapter.js.map +1 -0
- package/dist/panoramic/parser-registry.d.ts +1 -1
- package/dist/panoramic/parser-registry.js +1 -1
- package/dist/panoramic/parsers/types.d.ts +6 -6
- package/dist/panoramic/pattern-hints-generator.d.ts +28 -0
- package/dist/panoramic/pattern-hints-generator.d.ts.map +1 -0
- package/dist/panoramic/pattern-hints-generator.js +218 -0
- package/dist/panoramic/pattern-hints-generator.js.map +1 -0
- package/dist/panoramic/pattern-hints-model.d.ts +89 -0
- package/dist/panoramic/pattern-hints-model.d.ts.map +1 -0
- package/dist/panoramic/pattern-hints-model.js +61 -0
- package/dist/panoramic/pattern-hints-model.js.map +1 -0
- package/dist/panoramic/pattern-knowledge-base.d.ts +31 -0
- package/dist/panoramic/pattern-knowledge-base.d.ts.map +1 -0
- package/dist/panoramic/pattern-knowledge-base.js +407 -0
- package/dist/panoramic/pattern-knowledge-base.js.map +1 -0
- 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/pipelines/coverage-auditor.d.ts.map +1 -1
- package/dist/panoramic/pipelines/coverage-auditor.js +4 -2
- package/dist/panoramic/pipelines/coverage-auditor.js.map +1 -1
- package/dist/panoramic/pipelines/docs-bundle-orchestrator.js +13 -6
- package/dist/panoramic/pipelines/docs-bundle-orchestrator.js.map +1 -1
- package/dist/panoramic/pipelines/product-ux-docs.d.ts +5 -0
- package/dist/panoramic/pipelines/product-ux-docs.d.ts.map +1 -1
- package/dist/panoramic/pipelines/product-ux-docs.js +34 -6
- package/dist/panoramic/pipelines/product-ux-docs.js.map +1 -1
- package/dist/panoramic/product-ux-docs.d.ts +104 -0
- package/dist/panoramic/product-ux-docs.d.ts.map +1 -0
- package/dist/panoramic/product-ux-docs.js +817 -0
- package/dist/panoramic/product-ux-docs.js.map +1 -0
- package/dist/panoramic/qa/__tests__/citation.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/citation.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/citation.test.js +193 -0
- package/dist/panoramic/qa/__tests__/citation.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/debt-context.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/debt-context.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/debt-context.test.js +154 -0
- package/dist/panoramic/qa/__tests__/debt-context.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/graph-retriever.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/graph-retriever.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/graph-retriever.test.js +148 -0
- package/dist/panoramic/qa/__tests__/graph-retriever.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/index.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/index.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/index.test.js +246 -0
- package/dist/panoramic/qa/__tests__/index.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/llm-caller.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/llm-caller.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/llm-caller.test.js +168 -0
- package/dist/panoramic/qa/__tests__/llm-caller.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/prompt-builder.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/prompt-builder.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/prompt-builder.test.js +150 -0
- package/dist/panoramic/qa/__tests__/prompt-builder.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/qa-integration.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/qa-integration.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/qa-integration.test.js +296 -0
- package/dist/panoramic/qa/__tests__/qa-integration.test.js.map +1 -0
- package/dist/panoramic/qa/__tests__/rag-reranker.test.d.ts +2 -0
- package/dist/panoramic/qa/__tests__/rag-reranker.test.d.ts.map +1 -0
- package/dist/panoramic/qa/__tests__/rag-reranker.test.js +136 -0
- package/dist/panoramic/qa/__tests__/rag-reranker.test.js.map +1 -0
- package/dist/panoramic/qa/index.d.ts.map +1 -1
- package/dist/panoramic/qa/index.js +10 -3
- package/dist/panoramic/qa/index.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/panoramic/runtime-topology-generator.d.ts +77 -0
- package/dist/panoramic/runtime-topology-generator.d.ts.map +1 -0
- package/dist/panoramic/runtime-topology-generator.js +676 -0
- package/dist/panoramic/runtime-topology-generator.js.map +1 -0
- package/dist/panoramic/runtime-topology-model.d.ts +145 -0
- package/dist/panoramic/runtime-topology-model.d.ts.map +1 -0
- package/dist/panoramic/runtime-topology-model.js +300 -0
- package/dist/panoramic/runtime-topology-model.js.map +1 -0
- package/dist/panoramic/troubleshooting-generator.d.ts +51 -0
- package/dist/panoramic/troubleshooting-generator.d.ts.map +1 -0
- package/dist/panoramic/troubleshooting-generator.js +451 -0
- package/dist/panoramic/troubleshooting-generator.js.map +1 -0
- package/dist/panoramic/utils/text-segmenter.d.ts +15 -0
- package/dist/panoramic/utils/text-segmenter.d.ts.map +1 -1
- package/dist/panoramic/utils/text-segmenter.js +38 -0
- package/dist/panoramic/utils/text-segmenter.js.map +1 -1
- package/dist/panoramic/workspace-index-generator.d.ts +148 -0
- package/dist/panoramic/workspace-index-generator.d.ts.map +1 -0
- package/dist/panoramic/workspace-index-generator.js +497 -0
- package/dist/panoramic/workspace-index-generator.js.map +1 -0
- package/dist/runtime-bootstrap.d.ts +9 -0
- package/dist/runtime-bootstrap.d.ts.map +1 -0
- package/dist/runtime-bootstrap.js +33 -0
- package/dist/runtime-bootstrap.js.map +1 -0
- 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 +18 -1
- 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 +22 -3
- 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 +50 -1
- package/plugins/spec-driver/agents/implement.md +20 -1
- package/plugins/spec-driver/agents/plan.md +20 -1
- package/plugins/spec-driver/agents/quality-review.md +20 -1
- package/plugins/spec-driver/agents/spec-review.md +20 -1
- package/plugins/spec-driver/agents/verify.md +108 -1
- 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/docs/customization.md +134 -0
- package/plugins/spec-driver/docs/spectra-mcp-integration.md +165 -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/lib/preference-rules.mjs +96 -0
- 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/sync-preference-rules.mjs +148 -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 +302 -0
- package/plugins/spec-driver/skills/spec-driver-fix/SKILL.md +97 -8
- package/plugins/spec-driver/skills/spec-driver-implement/SKILL.md +18 -0
- package/plugins/spec-driver/skills/spec-driver-refactor/SKILL.md +10 -0
- package/plugins/spec-driver/skills/spec-driver-resume/SKILL.md +12 -1
- package/plugins/spec-driver/skills/spec-driver-story/SKILL.md +30 -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/preference-rules.md +39 -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 +48 -1
- package/plugins/spectra/hooks/post-commit.sh +40 -0
- package/templates/module-spec.hbs +1 -0
- package/templates/product-overview.hbs +1 -1
|
@@ -8,7 +8,7 @@ import * as fs from 'node:fs';
|
|
|
8
8
|
import * as path from 'node:path';
|
|
9
9
|
import pLimit from 'p-limit';
|
|
10
10
|
import { findReadmePath } from '../extraction/index.js';
|
|
11
|
-
import {
|
|
11
|
+
import { buildModuleGraphForProject } from '../knowledge-graph/module-derivation.js';
|
|
12
12
|
import { generateSpec } from '../core/single-spec-orchestrator.js';
|
|
13
13
|
import { generateIndex } from '../generator/index-generator.js';
|
|
14
14
|
import { renderIndex, initRenderer } from '../generator/spec-renderer.js';
|
|
@@ -20,10 +20,11 @@ import { estimateModuleCost, buildDryRunReport, renderDryRunReport, runBudgetGat
|
|
|
20
20
|
import { decideModelOverride } from './model-override-decision.js';
|
|
21
21
|
import { createLogger } from '../panoramic/utils/logger.js';
|
|
22
22
|
import { groupFilesToModules } from './module-grouper.js';
|
|
23
|
+
import { buildSpecCacheKey, normalizeProjectPath, resolveRegenPlan, resolveSourceTarget } from './regen-plan.js';
|
|
23
24
|
import { groupFilesByLanguage } from './language-grouper.js';
|
|
24
|
-
import { scanFiles } from '../utils/file-scanner.js';
|
|
25
|
+
import { scanFiles, createGitignoreFilter } from '../utils/file-scanner.js';
|
|
25
26
|
import { LanguageAdapterRegistry } from '../adapters/language-adapter-registry.js';
|
|
26
|
-
import { buildDocGraph, runAnchorIntegration, runHyperedgeIntegration, scanStoredModuleSpecs, } from '../panoramic/builders/doc-graph-builder.js';
|
|
27
|
+
import { buildDocGraph, isBatchGenerated, runAnchorIntegration, runHyperedgeIntegration, scanStoredModuleSpecs, } from '../panoramic/builders/doc-graph-builder.js';
|
|
27
28
|
import { chunkMarkdownFiles } from '../panoramic/anchoring/chunker.js';
|
|
28
29
|
import { createEmbeddingProvider } from '../panoramic/anchoring/providers/factory.js';
|
|
29
30
|
import { DOC_NODE_KINDS } from '../panoramic/hyperedges/constants.js';
|
|
@@ -37,10 +38,13 @@ import { detectAuth } from '../auth/auth-detector.js';
|
|
|
37
38
|
import { orchestrateDocsBundle } from '../panoramic/pipelines/docs-bundle-orchestrator.js';
|
|
38
39
|
import { generateDebtIntelligence, } from '../panoramic/pipelines/debt-intelligence-pipeline.js';
|
|
39
40
|
import { BATCH_OUTPUT_SUBDIRS } from '../panoramic/output-filenames.js';
|
|
40
|
-
import { buildKnowledgeGraph, writeKnowledgeGraph } from '../panoramic/graph/index.js';
|
|
41
|
+
import { buildKnowledgeGraph, writeKnowledgeGraph, normalizeGraphForWrite } from '../panoramic/graph/index.js';
|
|
42
|
+
import { buildUnifiedGraph, setCurrentUnifiedGraph, getCurrentUnifiedGraph, } from '../knowledge-graph/index.js';
|
|
41
43
|
import { buildHtmlTemplate } from '../panoramic/exporters/html-template.js';
|
|
42
44
|
import { SpecStore } from '../spec-store/index.js';
|
|
43
45
|
import { createRequire } from 'node:module';
|
|
46
|
+
import { resolvePythonImport } from '../knowledge-graph/import-resolver.js';
|
|
47
|
+
import { resolveTsJsImport, findNearestTsConfig, buildTsConfigContext, } from '../core/import-resolver.js';
|
|
44
48
|
// 从 package.json 读取版本号(避免硬编码)
|
|
45
49
|
const _require = createRequire(import.meta.url);
|
|
46
50
|
const SPECTRA_VERSION = _require('../../package.json').version;
|
|
@@ -63,7 +67,40 @@ const logger = createLogger('batch-orchestrator');
|
|
|
63
67
|
// 内部辅助函数
|
|
64
68
|
// ============================================================
|
|
65
69
|
/**
|
|
66
|
-
*
|
|
70
|
+
* Feature 182 修复面 4:checkpoint replace 语义(completed/failed 互斥去重)。
|
|
71
|
+
*
|
|
72
|
+
* 背景:F175 给 checkpoint 加了「mustRegen 失效重跑」(fall-through)语义,但 completedModules
|
|
73
|
+
* 仍沿用 append-only 写法——已完成 module 被重跑后会二次 push,导致 resume 进度超 totalModules,
|
|
74
|
+
* 且 completed / failed 可能交叉污染(同一 module 同时出现在两个集合)。
|
|
75
|
+
*
|
|
76
|
+
* 本 helper 以 path 为身份键先剔除两个集合中的同名旧条目,再 push 到目标集合,保证:
|
|
77
|
+
* (1) 同一 module 在每个集合最多出现一次;(2) completed 与 failed 互斥。
|
|
78
|
+
*
|
|
79
|
+
* 注意:helper 内不得有 await——JS 单线程下同步段不被 pLimit 并发交错,
|
|
80
|
+
* 保持纯同步可防未来插入 await 后语义退化为「读-改-写」竞态。
|
|
81
|
+
*/
|
|
82
|
+
function upsertCompletedModule(state, entry) {
|
|
83
|
+
state.completedModules = state.completedModules.filter((m) => m.path !== entry.path);
|
|
84
|
+
state.failedModules = state.failedModules.filter((m) => m.path !== entry.path);
|
|
85
|
+
state.completedModules.push(entry);
|
|
86
|
+
}
|
|
87
|
+
function recordFailedModule(state, entry) {
|
|
88
|
+
state.failedModules = state.failedModules.filter((m) => m.path !== entry.path);
|
|
89
|
+
state.completedModules = state.completedModules.filter((m) => m.path !== entry.path);
|
|
90
|
+
state.failedModules.push(entry);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* F175 FR-017/EC-009:判定 absPath 是否位于受管 modules/ 输出目录内(孤儿删除 ownership 必要条件2)。
|
|
94
|
+
*
|
|
95
|
+
* 用 path.relative 判定目录归属,禁用字符串 startsWith——否则 `specs/modules-old/...` 这类
|
|
96
|
+
* sibling 目录会被前缀匹配误判为受管目录(目录穿越)。同时校验 .spec.md 后缀。
|
|
97
|
+
*/
|
|
98
|
+
function isInManagedOutputDir(absPath, modulesDir) {
|
|
99
|
+
const rel = path.relative(modulesDir, path.resolve(absPath));
|
|
100
|
+
return !rel.startsWith('..') && !path.isAbsolute(rel) && absPath.endsWith('.spec.md');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 合并多个语言的 ModuleGraph 用于全局拓扑排序
|
|
67
104
|
* 仅合并 modules 和 edges,SCC/Mermaid 按语言独立保留(TD-002 选项 C)
|
|
68
105
|
*/
|
|
69
106
|
export function mergeGraphsForTopologicalSort(graphs, projectRoot) {
|
|
@@ -170,7 +207,14 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
170
207
|
const effectiveMode = options.mode ?? 'full';
|
|
171
208
|
// F5:FR-006 — 日志输出当前 mode
|
|
172
209
|
logger.info(`[info] batch mode: ${effectiveMode}`);
|
|
173
|
-
const {
|
|
210
|
+
const { maxRetries = 3, outputDir = 'specs', } = options;
|
|
211
|
+
// F175 FR-002:唯一默认值来源——对直接调用方兜底解析 RegenPlan(CLI/MCP 已在各自入口解析后传入有效值)。
|
|
212
|
+
// 删除原 `incremental = false` 硬编码,默认增量(regenPlan.incremental)由 resolveRegenPlan 决定(FR-001)。
|
|
213
|
+
const regenPlan = resolveRegenPlan({
|
|
214
|
+
incremental: options.incremental,
|
|
215
|
+
full: options.full,
|
|
216
|
+
force: options.force,
|
|
217
|
+
});
|
|
174
218
|
const startTime = Date.now();
|
|
175
219
|
const resolvedRoot = path.resolve(projectRoot);
|
|
176
220
|
const resolvedOutputDir = path.isAbsolute(outputDir)
|
|
@@ -185,7 +229,6 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
185
229
|
const rel = path.relative(resolvedRoot, absPath);
|
|
186
230
|
return rel.startsWith('..') ? absPath : rel;
|
|
187
231
|
};
|
|
188
|
-
const normalizeProjectPath = (inputPath) => inputPath.split(path.sep).join('/');
|
|
189
232
|
// 步骤 1:扫描文件获取 languageStats
|
|
190
233
|
const scanResult = scanFiles(resolvedRoot, { projectRoot: resolvedRoot });
|
|
191
234
|
const languageStats = scanResult.languageStats;
|
|
@@ -214,14 +257,14 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
214
257
|
// 步骤 1.7:合并拓扑排序
|
|
215
258
|
mergedGraph = perLangGraphs.length > 0
|
|
216
259
|
? mergeGraphsForTopologicalSort(perLangGraphs, resolvedRoot)
|
|
217
|
-
: await
|
|
260
|
+
: await buildModuleGraphForProject(resolvedRoot);
|
|
218
261
|
}
|
|
219
262
|
else if (isSingleNonTsJs && languageGroupsList[0]) {
|
|
220
263
|
mergedGraph = await buildGraphForLanguageGroup(languageGroupsList[0], resolvedRoot);
|
|
221
264
|
}
|
|
222
265
|
else {
|
|
223
|
-
// 纯 TS/JS
|
|
224
|
-
mergedGraph = await
|
|
266
|
+
// 纯 TS/JS 或未识别受支持语言:走 UnifiedGraph 派生路径(Feature 156 删除 dependency-cruiser)
|
|
267
|
+
mergedGraph = await buildModuleGraphForProject(resolvedRoot);
|
|
225
268
|
}
|
|
226
269
|
// 步骤 2:文件→模块聚合 + 模块级拓扑排序
|
|
227
270
|
const groupingOptions = {
|
|
@@ -235,42 +278,34 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
235
278
|
const moduleGroups = new Map(groupResult.groups.map((g) => [g.name, g]));
|
|
236
279
|
const rootModuleName = options.grouping?.rootModuleName ?? 'root';
|
|
237
280
|
const existingStoredSpecs = scanStoredModuleSpecs(resolvedOutputDir, resolvedRoot);
|
|
238
|
-
|
|
281
|
+
// Feature 182:以 cache key 入索引(languageSplit 组带 `::language` 后缀),与 processOneModule
|
|
282
|
+
// 的 moduleCacheKey 口径对齐;旧 spec 无 sourceTargetKey 时回落纯路径 sourceTarget。
|
|
283
|
+
const storedSpecByTarget = new Map(existingStoredSpecs.map((spec) => [spec.sourceTargetKey ?? spec.sourceTarget, spec]));
|
|
284
|
+
// F175:全量逃生口(--full / --force 合并为 regenPlan.full)打可观测日志,
|
|
285
|
+
// 替代原 fallbackReason='force-enabled' 内部信号(W-1 取舍)。
|
|
286
|
+
if (regenPlan.full) {
|
|
287
|
+
logger.info(`[regen] full regeneration (source=${regenPlan.source})`);
|
|
288
|
+
}
|
|
289
|
+
// F175:仅增量路径(regenPlan.incremental)调用 DeltaRegenerator;full 路径直接走全量。
|
|
239
290
|
let deltaReport;
|
|
240
|
-
if (incremental) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
regenerateTargets: [],
|
|
252
|
-
directChanges: [],
|
|
253
|
-
propagatedChanges: [],
|
|
254
|
-
unchangedTargets: [],
|
|
255
|
-
fallbackReason: 'force-enabled',
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
const deltaRegenerator = new DeltaRegenerator();
|
|
260
|
-
deltaReport = await deltaRegenerator.plan({
|
|
261
|
-
projectRoot: resolvedRoot,
|
|
262
|
-
dependencyGraph: mergedGraph,
|
|
263
|
-
moduleGroups: groupResult.groups,
|
|
264
|
-
storedSpecs: existingStoredSpecs,
|
|
265
|
-
// Bug 142:传入 effectiveMode 启用 mode-aware cache,
|
|
266
|
-
// 旧 spec(无 generatedByMode)或 mode 不匹配时强制 cache miss。
|
|
267
|
-
effectiveMode,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
291
|
+
if (regenPlan.incremental) {
|
|
292
|
+
const deltaRegenerator = new DeltaRegenerator();
|
|
293
|
+
deltaReport = await deltaRegenerator.plan({
|
|
294
|
+
projectRoot: resolvedRoot,
|
|
295
|
+
dependencyGraph: mergedGraph,
|
|
296
|
+
moduleGroups: groupResult.groups,
|
|
297
|
+
storedSpecs: existingStoredSpecs,
|
|
298
|
+
// Bug 142:传入 effectiveMode 启用 mode-aware cache,
|
|
299
|
+
// 旧 spec(无 generatedByMode)或 mode 不匹配时强制 cache miss。
|
|
300
|
+
effectiveMode,
|
|
301
|
+
});
|
|
270
302
|
}
|
|
271
303
|
const regenerateTargets = new Set(deltaReport?.regenerateTargets ?? []);
|
|
272
|
-
|
|
273
|
-
|
|
304
|
+
// EC-001 force/full 优先:regenPlan.full 直接全量;增量路径 deltaReport.mode==='full'
|
|
305
|
+
//(首次运行 / 无历史 spec / mode 切换)退化全量仍走 forceFullRegeneration。
|
|
306
|
+
// Feature 182:改为 let——full-resume 时序修复需在 checkpoint 加载后回写(见下方 isResume 块)。
|
|
307
|
+
let forceFullRegeneration = regenPlan.full || (regenPlan.incremental && deltaReport?.mode === 'full');
|
|
308
|
+
let shouldUseIncrementalPlan = regenPlan.incremental && deltaReport?.mode === 'incremental';
|
|
274
309
|
console.log(`发现 ${mergedGraph.modules.length} 个文件,聚合为 ${processingOrder.length} 个模块`);
|
|
275
310
|
if (isMultiLang) {
|
|
276
311
|
console.log(`检测到 ${processedLanguages.length} 种语言: ${processedLanguages.join(', ')}`);
|
|
@@ -361,6 +396,18 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
361
396
|
}
|
|
362
397
|
// 步骤 3:检查是否存在检查点
|
|
363
398
|
let state = loadCheckpoint(checkpointPath);
|
|
399
|
+
// F175 FR-016/EC-007:full/force 启动时丢弃已加载的 checkpoint completed + failed state,
|
|
400
|
+
// 防止残留 checkpoint 命中导致全量语义被绕过(必须在 completedPaths 构建前清空——
|
|
401
|
+
// 加载时即清,而非在 processOneModule 内"忽略",避免中途崩溃 resume 复用脏 set)。
|
|
402
|
+
// W-1:必须同时清空 failedModules——否则 full 后 summary(:1749 起用 checkedState.failedModules)
|
|
403
|
+
// 仍混入上一轮的旧失败详情,与"full 是干净全量"语义矛盾。
|
|
404
|
+
if (state &&
|
|
405
|
+
regenPlan.full &&
|
|
406
|
+
(state.completedModules.length > 0 || state.failedModules.length > 0)) {
|
|
407
|
+
logger.info(`[regen] full regeneration 丢弃残留 checkpoint state(completed ${state.completedModules.length} / failed ${state.failedModules.length} 模块)`);
|
|
408
|
+
state = { ...state, completedModules: [], failedModules: [] };
|
|
409
|
+
saveCheckpoint(state, checkpointPath);
|
|
410
|
+
}
|
|
364
411
|
const isResume = state !== null;
|
|
365
412
|
if (!state) {
|
|
366
413
|
state = {
|
|
@@ -372,7 +419,7 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
372
419
|
processingOrder,
|
|
373
420
|
completedModules: [],
|
|
374
421
|
failedModules: [],
|
|
375
|
-
forceRegenerate:
|
|
422
|
+
forceRegenerate: regenPlan.full,
|
|
376
423
|
// 多语言扩展字段
|
|
377
424
|
languageGroups: isMultiLang
|
|
378
425
|
? Object.fromEntries(languageGroupsList.map((g) => [g.adapterId, g.files]))
|
|
@@ -382,6 +429,17 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
382
429
|
}
|
|
383
430
|
if (isResume) {
|
|
384
431
|
console.log(`恢复断点: 已完成 ${state.completedModules.length}/${state.totalModules} 模块`);
|
|
432
|
+
// Feature 182 修复面 5:恢复中断的 --full run 意图。
|
|
433
|
+
// 背景:首轮 --full 把 forceRegenerate=true 落盘到 checkpoint(:660),但 runtime 仅用本轮
|
|
434
|
+
// regenPlan 重算的 forceFullRegeneration——裸增量 resume 时为 false,剩余模块静默降级为增量,
|
|
435
|
+
// 产出半新半旧混合产物。此处从 checkpoint 恢复 full 意图,剩余模块继续全量。
|
|
436
|
+
// 时序安全:两变量消费点全在 processOneModule 内(在此回写之后才被调用)。
|
|
437
|
+
// 注意:full-resume 不清空 completed(:636 清空条件用 regenPlan.full 而非本变量),正是 resume 语义。
|
|
438
|
+
if (state.forceRegenerate && !forceFullRegeneration) {
|
|
439
|
+
forceFullRegeneration = true;
|
|
440
|
+
shouldUseIncrementalPlan = false;
|
|
441
|
+
logger.info('[resume] 检测到中断的 full run,剩余模块继续全量');
|
|
442
|
+
}
|
|
385
443
|
}
|
|
386
444
|
// 步骤 4:按模块级拓扑顺序处理
|
|
387
445
|
// Feature 146 FR-010/FR-011:通过 getActiveCount getter 注入 limit.activeCount,
|
|
@@ -441,16 +499,30 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
441
499
|
const group = moduleGroups.get(moduleName);
|
|
442
500
|
if (!group)
|
|
443
501
|
return;
|
|
444
|
-
if (completedPaths.has(moduleName))
|
|
445
|
-
return;
|
|
446
502
|
const isRoot = moduleName === rootModuleName || moduleName.startsWith(`${rootModuleName}--`);
|
|
447
503
|
const specPath = path.join(modulesDir, `${moduleName}.spec.md`);
|
|
448
|
-
//
|
|
449
|
-
// 否则 --incremental 的 regenerateTargets 查询和 storedSpecByTarget
|
|
450
|
-
|
|
451
|
-
const moduleSourceTarget =
|
|
452
|
-
|
|
453
|
-
|
|
504
|
+
// FR-019:target 口径与 DeltaRegenerator 共用 resolveSourceTarget(文件级降级分支一致),
|
|
505
|
+
// 否则 --incremental 的 regenerateTargets 查询和 storedSpecByTarget 查询全部错位。
|
|
506
|
+
// T020:target 计算前移到 checkpoint 判定之前,供增量 resume 失效判定使用。
|
|
507
|
+
const moduleSourceTarget = resolveSourceTarget(group, conflictingDirPaths, isRoot);
|
|
508
|
+
// Feature 182:cache key(languageSplit 组带 `::language` 后缀),用于 regenerateTargets /
|
|
509
|
+
// storedSpecByTarget / existingVersion 查询,消除同目录多语言组键碰撞;targetPath 与
|
|
510
|
+
// frontmatter 继续用纯路径 moduleSourceTarget(statSync 路径 + panoramic 匹配口径不变)。
|
|
511
|
+
const moduleCacheKey = buildSpecCacheKey(moduleSourceTarget, group);
|
|
512
|
+
// F175 FR-016:checkpoint 判定。full 路径已在加载时清空 completedPaths(必为干净);
|
|
513
|
+
// 增量 resume 下若 checkpoint 命中但本轮 delta 要求重生成该 target,则失效重跑。
|
|
514
|
+
// C-3:root 模块的 regenerateTargets 是文件级(DeltaRegenerator 对 root 按每个文件
|
|
515
|
+
// 产出 snapshot),但 moduleSourceTarget(root 时为 group.dirPath)不在文件级集合里,
|
|
516
|
+
// 用 dirPath 查永远 miss → mustRegen=false → root 文件变更时 checkpoint 命中被错误跳过。
|
|
517
|
+
// 故 root 模块改判 group.files 中任一文件 target 是否命中 regenerateTargets。
|
|
518
|
+
if (completedPaths.has(moduleName)) {
|
|
519
|
+
const mustRegen = shouldUseIncrementalPlan &&
|
|
520
|
+
(isRoot
|
|
521
|
+
? group.files.some((filePath) => regenerateTargets.has(normalizeProjectPath(filePath)))
|
|
522
|
+
: regenerateTargets.has(moduleCacheKey));
|
|
523
|
+
if (!mustRegen)
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
454
526
|
const rootTargetsToGenerate = isRoot
|
|
455
527
|
? group.files
|
|
456
528
|
.map((filePath) => normalizeProjectPath(filePath))
|
|
@@ -473,7 +545,7 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
473
545
|
else {
|
|
474
546
|
const shouldGenerate = forceFullRegeneration
|
|
475
547
|
|| (shouldUseIncrementalPlan
|
|
476
|
-
? regenerateTargets.has(
|
|
548
|
+
? regenerateTargets.has(moduleCacheKey)
|
|
477
549
|
: !fs.existsSync(specPath));
|
|
478
550
|
if (!shouldGenerate) {
|
|
479
551
|
skipped.push(moduleName);
|
|
@@ -587,24 +659,32 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
587
659
|
}
|
|
588
660
|
successful.push(moduleName);
|
|
589
661
|
reporter.complete(moduleName, 'success');
|
|
590
|
-
|
|
662
|
+
// Feature 182:replace 语义(失效重跑时去重 + completed/failed 互斥)
|
|
663
|
+
upsertCompletedModule(checkedState, {
|
|
591
664
|
path: moduleName,
|
|
592
665
|
specPath: generatedRootSpecs[0],
|
|
593
666
|
completedAt: new Date().toISOString(),
|
|
594
667
|
});
|
|
595
668
|
}
|
|
596
669
|
else {
|
|
597
|
-
// BUG-A
|
|
598
|
-
//
|
|
599
|
-
|
|
600
|
-
// 注意:hasDirPathConflict 已在上方计算(H4 修复)
|
|
601
|
-
const targetPath = hasDirPathConflict
|
|
602
|
-
? path.join(resolvedRoot, group.files[0])
|
|
603
|
-
: path.join(resolvedRoot, group.dirPath);
|
|
670
|
+
// BUG-A / H4 修复:targetPath 直接由 moduleSourceTarget 推导(FR-019:resolveSourceTarget
|
|
671
|
+
// 已处理"同一 dirPath 多单文件冲突走文件路径"的降级分支),与 sourceTarget 口径保持一致。
|
|
672
|
+
const targetPath = path.join(resolvedRoot, moduleSourceTarget);
|
|
604
673
|
// genOptions.skipEnrichment 已在 L648 处理 reading/code-only 模式分派
|
|
605
674
|
const result = await generateSpec(targetPath, {
|
|
606
675
|
...genOptions,
|
|
607
|
-
|
|
676
|
+
// Feature 182:注入 group.files(语言限定子集,绝对路径),使写侧只分析本语言文件,
|
|
677
|
+
// 与读侧 group.files 文件集口径一致(消除混语言 hash 分叉 + 双倍分析)。
|
|
678
|
+
files: group.files.map((f) => path.join(resolvedRoot, f)),
|
|
679
|
+
existingVersion: storedSpecByTarget.get(moduleCacheKey)?.version,
|
|
680
|
+
// Feature 182 修复 1:仅 languageSplit 组按 moduleName 显式命名输出文件,
|
|
681
|
+
// 避免同目录多语言组(ts / py)都派生为同名 `<dir>.spec.md` 互相覆盖;
|
|
682
|
+
// 非拆分组不传 → basename 派生,存量单语言仓库命名零变化。
|
|
683
|
+
...(group.languageSplit ? { outputFileName: `${moduleName}.spec.md` } : {}),
|
|
684
|
+
// Feature 182 修复 2:languageSplit 组首写即落入 frontmatter.sourceTargetKey,
|
|
685
|
+
// 消除「post-mutation 依赖 doc-graph re-render 落盘晚于 checkpoint save」崩溃窗口;
|
|
686
|
+
// in-memory moduleSpec.frontmatter 由 generateFrontmatter 返回自然带上。
|
|
687
|
+
sourceTargetKey: group.languageSplit ? moduleCacheKey : undefined,
|
|
608
688
|
});
|
|
609
689
|
// Bug 142:非 root 分支累积 input token,供 catch 块统一做预算检查。
|
|
610
690
|
if (result.costMetadata?.tokenUsage.input) {
|
|
@@ -629,7 +709,8 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
629
709
|
successful.push(moduleName);
|
|
630
710
|
reporter.complete(moduleName, 'success');
|
|
631
711
|
}
|
|
632
|
-
|
|
712
|
+
// Feature 182:replace 语义(失效重跑时去重 + completed/failed 互斥)
|
|
713
|
+
upsertCompletedModule(checkedState, {
|
|
633
714
|
path: moduleName,
|
|
634
715
|
specPath: toProjectPath(path.resolve(result.specPath)),
|
|
635
716
|
completedAt: new Date().toISOString(),
|
|
@@ -684,7 +765,8 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
684
765
|
reason: 'retry-budget-exceeded',
|
|
685
766
|
};
|
|
686
767
|
failed.push(failedModule);
|
|
687
|
-
|
|
768
|
+
// Feature 182:replace 语义(失效重跑时去重 + completed/failed 互斥)
|
|
769
|
+
recordFailedModule(checkedState, failedModule);
|
|
688
770
|
reporter.complete(moduleName, 'failed');
|
|
689
771
|
break;
|
|
690
772
|
}
|
|
@@ -698,7 +780,8 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
698
780
|
degradedToAstOnly: false,
|
|
699
781
|
};
|
|
700
782
|
failed.push(failedModule);
|
|
701
|
-
|
|
783
|
+
// Feature 182:replace 语义(失效重跑时去重 + completed/failed 互斥)
|
|
784
|
+
recordFailedModule(checkedState, failedModule);
|
|
702
785
|
reporter.complete(moduleName, 'failed');
|
|
703
786
|
}
|
|
704
787
|
}
|
|
@@ -743,7 +826,8 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
743
826
|
reason: 'unhandled-exception',
|
|
744
827
|
};
|
|
745
828
|
failed.push(failedModule);
|
|
746
|
-
|
|
829
|
+
// Feature 182:replace 语义(失效重跑时去重 + completed/failed 互斥)
|
|
830
|
+
recordFailedModule(checkedState, failedModule);
|
|
747
831
|
try {
|
|
748
832
|
reporter.complete(moduleName, 'failed');
|
|
749
833
|
}
|
|
@@ -762,10 +846,63 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
762
846
|
let projectDocsResult;
|
|
763
847
|
let docsBundleManifestPath;
|
|
764
848
|
let docsBundleProfiles;
|
|
765
|
-
//
|
|
849
|
+
// F175 FR-017/EC-008/EC-009:删除孤儿 spec(源文件已删除的 batch 产物),使增量产物文件集与全量一致。
|
|
850
|
+
// 必须在构造 SpecStore 之前执行 + 从 storedSpecs 集合中剔除已删项(C-2)——否则后续
|
|
851
|
+
// 所有聚合(index/graph/coverage/cross-ref)仍引用陈旧的已删 spec 视图,产生 stale 输出。
|
|
852
|
+
// 仅在增量/全量路径执行;ownership 边界缺一不删:(1) generatedByMode 存在(batch 专属标记)+
|
|
853
|
+
// (2) 位于受管 modules/ 输出目录内(path.relative 防目录穿越,禁字符串 startsWith)+
|
|
854
|
+
// (3) sourceTarget 已无任何在库源文件(EC-008:删除模块最后一个源文件后,空目录仍 existsSync=true,
|
|
855
|
+
// 故不能仅靠目录存在性判定——以当前扫描到的源文件集合为准)。
|
|
856
|
+
let storedSpecsForStore = existingStoredSpecs;
|
|
857
|
+
if (regenPlan.incremental || regenPlan.full) {
|
|
858
|
+
// 当前扫描到的源文件(项目相对,正斜杠口径),用于判定 sourceTarget 是否仍有活跃源文件
|
|
859
|
+
const liveSourceFiles = new Set(scanResult.files.map((f) => normalizeProjectPath(f)));
|
|
860
|
+
const hasLiveSource = (sourceTarget) => {
|
|
861
|
+
const prefix = `${sourceTarget}/`;
|
|
862
|
+
for (const f of liveSourceFiles) {
|
|
863
|
+
if (f === sourceTarget || f.startsWith(prefix))
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
866
|
+
return false;
|
|
867
|
+
};
|
|
868
|
+
// 已确认删除的孤儿 outputPath 集合,用于从 storedSpecs 中剔除,使 SpecStore 不持有陈旧视图。
|
|
869
|
+
const deletedOrphanPaths = new Set();
|
|
870
|
+
for (const orphan of existingStoredSpecs) {
|
|
871
|
+
if (!isBatchGenerated(orphan))
|
|
872
|
+
continue; // 必要条件1:无 generatedByMode → 跳过(防误删手写 / 单文件 generate 产物)
|
|
873
|
+
if (hasLiveSource(orphan.sourceTarget))
|
|
874
|
+
continue; // 必要条件3:仍有活跃源文件 → 非孤儿
|
|
875
|
+
const absPath = path.isAbsolute(orphan.outputPath)
|
|
876
|
+
? orphan.outputPath
|
|
877
|
+
: path.join(resolvedRoot, orphan.outputPath);
|
|
878
|
+
if (!isInManagedOutputDir(absPath, modulesDir))
|
|
879
|
+
continue; // 必要条件2:受管 modules/ 目录外 → 跳过
|
|
880
|
+
// 磁盘文件已被本轮其它逻辑清理:视为已删除,从内存视图剔除(保持内存与磁盘一致)。
|
|
881
|
+
if (!fs.existsSync(absPath)) {
|
|
882
|
+
deletedOrphanPaths.add(orphan.outputPath);
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
// W-1(quality-review):rmSync 是破坏性新操作,权限/OS 错误不应让整个 batch 崩溃。
|
|
886
|
+
// 失败时 warn + 跳过,且【不】加入 deletedOrphanPaths——文件仍在磁盘,内存视图须保留它,
|
|
887
|
+
// 避免"内存说已删、磁盘还在"的不一致。仅删除成功才剔除内存视图。
|
|
888
|
+
try {
|
|
889
|
+
logger.info(`[orphan-cleanup] 删除孤儿 spec: ${orphan.outputPath}`);
|
|
890
|
+
fs.rmSync(absPath, { force: true });
|
|
891
|
+
deletedOrphanPaths.add(orphan.outputPath);
|
|
892
|
+
}
|
|
893
|
+
catch (err) {
|
|
894
|
+
logger.warn(`[orphan-cleanup] 删除孤儿 spec 失败,保守跳过: ${orphan.outputPath}(${err.message})`);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (deletedOrphanPaths.size > 0) {
|
|
898
|
+
storedSpecsForStore = existingStoredSpecs.filter((spec) => !deletedOrphanPaths.has(spec.outputPath));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
// SpecStore 统一查询入口:所有消费方(README、graph、coverage、index、cross-ref)共享此源。
|
|
902
|
+
// 使用已剔除孤儿的 storedSpecsForStore,确保后续聚合不引用已删 spec(C-2)。
|
|
766
903
|
const specStore = new SpecStore({
|
|
767
904
|
currentSpecs: collectedModuleSpecs,
|
|
768
|
-
storedSpecs:
|
|
905
|
+
storedSpecs: storedSpecsForStore,
|
|
769
906
|
projectRoot: resolvedRoot,
|
|
770
907
|
toProjectPath,
|
|
771
908
|
});
|
|
@@ -824,6 +961,34 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
824
961
|
logger.warn(`README 早期读取失败(不阻断 narrative 主流程): ${String(readmeErr)}`);
|
|
825
962
|
}
|
|
826
963
|
}
|
|
964
|
+
// Feature 151 Codex Final C-1 修订 — 在 generateBatchProjectDocs 之前构建 UnifiedGraph
|
|
965
|
+
// 让 component-view-builder 能在生成时获取 graph(DI provider getCurrentUnifiedGraph)
|
|
966
|
+
//
|
|
967
|
+
// Feature 152 Codex final C-1 修复 — 同时合并 Python + TS/JS codeSkeletons,
|
|
968
|
+
// 否则用户跑 spectra batch 后 TS 项目 graph.json 中没有 calls 边(US-001 失败)
|
|
969
|
+
setCurrentUnifiedGraph(null);
|
|
970
|
+
try {
|
|
971
|
+
const pythonSkeletons = await collectPythonCodeSkeletons(resolvedRoot);
|
|
972
|
+
const tsJsSkeletons = await collectTsJsCodeSkeletons(resolvedRoot, {
|
|
973
|
+
extractCallSites: true,
|
|
974
|
+
});
|
|
975
|
+
// 合并两个 Map(projectRoot 都已 normalize 为绝对路径,key 形态一致)
|
|
976
|
+
const earlyCodeSkeletons = new Map([...pythonSkeletons, ...tsJsSkeletons]);
|
|
977
|
+
if (earlyCodeSkeletons.size > 0) {
|
|
978
|
+
const earlyUg = buildUnifiedGraph({
|
|
979
|
+
projectRoot: resolvedRoot,
|
|
980
|
+
codeSkeletons: earlyCodeSkeletons,
|
|
981
|
+
});
|
|
982
|
+
setCurrentUnifiedGraph(earlyUg);
|
|
983
|
+
const callEdges = earlyUg.edges.filter((e) => e.relation === 'calls').length;
|
|
984
|
+
logger.info(`[Feature 151+152] 早期 UnifiedGraph 构建:${earlyUg.nodes.length} 节点 / ${callEdges} calls 边 ` +
|
|
985
|
+
`(${pythonSkeletons.size} .py + ${tsJsSkeletons.size} .ts/.tsx/.js/.jsx 文件)`);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
catch (ugErr) {
|
|
989
|
+
setCurrentUnifiedGraph(null);
|
|
990
|
+
logger.warn(`[Feature 151+152] 早期 UnifiedGraph 构建失败(不阻塞): ${String(ugErr)}`);
|
|
991
|
+
}
|
|
827
992
|
try {
|
|
828
993
|
projectDocsResult = await generateBatchProjectDocs({
|
|
829
994
|
projectRoot: resolvedRoot,
|
|
@@ -913,11 +1078,22 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
913
1078
|
...pythonSymbolResults,
|
|
914
1079
|
...(extractionResults ?? []),
|
|
915
1080
|
];
|
|
1081
|
+
// Feature 151 — UnifiedGraph 接入 graph-builder 第五路(早期已在 generateBatchProjectDocs 之前构建,此处复用 cache)
|
|
1082
|
+
// 复用早期构建结果(Codex Final C-1 修订):cache 在 generateBatchProjectDocs 之前已 set
|
|
1083
|
+
const unifiedGraph = getCurrentUnifiedGraph();
|
|
1084
|
+
if (unifiedGraph) {
|
|
1085
|
+
const callEdgeCount = unifiedGraph.edges.filter((e) => e.relation === 'calls').length;
|
|
1086
|
+
const dependEdgeCount = unifiedGraph.edges.filter((e) => e.relation === 'depends-on').length;
|
|
1087
|
+
logger.info(`[Feature 151] graph-builder 注入 UnifiedGraph:${unifiedGraph.nodes.length} 节点,` +
|
|
1088
|
+
`${callEdgeCount} calls 边,${dependEdgeCount} depends-on 边`);
|
|
1089
|
+
}
|
|
916
1090
|
const graphJson = buildKnowledgeGraph({
|
|
917
1091
|
architectureIR: projectDocsResult?.architectureIR,
|
|
918
1092
|
docGraph,
|
|
919
1093
|
crossReferenceLinks,
|
|
920
1094
|
extractionResults: mergedResults.length > 0 ? mergedResults : undefined, // Feature 107 + 143 第四路数据源
|
|
1095
|
+
// Feature 151 T-012a:UnifiedGraph 第五路(calls + depends-on 边 + per-file callSitesCount metadata)
|
|
1096
|
+
...(unifiedGraph ? { unifiedGraph } : {}),
|
|
921
1097
|
});
|
|
922
1098
|
// Feature 133 P1-1(adversarial-review post-fix):anchor + hyperedge 集成
|
|
923
1099
|
// F4 提供了 runAnchorIntegration / runHyperedgeIntegration 集成函数,
|
|
@@ -1074,6 +1250,11 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
1074
1250
|
catch (communityErr) {
|
|
1075
1251
|
logger.warn(`community-analysis: 社区分析失败,跳过报告生成: ${communityErr instanceof Error ? communityErr.message : String(communityErr)}`);
|
|
1076
1252
|
}
|
|
1253
|
+
// F175 FR-006/FR-007:写盘前归一化(byte-stable)——nodes/links/hyperedges 确定性排序,
|
|
1254
|
+
// 在追加 semantic edges + 社区分析之后调用,覆盖完整边集。
|
|
1255
|
+
// F179:stripTimestamps:true 使 graph.generatedAt 固定为 epoch,落盘 graph.json 真 byte-stable
|
|
1256
|
+
// (此前 F175 仅在测试读取侧 delete generatedAt,是 over-claim;现在落盘侧直接固定)。
|
|
1257
|
+
normalizeGraphForWrite(graphJson, { stripTimestamps: true });
|
|
1077
1258
|
// 社区分析完成后写盘(graphJson 已含 degree metadata)
|
|
1078
1259
|
const graphWrittenPath = writeKnowledgeGraph(graphJson, resolvedOutputDir);
|
|
1079
1260
|
docGraphPath = toProjectPath(graphWrittenPath);
|
|
@@ -1333,6 +1514,7 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
1333
1514
|
docGraphPath,
|
|
1334
1515
|
coverageReportPath,
|
|
1335
1516
|
deltaReportPath,
|
|
1517
|
+
deltaReport,
|
|
1336
1518
|
projectDocs,
|
|
1337
1519
|
docsBundleManifestPath,
|
|
1338
1520
|
docsBundleProfiles,
|
|
@@ -1345,9 +1527,9 @@ export async function runBatch(projectRoot, options = {}) {
|
|
|
1345
1527
|
async function buildGraphForLanguageGroup(langGroup, projectRoot) {
|
|
1346
1528
|
const registry = LanguageAdapterRegistry.getInstance();
|
|
1347
1529
|
const adapter = registry.getAllAdapters().find((item) => item.id === langGroup.adapterId);
|
|
1348
|
-
if (adapter?.
|
|
1530
|
+
if (adapter?.buildModuleGraph) {
|
|
1349
1531
|
try {
|
|
1350
|
-
const langGraph = await adapter.
|
|
1532
|
+
const langGraph = await adapter.buildModuleGraph(projectRoot);
|
|
1351
1533
|
for (const node of langGraph.modules) {
|
|
1352
1534
|
node.language = langGroup.adapterId;
|
|
1353
1535
|
}
|
|
@@ -1549,4 +1731,335 @@ function collectMdRecursive(dir, out) {
|
|
|
1549
1731
|
}
|
|
1550
1732
|
}
|
|
1551
1733
|
}
|
|
1734
|
+
// ============================================================
|
|
1735
|
+
// Feature 151 — Python CodeSkeleton 收集(含 callSites 抽取)
|
|
1736
|
+
// ============================================================
|
|
1737
|
+
const PY_SKELETON_IGNORE_DIRS = new Set([
|
|
1738
|
+
'node_modules', '.git', '__pycache__', '.venv', 'venv',
|
|
1739
|
+
'build', 'dist', 'coverage', 'out', 'target', '.tox',
|
|
1740
|
+
]);
|
|
1741
|
+
/**
|
|
1742
|
+
* Feature 151 T-008c — 收集 .py 文件 CodeSkeleton(含 callSites + 本地 import 解析)。
|
|
1743
|
+
*
|
|
1744
|
+
* 与 PythonLanguageAdapter.extractSymbolNodes / buildModuleGraph 不同:
|
|
1745
|
+
* - 显式传 extractCallSites=true,让 graph.json 含 callSites 字段
|
|
1746
|
+
* - 在 PythonMapper 输出基础上补充 import 的 resolvedPath(基于项目内 .py 模块 basename map)
|
|
1747
|
+
* — Codex P1 C-1 修订:mapper 当前只输出 moduleSpecifier,resolvedPath 始终 null,
|
|
1748
|
+
* 导致 deriveImportEdges / call-resolver Stage 3 cross-module 全部失效
|
|
1749
|
+
*
|
|
1750
|
+
* 单文件解析失败 / 大文件 / 非 UTF-8 都按 EC-14 兜底(mapper 已处理),不影响整体 collection。
|
|
1751
|
+
*/
|
|
1752
|
+
export async function collectPythonCodeSkeletons(projectRoot) {
|
|
1753
|
+
const out = new Map();
|
|
1754
|
+
const { PythonLanguageAdapter } = await import('../adapters/python-adapter.js');
|
|
1755
|
+
const adapter = new PythonLanguageAdapter();
|
|
1756
|
+
// Codex P3+P4 复审 C-2 修复:projectRoot 显式 normalize 为绝对路径
|
|
1757
|
+
// 避免调用方传相对路径 → Map key 与 imports[].resolvedPath 形态不一致
|
|
1758
|
+
// → call-resolver buildImportIndex lookup miss
|
|
1759
|
+
const resolvedProjectRoot = path.resolve(projectRoot);
|
|
1760
|
+
// F194:构建 .gitignore 过滤器,基准 = resolvedProjectRoot(与 walk 内 path.relative 同口径)
|
|
1761
|
+
const isGitignored = createGitignoreFilter(resolvedProjectRoot);
|
|
1762
|
+
const pyFiles = [];
|
|
1763
|
+
walkPyFiles(resolvedProjectRoot, pyFiles, isGitignored, resolvedProjectRoot);
|
|
1764
|
+
// Feature 152 P3 T-017:大文件 size guard 提前到 parse 之前(避免 tree-sitter 解析阻塞)
|
|
1765
|
+
// 1MB 阈值与 PythonMapper.CALLSITES_MAX_FILE_BYTES 对齐(EC-14)
|
|
1766
|
+
const MAX_FILE_BYTES = 1_000_000;
|
|
1767
|
+
for (const filePath of pyFiles) {
|
|
1768
|
+
try {
|
|
1769
|
+
let stat;
|
|
1770
|
+
try {
|
|
1771
|
+
stat = fs.statSync(filePath);
|
|
1772
|
+
}
|
|
1773
|
+
catch {
|
|
1774
|
+
continue; // 文件读不到 stat → 跳过
|
|
1775
|
+
}
|
|
1776
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
1777
|
+
// 大文件 skip — 不调 analyzeFile(避免 tree-sitter parse 巨型文件)
|
|
1778
|
+
continue;
|
|
1779
|
+
}
|
|
1780
|
+
const skeleton = await adapter.analyzeFile(filePath, { extractCallSites: true });
|
|
1781
|
+
// Feature 152 P3 T-017:使用 resolvePythonImport 替换 basename map(plan §5.1)
|
|
1782
|
+
// C-1 修复:from . import X1, X2 形态(moduleSpecifier='.'/'..') 需对每个 namedImport 单独调用
|
|
1783
|
+
// EC-10 修复:resolvedPath 转为绝对路径,与 Map key 格式对齐
|
|
1784
|
+
const resolvedSkeleton = {
|
|
1785
|
+
...skeleton,
|
|
1786
|
+
imports: skeleton.imports.flatMap((imp) => {
|
|
1787
|
+
if (imp.resolvedPath)
|
|
1788
|
+
return [imp];
|
|
1789
|
+
const spec = imp.moduleSpecifier;
|
|
1790
|
+
// C-1:裸相对 import —— moduleSpecifier 仅为纯点('.' / '..' / '...' / 更深)
|
|
1791
|
+
// "from . import nn, Value" → imp.namedImports=['nn','Value'],逐个拆解
|
|
1792
|
+
// quality-review W-2 修复:扩展到任意点深度(PEP 328 不限层数),
|
|
1793
|
+
// 避免 'from ... import a, b' 时 a/b 都映射到同一 resolvedPath(namedImports 污染)
|
|
1794
|
+
if (/^\.+$/.test(spec)) {
|
|
1795
|
+
const namedImports = Array.isArray(imp.namedImports)
|
|
1796
|
+
? imp.namedImports
|
|
1797
|
+
: [];
|
|
1798
|
+
if (namedImports.length === 0) {
|
|
1799
|
+
// 没有 namedImports(罕见),仅尝试解析包 __init__
|
|
1800
|
+
const result = resolvePythonImport(spec, filePath, resolvedProjectRoot);
|
|
1801
|
+
const resolvedPath = result.resolvedPath
|
|
1802
|
+
? path.resolve(resolvedProjectRoot, result.resolvedPath)
|
|
1803
|
+
: null;
|
|
1804
|
+
return [{ ...imp, resolvedPath }];
|
|
1805
|
+
}
|
|
1806
|
+
// 每个 namedImport 单独解析为独立 import 记录
|
|
1807
|
+
// Codex P3+P4 复审 C-1 修复:每条拆出记录的 namedImports 必须**只**含
|
|
1808
|
+
// 当前拆出的 name,否则 buildImportIndex 会把所有 namedImports 都映射到
|
|
1809
|
+
// 同一 resolvedPath(最后一条胜出),导致 alias 污染
|
|
1810
|
+
return namedImports.map((name) => {
|
|
1811
|
+
const combinedSpec = `${spec}${name}`; // '.' + 'nn' → '.nn'
|
|
1812
|
+
const result = resolvePythonImport(combinedSpec, filePath, resolvedProjectRoot);
|
|
1813
|
+
const resolvedPath = result.resolvedPath
|
|
1814
|
+
? path.resolve(resolvedProjectRoot, result.resolvedPath)
|
|
1815
|
+
: null;
|
|
1816
|
+
return {
|
|
1817
|
+
...imp,
|
|
1818
|
+
moduleSpecifier: combinedSpec,
|
|
1819
|
+
namedImports: [name], // 关键:仅含本次拆出的 name,避免 alias 污染
|
|
1820
|
+
resolvedPath,
|
|
1821
|
+
};
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
// 常规形态:直接调用 resolver(from pkg.engine import Value / import os)
|
|
1825
|
+
const result = resolvePythonImport(spec, filePath, resolvedProjectRoot);
|
|
1826
|
+
// EC-10:resolver 返回相对 projectRoot 的 POSIX 路径,需转绝对路径与 Map key 对齐
|
|
1827
|
+
const resolvedPath = result.resolvedPath
|
|
1828
|
+
? path.resolve(resolvedProjectRoot, result.resolvedPath)
|
|
1829
|
+
: null;
|
|
1830
|
+
return [{ ...imp, resolvedPath }];
|
|
1831
|
+
}),
|
|
1832
|
+
};
|
|
1833
|
+
out.set(filePath, resolvedSkeleton);
|
|
1834
|
+
}
|
|
1835
|
+
catch {
|
|
1836
|
+
// 单文件失败不影响整体
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
return out;
|
|
1840
|
+
}
|
|
1841
|
+
/**
|
|
1842
|
+
* F194:isGitignored 与 resolvedRoot 由 collectPythonCodeSkeletons 构建并通过参数传入,
|
|
1843
|
+
* 在自写 walk 上叠加 .gitignore 过滤层(保留 PY_SKELETON_IGNORE_DIRS 与点前缀剪枝不变)。
|
|
1844
|
+
*/
|
|
1845
|
+
function walkPyFiles(dir, out, isGitignored, resolvedRoot) {
|
|
1846
|
+
let entries;
|
|
1847
|
+
try {
|
|
1848
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1849
|
+
}
|
|
1850
|
+
catch {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
for (const entry of entries) {
|
|
1854
|
+
// 基准 = resolvedRoot,path.relative 输出不做 sep 转换(与 file-scanner walkDir 一致)
|
|
1855
|
+
const relPath = path.relative(resolvedRoot, path.join(dir, entry.name));
|
|
1856
|
+
if (entry.isDirectory()) {
|
|
1857
|
+
if (entry.name.startsWith('.'))
|
|
1858
|
+
continue;
|
|
1859
|
+
if (PY_SKELETON_IGNORE_DIRS.has(entry.name))
|
|
1860
|
+
continue;
|
|
1861
|
+
if (isGitignored(relPath))
|
|
1862
|
+
continue; // 目录命中 .gitignore → 剪枝
|
|
1863
|
+
walkPyFiles(path.join(dir, entry.name), out, isGitignored, resolvedRoot);
|
|
1864
|
+
}
|
|
1865
|
+
else if (entry.isFile() && (entry.name.endsWith('.py') || entry.name.endsWith('.pyi'))) {
|
|
1866
|
+
if (isGitignored(relPath))
|
|
1867
|
+
continue; // 文件命中 .gitignore → 跳过
|
|
1868
|
+
out.push(path.join(dir, entry.name));
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
// ============================================================
|
|
1873
|
+
// Feature 152 — TypeScript/JavaScript CodeSkeleton 收集
|
|
1874
|
+
// ============================================================
|
|
1875
|
+
/** T-020:TS/JS 文件扫描时忽略的目录集合(与 Python 对齐,增加 .next / .nuxt 等前端产物目录) */
|
|
1876
|
+
const TSJS_SKELETON_IGNORE_DIRS = new Set([
|
|
1877
|
+
'node_modules', '.git', 'dist', 'build', 'coverage', 'out', 'target',
|
|
1878
|
+
'.next', '.nuxt', '.turbo', '.cache', 'tmp', '.tmp',
|
|
1879
|
+
'__pycache__', '.pytest_cache', '.tox',
|
|
1880
|
+
]);
|
|
1881
|
+
/**
|
|
1882
|
+
* Feature 152 T-020 — 收集 .ts/.tsx/.js/.jsx 文件 CodeSkeleton(含 callSites + import 路径解析)。
|
|
1883
|
+
*
|
|
1884
|
+
* 与 collectPythonCodeSkeletons 设计对齐:
|
|
1885
|
+
* - 可选 extractCallSites,走 TsJsLanguageAdapter 双路径 merge(Feature 152 T-013/T-014)
|
|
1886
|
+
* - 解析 imports[].resolvedPath:findNearestTsConfig + buildTsConfigContext + resolveTsJsImport
|
|
1887
|
+
* - EC-10:resolvedPath 转绝对路径与 Map key 格式对齐
|
|
1888
|
+
* - T-021a:tsconfig context 按 configDir 缓存,避免每文件重复读
|
|
1889
|
+
* - 单文件失败不阻塞整体(catch 吞掉,同 Python 版本 EC-14 兜底)
|
|
1890
|
+
*/
|
|
1891
|
+
export async function collectTsJsCodeSkeletons(projectRoot, options) {
|
|
1892
|
+
const out = new Map();
|
|
1893
|
+
const { TsJsLanguageAdapter } = await import('../adapters/ts-js-adapter.js');
|
|
1894
|
+
const adapter = new TsJsLanguageAdapter();
|
|
1895
|
+
// Codex P3+P4 复审 C-2 修复:projectRoot 显式 normalize 为绝对路径
|
|
1896
|
+
// 避免调用方传相对路径 → Map key 与 imports[].resolvedPath 形态不一致
|
|
1897
|
+
const resolvedProjectRoot = path.resolve(projectRoot);
|
|
1898
|
+
// F194:构建 .gitignore 过滤器,基准 = resolvedProjectRoot(与 walk 内 path.relative 同口径)
|
|
1899
|
+
const isGitignored = createGitignoreFilter(resolvedProjectRoot);
|
|
1900
|
+
const tsJsFiles = [];
|
|
1901
|
+
walkTsJsFiles(resolvedProjectRoot, tsJsFiles, isGitignored, resolvedProjectRoot);
|
|
1902
|
+
// T-021a:tsconfig context 缓存(by configDir),避免每个文件重复读
|
|
1903
|
+
const tsConfigCache = new Map();
|
|
1904
|
+
// 大文件 size guard 与 Python 版本对齐(EC-14:1MB 阈值)
|
|
1905
|
+
const MAX_FILE_BYTES = 1_000_000;
|
|
1906
|
+
for (const filePath of tsJsFiles) {
|
|
1907
|
+
try {
|
|
1908
|
+
let stat;
|
|
1909
|
+
try {
|
|
1910
|
+
stat = fs.statSync(filePath);
|
|
1911
|
+
}
|
|
1912
|
+
catch {
|
|
1913
|
+
continue; // 文件读不到 stat → 跳过
|
|
1914
|
+
}
|
|
1915
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
1916
|
+
continue; // 大文件 skip
|
|
1917
|
+
}
|
|
1918
|
+
// 主分析(含 callSites if options.extractCallSites)
|
|
1919
|
+
const skeleton = await adapter.analyzeFile(filePath, {
|
|
1920
|
+
extractCallSites: options?.extractCallSites,
|
|
1921
|
+
});
|
|
1922
|
+
// T-021a:查找最近的 tsconfig.json 并缓存 context(Feature 181:loader 收口为 configPath 单参)
|
|
1923
|
+
const configPath = findNearestTsConfig(filePath, resolvedProjectRoot);
|
|
1924
|
+
let tsConfigContext = null;
|
|
1925
|
+
if (configPath) {
|
|
1926
|
+
if (!tsConfigCache.has(configPath)) {
|
|
1927
|
+
tsConfigCache.set(configPath, buildTsConfigContext(configPath));
|
|
1928
|
+
}
|
|
1929
|
+
tsConfigContext = tsConfigCache.get(configPath) ?? null;
|
|
1930
|
+
}
|
|
1931
|
+
// 解析 imports[].resolvedPath(EC-10:转绝对路径)
|
|
1932
|
+
const resolvedSkeleton = {
|
|
1933
|
+
...skeleton,
|
|
1934
|
+
imports: skeleton.imports.map((imp) => {
|
|
1935
|
+
if (imp.resolvedPath)
|
|
1936
|
+
return imp;
|
|
1937
|
+
const result = resolveTsJsImport(imp.moduleSpecifier, filePath, resolvedProjectRoot, tsConfigContext);
|
|
1938
|
+
// EC-10:resolver 返回相对 projectRoot 的 POSIX 路径,需转绝对路径与 Map key 对齐
|
|
1939
|
+
const resolvedPath = result.resolvedPath
|
|
1940
|
+
? path.resolve(resolvedProjectRoot, result.resolvedPath)
|
|
1941
|
+
: null;
|
|
1942
|
+
return { ...imp, resolvedPath };
|
|
1943
|
+
}),
|
|
1944
|
+
};
|
|
1945
|
+
out.set(filePath, resolvedSkeleton);
|
|
1946
|
+
}
|
|
1947
|
+
catch {
|
|
1948
|
+
// 单文件失败不影响整体(与 collectPythonCodeSkeletons EC-14 一致)
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
return out;
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* 递归扫描 .ts/.tsx/.js/.jsx 文件(排除产物目录)。
|
|
1955
|
+
* 复用 walkPyFiles 的扫描模式,扩展 TS/JS 扩展名集合。
|
|
1956
|
+
*
|
|
1957
|
+
* F194:isGitignored 与 resolvedRoot 由 collectTsJsCodeSkeletons 构建并通过参数传入,
|
|
1958
|
+
* 在自写 walk 上叠加 .gitignore 过滤层(保留 TSJS_SKELETON_IGNORE_DIRS 与点前缀剪枝不变)。
|
|
1959
|
+
*/
|
|
1960
|
+
function walkTsJsFiles(dir, out, isGitignored, resolvedRoot) {
|
|
1961
|
+
let entries;
|
|
1962
|
+
try {
|
|
1963
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1964
|
+
}
|
|
1965
|
+
catch {
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
for (const entry of entries) {
|
|
1969
|
+
// 基准 = resolvedRoot,path.relative 输出不做 sep 转换(与 file-scanner walkDir 一致)
|
|
1970
|
+
const relPath = path.relative(resolvedRoot, path.join(dir, entry.name));
|
|
1971
|
+
if (entry.isDirectory()) {
|
|
1972
|
+
if (entry.name.startsWith('.'))
|
|
1973
|
+
continue;
|
|
1974
|
+
if (TSJS_SKELETON_IGNORE_DIRS.has(entry.name))
|
|
1975
|
+
continue;
|
|
1976
|
+
if (isGitignored(relPath))
|
|
1977
|
+
continue; // 目录命中 .gitignore → 剪枝
|
|
1978
|
+
walkTsJsFiles(path.join(dir, entry.name), out, isGitignored, resolvedRoot);
|
|
1979
|
+
}
|
|
1980
|
+
else if (entry.isFile()) {
|
|
1981
|
+
const name = entry.name;
|
|
1982
|
+
if (name.endsWith('.ts') ||
|
|
1983
|
+
name.endsWith('.tsx') ||
|
|
1984
|
+
name.endsWith('.js') ||
|
|
1985
|
+
name.endsWith('.jsx')) {
|
|
1986
|
+
if (isGitignored(relPath))
|
|
1987
|
+
continue; // 文件命中 .gitignore → 跳过
|
|
1988
|
+
out.push(path.join(dir, entry.name));
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
/**
|
|
1994
|
+
* Feature 195:全仓纯 AST、零 LLM 的 graph-only 建图。
|
|
1995
|
+
*
|
|
1996
|
+
* 与 runBatch 解耦的姊妹管线——只跑 AST 采集 → unifiedGraph(call graph + depends-on)
|
|
1997
|
+
* + Python 符号节点 → buildKnowledgeGraph → writeKnowledgeGraph,全程不调用任何
|
|
1998
|
+
* spec-gen / enrichment / hyperedge LLM,也不需要认证。
|
|
1999
|
+
*
|
|
2000
|
+
* why 复用 collectPython/collectTsJs 而非 scanFiles:batch 的 unifiedGraph(见 runBatch
|
|
2001
|
+
* 内早期 UnifiedGraph 构建段)正是用这两个采集器构建,复用它们使 graph-only 的 unifiedGraph
|
|
2002
|
+
* 与 batch 口径逐一对齐(扩展名集合 + ignore 规则一致)。不按 languages 过滤,与 batch
|
|
2003
|
+
* unifiedGraph 行为一致。
|
|
2004
|
+
*
|
|
2005
|
+
* why writeKnowledgeGraph 传 stripTimestamps:true:与 batch 写盘一致,剥除 generatedAt
|
|
2006
|
+
* 实时戳,保 byte-stable 与跨 worktree 一致(F193/NFR-002)。
|
|
2007
|
+
*/
|
|
2008
|
+
export async function buildAstGraphOnly(projectRoot, options) {
|
|
2009
|
+
const startTime = Date.now();
|
|
2010
|
+
const resolvedRoot = path.resolve(projectRoot);
|
|
2011
|
+
const outputDir = options?.outputDir ?? 'specs';
|
|
2012
|
+
const resolvedOutputDir = path.isAbsolute(outputDir)
|
|
2013
|
+
? outputDir
|
|
2014
|
+
: path.join(resolvedRoot, outputDir);
|
|
2015
|
+
logger.info('[Feature 195] graph-only 建图:纯 AST / 零 LLM');
|
|
2016
|
+
// 步骤 1:AST 采集(与 batch unifiedGraph 同款采集器,合并 Python + TS/JS)
|
|
2017
|
+
const pythonSkeletons = await collectPythonCodeSkeletons(resolvedRoot);
|
|
2018
|
+
const tsJsSkeletons = await collectTsJsCodeSkeletons(resolvedRoot, {
|
|
2019
|
+
extractCallSites: true,
|
|
2020
|
+
});
|
|
2021
|
+
const codeSkeletons = new Map([...pythonSkeletons, ...tsJsSkeletons]);
|
|
2022
|
+
if (codeSkeletons.size === 0) {
|
|
2023
|
+
// EC-001:无可解析源码 → 仍产出 schema 合法的空图,不崩溃
|
|
2024
|
+
logger.warn('[Feature 195] 未发现可建图的源码(将产出空图)');
|
|
2025
|
+
}
|
|
2026
|
+
// 步骤 2:UnifiedGraph(calls + depends-on,纯 AST)
|
|
2027
|
+
const unifiedGraph = codeSkeletons.size > 0
|
|
2028
|
+
? buildUnifiedGraph({ projectRoot: resolvedRoot, codeSkeletons })
|
|
2029
|
+
: undefined;
|
|
2030
|
+
// 步骤 3:Python 符号节点(纯 AST,extractionResults 第四路)
|
|
2031
|
+
// EC-003:extractSymbolNodes 内部已 best-effort(单文件失败仍产文件级节点),此处仅兜底捕获
|
|
2032
|
+
let pythonSymbolResults = [];
|
|
2033
|
+
try {
|
|
2034
|
+
const { PythonLanguageAdapter } = await import('../adapters/python-adapter.js');
|
|
2035
|
+
pythonSymbolResults = await new PythonLanguageAdapter().extractSymbolNodes(resolvedRoot);
|
|
2036
|
+
}
|
|
2037
|
+
catch (pyErr) {
|
|
2038
|
+
logger.warn(`[Feature 195] Python 符号提取失败,跳过: ${String(pyErr)}`);
|
|
2039
|
+
}
|
|
2040
|
+
const pythonSymbolCount = pythonSymbolResults.reduce((sum, r) => sum + r.nodes.filter((n) => n.kind === 'component').length, 0);
|
|
2041
|
+
// 步骤 4:合并构建 knowledge graph(不传 docGraph/architectureIR/crossReferenceLinks——
|
|
2042
|
+
// 那三路依赖 spec-gen 产物;EC-004:buildKnowledgeGraph 对缺席数据源 graceful skip)
|
|
2043
|
+
const graphJson = buildKnowledgeGraph({
|
|
2044
|
+
...(unifiedGraph ? { unifiedGraph } : {}),
|
|
2045
|
+
...(pythonSymbolResults.length > 0 ? { extractionResults: pythonSymbolResults } : {}),
|
|
2046
|
+
});
|
|
2047
|
+
// 步骤 5:复用 F183 写盘出口(内部 portable 守卫扫描 → normalizeGraphForWrite → 原子写)
|
|
2048
|
+
const graphPath = writeKnowledgeGraph(graphJson, resolvedOutputDir, {
|
|
2049
|
+
stripTimestamps: true,
|
|
2050
|
+
});
|
|
2051
|
+
const callEdgeCount = graphJson.links.filter((e) => e.relation === 'calls').length;
|
|
2052
|
+
const dependsOnEdgeCount = graphJson.links.filter((e) => e.relation === 'depends-on').length;
|
|
2053
|
+
logger.info(`[Feature 195] graph-only 完成:${graphJson.nodes.length} 节点 / ${graphJson.links.length} 边 ` +
|
|
2054
|
+
`(${callEdgeCount} calls, ${dependsOnEdgeCount} depends-on, ${pythonSymbolCount} Python 符号)`);
|
|
2055
|
+
return {
|
|
2056
|
+
graphPath,
|
|
2057
|
+
nodeCount: graphJson.nodes.length,
|
|
2058
|
+
edgeCount: graphJson.links.length,
|
|
2059
|
+
callEdgeCount,
|
|
2060
|
+
dependsOnEdgeCount,
|
|
2061
|
+
pythonSymbolCount,
|
|
2062
|
+
durationMs: Date.now() - startTime,
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
1552
2065
|
//# sourceMappingURL=batch-orchestrator.js.map
|