@specship/specship 0.11.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/.claude-plugin/plugin.json +6 -0
- package/LICENSE +21 -0
- package/README.md +583 -0
- package/agents/specship-explorer.md +29 -0
- package/commands/ss-behaviour.md +116 -0
- package/commands/ss-check.md +43 -0
- package/commands/ss-design-implement.md +84 -0
- package/commands/ss-design-loop.md +125 -0
- package/commands/ss-explore.md +43 -0
- package/commands/ss-spec.md +118 -0
- package/dist/activation/starter-prompt.d.ts +57 -0
- package/dist/activation/starter-prompt.d.ts.map +1 -0
- package/dist/activation/starter-prompt.js +164 -0
- package/dist/activation/starter-prompt.js.map +1 -0
- package/dist/analytics/specship-impact.d.ts +72 -0
- package/dist/analytics/specship-impact.d.ts.map +1 -0
- package/dist/analytics/specship-impact.js +216 -0
- package/dist/analytics/specship-impact.js.map +1 -0
- package/dist/behaviour/behaviour-surface.d.ts +59 -0
- package/dist/behaviour/behaviour-surface.d.ts.map +1 -0
- package/dist/behaviour/behaviour-surface.js +112 -0
- package/dist/behaviour/behaviour-surface.js.map +1 -0
- package/dist/bin/node-version-check.d.ts +37 -0
- package/dist/bin/node-version-check.d.ts.map +1 -0
- package/dist/bin/node-version-check.js +79 -0
- package/dist/bin/node-version-check.js.map +1 -0
- package/dist/bin/specship.d.ts +25 -0
- package/dist/bin/specship.d.ts.map +1 -0
- package/dist/bin/specship.js +2823 -0
- package/dist/bin/specship.js.map +1 -0
- package/dist/bin/uninstall.d.ts +13 -0
- package/dist/bin/uninstall.d.ts.map +1 -0
- package/dist/bin/uninstall.js +35 -0
- package/dist/bin/uninstall.js.map +1 -0
- package/dist/context/formatter.d.ts +30 -0
- package/dist/context/formatter.d.ts.map +1 -0
- package/dist/context/formatter.js +263 -0
- package/dist/context/formatter.js.map +1 -0
- package/dist/context/index.d.ts +119 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +1289 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/markers.d.ts +19 -0
- package/dist/context/markers.d.ts.map +1 -0
- package/dist/context/markers.js +22 -0
- package/dist/context/markers.js.map +1 -0
- package/dist/db/index.d.ts +103 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +279 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations.d.ts +44 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +503 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/queries.d.ts +357 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +1504 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.sql +451 -0
- package/dist/db/spec-queries.d.ts +130 -0
- package/dist/db/spec-queries.d.ts.map +1 -0
- package/dist/db/spec-queries.js +738 -0
- package/dist/db/spec-queries.js.map +1 -0
- package/dist/db/sqlite-adapter.d.ts +65 -0
- package/dist/db/sqlite-adapter.d.ts.map +1 -0
- package/dist/db/sqlite-adapter.js +214 -0
- package/dist/db/sqlite-adapter.js.map +1 -0
- package/dist/designer/artifact-store.js +54 -0
- package/dist/designer/browser.js +141 -0
- package/dist/designer/cdp-ensure.js +60 -0
- package/dist/designer/cdp-env.js +18 -0
- package/dist/designer/cdp-trace.js +599 -0
- package/dist/designer/cross-platform.js +74 -0
- package/dist/designer/designer-controller.js +1413 -0
- package/dist/designer/file-panel.js +39 -0
- package/dist/designer/interstitials.js +97 -0
- package/dist/designer/oopif-reader.js +176 -0
- package/dist/designer/package-meta.js +18 -0
- package/dist/designer/preview-host.js +50 -0
- package/dist/designer/repo-root.js +31 -0
- package/dist/designer/run-state.js +353 -0
- package/dist/designer/session-store.js +59 -0
- package/dist/designer/ui-anchors.js +651 -0
- package/dist/directory.d.ts +67 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +267 -0
- package/dist/directory.js.map +1 -0
- package/dist/enforce/enforce.d.ts +70 -0
- package/dist/enforce/enforce.d.ts.map +1 -0
- package/dist/enforce/enforce.js +125 -0
- package/dist/enforce/enforce.js.map +1 -0
- package/dist/errors.d.ts +136 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +219 -0
- package/dist/errors.js.map +1 -0
- package/dist/extraction/dfm-extractor.d.ts +31 -0
- package/dist/extraction/dfm-extractor.d.ts.map +1 -0
- package/dist/extraction/dfm-extractor.js +151 -0
- package/dist/extraction/dfm-extractor.js.map +1 -0
- package/dist/extraction/generated-detection.d.ts +30 -0
- package/dist/extraction/generated-detection.d.ts.map +1 -0
- package/dist/extraction/generated-detection.js +80 -0
- package/dist/extraction/generated-detection.js.map +1 -0
- package/dist/extraction/grammars.d.ts +100 -0
- package/dist/extraction/grammars.d.ts.map +1 -0
- package/dist/extraction/grammars.js +426 -0
- package/dist/extraction/grammars.js.map +1 -0
- package/dist/extraction/index.d.ts +138 -0
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/index.js +1394 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/extraction/languages/c-cpp.d.ts +4 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
- package/dist/extraction/languages/c-cpp.js +171 -0
- package/dist/extraction/languages/c-cpp.js.map +1 -0
- package/dist/extraction/languages/csharp.d.ts +3 -0
- package/dist/extraction/languages/csharp.d.ts.map +1 -0
- package/dist/extraction/languages/csharp.js +73 -0
- package/dist/extraction/languages/csharp.js.map +1 -0
- package/dist/extraction/languages/dart.d.ts +3 -0
- package/dist/extraction/languages/dart.d.ts.map +1 -0
- package/dist/extraction/languages/dart.js +192 -0
- package/dist/extraction/languages/dart.js.map +1 -0
- package/dist/extraction/languages/go.d.ts +3 -0
- package/dist/extraction/languages/go.d.ts.map +1 -0
- package/dist/extraction/languages/go.js +74 -0
- package/dist/extraction/languages/go.js.map +1 -0
- package/dist/extraction/languages/index.d.ts +10 -0
- package/dist/extraction/languages/index.d.ts.map +1 -0
- package/dist/extraction/languages/index.js +51 -0
- package/dist/extraction/languages/index.js.map +1 -0
- package/dist/extraction/languages/java.d.ts +3 -0
- package/dist/extraction/languages/java.d.ts.map +1 -0
- package/dist/extraction/languages/java.js +70 -0
- package/dist/extraction/languages/java.js.map +1 -0
- package/dist/extraction/languages/javascript.d.ts +3 -0
- package/dist/extraction/languages/javascript.d.ts.map +1 -0
- package/dist/extraction/languages/javascript.js +90 -0
- package/dist/extraction/languages/javascript.js.map +1 -0
- package/dist/extraction/languages/kotlin.d.ts +3 -0
- package/dist/extraction/languages/kotlin.d.ts.map +1 -0
- package/dist/extraction/languages/kotlin.js +259 -0
- package/dist/extraction/languages/kotlin.js.map +1 -0
- package/dist/extraction/languages/lua.d.ts +3 -0
- package/dist/extraction/languages/lua.d.ts.map +1 -0
- package/dist/extraction/languages/lua.js +150 -0
- package/dist/extraction/languages/lua.js.map +1 -0
- package/dist/extraction/languages/luau.d.ts +3 -0
- package/dist/extraction/languages/luau.d.ts.map +1 -0
- package/dist/extraction/languages/luau.js +37 -0
- package/dist/extraction/languages/luau.js.map +1 -0
- package/dist/extraction/languages/objc.d.ts +3 -0
- package/dist/extraction/languages/objc.d.ts.map +1 -0
- package/dist/extraction/languages/objc.js +133 -0
- package/dist/extraction/languages/objc.js.map +1 -0
- package/dist/extraction/languages/pascal.d.ts +3 -0
- package/dist/extraction/languages/pascal.d.ts.map +1 -0
- package/dist/extraction/languages/pascal.js +66 -0
- package/dist/extraction/languages/pascal.js.map +1 -0
- package/dist/extraction/languages/php.d.ts +3 -0
- package/dist/extraction/languages/php.d.ts.map +1 -0
- package/dist/extraction/languages/php.js +107 -0
- package/dist/extraction/languages/php.js.map +1 -0
- package/dist/extraction/languages/python.d.ts +3 -0
- package/dist/extraction/languages/python.d.ts.map +1 -0
- package/dist/extraction/languages/python.js +56 -0
- package/dist/extraction/languages/python.js.map +1 -0
- package/dist/extraction/languages/ruby.d.ts +3 -0
- package/dist/extraction/languages/ruby.d.ts.map +1 -0
- package/dist/extraction/languages/ruby.js +114 -0
- package/dist/extraction/languages/ruby.js.map +1 -0
- package/dist/extraction/languages/rust.d.ts +3 -0
- package/dist/extraction/languages/rust.d.ts.map +1 -0
- package/dist/extraction/languages/rust.js +109 -0
- package/dist/extraction/languages/rust.js.map +1 -0
- package/dist/extraction/languages/scala.d.ts +3 -0
- package/dist/extraction/languages/scala.d.ts.map +1 -0
- package/dist/extraction/languages/scala.js +139 -0
- package/dist/extraction/languages/scala.js.map +1 -0
- package/dist/extraction/languages/swift.d.ts +3 -0
- package/dist/extraction/languages/swift.d.ts.map +1 -0
- package/dist/extraction/languages/swift.js +91 -0
- package/dist/extraction/languages/swift.js.map +1 -0
- package/dist/extraction/languages/typescript.d.ts +3 -0
- package/dist/extraction/languages/typescript.d.ts.map +1 -0
- package/dist/extraction/languages/typescript.js +129 -0
- package/dist/extraction/languages/typescript.js.map +1 -0
- package/dist/extraction/liquid-extractor.d.ts +52 -0
- package/dist/extraction/liquid-extractor.d.ts.map +1 -0
- package/dist/extraction/liquid-extractor.js +313 -0
- package/dist/extraction/liquid-extractor.js.map +1 -0
- package/dist/extraction/mybatis-extractor.d.ts +48 -0
- package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
- package/dist/extraction/mybatis-extractor.js +198 -0
- package/dist/extraction/mybatis-extractor.js.map +1 -0
- package/dist/extraction/parse-worker.d.ts +8 -0
- package/dist/extraction/parse-worker.d.ts.map +1 -0
- package/dist/extraction/parse-worker.js +94 -0
- package/dist/extraction/parse-worker.js.map +1 -0
- package/dist/extraction/specs/markdown-spec-extractor.d.ts +114 -0
- package/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -0
- package/dist/extraction/specs/markdown-spec-extractor.js +699 -0
- package/dist/extraction/specs/markdown-spec-extractor.js.map +1 -0
- package/dist/extraction/specs/types.d.ts +39 -0
- package/dist/extraction/specs/types.d.ts.map +1 -0
- package/dist/extraction/specs/types.js +8 -0
- package/dist/extraction/specs/types.js.map +1 -0
- package/dist/extraction/svelte-extractor.d.ts +56 -0
- package/dist/extraction/svelte-extractor.d.ts.map +1 -0
- package/dist/extraction/svelte-extractor.js +272 -0
- package/dist/extraction/svelte-extractor.js.map +1 -0
- package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-helpers.js +103 -0
- package/dist/extraction/tree-sitter-helpers.js.map +1 -0
- package/dist/extraction/tree-sitter-types.d.ts +193 -0
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-types.js +10 -0
- package/dist/extraction/tree-sitter-types.js.map +1 -0
- package/dist/extraction/tree-sitter.d.ts +317 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -0
- package/dist/extraction/tree-sitter.js +3092 -0
- package/dist/extraction/tree-sitter.js.map +1 -0
- package/dist/extraction/vue-extractor.d.ts +51 -0
- package/dist/extraction/vue-extractor.d.ts.map +1 -0
- package/dist/extraction/vue-extractor.js +251 -0
- package/dist/extraction/vue-extractor.js.map +1 -0
- package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/dist/extraction/wasm-runtime-flags.d.ts +38 -0
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
- package/dist/extraction/wasm-runtime-flags.js +106 -0
- package/dist/extraction/wasm-runtime-flags.js.map +1 -0
- package/dist/fitness/fitness.d.ts +75 -0
- package/dist/fitness/fitness.d.ts.map +1 -0
- package/dist/fitness/fitness.js +204 -0
- package/dist/fitness/fitness.js.map +1 -0
- package/dist/graph/index.d.ts +8 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +13 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/maintainability.d.ts +115 -0
- package/dist/graph/maintainability.d.ts.map +1 -0
- package/dist/graph/maintainability.js +299 -0
- package/dist/graph/maintainability.js.map +1 -0
- package/dist/graph/queries.d.ts +106 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +366 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/traversal.d.ts +127 -0
- package/dist/graph/traversal.d.ts.map +1 -0
- package/dist/graph/traversal.js +531 -0
- package/dist/graph/traversal.js.map +1 -0
- package/dist/health/smoke-check.d.ts +85 -0
- package/dist/health/smoke-check.d.ts.map +1 -0
- package/dist/health/smoke-check.js +246 -0
- package/dist/health/smoke-check.js.map +1 -0
- package/dist/index.d.ts +674 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1473 -0
- package/dist/index.js.map +1 -0
- package/dist/installer/config-writer.d.ts +28 -0
- package/dist/installer/config-writer.d.ts.map +1 -0
- package/dist/installer/config-writer.js +91 -0
- package/dist/installer/config-writer.js.map +1 -0
- package/dist/installer/index.d.ts +100 -0
- package/dist/installer/index.d.ts.map +1 -0
- package/dist/installer/index.js +442 -0
- package/dist/installer/index.js.map +1 -0
- package/dist/installer/init-offer.d.ts +31 -0
- package/dist/installer/init-offer.d.ts.map +1 -0
- package/dist/installer/init-offer.js +30 -0
- package/dist/installer/init-offer.js.map +1 -0
- package/dist/installer/instructions-template.d.ts +36 -0
- package/dist/installer/instructions-template.d.ts.map +1 -0
- package/dist/installer/instructions-template.js +57 -0
- package/dist/installer/instructions-template.js.map +1 -0
- package/dist/installer/targets/claude.d.ts +146 -0
- package/dist/installer/targets/claude.d.ts.map +1 -0
- package/dist/installer/targets/claude.js +864 -0
- package/dist/installer/targets/claude.js.map +1 -0
- package/dist/installer/targets/registry.d.ts +19 -0
- package/dist/installer/targets/registry.d.ts.map +1 -0
- package/dist/installer/targets/registry.js +31 -0
- package/dist/installer/targets/registry.js.map +1 -0
- package/dist/installer/targets/shared.d.ts +76 -0
- package/dist/installer/targets/shared.d.ts.map +1 -0
- package/dist/installer/targets/shared.js +260 -0
- package/dist/installer/targets/shared.js.map +1 -0
- package/dist/installer/targets/types.d.ts +95 -0
- package/dist/installer/targets/types.d.ts.map +1 -0
- package/dist/installer/targets/types.js +12 -0
- package/dist/installer/targets/types.js.map +1 -0
- package/dist/isolation/worktree.d.ts +65 -0
- package/dist/isolation/worktree.d.ts.map +1 -0
- package/dist/isolation/worktree.js +231 -0
- package/dist/isolation/worktree.js.map +1 -0
- package/dist/mcp/daemon-paths.d.ts +46 -0
- package/dist/mcp/daemon-paths.d.ts.map +1 -0
- package/dist/mcp/daemon-paths.js +125 -0
- package/dist/mcp/daemon-paths.js.map +1 -0
- package/dist/mcp/daemon.d.ts +161 -0
- package/dist/mcp/daemon.d.ts.map +1 -0
- package/dist/mcp/daemon.js +403 -0
- package/dist/mcp/daemon.js.map +1 -0
- package/dist/mcp/designer-tools.d.ts +33 -0
- package/dist/mcp/designer-tools.d.ts.map +1 -0
- package/dist/mcp/designer-tools.js +313 -0
- package/dist/mcp/designer-tools.js.map +1 -0
- package/dist/mcp/engine.d.ts +105 -0
- package/dist/mcp/engine.d.ts.map +1 -0
- package/dist/mcp/engine.js +270 -0
- package/dist/mcp/engine.js.map +1 -0
- package/dist/mcp/fitness-tool.d.ts +12 -0
- package/dist/mcp/fitness-tool.d.ts.map +1 -0
- package/dist/mcp/fitness-tool.js +46 -0
- package/dist/mcp/fitness-tool.js.map +1 -0
- package/dist/mcp/index.d.ts +112 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +477 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/maintainability-tool.d.ts +13 -0
- package/dist/mcp/maintainability-tool.d.ts.map +1 -0
- package/dist/mcp/maintainability-tool.js +64 -0
- package/dist/mcp/maintainability-tool.js.map +1 -0
- package/dist/mcp/proxy.d.ts +81 -0
- package/dist/mcp/proxy.d.ts.map +1 -0
- package/dist/mcp/proxy.js +510 -0
- package/dist/mcp/proxy.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +18 -0
- package/dist/mcp/server-instructions.d.ts.map +1 -0
- package/dist/mcp/server-instructions.js +79 -0
- package/dist/mcp/server-instructions.js.map +1 -0
- package/dist/mcp/session.d.ts +77 -0
- package/dist/mcp/session.d.ts.map +1 -0
- package/dist/mcp/session.js +294 -0
- package/dist/mcp/session.js.map +1 -0
- package/dist/mcp/spec-tools.d.ts +39 -0
- package/dist/mcp/spec-tools.d.ts.map +1 -0
- package/dist/mcp/spec-tools.js +534 -0
- package/dist/mcp/spec-tools.js.map +1 -0
- package/dist/mcp/tools.d.ts +417 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +3179 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/transport.d.ts +188 -0
- package/dist/mcp/transport.d.ts.map +1 -0
- package/dist/mcp/transport.js +343 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/mcp/version.d.ts +19 -0
- package/dist/mcp/version.d.ts.map +1 -0
- package/dist/mcp/version.js +71 -0
- package/dist/mcp/version.js.map +1 -0
- package/dist/reflect/apply.d.ts +31 -0
- package/dist/reflect/apply.d.ts.map +1 -0
- package/dist/reflect/apply.js +286 -0
- package/dist/reflect/apply.js.map +1 -0
- package/dist/reflect/hash.d.ts +20 -0
- package/dist/reflect/hash.d.ts.map +1 -0
- package/dist/reflect/hash.js +36 -0
- package/dist/reflect/hash.js.map +1 -0
- package/dist/reflect/index.d.ts +16 -0
- package/dist/reflect/index.d.ts.map +1 -0
- package/dist/reflect/index.js +43 -0
- package/dist/reflect/index.js.map +1 -0
- package/dist/reflect/miner.d.ts +21 -0
- package/dist/reflect/miner.d.ts.map +1 -0
- package/dist/reflect/miner.js +463 -0
- package/dist/reflect/miner.js.map +1 -0
- package/dist/reflect/store.d.ts +31 -0
- package/dist/reflect/store.d.ts.map +1 -0
- package/dist/reflect/store.js +101 -0
- package/dist/reflect/store.js.map +1 -0
- package/dist/reflect/sweep.d.ts +26 -0
- package/dist/reflect/sweep.d.ts.map +1 -0
- package/dist/reflect/sweep.js +42 -0
- package/dist/reflect/sweep.js.map +1 -0
- package/dist/reflect/targets.d.ts +52 -0
- package/dist/reflect/targets.d.ts.map +1 -0
- package/dist/reflect/targets.js +192 -0
- package/dist/reflect/targets.js.map +1 -0
- package/dist/reflect/types.d.ts +96 -0
- package/dist/reflect/types.d.ts.map +1 -0
- package/dist/reflect/types.js +13 -0
- package/dist/reflect/types.js.map +1 -0
- package/dist/resolution/brief-link-resolver.d.ts +114 -0
- package/dist/resolution/brief-link-resolver.d.ts.map +1 -0
- package/dist/resolution/brief-link-resolver.js +261 -0
- package/dist/resolution/brief-link-resolver.js.map +1 -0
- package/dist/resolution/callback-synthesizer.d.ts +10 -0
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
- package/dist/resolution/callback-synthesizer.js +1300 -0
- package/dist/resolution/callback-synthesizer.js.map +1 -0
- package/dist/resolution/domain-gap-seed.d.ts +60 -0
- package/dist/resolution/domain-gap-seed.d.ts.map +1 -0
- package/dist/resolution/domain-gap-seed.js +87 -0
- package/dist/resolution/domain-gap-seed.js.map +1 -0
- package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
- package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
- package/dist/resolution/frameworks/cargo-workspace.js +225 -0
- package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
- package/dist/resolution/frameworks/csharp.d.ts +8 -0
- package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
- package/dist/resolution/frameworks/csharp.js +241 -0
- package/dist/resolution/frameworks/csharp.js.map +1 -0
- package/dist/resolution/frameworks/drupal.d.ts +51 -0
- package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
- package/dist/resolution/frameworks/drupal.js +367 -0
- package/dist/resolution/frameworks/drupal.js.map +1 -0
- package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
- package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
- package/dist/resolution/frameworks/expo-modules.js +143 -0
- package/dist/resolution/frameworks/expo-modules.js.map +1 -0
- package/dist/resolution/frameworks/express.d.ts +8 -0
- package/dist/resolution/frameworks/express.d.ts.map +1 -0
- package/dist/resolution/frameworks/express.js +308 -0
- package/dist/resolution/frameworks/express.js.map +1 -0
- package/dist/resolution/frameworks/fabric.d.ts +3 -0
- package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
- package/dist/resolution/frameworks/fabric.js +354 -0
- package/dist/resolution/frameworks/fabric.js.map +1 -0
- package/dist/resolution/frameworks/go.d.ts +8 -0
- package/dist/resolution/frameworks/go.d.ts.map +1 -0
- package/dist/resolution/frameworks/go.js +161 -0
- package/dist/resolution/frameworks/go.js.map +1 -0
- package/dist/resolution/frameworks/index.d.ts +48 -0
- package/dist/resolution/frameworks/index.d.ts.map +1 -0
- package/dist/resolution/frameworks/index.js +161 -0
- package/dist/resolution/frameworks/index.js.map +1 -0
- package/dist/resolution/frameworks/java.d.ts +8 -0
- package/dist/resolution/frameworks/java.d.ts.map +1 -0
- package/dist/resolution/frameworks/java.js +504 -0
- package/dist/resolution/frameworks/java.js.map +1 -0
- package/dist/resolution/frameworks/laravel.d.ts +13 -0
- package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
- package/dist/resolution/frameworks/laravel.js +257 -0
- package/dist/resolution/frameworks/laravel.js.map +1 -0
- package/dist/resolution/frameworks/nestjs.d.ts +26 -0
- package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
- package/dist/resolution/frameworks/nestjs.js +698 -0
- package/dist/resolution/frameworks/nestjs.js.map +1 -0
- package/dist/resolution/frameworks/play.d.ts +19 -0
- package/dist/resolution/frameworks/play.d.ts.map +1 -0
- package/dist/resolution/frameworks/play.js +111 -0
- package/dist/resolution/frameworks/play.js.map +1 -0
- package/dist/resolution/frameworks/python.d.ts +10 -0
- package/dist/resolution/frameworks/python.d.ts.map +1 -0
- package/dist/resolution/frameworks/python.js +396 -0
- package/dist/resolution/frameworks/python.js.map +1 -0
- package/dist/resolution/frameworks/react-native.d.ts +3 -0
- package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
- package/dist/resolution/frameworks/react-native.js +360 -0
- package/dist/resolution/frameworks/react-native.js.map +1 -0
- package/dist/resolution/frameworks/react.d.ts +8 -0
- package/dist/resolution/frameworks/react.d.ts.map +1 -0
- package/dist/resolution/frameworks/react.js +365 -0
- package/dist/resolution/frameworks/react.js.map +1 -0
- package/dist/resolution/frameworks/ruby.d.ts +8 -0
- package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
- package/dist/resolution/frameworks/ruby.js +302 -0
- package/dist/resolution/frameworks/ruby.js.map +1 -0
- package/dist/resolution/frameworks/rust.d.ts +8 -0
- package/dist/resolution/frameworks/rust.d.ts.map +1 -0
- package/dist/resolution/frameworks/rust.js +304 -0
- package/dist/resolution/frameworks/rust.js.map +1 -0
- package/dist/resolution/frameworks/svelte.d.ts +9 -0
- package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
- package/dist/resolution/frameworks/svelte.js +249 -0
- package/dist/resolution/frameworks/svelte.js.map +1 -0
- package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
- package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
- package/dist/resolution/frameworks/swift-objc.js +252 -0
- package/dist/resolution/frameworks/swift-objc.js.map +1 -0
- package/dist/resolution/frameworks/swift.d.ts +10 -0
- package/dist/resolution/frameworks/swift.d.ts.map +1 -0
- package/dist/resolution/frameworks/swift.js +400 -0
- package/dist/resolution/frameworks/swift.js.map +1 -0
- package/dist/resolution/frameworks/vue.d.ts +9 -0
- package/dist/resolution/frameworks/vue.d.ts.map +1 -0
- package/dist/resolution/frameworks/vue.js +306 -0
- package/dist/resolution/frameworks/vue.js.map +1 -0
- package/dist/resolution/go-module.d.ts +26 -0
- package/dist/resolution/go-module.d.ts.map +1 -0
- package/dist/resolution/go-module.js +78 -0
- package/dist/resolution/go-module.js.map +1 -0
- package/dist/resolution/import-resolver.d.ts +68 -0
- package/dist/resolution/import-resolver.d.ts.map +1 -0
- package/dist/resolution/import-resolver.js +1275 -0
- package/dist/resolution/import-resolver.js.map +1 -0
- package/dist/resolution/index.d.ts +117 -0
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +895 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/lru-cache.d.ts +24 -0
- package/dist/resolution/lru-cache.d.ts.map +1 -0
- package/dist/resolution/lru-cache.js +62 -0
- package/dist/resolution/lru-cache.js.map +1 -0
- package/dist/resolution/name-matcher.d.ts +32 -0
- package/dist/resolution/name-matcher.d.ts.map +1 -0
- package/dist/resolution/name-matcher.js +596 -0
- package/dist/resolution/name-matcher.js.map +1 -0
- package/dist/resolution/path-aliases.d.ts +68 -0
- package/dist/resolution/path-aliases.d.ts.map +1 -0
- package/dist/resolution/path-aliases.js +238 -0
- package/dist/resolution/path-aliases.js.map +1 -0
- package/dist/resolution/spec-link-resolver.d.ts +148 -0
- package/dist/resolution/spec-link-resolver.d.ts.map +1 -0
- package/dist/resolution/spec-link-resolver.js +337 -0
- package/dist/resolution/spec-link-resolver.js.map +1 -0
- package/dist/resolution/strip-comments.d.ts +27 -0
- package/dist/resolution/strip-comments.d.ts.map +1 -0
- package/dist/resolution/strip-comments.js +441 -0
- package/dist/resolution/strip-comments.js.map +1 -0
- package/dist/resolution/swift-objc-bridge.d.ts +134 -0
- package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
- package/dist/resolution/swift-objc-bridge.js +256 -0
- package/dist/resolution/swift-objc-bridge.js.map +1 -0
- package/dist/resolution/types.d.ts +216 -0
- package/dist/resolution/types.d.ts.map +1 -0
- package/dist/resolution/types.js +8 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/resolution/workspace-packages.d.ts +48 -0
- package/dist/resolution/workspace-packages.d.ts.map +1 -0
- package/dist/resolution/workspace-packages.js +208 -0
- package/dist/resolution/workspace-packages.js.map +1 -0
- package/dist/search/query-parser.d.ts +57 -0
- package/dist/search/query-parser.d.ts.map +1 -0
- package/dist/search/query-parser.js +177 -0
- package/dist/search/query-parser.js.map +1 -0
- package/dist/search/query-utils.d.ts +71 -0
- package/dist/search/query-utils.d.ts.map +1 -0
- package/dist/search/query-utils.js +380 -0
- package/dist/search/query-utils.js.map +1 -0
- package/dist/server/cli.js +152 -0
- package/dist/server/index.js +12 -0
- package/dist/server/ingest/impact-backfill.js +69 -0
- package/dist/server/ingest/impact-query.js +343 -0
- package/dist/server/ingest/index.js +19 -0
- package/dist/server/ingest/ingestor.js +541 -0
- package/dist/server/ingest/parser.js +104 -0
- package/dist/server/ingest/pricing.js +78 -0
- package/dist/server/ingest/specship-classify.js +153 -0
- package/dist/server/ingest/types.js +9 -0
- package/dist/server/ingest/watcher.js +77 -0
- package/dist/server/package.json +3 -0
- package/dist/server/project-registry.js +101 -0
- package/dist/server/routes/claude.js +907 -0
- package/dist/server/routes/domain.js +0 -0
- package/dist/server/routes/events.js +134 -0
- package/dist/server/routes/graph.js +248 -0
- package/dist/server/routes/maintainability.js +18 -0
- package/dist/server/routes/memory.js +272 -0
- package/dist/server/routes/projects.js +197 -0
- package/dist/server/routes/reflect.js +93 -0
- package/dist/server/routes/spec.js +373 -0
- package/dist/server/routes/status.js +112 -0
- package/dist/server/routes/workflow.js +253 -0
- package/dist/server/server.js +238 -0
- package/dist/server/static-handler.js +87 -0
- package/dist/statusline/active-run.d.ts +16 -0
- package/dist/statusline/active-run.d.ts.map +1 -0
- package/dist/statusline/active-run.js +73 -0
- package/dist/statusline/active-run.js.map +1 -0
- package/dist/statusline/cache.d.ts +21 -0
- package/dist/statusline/cache.d.ts.map +1 -0
- package/dist/statusline/cache.js +34 -0
- package/dist/statusline/cache.js.map +1 -0
- package/dist/statusline/index.d.ts +24 -0
- package/dist/statusline/index.d.ts.map +1 -0
- package/dist/statusline/index.js +128 -0
- package/dist/statusline/index.js.map +1 -0
- package/dist/statusline/paths.d.ts +27 -0
- package/dist/statusline/paths.d.ts.map +1 -0
- package/dist/statusline/paths.js +101 -0
- package/dist/statusline/paths.js.map +1 -0
- package/dist/statusline/render.d.ts +25 -0
- package/dist/statusline/render.d.ts.map +1 -0
- package/dist/statusline/render.js +72 -0
- package/dist/statusline/render.js.map +1 -0
- package/dist/statusline/session-marker.d.ts +30 -0
- package/dist/statusline/session-marker.d.ts.map +1 -0
- package/dist/statusline/session-marker.js +71 -0
- package/dist/statusline/session-marker.js.map +1 -0
- package/dist/statusline/types.d.ts +67 -0
- package/dist/statusline/types.d.ts.map +1 -0
- package/dist/statusline/types.js +16 -0
- package/dist/statusline/types.js.map +1 -0
- package/dist/sync/git-hooks.d.ts +45 -0
- package/dist/sync/git-hooks.d.ts.map +1 -0
- package/dist/sync/git-hooks.js +225 -0
- package/dist/sync/git-hooks.js.map +1 -0
- package/dist/sync/index.d.ts +19 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +35 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/watch-policy.d.ts +48 -0
- package/dist/sync/watch-policy.d.ts.map +1 -0
- package/dist/sync/watch-policy.js +124 -0
- package/dist/sync/watch-policy.js.map +1 -0
- package/dist/sync/watcher.d.ts +283 -0
- package/dist/sync/watcher.d.ts.map +1 -0
- package/dist/sync/watcher.js +606 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/sync/worktree.d.ts +54 -0
- package/dist/sync/worktree.d.ts.map +1 -0
- package/dist/sync/worktree.js +137 -0
- package/dist/sync/worktree.js.map +1 -0
- package/dist/types.d.ts +625 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +118 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/glyphs.d.ts +42 -0
- package/dist/ui/glyphs.d.ts.map +1 -0
- package/dist/ui/glyphs.js +78 -0
- package/dist/ui/glyphs.js.map +1 -0
- package/dist/ui/shimmer-progress.d.ts +11 -0
- package/dist/ui/shimmer-progress.d.ts.map +1 -0
- package/dist/ui/shimmer-progress.js +90 -0
- package/dist/ui/shimmer-progress.js.map +1 -0
- package/dist/ui/shimmer-worker.d.ts +2 -0
- package/dist/ui/shimmer-worker.d.ts.map +1 -0
- package/dist/ui/shimmer-worker.js +118 -0
- package/dist/ui/shimmer-worker.js.map +1 -0
- package/dist/ui/types.d.ts +17 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +3 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/utils.d.ts +205 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +549 -0
- package/dist/utils.js.map +1 -0
- package/dist/web/chunk-2AJCHB7P.js +1 -0
- package/dist/web/chunk-2CPLUFCH.js +2 -0
- package/dist/web/chunk-2I7L37NS.js +1 -0
- package/dist/web/chunk-2NAWAJB5.js +1 -0
- package/dist/web/chunk-2OJBIPE4.js +1 -0
- package/dist/web/chunk-372AYXK6.js +17 -0
- package/dist/web/chunk-3E2WB6D5.js +1 -0
- package/dist/web/chunk-3EBFYSCH.js +2 -0
- package/dist/web/chunk-3QCQ4BXS.js +1 -0
- package/dist/web/chunk-42XVAQ6I.js +1 -0
- package/dist/web/chunk-4IMMPEYM.js +1 -0
- package/dist/web/chunk-4JYHAP7B.js +1 -0
- package/dist/web/chunk-4TJQJPCZ.js +1 -0
- package/dist/web/chunk-4WZIHTPC.js +1 -0
- package/dist/web/chunk-4YVSYOSD.js +1 -0
- package/dist/web/chunk-52PO6IMB.js +2 -0
- package/dist/web/chunk-54D6RFSW.js +1 -0
- package/dist/web/chunk-5BQIOYKW.js +1 -0
- package/dist/web/chunk-5HGWHUJA.js +1 -0
- package/dist/web/chunk-5XRUOPZE.js +1 -0
- package/dist/web/chunk-5Y244R4G.js +1 -0
- package/dist/web/chunk-6O7Z3P2M.js +1 -0
- package/dist/web/chunk-6QXULGLG.js +1 -0
- package/dist/web/chunk-6RRDPT5Z.js +1 -0
- package/dist/web/chunk-6VKB2ZWM.js +1 -0
- package/dist/web/chunk-7DMFVTU4.js +1 -0
- package/dist/web/chunk-7P5CVBJZ.js +1 -0
- package/dist/web/chunk-7SMPKVEP.js +1 -0
- package/dist/web/chunk-AHLX543M.js +1 -0
- package/dist/web/chunk-AMGJBO7D.js +3 -0
- package/dist/web/chunk-AZJVTPLU.js +1 -0
- package/dist/web/chunk-B3CWIVBW.js +1 -0
- package/dist/web/chunk-BLBRMCN2.js +1 -0
- package/dist/web/chunk-BMIAXD2V.js +2 -0
- package/dist/web/chunk-BPCJLNBS.js +47 -0
- package/dist/web/chunk-BRHEUDLY.js +6 -0
- package/dist/web/chunk-BUXWEHIY.js +1 -0
- package/dist/web/chunk-CD5IZM7Y.js +1 -0
- package/dist/web/chunk-DLQPZWSI.css +1 -0
- package/dist/web/chunk-DSGNOCKQ.js +1 -0
- package/dist/web/chunk-DT5LJYFX.js +1 -0
- package/dist/web/chunk-DYRFLPJA.js +1 -0
- package/dist/web/chunk-E3J3CXR5.js +1 -0
- package/dist/web/chunk-E73OX2P7.js +1 -0
- package/dist/web/chunk-EAXRKDLV.js +1 -0
- package/dist/web/chunk-EBKKDHYI.js +1 -0
- package/dist/web/chunk-EE7V7Q5P.js +1 -0
- package/dist/web/chunk-EKY2FUHU.js +1 -0
- package/dist/web/chunk-EP6XOPXH.js +1 -0
- package/dist/web/chunk-ESGDLJOJ.js +1 -0
- package/dist/web/chunk-ETJG7NCY.js +1 -0
- package/dist/web/chunk-EUUEFEDI.js +1 -0
- package/dist/web/chunk-EX4ZHR4F.js +1 -0
- package/dist/web/chunk-F5UNCSXP.js +1 -0
- package/dist/web/chunk-FFGJXUHI.js +1 -0
- package/dist/web/chunk-FGNZDHTL.js +11 -0
- package/dist/web/chunk-FIJW2UNJ.js +1 -0
- package/dist/web/chunk-FMV5PXRC.js +5 -0
- package/dist/web/chunk-G7VZT5KB.js +3 -0
- package/dist/web/chunk-GCOM4JPR.js +2 -0
- package/dist/web/chunk-GEIIDO6C.js +1 -0
- package/dist/web/chunk-GRZYXPSO.js +7 -0
- package/dist/web/chunk-GWBABPZ5.js +1 -0
- package/dist/web/chunk-GYGPS3AN.js +1 -0
- package/dist/web/chunk-H4GLRD3Q.js +1 -0
- package/dist/web/chunk-H5TWEFYX.js +1 -0
- package/dist/web/chunk-H7AF7YS4.js +1 -0
- package/dist/web/chunk-HCB2N2KH.js +1 -0
- package/dist/web/chunk-HDZDQILN.js +1 -0
- package/dist/web/chunk-HMK6UO6N.js +1 -0
- package/dist/web/chunk-HVVXPI4D.js +1 -0
- package/dist/web/chunk-IHEE5NYJ.js +1 -0
- package/dist/web/chunk-IPB746BT.js +1 -0
- package/dist/web/chunk-ISNEBICW.js +1 -0
- package/dist/web/chunk-J2GZVLHH.js +1 -0
- package/dist/web/chunk-JTFXTIPE.js +903 -0
- package/dist/web/chunk-KHU5M2AL.js +1 -0
- package/dist/web/chunk-KW3DHCFV.js +1 -0
- package/dist/web/chunk-LB6JPLX2.js +1 -0
- package/dist/web/chunk-LBXLFPVN.js +1 -0
- package/dist/web/chunk-LGNSHRCE.js +1 -0
- package/dist/web/chunk-LNSVDHCI.js +1 -0
- package/dist/web/chunk-LVGIY3SO.js +1 -0
- package/dist/web/chunk-LXLHIHEN.js +1 -0
- package/dist/web/chunk-MFHO2F2U.js +4 -0
- package/dist/web/chunk-N5OSSQFZ.js +1 -0
- package/dist/web/chunk-N6SS4G6S.js +1 -0
- package/dist/web/chunk-NAJYJNHS.js +1 -0
- package/dist/web/chunk-NHD66NOI.js +1 -0
- package/dist/web/chunk-NNLJ55MY.js +1 -0
- package/dist/web/chunk-NTBJG6SJ.js +1 -0
- package/dist/web/chunk-NUDB3Q2Y.js +3 -0
- package/dist/web/chunk-OM7JVWQQ.js +1 -0
- package/dist/web/chunk-OXEF5E3E.js +1 -0
- package/dist/web/chunk-PGGJPDJG.js +1 -0
- package/dist/web/chunk-PUYSJNJR.js +1 -0
- package/dist/web/chunk-Q2RVFS45.js +1 -0
- package/dist/web/chunk-Q7L6LLAK.js +1 -0
- package/dist/web/chunk-QCMKJIWY.js +1 -0
- package/dist/web/chunk-QEQRY4QQ.js +1 -0
- package/dist/web/chunk-QH6CF3M3.js +1 -0
- package/dist/web/chunk-QQ5LD7PI.js +1 -0
- package/dist/web/chunk-QR6L3KAC.js +1 -0
- package/dist/web/chunk-QXJS6F3U.js +1 -0
- package/dist/web/chunk-R2DLK4HO.js +1 -0
- package/dist/web/chunk-RD6TVPOT.js +1 -0
- package/dist/web/chunk-RKY4EJYJ.js +1 -0
- package/dist/web/chunk-RONYWVY7.js +1 -0
- package/dist/web/chunk-RSZZWGGC.js +1 -0
- package/dist/web/chunk-RXKXYF2C.js +1 -0
- package/dist/web/chunk-SCNDZRN2.js +1 -0
- package/dist/web/chunk-SH6UVHQC.js +1 -0
- package/dist/web/chunk-SWKJRNYY.js +1 -0
- package/dist/web/chunk-T7AZ65JP.js +1 -0
- package/dist/web/chunk-TCZDVOHD.js +1 -0
- package/dist/web/chunk-TF5TF6IP.js +1 -0
- package/dist/web/chunk-TPTITA3V.js +1 -0
- package/dist/web/chunk-TR335633.js +1 -0
- package/dist/web/chunk-UR5KDXPX.js +1 -0
- package/dist/web/chunk-UR6O2GEH.js +1 -0
- package/dist/web/chunk-UTNMGWTP.js +1 -0
- package/dist/web/chunk-VECWMHJP.js +1 -0
- package/dist/web/chunk-VUACT35R.js +3 -0
- package/dist/web/chunk-VZI7H4SZ.js +1 -0
- package/dist/web/chunk-W22AVG3N.js +1 -0
- package/dist/web/chunk-W6NGHRHX.js +1 -0
- package/dist/web/chunk-WB6YHOD4.js +1 -0
- package/dist/web/chunk-WBT64AWV.js +1 -0
- package/dist/web/chunk-WFXJIXZE.js +4 -0
- package/dist/web/chunk-WTGYRH3Z.js +298 -0
- package/dist/web/chunk-WXTCVDTP.js +1 -0
- package/dist/web/chunk-XCDHWLVH.js +1 -0
- package/dist/web/chunk-Y3H6FFUZ.js +1 -0
- package/dist/web/chunk-Y4F5ULGJ.js +1 -0
- package/dist/web/chunk-YEGKAAEE.js +1 -0
- package/dist/web/chunk-YM2KU57F.js +1 -0
- package/dist/web/chunk-YRERBP6T.js +1 -0
- package/dist/web/chunk-ZLV4VCDG.js +3 -0
- package/dist/web/chunk-ZQUJMA5K.js +4 -0
- package/dist/web/chunk-ZTVI5KFF.js +1 -0
- package/dist/web/favicon-16.png +0 -0
- package/dist/web/favicon-180.png +0 -0
- package/dist/web/favicon-32.png +0 -0
- package/dist/web/favicon-512.png +0 -0
- package/dist/web/favicon-small.svg +15 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/favicon.svg +20 -0
- package/dist/web/icon-192.png +0 -0
- package/dist/web/icon-512.png +0 -0
- package/dist/web/index.html +146 -0
- package/dist/web/main-ESADRXN2.css +1 -0
- package/dist/web/main-SQFUMVQA.js +1 -0
- package/dist/web/manifest.webmanifest +15 -0
- package/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
- package/dist/web/styles-KSOPUVDA.css +1 -0
- package/dist/web/sw.js +69 -0
- package/dist/workflows/condition-evaluator.d.ts +75 -0
- package/dist/workflows/condition-evaluator.d.ts.map +1 -0
- package/dist/workflows/condition-evaluator.js +282 -0
- package/dist/workflows/condition-evaluator.js.map +1 -0
- package/dist/workflows/defaults/claude-design-implement.yaml +336 -0
- package/dist/workflows/defaults/index.d.ts +26 -0
- package/dist/workflows/defaults/index.d.ts.map +1 -0
- package/dist/workflows/defaults/index.js +94 -0
- package/dist/workflows/defaults/index.js.map +1 -0
- package/dist/workflows/defaults/spec-author.yaml +214 -0
- package/dist/workflows/defaults/spec-fix.yaml +110 -0
- package/dist/workflows/defaults/spec-implement.yaml +150 -0
- package/dist/workflows/defaults/spec-relink.yaml +81 -0
- package/dist/workflows/defaults/spec-verify.yaml +51 -0
- package/dist/workflows/discovery.d.ts +46 -0
- package/dist/workflows/discovery.d.ts.map +1 -0
- package/dist/workflows/discovery.js +193 -0
- package/dist/workflows/discovery.js.map +1 -0
- package/dist/workflows/executor.d.ts +98 -0
- package/dist/workflows/executor.d.ts.map +1 -0
- package/dist/workflows/executor.js +664 -0
- package/dist/workflows/executor.js.map +1 -0
- package/dist/workflows/runners/approval.d.ts +18 -0
- package/dist/workflows/runners/approval.d.ts.map +1 -0
- package/dist/workflows/runners/approval.js +34 -0
- package/dist/workflows/runners/approval.js.map +1 -0
- package/dist/workflows/runners/bash.d.ts +13 -0
- package/dist/workflows/runners/bash.d.ts.map +1 -0
- package/dist/workflows/runners/bash.js +143 -0
- package/dist/workflows/runners/bash.js.map +1 -0
- package/dist/workflows/runners/cancel.d.ts +10 -0
- package/dist/workflows/runners/cancel.d.ts.map +1 -0
- package/dist/workflows/runners/cancel.js +19 -0
- package/dist/workflows/runners/cancel.js.map +1 -0
- package/dist/workflows/runners/prompt.d.ts +51 -0
- package/dist/workflows/runners/prompt.d.ts.map +1 -0
- package/dist/workflows/runners/prompt.js +306 -0
- package/dist/workflows/runners/prompt.js.map +1 -0
- package/dist/workflows/runners/script.d.ts +17 -0
- package/dist/workflows/runners/script.d.ts.map +1 -0
- package/dist/workflows/runners/script.js +155 -0
- package/dist/workflows/runners/script.js.map +1 -0
- package/dist/workflows/runners/types.d.ts +57 -0
- package/dist/workflows/runners/types.d.ts.map +1 -0
- package/dist/workflows/runners/types.js +13 -0
- package/dist/workflows/runners/types.js.map +1 -0
- package/dist/workflows/schemas/workflow.d.ts +166 -0
- package/dist/workflows/schemas/workflow.d.ts.map +1 -0
- package/dist/workflows/schemas/workflow.js +437 -0
- package/dist/workflows/schemas/workflow.js.map +1 -0
- package/hooks/hooks.json +38 -0
- package/package.json +78 -0
- package/scripts/add-lang/bench.sh +60 -0
- package/scripts/add-lang/check-grammar.mjs +75 -0
- package/scripts/add-lang/dump-ast.mjs +103 -0
- package/scripts/add-lang/verify-extraction.mjs +70 -0
- package/scripts/agent-eval/arms-F.sh +21 -0
- package/scripts/agent-eval/arms-matrix.sh +37 -0
- package/scripts/agent-eval/audit.sh +68 -0
- package/scripts/agent-eval/bench-readme.sh +28 -0
- package/scripts/agent-eval/bench-why-repo.sh +22 -0
- package/scripts/agent-eval/block-read-hook.sh +19 -0
- package/scripts/agent-eval/hook-settings.json +15 -0
- package/scripts/agent-eval/itrun.sh +120 -0
- package/scripts/agent-eval/parse-arms.mjs +116 -0
- package/scripts/agent-eval/parse-bench-readme.mjs +84 -0
- package/scripts/agent-eval/parse-run.mjs +45 -0
- package/scripts/agent-eval/parse-session.mjs +93 -0
- package/scripts/agent-eval/probe-context.mjs +21 -0
- package/scripts/agent-eval/probe-explore.mjs +40 -0
- package/scripts/agent-eval/probe-node.mjs +20 -0
- package/scripts/agent-eval/probe-sweep.mjs +119 -0
- package/scripts/agent-eval/probe-trace.mjs +20 -0
- package/scripts/agent-eval/run-agent.sh +34 -0
- package/scripts/agent-eval/run-all.sh +67 -0
- package/scripts/agent-eval/run-arms.sh +56 -0
- package/scripts/agent-eval/seq-matrix.mjs +137 -0
- package/scripts/build-bundle.sh +118 -0
- package/scripts/build-server-bundle.mjs +80 -0
- package/scripts/build-web-bundle.mjs +66 -0
- package/scripts/extract-release-notes.mjs +130 -0
- package/scripts/local-install.sh +41 -0
- package/scripts/npm-sdk.js +75 -0
- package/scripts/npm-shim.js +246 -0
- package/scripts/offline-install.ps1 +148 -0
- package/scripts/offline-install.sh +149 -0
- package/scripts/pack-npm.sh +119 -0
- package/scripts/prepare-release.mjs +270 -0
- package/scripts/sync-shim-version.mjs +64 -0
- package/selectors.json +41 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /api/projects — enumerate every project visible to Claude Code
|
|
3
|
+
* (every dir under ~/.claude/projects/).
|
|
4
|
+
* GET /api/projects/events — SSE stream that pushes a refresh whenever the
|
|
5
|
+
* watcher sees the project list change. Used by
|
|
6
|
+
* the desktop UI's Project picker so newly opened
|
|
7
|
+
* projects appear without a refresh.
|
|
8
|
+
*
|
|
9
|
+
* Why this lives in its own route file: the rest of the analytics endpoints
|
|
10
|
+
* already read ~/.claude/projects/ via the ingest pipeline. This route adds
|
|
11
|
+
* a *navigation* primitive on top of that data — "what projects does the
|
|
12
|
+
* user have at all?" — without coupling to the specship instance.
|
|
13
|
+
*/
|
|
14
|
+
import { EventEmitter } from 'node:events';
|
|
15
|
+
import { promises as fs, watch } from 'node:fs';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { decodeProjectSlug } from '../ingest/ingestor.js';
|
|
19
|
+
const projectsBus = new EventEmitter();
|
|
20
|
+
projectsBus.setMaxListeners(0); // many SSE subscribers + internal
|
|
21
|
+
export async function enumerate(claudeRoot) {
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = await fs.readdir(claudeRoot, { withFileTypes: true });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const ent of entries) {
|
|
31
|
+
if (!ent.isDirectory())
|
|
32
|
+
continue;
|
|
33
|
+
const slug = ent.name;
|
|
34
|
+
const decoded = decodeProjectSlug(slug);
|
|
35
|
+
const projDir = path.join(claudeRoot, slug);
|
|
36
|
+
let sessionCount = 0;
|
|
37
|
+
let lastModifiedMs = 0;
|
|
38
|
+
try {
|
|
39
|
+
const inside = await fs.readdir(projDir, { withFileTypes: true });
|
|
40
|
+
for (const f of inside) {
|
|
41
|
+
if (f.isFile() && f.name.toLowerCase().endsWith('.jsonl')) {
|
|
42
|
+
sessionCount++;
|
|
43
|
+
try {
|
|
44
|
+
const stat = await fs.stat(path.join(projDir, f.name));
|
|
45
|
+
if (stat.mtimeMs > lastModifiedMs)
|
|
46
|
+
lastModifiedMs = stat.mtimeMs;
|
|
47
|
+
}
|
|
48
|
+
catch { /* ignore */ }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch { /* project dir disappeared mid-scan — skip its files */ }
|
|
53
|
+
let exists = false;
|
|
54
|
+
let initialized = false;
|
|
55
|
+
try {
|
|
56
|
+
const st = await fs.stat(decoded);
|
|
57
|
+
exists = st.isDirectory();
|
|
58
|
+
if (exists) {
|
|
59
|
+
try {
|
|
60
|
+
const cg = await fs.stat(path.join(decoded, '.specship'));
|
|
61
|
+
initialized = cg.isDirectory();
|
|
62
|
+
}
|
|
63
|
+
catch { /* not initialized — OK */ }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch { /* path missing — OK, still surface it so UI can flag it */ }
|
|
67
|
+
out.push({ slug, path: decoded, exists, initialized, sessionCount, lastModifiedMs });
|
|
68
|
+
}
|
|
69
|
+
// Recent activity first; ties broken by path.
|
|
70
|
+
out.sort((a, b) => {
|
|
71
|
+
if (b.lastModifiedMs !== a.lastModifiedMs)
|
|
72
|
+
return b.lastModifiedMs - a.lastModifiedMs;
|
|
73
|
+
return a.path.localeCompare(b.path);
|
|
74
|
+
});
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
// --- Watcher (singleton across the process) ---------------------------------
|
|
78
|
+
let watcher = null;
|
|
79
|
+
let lastSlugs = new Set();
|
|
80
|
+
let debounceHandle = null;
|
|
81
|
+
let watchedRoot = null;
|
|
82
|
+
function startWatcher(claudeRoot, verbose) {
|
|
83
|
+
if (watcher)
|
|
84
|
+
return;
|
|
85
|
+
watchedRoot = claudeRoot;
|
|
86
|
+
try {
|
|
87
|
+
watcher = watch(claudeRoot, { persistent: true }, () => {
|
|
88
|
+
scheduleRescan(claudeRoot);
|
|
89
|
+
});
|
|
90
|
+
if (verbose)
|
|
91
|
+
console.error(`[projects] watching ${claudeRoot}`);
|
|
92
|
+
// Warm the cache so the first SSE snapshot has accurate state and the
|
|
93
|
+
// first change diff is meaningful.
|
|
94
|
+
void enumerate(claudeRoot).then((list) => {
|
|
95
|
+
lastSlugs = new Set(list.map((p) => p.slug));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
if (verbose)
|
|
100
|
+
console.error(`[projects] watch failed for ${claudeRoot}:`, err instanceof Error ? err.message : String(err));
|
|
101
|
+
// Directory may not exist yet — that's OK, every /api/projects GET
|
|
102
|
+
// returns [] until it does. We don't retry here; if the watcher is
|
|
103
|
+
// critical the user can restart the server after creating it.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function scheduleRescan(claudeRoot) {
|
|
107
|
+
if (debounceHandle)
|
|
108
|
+
clearTimeout(debounceHandle);
|
|
109
|
+
debounceHandle = setTimeout(async () => {
|
|
110
|
+
debounceHandle = null;
|
|
111
|
+
const list = await enumerate(claudeRoot);
|
|
112
|
+
const newSlugs = new Set(list.map((p) => p.slug));
|
|
113
|
+
const added = list.filter((p) => !lastSlugs.has(p.slug));
|
|
114
|
+
const removed = [...lastSlugs].filter((s) => !newSlugs.has(s));
|
|
115
|
+
lastSlugs = newSlugs;
|
|
116
|
+
if (added.length || removed.length) {
|
|
117
|
+
projectsBus.emit('change', { added, removed, list });
|
|
118
|
+
}
|
|
119
|
+
// Refresh is always emitted so subscribers can pick up lastModified /
|
|
120
|
+
// sessionCount drift even without slug-level changes.
|
|
121
|
+
projectsBus.emit('refresh', { list });
|
|
122
|
+
}, 350);
|
|
123
|
+
}
|
|
124
|
+
function stopWatcher() {
|
|
125
|
+
if (watcher) {
|
|
126
|
+
try {
|
|
127
|
+
watcher.close();
|
|
128
|
+
}
|
|
129
|
+
catch { /* ignore */ }
|
|
130
|
+
watcher = null;
|
|
131
|
+
}
|
|
132
|
+
if (debounceHandle) {
|
|
133
|
+
clearTimeout(debounceHandle);
|
|
134
|
+
debounceHandle = null;
|
|
135
|
+
}
|
|
136
|
+
watchedRoot = null;
|
|
137
|
+
}
|
|
138
|
+
// --- Route registration -----------------------------------------------------
|
|
139
|
+
export async function registerProjectsRoutes(app) {
|
|
140
|
+
const claudeRoot = path.join(os.homedir(), '.claude', 'projects');
|
|
141
|
+
startWatcher(claudeRoot, false);
|
|
142
|
+
app.addHook('onClose', async () => { stopWatcher(); });
|
|
143
|
+
app.get('/api/projects', async () => {
|
|
144
|
+
return { claudeRoot, projects: await enumerate(claudeRoot) };
|
|
145
|
+
});
|
|
146
|
+
app.get('/api/projects/events', async (req, reply) => {
|
|
147
|
+
reply.raw.setHeader('Content-Type', 'text/event-stream');
|
|
148
|
+
reply.raw.setHeader('Cache-Control', 'no-cache');
|
|
149
|
+
reply.raw.setHeader('Connection', 'keep-alive');
|
|
150
|
+
reply.raw.flushHeaders();
|
|
151
|
+
let closed = false;
|
|
152
|
+
const onClose = () => {
|
|
153
|
+
closed = true;
|
|
154
|
+
projectsBus.off('change', onChange);
|
|
155
|
+
projectsBus.off('refresh', onRefresh);
|
|
156
|
+
clearInterval(hb);
|
|
157
|
+
};
|
|
158
|
+
req.raw.on('close', onClose);
|
|
159
|
+
const writeEvent = (event, data) => {
|
|
160
|
+
if (closed)
|
|
161
|
+
return;
|
|
162
|
+
try {
|
|
163
|
+
reply.raw.write(`event: ${event}\n`);
|
|
164
|
+
reply.raw.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
165
|
+
}
|
|
166
|
+
catch { /* socket gone */
|
|
167
|
+
closed = true;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const initial = await enumerate(claudeRoot);
|
|
171
|
+
lastSlugs = new Set(initial.map((p) => p.slug));
|
|
172
|
+
writeEvent('snapshot', { claudeRoot, projects: initial });
|
|
173
|
+
const onChange = (payload) => {
|
|
174
|
+
writeEvent('change', payload);
|
|
175
|
+
};
|
|
176
|
+
const onRefresh = (payload) => {
|
|
177
|
+
writeEvent('refresh', payload);
|
|
178
|
+
};
|
|
179
|
+
projectsBus.on('change', onChange);
|
|
180
|
+
projectsBus.on('refresh', onRefresh);
|
|
181
|
+
// Heartbeat keeps proxies / NATs from dropping the idle connection.
|
|
182
|
+
const hb = setInterval(() => {
|
|
183
|
+
if (closed) {
|
|
184
|
+
clearInterval(hb);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
reply.raw.write(`: ping\n\n`);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
onClose();
|
|
192
|
+
}
|
|
193
|
+
}, 30000);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Test seam — re-export so __tests__ can stop the watcher between cases. */
|
|
197
|
+
export const _testing = { stopWatcher, watchedRoot: () => watchedRoot };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reflection engine HTTP surface (REFLECT-DOC).
|
|
3
|
+
*
|
|
4
|
+
* GET /api/reflect — list persisted proposals (?state=open|applied|undone|dismissed)
|
|
5
|
+
* POST /api/reflect/analyze — run a reflection pass, persist, return open proposals
|
|
6
|
+
* GET /api/reflect/:hash/preview — non-mutating diff of the change a proposal would make
|
|
7
|
+
* POST /api/reflect/:hash/apply — preview-confirmed write (idempotent + reversible)
|
|
8
|
+
* POST /api/reflect/:hash/undo — reverse a previously applied proposal
|
|
9
|
+
* POST /api/reflect/:hash/dismiss — hide a proposal from future sweeps
|
|
10
|
+
*
|
|
11
|
+
* Like the tips engine, reflection reads the cross-project claude_* tables that
|
|
12
|
+
* live in the boot-time "primary" project's DB, so every handler resolves the
|
|
13
|
+
* primary instance and drives it through its `reflect*` methods. These are
|
|
14
|
+
* instance methods on the dynamically-loaded SpecShip — NOT a runtime package
|
|
15
|
+
* import — so the route never trips the stale-build hazard.
|
|
16
|
+
*/
|
|
17
|
+
export async function registerReflectRoutes(app) {
|
|
18
|
+
function requirePrimary(reply) {
|
|
19
|
+
if (!app.primaryCg) {
|
|
20
|
+
reply.code(409).send({ error: 'reflection unavailable: no primary project configured', code: 'no_primary' });
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return app.primaryCg;
|
|
24
|
+
}
|
|
25
|
+
// List persisted proposals, optionally filtered by state.
|
|
26
|
+
app.get('/api/reflect', async (req, reply) => {
|
|
27
|
+
const cg = requirePrimary(reply);
|
|
28
|
+
if (!cg)
|
|
29
|
+
return;
|
|
30
|
+
const state = req.query.state;
|
|
31
|
+
return { proposals: cg.reflectList(state) };
|
|
32
|
+
});
|
|
33
|
+
// Run a reflection pass: mine + persist + return the current open proposals.
|
|
34
|
+
app.post('/api/reflect/analyze', async (_req, reply) => {
|
|
35
|
+
const cg = requirePrimary(reply);
|
|
36
|
+
if (!cg)
|
|
37
|
+
return;
|
|
38
|
+
const result = cg.reflectAnalyze();
|
|
39
|
+
return { open: result.open, empty: result.empty };
|
|
40
|
+
});
|
|
41
|
+
// Non-mutating preview of a proposal's change (REQ-REFLECT-003).
|
|
42
|
+
app.get('/api/reflect/:hash/preview', async (req, reply) => {
|
|
43
|
+
const cg = requirePrimary(reply);
|
|
44
|
+
if (!cg)
|
|
45
|
+
return;
|
|
46
|
+
const preview = cg.reflectPreview(req.params.hash);
|
|
47
|
+
if (!preview) {
|
|
48
|
+
reply.code(404).send({ error: 'proposal not found', code: 'not_found' });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
return preview;
|
|
52
|
+
});
|
|
53
|
+
// Apply a proposal — preview-confirmed write (REQ-REFLECT-004).
|
|
54
|
+
app.post('/api/reflect/:hash/apply', async (req, reply) => {
|
|
55
|
+
const cg = requirePrimary(reply);
|
|
56
|
+
if (!cg)
|
|
57
|
+
return;
|
|
58
|
+
const outcome = cg.reflectApply(req.params.hash);
|
|
59
|
+
if (outcome === null) {
|
|
60
|
+
reply.code(404).send({ error: 'proposal not found', code: 'not_found' });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (outcome === 'conflict') {
|
|
64
|
+
reply.code(409).send({ error: 'a non-SpecShip file already occupies the target path', code: 'conflict' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return { outcome, proposal: cg.reflectGet(req.params.hash) };
|
|
68
|
+
});
|
|
69
|
+
// Undo a previously applied proposal (REQ-REFLECT-004.A3).
|
|
70
|
+
app.post('/api/reflect/:hash/undo', async (req, reply) => {
|
|
71
|
+
const cg = requirePrimary(reply);
|
|
72
|
+
if (!cg)
|
|
73
|
+
return;
|
|
74
|
+
const outcome = cg.reflectUndo(req.params.hash);
|
|
75
|
+
if (outcome === null) {
|
|
76
|
+
reply.code(404).send({ error: 'proposal not found', code: 'not_found' });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
return { outcome, proposal: cg.reflectGet(req.params.hash) };
|
|
80
|
+
});
|
|
81
|
+
// Dismiss a proposal so it does not resurface on later sweeps (REQ-REFLECT-007.A2).
|
|
82
|
+
app.post('/api/reflect/:hash/dismiss', async (req, reply) => {
|
|
83
|
+
const cg = requirePrimary(reply);
|
|
84
|
+
if (!cg)
|
|
85
|
+
return;
|
|
86
|
+
const ok = cg.reflectDismiss(req.params.hash);
|
|
87
|
+
if (!ok) {
|
|
88
|
+
reply.code(404).send({ error: 'proposal not found', code: 'not_found' });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
return { ok: true, proposal: cg.reflectGet(req.params.hash) };
|
|
92
|
+
});
|
|
93
|
+
}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec layer routes — list / fetch / link assert / link verify / drift queue.
|
|
3
|
+
* Plus the v0.2 write endpoints: PUT /api/spec/:id and POST /api/specs,
|
|
4
|
+
* which let the dashboard's Monaco editor save spec edits back to disk.
|
|
5
|
+
*
|
|
6
|
+
* Every route is project-scoped via `?project=<slug>` (falls back to the
|
|
7
|
+
* boot-time primary). Returns 409 / `no_project` when neither is selectable.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
/**
|
|
12
|
+
* Resolve a project-relative path to an absolute path under the project
|
|
13
|
+
* root, refusing anything that escapes the root (path-traversal guard).
|
|
14
|
+
* Returns null when the resolved path is outside the project — caller
|
|
15
|
+
* surfaces 400 in that case.
|
|
16
|
+
*/
|
|
17
|
+
function safeProjectPath(projectRoot, relPath) {
|
|
18
|
+
// Strip leading slashes so absolute paths in user input don't blow past
|
|
19
|
+
// path.resolve's "drop earlier components" behavior.
|
|
20
|
+
const cleaned = relPath.replace(/^[/\\]+/, '');
|
|
21
|
+
const abs = path.resolve(projectRoot, cleaned);
|
|
22
|
+
const rootResolved = path.resolve(projectRoot);
|
|
23
|
+
const rel = path.relative(rootResolved, abs);
|
|
24
|
+
if (rel.startsWith('..') || path.isAbsolute(rel))
|
|
25
|
+
return null;
|
|
26
|
+
return abs;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract the `brief:` value from the leading YAML frontmatter block of a
|
|
30
|
+
* spec source file (between the first pair of `---` fences). Returns null
|
|
31
|
+
* when there is no frontmatter, no `brief:` key, or the value is empty.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately dependency-free: a simple line scan that mirrors the style
|
|
34
|
+
* used by `MarkdownSpecExtractor.parseFrontmatter`. Exported so tests can
|
|
35
|
+
* exercise the parsing logic in isolation.
|
|
36
|
+
*/
|
|
37
|
+
export function parseBriefField(source) {
|
|
38
|
+
const lines = source.split(/\r?\n/);
|
|
39
|
+
if (lines.length === 0 || (lines[0] ?? '').trim() !== '---')
|
|
40
|
+
return null;
|
|
41
|
+
// Find the closing `---` fence.
|
|
42
|
+
let closingIdx = -1;
|
|
43
|
+
for (let i = 1; i < lines.length; i++) {
|
|
44
|
+
if ((lines[i] ?? '').trim() === '---') {
|
|
45
|
+
closingIdx = i;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (closingIdx === -1)
|
|
50
|
+
return null;
|
|
51
|
+
// Scan frontmatter body for `brief: <value>`.
|
|
52
|
+
for (let i = 1; i < closingIdx; i++) {
|
|
53
|
+
const line = (lines[i] ?? '').trim();
|
|
54
|
+
if (!line.startsWith('brief:'))
|
|
55
|
+
continue;
|
|
56
|
+
let value = line.slice('brief:'.length).trim();
|
|
57
|
+
if (!value)
|
|
58
|
+
return null;
|
|
59
|
+
// Strip surrounding quotes.
|
|
60
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
61
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
62
|
+
value = value.slice(1, -1).trim();
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Strip a trailing ` # comment` from an UNQUOTED value only. Requires
|
|
66
|
+
// whitespace before the `#` so a `#fragment` inside the path — or a `#`
|
|
67
|
+
// inside a quoted value (handled above) — isn't mangled.
|
|
68
|
+
const hashIdx = value.search(/\s#/);
|
|
69
|
+
if (hashIdx !== -1)
|
|
70
|
+
value = value.slice(0, hashIdx).trim();
|
|
71
|
+
}
|
|
72
|
+
return value || null;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Atomic file write: tmp + rename. Mirrors `atomicWriteFileSync` in
|
|
78
|
+
* `src/installer/targets/shared.ts` — kept local here to avoid the
|
|
79
|
+
* @selvakumaresra/specship deep-import dance for a 10-line helper.
|
|
80
|
+
*/
|
|
81
|
+
function atomicWriteFile(targetPath, content) {
|
|
82
|
+
const dir = path.dirname(targetPath);
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
const tmp = `${targetPath}.tmp.${process.pid}.${Date.now()}`;
|
|
85
|
+
fs.writeFileSync(tmp, content, 'utf-8');
|
|
86
|
+
fs.renameSync(tmp, targetPath);
|
|
87
|
+
}
|
|
88
|
+
async function resolveCg(app, req, reply) {
|
|
89
|
+
const cg = await app.activeCg(req);
|
|
90
|
+
if (!cg) {
|
|
91
|
+
reply.code(409).send({ error: 'no project selected', code: 'no_project' });
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return cg;
|
|
95
|
+
}
|
|
96
|
+
export async function registerSpecRoutes(app) {
|
|
97
|
+
app.get('/api/specs', async (req, reply) => {
|
|
98
|
+
const cg = await resolveCg(app, req, reply);
|
|
99
|
+
if (!cg)
|
|
100
|
+
return;
|
|
101
|
+
const docs = cg.getSpecQueries().getAllSpecs();
|
|
102
|
+
return { specs: docs };
|
|
103
|
+
});
|
|
104
|
+
// Spec lifecycle funnel: idea → spec → implemented (REQ-FUNNEL-006). Computed
|
|
105
|
+
// on the dynamically-loaded SpecShip instance — no runtime import of the
|
|
106
|
+
// package from the server.
|
|
107
|
+
app.get('/api/spec/funnel', async (req, reply) => {
|
|
108
|
+
const cg = await resolveCg(app, req, reply);
|
|
109
|
+
if (!cg)
|
|
110
|
+
return;
|
|
111
|
+
return cg.getSpecFunnel();
|
|
112
|
+
});
|
|
113
|
+
app.get('/api/spec/:id', async (req, reply) => {
|
|
114
|
+
const cg = await resolveCg(app, req, reply);
|
|
115
|
+
if (!cg)
|
|
116
|
+
return;
|
|
117
|
+
const sq = cg.getSpecQueries();
|
|
118
|
+
const spec = sq.getSpecById(req.params.id);
|
|
119
|
+
if (!spec)
|
|
120
|
+
return reply.code(404).send({ error: 'spec not found' });
|
|
121
|
+
const parent = spec.parentId ? sq.getSpecById(spec.parentId) : null;
|
|
122
|
+
const children = sq.getSpecsByParent(spec.id);
|
|
123
|
+
const siblings = parent ? sq.getSpecsByParent(parent.id).filter((s) => s.id !== spec.id) : [];
|
|
124
|
+
const links = sq.getLinksBySpec(spec.id);
|
|
125
|
+
// Per-child links so the detail page can show each acceptance criterion's
|
|
126
|
+
// met/unmet state and an "N / M met" rollup (DASH-SPECDETAIL-DOC, REQ-004).
|
|
127
|
+
const childLinks = {};
|
|
128
|
+
for (const c of children)
|
|
129
|
+
childLinks[c.id] = sq.getLinksBySpec(c.id);
|
|
130
|
+
// Read the raw source file so the dashboard's Monaco editor can edit
|
|
131
|
+
// the whole document, not just the DB-parsed body fragment for this
|
|
132
|
+
// requirement. The `spec.body` field stores per-section content; the
|
|
133
|
+
// editor needs the file.
|
|
134
|
+
let source = null;
|
|
135
|
+
try {
|
|
136
|
+
const projectRoot = cg.getProjectRoot();
|
|
137
|
+
const absPath = safeProjectPath(projectRoot, spec.sourcePath);
|
|
138
|
+
if (absPath && fs.existsSync(absPath)) {
|
|
139
|
+
source = fs.readFileSync(absPath, 'utf-8');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// File missing or unreadable — return null so the UI can show a
|
|
144
|
+
// "source not available" hint without failing the whole fetch.
|
|
145
|
+
}
|
|
146
|
+
return { spec, parent, siblings, children, links, childLinks, source };
|
|
147
|
+
});
|
|
148
|
+
/**
|
|
149
|
+
* GET /api/spec/:id/brief — return the brainstorm brief for a spec.
|
|
150
|
+
*
|
|
151
|
+
* Reads the spec's source file, parses the `brief:` frontmatter key, and
|
|
152
|
+
* returns the brief markdown from the path it names. The `brief:` value is
|
|
153
|
+
* resolved relative to the spec file's own directory (so a nested spec at
|
|
154
|
+
* `specs/area/foo.md` with `brief: foo/brief.md` resolves to
|
|
155
|
+
* `specs/area/foo/brief.md`). safeProjectPath guards against traversal.
|
|
156
|
+
*/
|
|
157
|
+
app.get('/api/spec/:id/brief', async (req, reply) => {
|
|
158
|
+
const cg = await resolveCg(app, req, reply);
|
|
159
|
+
if (!cg)
|
|
160
|
+
return;
|
|
161
|
+
const spec = cg.getSpecQueries().getSpecById(req.params.id);
|
|
162
|
+
if (!spec)
|
|
163
|
+
return reply.code(404).send({ error: 'spec not found' });
|
|
164
|
+
const projectRoot = cg.getProjectRoot();
|
|
165
|
+
const specAbs = safeProjectPath(projectRoot, spec.sourcePath);
|
|
166
|
+
if (!specAbs)
|
|
167
|
+
return reply.code(404).send({ error: 'no brief' });
|
|
168
|
+
// TOCTOU: read directly under try/catch rather than existsSync-then-read,
|
|
169
|
+
// so a file deleted between the check and the read degrades to 404 (the
|
|
170
|
+
// sibling GET /api/spec/:id read is guarded the same way) instead of 500.
|
|
171
|
+
let specSource;
|
|
172
|
+
try {
|
|
173
|
+
specSource = fs.readFileSync(specAbs, 'utf-8');
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return reply.code(404).send({ error: 'no brief' });
|
|
177
|
+
}
|
|
178
|
+
const briefRel = parseBriefField(specSource);
|
|
179
|
+
if (!briefRel)
|
|
180
|
+
return reply.code(404).send({ error: 'no brief' });
|
|
181
|
+
// CONVENTION: `brief:` is relative to the SPEC FILE's own directory (resolves
|
|
182
|
+
// whether the spec is flat at specs/<id>.md or nested at specs/<area>/<id>.md).
|
|
183
|
+
// safeProjectPath GUARDS against traversal outside the project root.
|
|
184
|
+
const briefAbs = safeProjectPath(projectRoot, path.join(path.dirname(spec.sourcePath), briefRel));
|
|
185
|
+
if (!briefAbs)
|
|
186
|
+
return reply.code(404).send({ error: 'no brief' });
|
|
187
|
+
try {
|
|
188
|
+
return { path: briefRel, markdown: fs.readFileSync(briefAbs, 'utf-8') };
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return reply.code(404).send({ error: 'no brief' });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
app.get('/api/drift', async (req, reply) => {
|
|
195
|
+
const cg = await resolveCg(app, req, reply);
|
|
196
|
+
if (!cg)
|
|
197
|
+
return;
|
|
198
|
+
const sq = cg.getSpecQueries();
|
|
199
|
+
const validStates = [
|
|
200
|
+
'drafted', 'implementing', 'implemented', 'verified',
|
|
201
|
+
'drifted', 'broken', 'orphaned',
|
|
202
|
+
];
|
|
203
|
+
const requested = (req.query.state ?? 'drifted,broken,orphaned')
|
|
204
|
+
.split(',')
|
|
205
|
+
.map((s) => s.trim())
|
|
206
|
+
.filter((s) => validStates.includes(s));
|
|
207
|
+
const limit = Math.min(parseInt(req.query.limit ?? '100', 10) || 100, 500);
|
|
208
|
+
const links = sq.getLinksByState(requested).slice(0, limit);
|
|
209
|
+
const out = links.map((l) => {
|
|
210
|
+
const spec = sq.getSpecById(l.specId);
|
|
211
|
+
return { ...l, specTitle: spec?.title ?? null };
|
|
212
|
+
});
|
|
213
|
+
return { links: out };
|
|
214
|
+
});
|
|
215
|
+
app.post('/api/spec/link-assert', async (req, reply) => {
|
|
216
|
+
const cg = await resolveCg(app, req, reply);
|
|
217
|
+
if (!cg)
|
|
218
|
+
return;
|
|
219
|
+
const body = req.body;
|
|
220
|
+
if (!body?.spec_id || !body.target_file_path || !body.target_qualified_name) {
|
|
221
|
+
return reply.code(400).send({ error: 'spec_id, target_file_path, target_qualified_name required' });
|
|
222
|
+
}
|
|
223
|
+
const sq = cg.getSpecQueries();
|
|
224
|
+
const spec = sq.getSpecById(body.spec_id);
|
|
225
|
+
if (!spec)
|
|
226
|
+
return reply.code(404).send({ error: 'spec not found' });
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const id = sq.upsertSpecLink({
|
|
229
|
+
specId: body.spec_id,
|
|
230
|
+
targetFilePath: body.target_file_path,
|
|
231
|
+
targetQualifiedName: body.target_qualified_name,
|
|
232
|
+
targetNodeKind: body.target_node_kind ?? 'function',
|
|
233
|
+
resolvedNodeId: undefined,
|
|
234
|
+
kind: body.kind ?? 'implements',
|
|
235
|
+
state: 'implemented',
|
|
236
|
+
driftAxis: null,
|
|
237
|
+
specHashAtLink: spec.contentHash,
|
|
238
|
+
nodeSigAtLink: undefined,
|
|
239
|
+
provenance: 'agent-asserted',
|
|
240
|
+
confidence: 1.0,
|
|
241
|
+
createdAt: now,
|
|
242
|
+
updatedAt: now,
|
|
243
|
+
});
|
|
244
|
+
cg.getSpecLinkResolver().resolveLinksForFiles([body.target_file_path]);
|
|
245
|
+
return { id, ok: true };
|
|
246
|
+
});
|
|
247
|
+
app.post('/api/spec/link-verify', async (req, reply) => {
|
|
248
|
+
const cg = await resolveCg(app, req, reply);
|
|
249
|
+
if (!cg)
|
|
250
|
+
return;
|
|
251
|
+
const body = req.body;
|
|
252
|
+
if (typeof body?.link_id !== 'number' || (body.result !== 'pass' && body.result !== 'fail')) {
|
|
253
|
+
return reply.code(400).send({ error: 'link_id (number) and result ("pass"|"fail") required' });
|
|
254
|
+
}
|
|
255
|
+
const sq = cg.getSpecQueries();
|
|
256
|
+
const link = sq.getLinkById(body.link_id);
|
|
257
|
+
if (!link)
|
|
258
|
+
return reply.code(404).send({ error: 'link not found' });
|
|
259
|
+
sq.updateSpecLinkState(body.link_id, body.result === 'pass' ? 'verified' : 'broken', null);
|
|
260
|
+
return { ok: true, state: body.result === 'pass' ? 'verified' : 'broken' };
|
|
261
|
+
});
|
|
262
|
+
/**
|
|
263
|
+
* PUT /api/spec/:id — overwrite the spec file backing this spec.
|
|
264
|
+
*
|
|
265
|
+
* Resolves the source file path from the existing spec row, validates it's
|
|
266
|
+
* under the project root (path-traversal guard), atomically writes the new
|
|
267
|
+
* content, then re-syncs the project so the indexer picks up the change.
|
|
268
|
+
* Returns the freshly re-parsed spec node. Used by the dashboard's Monaco
|
|
269
|
+
* editor.
|
|
270
|
+
*/
|
|
271
|
+
app.put('/api/spec/:id', async (req, reply) => {
|
|
272
|
+
const cg = await resolveCg(app, req, reply);
|
|
273
|
+
if (!cg)
|
|
274
|
+
return;
|
|
275
|
+
const sq = cg.getSpecQueries();
|
|
276
|
+
const spec = sq.getSpecById(req.params.id);
|
|
277
|
+
if (!spec)
|
|
278
|
+
return reply.code(404).send({ error: 'spec not found' });
|
|
279
|
+
const body = req.body;
|
|
280
|
+
if (typeof body?.content !== 'string') {
|
|
281
|
+
return reply.code(400).send({ error: 'content (string) required' });
|
|
282
|
+
}
|
|
283
|
+
const projectRoot = cg.getProjectRoot();
|
|
284
|
+
const absPath = safeProjectPath(projectRoot, spec.sourcePath);
|
|
285
|
+
if (!absPath) {
|
|
286
|
+
return reply.code(400).send({
|
|
287
|
+
error: 'spec.sourcePath resolves outside project root',
|
|
288
|
+
code: 'path_traversal',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
atomicWriteFile(absPath, body.content);
|
|
293
|
+
}
|
|
294
|
+
catch (e) {
|
|
295
|
+
return reply.code(500).send({
|
|
296
|
+
error: 'failed to write spec file',
|
|
297
|
+
detail: e instanceof Error ? e.message : String(e),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Re-index so the freshly-edited spec replaces the old graph nodes.
|
|
301
|
+
// The Markdown extractor will rebuild the doc + REQs + acceptance
|
|
302
|
+
// children, and the link resolver re-runs against the new content
|
|
303
|
+
// hash so drift states transition correctly.
|
|
304
|
+
try {
|
|
305
|
+
await cg.sync();
|
|
306
|
+
}
|
|
307
|
+
catch (e) {
|
|
308
|
+
// Sync errors don't roll back the write — the file is on disk and
|
|
309
|
+
// the next sync will pick it up. Surface so the UI can show a
|
|
310
|
+
// "saved but not yet indexed" hint.
|
|
311
|
+
const updated = sq.getSpecById(req.params.id);
|
|
312
|
+
return {
|
|
313
|
+
ok: true,
|
|
314
|
+
spec: updated ?? spec,
|
|
315
|
+
syncError: e instanceof Error ? e.message : String(e),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const updated = sq.getSpecById(req.params.id);
|
|
319
|
+
return { ok: true, spec: updated ?? spec };
|
|
320
|
+
});
|
|
321
|
+
/**
|
|
322
|
+
* POST /api/specs — create a new spec file under the project's specs/
|
|
323
|
+
* directory.
|
|
324
|
+
*
|
|
325
|
+
* `filePath` is project-relative (e.g. `specs/billing.md`). 409 if the
|
|
326
|
+
* file already exists. Used by the dashboard's Draft-with-Claude flow
|
|
327
|
+
* for the optional "finalize via dashboard" path.
|
|
328
|
+
*/
|
|
329
|
+
app.post('/api/specs', async (req, reply) => {
|
|
330
|
+
const cg = await resolveCg(app, req, reply);
|
|
331
|
+
if (!cg)
|
|
332
|
+
return;
|
|
333
|
+
const body = req.body;
|
|
334
|
+
if (typeof body?.filePath !== 'string' || typeof body?.content !== 'string') {
|
|
335
|
+
return reply.code(400).send({ error: 'filePath and content (strings) required' });
|
|
336
|
+
}
|
|
337
|
+
const projectRoot = cg.getProjectRoot();
|
|
338
|
+
const absPath = safeProjectPath(projectRoot, body.filePath);
|
|
339
|
+
if (!absPath) {
|
|
340
|
+
return reply.code(400).send({
|
|
341
|
+
error: 'filePath resolves outside project root',
|
|
342
|
+
code: 'path_traversal',
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
if (fs.existsSync(absPath)) {
|
|
346
|
+
return reply.code(409).send({
|
|
347
|
+
error: 'file already exists',
|
|
348
|
+
code: 'file_exists',
|
|
349
|
+
filePath: body.filePath,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
atomicWriteFile(absPath, body.content);
|
|
354
|
+
}
|
|
355
|
+
catch (e) {
|
|
356
|
+
return reply.code(500).send({
|
|
357
|
+
error: 'failed to write spec file',
|
|
358
|
+
detail: e instanceof Error ? e.message : String(e),
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
await cg.sync();
|
|
363
|
+
}
|
|
364
|
+
catch (e) {
|
|
365
|
+
return {
|
|
366
|
+
ok: true,
|
|
367
|
+
filePath: body.filePath,
|
|
368
|
+
syncError: e instanceof Error ? e.message : String(e),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return { ok: true, filePath: body.filePath };
|
|
372
|
+
});
|
|
373
|
+
}
|