@isaacriehm/cairn-core 0.1.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/dist/.tsbuildinfo +1 -0
- package/dist/claude/error.d.ts +33 -0
- package/dist/claude/error.js +58 -0
- package/dist/claude/error.js.map +1 -0
- package/dist/claude/index.d.ts +3 -0
- package/dist/claude/index.js +3 -0
- package/dist/claude/index.js.map +1 -0
- package/dist/claude/runner.d.ts +11 -0
- package/dist/claude/runner.js +132 -0
- package/dist/claude/runner.js.map +1 -0
- package/dist/claude/types.d.ts +52 -0
- package/dist/claude/types.js +14 -0
- package/dist/claude/types.js.map +1 -0
- package/dist/context/checkpoint.d.ts +10 -0
- package/dist/context/checkpoint.js +29 -0
- package/dist/context/checkpoint.js.map +1 -0
- package/dist/context/handoff-builder.d.ts +11 -0
- package/dist/context/handoff-builder.js +268 -0
- package/dist/context/handoff-builder.js.map +1 -0
- package/dist/context/index.d.ts +11 -0
- package/dist/context/index.js +11 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/spec-delta.d.ts +47 -0
- package/dist/context/spec-delta.js +237 -0
- package/dist/context/spec-delta.js.map +1 -0
- package/dist/decision-capture/capture.d.ts +57 -0
- package/dist/decision-capture/capture.js +186 -0
- package/dist/decision-capture/capture.js.map +1 -0
- package/dist/decision-capture/extractor.d.ts +20 -0
- package/dist/decision-capture/extractor.js +103 -0
- package/dist/decision-capture/extractor.js.map +1 -0
- package/dist/decision-capture/id.d.ts +21 -0
- package/dist/decision-capture/id.js +60 -0
- package/dist/decision-capture/id.js.map +1 -0
- package/dist/decision-capture/index.d.ts +25 -0
- package/dist/decision-capture/index.js +21 -0
- package/dist/decision-capture/index.js.map +1 -0
- package/dist/decision-capture/prompt.d.ts +15 -0
- package/dist/decision-capture/prompt.js +68 -0
- package/dist/decision-capture/prompt.js.map +1 -0
- package/dist/decision-capture/refinement-prompt.d.ts +25 -0
- package/dist/decision-capture/refinement-prompt.js +146 -0
- package/dist/decision-capture/refinement-prompt.js.map +1 -0
- package/dist/decision-capture/refinement-schema.d.ts +52 -0
- package/dist/decision-capture/refinement-schema.js +61 -0
- package/dist/decision-capture/refinement-schema.js.map +1 -0
- package/dist/decision-capture/refinement.d.ts +60 -0
- package/dist/decision-capture/refinement.js +439 -0
- package/dist/decision-capture/refinement.js.map +1 -0
- package/dist/decision-capture/schema.d.ts +70 -0
- package/dist/decision-capture/schema.js +71 -0
- package/dist/decision-capture/schema.js.map +1 -0
- package/dist/decision-capture/types.d.ts +201 -0
- package/dist/decision-capture/types.js +20 -0
- package/dist/decision-capture/types.js.map +1 -0
- package/dist/decision-capture/writer.d.ts +90 -0
- package/dist/decision-capture/writer.js +267 -0
- package/dist/decision-capture/writer.js.map +1 -0
- package/dist/doctor/index.d.ts +48 -0
- package/dist/doctor/index.js +460 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/events/index.d.ts +15 -0
- package/dist/events/index.js +14 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/paths.d.ts +2 -0
- package/dist/events/paths.js +6 -0
- package/dist/events/paths.js.map +1 -0
- package/dist/events/reader.d.ts +40 -0
- package/dist/events/reader.js +139 -0
- package/dist/events/reader.js.map +1 -0
- package/dist/events/writer.d.ts +61 -0
- package/dist/events/writer.js +68 -0
- package/dist/events/writer.js.map +1 -0
- package/dist/frontend-types.d.ts +243 -0
- package/dist/frontend-types.js +15 -0
- package/dist/frontend-types.js.map +1 -0
- package/dist/gc/apply.d.ts +26 -0
- package/dist/gc/apply.js +48 -0
- package/dist/gc/apply.js.map +1 -0
- package/dist/gc/canary.d.ts +42 -0
- package/dist/gc/canary.js +134 -0
- package/dist/gc/canary.js.map +1 -0
- package/dist/gc/citation-integrity.d.ts +24 -0
- package/dist/gc/citation-integrity.js +151 -0
- package/dist/gc/citation-integrity.js.map +1 -0
- package/dist/gc/classify.d.ts +25 -0
- package/dist/gc/classify.js +89 -0
- package/dist/gc/classify.js.map +1 -0
- package/dist/gc/completion-integrity.d.ts +22 -0
- package/dist/gc/completion-integrity.js +165 -0
- package/dist/gc/completion-integrity.js.map +1 -0
- package/dist/gc/doc-gardening.d.ts +29 -0
- package/dist/gc/doc-gardening.js +146 -0
- package/dist/gc/doc-gardening.js.map +1 -0
- package/dist/gc/frontmatter.d.ts +35 -0
- package/dist/gc/frontmatter.js +105 -0
- package/dist/gc/frontmatter.js.map +1 -0
- package/dist/gc/generator-drift.d.ts +28 -0
- package/dist/gc/generator-drift.js +53 -0
- package/dist/gc/generator-drift.js.map +1 -0
- package/dist/gc/index.d.ts +42 -0
- package/dist/gc/index.js +30 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/gc/quality-update.d.ts +23 -0
- package/dist/gc/quality-update.js +69 -0
- package/dist/gc/quality-update.js.map +1 -0
- package/dist/gc/scope-coverage.d.ts +20 -0
- package/dist/gc/scope-coverage.js +70 -0
- package/dist/gc/scope-coverage.js.map +1 -0
- package/dist/gc/stub-hits.d.ts +31 -0
- package/dist/gc/stub-hits.js +78 -0
- package/dist/gc/stub-hits.js.map +1 -0
- package/dist/gc/sweep.d.ts +56 -0
- package/dist/gc/sweep.js +205 -0
- package/dist/gc/sweep.js.map +1 -0
- package/dist/gc/types.d.ts +129 -0
- package/dist/gc/types.js +26 -0
- package/dist/gc/types.js.map +1 -0
- package/dist/gc/walk-source.d.ts +14 -0
- package/dist/gc/walk-source.js +59 -0
- package/dist/gc/walk-source.js.map +1 -0
- package/dist/ground/drift.d.ts +8 -0
- package/dist/ground/drift.js +23 -0
- package/dist/ground/drift.js.map +1 -0
- package/dist/ground/frontmatter.d.ts +20 -0
- package/dist/ground/frontmatter.js +49 -0
- package/dist/ground/frontmatter.js.map +1 -0
- package/dist/ground/glob.d.ts +10 -0
- package/dist/ground/glob.js +46 -0
- package/dist/ground/glob.js.map +1 -0
- package/dist/ground/index.d.ts +16 -0
- package/dist/ground/index.js +11 -0
- package/dist/ground/index.js.map +1 -0
- package/dist/ground/ledgers.d.ts +18 -0
- package/dist/ground/ledgers.js +103 -0
- package/dist/ground/ledgers.js.map +1 -0
- package/dist/ground/manifest.d.ts +10 -0
- package/dist/ground/manifest.js +88 -0
- package/dist/ground/manifest.js.map +1 -0
- package/dist/ground/paths.d.ts +20 -0
- package/dist/ground/paths.js +61 -0
- package/dist/ground/paths.js.map +1 -0
- package/dist/ground/quality-grades.d.ts +11 -0
- package/dist/ground/quality-grades.js +98 -0
- package/dist/ground/quality-grades.js.map +1 -0
- package/dist/ground/schemas.d.ts +306 -0
- package/dist/ground/schemas.js +188 -0
- package/dist/ground/schemas.js.map +1 -0
- package/dist/ground/scope-index.d.ts +48 -0
- package/dist/ground/scope-index.js +120 -0
- package/dist/ground/scope-index.js.map +1 -0
- package/dist/ground/walk.d.ts +7 -0
- package/dist/ground/walk.js +53 -0
- package/dist/ground/walk.js.map +1 -0
- package/dist/hooks/bypass-detection.d.ts +28 -0
- package/dist/hooks/bypass-detection.js +106 -0
- package/dist/hooks/bypass-detection.js.map +1 -0
- package/dist/hooks/index.d.ts +12 -0
- package/dist/hooks/index.js +13 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/post-tool-use/allowlist-reader.d.ts +14 -0
- package/dist/hooks/post-tool-use/allowlist-reader.js +69 -0
- package/dist/hooks/post-tool-use/allowlist-reader.js.map +1 -0
- package/dist/hooks/post-tool-use/citation-scanner.d.ts +23 -0
- package/dist/hooks/post-tool-use/citation-scanner.js +59 -0
- package/dist/hooks/post-tool-use/citation-scanner.js.map +1 -0
- package/dist/hooks/post-tool-use/copy-scanner.d.ts +25 -0
- package/dist/hooks/post-tool-use/copy-scanner.js +192 -0
- package/dist/hooks/post-tool-use/copy-scanner.js.map +1 -0
- package/dist/hooks/post-tool-use/index.d.ts +19 -0
- package/dist/hooks/post-tool-use/index.js +15 -0
- package/dist/hooks/post-tool-use/index.js.map +1 -0
- package/dist/hooks/post-tool-use/ledger-cache.d.ts +32 -0
- package/dist/hooks/post-tool-use/ledger-cache.js +236 -0
- package/dist/hooks/post-tool-use/ledger-cache.js.map +1 -0
- package/dist/hooks/post-tool-use/legend-builder.d.ts +15 -0
- package/dist/hooks/post-tool-use/legend-builder.js +84 -0
- package/dist/hooks/post-tool-use/legend-builder.js.map +1 -0
- package/dist/hooks/post-tool-use/read-enricher.d.ts +13 -0
- package/dist/hooks/post-tool-use/read-enricher.js +157 -0
- package/dist/hooks/post-tool-use/read-enricher.js.map +1 -0
- package/dist/hooks/post-tool-use/write-guardian.d.ts +17 -0
- package/dist/hooks/post-tool-use/write-guardian.js +176 -0
- package/dist/hooks/post-tool-use/write-guardian.js.map +1 -0
- package/dist/hooks/read-enrich.d.ts +6 -0
- package/dist/hooks/read-enrich.js +11 -0
- package/dist/hooks/read-enrich.js.map +1 -0
- package/dist/hooks/runners/index.d.ts +12 -0
- package/dist/hooks/runners/index.js +11 -0
- package/dist/hooks/runners/index.js.map +1 -0
- package/dist/hooks/runners/payload.d.ts +32 -0
- package/dist/hooks/runners/payload.js +70 -0
- package/dist/hooks/runners/payload.js.map +1 -0
- package/dist/hooks/runners/session-end.d.ts +7 -0
- package/dist/hooks/runners/session-end.js +42 -0
- package/dist/hooks/runners/session-end.js.map +1 -0
- package/dist/hooks/runners/session-start.d.ts +10 -0
- package/dist/hooks/runners/session-start.js +167 -0
- package/dist/hooks/runners/session-start.js.map +1 -0
- package/dist/hooks/runners/stop.d.ts +18 -0
- package/dist/hooks/runners/stop.js +165 -0
- package/dist/hooks/runners/stop.js.map +1 -0
- package/dist/hooks/session-end.d.ts +5 -0
- package/dist/hooks/session-end.js +10 -0
- package/dist/hooks/session-end.js.map +1 -0
- package/dist/hooks/session-start.d.ts +7 -0
- package/dist/hooks/session-start.js +12 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/stop.d.ts +5 -0
- package/dist/hooks/stop.js +10 -0
- package/dist/hooks/stop.js.map +1 -0
- package/dist/hooks/write-guard.d.ts +6 -0
- package/dist/hooks/write-guard.js +11 -0
- package/dist/hooks/write-guard.js.map +1 -0
- package/dist/inbox.d.ts +17 -0
- package/dist/inbox.js +30 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/init/baseline-audit.d.ts +71 -0
- package/dist/init/baseline-audit.js +377 -0
- package/dist/init/baseline-audit.js.map +1 -0
- package/dist/init/brand-setup.d.ts +44 -0
- package/dist/init/brand-setup.js +201 -0
- package/dist/init/brand-setup.js.map +1 -0
- package/dist/init/daemon-autostart.d.ts +16 -0
- package/dist/init/daemon-autostart.js +95 -0
- package/dist/init/daemon-autostart.js.map +1 -0
- package/dist/init/detect.d.ts +25 -0
- package/dist/init/detect.js +319 -0
- package/dist/init/detect.js.map +1 -0
- package/dist/init/index.d.ts +32 -0
- package/dist/init/index.js +18 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/ingest-docs.d.ts +74 -0
- package/dist/init/ingest-docs.js +499 -0
- package/dist/init/ingest-docs.js.map +1 -0
- package/dist/init/init.d.ts +165 -0
- package/dist/init/init.js +1166 -0
- package/dist/init/init.js.map +1 -0
- package/dist/init/mapper-legacy.d.ts +148 -0
- package/dist/init/mapper-legacy.js +238 -0
- package/dist/init/mapper-legacy.js.map +1 -0
- package/dist/init/mapper-merge.d.ts +38 -0
- package/dist/init/mapper-merge.js +238 -0
- package/dist/init/mapper-merge.js.map +1 -0
- package/dist/init/mapper-parallel.d.ts +48 -0
- package/dist/init/mapper-parallel.js +409 -0
- package/dist/init/mapper-parallel.js.map +1 -0
- package/dist/init/mapper-prompts.d.ts +135 -0
- package/dist/init/mapper-prompts.js +189 -0
- package/dist/init/mapper-prompts.js.map +1 -0
- package/dist/init/mapper.d.ts +211 -0
- package/dist/init/mapper.js +151 -0
- package/dist/init/mapper.js.map +1 -0
- package/dist/init/module-slicer.d.ts +39 -0
- package/dist/init/module-slicer.js +809 -0
- package/dist/init/module-slicer.js.map +1 -0
- package/dist/init/multi-dev/index.d.ts +2 -0
- package/dist/init/multi-dev/index.js +2 -0
- package/dist/init/multi-dev/index.js.map +1 -0
- package/dist/init/multi-dev/install.d.ts +40 -0
- package/dist/init/multi-dev/install.js +139 -0
- package/dist/init/multi-dev/install.js.map +1 -0
- package/dist/init/preflight-guards.d.ts +42 -0
- package/dist/init/preflight-guards.js +108 -0
- package/dist/init/preflight-guards.js.map +1 -0
- package/dist/init/prompts.d.ts +61 -0
- package/dist/init/prompts.js +66 -0
- package/dist/init/prompts.js.map +1 -0
- package/dist/init/rules-merge/discover.d.ts +21 -0
- package/dist/init/rules-merge/discover.js +78 -0
- package/dist/init/rules-merge/discover.js.map +1 -0
- package/dist/init/rules-merge/index.d.ts +10 -0
- package/dist/init/rules-merge/index.js +6 -0
- package/dist/init/rules-merge/index.js.map +1 -0
- package/dist/init/rules-merge/ingest.d.ts +56 -0
- package/dist/init/rules-merge/ingest.js +336 -0
- package/dist/init/rules-merge/ingest.js.map +1 -0
- package/dist/init/rules-merge/keep-markers.d.ts +39 -0
- package/dist/init/rules-merge/keep-markers.js +97 -0
- package/dist/init/rules-merge/keep-markers.js.map +1 -0
- package/dist/init/rules-merge/parse-sections.d.ts +24 -0
- package/dist/init/rules-merge/parse-sections.js +71 -0
- package/dist/init/rules-merge/parse-sections.js.map +1 -0
- package/dist/init/rules-merge/regenerate.d.ts +33 -0
- package/dist/init/rules-merge/regenerate.js +163 -0
- package/dist/init/rules-merge/regenerate.js.map +1 -0
- package/dist/init/secrets.d.ts +18 -0
- package/dist/init/secrets.js +76 -0
- package/dist/init/secrets.js.map +1 -0
- package/dist/init/seed.d.ts +21 -0
- package/dist/init/seed.js +96 -0
- package/dist/init/seed.js.map +1 -0
- package/dist/init/setup-runners.d.ts +15 -0
- package/dist/init/setup-runners.js +143 -0
- package/dist/init/setup-runners.js.map +1 -0
- package/dist/init/source-comments/classify.d.ts +98 -0
- package/dist/init/source-comments/classify.js +244 -0
- package/dist/init/source-comments/classify.js.map +1 -0
- package/dist/init/source-comments/index.d.ts +8 -0
- package/dist/init/source-comments/index.js +5 -0
- package/dist/init/source-comments/index.js.map +1 -0
- package/dist/init/source-comments/ingest.d.ts +51 -0
- package/dist/init/source-comments/ingest.js +236 -0
- package/dist/init/source-comments/ingest.js.map +1 -0
- package/dist/init/source-comments/strip-replace.d.ts +106 -0
- package/dist/init/source-comments/strip-replace.js +284 -0
- package/dist/init/source-comments/strip-replace.js.map +1 -0
- package/dist/init/source-comments/walker.d.ts +65 -0
- package/dist/init/source-comments/walker.js +777 -0
- package/dist/init/source-comments/walker.js.map +1 -0
- package/dist/init/submodules.d.ts +48 -0
- package/dist/init/submodules.js +149 -0
- package/dist/init/submodules.js.map +1 -0
- package/dist/init/types.d.ts +55 -0
- package/dist/init/types.js +10 -0
- package/dist/init/types.js.map +1 -0
- package/dist/init/visual.d.ts +69 -0
- package/dist/init/visual.js +265 -0
- package/dist/init/visual.js.map +1 -0
- package/dist/init/walker.d.ts +82 -0
- package/dist/init/walker.js +585 -0
- package/dist/init/walker.js.map +1 -0
- package/dist/init/workflow-block.d.ts +34 -0
- package/dist/init/workflow-block.js +110 -0
- package/dist/init/workflow-block.js.map +1 -0
- package/dist/join/index.d.ts +67 -0
- package/dist/join/index.js +256 -0
- package/dist/join/index.js.map +1 -0
- package/dist/lock.d.ts +39 -0
- package/dist/lock.js +129 -0
- package/dist/lock.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/bootstrap-guard.d.ts +29 -0
- package/dist/mcp/bootstrap-guard.js +47 -0
- package/dist/mcp/bootstrap-guard.js.map +1 -0
- package/dist/mcp/context.d.ts +23 -0
- package/dist/mcp/context.js +9 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/errors.d.ts +17 -0
- package/dist/mcp/errors.js +23 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/history/index.d.ts +6 -0
- package/dist/mcp/history/index.js +5 -0
- package/dist/mcp/history/index.js.map +1 -0
- package/dist/mcp/history/prompt.d.ts +32 -0
- package/dist/mcp/history/prompt.js +99 -0
- package/dist/mcp/history/prompt.js.map +1 -0
- package/dist/mcp/history/schema.d.ts +58 -0
- package/dist/mcp/history/schema.js +41 -0
- package/dist/mcp/history/schema.js.map +1 -0
- package/dist/mcp/history/summarizer.d.ts +81 -0
- package/dist/mcp/history/summarizer.js +196 -0
- package/dist/mcp/history/summarizer.js.map +1 -0
- package/dist/mcp/history/walker.d.ts +57 -0
- package/dist/mcp/history/walker.js +156 -0
- package/dist/mcp/history/walker.js.map +1 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/path-allowlist.d.ts +29 -0
- package/dist/mcp/path-allowlist.js +71 -0
- package/dist/mcp/path-allowlist.js.map +1 -0
- package/dist/mcp/result.d.ts +8 -0
- package/dist/mcp/result.js +18 -0
- package/dist/mcp/result.js.map +1 -0
- package/dist/mcp/schemas.d.ts +192 -0
- package/dist/mcp/schemas.js +174 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/serve.d.ts +15 -0
- package/dist/mcp/serve.js +71 -0
- package/dist/mcp/serve.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.js +58 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/telemetry.d.ts +15 -0
- package/dist/mcp/telemetry.js +13 -0
- package/dist/mcp/telemetry.js.map +1 -0
- package/dist/mcp/tools/append-run-note.d.ts +18 -0
- package/dist/mcp/tools/append-run-note.js +47 -0
- package/dist/mcp/tools/append-run-note.js.map +1 -0
- package/dist/mcp/tools/append.d.ts +8 -0
- package/dist/mcp/tools/append.js +37 -0
- package/dist/mcp/tools/append.js.map +1 -0
- package/dist/mcp/tools/archive.d.ts +8 -0
- package/dist/mcp/tools/archive.js +72 -0
- package/dist/mcp/tools/archive.js.map +1 -0
- package/dist/mcp/tools/ask-operator.d.ts +34 -0
- package/dist/mcp/tools/ask-operator.js +97 -0
- package/dist/mcp/tools/ask-operator.js.map +1 -0
- package/dist/mcp/tools/canonical-for-topic.d.ts +6 -0
- package/dist/mcp/tools/canonical-for-topic.js +40 -0
- package/dist/mcp/tools/canonical-for-topic.js.map +1 -0
- package/dist/mcp/tools/decision-get.d.ts +6 -0
- package/dist/mcp/tools/decision-get.js +49 -0
- package/dist/mcp/tools/decision-get.js.map +1 -0
- package/dist/mcp/tools/decisions-for-symbol.d.ts +7 -0
- package/dist/mcp/tools/decisions-for-symbol.js +42 -0
- package/dist/mcp/tools/decisions-for-symbol.js.map +1 -0
- package/dist/mcp/tools/decisions-in-scope.d.ts +7 -0
- package/dist/mcp/tools/decisions-in-scope.js +47 -0
- package/dist/mcp/tools/decisions-in-scope.js.map +1 -0
- package/dist/mcp/tools/drop-task.d.ts +12 -0
- package/dist/mcp/tools/drop-task.js +68 -0
- package/dist/mcp/tools/drop-task.js.map +1 -0
- package/dist/mcp/tools/get-full.d.ts +7 -0
- package/dist/mcp/tools/get-full.js +46 -0
- package/dist/mcp/tools/get-full.js.map +1 -0
- package/dist/mcp/tools/ground-get.d.ts +7 -0
- package/dist/mcp/tools/ground-get.js +77 -0
- package/dist/mcp/tools/ground-get.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +3 -0
- package/dist/mcp/tools/index.js +40 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/invariant-get.d.ts +6 -0
- package/dist/mcp/tools/invariant-get.js +49 -0
- package/dist/mcp/tools/invariant-get.js.map +1 -0
- package/dist/mcp/tools/invariants-in-scope.d.ts +7 -0
- package/dist/mcp/tools/invariants-in-scope.js +62 -0
- package/dist/mcp/tools/invariants-in-scope.js.map +1 -0
- package/dist/mcp/tools/query-history.d.ts +20 -0
- package/dist/mcp/tools/query-history.js +51 -0
- package/dist/mcp/tools/query-history.js.map +1 -0
- package/dist/mcp/tools/record-decision.d.ts +14 -0
- package/dist/mcp/tools/record-decision.js +98 -0
- package/dist/mcp/tools/record-decision.js.map +1 -0
- package/dist/mcp/tools/record-run-event.d.ts +10 -0
- package/dist/mcp/tools/record-run-event.js +32 -0
- package/dist/mcp/tools/record-run-event.js.map +1 -0
- package/dist/mcp/tools/resolve-attention.d.ts +31 -0
- package/dist/mcp/tools/resolve-attention.js +191 -0
- package/dist/mcp/tools/resolve-attention.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +9 -0
- package/dist/mcp/tools/search.js +164 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/tools/supersedes-chain.d.ts +6 -0
- package/dist/mcp/tools/supersedes-chain.js +66 -0
- package/dist/mcp/tools/supersedes-chain.js.map +1 -0
- package/dist/mcp/tools/timeline.d.ts +9 -0
- package/dist/mcp/tools/timeline.js +65 -0
- package/dist/mcp/tools/timeline.js.map +1 -0
- package/dist/mcp/tools/types.d.ts +9 -0
- package/dist/mcp/tools/types.js +2 -0
- package/dist/mcp/tools/types.js.map +1 -0
- package/dist/mirror/clone.d.ts +6 -0
- package/dist/mirror/clone.js +48 -0
- package/dist/mirror/clone.js.map +1 -0
- package/dist/mirror/dirty-overlap.d.ts +13 -0
- package/dist/mirror/dirty-overlap.js +42 -0
- package/dist/mirror/dirty-overlap.js.map +1 -0
- package/dist/mirror/index.d.ts +7 -0
- package/dist/mirror/index.js +7 -0
- package/dist/mirror/index.js.map +1 -0
- package/dist/mirror/paths.d.ts +18 -0
- package/dist/mirror/paths.js +45 -0
- package/dist/mirror/paths.js.map +1 -0
- package/dist/mirror/push.d.ts +9 -0
- package/dist/mirror/push.js +27 -0
- package/dist/mirror/push.js.map +1 -0
- package/dist/mirror/state.d.ts +4 -0
- package/dist/mirror/state.js +36 -0
- package/dist/mirror/state.js.map +1 -0
- package/dist/mirror/sync.d.ts +9 -0
- package/dist/mirror/sync.js +33 -0
- package/dist/mirror/sync.js.map +1 -0
- package/dist/mirror/types.d.ts +77 -0
- package/dist/mirror/types.js +2 -0
- package/dist/mirror/types.js.map +1 -0
- package/dist/paths/index.d.ts +23 -0
- package/dist/paths/index.js +50 -0
- package/dist/paths/index.js.map +1 -0
- package/dist/profiles/index.d.ts +3 -0
- package/dist/profiles/index.js +3 -0
- package/dist/profiles/index.js.map +1 -0
- package/dist/profiles/registry.d.ts +5 -0
- package/dist/profiles/registry.js +31 -0
- package/dist/profiles/registry.js.map +1 -0
- package/dist/profiles/types.d.ts +48 -0
- package/dist/profiles/types.js +11 -0
- package/dist/profiles/types.js.map +1 -0
- package/dist/profiles/unknown.d.ts +9 -0
- package/dist/profiles/unknown.js +17 -0
- package/dist/profiles/unknown.js.map +1 -0
- package/dist/prompt.d.ts +19 -0
- package/dist/prompt.js +50 -0
- package/dist/prompt.js.map +1 -0
- package/dist/sensors/attestation.d.ts +44 -0
- package/dist/sensors/attestation.js +262 -0
- package/dist/sensors/attestation.js.map +1 -0
- package/dist/sensors/catalog.d.ts +41 -0
- package/dist/sensors/catalog.js +123 -0
- package/dist/sensors/catalog.js.map +1 -0
- package/dist/sensors/decisions.d.ts +30 -0
- package/dist/sensors/decisions.js +393 -0
- package/dist/sensors/decisions.js.map +1 -0
- package/dist/sensors/diff.d.ts +27 -0
- package/dist/sensors/diff.js +148 -0
- package/dist/sensors/diff.js.map +1 -0
- package/dist/sensors/index.d.ts +13 -0
- package/dist/sensors/index.js +9 -0
- package/dist/sensors/index.js.map +1 -0
- package/dist/sensors/remediation.d.ts +20 -0
- package/dist/sensors/remediation.js +65 -0
- package/dist/sensors/remediation.js.map +1 -0
- package/dist/sensors/runner.d.ts +44 -0
- package/dist/sensors/runner.js +95 -0
- package/dist/sensors/runner.js.map +1 -0
- package/dist/sensors/structural.d.ts +30 -0
- package/dist/sensors/structural.js +204 -0
- package/dist/sensors/structural.js.map +1 -0
- package/dist/sensors/stub-catalog.d.ts +39 -0
- package/dist/sensors/stub-catalog.js +115 -0
- package/dist/sensors/stub-catalog.js.map +1 -0
- package/dist/sensors/types.d.ts +135 -0
- package/dist/sensors/types.js +14 -0
- package/dist/sensors/types.js.map +1 -0
- package/dist/session/events-marker.d.ts +39 -0
- package/dist/session/events-marker.js +74 -0
- package/dist/session/events-marker.js.map +1 -0
- package/dist/session/id.d.ts +83 -0
- package/dist/session/id.js +166 -0
- package/dist/session/id.js.map +1 -0
- package/dist/session/index.d.ts +14 -0
- package/dist/session/index.js +13 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session-start/build.d.ts +53 -0
- package/dist/session-start/build.js +645 -0
- package/dist/session-start/build.js.map +1 -0
- package/dist/session-start/index.d.ts +18 -0
- package/dist/session-start/index.js +18 -0
- package/dist/session-start/index.js.map +1 -0
- package/dist/session-start/templates.d.ts +6 -0
- package/dist/session-start/templates.js +38 -0
- package/dist/session-start/templates.js.map +1 -0
- package/dist/status-line/format.d.ts +14 -0
- package/dist/status-line/format.js +40 -0
- package/dist/status-line/format.js.map +1 -0
- package/dist/status-line/index.d.ts +29 -0
- package/dist/status-line/index.js +14 -0
- package/dist/status-line/index.js.map +1 -0
- package/dist/status-line/reader.d.ts +13 -0
- package/dist/status-line/reader.js +76 -0
- package/dist/status-line/reader.js.map +1 -0
- package/dist/status-line/writer.d.ts +33 -0
- package/dist/status-line/writer.js +72 -0
- package/dist/status-line/writer.js.map +1 -0
- package/dist/tier0/classify.d.ts +10 -0
- package/dist/tier0/classify.js +110 -0
- package/dist/tier0/classify.js.map +1 -0
- package/dist/tier0/index.d.ts +2 -0
- package/dist/tier0/index.js +2 -0
- package/dist/tier0/index.js.map +1 -0
- package/dist/tier0/ollama.d.ts +22 -0
- package/dist/tier0/ollama.js +63 -0
- package/dist/tier0/ollama.js.map +1 -0
- package/dist/tier0/types.d.ts +24 -0
- package/dist/tier0/types.js +9 -0
- package/dist/tier0/types.js.map +1 -0
- package/dist/tightener/index.d.ts +4 -0
- package/dist/tightener/index.js +4 -0
- package/dist/tightener/index.js.map +1 -0
- package/dist/tightener/prompt.d.ts +3 -0
- package/dist/tightener/prompt.js +67 -0
- package/dist/tightener/prompt.js.map +1 -0
- package/dist/tightener/schema.d.ts +68 -0
- package/dist/tightener/schema.js +44 -0
- package/dist/tightener/schema.js.map +1 -0
- package/dist/tightener/tighten.d.ts +2 -0
- package/dist/tightener/tighten.js +66 -0
- package/dist/tightener/tighten.js.map +1 -0
- package/dist/tightener/types.d.ts +74 -0
- package/dist/tightener/types.js +6 -0
- package/dist/tightener/types.js.map +1 -0
- package/dist/voice/index.d.ts +4 -0
- package/dist/voice/index.js +4 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/model.d.ts +23 -0
- package/dist/voice/model.js +46 -0
- package/dist/voice/model.js.map +1 -0
- package/dist/voice/pipe.d.ts +9 -0
- package/dist/voice/pipe.js +47 -0
- package/dist/voice/pipe.js.map +1 -0
- package/dist/voice/transcribe.d.ts +3 -0
- package/dist/voice/transcribe.js +43 -0
- package/dist/voice/transcribe.js.map +1 -0
- package/dist/voice/types.d.ts +26 -0
- package/dist/voice/types.js +9 -0
- package/dist/voice/types.js.map +1 -0
- package/package.json +54 -0
- package/templates/.archive/README.md +67 -0
- package/templates/.cairn/JOIN.md +87 -0
- package/templates/.cairn/config/sensors.yaml +185 -0
- package/templates/.cairn/config/stub-patterns.yaml +231 -0
- package/templates/.cairn/config/trust-policy.yaml +95 -0
- package/templates/.cairn/config/workflow.md +230 -0
- package/templates/.cairn/git-hooks/commit-msg +17 -0
- package/templates/.cairn/git-hooks/post-commit +28 -0
- package/templates/.cairn/git-hooks/pre-commit +24 -0
- package/templates/.cairn/ground/brand/overview.md +24 -0
- package/templates/.cairn/ground/brand/voice.md +20 -0
- package/templates/.cairn/ground/canonical-map/topics.yaml +54 -0
- package/templates/.cairn/ground/capabilities/mcp-tools.yaml +4 -0
- package/templates/.cairn/ground/capabilities/skills.yaml +3 -0
- package/templates/.cairn/ground/capabilities/snippets.yaml +3 -0
- package/templates/.cairn/ground/manifest.yaml +16 -0
- package/templates/.cairn/ground/product/personas.yaml +4 -0
- package/templates/.cairn/ground/product/positioning.md +21 -0
- package/templates/.claude/settings.json +57 -0
- package/templates/.github/workflows/cairn-check.yml +31 -0
- package/templates/.mcp.json +8 -0
- package/templates/README.md +24 -0
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module slicer — partitions a repo into per-module slices for the chunked
|
|
3
|
+
* parallel mapper. Each ModuleSlice is the focused input one Sonnet call sees.
|
|
4
|
+
*
|
|
5
|
+
* Per `docs/INIT_SPEC.md` §3 (chunked parallel path):
|
|
6
|
+
* - Detect modules via .gitmodules, pnpm/yarn/lerna workspaces, top-level
|
|
7
|
+
* package.json children, OR top-level dirs with >20 source files.
|
|
8
|
+
* - Single-package repos collapse to one slice covering the whole repo.
|
|
9
|
+
* - Each slice carries: directory tree (paths only), package.json (full),
|
|
10
|
+
* up to 5 representative files (full content), local docs (capped).
|
|
11
|
+
*
|
|
12
|
+
* The mapper-parallel module dispatches one Sonnet call per slice, and the
|
|
13
|
+
* merge call assembles the per-module proposals into a single MapperOutput.
|
|
14
|
+
*/
|
|
15
|
+
import { execFileSync } from "node:child_process";
|
|
16
|
+
import { existsSync, readFileSync, readdirSync, statSync, } from "node:fs";
|
|
17
|
+
import { basename, join, relative } from "node:path";
|
|
18
|
+
import { parse as parseYaml } from "yaml";
|
|
19
|
+
import { logger } from "../logger.js";
|
|
20
|
+
const log = logger("init.module-slicer");
|
|
21
|
+
const SOURCE_EXTS = new Set([
|
|
22
|
+
".ts",
|
|
23
|
+
".tsx",
|
|
24
|
+
".js",
|
|
25
|
+
".jsx",
|
|
26
|
+
".mjs",
|
|
27
|
+
".cjs",
|
|
28
|
+
".py",
|
|
29
|
+
".rb",
|
|
30
|
+
".go",
|
|
31
|
+
".rs",
|
|
32
|
+
".java",
|
|
33
|
+
".kt",
|
|
34
|
+
".swift",
|
|
35
|
+
".php",
|
|
36
|
+
".cs",
|
|
37
|
+
".ex",
|
|
38
|
+
".exs",
|
|
39
|
+
".c",
|
|
40
|
+
".cc",
|
|
41
|
+
".cpp",
|
|
42
|
+
".h",
|
|
43
|
+
".hpp",
|
|
44
|
+
]);
|
|
45
|
+
const SKIP_DIRS = new Set([
|
|
46
|
+
".git",
|
|
47
|
+
"node_modules",
|
|
48
|
+
"dist",
|
|
49
|
+
"build",
|
|
50
|
+
"target",
|
|
51
|
+
"out",
|
|
52
|
+
"__pycache__",
|
|
53
|
+
"vendor",
|
|
54
|
+
".venv",
|
|
55
|
+
".direnv",
|
|
56
|
+
".cache",
|
|
57
|
+
"coverage",
|
|
58
|
+
".next",
|
|
59
|
+
".turbo",
|
|
60
|
+
".nuxt",
|
|
61
|
+
".svelte-kit",
|
|
62
|
+
".astro",
|
|
63
|
+
".parcel-cache",
|
|
64
|
+
".vercel",
|
|
65
|
+
".netlify",
|
|
66
|
+
".pytest_cache",
|
|
67
|
+
".mypy_cache",
|
|
68
|
+
".ruff_cache",
|
|
69
|
+
".tox",
|
|
70
|
+
".gradle",
|
|
71
|
+
".idea",
|
|
72
|
+
".vscode",
|
|
73
|
+
".cairn",
|
|
74
|
+
".archive",
|
|
75
|
+
]);
|
|
76
|
+
const TOPLEVEL_MODULE_MIN_FILES = 20;
|
|
77
|
+
const REPRESENTATIVE_FILE_BUDGET = 5;
|
|
78
|
+
const LOCAL_DOCS_CHAR_CAP = 8000;
|
|
79
|
+
const REPRESENTATIVE_FILE_CHAR_CAP = 12000;
|
|
80
|
+
const DIRECTORY_TREE_LINE_CAP = 800;
|
|
81
|
+
/**
|
|
82
|
+
* Per-module thresholds that drive the pre-dispatch split.
|
|
83
|
+
*
|
|
84
|
+
* A monolithic backend module (~400 source files) trips Sonnet's per-call
|
|
85
|
+
* latency / token-budget far past parallel sweet spot, so any module above
|
|
86
|
+
* `LARGE_MODULE_SOURCE_THRESHOLD` is broken into sub-slices on its top-level
|
|
87
|
+
* subdirs. Sub-slices below `SUBSLICE_SOURCE_THRESHOLD` aren't worth a call;
|
|
88
|
+
* we cap at `MAX_SUBSLICES_PER_PARENT` highest-source-count subdirs and let
|
|
89
|
+
* the parent stay if no subdir clears the floor.
|
|
90
|
+
*/
|
|
91
|
+
const LARGE_MODULE_SOURCE_THRESHOLD = 150;
|
|
92
|
+
const SUBSLICE_SOURCE_THRESHOLD = 20;
|
|
93
|
+
const MAX_SUBSLICES_PER_PARENT = 6;
|
|
94
|
+
export function sliceModules(args) {
|
|
95
|
+
const repoRoot = args.repoRoot;
|
|
96
|
+
const detected = detectModuleRoots(repoRoot);
|
|
97
|
+
log.info({
|
|
98
|
+
repo_root: repoRoot,
|
|
99
|
+
detected: detected.length,
|
|
100
|
+
sources: [...new Set(detected.map((d) => d.source))],
|
|
101
|
+
}, "module roots detected");
|
|
102
|
+
const out = [];
|
|
103
|
+
if (detected.length === 0) {
|
|
104
|
+
// Single-package: one slice covers the whole repo. Don't split — single-
|
|
105
|
+
// package init is the common case; sub-slicing here would over-fragment.
|
|
106
|
+
const tree = listModuleTree(repoRoot, repoRoot);
|
|
107
|
+
out.push(buildSliceFromTree({
|
|
108
|
+
repoRoot,
|
|
109
|
+
moduleAbsPath: repoRoot,
|
|
110
|
+
moduleRel: ".",
|
|
111
|
+
tree,
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
for (const d of detected) {
|
|
116
|
+
const tree = listModuleTree(repoRoot, d.absPath);
|
|
117
|
+
const parentSlice = buildSliceFromTree({
|
|
118
|
+
repoRoot,
|
|
119
|
+
moduleAbsPath: d.absPath,
|
|
120
|
+
moduleRel: d.relPath,
|
|
121
|
+
tree,
|
|
122
|
+
});
|
|
123
|
+
const subs = maybeSplitLargeModule({
|
|
124
|
+
parentSlice,
|
|
125
|
+
parentRelPaths: tree.relPaths,
|
|
126
|
+
repoRoot,
|
|
127
|
+
});
|
|
128
|
+
if (subs !== null) {
|
|
129
|
+
log.info({
|
|
130
|
+
parent: parentSlice.moduleSlug,
|
|
131
|
+
parent_files: tree.relPaths.length,
|
|
132
|
+
children: subs.map((s) => s.moduleSlug),
|
|
133
|
+
}, "large module split into sub-slices");
|
|
134
|
+
out.push(...subs);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
out.push(parentSlice);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (args.maxSlices !== undefined && out.length > args.maxSlices) {
|
|
142
|
+
return out.slice(0, args.maxSlices);
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* If `parentSlice` exceeds LARGE_MODULE_SOURCE_THRESHOLD, walk one level
|
|
148
|
+
* deeper into its top-level subdirs and return up to MAX_SUBSLICES_PER_PARENT
|
|
149
|
+
* sub-slices (those with > SUBSLICE_SOURCE_THRESHOLD source files, picked
|
|
150
|
+
* highest-count first). Returns `null` when the module shouldn't or can't
|
|
151
|
+
* be split (under threshold, no subdir clears the floor, or the module's
|
|
152
|
+
* source files all live at module root).
|
|
153
|
+
*/
|
|
154
|
+
/**
|
|
155
|
+
* Conventional wrappers we transparently descend through when the parent
|
|
156
|
+
* module's source all lives under a single one of these. Without this, a
|
|
157
|
+
* module like `core/{src/auth,src/billing,src/integrations,...}` would split
|
|
158
|
+
* into one sub-slice named `core/src` instead of `core/auth`, `core/billing`,
|
|
159
|
+
* `core/integrations` — useless.
|
|
160
|
+
*/
|
|
161
|
+
const TRANSPARENT_WRAPPER_DIRS = new Set(["src", "lib", "app", "source"]);
|
|
162
|
+
const MAX_TRANSPARENT_DESCENT = 2;
|
|
163
|
+
function maybeSplitLargeModule(args) {
|
|
164
|
+
const sourceCount = countSourceFilesInPaths(args.parentRelPaths);
|
|
165
|
+
if (sourceCount <= LARGE_MODULE_SOURCE_THRESHOLD)
|
|
166
|
+
return null;
|
|
167
|
+
// Walk forward through any transparent wrappers (`src/` etc.) so the split
|
|
168
|
+
// happens at the meaningful directory layer.
|
|
169
|
+
let workingPaths = args.parentRelPaths;
|
|
170
|
+
let wrapperPrefix = "";
|
|
171
|
+
for (let depth = 0; depth < MAX_TRANSPARENT_DESCENT; depth++) {
|
|
172
|
+
const initial = pickSubdirCandidates(workingPaths);
|
|
173
|
+
if (initial.length !== 1)
|
|
174
|
+
break;
|
|
175
|
+
const onlyCandidate = initial[0];
|
|
176
|
+
if (onlyCandidate === undefined)
|
|
177
|
+
break;
|
|
178
|
+
const [name] = onlyCandidate;
|
|
179
|
+
if (!TRANSPARENT_WRAPPER_DIRS.has(name))
|
|
180
|
+
break;
|
|
181
|
+
workingPaths = workingPaths
|
|
182
|
+
.filter((p) => p === name || p.startsWith(`${name}/`))
|
|
183
|
+
.map((p) => (p.startsWith(`${name}/`) ? p.slice(name.length + 1) : p));
|
|
184
|
+
wrapperPrefix = wrapperPrefix === "" ? name : `${wrapperPrefix}/${name}`;
|
|
185
|
+
}
|
|
186
|
+
// Group source files + all files at the (possibly post-wrapper) layer.
|
|
187
|
+
const sourceCounts = new Map();
|
|
188
|
+
const childPathsByDir = new Map();
|
|
189
|
+
for (const rel of workingPaths) {
|
|
190
|
+
const slash = rel.indexOf("/");
|
|
191
|
+
if (slash < 0)
|
|
192
|
+
continue; // top-level files of the working layer — stay with parent
|
|
193
|
+
const top = rel.slice(0, slash);
|
|
194
|
+
const remainder = rel.slice(slash + 1);
|
|
195
|
+
if (SOURCE_EXTS.has(extOf(rel))) {
|
|
196
|
+
sourceCounts.set(top, (sourceCounts.get(top) ?? 0) + 1);
|
|
197
|
+
}
|
|
198
|
+
let bucket = childPathsByDir.get(top);
|
|
199
|
+
if (bucket === undefined) {
|
|
200
|
+
bucket = [];
|
|
201
|
+
childPathsByDir.set(top, bucket);
|
|
202
|
+
}
|
|
203
|
+
bucket.push(remainder);
|
|
204
|
+
}
|
|
205
|
+
const candidates = [...sourceCounts.entries()]
|
|
206
|
+
.filter(([, n]) => n >= SUBSLICE_SOURCE_THRESHOLD)
|
|
207
|
+
.sort((a, b) => b[1] - a[1])
|
|
208
|
+
.slice(0, MAX_SUBSLICES_PER_PARENT);
|
|
209
|
+
if (candidates.length === 0)
|
|
210
|
+
return null;
|
|
211
|
+
const subs = [];
|
|
212
|
+
for (const [subdir] of candidates) {
|
|
213
|
+
const subRelPaths = (childPathsByDir.get(subdir) ?? []).sort();
|
|
214
|
+
// Filesystem path includes the transparent wrapper (so files are
|
|
215
|
+
// reachable on disk); display slug + moduleRel collapse it for the
|
|
216
|
+
// operator-friendly form ("core/auth", not "core/src/auth").
|
|
217
|
+
const subAbsPath = wrapperPrefix === ""
|
|
218
|
+
? join(args.parentSlice.modulePath, subdir)
|
|
219
|
+
: join(args.parentSlice.modulePath, wrapperPrefix, subdir);
|
|
220
|
+
const subRel = args.parentSlice.moduleRel === "."
|
|
221
|
+
? subdir
|
|
222
|
+
: `${args.parentSlice.moduleRel}/${subdir}`;
|
|
223
|
+
subs.push(buildSliceFromTree({
|
|
224
|
+
repoRoot: args.repoRoot,
|
|
225
|
+
moduleAbsPath: subAbsPath,
|
|
226
|
+
moduleRel: subRel,
|
|
227
|
+
tree: { relPaths: subRelPaths, contentCache: new Map() },
|
|
228
|
+
// Sub-slices typically share the parent module's package.json and
|
|
229
|
+
// overarching docs — pass them in as fallbacks. The sub-slice still
|
|
230
|
+
// prefers its own package.json / docs if they exist.
|
|
231
|
+
parentFallbackPackageJson: args.parentSlice.packageJson,
|
|
232
|
+
parentFallbackDocs: args.parentSlice.localDocs,
|
|
233
|
+
// Keep the prefixed slug so progress display / merge see "core/auth"
|
|
234
|
+
// rather than just "auth".
|
|
235
|
+
explicitSlug: subRel,
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
return subs;
|
|
239
|
+
}
|
|
240
|
+
function pickSubdirCandidates(paths) {
|
|
241
|
+
const counts = new Map();
|
|
242
|
+
for (const rel of paths) {
|
|
243
|
+
const slash = rel.indexOf("/");
|
|
244
|
+
if (slash < 0)
|
|
245
|
+
continue;
|
|
246
|
+
if (!SOURCE_EXTS.has(extOf(rel)))
|
|
247
|
+
continue;
|
|
248
|
+
const top = rel.slice(0, slash);
|
|
249
|
+
counts.set(top, (counts.get(top) ?? 0) + 1);
|
|
250
|
+
}
|
|
251
|
+
return [...counts.entries()]
|
|
252
|
+
.filter(([, n]) => n >= SUBSLICE_SOURCE_THRESHOLD)
|
|
253
|
+
.sort((a, b) => b[1] - a[1]);
|
|
254
|
+
}
|
|
255
|
+
function countSourceFilesInPaths(paths) {
|
|
256
|
+
let n = 0;
|
|
257
|
+
for (const p of paths) {
|
|
258
|
+
if (SOURCE_EXTS.has(extOf(p)))
|
|
259
|
+
n++;
|
|
260
|
+
}
|
|
261
|
+
return n;
|
|
262
|
+
}
|
|
263
|
+
function detectModuleRoots(repoRoot) {
|
|
264
|
+
const found = new Map();
|
|
265
|
+
// 1. .gitmodules — every submodule is a hard module boundary.
|
|
266
|
+
for (const path of readGitmodulePaths(repoRoot)) {
|
|
267
|
+
const abs = join(repoRoot, path);
|
|
268
|
+
if (!existsSync(abs))
|
|
269
|
+
continue;
|
|
270
|
+
found.set(path, { absPath: abs, relPath: path, source: "submodule" });
|
|
271
|
+
}
|
|
272
|
+
// 2. Workspace configs — pnpm / yarn / lerna.
|
|
273
|
+
for (const path of readWorkspaceMembers(repoRoot)) {
|
|
274
|
+
if (found.has(path))
|
|
275
|
+
continue;
|
|
276
|
+
const abs = join(repoRoot, path);
|
|
277
|
+
if (!existsSync(abs) || !statSync(abs).isDirectory())
|
|
278
|
+
continue;
|
|
279
|
+
found.set(path, { absPath: abs, relPath: path, source: "workspace" });
|
|
280
|
+
}
|
|
281
|
+
// 3. Top-level dirs with their own package.json.
|
|
282
|
+
for (const path of readTopLevelPackages(repoRoot)) {
|
|
283
|
+
if (found.has(path))
|
|
284
|
+
continue;
|
|
285
|
+
const abs = join(repoRoot, path);
|
|
286
|
+
found.set(path, { absPath: abs, relPath: path, source: "package-json" });
|
|
287
|
+
}
|
|
288
|
+
// 4. If still empty, fall back to heuristic — top-level dirs with >20
|
|
289
|
+
// source files become modules.
|
|
290
|
+
if (found.size === 0) {
|
|
291
|
+
for (const path of readHeuristicModules(repoRoot)) {
|
|
292
|
+
const abs = join(repoRoot, path);
|
|
293
|
+
found.set(path, { absPath: abs, relPath: path, source: "heuristic" });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return [...found.values()].sort((a, b) => a.relPath.localeCompare(b.relPath));
|
|
297
|
+
}
|
|
298
|
+
function readGitmodulePaths(repoRoot) {
|
|
299
|
+
const path = join(repoRoot, ".gitmodules");
|
|
300
|
+
if (!existsSync(path))
|
|
301
|
+
return [];
|
|
302
|
+
try {
|
|
303
|
+
const text = readFileSync(path, "utf8");
|
|
304
|
+
const out = [];
|
|
305
|
+
for (const line of text.split(/\r?\n/)) {
|
|
306
|
+
const m = line.match(/^\s*path\s*=\s*(.+)\s*$/);
|
|
307
|
+
if (m && m[1])
|
|
308
|
+
out.push(m[1].trim());
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return [];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function readWorkspaceMembers(repoRoot) {
|
|
317
|
+
const out = new Set();
|
|
318
|
+
// pnpm
|
|
319
|
+
const pnpm = join(repoRoot, "pnpm-workspace.yaml");
|
|
320
|
+
if (existsSync(pnpm)) {
|
|
321
|
+
try {
|
|
322
|
+
const parsed = parseYaml(readFileSync(pnpm, "utf8"));
|
|
323
|
+
const pkgs = parsed["packages"];
|
|
324
|
+
if (Array.isArray(pkgs)) {
|
|
325
|
+
for (const glob of pkgs) {
|
|
326
|
+
if (typeof glob !== "string")
|
|
327
|
+
continue;
|
|
328
|
+
for (const p of expandWorkspaceGlob(repoRoot, glob))
|
|
329
|
+
out.add(p);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// ignore
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// yarn / npm — root package.json `workspaces`
|
|
338
|
+
const rootPkg = join(repoRoot, "package.json");
|
|
339
|
+
if (existsSync(rootPkg)) {
|
|
340
|
+
try {
|
|
341
|
+
const parsed = JSON.parse(readFileSync(rootPkg, "utf8"));
|
|
342
|
+
const ws = parsed["workspaces"];
|
|
343
|
+
const globs = Array.isArray(ws)
|
|
344
|
+
? ws.filter((s) => typeof s === "string")
|
|
345
|
+
: typeof ws === "object" && ws !== null && Array.isArray(ws["packages"])
|
|
346
|
+
? ws["packages"].filter((s) => typeof s === "string")
|
|
347
|
+
: [];
|
|
348
|
+
for (const g of globs) {
|
|
349
|
+
for (const p of expandWorkspaceGlob(repoRoot, g))
|
|
350
|
+
out.add(p);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// ignore
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// lerna
|
|
358
|
+
const lerna = join(repoRoot, "lerna.json");
|
|
359
|
+
if (existsSync(lerna)) {
|
|
360
|
+
try {
|
|
361
|
+
const parsed = JSON.parse(readFileSync(lerna, "utf8"));
|
|
362
|
+
const pkgs = parsed["packages"];
|
|
363
|
+
if (Array.isArray(pkgs)) {
|
|
364
|
+
for (const g of pkgs) {
|
|
365
|
+
if (typeof g !== "string")
|
|
366
|
+
continue;
|
|
367
|
+
for (const p of expandWorkspaceGlob(repoRoot, g))
|
|
368
|
+
out.add(p);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
// ignore
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return [...out];
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Expand a workspace glob like `packages/*` or `apps/*` into actual directory
|
|
380
|
+
* paths relative to repoRoot. Supports trailing `/*` and `/**` only —
|
|
381
|
+
* sufficient for every workspace config we've seen in the wild. Returns
|
|
382
|
+
* directories only (not files).
|
|
383
|
+
*/
|
|
384
|
+
function expandWorkspaceGlob(repoRoot, glob) {
|
|
385
|
+
const trimmed = glob.replace(/\/(\*\*?|\*)$/, "");
|
|
386
|
+
const isWildcard = glob.endsWith("/*") || glob.endsWith("/**");
|
|
387
|
+
const baseAbs = join(repoRoot, trimmed);
|
|
388
|
+
if (!existsSync(baseAbs))
|
|
389
|
+
return [];
|
|
390
|
+
if (!isWildcard) {
|
|
391
|
+
if (statSync(baseAbs).isDirectory())
|
|
392
|
+
return [trimmed];
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
let entries;
|
|
396
|
+
try {
|
|
397
|
+
entries = readdirSync(baseAbs);
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
return [];
|
|
401
|
+
}
|
|
402
|
+
const out = [];
|
|
403
|
+
for (const name of entries) {
|
|
404
|
+
if (SKIP_DIRS.has(name))
|
|
405
|
+
continue;
|
|
406
|
+
const abs = join(baseAbs, name);
|
|
407
|
+
try {
|
|
408
|
+
if (statSync(abs).isDirectory()) {
|
|
409
|
+
out.push(trimmed === "" ? name : `${trimmed}/${name}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
// skip
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return out;
|
|
417
|
+
}
|
|
418
|
+
function readTopLevelPackages(repoRoot) {
|
|
419
|
+
let entries;
|
|
420
|
+
try {
|
|
421
|
+
entries = readdirSync(repoRoot);
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
const out = [];
|
|
427
|
+
for (const name of entries) {
|
|
428
|
+
if (SKIP_DIRS.has(name))
|
|
429
|
+
continue;
|
|
430
|
+
const abs = join(repoRoot, name);
|
|
431
|
+
try {
|
|
432
|
+
if (!statSync(abs).isDirectory())
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (existsSync(join(abs, "package.json")))
|
|
439
|
+
out.push(name);
|
|
440
|
+
}
|
|
441
|
+
return out;
|
|
442
|
+
}
|
|
443
|
+
function readHeuristicModules(repoRoot) {
|
|
444
|
+
let entries;
|
|
445
|
+
try {
|
|
446
|
+
entries = readdirSync(repoRoot);
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
return [];
|
|
450
|
+
}
|
|
451
|
+
const out = [];
|
|
452
|
+
for (const name of entries) {
|
|
453
|
+
if (SKIP_DIRS.has(name))
|
|
454
|
+
continue;
|
|
455
|
+
if (name.startsWith("."))
|
|
456
|
+
continue;
|
|
457
|
+
const abs = join(repoRoot, name);
|
|
458
|
+
try {
|
|
459
|
+
if (!statSync(abs).isDirectory())
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
if (countSourceFiles(abs) >= TOPLEVEL_MODULE_MIN_FILES) {
|
|
466
|
+
out.push(name);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return out;
|
|
470
|
+
}
|
|
471
|
+
function countSourceFiles(dir) {
|
|
472
|
+
let n = 0;
|
|
473
|
+
const stack = [dir];
|
|
474
|
+
while (stack.length > 0 && n < TOPLEVEL_MODULE_MIN_FILES + 1) {
|
|
475
|
+
const cur = stack.pop();
|
|
476
|
+
if (cur === undefined)
|
|
477
|
+
break;
|
|
478
|
+
let entries;
|
|
479
|
+
try {
|
|
480
|
+
entries = readdirSync(cur);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
for (const name of entries) {
|
|
486
|
+
if (SKIP_DIRS.has(name))
|
|
487
|
+
continue;
|
|
488
|
+
const abs = join(cur, name);
|
|
489
|
+
let s;
|
|
490
|
+
try {
|
|
491
|
+
s = statSync(abs);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (s.isDirectory()) {
|
|
497
|
+
stack.push(abs);
|
|
498
|
+
}
|
|
499
|
+
else if (s.isFile()) {
|
|
500
|
+
const ext = extOf(name);
|
|
501
|
+
if (SOURCE_EXTS.has(ext))
|
|
502
|
+
n++;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return n;
|
|
507
|
+
}
|
|
508
|
+
function extOf(name) {
|
|
509
|
+
const idx = name.lastIndexOf(".");
|
|
510
|
+
return idx === -1 ? "" : name.slice(idx).toLowerCase();
|
|
511
|
+
}
|
|
512
|
+
function buildSliceFromTree(args) {
|
|
513
|
+
const moduleAbsPath = args.moduleAbsPath;
|
|
514
|
+
const moduleRel = args.moduleRel;
|
|
515
|
+
const moduleSlug = args.explicitSlug !== undefined
|
|
516
|
+
? args.explicitSlug
|
|
517
|
+
: moduleRel === "."
|
|
518
|
+
? basename(args.repoRoot) || "root"
|
|
519
|
+
: basename(moduleRel);
|
|
520
|
+
const directoryTree = capLines(args.tree.relPaths, DIRECTORY_TREE_LINE_CAP);
|
|
521
|
+
const ownPackageJson = readIfExists(join(moduleAbsPath, "package.json"));
|
|
522
|
+
const packageJson = ownPackageJson !== null
|
|
523
|
+
? ownPackageJson
|
|
524
|
+
: args.parentFallbackPackageJson ?? null;
|
|
525
|
+
const representativeFiles = pickRepresentativeFiles({
|
|
526
|
+
moduleAbsPath,
|
|
527
|
+
moduleRel,
|
|
528
|
+
relPaths: args.tree.relPaths,
|
|
529
|
+
contentByPath: args.tree.contentCache,
|
|
530
|
+
});
|
|
531
|
+
const ownDocs = readLocalDocs(moduleAbsPath, args.tree.relPaths);
|
|
532
|
+
const localDocs = ownDocs !== null ? ownDocs : args.parentFallbackDocs ?? null;
|
|
533
|
+
return {
|
|
534
|
+
modulePath: moduleAbsPath,
|
|
535
|
+
moduleRel,
|
|
536
|
+
moduleSlug,
|
|
537
|
+
directoryTree,
|
|
538
|
+
packageJson,
|
|
539
|
+
representativeFiles,
|
|
540
|
+
localDocs,
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
function listModuleTree(repoRoot, moduleAbsPath) {
|
|
544
|
+
// Try git ls-files filtered to the module path first; falls back to FS walk.
|
|
545
|
+
const fromGit = tryGitLsModule(repoRoot, moduleAbsPath);
|
|
546
|
+
if (fromGit !== null) {
|
|
547
|
+
return { relPaths: fromGit.sort(), contentCache: new Map() };
|
|
548
|
+
}
|
|
549
|
+
const out = [];
|
|
550
|
+
const stack = [moduleAbsPath];
|
|
551
|
+
while (stack.length > 0) {
|
|
552
|
+
const cur = stack.pop();
|
|
553
|
+
if (cur === undefined)
|
|
554
|
+
break;
|
|
555
|
+
let entries;
|
|
556
|
+
try {
|
|
557
|
+
entries = readdirSync(cur);
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
for (const name of entries) {
|
|
563
|
+
if (SKIP_DIRS.has(name))
|
|
564
|
+
continue;
|
|
565
|
+
const abs = join(cur, name);
|
|
566
|
+
let s;
|
|
567
|
+
try {
|
|
568
|
+
s = statSync(abs);
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (s.isDirectory()) {
|
|
574
|
+
stack.push(abs);
|
|
575
|
+
}
|
|
576
|
+
else if (s.isFile()) {
|
|
577
|
+
out.push(relative(moduleAbsPath, abs).split("\\").join("/"));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return { relPaths: out.sort(), contentCache: new Map() };
|
|
582
|
+
}
|
|
583
|
+
function tryGitLsModule(repoRoot, moduleAbsPath) {
|
|
584
|
+
const isRoot = moduleAbsPath === repoRoot;
|
|
585
|
+
// Submodules are their own git worktree — ls-files from the submodule itself.
|
|
586
|
+
const cwdForGit = moduleAbsPath;
|
|
587
|
+
if (!existsSync(join(cwdForGit, ".git"))) {
|
|
588
|
+
// Not a git worktree. If we're inside the parent repo, we can still ls
|
|
589
|
+
// the module subset by prefix-filtering.
|
|
590
|
+
if (!isRoot && existsSync(join(repoRoot, ".git"))) {
|
|
591
|
+
try {
|
|
592
|
+
const out = execFileSync("git", [
|
|
593
|
+
"-C",
|
|
594
|
+
repoRoot,
|
|
595
|
+
"ls-files",
|
|
596
|
+
"--cached",
|
|
597
|
+
"--others",
|
|
598
|
+
"--exclude-standard",
|
|
599
|
+
"-z",
|
|
600
|
+
"--",
|
|
601
|
+
relative(repoRoot, moduleAbsPath),
|
|
602
|
+
], { encoding: "buffer", maxBuffer: 100 * 1024 * 1024 });
|
|
603
|
+
const prefix = relative(repoRoot, moduleAbsPath) + "/";
|
|
604
|
+
return out
|
|
605
|
+
.toString("utf8")
|
|
606
|
+
.split("\0")
|
|
607
|
+
.filter((s) => s.length > 0)
|
|
608
|
+
.map((p) => (p.startsWith(prefix) ? p.slice(prefix.length) : p));
|
|
609
|
+
}
|
|
610
|
+
catch {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
const out = execFileSync("git", [
|
|
618
|
+
"-C",
|
|
619
|
+
cwdForGit,
|
|
620
|
+
"ls-files",
|
|
621
|
+
"--cached",
|
|
622
|
+
"--others",
|
|
623
|
+
"--exclude-standard",
|
|
624
|
+
"-z",
|
|
625
|
+
], { encoding: "buffer", maxBuffer: 100 * 1024 * 1024 });
|
|
626
|
+
return out
|
|
627
|
+
.toString("utf8")
|
|
628
|
+
.split("\0")
|
|
629
|
+
.filter((s) => s.length > 0);
|
|
630
|
+
}
|
|
631
|
+
catch {
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function capLines(lines, cap) {
|
|
636
|
+
if (lines.length <= cap)
|
|
637
|
+
return lines.join("\n");
|
|
638
|
+
const head = lines.slice(0, cap);
|
|
639
|
+
return [...head, `… (${lines.length - cap} more files truncated)`].join("\n");
|
|
640
|
+
}
|
|
641
|
+
function readIfExists(path) {
|
|
642
|
+
if (!existsSync(path))
|
|
643
|
+
return null;
|
|
644
|
+
try {
|
|
645
|
+
return readFileSync(path, "utf8");
|
|
646
|
+
}
|
|
647
|
+
catch {
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function pickRepresentativeFiles(args) {
|
|
652
|
+
const picked = new Map();
|
|
653
|
+
const tryAdd = (rel) => {
|
|
654
|
+
if (picked.size >= REPRESENTATIVE_FILE_BUDGET)
|
|
655
|
+
return true;
|
|
656
|
+
if (picked.has(rel))
|
|
657
|
+
return false;
|
|
658
|
+
const abs = join(args.moduleAbsPath, rel);
|
|
659
|
+
let content = args.contentByPath.get(rel);
|
|
660
|
+
if (content === undefined) {
|
|
661
|
+
try {
|
|
662
|
+
content = readFileSync(abs, "utf8");
|
|
663
|
+
}
|
|
664
|
+
catch {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
args.contentByPath.set(rel, content);
|
|
668
|
+
}
|
|
669
|
+
if (content.length > REPRESENTATIVE_FILE_CHAR_CAP) {
|
|
670
|
+
content =
|
|
671
|
+
content.slice(0, REPRESENTATIVE_FILE_CHAR_CAP) +
|
|
672
|
+
`\n… (truncated; original ${content.length} chars)\n`;
|
|
673
|
+
}
|
|
674
|
+
picked.set(rel, content);
|
|
675
|
+
return picked.size >= REPRESENTATIVE_FILE_BUDGET;
|
|
676
|
+
};
|
|
677
|
+
// 1. Module-root entry points.
|
|
678
|
+
for (const candidate of ["index.ts", "index.tsx", "main.ts", "app.ts"]) {
|
|
679
|
+
if (args.relPaths.includes(candidate)) {
|
|
680
|
+
if (tryAdd(candidate))
|
|
681
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// 2. Largest *.controller.ts / *.service.ts by line count.
|
|
685
|
+
const ctrlServiceCandidates = args.relPaths.filter((p) => /\.(controller|service)\.(ts|tsx|js)$/i.test(p));
|
|
686
|
+
if (ctrlServiceCandidates.length > 0) {
|
|
687
|
+
let best = null;
|
|
688
|
+
for (const cand of ctrlServiceCandidates) {
|
|
689
|
+
const abs = join(args.moduleAbsPath, cand);
|
|
690
|
+
try {
|
|
691
|
+
const text = readFileSync(abs, "utf8");
|
|
692
|
+
args.contentByPath.set(cand, text);
|
|
693
|
+
const lines = text.split("\n").length;
|
|
694
|
+
if (best === null || lines > best.lines)
|
|
695
|
+
best = { path: cand, lines };
|
|
696
|
+
}
|
|
697
|
+
catch {
|
|
698
|
+
// skip unreadable
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if (best !== null) {
|
|
702
|
+
if (tryAdd(best.path))
|
|
703
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
// 3. Schema roots — drizzle, prisma, mongoose-style models.
|
|
707
|
+
for (const cand of args.relPaths) {
|
|
708
|
+
if (/(^|\/)(prisma\/schema\.prisma|src\/db\/schema\.ts|db\/schema\.ts|schema\.ts|models\/index\.ts)$/i.test(cand)) {
|
|
709
|
+
if (tryAdd(cand))
|
|
710
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
// 4. Most-imported file (approximate via grep for relative imports).
|
|
714
|
+
const mostImported = approximateMostImported({
|
|
715
|
+
moduleAbsPath: args.moduleAbsPath,
|
|
716
|
+
relPaths: args.relPaths,
|
|
717
|
+
});
|
|
718
|
+
if (mostImported !== null) {
|
|
719
|
+
if (tryAdd(mostImported))
|
|
720
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
721
|
+
}
|
|
722
|
+
// 5. Router-style entry points.
|
|
723
|
+
for (const cand of args.relPaths) {
|
|
724
|
+
if (/(^|\/)(router|routes|api)\.(ts|tsx|js)$/i.test(cand)) {
|
|
725
|
+
if (tryAdd(cand))
|
|
726
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return [...picked].map(([path, content]) => ({ path, content }));
|
|
730
|
+
}
|
|
731
|
+
function approximateMostImported(args) {
|
|
732
|
+
const sourceFiles = args.relPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs)$/i.test(p));
|
|
733
|
+
if (sourceFiles.length === 0)
|
|
734
|
+
return null;
|
|
735
|
+
const counts = new Map();
|
|
736
|
+
// Scan up to 200 source files for `from "./..."` or `from "../..."`.
|
|
737
|
+
// Each found relative-import target gets counted.
|
|
738
|
+
const scanCap = Math.min(sourceFiles.length, 200);
|
|
739
|
+
for (let i = 0; i < scanCap; i++) {
|
|
740
|
+
const rel = sourceFiles[i];
|
|
741
|
+
if (rel === undefined)
|
|
742
|
+
continue;
|
|
743
|
+
const abs = join(args.moduleAbsPath, rel);
|
|
744
|
+
let text;
|
|
745
|
+
try {
|
|
746
|
+
text = readFileSync(abs, "utf8");
|
|
747
|
+
}
|
|
748
|
+
catch {
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const importRe = /from\s+["'](\.{1,2}\/[^"']+)["']/g;
|
|
752
|
+
let m;
|
|
753
|
+
while ((m = importRe.exec(text)) !== null) {
|
|
754
|
+
const target = m[1];
|
|
755
|
+
if (target === undefined)
|
|
756
|
+
continue;
|
|
757
|
+
counts.set(target, (counts.get(target) ?? 0) + 1);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
if (counts.size === 0)
|
|
761
|
+
return null;
|
|
762
|
+
// Resolve top target back to a relPath that exists in the module.
|
|
763
|
+
const sorted = [...counts.entries()].sort(([, a], [, b]) => b - a);
|
|
764
|
+
for (const [target] of sorted) {
|
|
765
|
+
// crude: strip leading ./ or ../, drop extension if present, look for a
|
|
766
|
+
// matching relPath suffix
|
|
767
|
+
const stripped = target.replace(/^\.+\//, "").replace(/\.\w+$/, "");
|
|
768
|
+
const candidates = args.relPaths.filter((p) => p.replace(/\.\w+$/, "").endsWith(stripped));
|
|
769
|
+
if (candidates.length > 0 && candidates[0] !== undefined)
|
|
770
|
+
return candidates[0];
|
|
771
|
+
}
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
function readLocalDocs(moduleAbsPath, relPaths) {
|
|
775
|
+
const docPaths = [];
|
|
776
|
+
for (const rel of relPaths) {
|
|
777
|
+
if (/^README(\.[a-z]+)?$/i.test(rel) ||
|
|
778
|
+
/^AGENTS\.md$/i.test(rel) ||
|
|
779
|
+
/^CLAUDE\.md$/i.test(rel) ||
|
|
780
|
+
/^docs\/[^/]+\.(md|mdx)$/i.test(rel)) {
|
|
781
|
+
docPaths.push(rel);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (docPaths.length === 0)
|
|
785
|
+
return null;
|
|
786
|
+
const parts = [];
|
|
787
|
+
let total = 0;
|
|
788
|
+
for (const rel of docPaths.sort()) {
|
|
789
|
+
const abs = join(moduleAbsPath, rel);
|
|
790
|
+
let content;
|
|
791
|
+
try {
|
|
792
|
+
content = readFileSync(abs, "utf8");
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
const block = `### ${rel}\n${content}`;
|
|
798
|
+
if (total + block.length > LOCAL_DOCS_CHAR_CAP) {
|
|
799
|
+
const room = Math.max(0, LOCAL_DOCS_CHAR_CAP - total);
|
|
800
|
+
if (room > 0)
|
|
801
|
+
parts.push(block.slice(0, room) + "\n… (truncated)");
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
parts.push(block);
|
|
805
|
+
total += block.length + 2;
|
|
806
|
+
}
|
|
807
|
+
return parts.join("\n\n");
|
|
808
|
+
}
|
|
809
|
+
//# sourceMappingURL=module-slicer.js.map
|