@decibelsystems/tools 2.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/LICENSE +21 -0
- package/README.md +342 -0
- package/dist/agentic/compiler.d.ts +21 -0
- package/dist/agentic/compiler.d.ts.map +1 -0
- package/dist/agentic/compiler.js +267 -0
- package/dist/agentic/compiler.js.map +1 -0
- package/dist/agentic/golden.d.ts +25 -0
- package/dist/agentic/golden.d.ts.map +1 -0
- package/dist/agentic/golden.js +255 -0
- package/dist/agentic/golden.js.map +1 -0
- package/dist/agentic/index.d.ts +17 -0
- package/dist/agentic/index.d.ts.map +1 -0
- package/dist/agentic/index.js +153 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/linter.d.ts +20 -0
- package/dist/agentic/linter.d.ts.map +1 -0
- package/dist/agentic/linter.js +340 -0
- package/dist/agentic/linter.js.map +1 -0
- package/dist/agentic/renderer.d.ts +17 -0
- package/dist/agentic/renderer.d.ts.map +1 -0
- package/dist/agentic/renderer.js +277 -0
- package/dist/agentic/renderer.js.map +1 -0
- package/dist/agentic/types.d.ts +199 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/agentic/types.js +8 -0
- package/dist/agentic/types.js.map +1 -0
- package/dist/architectAdrs.d.ts +32 -0
- package/dist/architectAdrs.d.ts.map +1 -0
- package/dist/architectAdrs.js +162 -0
- package/dist/architectAdrs.js.map +1 -0
- package/dist/client/facade-client.d.ts +41 -0
- package/dist/client/facade-client.d.ts.map +1 -0
- package/dist/client/facade-client.js +243 -0
- package/dist/client/facade-client.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +18 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/transports.d.ts +78 -0
- package/dist/client/transports.d.ts.map +1 -0
- package/dist/client/transports.js +258 -0
- package/dist/client/transports.js.map +1 -0
- package/dist/client/types.d.ts +49 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +8 -0
- package/dist/client/types.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon.d.ts +77 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +374 -0
- package/dist/daemon.js.map +1 -0
- package/dist/daemonConfig.d.ts +43 -0
- package/dist/daemonConfig.d.ts.map +1 -0
- package/dist/daemonConfig.js +113 -0
- package/dist/daemonConfig.js.map +1 -0
- package/dist/dataRoot.d.ts +5 -0
- package/dist/dataRoot.d.ts.map +1 -0
- package/dist/dataRoot.js +23 -0
- package/dist/dataRoot.js.map +1 -0
- package/dist/decibelPaths.d.ts +42 -0
- package/dist/decibelPaths.d.ts.map +1 -0
- package/dist/decibelPaths.js +150 -0
- package/dist/decibelPaths.js.map +1 -0
- package/dist/facades/definitions.d.ts +6 -0
- package/dist/facades/definitions.d.ts.map +1 -0
- package/dist/facades/definitions.js +450 -0
- package/dist/facades/definitions.js.map +1 -0
- package/dist/facades/index.d.ts +27 -0
- package/dist/facades/index.d.ts.map +1 -0
- package/dist/facades/index.js +124 -0
- package/dist/facades/index.js.map +1 -0
- package/dist/facades/types.d.ts +38 -0
- package/dist/facades/types.d.ts.map +1 -0
- package/dist/facades/types.js +8 -0
- package/dist/facades/types.js.map +1 -0
- package/dist/httpServer.d.ts +66 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +1723 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/kernel.d.ts +87 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +256 -0
- package/dist/kernel.js.map +1 -0
- package/dist/lib/agent-services/assumptions.d.ts +16 -0
- package/dist/lib/agent-services/assumptions.d.ts.map +1 -0
- package/dist/lib/agent-services/assumptions.js +284 -0
- package/dist/lib/agent-services/assumptions.js.map +1 -0
- package/dist/lib/agent-services/context-pack.d.ts +6 -0
- package/dist/lib/agent-services/context-pack.d.ts.map +1 -0
- package/dist/lib/agent-services/context-pack.js +354 -0
- package/dist/lib/agent-services/context-pack.js.map +1 -0
- package/dist/lib/agent-services/drift-guard.d.ts +14 -0
- package/dist/lib/agent-services/drift-guard.d.ts.map +1 -0
- package/dist/lib/agent-services/drift-guard.js +355 -0
- package/dist/lib/agent-services/drift-guard.js.map +1 -0
- package/dist/lib/agent-services/index.d.ts +5 -0
- package/dist/lib/agent-services/index.d.ts.map +1 -0
- package/dist/lib/agent-services/index.js +10 -0
- package/dist/lib/agent-services/index.js.map +1 -0
- package/dist/lib/benchmark.d.ts +110 -0
- package/dist/lib/benchmark.d.ts.map +1 -0
- package/dist/lib/benchmark.js +338 -0
- package/dist/lib/benchmark.js.map +1 -0
- package/dist/lib/supabase.d.ts +123 -0
- package/dist/lib/supabase.d.ts.map +1 -0
- package/dist/lib/supabase.js +91 -0
- package/dist/lib/supabase.js.map +1 -0
- package/dist/license.d.ts +30 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +131 -0
- package/dist/license.js.map +1 -0
- package/dist/projectPaths.d.ts +27 -0
- package/dist/projectPaths.d.ts.map +1 -0
- package/dist/projectPaths.js +86 -0
- package/dist/projectPaths.js.map +1 -0
- package/dist/projectRegistry.d.ts +97 -0
- package/dist/projectRegistry.d.ts.map +1 -0
- package/dist/projectRegistry.js +374 -0
- package/dist/projectRegistry.js.map +1 -0
- package/dist/sentinelIssues.d.ts +65 -0
- package/dist/sentinelIssues.d.ts.map +1 -0
- package/dist/sentinelIssues.js +297 -0
- package/dist/sentinelIssues.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +195 -0
- package/dist/server.js.map +1 -0
- package/dist/test.d.ts +7 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +77 -0
- package/dist/test.js.map +1 -0
- package/dist/tools/agentic/index.d.ts +7 -0
- package/dist/tools/agentic/index.d.ts.map +1 -0
- package/dist/tools/agentic/index.js +203 -0
- package/dist/tools/agentic/index.js.map +1 -0
- package/dist/tools/architect/index.d.ts +11 -0
- package/dist/tools/architect/index.d.ts.map +1 -0
- package/dist/tools/architect/index.js +506 -0
- package/dist/tools/architect/index.js.map +1 -0
- package/dist/tools/architect.d.ts +19 -0
- package/dist/tools/architect.d.ts.map +1 -0
- package/dist/tools/architect.js +88 -0
- package/dist/tools/architect.js.map +1 -0
- package/dist/tools/auditor/index.d.ts +10 -0
- package/dist/tools/auditor/index.d.ts.map +1 -0
- package/dist/tools/auditor/index.js +310 -0
- package/dist/tools/auditor/index.js.map +1 -0
- package/dist/tools/auditor.d.ts +149 -0
- package/dist/tools/auditor.d.ts.map +1 -0
- package/dist/tools/auditor.js +775 -0
- package/dist/tools/auditor.js.map +1 -0
- package/dist/tools/bench/index.d.ts +3 -0
- package/dist/tools/bench/index.d.ts.map +1 -0
- package/dist/tools/bench/index.js +220 -0
- package/dist/tools/bench/index.js.map +1 -0
- package/dist/tools/bench.d.ts +89 -0
- package/dist/tools/bench.d.ts.map +1 -0
- package/dist/tools/bench.js +826 -0
- package/dist/tools/bench.js.map +1 -0
- package/dist/tools/context/index.d.ts +11 -0
- package/dist/tools/context/index.d.ts.map +1 -0
- package/dist/tools/context/index.js +482 -0
- package/dist/tools/context/index.js.map +1 -0
- package/dist/tools/context.d.ts +146 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +481 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/coordinator/coordinator.d.ts +168 -0
- package/dist/tools/coordinator/coordinator.d.ts.map +1 -0
- package/dist/tools/coordinator/coordinator.js +535 -0
- package/dist/tools/coordinator/coordinator.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts +12 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -0
- package/dist/tools/coordinator/index.js +381 -0
- package/dist/tools/coordinator/index.js.map +1 -0
- package/dist/tools/corpus/index.d.ts +5 -0
- package/dist/tools/corpus/index.d.ts.map +1 -0
- package/dist/tools/corpus/index.js +105 -0
- package/dist/tools/corpus/index.js.map +1 -0
- package/dist/tools/corpus.d.ts +33 -0
- package/dist/tools/corpus.d.ts.map +1 -0
- package/dist/tools/corpus.js +180 -0
- package/dist/tools/corpus.js.map +1 -0
- package/dist/tools/crit.d.ts +63 -0
- package/dist/tools/crit.d.ts.map +1 -0
- package/dist/tools/crit.js +159 -0
- package/dist/tools/crit.js.map +1 -0
- package/dist/tools/data-inspector.d.ts +189 -0
- package/dist/tools/data-inspector.d.ts.map +1 -0
- package/dist/tools/data-inspector.js +669 -0
- package/dist/tools/data-inspector.js.map +1 -0
- package/dist/tools/deck.d.ts +11 -0
- package/dist/tools/deck.d.ts.map +1 -0
- package/dist/tools/deck.js +188 -0
- package/dist/tools/deck.js.map +1 -0
- package/dist/tools/designer/index.d.ts +11 -0
- package/dist/tools/designer/index.d.ts.map +1 -0
- package/dist/tools/designer/index.js +442 -0
- package/dist/tools/designer/index.js.map +1 -0
- package/dist/tools/designer/lateral-tools.d.ts +6 -0
- package/dist/tools/designer/lateral-tools.d.ts.map +1 -0
- package/dist/tools/designer/lateral-tools.js +190 -0
- package/dist/tools/designer/lateral-tools.js.map +1 -0
- package/dist/tools/designer.d.ts +122 -0
- package/dist/tools/designer.d.ts.map +1 -0
- package/dist/tools/designer.js +495 -0
- package/dist/tools/designer.js.map +1 -0
- package/dist/tools/dojo/index.d.ts +13 -0
- package/dist/tools/dojo/index.d.ts.map +1 -0
- package/dist/tools/dojo/index.js +613 -0
- package/dist/tools/dojo/index.js.map +1 -0
- package/dist/tools/dojo.d.ts +254 -0
- package/dist/tools/dojo.d.ts.map +1 -0
- package/dist/tools/dojo.js +933 -0
- package/dist/tools/dojo.js.map +1 -0
- package/dist/tools/dojoBench.d.ts +49 -0
- package/dist/tools/dojoBench.d.ts.map +1 -0
- package/dist/tools/dojoBench.js +205 -0
- package/dist/tools/dojoBench.js.map +1 -0
- package/dist/tools/dojoGraduated.d.ts +50 -0
- package/dist/tools/dojoGraduated.d.ts.map +1 -0
- package/dist/tools/dojoGraduated.js +174 -0
- package/dist/tools/dojoGraduated.js.map +1 -0
- package/dist/tools/dojoPolicy.d.ts +65 -0
- package/dist/tools/dojoPolicy.d.ts.map +1 -0
- package/dist/tools/dojoPolicy.js +263 -0
- package/dist/tools/dojoPolicy.js.map +1 -0
- package/dist/tools/feedback/index.d.ts +5 -0
- package/dist/tools/feedback/index.d.ts.map +1 -0
- package/dist/tools/feedback/index.js +153 -0
- package/dist/tools/feedback/index.js.map +1 -0
- package/dist/tools/feedback.d.ts +61 -0
- package/dist/tools/feedback.d.ts.map +1 -0
- package/dist/tools/feedback.js +209 -0
- package/dist/tools/feedback.js.map +1 -0
- package/dist/tools/forecast/index.d.ts +8 -0
- package/dist/tools/forecast/index.d.ts.map +1 -0
- package/dist/tools/forecast/index.js +283 -0
- package/dist/tools/forecast/index.js.map +1 -0
- package/dist/tools/forecast.d.ts +147 -0
- package/dist/tools/forecast.d.ts.map +1 -0
- package/dist/tools/forecast.js +417 -0
- package/dist/tools/forecast.js.map +1 -0
- package/dist/tools/friction/index.d.ts +7 -0
- package/dist/tools/friction/index.d.ts.map +1 -0
- package/dist/tools/friction/index.js +265 -0
- package/dist/tools/friction/index.js.map +1 -0
- package/dist/tools/friction.d.ts +82 -0
- package/dist/tools/friction.d.ts.map +1 -0
- package/dist/tools/friction.js +331 -0
- package/dist/tools/friction.js.map +1 -0
- package/dist/tools/git/index.d.ts +9 -0
- package/dist/tools/git/index.d.ts.map +1 -0
- package/dist/tools/git/index.js +237 -0
- package/dist/tools/git/index.js.map +1 -0
- package/dist/tools/git-sentinel/index.d.ts +7 -0
- package/dist/tools/git-sentinel/index.d.ts.map +1 -0
- package/dist/tools/git-sentinel/index.js +178 -0
- package/dist/tools/git-sentinel/index.js.map +1 -0
- package/dist/tools/git-sentinel.d.ts +78 -0
- package/dist/tools/git-sentinel.d.ts.map +1 -0
- package/dist/tools/git-sentinel.js +391 -0
- package/dist/tools/git-sentinel.js.map +1 -0
- package/dist/tools/git.d.ts +134 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +374 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/guardian/index.d.ts +8 -0
- package/dist/tools/guardian/index.d.ts.map +1 -0
- package/dist/tools/guardian/index.js +171 -0
- package/dist/tools/guardian/index.js.map +1 -0
- package/dist/tools/guardian.d.ts +62 -0
- package/dist/tools/guardian.d.ts.map +1 -0
- package/dist/tools/guardian.js +332 -0
- package/dist/tools/guardian.js.map +1 -0
- package/dist/tools/hygiene/codebase-scanner.d.ts +38 -0
- package/dist/tools/hygiene/codebase-scanner.d.ts.map +1 -0
- package/dist/tools/hygiene/codebase-scanner.js +411 -0
- package/dist/tools/hygiene/codebase-scanner.js.map +1 -0
- package/dist/tools/hygiene/config-scanner.d.ts +33 -0
- package/dist/tools/hygiene/config-scanner.d.ts.map +1 -0
- package/dist/tools/hygiene/config-scanner.js +482 -0
- package/dist/tools/hygiene/config-scanner.js.map +1 -0
- package/dist/tools/hygiene/coverage-scanner.d.ts +41 -0
- package/dist/tools/hygiene/coverage-scanner.d.ts.map +1 -0
- package/dist/tools/hygiene/coverage-scanner.js +331 -0
- package/dist/tools/hygiene/coverage-scanner.js.map +1 -0
- package/dist/tools/hygiene/index.d.ts +7 -0
- package/dist/tools/hygiene/index.d.ts.map +1 -0
- package/dist/tools/hygiene/index.js +291 -0
- package/dist/tools/hygiene/index.js.map +1 -0
- package/dist/tools/hygiene/oracle-hygiene.d.ts +68 -0
- package/dist/tools/hygiene/oracle-hygiene.d.ts.map +1 -0
- package/dist/tools/hygiene/oracle-hygiene.js +324 -0
- package/dist/tools/hygiene/oracle-hygiene.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +130 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/lateral.d.ts +114 -0
- package/dist/tools/lateral.d.ts.map +1 -0
- package/dist/tools/lateral.js +536 -0
- package/dist/tools/lateral.js.map +1 -0
- package/dist/tools/learnings/index.d.ts +5 -0
- package/dist/tools/learnings/index.d.ts.map +1 -0
- package/dist/tools/learnings/index.js +138 -0
- package/dist/tools/learnings/index.js.map +1 -0
- package/dist/tools/learnings.d.ts +41 -0
- package/dist/tools/learnings.d.ts.map +1 -0
- package/dist/tools/learnings.js +149 -0
- package/dist/tools/learnings.js.map +1 -0
- package/dist/tools/oracle/index.d.ts +6 -0
- package/dist/tools/oracle/index.d.ts.map +1 -0
- package/dist/tools/oracle/index.js +217 -0
- package/dist/tools/oracle/index.js.map +1 -0
- package/dist/tools/oracle.d.ts +90 -0
- package/dist/tools/oracle.d.ts.map +1 -0
- package/dist/tools/oracle.js +529 -0
- package/dist/tools/oracle.js.map +1 -0
- package/dist/tools/policy.d.ts +119 -0
- package/dist/tools/policy.d.ts.map +1 -0
- package/dist/tools/policy.js +406 -0
- package/dist/tools/policy.js.map +1 -0
- package/dist/tools/provenance/index.d.ts +4 -0
- package/dist/tools/provenance/index.d.ts.map +1 -0
- package/dist/tools/provenance/index.js +63 -0
- package/dist/tools/provenance/index.js.map +1 -0
- package/dist/tools/provenance.d.ts +75 -0
- package/dist/tools/provenance.d.ts.map +1 -0
- package/dist/tools/provenance.js +224 -0
- package/dist/tools/provenance.js.map +1 -0
- package/dist/tools/rateLimiter.d.ts +45 -0
- package/dist/tools/rateLimiter.d.ts.map +1 -0
- package/dist/tools/rateLimiter.js +91 -0
- package/dist/tools/rateLimiter.js.map +1 -0
- package/dist/tools/registry/index.d.ts +10 -0
- package/dist/tools/registry/index.d.ts.map +1 -0
- package/dist/tools/registry/index.js +506 -0
- package/dist/tools/registry/index.js.map +1 -0
- package/dist/tools/registry.d.ts +3 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +189 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/roadmap/index.d.ts +11 -0
- package/dist/tools/roadmap/index.d.ts.map +1 -0
- package/dist/tools/roadmap/index.js +364 -0
- package/dist/tools/roadmap/index.js.map +1 -0
- package/dist/tools/roadmap.d.ts +103 -0
- package/dist/tools/roadmap.d.ts.map +1 -0
- package/dist/tools/roadmap.js +407 -0
- package/dist/tools/roadmap.js.map +1 -0
- package/dist/tools/senken.d.ts +11 -0
- package/dist/tools/senken.d.ts.map +1 -0
- package/dist/tools/senken.js +482 -0
- package/dist/tools/senken.js.map +1 -0
- package/dist/tools/sentinel/index.d.ts +21 -0
- package/dist/tools/sentinel/index.d.ts.map +1 -0
- package/dist/tools/sentinel/index.js +1067 -0
- package/dist/tools/sentinel/index.js.map +1 -0
- package/dist/tools/sentinel-scan-data.d.ts +90 -0
- package/dist/tools/sentinel-scan-data.d.ts.map +1 -0
- package/dist/tools/sentinel-scan-data.js +122 -0
- package/dist/tools/sentinel-scan-data.js.map +1 -0
- package/dist/tools/sentinel.d.ts +156 -0
- package/dist/tools/sentinel.d.ts.map +1 -0
- package/dist/tools/sentinel.js +603 -0
- package/dist/tools/sentinel.js.map +1 -0
- package/dist/tools/shared/index.d.ts +5 -0
- package/dist/tools/shared/index.d.ts.map +1 -0
- package/dist/tools/shared/index.js +8 -0
- package/dist/tools/shared/index.js.map +1 -0
- package/dist/tools/shared/project.d.ts +17 -0
- package/dist/tools/shared/project.d.ts.map +1 -0
- package/dist/tools/shared/project.js +36 -0
- package/dist/tools/shared/project.js.map +1 -0
- package/dist/tools/shared/response.d.ts +15 -0
- package/dist/tools/shared/response.d.ts.map +1 -0
- package/dist/tools/shared/response.js +77 -0
- package/dist/tools/shared/response.js.map +1 -0
- package/dist/tools/shared/runTracker.d.ts +87 -0
- package/dist/tools/shared/runTracker.d.ts.map +1 -0
- package/dist/tools/shared/runTracker.js +225 -0
- package/dist/tools/shared/runTracker.js.map +1 -0
- package/dist/tools/shared/validation.d.ts +10 -0
- package/dist/tools/shared/validation.d.ts.map +1 -0
- package/dist/tools/shared/validation.js +26 -0
- package/dist/tools/shared/validation.js.map +1 -0
- package/dist/tools/studio/cloud-spine.d.ts +27 -0
- package/dist/tools/studio/cloud-spine.d.ts.map +1 -0
- package/dist/tools/studio/cloud-spine.js +845 -0
- package/dist/tools/studio/cloud-spine.js.map +1 -0
- package/dist/tools/studio/index.d.ts +154 -0
- package/dist/tools/studio/index.d.ts.map +1 -0
- package/dist/tools/studio/index.js +541 -0
- package/dist/tools/studio/index.js.map +1 -0
- package/dist/tools/testSpec.d.ts +122 -0
- package/dist/tools/testSpec.d.ts.map +1 -0
- package/dist/tools/testSpec.js +525 -0
- package/dist/tools/testSpec.js.map +1 -0
- package/dist/tools/toolsIndex.d.ts +5 -0
- package/dist/tools/toolsIndex.d.ts.map +1 -0
- package/dist/tools/toolsIndex.js +37 -0
- package/dist/tools/toolsIndex.js.map +1 -0
- package/dist/tools/types.d.ts +47 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +7 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/vector/index.d.ts +13 -0
- package/dist/tools/vector/index.d.ts.map +1 -0
- package/dist/tools/vector/index.js +592 -0
- package/dist/tools/vector/index.js.map +1 -0
- package/dist/tools/vector.d.ts +189 -0
- package/dist/tools/vector.d.ts.map +1 -0
- package/dist/tools/vector.js +570 -0
- package/dist/tools/vector.js.map +1 -0
- package/dist/tools/velocity/index.d.ts +9 -0
- package/dist/tools/velocity/index.d.ts.map +1 -0
- package/dist/tools/velocity/index.js +306 -0
- package/dist/tools/velocity/index.js.map +1 -0
- package/dist/tools/velocity.d.ts +143 -0
- package/dist/tools/velocity.d.ts.map +1 -0
- package/dist/tools/velocity.js +628 -0
- package/dist/tools/velocity.js.map +1 -0
- package/dist/tools/voice/index.d.ts +8 -0
- package/dist/tools/voice/index.d.ts.map +1 -0
- package/dist/tools/voice/index.js +203 -0
- package/dist/tools/voice/index.js.map +1 -0
- package/dist/tools/voice.d.ts +291 -0
- package/dist/tools/voice.d.ts.map +1 -0
- package/dist/tools/voice.js +734 -0
- package/dist/tools/voice.js.map +1 -0
- package/dist/tools/workflow/index.d.ts +8 -0
- package/dist/tools/workflow/index.d.ts.map +1 -0
- package/dist/tools/workflow/index.js +199 -0
- package/dist/tools/workflow/index.js.map +1 -0
- package/dist/tools/workflow.d.ts +123 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +647 -0
- package/dist/tools/workflow.js.map +1 -0
- package/dist/transports/bridge.d.ts +22 -0
- package/dist/transports/bridge.d.ts.map +1 -0
- package/dist/transports/bridge.js +177 -0
- package/dist/transports/bridge.js.map +1 -0
- package/dist/transports/http.d.ts +9 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +35 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/index.d.ts +6 -0
- package/dist/transports/index.d.ts.map +1 -0
- package/dist/transports/index.js +8 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/mcp.d.ts +9 -0
- package/dist/transports/mcp.d.ts.map +1 -0
- package/dist/transports/mcp.js +51 -0
- package/dist/transports/mcp.js.map +1 -0
- package/dist/transports/stdio.d.ts +9 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +26 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/transports/types.d.ts +27 -0
- package/dist/transports/types.d.ts.map +1 -0
- package/dist/transports/types.js +8 -0
- package/dist/transports/types.js.map +1 -0
- package/dist/types/agent-services.d.ts +193 -0
- package/dist/types/agent-services.d.ts.map +1 -0
- package/dist/types/agent-services.js +8 -0
- package/dist/types/agent-services.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +72 -0
- package/templates/AGENT.md +87 -0
- package/templates/com.decibel.daemon.plist +47 -0
- package/templates/sentinel/ISSUE_TEMPLATE.md +20 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { log } from '../config.js';
|
|
6
|
+
import { resolveProjectPaths } from '../projectRegistry.js';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Path Resolution
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Find the .decibel root directory by walking up from the start path
|
|
12
|
+
*/
|
|
13
|
+
export function findDecibelRoot(start) {
|
|
14
|
+
const startPath = start || process.env.DECIBEL_PROJECT_ROOT || process.cwd();
|
|
15
|
+
let current = path.resolve(startPath);
|
|
16
|
+
while (true) {
|
|
17
|
+
const candidate = path.join(current, '.decibel');
|
|
18
|
+
if (fsSync.existsSync(candidate) && fsSync.statSync(candidate).isDirectory()) {
|
|
19
|
+
return candidate;
|
|
20
|
+
}
|
|
21
|
+
const parent = path.dirname(current);
|
|
22
|
+
if (parent === current) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
current = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the project name from the .decibel root's parent directory
|
|
30
|
+
*/
|
|
31
|
+
export function getProjectNameFromRoot(decibelRoot) {
|
|
32
|
+
const projectDir = path.dirname(decibelRoot);
|
|
33
|
+
return path.basename(projectDir);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get global data root (DECIBEL_MCP_ROOT or ~/.decibel)
|
|
37
|
+
*/
|
|
38
|
+
export function getGlobalRoot() {
|
|
39
|
+
return process.env.DECIBEL_MCP_ROOT || path.join(os.homedir(), '.decibel');
|
|
40
|
+
}
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// YAML Parsing
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* Parse simple YAML content (single-level key-value with array support)
|
|
46
|
+
* This is a lightweight parser for our specific schema needs
|
|
47
|
+
*/
|
|
48
|
+
function parseSimpleYaml(content) {
|
|
49
|
+
const result = {};
|
|
50
|
+
const lines = content.split('\n');
|
|
51
|
+
for (const line of lines) {
|
|
52
|
+
const trimmed = line.trim();
|
|
53
|
+
// Skip empty lines and comments
|
|
54
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
55
|
+
continue;
|
|
56
|
+
const colonIndex = trimmed.indexOf(':');
|
|
57
|
+
if (colonIndex <= 0)
|
|
58
|
+
continue;
|
|
59
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
60
|
+
let value = trimmed.slice(colonIndex + 1).trim();
|
|
61
|
+
// Handle arrays: [item1, item2]
|
|
62
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
63
|
+
const inner = value.slice(1, -1);
|
|
64
|
+
result[key] = inner
|
|
65
|
+
.split(',')
|
|
66
|
+
.map(s => s.trim())
|
|
67
|
+
.filter(s => s.length > 0);
|
|
68
|
+
}
|
|
69
|
+
else if (value === '' || value === '~' || value === 'null') {
|
|
70
|
+
result[key] = undefined;
|
|
71
|
+
}
|
|
72
|
+
else if (value === 'true') {
|
|
73
|
+
result[key] = true;
|
|
74
|
+
}
|
|
75
|
+
else if (value === 'false') {
|
|
76
|
+
result[key] = false;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Remove quotes if present
|
|
80
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
81
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
82
|
+
value = value.slice(1, -1);
|
|
83
|
+
}
|
|
84
|
+
result[key] = value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Data Loaders
|
|
91
|
+
// ============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Load all issues from the .decibel/sentinel/issues directory
|
|
94
|
+
*/
|
|
95
|
+
export async function loadIssues(decibelRoot) {
|
|
96
|
+
const issuesDir = path.join(decibelRoot, 'sentinel', 'issues');
|
|
97
|
+
const issues = [];
|
|
98
|
+
try {
|
|
99
|
+
const files = await fs.readdir(issuesDir);
|
|
100
|
+
for (const file of files) {
|
|
101
|
+
if (!file.endsWith('.yml') && !file.endsWith('.yaml'))
|
|
102
|
+
continue;
|
|
103
|
+
const filePath = path.join(issuesDir, file);
|
|
104
|
+
try {
|
|
105
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
106
|
+
const parsed = parseSimpleYaml(content);
|
|
107
|
+
const issue = {
|
|
108
|
+
id: parsed.id || file.replace(/\.ya?ml$/, ''),
|
|
109
|
+
title: parsed.title || '',
|
|
110
|
+
project: parsed.project,
|
|
111
|
+
status: parsed.status || 'open',
|
|
112
|
+
priority: parsed.priority || 'medium',
|
|
113
|
+
epic_id: parsed.epic_id,
|
|
114
|
+
tags: parsed.tags,
|
|
115
|
+
created_at: parsed.created_at,
|
|
116
|
+
updated_at: parsed.updated_at,
|
|
117
|
+
_file: filePath,
|
|
118
|
+
};
|
|
119
|
+
issues.push(issue);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
log(`Data Inspector: Failed to parse issue file ${file}: ${err}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Directory doesn't exist, return empty array
|
|
128
|
+
}
|
|
129
|
+
return issues;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Load all epics from the .decibel/sentinel/epics directory
|
|
133
|
+
*/
|
|
134
|
+
export async function loadEpics(decibelRoot) {
|
|
135
|
+
const epicsDir = path.join(decibelRoot, 'sentinel', 'epics');
|
|
136
|
+
const epics = [];
|
|
137
|
+
try {
|
|
138
|
+
const files = await fs.readdir(epicsDir);
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
if (!file.endsWith('.yml') && !file.endsWith('.yaml'))
|
|
141
|
+
continue;
|
|
142
|
+
const filePath = path.join(epicsDir, file);
|
|
143
|
+
try {
|
|
144
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
145
|
+
const parsed = parseSimpleYaml(content);
|
|
146
|
+
const epic = {
|
|
147
|
+
id: parsed.id || file.replace(/\.ya?ml$/, ''),
|
|
148
|
+
title: parsed.title || '',
|
|
149
|
+
project: parsed.project,
|
|
150
|
+
status: parsed.status || 'open',
|
|
151
|
+
owner: parsed.owner,
|
|
152
|
+
tags: parsed.tags,
|
|
153
|
+
created_at: parsed.created_at,
|
|
154
|
+
updated_at: parsed.updated_at,
|
|
155
|
+
_file: filePath,
|
|
156
|
+
};
|
|
157
|
+
epics.push(epic);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
log(`Data Inspector: Failed to parse epic file ${file}: ${err}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Directory doesn't exist, return empty array
|
|
166
|
+
}
|
|
167
|
+
return epics;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Load all ADRs from the .decibel/architect/adrs directory
|
|
171
|
+
*/
|
|
172
|
+
export async function loadADRs(decibelRoot) {
|
|
173
|
+
const adrsDir = path.join(decibelRoot, 'architect', 'adrs');
|
|
174
|
+
const adrs = [];
|
|
175
|
+
try {
|
|
176
|
+
const files = await fs.readdir(adrsDir);
|
|
177
|
+
for (const file of files) {
|
|
178
|
+
if (!file.endsWith('.yml') && !file.endsWith('.yaml'))
|
|
179
|
+
continue;
|
|
180
|
+
const filePath = path.join(adrsDir, file);
|
|
181
|
+
try {
|
|
182
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
183
|
+
const parsed = parseSimpleYaml(content);
|
|
184
|
+
const adr = {
|
|
185
|
+
id: parsed.id || file.replace(/\.ya?ml$/, ''),
|
|
186
|
+
scope: parsed.scope,
|
|
187
|
+
project: parsed.project,
|
|
188
|
+
title: parsed.title || '',
|
|
189
|
+
status: parsed.status || 'proposed',
|
|
190
|
+
related_issues: parsed.related_issues,
|
|
191
|
+
related_epics: parsed.related_epics,
|
|
192
|
+
created_at: parsed.created_at,
|
|
193
|
+
updated_at: parsed.updated_at,
|
|
194
|
+
_file: filePath,
|
|
195
|
+
};
|
|
196
|
+
adrs.push(adr);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
log(`Data Inspector: Failed to parse ADR file ${file}: ${err}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Directory doesn't exist, return empty array
|
|
205
|
+
}
|
|
206
|
+
return adrs;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Load all data into a DataIndex
|
|
210
|
+
*/
|
|
211
|
+
export async function loadDataIndex(decibelRoot) {
|
|
212
|
+
const [issues, epics, adrs] = await Promise.all([
|
|
213
|
+
loadIssues(decibelRoot),
|
|
214
|
+
loadEpics(decibelRoot),
|
|
215
|
+
loadADRs(decibelRoot),
|
|
216
|
+
]);
|
|
217
|
+
return {
|
|
218
|
+
issues,
|
|
219
|
+
epics,
|
|
220
|
+
adrs,
|
|
221
|
+
decibelRoot,
|
|
222
|
+
projectName: getProjectNameFromRoot(decibelRoot),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// Validation
|
|
227
|
+
// ============================================================================
|
|
228
|
+
const VALID_ISSUE_STATUSES = ['open', 'in_progress', 'done', 'blocked'];
|
|
229
|
+
const VALID_PRIORITIES = ['low', 'medium', 'high'];
|
|
230
|
+
const VALID_EPIC_STATUSES = ['open', 'in_progress', 'done', 'blocked'];
|
|
231
|
+
const VALID_ADR_STATUSES = ['proposed', 'accepted', 'superseded', 'deprecated'];
|
|
232
|
+
const VALID_ADR_SCOPES = ['project', 'global'];
|
|
233
|
+
/**
|
|
234
|
+
* Validate all data and return validation errors
|
|
235
|
+
*/
|
|
236
|
+
export function validateSchema(issues, epics, adrs) {
|
|
237
|
+
const errors = [];
|
|
238
|
+
// Validate issues
|
|
239
|
+
for (const issue of issues) {
|
|
240
|
+
if (!issue.id) {
|
|
241
|
+
errors.push({
|
|
242
|
+
severity: 'error',
|
|
243
|
+
type: 'issue',
|
|
244
|
+
id: issue._file || 'unknown',
|
|
245
|
+
file: issue._file,
|
|
246
|
+
field: 'id',
|
|
247
|
+
message: 'Missing required field: id',
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (!issue.title) {
|
|
251
|
+
errors.push({
|
|
252
|
+
severity: 'warn',
|
|
253
|
+
type: 'issue',
|
|
254
|
+
id: issue.id || issue._file || 'unknown',
|
|
255
|
+
file: issue._file,
|
|
256
|
+
field: 'title',
|
|
257
|
+
message: 'Missing field: title',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (issue.status && !VALID_ISSUE_STATUSES.includes(issue.status)) {
|
|
261
|
+
errors.push({
|
|
262
|
+
severity: 'warn',
|
|
263
|
+
type: 'issue',
|
|
264
|
+
id: issue.id,
|
|
265
|
+
file: issue._file,
|
|
266
|
+
field: 'status',
|
|
267
|
+
message: `Invalid status '${issue.status}'. Must be one of: ${VALID_ISSUE_STATUSES.join(', ')}`,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (issue.priority && !VALID_PRIORITIES.includes(issue.priority)) {
|
|
271
|
+
errors.push({
|
|
272
|
+
severity: 'warn',
|
|
273
|
+
type: 'issue',
|
|
274
|
+
id: issue.id,
|
|
275
|
+
file: issue._file,
|
|
276
|
+
field: 'priority',
|
|
277
|
+
message: `Invalid priority '${issue.priority}'. Must be one of: ${VALID_PRIORITIES.join(', ')}`,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Validate epics
|
|
282
|
+
for (const epic of epics) {
|
|
283
|
+
if (!epic.id) {
|
|
284
|
+
errors.push({
|
|
285
|
+
severity: 'error',
|
|
286
|
+
type: 'epic',
|
|
287
|
+
id: epic._file || 'unknown',
|
|
288
|
+
file: epic._file,
|
|
289
|
+
field: 'id',
|
|
290
|
+
message: 'Missing required field: id',
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (!epic.title) {
|
|
294
|
+
errors.push({
|
|
295
|
+
severity: 'warn',
|
|
296
|
+
type: 'epic',
|
|
297
|
+
id: epic.id || epic._file || 'unknown',
|
|
298
|
+
file: epic._file,
|
|
299
|
+
field: 'title',
|
|
300
|
+
message: 'Missing field: title',
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (epic.status && !VALID_EPIC_STATUSES.includes(epic.status)) {
|
|
304
|
+
errors.push({
|
|
305
|
+
severity: 'warn',
|
|
306
|
+
type: 'epic',
|
|
307
|
+
id: epic.id,
|
|
308
|
+
file: epic._file,
|
|
309
|
+
field: 'status',
|
|
310
|
+
message: `Invalid status '${epic.status}'. Must be one of: ${VALID_EPIC_STATUSES.join(', ')}`,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Validate ADRs
|
|
315
|
+
for (const adr of adrs) {
|
|
316
|
+
if (!adr.id) {
|
|
317
|
+
errors.push({
|
|
318
|
+
severity: 'error',
|
|
319
|
+
type: 'adr',
|
|
320
|
+
id: adr._file || 'unknown',
|
|
321
|
+
file: adr._file,
|
|
322
|
+
field: 'id',
|
|
323
|
+
message: 'Missing required field: id',
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (!adr.title) {
|
|
327
|
+
errors.push({
|
|
328
|
+
severity: 'warn',
|
|
329
|
+
type: 'adr',
|
|
330
|
+
id: adr.id || adr._file || 'unknown',
|
|
331
|
+
file: adr._file,
|
|
332
|
+
field: 'title',
|
|
333
|
+
message: 'Missing field: title',
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (adr.status && !VALID_ADR_STATUSES.includes(adr.status)) {
|
|
337
|
+
errors.push({
|
|
338
|
+
severity: 'warn',
|
|
339
|
+
type: 'adr',
|
|
340
|
+
id: adr.id,
|
|
341
|
+
file: adr._file,
|
|
342
|
+
field: 'status',
|
|
343
|
+
message: `Invalid status '${adr.status}'. Must be one of: ${VALID_ADR_STATUSES.join(', ')}`,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
if (adr.scope && !VALID_ADR_SCOPES.includes(adr.scope)) {
|
|
347
|
+
errors.push({
|
|
348
|
+
severity: 'warn',
|
|
349
|
+
type: 'adr',
|
|
350
|
+
id: adr.id,
|
|
351
|
+
file: adr._file,
|
|
352
|
+
field: 'scope',
|
|
353
|
+
message: `Invalid scope '${adr.scope}'. Must be one of: ${VALID_ADR_SCOPES.join(', ')}`,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return errors;
|
|
358
|
+
}
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// Orphan Detection
|
|
361
|
+
// ============================================================================
|
|
362
|
+
/**
|
|
363
|
+
* Find orphaned records (broken references)
|
|
364
|
+
*/
|
|
365
|
+
export function findOrphans(issues, epics, adrs) {
|
|
366
|
+
const issueIds = new Set(issues.map(i => i.id));
|
|
367
|
+
const epicIds = new Set(epics.map(e => e.id));
|
|
368
|
+
// Find epics with no issues
|
|
369
|
+
const issuesByEpic = new Map();
|
|
370
|
+
for (const issue of issues) {
|
|
371
|
+
if (issue.epic_id) {
|
|
372
|
+
issuesByEpic.set(issue.epic_id, (issuesByEpic.get(issue.epic_id) || 0) + 1);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const epicsWithNoIssues = epics
|
|
376
|
+
.filter(epic => !issuesByEpic.has(epic.id))
|
|
377
|
+
.map(epic => ({ id: epic.id, title: epic.title }));
|
|
378
|
+
// Find issues with missing epics
|
|
379
|
+
const issuesWithMissingEpic = issues
|
|
380
|
+
.filter(issue => issue.epic_id && !epicIds.has(issue.epic_id))
|
|
381
|
+
.map(issue => ({
|
|
382
|
+
id: issue.id,
|
|
383
|
+
title: issue.title,
|
|
384
|
+
epic_id: issue.epic_id,
|
|
385
|
+
}));
|
|
386
|
+
// Find ADRs with missing issues
|
|
387
|
+
const adrsWithMissingIssues = [];
|
|
388
|
+
for (const adr of adrs) {
|
|
389
|
+
if (adr.related_issues && adr.related_issues.length > 0) {
|
|
390
|
+
const missing = adr.related_issues.filter(issueId => !issueIds.has(issueId));
|
|
391
|
+
if (missing.length > 0) {
|
|
392
|
+
adrsWithMissingIssues.push({ id: adr.id, title: adr.title, missing });
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// Find ADRs with missing epics
|
|
397
|
+
const adrsWithMissingEpics = [];
|
|
398
|
+
for (const adr of adrs) {
|
|
399
|
+
if (adr.related_epics && adr.related_epics.length > 0) {
|
|
400
|
+
const missing = adr.related_epics.filter(epicId => !epicIds.has(epicId));
|
|
401
|
+
if (missing.length > 0) {
|
|
402
|
+
adrsWithMissingEpics.push({ id: adr.id, title: adr.title, missing });
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
epicsWithNoIssues,
|
|
408
|
+
issuesWithMissingEpic,
|
|
409
|
+
adrsWithMissingIssues,
|
|
410
|
+
adrsWithMissingEpics,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
// ============================================================================
|
|
414
|
+
// Stale Detection
|
|
415
|
+
// ============================================================================
|
|
416
|
+
/**
|
|
417
|
+
* Parse an ISO date string safely
|
|
418
|
+
*/
|
|
419
|
+
function parseDate(dateStr) {
|
|
420
|
+
if (!dateStr)
|
|
421
|
+
return null;
|
|
422
|
+
try {
|
|
423
|
+
const date = new Date(dateStr);
|
|
424
|
+
return isNaN(date.getTime()) ? null : date;
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Find stale records (not updated in N days)
|
|
432
|
+
*/
|
|
433
|
+
export function findStale(issues, epics, adrs, days = 21) {
|
|
434
|
+
const now = Date.now();
|
|
435
|
+
const threshold = days * 24 * 60 * 60 * 1000; // days in milliseconds
|
|
436
|
+
const isStale = (dateStr) => {
|
|
437
|
+
const date = parseDate(dateStr);
|
|
438
|
+
if (!date)
|
|
439
|
+
return false; // Can't determine staleness without a date
|
|
440
|
+
return (now - date.getTime()) > threshold;
|
|
441
|
+
};
|
|
442
|
+
// Filter stale issues (only open/in_progress ones - done issues should be stale)
|
|
443
|
+
const staleIssues = issues
|
|
444
|
+
.filter(issue => (issue.status === 'open' || issue.status === 'in_progress') &&
|
|
445
|
+
isStale(issue.updated_at || issue.created_at))
|
|
446
|
+
.map(issue => ({
|
|
447
|
+
id: issue.id,
|
|
448
|
+
title: issue.title,
|
|
449
|
+
updated_at: issue.updated_at || issue.created_at || 'unknown',
|
|
450
|
+
}));
|
|
451
|
+
// Filter stale epics (only open/in_progress ones)
|
|
452
|
+
const staleEpics = epics
|
|
453
|
+
.filter(epic => (epic.status === 'open' || epic.status === 'in_progress') &&
|
|
454
|
+
isStale(epic.updated_at || epic.created_at))
|
|
455
|
+
.map(epic => ({
|
|
456
|
+
id: epic.id,
|
|
457
|
+
title: epic.title,
|
|
458
|
+
updated_at: epic.updated_at || epic.created_at || 'unknown',
|
|
459
|
+
}));
|
|
460
|
+
// Filter stale ADRs (only proposed/accepted - not superseded/deprecated)
|
|
461
|
+
const staleADRs = adrs
|
|
462
|
+
.filter(adr => (adr.status === 'proposed' || adr.status === 'accepted') &&
|
|
463
|
+
isStale(adr.updated_at || adr.created_at))
|
|
464
|
+
.map(adr => ({
|
|
465
|
+
id: adr.id,
|
|
466
|
+
title: adr.title,
|
|
467
|
+
updated_at: adr.updated_at || adr.created_at || 'unknown',
|
|
468
|
+
}));
|
|
469
|
+
return {
|
|
470
|
+
issues: staleIssues,
|
|
471
|
+
epics: staleEpics,
|
|
472
|
+
adrs: staleADRs,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
// ============================================================================
|
|
476
|
+
// Summary Generation
|
|
477
|
+
// ============================================================================
|
|
478
|
+
/**
|
|
479
|
+
* Generate a summary of the data
|
|
480
|
+
*/
|
|
481
|
+
export function generateSummary(issues, epics, adrs) {
|
|
482
|
+
return {
|
|
483
|
+
issues: {
|
|
484
|
+
total: issues.length,
|
|
485
|
+
open: issues.filter(i => i.status === 'open').length,
|
|
486
|
+
in_progress: issues.filter(i => i.status === 'in_progress').length,
|
|
487
|
+
done: issues.filter(i => i.status === 'done').length,
|
|
488
|
+
blocked: issues.filter(i => i.status === 'blocked').length,
|
|
489
|
+
},
|
|
490
|
+
epics: {
|
|
491
|
+
total: epics.length,
|
|
492
|
+
open: epics.filter(e => e.status === 'open').length,
|
|
493
|
+
in_progress: epics.filter(e => e.status === 'in_progress').length,
|
|
494
|
+
done: epics.filter(e => e.status === 'done').length,
|
|
495
|
+
blocked: epics.filter(e => e.status === 'blocked').length,
|
|
496
|
+
},
|
|
497
|
+
adrs: {
|
|
498
|
+
total: adrs.length,
|
|
499
|
+
proposed: adrs.filter(a => a.status === 'proposed').length,
|
|
500
|
+
accepted: adrs.filter(a => a.status === 'accepted').length,
|
|
501
|
+
superseded: adrs.filter(a => a.status === 'superseded').length,
|
|
502
|
+
deprecated: adrs.filter(a => a.status === 'deprecated').length,
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
// ============================================================================
|
|
507
|
+
// Main Scan Function
|
|
508
|
+
// ============================================================================
|
|
509
|
+
/**
|
|
510
|
+
* Execute the data scan
|
|
511
|
+
*/
|
|
512
|
+
export async function scanData(input) {
|
|
513
|
+
const { projectId, scope, validate = false, flag = [], days = 21 } = input;
|
|
514
|
+
// For 'runtime' scope, just return a placeholder (not implemented yet)
|
|
515
|
+
if (scope === 'runtime') {
|
|
516
|
+
return {
|
|
517
|
+
scope,
|
|
518
|
+
projectName: 'unknown',
|
|
519
|
+
error: 'Runtime scan not yet implemented. Use scope "data" or "all".',
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
// Find .decibel root - use projectId if provided, otherwise walk up from cwd
|
|
523
|
+
let decibelRoot;
|
|
524
|
+
let projectName;
|
|
525
|
+
if (projectId) {
|
|
526
|
+
try {
|
|
527
|
+
const resolved = resolveProjectPaths(projectId);
|
|
528
|
+
decibelRoot = resolved.decibelPath;
|
|
529
|
+
projectName = resolved.id;
|
|
530
|
+
}
|
|
531
|
+
catch (err) {
|
|
532
|
+
return {
|
|
533
|
+
scope,
|
|
534
|
+
projectName: projectId,
|
|
535
|
+
error: `Failed to resolve project "${projectId}": ${err instanceof Error ? err.message : String(err)}`,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
decibelRoot = findDecibelRoot();
|
|
541
|
+
if (!decibelRoot) {
|
|
542
|
+
return {
|
|
543
|
+
scope,
|
|
544
|
+
projectName: 'unknown',
|
|
545
|
+
error: `No .decibel directory found above ${process.cwd()}. Data inspector cannot run.`,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
projectName = getProjectNameFromRoot(decibelRoot);
|
|
549
|
+
}
|
|
550
|
+
// Load all data
|
|
551
|
+
const { issues, epics, adrs } = await loadDataIndex(decibelRoot);
|
|
552
|
+
// Build output
|
|
553
|
+
const output = {
|
|
554
|
+
scope,
|
|
555
|
+
projectName,
|
|
556
|
+
decibelRoot,
|
|
557
|
+
summary: generateSummary(issues, epics, adrs),
|
|
558
|
+
};
|
|
559
|
+
// Run validation if requested
|
|
560
|
+
if (validate || flag.includes('invalid')) {
|
|
561
|
+
output.validation = validateSchema(issues, epics, adrs);
|
|
562
|
+
}
|
|
563
|
+
// Run orphan detection if flagged
|
|
564
|
+
if (flag.includes('orphans')) {
|
|
565
|
+
output.orphans = findOrphans(issues, epics, adrs);
|
|
566
|
+
}
|
|
567
|
+
// Run stale detection if flagged
|
|
568
|
+
if (flag.includes('stale')) {
|
|
569
|
+
output.stale = findStale(issues, epics, adrs, days);
|
|
570
|
+
}
|
|
571
|
+
return output;
|
|
572
|
+
}
|
|
573
|
+
// ============================================================================
|
|
574
|
+
// Output Formatting
|
|
575
|
+
// ============================================================================
|
|
576
|
+
/**
|
|
577
|
+
* Format the scan output as a human-readable string
|
|
578
|
+
*/
|
|
579
|
+
export function formatScanOutput(output) {
|
|
580
|
+
const lines = [];
|
|
581
|
+
lines.push('SENTINEL DATA INSPECTOR');
|
|
582
|
+
lines.push(` Project: ${output.projectName}`);
|
|
583
|
+
if (output.decibelRoot) {
|
|
584
|
+
lines.push(` .decibel root: ${output.decibelRoot}`);
|
|
585
|
+
}
|
|
586
|
+
if (output.error) {
|
|
587
|
+
lines.push('');
|
|
588
|
+
lines.push('ERROR');
|
|
589
|
+
lines.push(` ${output.error}`);
|
|
590
|
+
return lines.join('\n');
|
|
591
|
+
}
|
|
592
|
+
if (output.summary) {
|
|
593
|
+
lines.push('');
|
|
594
|
+
lines.push('SUMMARY');
|
|
595
|
+
const { issues, epics, adrs } = output.summary;
|
|
596
|
+
const issueBreakdown = [
|
|
597
|
+
`open: ${issues.open}`,
|
|
598
|
+
`in_progress: ${issues.in_progress}`,
|
|
599
|
+
`done: ${issues.done}`,
|
|
600
|
+
`blocked: ${issues.blocked}`,
|
|
601
|
+
].filter(s => !s.includes(': 0')).join(', ');
|
|
602
|
+
lines.push(` Issues: ${issues.total}${issueBreakdown ? ` (${issueBreakdown})` : ''}`);
|
|
603
|
+
const epicBreakdown = [
|
|
604
|
+
`open: ${epics.open}`,
|
|
605
|
+
`in_progress: ${epics.in_progress}`,
|
|
606
|
+
`done: ${epics.done}`,
|
|
607
|
+
`blocked: ${epics.blocked}`,
|
|
608
|
+
].filter(s => !s.includes(': 0')).join(', ');
|
|
609
|
+
lines.push(` Epics: ${epics.total}${epicBreakdown ? ` (${epicBreakdown})` : ''}`);
|
|
610
|
+
const adrBreakdown = [
|
|
611
|
+
`proposed: ${adrs.proposed}`,
|
|
612
|
+
`accepted: ${adrs.accepted}`,
|
|
613
|
+
`superseded: ${adrs.superseded}`,
|
|
614
|
+
`deprecated: ${adrs.deprecated}`,
|
|
615
|
+
].filter(s => !s.includes(': 0')).join(', ');
|
|
616
|
+
lines.push(` ADRs: ${adrs.total}${adrBreakdown ? ` (${adrBreakdown})` : ''}`);
|
|
617
|
+
}
|
|
618
|
+
if (output.validation && output.validation.length > 0) {
|
|
619
|
+
lines.push('');
|
|
620
|
+
lines.push('VALIDATION');
|
|
621
|
+
for (const err of output.validation) {
|
|
622
|
+
const prefix = err.severity === 'error' ? '[ERROR]' : '[WARN]';
|
|
623
|
+
const typeLabel = err.type.charAt(0).toUpperCase() + err.type.slice(1);
|
|
624
|
+
lines.push(` ${prefix} ${typeLabel} ${err.id}: ${err.message}`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (output.orphans) {
|
|
628
|
+
const { epicsWithNoIssues, issuesWithMissingEpic, adrsWithMissingIssues, adrsWithMissingEpics } = output.orphans;
|
|
629
|
+
const hasOrphans = epicsWithNoIssues.length > 0 ||
|
|
630
|
+
issuesWithMissingEpic.length > 0 ||
|
|
631
|
+
adrsWithMissingIssues.length > 0 ||
|
|
632
|
+
adrsWithMissingEpics.length > 0;
|
|
633
|
+
if (hasOrphans) {
|
|
634
|
+
lines.push('');
|
|
635
|
+
lines.push('ORPHANS');
|
|
636
|
+
for (const epic of epicsWithNoIssues) {
|
|
637
|
+
lines.push(` [EPIC] ${epic.id} (no issues attached)`);
|
|
638
|
+
}
|
|
639
|
+
for (const issue of issuesWithMissingEpic) {
|
|
640
|
+
lines.push(` [ISSUE] ${issue.id} references missing epic ${issue.epic_id}`);
|
|
641
|
+
}
|
|
642
|
+
for (const adr of adrsWithMissingIssues) {
|
|
643
|
+
lines.push(` [ADR] ${adr.id} references missing issues: ${adr.missing.join(', ')}`);
|
|
644
|
+
}
|
|
645
|
+
for (const adr of adrsWithMissingEpics) {
|
|
646
|
+
lines.push(` [ADR] ${adr.id} references missing epics: ${adr.missing.join(', ')}`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (output.stale) {
|
|
651
|
+
const { issues, epics, adrs } = output.stale;
|
|
652
|
+
const hasStale = issues.length > 0 || epics.length > 0 || adrs.length > 0;
|
|
653
|
+
if (hasStale) {
|
|
654
|
+
lines.push('');
|
|
655
|
+
lines.push('STALE');
|
|
656
|
+
for (const issue of issues) {
|
|
657
|
+
lines.push(` [ISSUE] ${issue.id} last updated ${issue.updated_at}`);
|
|
658
|
+
}
|
|
659
|
+
for (const epic of epics) {
|
|
660
|
+
lines.push(` [EPIC] ${epic.id} last updated ${epic.updated_at}`);
|
|
661
|
+
}
|
|
662
|
+
for (const adr of adrs) {
|
|
663
|
+
lines.push(` [ADR] ${adr.id} last updated ${adr.updated_at}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return lines.join('\n');
|
|
668
|
+
}
|
|
669
|
+
//# sourceMappingURL=data-inspector.js.map
|