opencode-telos 1.0.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 +927 -0
- package/dist/code-intelligence/analyzer.d.ts +9 -0
- package/dist/code-intelligence/analyzer.d.ts.map +1 -0
- package/dist/code-intelligence/analyzer.js +321 -0
- package/dist/code-intelligence/analyzer.js.map +1 -0
- package/dist/code-intelligence/ast/cache.d.ts +16 -0
- package/dist/code-intelligence/ast/cache.d.ts.map +1 -0
- package/dist/code-intelligence/ast/cache.js +44 -0
- package/dist/code-intelligence/ast/cache.js.map +1 -0
- package/dist/code-intelligence/ast/common.d.ts +8 -0
- package/dist/code-intelligence/ast/common.d.ts.map +1 -0
- package/dist/code-intelligence/ast/common.js +42 -0
- package/dist/code-intelligence/ast/common.js.map +1 -0
- package/dist/code-intelligence/ast/component.d.ts +10 -0
- package/dist/code-intelligence/ast/component.d.ts.map +1 -0
- package/dist/code-intelligence/ast/component.js +38 -0
- package/dist/code-intelligence/ast/component.js.map +1 -0
- package/dist/code-intelligence/ast/fallback.d.ts +9 -0
- package/dist/code-intelligence/ast/fallback.d.ts.map +1 -0
- package/dist/code-intelligence/ast/fallback.js +38 -0
- package/dist/code-intelligence/ast/fallback.js.map +1 -0
- package/dist/code-intelligence/ast/index.d.ts +5 -0
- package/dist/code-intelligence/ast/index.d.ts.map +1 -0
- package/dist/code-intelligence/ast/index.js +5 -0
- package/dist/code-intelligence/ast/index.js.map +1 -0
- package/dist/code-intelligence/ast/ir.d.ts +72 -0
- package/dist/code-intelligence/ast/ir.d.ts.map +1 -0
- package/dist/code-intelligence/ast/ir.js +2 -0
- package/dist/code-intelligence/ast/ir.js.map +1 -0
- package/dist/code-intelligence/ast/metrics.d.ts +25 -0
- package/dist/code-intelligence/ast/metrics.d.ts.map +1 -0
- package/dist/code-intelligence/ast/metrics.js +38 -0
- package/dist/code-intelligence/ast/metrics.js.map +1 -0
- package/dist/code-intelligence/ast/registry.d.ts +5 -0
- package/dist/code-intelligence/ast/registry.d.ts.map +1 -0
- package/dist/code-intelligence/ast/registry.js +22 -0
- package/dist/code-intelligence/ast/registry.js.map +1 -0
- package/dist/code-intelligence/ast/tree-sitter.d.ts +8 -0
- package/dist/code-intelligence/ast/tree-sitter.d.ts.map +1 -0
- package/dist/code-intelligence/ast/tree-sitter.js +247 -0
- package/dist/code-intelligence/ast/tree-sitter.js.map +1 -0
- package/dist/code-intelligence/ast/typescript.d.ts +8 -0
- package/dist/code-intelligence/ast/typescript.d.ts.map +1 -0
- package/dist/code-intelligence/ast/typescript.js +147 -0
- package/dist/code-intelligence/ast/typescript.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +27 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +67 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/opencode/hooks.d.ts +9 -0
- package/dist/opencode/hooks.d.ts.map +1 -0
- package/dist/opencode/hooks.js +583 -0
- package/dist/opencode/hooks.js.map +1 -0
- package/dist/opencode/router/categories.d.ts +31 -0
- package/dist/opencode/router/categories.d.ts.map +1 -0
- package/dist/opencode/router/categories.js +165 -0
- package/dist/opencode/router/categories.js.map +1 -0
- package/dist/opencode/router/embeddings.d.ts +41 -0
- package/dist/opencode/router/embeddings.d.ts.map +1 -0
- package/dist/opencode/router/embeddings.js +136 -0
- package/dist/opencode/router/embeddings.js.map +1 -0
- package/dist/opencode/router/graph-state-snapshot.d.ts +35 -0
- package/dist/opencode/router/graph-state-snapshot.d.ts.map +1 -0
- package/dist/opencode/router/graph-state-snapshot.js +129 -0
- package/dist/opencode/router/graph-state-snapshot.js.map +1 -0
- package/dist/opencode/router/index.d.ts +21 -0
- package/dist/opencode/router/index.d.ts.map +1 -0
- package/dist/opencode/router/index.js +23 -0
- package/dist/opencode/router/index.js.map +1 -0
- package/dist/opencode/router/intent-classifier.d.ts +35 -0
- package/dist/opencode/router/intent-classifier.d.ts.map +1 -0
- package/dist/opencode/router/intent-classifier.js +108 -0
- package/dist/opencode/router/intent-classifier.js.map +1 -0
- package/dist/opencode/router/semantic-nudge.d.ts +42 -0
- package/dist/opencode/router/semantic-nudge.d.ts.map +1 -0
- package/dist/opencode/router/semantic-nudge.js +73 -0
- package/dist/opencode/router/semantic-nudge.js.map +1 -0
- package/dist/opencode/router/state-gate.d.ts +25 -0
- package/dist/opencode/router/state-gate.d.ts.map +1 -0
- package/dist/opencode/router/state-gate.js +178 -0
- package/dist/opencode/router/state-gate.js.map +1 -0
- package/dist/opencode/router/tool-embeddings.d.ts +36 -0
- package/dist/opencode/router/tool-embeddings.d.ts.map +1 -0
- package/dist/opencode/router/tool-embeddings.js +140 -0
- package/dist/opencode/router/tool-embeddings.js.map +1 -0
- package/dist/opencode/router/tool-registry.d.ts +45 -0
- package/dist/opencode/router/tool-registry.d.ts.map +1 -0
- package/dist/opencode/router/tool-registry.js +103 -0
- package/dist/opencode/router/tool-registry.js.map +1 -0
- package/dist/opencode/router/tool-taxonomy.d.ts +51 -0
- package/dist/opencode/router/tool-taxonomy.d.ts.map +1 -0
- package/dist/opencode/router/tool-taxonomy.js +250 -0
- package/dist/opencode/router/tool-taxonomy.js.map +1 -0
- package/dist/opencode/router/tools-composite.d.ts +21 -0
- package/dist/opencode/router/tools-composite.d.ts.map +1 -0
- package/dist/opencode/router/tools-composite.js +684 -0
- package/dist/opencode/router/tools-composite.js.map +1 -0
- package/dist/opencode/shell-hooks.d.ts +7 -0
- package/dist/opencode/shell-hooks.d.ts.map +1 -0
- package/dist/opencode/shell-hooks.js +96 -0
- package/dist/opencode/shell-hooks.js.map +1 -0
- package/dist/opencode/system-prompt.d.ts +10 -0
- package/dist/opencode/system-prompt.d.ts.map +1 -0
- package/dist/opencode/system-prompt.js +600 -0
- package/dist/opencode/system-prompt.js.map +1 -0
- package/dist/opencode/tools.d.ts +8 -0
- package/dist/opencode/tools.d.ts.map +1 -0
- package/dist/opencode/tools.js +3731 -0
- package/dist/opencode/tools.js.map +1 -0
- package/dist/opencode/workflows/chains.d.ts +52 -0
- package/dist/opencode/workflows/chains.d.ts.map +1 -0
- package/dist/opencode/workflows/chains.js +170 -0
- package/dist/opencode/workflows/chains.js.map +1 -0
- package/dist/opencode/workflows/executor.d.ts +52 -0
- package/dist/opencode/workflows/executor.d.ts.map +1 -0
- package/dist/opencode/workflows/executor.js +130 -0
- package/dist/opencode/workflows/executor.js.map +1 -0
- package/dist/opencode/workflows/index.d.ts +14 -0
- package/dist/opencode/workflows/index.d.ts.map +1 -0
- package/dist/opencode/workflows/index.js +15 -0
- package/dist/opencode/workflows/index.js.map +1 -0
- package/dist/opencode/workflows/tools-workflow.d.ts +24 -0
- package/dist/opencode/workflows/tools-workflow.d.ts.map +1 -0
- package/dist/opencode/workflows/tools-workflow.js +85 -0
- package/dist/opencode/workflows/tools-workflow.js.map +1 -0
- package/dist/opencode/workflows/types.d.ts +32 -0
- package/dist/opencode/workflows/types.d.ts.map +1 -0
- package/dist/opencode/workflows/types.js +13 -0
- package/dist/opencode/workflows/types.js.map +1 -0
- package/dist/sdd/analysis/compliance.d.ts +30 -0
- package/dist/sdd/analysis/compliance.d.ts.map +1 -0
- package/dist/sdd/analysis/compliance.js +251 -0
- package/dist/sdd/analysis/compliance.js.map +1 -0
- package/dist/sdd/analysis/scalability.d.ts +15 -0
- package/dist/sdd/analysis/scalability.d.ts.map +1 -0
- package/dist/sdd/analysis/scalability.js +72 -0
- package/dist/sdd/analysis/scalability.js.map +1 -0
- package/dist/sdd/analysis/security.d.ts +25 -0
- package/dist/sdd/analysis/security.d.ts.map +1 -0
- package/dist/sdd/analysis/security.js +94 -0
- package/dist/sdd/analysis/security.js.map +1 -0
- package/dist/sdd/brownfield/scanner.d.ts +31 -0
- package/dist/sdd/brownfield/scanner.d.ts.map +1 -0
- package/dist/sdd/brownfield/scanner.js +228 -0
- package/dist/sdd/brownfield/scanner.js.map +1 -0
- package/dist/sdd/cache/manager.d.ts +237 -0
- package/dist/sdd/cache/manager.d.ts.map +1 -0
- package/dist/sdd/cache/manager.js +770 -0
- package/dist/sdd/cache/manager.js.map +1 -0
- package/dist/sdd/cache/snapshot-store.d.ts +39 -0
- package/dist/sdd/cache/snapshot-store.d.ts.map +1 -0
- package/dist/sdd/cache/snapshot-store.js +156 -0
- package/dist/sdd/cache/snapshot-store.js.map +1 -0
- package/dist/sdd/changes/manager.d.ts +58 -0
- package/dist/sdd/changes/manager.d.ts.map +1 -0
- package/dist/sdd/changes/manager.js +235 -0
- package/dist/sdd/changes/manager.js.map +1 -0
- package/dist/sdd/cicd/generators.d.ts +16 -0
- package/dist/sdd/cicd/generators.d.ts.map +1 -0
- package/dist/sdd/cicd/generators.js +1042 -0
- package/dist/sdd/cicd/generators.js.map +1 -0
- package/dist/sdd/code-quality/complexity.d.ts +38 -0
- package/dist/sdd/code-quality/complexity.d.ts.map +1 -0
- package/dist/sdd/code-quality/complexity.js +161 -0
- package/dist/sdd/code-quality/complexity.js.map +1 -0
- package/dist/sdd/code-quality/conventions.d.ts +33 -0
- package/dist/sdd/code-quality/conventions.d.ts.map +1 -0
- package/dist/sdd/code-quality/conventions.js +193 -0
- package/dist/sdd/code-quality/conventions.js.map +1 -0
- package/dist/sdd/code-quality/dependencies.d.ts +27 -0
- package/dist/sdd/code-quality/dependencies.d.ts.map +1 -0
- package/dist/sdd/code-quality/dependencies.js +142 -0
- package/dist/sdd/code-quality/dependencies.js.map +1 -0
- package/dist/sdd/code-quality/import-analyzer.d.ts +49 -0
- package/dist/sdd/code-quality/import-analyzer.d.ts.map +1 -0
- package/dist/sdd/code-quality/import-analyzer.js +213 -0
- package/dist/sdd/code-quality/import-analyzer.js.map +1 -0
- package/dist/sdd/code-quality/metrics.d.ts +35 -0
- package/dist/sdd/code-quality/metrics.d.ts.map +1 -0
- package/dist/sdd/code-quality/metrics.js +172 -0
- package/dist/sdd/code-quality/metrics.js.map +1 -0
- package/dist/sdd/code-quality/smells.d.ts +38 -0
- package/dist/sdd/code-quality/smells.d.ts.map +1 -0
- package/dist/sdd/code-quality/smells.js +319 -0
- package/dist/sdd/code-quality/smells.js.map +1 -0
- package/dist/sdd/code-quality/symbol-parser.d.ts +28 -0
- package/dist/sdd/code-quality/symbol-parser.d.ts.map +1 -0
- package/dist/sdd/code-quality/symbol-parser.js +230 -0
- package/dist/sdd/code-quality/symbol-parser.js.map +1 -0
- package/dist/sdd/code-quality/usage-tracker.d.ts +59 -0
- package/dist/sdd/code-quality/usage-tracker.d.ts.map +1 -0
- package/dist/sdd/code-quality/usage-tracker.js +402 -0
- package/dist/sdd/code-quality/usage-tracker.js.map +1 -0
- package/dist/sdd/code-quality/utils.d.ts +6 -0
- package/dist/sdd/code-quality/utils.d.ts.map +1 -0
- package/dist/sdd/code-quality/utils.js +14 -0
- package/dist/sdd/code-quality/utils.js.map +1 -0
- package/dist/sdd/codegen/generator.d.ts +42 -0
- package/dist/sdd/codegen/generator.d.ts.map +1 -0
- package/dist/sdd/codegen/generator.js +1023 -0
- package/dist/sdd/codegen/generator.js.map +1 -0
- package/dist/sdd/constitution/validator.d.ts +37 -0
- package/dist/sdd/constitution/validator.d.ts.map +1 -0
- package/dist/sdd/constitution/validator.js +192 -0
- package/dist/sdd/constitution/validator.js.map +1 -0
- package/dist/sdd/cost/estimator.d.ts +31 -0
- package/dist/sdd/cost/estimator.d.ts.map +1 -0
- package/dist/sdd/cost/estimator.js +92 -0
- package/dist/sdd/cost/estimator.js.map +1 -0
- package/dist/sdd/coverage/tracker.d.ts +47 -0
- package/dist/sdd/coverage/tracker.d.ts.map +1 -0
- package/dist/sdd/coverage/tracker.js +251 -0
- package/dist/sdd/coverage/tracker.js.map +1 -0
- package/dist/sdd/disaster/recovery.d.ts +11 -0
- package/dist/sdd/disaster/recovery.d.ts.map +1 -0
- package/dist/sdd/disaster/recovery.js +55 -0
- package/dist/sdd/disaster/recovery.js.map +1 -0
- package/dist/sdd/discovery/adaptive.d.ts +14 -0
- package/dist/sdd/discovery/adaptive.d.ts.map +1 -0
- package/dist/sdd/discovery/adaptive.js +145 -0
- package/dist/sdd/discovery/adaptive.js.map +1 -0
- package/dist/sdd/discovery/briefing-analyzer.d.ts +66 -0
- package/dist/sdd/discovery/briefing-analyzer.d.ts.map +1 -0
- package/dist/sdd/discovery/briefing-analyzer.js +672 -0
- package/dist/sdd/discovery/briefing-analyzer.js.map +1 -0
- package/dist/sdd/discovery/briefing.d.ts +109 -0
- package/dist/sdd/discovery/briefing.d.ts.map +1 -0
- package/dist/sdd/discovery/briefing.js +617 -0
- package/dist/sdd/discovery/briefing.js.map +1 -0
- package/dist/sdd/discovery/graph-builder.d.ts +10 -0
- package/dist/sdd/discovery/graph-builder.d.ts.map +1 -0
- package/dist/sdd/discovery/graph-builder.js +510 -0
- package/dist/sdd/discovery/graph-builder.js.map +1 -0
- package/dist/sdd/documentation/generator.d.ts +7 -0
- package/dist/sdd/documentation/generator.d.ts.map +1 -0
- package/dist/sdd/documentation/generator.js +119 -0
- package/dist/sdd/documentation/generator.js.map +1 -0
- package/dist/sdd/domain/types.d.ts +460 -0
- package/dist/sdd/domain/types.d.ts.map +1 -0
- package/dist/sdd/domain/types.js +25 -0
- package/dist/sdd/domain/types.js.map +1 -0
- package/dist/sdd/drift/detector.d.ts +28 -0
- package/dist/sdd/drift/detector.d.ts.map +1 -0
- package/dist/sdd/drift/detector.js +379 -0
- package/dist/sdd/drift/detector.js.map +1 -0
- package/dist/sdd/drift/exclusion.d.ts +54 -0
- package/dist/sdd/drift/exclusion.d.ts.map +1 -0
- package/dist/sdd/drift/exclusion.js +179 -0
- package/dist/sdd/drift/exclusion.js.map +1 -0
- package/dist/sdd/drift/signals.d.ts +52 -0
- package/dist/sdd/drift/signals.d.ts.map +1 -0
- package/dist/sdd/drift/signals.js +470 -0
- package/dist/sdd/drift/signals.js.map +1 -0
- package/dist/sdd/enforcement/interceptor.d.ts +47 -0
- package/dist/sdd/enforcement/interceptor.d.ts.map +1 -0
- package/dist/sdd/enforcement/interceptor.js +365 -0
- package/dist/sdd/enforcement/interceptor.js.map +1 -0
- package/dist/sdd/enforcement/workflow-tracker.d.ts +66 -0
- package/dist/sdd/enforcement/workflow-tracker.d.ts.map +1 -0
- package/dist/sdd/enforcement/workflow-tracker.js +229 -0
- package/dist/sdd/enforcement/workflow-tracker.js.map +1 -0
- package/dist/sdd/graph/engine.d.ts +44 -0
- package/dist/sdd/graph/engine.d.ts.map +1 -0
- package/dist/sdd/graph/engine.js +203 -0
- package/dist/sdd/graph/engine.js.map +1 -0
- package/dist/sdd/graph/index.d.ts +160 -0
- package/dist/sdd/graph/index.d.ts.map +1 -0
- package/dist/sdd/graph/index.js +624 -0
- package/dist/sdd/graph/index.js.map +1 -0
- package/dist/sdd/graph/integrity-guard.d.ts +129 -0
- package/dist/sdd/graph/integrity-guard.d.ts.map +1 -0
- package/dist/sdd/graph/integrity-guard.js +263 -0
- package/dist/sdd/graph/integrity-guard.js.map +1 -0
- package/dist/sdd/graph/integrity.d.ts +79 -0
- package/dist/sdd/graph/integrity.d.ts.map +1 -0
- package/dist/sdd/graph/integrity.js +462 -0
- package/dist/sdd/graph/integrity.js.map +1 -0
- package/dist/sdd/graph/pruner.d.ts +27 -0
- package/dist/sdd/graph/pruner.d.ts.map +1 -0
- package/dist/sdd/graph/pruner.js +203 -0
- package/dist/sdd/graph/pruner.js.map +1 -0
- package/dist/sdd/graph/traverse.d.ts +43 -0
- package/dist/sdd/graph/traverse.d.ts.map +1 -0
- package/dist/sdd/graph/traverse.js +265 -0
- package/dist/sdd/graph/traverse.js.map +1 -0
- package/dist/sdd/incidents/manager.d.ts +10 -0
- package/dist/sdd/incidents/manager.d.ts.map +1 -0
- package/dist/sdd/incidents/manager.js +63 -0
- package/dist/sdd/incidents/manager.js.map +1 -0
- package/dist/sdd/knowledge/transfer.d.ts +24 -0
- package/dist/sdd/knowledge/transfer.d.ts.map +1 -0
- package/dist/sdd/knowledge/transfer.js +94 -0
- package/dist/sdd/knowledge/transfer.js.map +1 -0
- package/dist/sdd/migrations/fixes.d.ts +2 -0
- package/dist/sdd/migrations/fixes.d.ts.map +1 -0
- package/dist/sdd/migrations/fixes.js +159 -0
- package/dist/sdd/migrations/fixes.js.map +1 -0
- package/dist/sdd/migrations/index.d.ts +2 -0
- package/dist/sdd/migrations/index.d.ts.map +1 -0
- package/dist/sdd/migrations/index.js +5 -0
- package/dist/sdd/migrations/index.js.map +1 -0
- package/dist/sdd/migrations/migration-runner.d.ts +41 -0
- package/dist/sdd/migrations/migration-runner.d.ts.map +1 -0
- package/dist/sdd/migrations/migration-runner.js +91 -0
- package/dist/sdd/migrations/migration-runner.js.map +1 -0
- package/dist/sdd/monitoring/setup.d.ts +40 -0
- package/dist/sdd/monitoring/setup.d.ts.map +1 -0
- package/dist/sdd/monitoring/setup.js +177 -0
- package/dist/sdd/monitoring/setup.js.map +1 -0
- package/dist/sdd/monitoring/telemetry.d.ts +18 -0
- package/dist/sdd/monitoring/telemetry.d.ts.map +1 -0
- package/dist/sdd/monitoring/telemetry.js +37 -0
- package/dist/sdd/monitoring/telemetry.js.map +1 -0
- package/dist/sdd/patterns/anti-patterns.d.ts +21 -0
- package/dist/sdd/patterns/anti-patterns.d.ts.map +1 -0
- package/dist/sdd/patterns/anti-patterns.js +286 -0
- package/dist/sdd/patterns/anti-patterns.js.map +1 -0
- package/dist/sdd/patterns/ast-clones.d.ts +23 -0
- package/dist/sdd/patterns/ast-clones.d.ts.map +1 -0
- package/dist/sdd/patterns/ast-clones.js +171 -0
- package/dist/sdd/patterns/ast-clones.js.map +1 -0
- package/dist/sdd/patterns/config-drift.d.ts +16 -0
- package/dist/sdd/patterns/config-drift.d.ts.map +1 -0
- package/dist/sdd/patterns/config-drift.js +322 -0
- package/dist/sdd/patterns/config-drift.js.map +1 -0
- package/dist/sdd/patterns/contradictions.d.ts +38 -0
- package/dist/sdd/patterns/contradictions.d.ts.map +1 -0
- package/dist/sdd/patterns/contradictions.js +237 -0
- package/dist/sdd/patterns/contradictions.js.map +1 -0
- package/dist/sdd/patterns/learner.d.ts +49 -0
- package/dist/sdd/patterns/learner.d.ts.map +1 -0
- package/dist/sdd/patterns/learner.js +226 -0
- package/dist/sdd/patterns/learner.js.map +1 -0
- package/dist/sdd/permissions/access.d.ts +69 -0
- package/dist/sdd/permissions/access.d.ts.map +1 -0
- package/dist/sdd/permissions/access.js +333 -0
- package/dist/sdd/permissions/access.js.map +1 -0
- package/dist/sdd/persistence/repository.d.ts +60 -0
- package/dist/sdd/persistence/repository.d.ts.map +1 -0
- package/dist/sdd/persistence/repository.js +96 -0
- package/dist/sdd/persistence/repository.js.map +1 -0
- package/dist/sdd/persistence/sqlite.d.ts +122 -0
- package/dist/sdd/persistence/sqlite.d.ts.map +1 -0
- package/dist/sdd/persistence/sqlite.js +602 -0
- package/dist/sdd/persistence/sqlite.js.map +1 -0
- package/dist/sdd/persistence/yaml.d.ts +41 -0
- package/dist/sdd/persistence/yaml.d.ts.map +1 -0
- package/dist/sdd/persistence/yaml.js +382 -0
- package/dist/sdd/persistence/yaml.js.map +1 -0
- package/dist/sdd/promises/classifier.d.ts +48 -0
- package/dist/sdd/promises/classifier.d.ts.map +1 -0
- package/dist/sdd/promises/classifier.js +215 -0
- package/dist/sdd/promises/classifier.js.map +1 -0
- package/dist/sdd/promises/tracker.d.ts +20 -0
- package/dist/sdd/promises/tracker.d.ts.map +1 -0
- package/dist/sdd/promises/tracker.js +204 -0
- package/dist/sdd/promises/tracker.js.map +1 -0
- package/dist/sdd/quality/scorer.d.ts +44 -0
- package/dist/sdd/quality/scorer.d.ts.map +1 -0
- package/dist/sdd/quality/scorer.js +216 -0
- package/dist/sdd/quality/scorer.js.map +1 -0
- package/dist/sdd/rollback/manager.d.ts +45 -0
- package/dist/sdd/rollback/manager.d.ts.map +1 -0
- package/dist/sdd/rollback/manager.js +266 -0
- package/dist/sdd/rollback/manager.js.map +1 -0
- package/dist/sdd/session/handoff.d.ts +52 -0
- package/dist/sdd/session/handoff.d.ts.map +1 -0
- package/dist/sdd/session/handoff.js +264 -0
- package/dist/sdd/session/handoff.js.map +1 -0
- package/dist/sdd/sla/tracker.d.ts +11 -0
- package/dist/sdd/sla/tracker.d.ts.map +1 -0
- package/dist/sdd/sla/tracker.js +52 -0
- package/dist/sdd/sla/tracker.js.map +1 -0
- package/dist/sdd/sync/git-sync.d.ts +61 -0
- package/dist/sdd/sync/git-sync.d.ts.map +1 -0
- package/dist/sdd/sync/git-sync.js +297 -0
- package/dist/sdd/sync/git-sync.js.map +1 -0
- package/dist/sdd/toggle/state.d.ts +8 -0
- package/dist/sdd/toggle/state.d.ts.map +1 -0
- package/dist/sdd/toggle/state.js +32 -0
- package/dist/sdd/toggle/state.js.map +1 -0
- package/dist/sdd/transactions/manager.d.ts +12 -0
- package/dist/sdd/transactions/manager.d.ts.map +1 -0
- package/dist/sdd/transactions/manager.js +80 -0
- package/dist/sdd/transactions/manager.js.map +1 -0
- package/dist/sdd/validation/coverage-index.d.ts +117 -0
- package/dist/sdd/validation/coverage-index.d.ts.map +1 -0
- package/dist/sdd/validation/coverage-index.js +251 -0
- package/dist/sdd/validation/coverage-index.js.map +1 -0
- package/dist/sdd/validation/executable.d.ts +26 -0
- package/dist/sdd/validation/executable.d.ts.map +1 -0
- package/dist/sdd/validation/executable.js +122 -0
- package/dist/sdd/validation/executable.js.map +1 -0
- package/dist/sdd/validation/smart-validator.d.ts +53 -0
- package/dist/sdd/validation/smart-validator.d.ts.map +1 -0
- package/dist/sdd/validation/smart-validator.js +347 -0
- package/dist/sdd/validation/smart-validator.js.map +1 -0
- package/dist/sdd/validation/validator.d.ts +39 -0
- package/dist/sdd/validation/validator.d.ts.map +1 -0
- package/dist/sdd/validation/validator.js +512 -0
- package/dist/sdd/validation/validator.js.map +1 -0
- package/dist/sdd/workflow/exporter.d.ts +36 -0
- package/dist/sdd/workflow/exporter.d.ts.map +1 -0
- package/dist/sdd/workflow/exporter.js +112 -0
- package/dist/sdd/workflow/exporter.js.map +1 -0
- package/dist/sdd/workflows/ab-testing.d.ts +18 -0
- package/dist/sdd/workflows/ab-testing.d.ts.map +1 -0
- package/dist/sdd/workflows/ab-testing.js +67 -0
- package/dist/sdd/workflows/ab-testing.js.map +1 -0
- package/dist/sdd/workflows/bug-fix.d.ts +13 -0
- package/dist/sdd/workflows/bug-fix.d.ts.map +1 -0
- package/dist/sdd/workflows/bug-fix.js +65 -0
- package/dist/sdd/workflows/bug-fix.js.map +1 -0
- package/dist/sdd/workflows/data-migration.d.ts +14 -0
- package/dist/sdd/workflows/data-migration.d.ts.map +1 -0
- package/dist/sdd/workflows/data-migration.js +68 -0
- package/dist/sdd/workflows/data-migration.js.map +1 -0
- package/dist/sdd/workflows/deprecation.d.ts +15 -0
- package/dist/sdd/workflows/deprecation.d.ts.map +1 -0
- package/dist/sdd/workflows/deprecation.js +68 -0
- package/dist/sdd/workflows/deprecation.js.map +1 -0
- package/dist/sdd/workflows/feature-flags.d.ts +14 -0
- package/dist/sdd/workflows/feature-flags.d.ts.map +1 -0
- package/dist/sdd/workflows/feature-flags.js +73 -0
- package/dist/sdd/workflows/feature-flags.js.map +1 -0
- package/dist/sdd/workflows/hotfix.d.ts +13 -0
- package/dist/sdd/workflows/hotfix.d.ts.map +1 -0
- package/dist/sdd/workflows/hotfix.js +67 -0
- package/dist/sdd/workflows/hotfix.js.map +1 -0
- package/dist/sdd/workflows/multi-tenancy.d.ts +13 -0
- package/dist/sdd/workflows/multi-tenancy.d.ts.map +1 -0
- package/dist/sdd/workflows/multi-tenancy.js +68 -0
- package/dist/sdd/workflows/multi-tenancy.js.map +1 -0
- package/dist/sdd/workflows/onboarding.d.ts +7 -0
- package/dist/sdd/workflows/onboarding.d.ts.map +1 -0
- package/dist/sdd/workflows/onboarding.js +43 -0
- package/dist/sdd/workflows/onboarding.js.map +1 -0
- package/dist/sdd/workflows/refactoring.d.ts +14 -0
- package/dist/sdd/workflows/refactoring.d.ts.map +1 -0
- package/dist/sdd/workflows/refactoring.js +73 -0
- package/dist/sdd/workflows/refactoring.js.map +1 -0
- package/dist/server/events.d.ts +64 -0
- package/dist/server/events.d.ts.map +1 -0
- package/dist/server/events.js +149 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/server.d.ts +33 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +1019 -0
- package/dist/server/server.js.map +1 -0
- package/marketplace.json +39 -0
- package/package.json +65 -0
- package/src/code-intelligence/analyzer.ts +350 -0
- package/src/code-intelligence/ast/cache.ts +61 -0
- package/src/code-intelligence/ast/common.ts +62 -0
- package/src/code-intelligence/ast/component.ts +39 -0
- package/src/code-intelligence/ast/fallback.ts +44 -0
- package/src/code-intelligence/ast/index.ts +4 -0
- package/src/code-intelligence/ast/ir.ts +91 -0
- package/src/code-intelligence/ast/metrics.ts +65 -0
- package/src/code-intelligence/ast/registry.ts +28 -0
- package/src/code-intelligence/ast/tree-sitter.ts +226 -0
- package/src/code-intelligence/ast/typescript.ts +140 -0
- package/src/index.ts +22 -0
- package/src/mcp/server.ts +77 -0
- package/src/opencode/hooks.ts +728 -0
- package/src/opencode/router/categories.ts +192 -0
- package/src/opencode/router/embeddings.ts +149 -0
- package/src/opencode/router/graph-state-snapshot.ts +163 -0
- package/src/opencode/router/index.ts +44 -0
- package/src/opencode/router/intent-classifier.ts +140 -0
- package/src/opencode/router/semantic-nudge.ts +89 -0
- package/src/opencode/router/state-gate.ts +192 -0
- package/src/opencode/router/tool-embeddings.ts +162 -0
- package/src/opencode/router/tool-registry.ts +135 -0
- package/src/opencode/router/tool-taxonomy.ts +284 -0
- package/src/opencode/router/tools-composite.ts +685 -0
- package/src/opencode/shell-hooks.ts +115 -0
- package/src/opencode/system-prompt.ts +617 -0
- package/src/opencode/tools.ts +4102 -0
- package/src/opencode/workflows/chains.ts +205 -0
- package/src/opencode/workflows/executor.ts +172 -0
- package/src/opencode/workflows/index.ts +21 -0
- package/src/opencode/workflows/tools-workflow.ts +91 -0
- package/src/opencode/workflows/types.ts +42 -0
- package/src/sdd/analysis/compliance.ts +279 -0
- package/src/sdd/analysis/scalability.ts +97 -0
- package/src/sdd/analysis/security.ts +135 -0
- package/src/sdd/brownfield/scanner.ts +276 -0
- package/src/sdd/cache/manager.ts +899 -0
- package/src/sdd/cache/snapshot-store.ts +185 -0
- package/src/sdd/changes/manager.ts +326 -0
- package/src/sdd/cicd/generators.ts +1095 -0
- package/src/sdd/code-quality/complexity.ts +235 -0
- package/src/sdd/code-quality/conventions.ts +220 -0
- package/src/sdd/code-quality/dependencies.ts +203 -0
- package/src/sdd/code-quality/import-analyzer.ts +294 -0
- package/src/sdd/code-quality/metrics.ts +232 -0
- package/src/sdd/code-quality/smells.ts +415 -0
- package/src/sdd/code-quality/symbol-parser.ts +335 -0
- package/src/sdd/code-quality/usage-tracker.ts +527 -0
- package/src/sdd/code-quality/utils.ts +13 -0
- package/src/sdd/codegen/generator.ts +1181 -0
- package/src/sdd/constitution/validator.ts +253 -0
- package/src/sdd/cost/estimator.ts +147 -0
- package/src/sdd/coverage/tracker.ts +342 -0
- package/src/sdd/disaster/recovery.ts +79 -0
- package/src/sdd/discovery/adaptive.ts +167 -0
- package/src/sdd/discovery/briefing-analyzer.ts +802 -0
- package/src/sdd/discovery/briefing.ts +770 -0
- package/src/sdd/discovery/graph-builder.ts +598 -0
- package/src/sdd/documentation/generator.ts +158 -0
- package/src/sdd/domain/types.ts +658 -0
- package/src/sdd/drift/detector.ts +465 -0
- package/src/sdd/drift/exclusion.ts +223 -0
- package/src/sdd/drift/signals.ts +577 -0
- package/src/sdd/enforcement/interceptor.ts +444 -0
- package/src/sdd/enforcement/workflow-tracker.ts +263 -0
- package/src/sdd/graph/engine.ts +277 -0
- package/src/sdd/graph/index.ts +700 -0
- package/src/sdd/graph/integrity-guard.ts +348 -0
- package/src/sdd/graph/integrity.ts +628 -0
- package/src/sdd/graph/pruner.ts +221 -0
- package/src/sdd/graph/traverse.ts +331 -0
- package/src/sdd/incidents/manager.ts +87 -0
- package/src/sdd/knowledge/transfer.ts +140 -0
- package/src/sdd/migrations/fixes.ts +154 -0
- package/src/sdd/migrations/index.ts +14 -0
- package/src/sdd/migrations/migration-runner.ts +118 -0
- package/src/sdd/monitoring/setup.ts +237 -0
- package/src/sdd/monitoring/telemetry.ts +44 -0
- package/src/sdd/patterns/anti-patterns.ts +333 -0
- package/src/sdd/patterns/ast-clones.ts +214 -0
- package/src/sdd/patterns/config-drift.ts +346 -0
- package/src/sdd/patterns/contradictions.ts +323 -0
- package/src/sdd/patterns/learner.ts +266 -0
- package/src/sdd/permissions/access.ts +478 -0
- package/src/sdd/persistence/repository.ts +166 -0
- package/src/sdd/persistence/sqlite.ts +703 -0
- package/src/sdd/persistence/yaml.ts +409 -0
- package/src/sdd/promises/classifier.ts +253 -0
- package/src/sdd/promises/tracker.ts +258 -0
- package/src/sdd/quality/scorer.ts +263 -0
- package/src/sdd/rollback/manager.ts +361 -0
- package/src/sdd/session/handoff.ts +354 -0
- package/src/sdd/sla/tracker.ts +68 -0
- package/src/sdd/sync/git-sync.ts +401 -0
- package/src/sdd/toggle/state.ts +38 -0
- package/src/sdd/transactions/manager.ts +93 -0
- package/src/sdd/validation/coverage-index.ts +339 -0
- package/src/sdd/validation/executable.ts +127 -0
- package/src/sdd/validation/smart-validator.ts +470 -0
- package/src/sdd/validation/validator.ts +641 -0
- package/src/sdd/workflow/exporter.ts +169 -0
- package/src/sdd/workflows/ab-testing.ts +90 -0
- package/src/sdd/workflows/bug-fix.ts +81 -0
- package/src/sdd/workflows/data-migration.ts +86 -0
- package/src/sdd/workflows/deprecation.ts +87 -0
- package/src/sdd/workflows/feature-flags.ts +91 -0
- package/src/sdd/workflows/hotfix.ts +83 -0
- package/src/sdd/workflows/multi-tenancy.ts +84 -0
- package/src/sdd/workflows/onboarding.ts +82 -0
- package/src/sdd/workflows/refactoring.ts +90 -0
- package/src/server/events.ts +184 -0
- package/src/server/server.ts +1088 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import type { KnowledgeGraph, FileNode, ChangeNode } from "../domain/types.js"
|
|
2
|
+
import { getNode, getNodesByType } from "../graph/engine.js"
|
|
3
|
+
import { existsSync, readFileSync } from "fs"
|
|
4
|
+
import { join } from "path"
|
|
5
|
+
import { detectAllSignals, formatDriftSignals } from "./signals.js"
|
|
6
|
+
import type { DriftSignals, DuplicateDetectionOptions } from "./signals.js"
|
|
7
|
+
import { getExclusionSets, isNodeExcludedOrDeprecated, isFileWhitelistedPattern } from "./exclusion.js"
|
|
8
|
+
import { hasPersistenceMapping } from "../validation/validator.js"
|
|
9
|
+
import { validateGraphIntegrity } from "../graph/integrity-guard.js"
|
|
10
|
+
import { parseWithCache, loadAstCache, saveAstCache } from "../../code-intelligence/ast/cache.js"
|
|
11
|
+
|
|
12
|
+
export interface DriftDetectionResult {
|
|
13
|
+
has_drift: boolean
|
|
14
|
+
missing_files: MissingFileDrift[]
|
|
15
|
+
untracked_files: UntrackedFileDrift[]
|
|
16
|
+
spec_code_mismatches: SpecCodeMismatch[]
|
|
17
|
+
signals?: DriftSignals
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MissingFileDrift {
|
|
21
|
+
node_id: string
|
|
22
|
+
file_path: string
|
|
23
|
+
expected_by: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface UntrackedFileDrift {
|
|
27
|
+
file_path: string
|
|
28
|
+
full_path?: string
|
|
29
|
+
severity?: "info" | "warning" | "error"
|
|
30
|
+
suggestion: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SpecCodeMismatch {
|
|
34
|
+
node_id: string
|
|
35
|
+
description: string
|
|
36
|
+
severity: "high" | "medium" | "low"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
export function detectDrift(
|
|
42
|
+
graph: KnowledgeGraph,
|
|
43
|
+
projectDir: string,
|
|
44
|
+
options?: DuplicateDetectionOptions,
|
|
45
|
+
): DriftDetectionResult {
|
|
46
|
+
const result: DriftDetectionResult = {
|
|
47
|
+
has_drift: false,
|
|
48
|
+
missing_files: [],
|
|
49
|
+
untracked_files: [],
|
|
50
|
+
spec_code_mismatches: [],
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Pre-compute sets of nodes that should be excluded from drift detection.
|
|
54
|
+
// Nodes removed via ChangeNode or deprecated should NOT trigger drift.
|
|
55
|
+
const { removed: removedNodeIds, deprecated: deprecatedNodeIds } = getExclusionSets(graph)
|
|
56
|
+
|
|
57
|
+
detectMissingFiles(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
|
|
58
|
+
detectUntrackedFiles(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
|
|
59
|
+
detectSpecCodeMismatches(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
|
|
60
|
+
detectAstFileMismatches(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
|
|
61
|
+
|
|
62
|
+
// Filter out whitelisted files from drift results
|
|
63
|
+
result.missing_files = result.missing_files.filter(
|
|
64
|
+
(f) => !isFileWhitelistedPattern(projectDir, f.file_path),
|
|
65
|
+
)
|
|
66
|
+
result.untracked_files = result.untracked_files.filter(
|
|
67
|
+
(f) => !isFileWhitelistedPattern(projectDir, f.file_path),
|
|
68
|
+
)
|
|
69
|
+
result.spec_code_mismatches = result.spec_code_mismatches.filter(
|
|
70
|
+
(m) => !isFileWhitelistedPattern(projectDir, m.node_id),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
// Anti-bypass: check for out-of-band graph modifications
|
|
74
|
+
try {
|
|
75
|
+
const tamperResult = validateGraphIntegrity(projectDir, graph)
|
|
76
|
+
if (tamperResult.tampered) {
|
|
77
|
+
result.spec_code_mismatches.push({
|
|
78
|
+
node_id: "__tamper__",
|
|
79
|
+
description: tamperResult.reason || "Graph modified outside SDD workflow",
|
|
80
|
+
severity: "high",
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
} catch {}
|
|
84
|
+
|
|
85
|
+
// Re-evaluate has_drift after filtering
|
|
86
|
+
result.has_drift =
|
|
87
|
+
result.missing_files.length > 0 ||
|
|
88
|
+
result.untracked_files.length > 0 ||
|
|
89
|
+
result.spec_code_mismatches.length > 0 ||
|
|
90
|
+
(result.signals?.total_signals ?? 0) > 0
|
|
91
|
+
|
|
92
|
+
const signals = detectAllSignals(graph, projectDir, options)
|
|
93
|
+
|
|
94
|
+
// Filter out whitelisted architecture violations from signals
|
|
95
|
+
signals.architecture_violations = signals.architecture_violations.filter(
|
|
96
|
+
(v) => !isFileWhitelistedPattern(projectDir, v.file),
|
|
97
|
+
)
|
|
98
|
+
// Recalculate total_signals after filtering
|
|
99
|
+
signals.total_signals =
|
|
100
|
+
signals.mutant_duplicates.length +
|
|
101
|
+
signals.architecture_violations.length +
|
|
102
|
+
signals.pattern_fragmentation.length +
|
|
103
|
+
signals.temporal_volatility.length
|
|
104
|
+
|
|
105
|
+
result.signals = signals
|
|
106
|
+
|
|
107
|
+
result.has_drift =
|
|
108
|
+
result.missing_files.length > 0 ||
|
|
109
|
+
result.untracked_files.length > 0 ||
|
|
110
|
+
result.spec_code_mismatches.length > 0 ||
|
|
111
|
+
signals.total_signals > 0
|
|
112
|
+
|
|
113
|
+
return result
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Compare persisted AST evidence with the current source without executing it. */
|
|
117
|
+
function detectAstFileMismatches(
|
|
118
|
+
graph: KnowledgeGraph,
|
|
119
|
+
projectDir: string,
|
|
120
|
+
result: DriftDetectionResult,
|
|
121
|
+
removedNodeIds: Set<string>,
|
|
122
|
+
deprecatedNodeIds: Set<string>,
|
|
123
|
+
): void {
|
|
124
|
+
const cache = loadAstCache(projectDir)
|
|
125
|
+
const fileNodes = getNodesByType<FileNode>(graph, "file")
|
|
126
|
+
for (const fileNode of fileNodes) {
|
|
127
|
+
if (isNodeExcludedOrDeprecated(fileNode.id, fileNode.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
128
|
+
const filePath = fileNode.metadata.path
|
|
129
|
+
if (!filePath || !existsSync(join(projectDir, filePath))) continue
|
|
130
|
+
try {
|
|
131
|
+
const content = readFileSync(join(projectDir, filePath), "utf-8")
|
|
132
|
+
const parsed = parseWithCache(projectDir, join(projectDir, filePath), content, cache)
|
|
133
|
+
const metadata = fileNode.metadata as Record<string, unknown>
|
|
134
|
+
if (typeof metadata.content_hash === "string" && metadata.content_hash !== parsed.content_hash) {
|
|
135
|
+
result.spec_code_mismatches.push({ node_id: fileNode.id, description: `AST content fingerprint changed for ${filePath}`, severity: "high" })
|
|
136
|
+
}
|
|
137
|
+
const expected = Array.isArray(metadata.expected_symbols) ? metadata.expected_symbols : Array.isArray(metadata.symbols) ? metadata.symbols : []
|
|
138
|
+
if (expected.length > 0) {
|
|
139
|
+
const actual = new Set(parsed.symbols.map((symbol) => symbol.qualified_name))
|
|
140
|
+
for (const value of expected) {
|
|
141
|
+
if (typeof value === "string" && !actual.has(value)) result.spec_code_mismatches.push({ node_id: fileNode.id, description: `Expected AST symbol ${value} is missing from ${filePath}`, severity: "high" })
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (parsed.analysis_source === "fallback") result.spec_code_mismatches.push({ node_id: fileNode.id, description: `File ${filePath} was analyzed with a low-confidence fallback parser`, severity: "low" })
|
|
145
|
+
} catch (error) {
|
|
146
|
+
result.spec_code_mismatches.push({ node_id: fileNode.id, description: `Could not parse ${filePath}: ${error instanceof Error ? error.message : String(error)}`, severity: "medium" })
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
saveAstCache(projectDir, cache)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function detectMissingFiles(
|
|
153
|
+
graph: KnowledgeGraph,
|
|
154
|
+
projectDir: string,
|
|
155
|
+
result: DriftDetectionResult,
|
|
156
|
+
removedNodeIds: Set<string>,
|
|
157
|
+
deprecatedNodeIds: Set<string>,
|
|
158
|
+
): void {
|
|
159
|
+
const fileNodes = getNodesByType<FileNode>(graph, "file")
|
|
160
|
+
for (const fileNode of fileNodes) {
|
|
161
|
+
// Skip files that were removed by a completed change or deprecated
|
|
162
|
+
if (isNodeExcludedOrDeprecated(fileNode.id, fileNode.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
163
|
+
|
|
164
|
+
const filePath = fileNode.metadata.path
|
|
165
|
+
if (!filePath) continue
|
|
166
|
+
const fullPath = join(projectDir, filePath)
|
|
167
|
+
if (existsSync(fullPath)) continue
|
|
168
|
+
|
|
169
|
+
// ── Fuzzy path matching: try to find the file in nearby locations ──
|
|
170
|
+
const fuzzyMatch = findFuzzyPathMatch(filePath, projectDir)
|
|
171
|
+
if (fuzzyMatch) {
|
|
172
|
+
// File exists but in a different path — suggest auto-heal
|
|
173
|
+
result.missing_files.push({
|
|
174
|
+
node_id: fileNode.id,
|
|
175
|
+
file_path: filePath,
|
|
176
|
+
expected_by: `File node ${fileNode.id} (exists at: ${fuzzyMatch} — consider updating path)`,
|
|
177
|
+
})
|
|
178
|
+
} else {
|
|
179
|
+
result.missing_files.push({
|
|
180
|
+
node_id: fileNode.id,
|
|
181
|
+
file_path: filePath,
|
|
182
|
+
expected_by: `File node ${fileNode.id}`,
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Also check task-referenced files
|
|
188
|
+
const taskNodes = graph.nodes.filter((n) => n.type === "task")
|
|
189
|
+
for (const task of taskNodes) {
|
|
190
|
+
// Skip tasks removed by a completed change or deprecated
|
|
191
|
+
if (isNodeExcludedOrDeprecated(task.id, task.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
192
|
+
|
|
193
|
+
const meta = task.metadata as Record<string, unknown>
|
|
194
|
+
if (Array.isArray(meta.files)) {
|
|
195
|
+
for (const file of meta.files) {
|
|
196
|
+
if (typeof file === "string") {
|
|
197
|
+
const fullPath = join(projectDir, file)
|
|
198
|
+
if (!existsSync(fullPath)) {
|
|
199
|
+
result.missing_files.push({
|
|
200
|
+
node_id: task.id,
|
|
201
|
+
file_path: file,
|
|
202
|
+
expected_by: `Task ${task.id}`,
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function detectUntrackedFiles(
|
|
212
|
+
graph: KnowledgeGraph,
|
|
213
|
+
projectDir: string,
|
|
214
|
+
result: DriftDetectionResult,
|
|
215
|
+
removedNodeIds: Set<string>,
|
|
216
|
+
deprecatedNodeIds: Set<string>,
|
|
217
|
+
): void {
|
|
218
|
+
const trackedPaths = new Set<string>()
|
|
219
|
+
const fileNodes = getNodesByType<FileNode>(graph, "file")
|
|
220
|
+
for (const fn of fileNodes) {
|
|
221
|
+
// Skip files removed by change or deprecated — their paths should NOT
|
|
222
|
+
// be added to trackedPaths, so if the file still exists on disk it
|
|
223
|
+
// will correctly appear as untracked (or be handled by change nodes).
|
|
224
|
+
if (isNodeExcludedOrDeprecated(fn.id, fn.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
225
|
+
if (fn.metadata.path) trackedPaths.add(fn.metadata.path)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const taskNodes = graph.nodes.filter((n) => n.type === "task")
|
|
229
|
+
for (const task of taskNodes) {
|
|
230
|
+
if (isNodeExcludedOrDeprecated(task.id, task.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
231
|
+
const meta = task.metadata as Record<string, unknown>
|
|
232
|
+
if (Array.isArray(meta.files)) {
|
|
233
|
+
for (const f of meta.files) {
|
|
234
|
+
if (typeof f === "string") trackedPaths.add(f)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Only track files from DRAFT/PROPOSED/APPROVED changes (pending changes)
|
|
240
|
+
// COMPLETED changes already had their affected files processed
|
|
241
|
+
const changeNodes = graph.nodes.filter((n) => n.type === "change") as ChangeNode[]
|
|
242
|
+
for (const change of changeNodes) {
|
|
243
|
+
if (["DRAFT", "PROPOSED", "APPROVED"].includes(change.status)) {
|
|
244
|
+
if (change.metadata.affected_files) {
|
|
245
|
+
for (const f of change.metadata.affected_files) {
|
|
246
|
+
trackedPaths.add(f)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const sourceExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".rb", ".vue", ".svelte"]
|
|
253
|
+
const excludePatterns = ["node_modules", ".sdd", "dist", "build", ".git", ".opencode", "__pycache__", "vendor"]
|
|
254
|
+
|
|
255
|
+
function scanDirectory(dir: string, relativePath: string = ""): void {
|
|
256
|
+
let entries: string[]
|
|
257
|
+
try {
|
|
258
|
+
entries = require("fs").readdirSync(dir)
|
|
259
|
+
} catch {
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
for (const entry of entries) {
|
|
264
|
+
if (excludePatterns.some(p => entry === p || entry.startsWith(p))) continue
|
|
265
|
+
|
|
266
|
+
const fullPath = `${dir}/${entry}`
|
|
267
|
+
const relPath = relativePath ? `${relativePath}/${entry}` : entry
|
|
268
|
+
|
|
269
|
+
let stat
|
|
270
|
+
try {
|
|
271
|
+
stat = require("fs").statSync(fullPath)
|
|
272
|
+
} catch {
|
|
273
|
+
continue
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (stat.isDirectory()) {
|
|
277
|
+
scanDirectory(fullPath, relPath)
|
|
278
|
+
} else if (sourceExtensions.some(ext => entry.endsWith(ext))) {
|
|
279
|
+
if (!trackedPaths.has(relPath) && !trackedPaths.has(fullPath)) {
|
|
280
|
+
result.untracked_files = result.untracked_files || []
|
|
281
|
+
// Infer what this file might implement based on name/path
|
|
282
|
+
const inferredEntity = inferEntityFromFile(relPath, graph)
|
|
283
|
+
const suggestion = inferredEntity
|
|
284
|
+
? `File likely implements "${inferredEntity}" — use sdd.add_node to create FileNode, then sdd.add_relationship to link it`
|
|
285
|
+
: "Arquivo não rastreado pelo SDD. Considere adicionar um FileNode."
|
|
286
|
+
result.untracked_files.push({
|
|
287
|
+
file_path: relPath,
|
|
288
|
+
full_path: fullPath,
|
|
289
|
+
severity: "info",
|
|
290
|
+
suggestion,
|
|
291
|
+
})
|
|
292
|
+
if (!result.has_drift) {
|
|
293
|
+
result.has_drift = true
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
scanDirectory(projectDir)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Try to infer which entity/feature a file implements based on its name.
|
|
305
|
+
*/
|
|
306
|
+
function inferEntityFromFile(filePath: string, graph: KnowledgeGraph): string | null {
|
|
307
|
+
const fileName = filePath.split("/").pop()?.toLowerCase().replace(/\.[^.]+$/, "") || ""
|
|
308
|
+
if (fileName.length < 3) return null
|
|
309
|
+
|
|
310
|
+
// Check against entity names
|
|
311
|
+
const entities = graph.nodes.filter(n => n.type === "entity")
|
|
312
|
+
for (const entity of entities) {
|
|
313
|
+
const entityName = entity.name.toLowerCase()
|
|
314
|
+
if (fileName.includes(entityName) || entityName.includes(fileName)) {
|
|
315
|
+
return entity.name
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Check against feature names
|
|
320
|
+
const features = graph.nodes.filter(n => n.type === "feature")
|
|
321
|
+
for (const feature of features) {
|
|
322
|
+
const featureName = feature.name.toLowerCase()
|
|
323
|
+
if (fileName.includes(featureName) || featureName.includes(fileName)) {
|
|
324
|
+
return feature.name
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return null
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function detectSpecCodeMismatches(
|
|
332
|
+
graph: KnowledgeGraph,
|
|
333
|
+
_projectDir: string,
|
|
334
|
+
result: DriftDetectionResult,
|
|
335
|
+
removedNodeIds: Set<string>,
|
|
336
|
+
deprecatedNodeIds: Set<string>,
|
|
337
|
+
): void {
|
|
338
|
+
// Check entity nodes for corresponding persistence (multiple strategies)
|
|
339
|
+
// Uses the same logic as hasPersistenceMapping in validation/validator.ts
|
|
340
|
+
const entities = graph.nodes.filter((n) => n.type === "entity")
|
|
341
|
+
for (const entity of entities) {
|
|
342
|
+
// Skip entities removed by change or deprecated
|
|
343
|
+
if (isNodeExcludedOrDeprecated(entity.id, entity.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
344
|
+
|
|
345
|
+
if (!hasPersistenceMapping(entity, graph) && entities.length > 0) {
|
|
346
|
+
result.spec_code_mismatches.push({
|
|
347
|
+
node_id: entity.id,
|
|
348
|
+
description: `Entity ${entity.id} has no persistence mapping`,
|
|
349
|
+
severity: "medium",
|
|
350
|
+
})
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Check API nodes for endpoint completeness
|
|
355
|
+
const apis = graph.nodes.filter((n) => n.type === "api")
|
|
356
|
+
for (const api of apis) {
|
|
357
|
+
// Skip APIs removed by change or deprecated
|
|
358
|
+
if (isNodeExcludedOrDeprecated(api.id, api.status, removedNodeIds, deprecatedNodeIds)) continue
|
|
359
|
+
|
|
360
|
+
const endpoints = graph.relationships
|
|
361
|
+
.filter((r) => r.from === api.id && r.type === "contains")
|
|
362
|
+
.map((r) => getNode(graph, r.to))
|
|
363
|
+
.filter((n) => n?.type === "endpoint")
|
|
364
|
+
|
|
365
|
+
if (endpoints.length === 0) {
|
|
366
|
+
result.spec_code_mismatches.push({
|
|
367
|
+
node_id: api.id,
|
|
368
|
+
description: `API ${api.id} has no endpoints defined`,
|
|
369
|
+
severity: "low",
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Try to find a file in a nearby location when the expected path doesn't exist.
|
|
377
|
+
* Handles common structural changes like:
|
|
378
|
+
* - src/validators.ts → src/fields/validators/index.ts
|
|
379
|
+
* - src/schema.ts → src/schema/index.ts
|
|
380
|
+
* - src/components/X.ts → src/components/X/index.ts
|
|
381
|
+
*/
|
|
382
|
+
function findFuzzyPathMatch(expectedPath: string, projectDir: string): string | null {
|
|
383
|
+
const segments = expectedPath.split("/")
|
|
384
|
+
const filename = segments[segments.length - 1]
|
|
385
|
+
const nameWithoutExt = filename.replace(/\.[^.]+$/, "")
|
|
386
|
+
|
|
387
|
+
// Strategy 1: Check if file exists as index in a subdirectory
|
|
388
|
+
// e.g., "src/validators.ts" → try "src/validators/index.ts"
|
|
389
|
+
const withoutExt = expectedPath.replace(/\.[^.]+$/, "")
|
|
390
|
+
const indexCandidates = [
|
|
391
|
+
`${withoutExt}/index.ts`,
|
|
392
|
+
`${withoutExt}/index.tsx`,
|
|
393
|
+
`${withoutExt}/index.js`,
|
|
394
|
+
`${withoutExt}/index.jsx`,
|
|
395
|
+
]
|
|
396
|
+
for (const candidate of indexCandidates) {
|
|
397
|
+
if (existsSync(join(projectDir, candidate))) return candidate
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Strategy 2: Search for files with the same name in parent/sibling directories
|
|
401
|
+
const dir = segments.slice(0, -1).join("/")
|
|
402
|
+
const parentDir = segments.slice(0, -2).join("/")
|
|
403
|
+
if (parentDir) {
|
|
404
|
+
try {
|
|
405
|
+
const entries = require("fs").readdirSync(join(projectDir, parentDir), { withFileTypes: true })
|
|
406
|
+
for (const entry of entries) {
|
|
407
|
+
if (!entry.isDirectory()) continue
|
|
408
|
+
const candidateDir = `${parentDir}/${entry.name}`
|
|
409
|
+
const candidatePath = `${candidateDir}/${filename}`
|
|
410
|
+
if (existsSync(join(projectDir, candidatePath))) return candidatePath
|
|
411
|
+
// Also check index files in subdirectories
|
|
412
|
+
const idxCandidates = [
|
|
413
|
+
`${candidateDir}/${nameWithoutExt}/index.ts`,
|
|
414
|
+
`${candidateDir}/${nameWithoutExt}/index.tsx`,
|
|
415
|
+
]
|
|
416
|
+
for (const idx of idxCandidates) {
|
|
417
|
+
if (existsSync(join(projectDir, idx))) return idx
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
} catch {
|
|
421
|
+
// skip
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Strategy 3: Check one level up in directory tree
|
|
426
|
+
if (segments.length > 2) {
|
|
427
|
+
const parentPath = segments.slice(0, -2).concat(filename).join("/")
|
|
428
|
+
if (existsSync(join(projectDir, parentPath))) return parentPath
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return null
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function formatDriftReport(result: DriftDetectionResult): string {
|
|
435
|
+
const lines: string[] = []
|
|
436
|
+
|
|
437
|
+
if (!result.has_drift) {
|
|
438
|
+
lines.push("✅ No drift detected. SDD and code are in sync.\n")
|
|
439
|
+
return lines.join("\n")
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
lines.push("⚠️ Drift Detected\n")
|
|
443
|
+
|
|
444
|
+
if (result.missing_files.length > 0) {
|
|
445
|
+
lines.push(`### Missing Files (${result.missing_files.length})`)
|
|
446
|
+
for (const missing of result.missing_files) {
|
|
447
|
+
lines.push(`- [${missing.node_id}] ${missing.file_path} (expected by: ${missing.expected_by})`)
|
|
448
|
+
}
|
|
449
|
+
lines.push("")
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (result.spec_code_mismatches.length > 0) {
|
|
453
|
+
lines.push(`### Specification Mismatches (${result.spec_code_mismatches.length})`)
|
|
454
|
+
for (const mismatch of result.spec_code_mismatches) {
|
|
455
|
+
lines.push(`- [${mismatch.node_id}] ${mismatch.description} (severity: ${mismatch.severity})`)
|
|
456
|
+
}
|
|
457
|
+
lines.push("")
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (result.signals && result.signals.total_signals > 0) {
|
|
461
|
+
lines.push(formatDriftSignals(result.signals))
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return lines.join("\n")
|
|
465
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { KnowledgeGraph, ChangeNode } from "../domain/types.js"
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"
|
|
3
|
+
import { join, dirname } from "path"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Collects all node IDs that were removed by completed or approved changes.
|
|
7
|
+
* Nodes removed via ChangeNode should not be flagged as drift or cause
|
|
8
|
+
* false positives in validation, coverage, contradictions, etc.
|
|
9
|
+
*/
|
|
10
|
+
export function getRemovedNodeIds(graph: KnowledgeGraph): Set<string> {
|
|
11
|
+
const removed = new Set<string>()
|
|
12
|
+
const changes = graph.nodes.filter(
|
|
13
|
+
(n): n is ChangeNode =>
|
|
14
|
+
n.type === "change" &&
|
|
15
|
+
["COMPLETED", "APPROVED", "IMPLEMENTED"].includes(n.status),
|
|
16
|
+
)
|
|
17
|
+
for (const change of changes) {
|
|
18
|
+
const meta = change.metadata as ChangeNode["metadata"]
|
|
19
|
+
if (Array.isArray(meta.removed_nodes)) {
|
|
20
|
+
for (const id of meta.removed_nodes) {
|
|
21
|
+
removed.add(id)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return removed
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Collects all node IDs that were deprecated via DeprecationNode relationships.
|
|
30
|
+
*/
|
|
31
|
+
export function getDeprecatedNodeIds(graph: KnowledgeGraph): Set<string> {
|
|
32
|
+
const deprecated = new Set<string>()
|
|
33
|
+
const deprecationNodes = graph.nodes.filter((n) => n.type === "deprecation")
|
|
34
|
+
for (const dep of deprecationNodes) {
|
|
35
|
+
const targets = graph.relationships
|
|
36
|
+
.filter((r) => r.from === dep.id && r.type === "deprecates")
|
|
37
|
+
.map((r) => r.to)
|
|
38
|
+
for (const id of targets) {
|
|
39
|
+
deprecated.add(id)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return deprecated
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Checks if a node should be excluded, also considering DEPRECATED status.
|
|
47
|
+
*/
|
|
48
|
+
export function isNodeExcludedOrDeprecated(
|
|
49
|
+
nodeId: string,
|
|
50
|
+
status: string,
|
|
51
|
+
removedIds: Set<string>,
|
|
52
|
+
deprecatedIds: Set<string>,
|
|
53
|
+
): boolean {
|
|
54
|
+
return (
|
|
55
|
+
status === "DEPRECATED" ||
|
|
56
|
+
removedIds.has(nodeId) ||
|
|
57
|
+
deprecatedIds.has(nodeId)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convenience: pre-compute both sets at once.
|
|
63
|
+
*/
|
|
64
|
+
export function getExclusionSets(graph: KnowledgeGraph): {
|
|
65
|
+
removed: Set<string>
|
|
66
|
+
deprecated: Set<string>
|
|
67
|
+
} {
|
|
68
|
+
return {
|
|
69
|
+
removed: getRemovedNodeIds(graph),
|
|
70
|
+
deprecated: getDeprecatedNodeIds(graph),
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Drift Whitelist ─────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
const DRIFT_WHITELIST_FILE = ".sdd/drift-whitelist.json"
|
|
77
|
+
|
|
78
|
+
export interface DriftWhitelistEntry {
|
|
79
|
+
file_path: string
|
|
80
|
+
reason: string
|
|
81
|
+
added_at: string
|
|
82
|
+
added_by?: string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface DriftWhitelist {
|
|
86
|
+
version: number
|
|
87
|
+
entries: DriftWhitelistEntry[]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Load the drift whitelist from disk.
|
|
92
|
+
*/
|
|
93
|
+
export function loadDriftWhitelist(projectDir: string): DriftWhitelist {
|
|
94
|
+
const path = join(projectDir, DRIFT_WHITELIST_FILE)
|
|
95
|
+
if (!existsSync(path)) return { version: 1, entries: [] }
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(readFileSync(path, "utf-8")) as DriftWhitelist
|
|
98
|
+
} catch {
|
|
99
|
+
return { version: 1, entries: [] }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Save the drift whitelist to disk.
|
|
105
|
+
*/
|
|
106
|
+
export function saveDriftWhitelist(projectDir: string, whitelist: DriftWhitelist): void {
|
|
107
|
+
const path = join(projectDir, DRIFT_WHITELIST_FILE)
|
|
108
|
+
const dir = dirname(path)
|
|
109
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
|
|
110
|
+
writeFileSync(path, JSON.stringify(whitelist, null, 2), "utf-8")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Add a file to the drift whitelist.
|
|
115
|
+
*/
|
|
116
|
+
export function addToDriftWhitelist(
|
|
117
|
+
projectDir: string,
|
|
118
|
+
filePath: string,
|
|
119
|
+
reason: string,
|
|
120
|
+
addedBy?: string,
|
|
121
|
+
): DriftWhitelist {
|
|
122
|
+
const whitelist = loadDriftWhitelist(projectDir)
|
|
123
|
+
const normalizedPath = filePath.replace(/^\.\//, "")
|
|
124
|
+
|
|
125
|
+
// Don't add duplicates
|
|
126
|
+
if (!whitelist.entries.some(e => e.file_path === normalizedPath)) {
|
|
127
|
+
whitelist.entries.push({
|
|
128
|
+
file_path: normalizedPath,
|
|
129
|
+
reason,
|
|
130
|
+
added_at: new Date().toISOString(),
|
|
131
|
+
added_by: addedBy,
|
|
132
|
+
})
|
|
133
|
+
saveDriftWhitelist(projectDir, whitelist)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return whitelist
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Remove a file from the drift whitelist.
|
|
141
|
+
*/
|
|
142
|
+
export function removeFromDriftWhitelist(
|
|
143
|
+
projectDir: string,
|
|
144
|
+
filePath: string,
|
|
145
|
+
): DriftWhitelist {
|
|
146
|
+
const whitelist = loadDriftWhitelist(projectDir)
|
|
147
|
+
const normalizedPath = filePath.replace(/^\.\//, "")
|
|
148
|
+
whitelist.entries = whitelist.entries.filter(e => e.file_path !== normalizedPath)
|
|
149
|
+
saveDriftWhitelist(projectDir, whitelist)
|
|
150
|
+
return whitelist
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check if a file path matches any whitelist pattern (supports wildcards).
|
|
155
|
+
* E.g., "src/validators/*" matches all files in src/validators/
|
|
156
|
+
*/
|
|
157
|
+
export function isFileWhitelistedPattern(projectDir: string, filePath: string): boolean {
|
|
158
|
+
const whitelist = loadDriftWhitelist(projectDir)
|
|
159
|
+
const normalizedPath = filePath.replace(/^\.\//, "")
|
|
160
|
+
|
|
161
|
+
for (const entry of whitelist.entries) {
|
|
162
|
+
// Exact match
|
|
163
|
+
if (entry.file_path === normalizedPath) return true
|
|
164
|
+
|
|
165
|
+
// Recursive wildcard: apps/**, packages/**, **/*.ts, etc.
|
|
166
|
+
if (entry.file_path.endsWith("/**")) {
|
|
167
|
+
const prefix = entry.file_path.slice(0, -3)
|
|
168
|
+
if (normalizedPath.startsWith(prefix + "/") || normalizedPath === prefix) return true
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Single-level wildcard: src/validators/*
|
|
172
|
+
if (entry.file_path.endsWith("/*") && !entry.file_path.endsWith("/**")) {
|
|
173
|
+
const prefix = entry.file_path.slice(0, -2)
|
|
174
|
+
if (normalizedPath.startsWith(prefix + "/") || normalizedPath === prefix) return true
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Directory match (ends with /)
|
|
178
|
+
if (entry.file_path.endsWith("/")) {
|
|
179
|
+
if (normalizedPath.startsWith(entry.file_path)) return true
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Glob wildcard in filename: **/*.ts, *.tsx, src/**/*.ts
|
|
183
|
+
if (entry.file_path.includes("*")) {
|
|
184
|
+
const regex = globToRegex(entry.file_path)
|
|
185
|
+
if (regex.test(normalizedPath)) return true
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return false
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Convert a glob pattern to a RegExp.
|
|
194
|
+
* Supports double-star and single-star patterns.
|
|
195
|
+
*/
|
|
196
|
+
function globToRegex(glob: string): RegExp {
|
|
197
|
+
// Process segments separated by /
|
|
198
|
+
const segments = glob.split("/")
|
|
199
|
+
const regexParts: string[] = []
|
|
200
|
+
|
|
201
|
+
for (const seg of segments) {
|
|
202
|
+
if (seg === "**") {
|
|
203
|
+
// ** matches any number of path segments
|
|
204
|
+
regexParts.push(".*")
|
|
205
|
+
} else if (seg === "*") {
|
|
206
|
+
// Single * matches within one segment
|
|
207
|
+
regexParts.push("[^/]+")
|
|
208
|
+
} else if (seg.includes("*")) {
|
|
209
|
+
// Mixed segment like *.ts or tsx-*.test
|
|
210
|
+
const escaped = seg.replace(/\./g, "\\.")
|
|
211
|
+
const inner = escaped.replace(/\*/g, "[^/]*")
|
|
212
|
+
regexParts.push(inner)
|
|
213
|
+
} else {
|
|
214
|
+
// Literal segment
|
|
215
|
+
const escaped = seg.replace(/\./g, "\\.")
|
|
216
|
+
regexParts.push(escaped)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Join with \/ to match path separators
|
|
221
|
+
const pattern = regexParts.join("\\/")
|
|
222
|
+
return new RegExp("^" + pattern + "$")
|
|
223
|
+
}
|