@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,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer A — mechanical stub-pattern catalog.
|
|
3
|
+
*
|
|
4
|
+
* Run regex patterns from `.cairn/config/stub-patterns.yaml` against every
|
|
5
|
+
* file changed in the diff. Hard-severity match fails the run; soft-severity
|
|
6
|
+
* contributes to attestation cross-check (stubs_introduced count).
|
|
7
|
+
*
|
|
8
|
+
* Per PRIMER §10 Layer A. Catalog grows additively via /oops dialog (L25).
|
|
9
|
+
*/
|
|
10
|
+
const SENSOR_ID = "stub-pattern-catalog";
|
|
11
|
+
/** Detect language from extension. Returns undefined for binaries / unknown. */
|
|
12
|
+
export function detectLanguage(path) {
|
|
13
|
+
const lower = path.toLowerCase();
|
|
14
|
+
if (lower.endsWith(".ts") || lower.endsWith(".tsx") || lower.endsWith(".cts") || lower.endsWith(".mts"))
|
|
15
|
+
return "typescript";
|
|
16
|
+
if (lower.endsWith(".js") || lower.endsWith(".jsx") || lower.endsWith(".cjs") || lower.endsWith(".mjs"))
|
|
17
|
+
return "javascript";
|
|
18
|
+
if (lower.endsWith(".py"))
|
|
19
|
+
return "python";
|
|
20
|
+
if (lower.endsWith(".rb"))
|
|
21
|
+
return "ruby";
|
|
22
|
+
if (lower.endsWith(".go"))
|
|
23
|
+
return "go";
|
|
24
|
+
if (lower.endsWith(".rs"))
|
|
25
|
+
return "rust";
|
|
26
|
+
if (lower.endsWith(".sql"))
|
|
27
|
+
return "sql";
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Walk the diff and emit a match for every regex hit on lines that were
|
|
32
|
+
* added or are part of a new file. Modified files: only count hits on lines
|
|
33
|
+
* not present at the SHA pin (i.e. genuinely-new debt).
|
|
34
|
+
*/
|
|
35
|
+
export function detectStubMatches(args) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const entry of args.diff) {
|
|
38
|
+
if (entry.status === "deleted")
|
|
39
|
+
continue;
|
|
40
|
+
const lang = detectLanguage(entry.path);
|
|
41
|
+
if (lang === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
if (args.languages !== undefined && !args.languages.includes(lang))
|
|
44
|
+
continue;
|
|
45
|
+
const after = entry.afterContent ?? "";
|
|
46
|
+
if (after.length === 0)
|
|
47
|
+
continue;
|
|
48
|
+
const beforeLines = new Set((entry.beforeContent ?? "").split(/\r?\n/));
|
|
49
|
+
const afterLines = after.split(/\r?\n/);
|
|
50
|
+
for (const pattern of args.catalog.patterns) {
|
|
51
|
+
if (!pattern.languages.includes(lang))
|
|
52
|
+
continue;
|
|
53
|
+
const re = new RegExp(pattern.regex, "gm");
|
|
54
|
+
let m;
|
|
55
|
+
while ((m = re.exec(after)) !== null) {
|
|
56
|
+
const matchedText = m[0];
|
|
57
|
+
// Find the line number this match starts on (1-based).
|
|
58
|
+
const lineIdx = lineOf(after, m.index);
|
|
59
|
+
const lineText = afterLines[lineIdx - 1] ?? "";
|
|
60
|
+
// Only count if this line was added — i.e. not present in the
|
|
61
|
+
// pre-change content. Catches genuinely-new debt; ignores stubs that
|
|
62
|
+
// existed prior. For added files the beforeLines set is empty.
|
|
63
|
+
if (beforeLines.has(lineText))
|
|
64
|
+
continue;
|
|
65
|
+
out.push({
|
|
66
|
+
sensor_id: SENSOR_ID,
|
|
67
|
+
pattern_id: pattern.id,
|
|
68
|
+
description: pattern.description,
|
|
69
|
+
severity: pattern.severity,
|
|
70
|
+
path: entry.path,
|
|
71
|
+
line: lineIdx,
|
|
72
|
+
matched_text: matchedText,
|
|
73
|
+
});
|
|
74
|
+
if (re.lastIndex === m.index)
|
|
75
|
+
re.lastIndex += 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/** Convert a character offset within `text` to a 1-based line number. */
|
|
82
|
+
function lineOf(text, charIndex) {
|
|
83
|
+
let line = 1;
|
|
84
|
+
for (let i = 0; i < charIndex && i < text.length; i++) {
|
|
85
|
+
if (text.charCodeAt(i) === 10 /* \n */)
|
|
86
|
+
line += 1;
|
|
87
|
+
}
|
|
88
|
+
return line;
|
|
89
|
+
}
|
|
90
|
+
/** Run the Layer A sensor against a diff. */
|
|
91
|
+
export function runStubCatalog(args) {
|
|
92
|
+
const startedAt = Date.now();
|
|
93
|
+
const matches = detectStubMatches({
|
|
94
|
+
diff: args.diff,
|
|
95
|
+
catalog: args.catalog,
|
|
96
|
+
languages: args.languages,
|
|
97
|
+
});
|
|
98
|
+
const findings = matches.map((m) => ({
|
|
99
|
+
sensor_id: SENSOR_ID,
|
|
100
|
+
pattern_id: m.pattern_id,
|
|
101
|
+
path: m.path,
|
|
102
|
+
line: m.line,
|
|
103
|
+
matched_text: m.matched_text,
|
|
104
|
+
severity: m.severity,
|
|
105
|
+
message: `${m.path}:${m.line} matches stub pattern \`${m.pattern_id}\` — ${m.description}`,
|
|
106
|
+
}));
|
|
107
|
+
const ok = findings.every((f) => f.severity !== "hard");
|
|
108
|
+
return {
|
|
109
|
+
sensor_id: SENSOR_ID,
|
|
110
|
+
ok,
|
|
111
|
+
duration_ms: Date.now() - startedAt,
|
|
112
|
+
findings,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=stub-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub-catalog.js","sourceRoot":"","sources":["../../src/sensors/stub-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensor types — Phase 9 honest-agent invariants stack.
|
|
3
|
+
*
|
|
4
|
+
* Sensors run after the implementer agent finishes. Each sensor reads a
|
|
5
|
+
* `SensorInput` (diff + attestation + decisions + project block) and emits
|
|
6
|
+
* `SensorFinding[]`. The orchestrator collects every sensor's `SensorResult`,
|
|
7
|
+
* builds a remediation prompt from any findings, and either passes the run
|
|
8
|
+
* through or feeds the prompt back to the agent for retry.
|
|
9
|
+
*
|
|
10
|
+
* Per PRIMER §10. Per OpenAI's pattern: failure messages are remediation
|
|
11
|
+
* prompts the agent consumes on retry.
|
|
12
|
+
*/
|
|
13
|
+
import type { DecisionFrontmatter } from "../ground/schemas.js";
|
|
14
|
+
/** A single file changed in this run. */
|
|
15
|
+
export interface DiffEntry {
|
|
16
|
+
/** Repo-relative path. */
|
|
17
|
+
path: string;
|
|
18
|
+
status: "added" | "modified" | "deleted" | "renamed";
|
|
19
|
+
/** Pre-change content. Undefined when status === "added". */
|
|
20
|
+
beforeContent?: string;
|
|
21
|
+
/** Post-change content. Undefined when status === "deleted". */
|
|
22
|
+
afterContent?: string;
|
|
23
|
+
/** Original path when status === "renamed". */
|
|
24
|
+
fromPath?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Languages used to filter Layer A patterns + AST assertions. */
|
|
27
|
+
export type SensorLanguage = "typescript" | "javascript" | "python" | "ruby" | "go" | "rust" | "sql";
|
|
28
|
+
/** One pattern entry from .cairn/config/stub-patterns.yaml. */
|
|
29
|
+
export interface StubPattern {
|
|
30
|
+
id: string;
|
|
31
|
+
languages: SensorLanguage[];
|
|
32
|
+
description: string;
|
|
33
|
+
regex: string;
|
|
34
|
+
severity: "hard" | "soft";
|
|
35
|
+
}
|
|
36
|
+
export interface StubCatalog {
|
|
37
|
+
version: number;
|
|
38
|
+
patterns: StubPattern[];
|
|
39
|
+
}
|
|
40
|
+
/** YAML block the agent emits at end of turn. */
|
|
41
|
+
export interface AttestationDelivered {
|
|
42
|
+
symbol: string;
|
|
43
|
+
path?: string;
|
|
44
|
+
behavior: "full" | "partial" | "scaffolded";
|
|
45
|
+
sensors_passed?: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface AttestationDeferred {
|
|
48
|
+
symbol: string;
|
|
49
|
+
reason: string;
|
|
50
|
+
}
|
|
51
|
+
export interface Attestation {
|
|
52
|
+
delivered: AttestationDelivered[];
|
|
53
|
+
deferred: AttestationDeferred[];
|
|
54
|
+
known_limitations: string[];
|
|
55
|
+
todos_introduced: number;
|
|
56
|
+
stubs_introduced: number;
|
|
57
|
+
files_touched: string[];
|
|
58
|
+
/** Set when the agent could not proceed; runner reports it as soft finding. */
|
|
59
|
+
blocked_by?: {
|
|
60
|
+
reason: string;
|
|
61
|
+
needed_from_operator?: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Project-extension block resolved from workflow.md `<project>:` extension.
|
|
66
|
+
* Sensors that trigger on `glob_keys` look up the matching key here.
|
|
67
|
+
*/
|
|
68
|
+
export interface ProjectGlobs {
|
|
69
|
+
route_handler_globs?: string[];
|
|
70
|
+
dto_globs?: string[];
|
|
71
|
+
generator_source_globs?: string[];
|
|
72
|
+
high_stakes_globs?: string[];
|
|
73
|
+
/** Off-limits — file_must_not_be_modified assertions also enforce these. */
|
|
74
|
+
off_limits?: string[];
|
|
75
|
+
[key: string]: string[] | undefined;
|
|
76
|
+
}
|
|
77
|
+
export interface SensorInput {
|
|
78
|
+
/** Absolute path to the mirror checkout. */
|
|
79
|
+
mirrorPath: string;
|
|
80
|
+
/** origin/main SHA pinned at workspace prep. */
|
|
81
|
+
shaPin: string;
|
|
82
|
+
/** Files changed in this run, content already loaded. */
|
|
83
|
+
changedFiles: DiffEntry[];
|
|
84
|
+
/** Parsed attestation; undefined if the agent emitted none (Layer B fails). */
|
|
85
|
+
attestation: Attestation | undefined;
|
|
86
|
+
/** Decisions accepted in scope of this diff. Already filtered. */
|
|
87
|
+
decisionsInScope: DecisionFrontmatter[];
|
|
88
|
+
/** Layer A catalog. */
|
|
89
|
+
stubCatalog: StubCatalog;
|
|
90
|
+
/** Stack profile language list — pattern filtering. */
|
|
91
|
+
languages: SensorLanguage[];
|
|
92
|
+
/** Project-extension globs. */
|
|
93
|
+
projectGlobs: ProjectGlobs;
|
|
94
|
+
/** Run id used in log lines. */
|
|
95
|
+
runId: string;
|
|
96
|
+
}
|
|
97
|
+
export interface SensorFinding {
|
|
98
|
+
/** id from sensors.yaml — e.g., "stub-pattern-catalog". */
|
|
99
|
+
sensor_id: string;
|
|
100
|
+
/** Layer A only — the pattern that matched. */
|
|
101
|
+
pattern_id?: string;
|
|
102
|
+
/** Decision-assertions only — the failing decision. */
|
|
103
|
+
decision_id?: string;
|
|
104
|
+
/** Decision-assertions only — the assertion that failed. */
|
|
105
|
+
assertion_id?: string;
|
|
106
|
+
/** Where the failure surfaced (repo-relative). */
|
|
107
|
+
path?: string;
|
|
108
|
+
/** Line number, 1-based. */
|
|
109
|
+
line?: number;
|
|
110
|
+
/** Verbatim text that caused the finding. */
|
|
111
|
+
matched_text?: string;
|
|
112
|
+
/** Human-readable, remediation-shaped one-liner. */
|
|
113
|
+
message: string;
|
|
114
|
+
severity: "hard" | "soft";
|
|
115
|
+
}
|
|
116
|
+
export interface SensorResult {
|
|
117
|
+
sensor_id: string;
|
|
118
|
+
ok: boolean;
|
|
119
|
+
duration_ms: number;
|
|
120
|
+
findings: SensorFinding[];
|
|
121
|
+
/** Set when the sensor opted out (e.g. no diff hits its glob keys). */
|
|
122
|
+
skipped?: {
|
|
123
|
+
reason: string;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Aggregated outcome of a single sensor sweep. */
|
|
127
|
+
export interface SensorSweepResult {
|
|
128
|
+
ok: boolean;
|
|
129
|
+
hard_failures: number;
|
|
130
|
+
soft_findings: number;
|
|
131
|
+
results: SensorResult[];
|
|
132
|
+
/** Remediation prompt body to feed back to the agent on retry. Empty when ok. */
|
|
133
|
+
remediation_prompt: string;
|
|
134
|
+
duration_ms: number;
|
|
135
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensor types — Phase 9 honest-agent invariants stack.
|
|
3
|
+
*
|
|
4
|
+
* Sensors run after the implementer agent finishes. Each sensor reads a
|
|
5
|
+
* `SensorInput` (diff + attestation + decisions + project block) and emits
|
|
6
|
+
* `SensorFinding[]`. The orchestrator collects every sensor's `SensorResult`,
|
|
7
|
+
* builds a remediation prompt from any findings, and either passes the run
|
|
8
|
+
* through or feeds the prompt back to the agent for retry.
|
|
9
|
+
*
|
|
10
|
+
* Per PRIMER §10. Per OpenAI's pattern: failure messages are remediation
|
|
11
|
+
* prompts the agent consumes on retry.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sensors/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session events marker — `.cairn/sessions/<id>/events-marker.json`.
|
|
3
|
+
*
|
|
4
|
+
* Records the timestamp at which a session armed its events watch. The
|
|
5
|
+
* Stop hook (step 4) reads `eventsSince(repoRoot, marker.ts)` and
|
|
6
|
+
* surfaces only events that landed after this session started.
|
|
7
|
+
*
|
|
8
|
+
* Spec: PLUGIN_ARCHITECTURE §7 (invalidation events).
|
|
9
|
+
*/
|
|
10
|
+
export interface EventsMarker {
|
|
11
|
+
/** ms epoch at which the session armed its events watch. */
|
|
12
|
+
ts: number;
|
|
13
|
+
/** ms epoch of the last poll the Stop hook performed. Defaults to ts. */
|
|
14
|
+
last_polled_ts: number;
|
|
15
|
+
}
|
|
16
|
+
/** Absolute path to the marker file for `sessionId`. */
|
|
17
|
+
export declare function eventsMarkerPath(repoRoot: string, sessionId: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Seed the marker at session start. If a marker already exists (e.g.
|
|
20
|
+
* the SessionStart hook ran twice), the existing marker is preserved
|
|
21
|
+
* and returned unchanged.
|
|
22
|
+
*/
|
|
23
|
+
export declare function seedEventsMarker(args: {
|
|
24
|
+
repoRoot: string;
|
|
25
|
+
sessionId: string;
|
|
26
|
+
ts?: number;
|
|
27
|
+
}): EventsMarker;
|
|
28
|
+
/** Read the marker. Returns null when absent or malformed. */
|
|
29
|
+
export declare function readEventsMarker(repoRoot: string, sessionId: string): EventsMarker | null;
|
|
30
|
+
/**
|
|
31
|
+
* Stamp the marker's `last_polled_ts`. Called by the Stop hook after
|
|
32
|
+
* draining events so the next poll only sees newer ones. Safe to call
|
|
33
|
+
* before the marker exists — falls through and seeds.
|
|
34
|
+
*/
|
|
35
|
+
export declare function stampEventsPoll(args: {
|
|
36
|
+
repoRoot: string;
|
|
37
|
+
sessionId: string;
|
|
38
|
+
ts: number;
|
|
39
|
+
}): EventsMarker;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session events marker — `.cairn/sessions/<id>/events-marker.json`.
|
|
3
|
+
*
|
|
4
|
+
* Records the timestamp at which a session armed its events watch. The
|
|
5
|
+
* Stop hook (step 4) reads `eventsSince(repoRoot, marker.ts)` and
|
|
6
|
+
* surfaces only events that landed after this session started.
|
|
7
|
+
*
|
|
8
|
+
* Spec: PLUGIN_ARCHITECTURE §7 (invalidation events).
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { sessionStateDir } from "../paths/index.js";
|
|
13
|
+
const MARKER_FILE = "events-marker.json";
|
|
14
|
+
/** Absolute path to the marker file for `sessionId`. */
|
|
15
|
+
export function eventsMarkerPath(repoRoot, sessionId) {
|
|
16
|
+
return join(sessionStateDir(repoRoot, sessionId), MARKER_FILE);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Seed the marker at session start. If a marker already exists (e.g.
|
|
20
|
+
* the SessionStart hook ran twice), the existing marker is preserved
|
|
21
|
+
* and returned unchanged.
|
|
22
|
+
*/
|
|
23
|
+
export function seedEventsMarker(args) {
|
|
24
|
+
const dir = sessionStateDir(args.repoRoot, args.sessionId);
|
|
25
|
+
const path = join(dir, MARKER_FILE);
|
|
26
|
+
if (existsSync(path)) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
29
|
+
if (typeof parsed?.ts === "number") {
|
|
30
|
+
const last = typeof parsed.last_polled_ts === "number" ? parsed.last_polled_ts : parsed.ts;
|
|
31
|
+
return { ts: parsed.ts, last_polled_ts: last };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// fall through and overwrite
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const ts = args.ts ?? Date.now();
|
|
39
|
+
const marker = { ts, last_polled_ts: ts };
|
|
40
|
+
mkdirSync(dir, { recursive: true });
|
|
41
|
+
writeFileSync(path, `${JSON.stringify(marker, null, 2)}\n`, "utf8");
|
|
42
|
+
return marker;
|
|
43
|
+
}
|
|
44
|
+
/** Read the marker. Returns null when absent or malformed. */
|
|
45
|
+
export function readEventsMarker(repoRoot, sessionId) {
|
|
46
|
+
const path = eventsMarkerPath(repoRoot, sessionId);
|
|
47
|
+
if (!existsSync(path))
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
51
|
+
if (typeof parsed?.ts !== "number")
|
|
52
|
+
return null;
|
|
53
|
+
const last = typeof parsed.last_polled_ts === "number" ? parsed.last_polled_ts : parsed.ts;
|
|
54
|
+
return { ts: parsed.ts, last_polled_ts: last };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stamp the marker's `last_polled_ts`. Called by the Stop hook after
|
|
62
|
+
* draining events so the next poll only sees newer ones. Safe to call
|
|
63
|
+
* before the marker exists — falls through and seeds.
|
|
64
|
+
*/
|
|
65
|
+
export function stampEventsPoll(args) {
|
|
66
|
+
const existing = readEventsMarker(args.repoRoot, args.sessionId);
|
|
67
|
+
const baseTs = existing?.ts ?? args.ts;
|
|
68
|
+
const marker = { ts: baseTs, last_polled_ts: args.ts };
|
|
69
|
+
const dir = sessionStateDir(args.repoRoot, args.sessionId);
|
|
70
|
+
mkdirSync(dir, { recursive: true });
|
|
71
|
+
writeFileSync(eventsMarkerPath(args.repoRoot, args.sessionId), `${JSON.stringify(marker, null, 2)}\n`, "utf8");
|
|
72
|
+
return marker;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=events-marker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-marker.js","sourceRoot":"","sources":["../../src/session/events-marker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session id resolution + per-session directory lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Per PLUGIN_ARCHITECTURE §7, each Claude Code session owns a
|
|
5
|
+
* `.cairn/sessions/<session-id>/` directory holding its mutable state
|
|
6
|
+
* (status.json, current task pointer, run notes). The directory is
|
|
7
|
+
* created at SessionStart and removed at SessionEnd. Stale dirs left
|
|
8
|
+
* behind by crashed sessions (no live PID, > MAX_AGE_MS old) are GC'd
|
|
9
|
+
* by the next SessionStart in any session.
|
|
10
|
+
*
|
|
11
|
+
* Concurrency: session dirs are owned by one session — no lock. The
|
|
12
|
+
* GC sweep only deletes dirs whose PID is dead OR whose mtime is past
|
|
13
|
+
* the staleness threshold; it never touches a live session's dir.
|
|
14
|
+
*/
|
|
15
|
+
/** Session id payload shape — Claude Code's hook stdin includes `session_id`. */
|
|
16
|
+
export interface SessionIdSource {
|
|
17
|
+
session_id?: unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a session id from a hook payload. Prefers Claude Code's
|
|
21
|
+
* `session_id` when present; otherwise generates a uuid for the
|
|
22
|
+
* caller to use (CLI / test invocation).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveSessionId(payload: SessionIdSource | null | undefined): string;
|
|
25
|
+
export interface SessionMeta {
|
|
26
|
+
/** Session id (post-sanitize, matches the dir name). */
|
|
27
|
+
session_id: string;
|
|
28
|
+
/** ISO timestamp the session dir was created. */
|
|
29
|
+
started_at: string;
|
|
30
|
+
/** PID of the Claude Code process that owns the session, when known. */
|
|
31
|
+
pid: number | null;
|
|
32
|
+
}
|
|
33
|
+
export interface EnsureSessionDirArgs {
|
|
34
|
+
repoRoot: string;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
/**
|
|
37
|
+
* PID of the owning process. Default `process.pid` (the SessionStart
|
|
38
|
+
* hook subprocess — short-lived, but its parent Claude Code PID is
|
|
39
|
+
* not exposed via the payload, so subprocess PID is the best proxy
|
|
40
|
+
* for "was this session started by a live process at this time").
|
|
41
|
+
*/
|
|
42
|
+
pid?: number | null;
|
|
43
|
+
}
|
|
44
|
+
export interface EnsureSessionDirResult {
|
|
45
|
+
/** Absolute path to the per-session dir. */
|
|
46
|
+
dir: string;
|
|
47
|
+
/** Whether the dir was just created (false if it already existed). */
|
|
48
|
+
created: boolean;
|
|
49
|
+
/** Meta written into `meta.json`. */
|
|
50
|
+
meta: SessionMeta;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create (or refresh) the per-session directory and write `meta.json`.
|
|
54
|
+
* Idempotent — if the dir exists already, the existing meta is read,
|
|
55
|
+
* `pid` and `started_at` left intact when valid.
|
|
56
|
+
*/
|
|
57
|
+
export declare function ensureSessionDir(args: EnsureSessionDirArgs): EnsureSessionDirResult;
|
|
58
|
+
/**
|
|
59
|
+
* Remove the per-session directory. Returns true when something was
|
|
60
|
+
* removed, false when the dir was already absent.
|
|
61
|
+
*/
|
|
62
|
+
export declare function cleanupSession(repoRoot: string, sessionId: string): boolean;
|
|
63
|
+
export interface GcStaleSessionsArgs {
|
|
64
|
+
repoRoot: string;
|
|
65
|
+
/** ISO time threshold; dirs older than this AND with a dead PID are removed. Default 24h. */
|
|
66
|
+
maxAgeMs?: number;
|
|
67
|
+
/** Override Date.now() for tests. */
|
|
68
|
+
now?: () => number;
|
|
69
|
+
}
|
|
70
|
+
export interface GcStaleSessionsResult {
|
|
71
|
+
/** Session ids that were removed. */
|
|
72
|
+
removed: string[];
|
|
73
|
+
/** Session ids that were inspected but kept (live PID or fresh). */
|
|
74
|
+
kept: string[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Sweep the sessions directory and remove dirs that look abandoned —
|
|
78
|
+
* either older than `maxAgeMs` AND with a dead PID, or with a malformed
|
|
79
|
+
* meta.json. Live sessions (PID alive) are never touched, regardless
|
|
80
|
+
* of age. A missing PID counts as "dead" so dirs from operator-deleted
|
|
81
|
+
* meta files don't accumulate.
|
|
82
|
+
*/
|
|
83
|
+
export declare function gcStaleSessions(args: GcStaleSessionsArgs): GcStaleSessionsResult;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session id resolution + per-session directory lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Per PLUGIN_ARCHITECTURE §7, each Claude Code session owns a
|
|
5
|
+
* `.cairn/sessions/<session-id>/` directory holding its mutable state
|
|
6
|
+
* (status.json, current task pointer, run notes). The directory is
|
|
7
|
+
* created at SessionStart and removed at SessionEnd. Stale dirs left
|
|
8
|
+
* behind by crashed sessions (no live PID, > MAX_AGE_MS old) are GC'd
|
|
9
|
+
* by the next SessionStart in any session.
|
|
10
|
+
*
|
|
11
|
+
* Concurrency: session dirs are owned by one session — no lock. The
|
|
12
|
+
* GC sweep only deletes dirs whose PID is dead OR whose mtime is past
|
|
13
|
+
* the staleness threshold; it never touches a live session's dir.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { sessionStateDir, sessionsDir } from "../paths/index.js";
|
|
19
|
+
/**
|
|
20
|
+
* Stale-session GC threshold. A session dir whose PID is dead AND whose
|
|
21
|
+
* `meta.json` `started_at` is older than this gets removed at the next
|
|
22
|
+
* SessionStart. 24h matches the spec.
|
|
23
|
+
*/
|
|
24
|
+
const MAX_STALE_AGE_MS = 24 * 60 * 60 * 1000;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a session id from a hook payload. Prefers Claude Code's
|
|
27
|
+
* `session_id` when present; otherwise generates a uuid for the
|
|
28
|
+
* caller to use (CLI / test invocation).
|
|
29
|
+
*/
|
|
30
|
+
export function resolveSessionId(payload) {
|
|
31
|
+
const candidate = payload?.session_id;
|
|
32
|
+
if (typeof candidate === "string" && candidate.length > 0)
|
|
33
|
+
return candidate;
|
|
34
|
+
return randomUUID();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create (or refresh) the per-session directory and write `meta.json`.
|
|
38
|
+
* Idempotent — if the dir exists already, the existing meta is read,
|
|
39
|
+
* `pid` and `started_at` left intact when valid.
|
|
40
|
+
*/
|
|
41
|
+
export function ensureSessionDir(args) {
|
|
42
|
+
const dir = sessionStateDir(args.repoRoot, args.sessionId);
|
|
43
|
+
const metaPath = join(dir, "meta.json");
|
|
44
|
+
const existed = existsSync(dir);
|
|
45
|
+
let meta;
|
|
46
|
+
if (existed && existsSync(metaPath)) {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(readFileSync(metaPath, "utf8"));
|
|
49
|
+
const startedAt = typeof parsed.started_at === "string" ? parsed.started_at : new Date().toISOString();
|
|
50
|
+
const pidVal = typeof parsed.pid === "number" ? parsed.pid : (args.pid ?? process.pid);
|
|
51
|
+
meta = {
|
|
52
|
+
session_id: args.sessionId,
|
|
53
|
+
started_at: startedAt,
|
|
54
|
+
pid: pidVal,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
meta = freshMeta(args);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
meta = freshMeta(args);
|
|
63
|
+
}
|
|
64
|
+
mkdirSync(dir, { recursive: true });
|
|
65
|
+
writeFileSync(metaPath, `${JSON.stringify(meta, null, 2)}\n`, "utf8");
|
|
66
|
+
return { dir, created: !existed, meta };
|
|
67
|
+
}
|
|
68
|
+
function freshMeta(args) {
|
|
69
|
+
return {
|
|
70
|
+
session_id: args.sessionId,
|
|
71
|
+
started_at: new Date().toISOString(),
|
|
72
|
+
pid: args.pid === undefined ? process.pid : args.pid,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Remove the per-session directory. Returns true when something was
|
|
77
|
+
* removed, false when the dir was already absent.
|
|
78
|
+
*/
|
|
79
|
+
export function cleanupSession(repoRoot, sessionId) {
|
|
80
|
+
const dir = sessionStateDir(repoRoot, sessionId);
|
|
81
|
+
if (!existsSync(dir))
|
|
82
|
+
return false;
|
|
83
|
+
rmSync(dir, { recursive: true, force: true });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Sweep the sessions directory and remove dirs that look abandoned —
|
|
88
|
+
* either older than `maxAgeMs` AND with a dead PID, or with a malformed
|
|
89
|
+
* meta.json. Live sessions (PID alive) are never touched, regardless
|
|
90
|
+
* of age. A missing PID counts as "dead" so dirs from operator-deleted
|
|
91
|
+
* meta files don't accumulate.
|
|
92
|
+
*/
|
|
93
|
+
export function gcStaleSessions(args) {
|
|
94
|
+
const root = sessionsDir(args.repoRoot);
|
|
95
|
+
const removed = [];
|
|
96
|
+
const kept = [];
|
|
97
|
+
if (!existsSync(root))
|
|
98
|
+
return { removed, kept };
|
|
99
|
+
const maxAge = args.maxAgeMs ?? MAX_STALE_AGE_MS;
|
|
100
|
+
const now = args.now ? args.now() : Date.now();
|
|
101
|
+
const entries = readdirSync(root, { withFileTypes: true, encoding: "utf8" });
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (!entry.isDirectory())
|
|
104
|
+
continue;
|
|
105
|
+
const sessionId = entry.name;
|
|
106
|
+
const dir = join(root, sessionId);
|
|
107
|
+
const metaPath = join(dir, "meta.json");
|
|
108
|
+
let meta = null;
|
|
109
|
+
let mtime;
|
|
110
|
+
try {
|
|
111
|
+
mtime = statSync(dir).mtimeMs;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
mtime = 0;
|
|
115
|
+
}
|
|
116
|
+
if (existsSync(metaPath)) {
|
|
117
|
+
try {
|
|
118
|
+
meta = JSON.parse(readFileSync(metaPath, "utf8"));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
meta = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const pid = meta && typeof meta.pid === "number" ? meta.pid : null;
|
|
125
|
+
const startedAt = meta && typeof meta.started_at === "string" ? Date.parse(meta.started_at) : NaN;
|
|
126
|
+
const ageMs = Number.isFinite(startedAt) ? now - startedAt : now - mtime;
|
|
127
|
+
const pidAlive = pid !== null && isPidAlive(pid);
|
|
128
|
+
if (pidAlive) {
|
|
129
|
+
kept.push(sessionId);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (ageMs >= maxAge) {
|
|
133
|
+
try {
|
|
134
|
+
rmSync(dir, { recursive: true, force: true });
|
|
135
|
+
removed.push(sessionId);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
kept.push(sessionId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
kept.push(sessionId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { removed, kept };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Probe whether `pid` belongs to a live process. `kill(pid, 0)` is the
|
|
149
|
+
* portable way; throws ESRCH for dead PIDs. EPERM means "alive but not
|
|
150
|
+
* ours" — still alive.
|
|
151
|
+
*/
|
|
152
|
+
function isPidAlive(pid) {
|
|
153
|
+
if (!Number.isFinite(pid) || pid <= 0)
|
|
154
|
+
return false;
|
|
155
|
+
try {
|
|
156
|
+
process.kill(pid, 0);
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const code = err.code;
|
|
161
|
+
if (code === "EPERM")
|
|
162
|
+
return true;
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/session/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOjE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA2C;IAC1E,MAAM,SAAS,GAAG,OAAO,EAAE,UAAU,CAAC;IACtC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAgCD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAA0B;IACzD,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhC,IAAI,IAAiB,CAAC;IACtB,IAAI,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAyB,CAAC;YAClF,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACvG,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;YACvF,IAAI,GAAG;gBACL,UAAU,EAAE,IAAI,CAAC,SAAS;gBAC1B,UAAU,EAAE,SAAS;gBACrB,GAAG,EAAE,MAAM;aACZ,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,SAAS,CAAC,IAA0B;IAC3C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;KACrD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,SAAiB;IAChE,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAiBD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAyB;IACvD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAE/C,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7E,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAExC,IAAI,IAAI,GAAgC,IAAI,CAAC;QAC7C,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;QAED,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAyB,CAAC;YAC5E,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAClG,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;QAEzE,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session state lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Owns `.cairn/sessions/<id>/` — the directory each Claude Code
|
|
5
|
+
* session uses for its own status.json, current task pointer, and run
|
|
6
|
+
* notes. Spec: PLUGIN_ARCHITECTURE §7.
|
|
7
|
+
*
|
|
8
|
+
* SessionStart hook calls `ensureSessionDir` + `gcStaleSessions`.
|
|
9
|
+
* SessionEnd hook calls `cleanupSession`.
|
|
10
|
+
*/
|
|
11
|
+
export { cleanupSession, ensureSessionDir, gcStaleSessions, resolveSessionId, } from "./id.js";
|
|
12
|
+
export type { EnsureSessionDirArgs, EnsureSessionDirResult, GcStaleSessionsArgs, GcStaleSessionsResult, SessionIdSource, SessionMeta, } from "./id.js";
|
|
13
|
+
export { eventsMarkerPath, readEventsMarker, seedEventsMarker, stampEventsPoll, } from "./events-marker.js";
|
|
14
|
+
export type { EventsMarker } from "./events-marker.js";
|