@isaacriehm/cairn-core 0.6.0 → 0.7.1
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/dist/.tsbuildinfo +1 -1
- package/dist/align-undo/undo.js +2 -2
- package/dist/align-undo/undo.js.map +1 -1
- package/dist/attention/bulk-accept.js +104 -55
- package/dist/attention/bulk-accept.js.map +1 -1
- package/dist/attention/dedup.js +23 -10
- package/dist/attention/dedup.js.map +1 -1
- package/dist/attention/restore.js +2 -2
- package/dist/attention/restore.js.map +1 -1
- package/dist/attention/scoring.js +1 -1
- package/dist/attention/scoring.js.map +1 -1
- package/dist/attention/serve/api.d.ts +1 -0
- package/dist/attention/serve/api.js +130 -77
- package/dist/attention/serve/api.js.map +1 -1
- package/dist/attention/serve/index.d.ts +1 -0
- package/dist/attention/serve/index.js +21 -7
- package/dist/attention/serve/index.js.map +1 -1
- package/dist/attention/source-strip.js +41 -46
- package/dist/attention/source-strip.js.map +1 -1
- package/dist/claude/cache.d.ts +10 -19
- package/dist/claude/cache.js +0 -0
- package/dist/claude/cache.js.map +1 -1
- package/dist/claude/runner.d.ts +4 -6
- package/dist/claude/runner.js +242 -203
- package/dist/claude/runner.js.map +1 -1
- package/dist/claude/types.d.ts +5 -5
- package/dist/context/handoff-builder.d.ts +28 -4
- package/dist/context/handoff-builder.js +75 -157
- package/dist/context/handoff-builder.js.map +1 -1
- package/dist/context/spec-delta.js +61 -9
- package/dist/context/spec-delta.js.map +1 -1
- package/dist/context/task-summary.js +5 -1
- package/dist/context/task-summary.js.map +1 -1
- package/dist/decision-capture/id.js +1 -1
- package/dist/decision-capture/id.js.map +1 -1
- package/dist/doctor/index.d.ts +9 -11
- package/dist/doctor/index.js +118 -175
- package/dist/doctor/index.js.map +1 -1
- package/dist/drain/drain.d.ts +1 -1
- package/dist/drain/drain.js +16 -16
- package/dist/drain/drain.js.map +1 -1
- package/dist/drain/index.d.ts +1 -1
- package/dist/drain/index.js +1 -1
- package/dist/events/reader.d.ts +9 -10
- package/dist/events/reader.js +46 -57
- package/dist/events/reader.js.map +1 -1
- package/dist/events/writer.js +1 -1
- package/dist/events/writer.js.map +1 -1
- package/dist/fix-align/index.d.ts +1 -1
- package/dist/fix-align/index.js +1 -1
- package/dist/fix-align/run.d.ts +1 -1
- package/dist/fix-align/run.js +4 -3
- package/dist/fix-align/run.js.map +1 -1
- package/dist/fix-align/sentinel.d.ts +1 -2
- package/dist/fix-align/sentinel.js +3 -4
- package/dist/fix-align/sentinel.js.map +1 -1
- package/dist/gc/apply.js +1 -1
- package/dist/gc/apply.js.map +1 -1
- package/dist/gc/attested-commits.d.ts +19 -0
- package/dist/gc/attested-commits.js +48 -0
- package/dist/gc/attested-commits.js.map +1 -0
- package/dist/gc/canary.d.ts +11 -21
- package/dist/gc/canary.js +18 -24
- package/dist/gc/canary.js.map +1 -1
- package/dist/gc/citation-integrity.d.ts +11 -14
- package/dist/gc/citation-integrity.js +124 -125
- package/dist/gc/citation-integrity.js.map +1 -1
- package/dist/gc/classify.d.ts +1 -1
- package/dist/gc/classify.js +2 -2
- package/dist/gc/classify.js.map +1 -1
- package/dist/gc/completion-integrity.d.ts +6 -7
- package/dist/gc/completion-integrity.js +45 -53
- package/dist/gc/completion-integrity.js.map +1 -1
- package/dist/gc/doc-gardening.js +1 -9
- package/dist/gc/doc-gardening.js.map +1 -1
- package/dist/gc/frontmatter.js +2 -2
- package/dist/gc/frontmatter.js.map +1 -1
- package/dist/gc/index.d.ts +7 -6
- package/dist/gc/index.js +3 -2
- package/dist/gc/index.js.map +1 -1
- package/dist/gc/quality-update.d.ts +6 -10
- package/dist/gc/quality-update.js +12 -15
- package/dist/gc/quality-update.js.map +1 -1
- package/dist/gc/scope-coverage.js +1 -1
- package/dist/gc/scope-coverage.js.map +1 -1
- package/dist/gc/stub-hits.d.ts +7 -25
- package/dist/gc/stub-hits.js +14 -40
- package/dist/gc/stub-hits.js.map +1 -1
- package/dist/gc/sweep.js +15 -6
- package/dist/gc/sweep.js.map +1 -1
- package/dist/gc/types.d.ts +5 -5
- package/dist/gc/types.js +2 -2
- package/dist/gc/walk-source.js +8 -28
- package/dist/gc/walk-source.js.map +1 -1
- package/dist/hooks/defer.d.ts +9 -20
- package/dist/hooks/defer.js +10 -27
- package/dist/hooks/defer.js.map +1 -1
- package/dist/hooks/post-tool-use/allowlist-reader.d.ts +2 -1
- package/dist/hooks/post-tool-use/allowlist-reader.js +49 -34
- package/dist/hooks/post-tool-use/allowlist-reader.js.map +1 -1
- package/dist/hooks/post-tool-use/index.d.ts +3 -4
- package/dist/hooks/post-tool-use/index.js +3 -3
- package/dist/hooks/post-tool-use/index.js.map +1 -1
- package/dist/hooks/post-tool-use/legend-builder.d.ts +11 -2
- package/dist/hooks/post-tool-use/legend-builder.js +27 -2
- package/dist/hooks/post-tool-use/legend-builder.js.map +1 -1
- package/dist/hooks/post-tool-use/post-write.d.ts +8 -0
- package/dist/hooks/post-tool-use/post-write.js +112 -0
- package/dist/hooks/post-tool-use/post-write.js.map +1 -0
- package/dist/hooks/post-tool-use/read-enricher.d.ts +10 -5
- package/dist/hooks/post-tool-use/read-enricher.js +114 -149
- package/dist/hooks/post-tool-use/read-enricher.js.map +1 -1
- package/dist/hooks/post-tool-use/sot-align.d.ts +12 -0
- package/dist/hooks/post-tool-use/sot-align.js +73 -49
- package/dist/hooks/post-tool-use/sot-align.js.map +1 -1
- package/dist/hooks/post-tool-use/write-guardian.d.ts +40 -8
- package/dist/hooks/post-tool-use/write-guardian.js +202 -254
- package/dist/hooks/post-tool-use/write-guardian.js.map +1 -1
- package/dist/hooks/pre-commit/sot-align-precommit.js +2 -2
- package/dist/hooks/pre-commit/sot-align-precommit.js.map +1 -1
- package/dist/hooks/runners/index.d.ts +2 -2
- package/dist/hooks/runners/index.js +1 -1
- package/dist/hooks/runners/index.js.map +1 -1
- package/dist/hooks/runners/payload.d.ts +34 -19
- package/dist/hooks/runners/payload.js +47 -44
- package/dist/hooks/runners/payload.js.map +1 -1
- package/dist/hooks/runners/session-end.js +12 -11
- package/dist/hooks/runners/session-end.js.map +1 -1
- package/dist/hooks/runners/session-start.d.ts +4 -2
- package/dist/hooks/runners/session-start.js +88 -261
- package/dist/hooks/runners/session-start.js.map +1 -1
- package/dist/hooks/runners/stop.js +27 -8
- package/dist/hooks/runners/stop.js.map +1 -1
- package/dist/hooks/runners/user-prompt-submit.js +7 -1
- package/dist/hooks/runners/user-prompt-submit.js.map +1 -1
- package/dist/hooks/sot-align-common.d.ts +1 -2
- package/dist/hooks/sot-align-common.js +2 -2
- package/dist/hooks/sot-align-common.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/init/baseline-audit.d.ts +14 -58
- package/dist/init/baseline-audit.js +92 -320
- package/dist/init/baseline-audit.js.map +1 -1
- package/dist/init/brand-derive.d.ts +11 -15
- package/dist/init/brand-derive.js +21 -46
- package/dist/init/brand-derive.js.map +1 -1
- package/dist/init/brand-setup.d.ts +1 -1
- package/dist/init/brand-setup.js +1 -1
- package/dist/init/detect.d.ts +25 -6
- package/dist/init/detect.js +107 -136
- package/dist/init/detect.js.map +1 -1
- package/dist/init/index.d.ts +4 -4
- package/dist/init/index.js +2 -2
- package/dist/init/index.js.map +1 -1
- package/dist/init/ingest-docs.d.ts +83 -23
- package/dist/init/ingest-docs.js +648 -136
- package/dist/init/ingest-docs.js.map +1 -1
- package/dist/init/init.d.ts +29 -20
- package/dist/init/init.js +132 -290
- package/dist/init/init.js.map +1 -1
- package/dist/init/mapper-merge.js +1 -1
- package/dist/init/mapper-merge.js.map +1 -1
- package/dist/init/mapper-parallel.d.ts +1 -1
- package/dist/init/mapper-parallel.js +10 -1
- package/dist/init/mapper-parallel.js.map +1 -1
- package/dist/init/mapper.js +1 -1
- package/dist/init/mapper.js.map +1 -1
- package/dist/init/multi-dev/install.d.ts +5 -5
- package/dist/init/multi-dev/install.js +4 -4
- package/dist/init/overlay.js +1 -0
- package/dist/init/overlay.js.map +1 -1
- package/dist/init/phases/1-detect.js +1 -1
- package/dist/init/phases/1-detect.js.map +1 -1
- package/dist/init/phases/{7c-rules-merge.d.ts → 10-rules-merge.d.ts} +2 -2
- package/dist/init/phases/{7c-rules-merge.js → 10-rules-merge.js} +6 -12
- package/dist/init/phases/10-rules-merge.js.map +1 -0
- package/dist/init/phases/11-baseline.d.ts +7 -0
- package/dist/init/phases/{8-baseline.js → 11-baseline.js} +5 -9
- package/dist/init/phases/11-baseline.js.map +1 -0
- package/dist/init/phases/12-strip.d.ts +10 -0
- package/dist/init/phases/{10-strip.js → 12-strip.js} +10 -14
- package/dist/init/phases/12-strip.js.map +1 -0
- package/dist/init/phases/{12-multidev.d.ts → 13-multidev.d.ts} +2 -2
- package/dist/init/phases/{12-multidev.js → 13-multidev.js} +4 -4
- package/dist/init/phases/{12-multidev.js.map → 13-multidev.js.map} +1 -1
- package/dist/init/phases/3-mapper.d.ts +1 -1
- package/dist/init/phases/3-mapper.js +2 -2
- package/dist/init/phases/3-mapper.js.map +1 -1
- package/dist/init/phases/{3b-seed.d.ts → 4-seed.d.ts} +2 -2
- package/dist/init/phases/{3b-seed.js → 4-seed.js} +7 -7
- package/dist/init/phases/4-seed.js.map +1 -0
- package/dist/init/phases/{4-pilot.d.ts → 5-pilot.d.ts} +2 -2
- package/dist/init/phases/{4-pilot.js → 5-pilot.js} +9 -9
- package/dist/init/phases/{4-pilot.js.map → 5-pilot.js.map} +1 -1
- package/dist/init/phases/{5-brand.d.ts → 6-brand.d.ts} +2 -7
- package/dist/init/phases/{5-brand.js → 6-brand.js} +6 -14
- package/dist/init/phases/6-brand.js.map +1 -0
- package/dist/init/phases/{5b-topic-index.d.ts → 7-topic-index.d.ts} +2 -11
- package/dist/init/phases/{5b-topic-index.js → 7-topic-index.js} +9 -18
- package/dist/init/phases/7-topic-index.js.map +1 -0
- package/dist/init/phases/8-docs-ingest.d.ts +10 -0
- package/dist/init/phases/{6-docs-ingest.js → 8-docs-ingest.js} +12 -14
- package/dist/init/phases/8-docs-ingest.js.map +1 -0
- package/dist/init/phases/9-source-comments.d.ts +6 -0
- package/dist/init/phases/{7b-source-comments.js → 9-source-comments.js} +7 -26
- package/dist/init/phases/9-source-comments.js.map +1 -0
- package/dist/init/phases/index.d.ts +12 -12
- package/dist/init/phases/index.js +11 -11
- package/dist/init/phases/index.js.map +1 -1
- package/dist/init/phases/{parallel-678.d.ts → parallel-8910.d.ts} +7 -8
- package/dist/init/phases/{parallel-678.js → parallel-8910.js} +34 -46
- package/dist/init/phases/parallel-8910.js.map +1 -0
- package/dist/init/phases/source-comments-output-io.d.ts +3 -3
- package/dist/init/phases/source-comments-output-io.js +3 -3
- package/dist/init/phases/types.d.ts +1 -1
- package/dist/init/phases/types.js +10 -10
- package/dist/init/phases/types.js.map +1 -1
- package/dist/init/rules-merge/discover.d.ts +2 -2
- package/dist/init/rules-merge/discover.js +28 -43
- package/dist/init/rules-merge/discover.js.map +1 -1
- package/dist/init/rules-merge/ingest.d.ts +6 -6
- package/dist/init/rules-merge/ingest.js +9 -10
- package/dist/init/rules-merge/ingest.js.map +1 -1
- package/dist/init/rules-merge/keep-markers.d.ts +1 -1
- package/dist/init/rules-merge/keep-markers.js +1 -1
- package/dist/init/rules-merge/regenerate.d.ts +3 -3
- package/dist/init/rules-merge/regenerate.js +3 -3
- package/dist/init/seed.js +17 -24
- package/dist/init/seed.js.map +1 -1
- package/dist/init/sot-emit.d.ts +48 -8
- package/dist/init/sot-emit.js +88 -10
- package/dist/init/sot-emit.js.map +1 -1
- package/dist/init/source-comments/classify.d.ts +2 -2
- package/dist/init/source-comments/classify.js +9 -1
- package/dist/init/source-comments/classify.js.map +1 -1
- package/dist/init/source-comments/index.d.ts +1 -1
- package/dist/init/source-comments/index.js.map +1 -1
- package/dist/init/source-comments/ingest.d.ts +2 -2
- package/dist/init/source-comments/ingest.js +110 -12
- package/dist/init/source-comments/ingest.js.map +1 -1
- package/dist/init/source-comments/strip-replace.js +3 -2
- package/dist/init/source-comments/strip-replace.js.map +1 -1
- package/dist/init/source-comments/walker.d.ts +3 -26
- package/dist/init/source-comments/walker.js +18 -30
- package/dist/init/source-comments/walker.js.map +1 -1
- package/dist/init/topic-index/index.d.ts +15 -1
- package/dist/init/topic-index/index.js +84 -5
- package/dist/init/topic-index/index.js.map +1 -1
- package/dist/init/topic-index/judge.d.ts +5 -9
- package/dist/init/topic-index/judge.js +25 -17
- package/dist/init/topic-index/judge.js.map +1 -1
- package/dist/init/topic-index/resolve.d.ts +23 -3
- package/dist/init/topic-index/resolve.js +102 -16
- package/dist/init/topic-index/resolve.js.map +1 -1
- package/dist/init/topic-index/walk.d.ts +36 -4
- package/dist/init/topic-index/walk.js +78 -12
- package/dist/init/topic-index/walk.js.map +1 -1
- package/dist/lock.js +4 -1
- package/dist/lock.js.map +1 -1
- package/dist/logger.js +3 -0
- package/dist/logger.js.map +1 -1
- package/dist/mcp/history/summarizer.js +6 -1
- package/dist/mcp/history/summarizer.js.map +1 -1
- package/dist/mcp/history/walker.js +1 -1
- package/dist/mcp/history/walker.js.map +1 -1
- package/dist/mcp/path-allowlist.js +1 -1
- package/dist/mcp/path-allowlist.js.map +1 -1
- package/dist/mcp/schemas.d.ts +47 -21
- package/dist/mcp/schemas.js +38 -9
- package/dist/mcp/schemas.js.map +1 -1
- package/dist/mcp/server.js +10 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/archive.js +1 -1
- package/dist/mcp/tools/archive.js.map +1 -1
- package/dist/mcp/tools/attention-wait.js +12 -2
- package/dist/mcp/tools/attention-wait.js.map +1 -1
- package/dist/mcp/tools/bulk-accept-attention.js +29 -30
- package/dist/mcp/tools/bulk-accept-attention.js.map +1 -1
- package/dist/mcp/tools/canonical-for-topic.js +37 -15
- package/dist/mcp/tools/canonical-for-topic.js.map +1 -1
- package/dist/mcp/tools/decision-get.js +2 -2
- package/dist/mcp/tools/decision-get.js.map +1 -1
- package/dist/mcp/tools/decisions-for-symbol.js +2 -2
- package/dist/mcp/tools/decisions-for-symbol.js.map +1 -1
- package/dist/mcp/tools/get-full.js +1 -1
- package/dist/mcp/tools/get-full.js.map +1 -1
- package/dist/mcp/tools/ground-get.js +1 -1
- package/dist/mcp/tools/ground-get.js.map +1 -1
- package/dist/mcp/tools/in-scope.d.ts +8 -0
- package/dist/mcp/tools/in-scope.js +125 -0
- package/dist/mcp/tools/in-scope.js.map +1 -0
- package/dist/mcp/tools/index.js +11 -6
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/init-phases.d.ts +3 -2
- package/dist/mcp/tools/init-phases.js +125 -124
- package/dist/mcp/tools/init-phases.js.map +1 -1
- package/dist/mcp/tools/invariant-get.js +2 -2
- package/dist/mcp/tools/invariant-get.js.map +1 -1
- package/dist/mcp/tools/record-decision.d.ts +4 -3
- package/dist/mcp/tools/record-decision.js +111 -36
- package/dist/mcp/tools/record-decision.js.map +1 -1
- package/dist/mcp/tools/reject-candidate.d.ts +24 -0
- package/dist/mcp/tools/reject-candidate.js +71 -0
- package/dist/mcp/tools/reject-candidate.js.map +1 -0
- package/dist/mcp/tools/resolve-attention.d.ts +5 -18
- package/dist/mcp/tools/resolve-attention.js +58 -158
- package/dist/mcp/tools/resolve-attention.js.map +1 -1
- package/dist/mcp/tools/search-candidates.d.ts +20 -0
- package/dist/mcp/tools/search-candidates.js +93 -0
- package/dist/mcp/tools/search-candidates.js.map +1 -0
- package/dist/mcp/tools/search.js +5 -4
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/mcp/tools/supersedes-chain.js +2 -2
- package/dist/mcp/tools/supersedes-chain.js.map +1 -1
- package/dist/mcp/tools/task-create.d.ts +1 -0
- package/dist/mcp/tools/task-create.js +2 -0
- package/dist/mcp/tools/task-create.js.map +1 -1
- package/dist/mcp/tools/timeline.js +1 -1
- package/dist/mcp/tools/timeline.js.map +1 -1
- package/dist/mcp/tools/types.d.ts +1 -0
- package/dist/mcp/tools/types.js +9 -1
- package/dist/mcp/tools/types.js.map +1 -1
- package/dist/sensors/attestation.d.ts +1 -1
- package/dist/sensors/attestation.js +2 -2
- package/dist/sensors/attestation.js.map +1 -1
- package/dist/sensors/catalog.d.ts +26 -28
- package/dist/sensors/catalog.js +79 -81
- package/dist/sensors/catalog.js.map +1 -1
- package/dist/sensors/decisions.d.ts +1 -1
- package/dist/sensors/decisions.js +15 -14
- package/dist/sensors/decisions.js.map +1 -1
- package/dist/sensors/diff.js +46 -22
- package/dist/sensors/diff.js.map +1 -1
- package/dist/sensors/runner.d.ts +2 -2
- package/dist/sensors/runner.js +3 -3
- package/dist/sensors/shell.d.ts +4 -0
- package/dist/sensors/shell.js +16 -0
- package/dist/sensors/shell.js.map +1 -0
- package/dist/sensors/structural.d.ts +3 -2
- package/dist/sensors/structural.js +3 -11
- package/dist/sensors/structural.js.map +1 -1
- package/dist/sensors/stub-catalog.d.ts +2 -1
- package/dist/sensors/stub-catalog.js +2 -9
- package/dist/sensors/stub-catalog.js.map +1 -1
- package/dist/sensors/types.d.ts +3 -4
- package/dist/sensors/types.js +1 -2
- package/dist/sensors/types.js.map +1 -1
- package/dist/session-start/build.js +1 -1
- package/dist/session-start/build.js.map +1 -1
- package/dist/status-line/event-queue.js +1 -1
- package/dist/status-line/index.d.ts +1 -1
- package/package.json +3 -2
- package/templates/.cairn/config/sensors.yaml +8 -8
- package/templates/attention-ui/app.js +101 -39
- package/dist/fs.d.ts +0 -5
- package/dist/fs.js +0 -11
- package/dist/fs.js.map +0 -1
- package/dist/ground/alignment-pending.d.ts +0 -28
- package/dist/ground/alignment-pending.js +0 -83
- package/dist/ground/alignment-pending.js.map +0 -1
- package/dist/ground/anchor-map.d.ts +0 -14
- package/dist/ground/anchor-map.js +0 -56
- package/dist/ground/anchor-map.js.map +0 -1
- package/dist/ground/drift.d.ts +0 -8
- package/dist/ground/drift.js +0 -23
- package/dist/ground/drift.js.map +0 -1
- package/dist/ground/frontmatter.d.ts +0 -32
- package/dist/ground/frontmatter.js +0 -77
- package/dist/ground/frontmatter.js.map +0 -1
- package/dist/ground/glob.d.ts +0 -10
- package/dist/ground/glob.js +0 -46
- package/dist/ground/glob.js.map +0 -1
- package/dist/ground/index.d.ts +0 -23
- package/dist/ground/index.js +0 -17
- package/dist/ground/index.js.map +0 -1
- package/dist/ground/ledgers.d.ts +0 -14
- package/dist/ground/ledgers.js +0 -105
- package/dist/ground/ledgers.js.map +0 -1
- package/dist/ground/manifest.d.ts +0 -10
- package/dist/ground/manifest.js +0 -84
- package/dist/ground/manifest.js.map +0 -1
- package/dist/ground/paths.d.ts +0 -41
- package/dist/ground/paths.js +0 -103
- package/dist/ground/paths.js.map +0 -1
- package/dist/ground/quality-grades.d.ts +0 -11
- package/dist/ground/quality-grades.js +0 -100
- package/dist/ground/quality-grades.js.map +0 -1
- package/dist/ground/schemas.d.ts +0 -502
- package/dist/ground/schemas.js +0 -318
- package/dist/ground/schemas.js.map +0 -1
- package/dist/ground/scope-index.d.ts +0 -96
- package/dist/ground/scope-index.js +0 -290
- package/dist/ground/scope-index.js.map +0 -1
- package/dist/ground/slug.d.ts +0 -60
- package/dist/ground/slug.js +0 -103
- package/dist/ground/slug.js.map +0 -1
- package/dist/ground/sot-bindings.d.ts +0 -14
- package/dist/ground/sot-bindings.js +0 -79
- package/dist/ground/sot-bindings.js.map +0 -1
- package/dist/ground/sot-cache.d.ts +0 -18
- package/dist/ground/sot-cache.js +0 -62
- package/dist/ground/sot-cache.js.map +0 -1
- package/dist/ground/topic-index.d.ts +0 -27
- package/dist/ground/topic-index.js +0 -82
- package/dist/ground/topic-index.js.map +0 -1
- package/dist/ground/walk.d.ts +0 -7
- package/dist/ground/walk.js +0 -53
- package/dist/ground/walk.js.map +0 -1
- package/dist/hooks/post-tool-use/ledger-cache.d.ts +0 -40
- package/dist/hooks/post-tool-use/ledger-cache.js +0 -290
- package/dist/hooks/post-tool-use/ledger-cache.js.map +0 -1
- package/dist/init/phases/10-strip.d.ts +0 -11
- package/dist/init/phases/10-strip.js.map +0 -1
- package/dist/init/phases/3b-seed.js.map +0 -1
- package/dist/init/phases/5-brand.js.map +0 -1
- package/dist/init/phases/5b-topic-index.js.map +0 -1
- package/dist/init/phases/6-docs-ingest.d.ts +0 -10
- package/dist/init/phases/6-docs-ingest.js.map +0 -1
- package/dist/init/phases/7b-source-comments.d.ts +0 -15
- package/dist/init/phases/7b-source-comments.js.map +0 -1
- package/dist/init/phases/7c-rules-merge.js.map +0 -1
- package/dist/init/phases/8-baseline.d.ts +0 -10
- package/dist/init/phases/8-baseline.js.map +0 -1
- package/dist/init/phases/parallel-678.js.map +0 -1
- package/dist/mcp/tools/decisions-in-scope.d.ts +0 -7
- package/dist/mcp/tools/decisions-in-scope.js +0 -66
- package/dist/mcp/tools/decisions-in-scope.js.map +0 -1
- package/dist/mcp/tools/invariants-in-scope.d.ts +0 -7
- package/dist/mcp/tools/invariants-in-scope.js +0 -81
- package/dist/mcp/tools/invariants-in-scope.js.map +0 -1
|
@@ -4,50 +4,47 @@
|
|
|
4
4
|
* Spec: PLUGIN_ARCHITECTURE §9 (MCP write tools — plugin-era addition).
|
|
5
5
|
*
|
|
6
6
|
* The cairn-attention skill calls this after the operator picks an
|
|
7
|
-
* option. It maps
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* | kind | choice | resolution |
|
|
11
|
-
* |---------------------|--------|---------------------------------------------|
|
|
12
|
-
* | decision_draft | a | accept — move `_inbox/<id>.draft.md` → `<id>.md`, status=accepted |
|
|
13
|
-
* | decision_draft | b | reject — rename draft to .rejected.md (id reserved forever) |
|
|
14
|
-
* | decision_draft | c | edit-pending — return draft body (no write) |
|
|
15
|
-
* | baseline_finding | a | triage-now — no-op (skill opens the file) |
|
|
16
|
-
* | baseline_finding | b | suppress — append to baseline/suppressions.yaml |
|
|
17
|
-
* | baseline_finding | c | defer — no-op |
|
|
18
|
-
* | invalidation_event | a | refresh — re-read in-scope DECs/§INVs |
|
|
19
|
-
* | invalidation_event | b | continue-under-old — no-op |
|
|
20
|
-
* | invalidation_event | c | abort — caller archives task (no-op here) |
|
|
21
|
-
* | drift | a/b/c | acknowledged (drift surface not yet active) |
|
|
7
|
+
* option. It maps the option (a/b/c/d) to a ground-state write (promote
|
|
8
|
+
* draft, suppress finding, record resolution event).
|
|
22
9
|
*/
|
|
23
10
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
24
11
|
import { dirname, join } from "node:path";
|
|
25
|
-
import { writeFileSafe } from "../../fs.js";
|
|
26
12
|
import { createHash } from "node:crypto";
|
|
27
13
|
import { stringify as stringifyYaml } from "yaml";
|
|
28
|
-
import {
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { bindDec, bodyContentHash, conflictsDir, readSotBindings, readSotCache, recordDriftEvent, setSotCacheEntry, writeSotBindings, writeSotCache, decisionsDir, invariantsDir, writeDecisionsLedger, writeInvariantsLedger, parseFrontmatterRecord, deleteSotCacheEntry, unbindDec, alignmentPendingDir, archivedConflictsDir, deriveLedgerDecId, deriveLedgerInvId, writeFileSafe, } from "@isaacriehm/cairn-state";
|
|
29
16
|
import { writeInvalidationEvent } from "../../events/index.js";
|
|
30
|
-
import { alignmentPendingDir, archivedConflictsDir, bindDec, bodyContentHash, conflictsDir, decisionsDir, deleteSotCacheEntry, deriveLedgerDecId, deriveLedgerInvId, invariantsDir, parseFrontmatterRecord, readSotBindings, readSotCache, recordDriftEvent, setSotCacheEntry, unbindDec, writeSotBindings, writeSotCache, } from "../../ground/index.js";
|
|
31
|
-
import { tokenize } from "../../text/jaccard.js";
|
|
32
|
-
import { applyStripReplace, formatBareCitation, } from "../../init/source-comments/index.js";
|
|
33
|
-
import { writeDecisionsLedger, writeInvariantsLedger } from "../../ground/ledgers.js";
|
|
34
|
-
import { clearDeferState, writeDeferState, } from "../../hooks/defer.js";
|
|
35
17
|
import { withWriteLock } from "../../lock.js";
|
|
36
|
-
import { logger } from "../../logger.js";
|
|
37
18
|
import { requireBootstrap } from "../bootstrap-guard.js";
|
|
38
|
-
import { mcpError } from "
|
|
39
|
-
import {
|
|
40
|
-
|
|
19
|
+
import { mcpError } from "./types.js";
|
|
20
|
+
import { parseDraftMeta, runDecSourceStrip, } from "../../attention/source-strip.js";
|
|
21
|
+
import { restoreDec } from "../../attention/restore.js";
|
|
22
|
+
import { tokenize } from "../../text/jaccard.js";
|
|
23
|
+
import { applyStripReplace, formatBareCitation, } from "../../init/source-comments/strip-replace.js";
|
|
24
|
+
import { writeDeferState, clearDeferState } from "../../hooks/defer.js";
|
|
25
|
+
import { logger } from "../../logger.js";
|
|
26
|
+
const log = logger("mcp.tools.resolve-attention");
|
|
27
|
+
const resolveAttentionInput = {
|
|
28
|
+
kind: z.enum([
|
|
29
|
+
"decision_draft",
|
|
30
|
+
"baseline_finding",
|
|
31
|
+
"invalidation_event",
|
|
32
|
+
"drift",
|
|
33
|
+
"bypass",
|
|
34
|
+
"review",
|
|
35
|
+
"conflict",
|
|
36
|
+
"alignment_pending",
|
|
37
|
+
]),
|
|
38
|
+
item_id: z.string(),
|
|
39
|
+
choice: z.enum(["a", "b", "c", "d"]),
|
|
40
|
+
rationale: z.string().optional(),
|
|
41
|
+
defer_hours: z.number().optional(),
|
|
42
|
+
flagged_items: z.array(z.string()).optional(),
|
|
43
|
+
};
|
|
41
44
|
async function handler(ctx, input) {
|
|
42
45
|
const block = requireBootstrap(ctx.repoRoot);
|
|
43
46
|
if (block !== null)
|
|
44
47
|
return block;
|
|
45
|
-
// The fourth choice slot is only meaningful for conflict resolution.
|
|
46
|
-
// Reject `d` on every other kind so the schema's permissive enum
|
|
47
|
-
// doesn't quietly fall through.
|
|
48
|
-
if (input.choice === "d" && input.kind !== "conflict") {
|
|
49
|
-
return mcpError("VALIDATION_FAILED", `choice "d" is only valid for kind=conflict, got kind=${input.kind}`);
|
|
50
|
-
}
|
|
51
48
|
switch (input.kind) {
|
|
52
49
|
case "decision_draft":
|
|
53
50
|
return resolveDecisionDraft(ctx, input);
|
|
@@ -55,28 +52,18 @@ async function handler(ctx, input) {
|
|
|
55
52
|
return resolveBaselineFinding(ctx, input);
|
|
56
53
|
case "invalidation_event":
|
|
57
54
|
return resolveInvalidationEvent(ctx, input);
|
|
58
|
-
case "drift":
|
|
59
|
-
return {
|
|
60
|
-
ok: true,
|
|
61
|
-
resolved_kind: "drift_acknowledged",
|
|
62
|
-
note: "drift resolution surface not yet implemented (step 7+); item left in queue",
|
|
63
|
-
};
|
|
64
55
|
case "bypass":
|
|
65
|
-
return
|
|
56
|
+
return resolveStopSignal(ctx, input, "bypass");
|
|
66
57
|
case "review":
|
|
67
|
-
return
|
|
58
|
+
return resolveStopSignal(ctx, input, "review");
|
|
68
59
|
case "conflict":
|
|
69
60
|
return resolveConflict(ctx, input);
|
|
70
61
|
case "alignment_pending":
|
|
71
62
|
return resolveAlignmentPending(ctx, input);
|
|
63
|
+
default:
|
|
64
|
+
return mcpError("VALIDATION_FAILED", `unknown kind: ${input.kind}`);
|
|
72
65
|
}
|
|
73
66
|
}
|
|
74
|
-
function resolveBypass(ctx, input) {
|
|
75
|
-
return resolveStopSignal(ctx, input, "bypass");
|
|
76
|
-
}
|
|
77
|
-
function resolveReview(ctx, input) {
|
|
78
|
-
return resolveStopSignal(ctx, input, "review");
|
|
79
|
-
}
|
|
80
67
|
/**
|
|
81
68
|
* Shared resolution path for the two Stop-hook surfaces. choice=a/b
|
|
82
69
|
* are kind-specific intents (the calling skill executes them); the
|
|
@@ -92,7 +79,6 @@ function resolveStopSignal(ctx, input, kind) {
|
|
|
92
79
|
const state = writeDeferState(ctx.repoRoot, kind, {
|
|
93
80
|
flagged_shas: kind === "bypass" ? flagged : [],
|
|
94
81
|
flagged_task_ids: kind === "review" ? flagged : [],
|
|
95
|
-
...(input.defer_hours !== undefined ? { hours: input.defer_hours } : {}),
|
|
96
82
|
});
|
|
97
83
|
return {
|
|
98
84
|
ok: true,
|
|
@@ -133,13 +119,6 @@ async function resolveDecisionDraft(ctx, input) {
|
|
|
133
119
|
const inboxPath = join(decDir, "_inbox", `${input.item_id}.draft.md`);
|
|
134
120
|
const rejectedPath = join(decDir, "_inbox", `${input.item_id}.rejected.md`);
|
|
135
121
|
const acceptedPath = join(decDir, `${input.item_id}.md`);
|
|
136
|
-
// Auto-restore: when the draft is missing but the same id sits as a
|
|
137
|
-
// rejected or already-accepted entry, transparently roll it back to
|
|
138
|
-
// a draft so the operator's choice (a/b/c) lands in one MCP call
|
|
139
|
-
// instead of needing an explicit `cairn_attention_restore` first.
|
|
140
|
-
// Idempotent re-accept on a still-canonical accepted DEC is the same
|
|
141
|
-
// shape as accepting a fresh draft — rebuild ledger, no double-strip
|
|
142
|
-
// (already-stripped check inside runDecSourceStrip).
|
|
143
122
|
let autoRestoredFrom = null;
|
|
144
123
|
if (!existsSync(inboxPath)) {
|
|
145
124
|
if (existsSync(rejectedPath) || existsSync(acceptedPath)) {
|
|
@@ -160,8 +139,6 @@ async function resolveDecisionDraft(ctx, input) {
|
|
|
160
139
|
}
|
|
161
140
|
}
|
|
162
141
|
if (input.choice === "c") {
|
|
163
|
-
// Edit-pending: return the draft body so the skill can hand it to
|
|
164
|
-
// the operator's editor flow. No state change.
|
|
165
142
|
const body = readFileSync(inboxPath, "utf8");
|
|
166
143
|
const editBase = {
|
|
167
144
|
ok: true,
|
|
@@ -174,7 +151,7 @@ async function resolveDecisionDraft(ctx, input) {
|
|
|
174
151
|
? editBase
|
|
175
152
|
: { ...editBase, auto_restored_from: autoRestoredFrom };
|
|
176
153
|
}
|
|
177
|
-
return withWriteLock(ctx.repoRoot, () => {
|
|
154
|
+
return withWriteLock(ctx.repoRoot, async () => {
|
|
178
155
|
if (input.choice === "a") {
|
|
179
156
|
const acceptedPath = join(decDir, `${input.item_id}.md`);
|
|
180
157
|
mkdirSync(dirname(acceptedPath), { recursive: true });
|
|
@@ -182,25 +159,18 @@ async function resolveDecisionDraft(ctx, input) {
|
|
|
182
159
|
const draftMeta = parseDraftMeta(draft);
|
|
183
160
|
const promoted = promoteDraftStatus(draft);
|
|
184
161
|
writeFileSync(acceptedPath, promoted, "utf8");
|
|
185
|
-
// Remove the draft after promoting so the inbox stays clean.
|
|
186
|
-
// The canonical accepted file at <decDir>/<id>.md is the
|
|
187
|
-
// recoverable copy if the rmSync interrupts.
|
|
188
162
|
try {
|
|
189
163
|
rmSync(inboxPath, { force: true });
|
|
190
164
|
}
|
|
191
165
|
catch {
|
|
192
|
-
// ignore
|
|
166
|
+
// ignore
|
|
193
167
|
}
|
|
194
168
|
try {
|
|
195
169
|
emitEvent(ctx, "decision_accepted", input.item_id, `.cairn/ground/decisions/${input.item_id}.md`);
|
|
196
170
|
}
|
|
197
171
|
catch {
|
|
198
|
-
//
|
|
172
|
+
// ignore
|
|
199
173
|
}
|
|
200
|
-
// Rebuild `.cairn/ground/decisions/decisions.ledger.yaml` from
|
|
201
|
-
// every accepted DEC on disk. Cairn Lens reads the ledger to
|
|
202
|
-
// resolve `// DEC-NNNN` citations inline; without this rebuild
|
|
203
|
-
// the ledger sits empty and lens renders nothing.
|
|
204
174
|
try {
|
|
205
175
|
writeDecisionsLedger({ repoRoot: ctx.repoRoot });
|
|
206
176
|
}
|
|
@@ -226,8 +196,7 @@ async function resolveDecisionDraft(ctx, input) {
|
|
|
226
196
|
? withStrip
|
|
227
197
|
: { ...withStrip, auto_restored_from: autoRestoredFrom };
|
|
228
198
|
}
|
|
229
|
-
// choice === "b" — reject.
|
|
230
|
-
// keeps the id in the high-water mark and it is never recycled.
|
|
199
|
+
// choice === "b" — reject.
|
|
231
200
|
renameSync(inboxPath, rejectedPath);
|
|
232
201
|
const rejectedRel = `.cairn/ground/decisions/_inbox/${input.item_id}.rejected.md`;
|
|
233
202
|
try {
|
|
@@ -265,9 +234,6 @@ function resolveBaselineFinding(ctx, input) {
|
|
|
265
234
|
return withWriteLock(ctx.repoRoot, () => {
|
|
266
235
|
const suppressionsPath = join(ctx.repoRoot, ".cairn", "baseline", "suppressions.yaml");
|
|
267
236
|
mkdirSync(dirname(suppressionsPath), { recursive: true });
|
|
268
|
-
// Empty / missing file → seed the YAML root key so the appended
|
|
269
|
-
// entries land under a valid `suppressions:` list. statSync may
|
|
270
|
-
// throw on race; treat any error as "needs header".
|
|
271
237
|
let needsHeader = !existsSync(suppressionsPath);
|
|
272
238
|
if (!needsHeader) {
|
|
273
239
|
try {
|
|
@@ -391,20 +357,6 @@ function deleteConflictFile(conflict) {
|
|
|
391
357
|
/* best-effort */
|
|
392
358
|
}
|
|
393
359
|
}
|
|
394
|
-
/**
|
|
395
|
-
* Plan §5.4.1 — losing-side prose stays in its source file
|
|
396
|
-
* post-resolution; the doc / CLAUDE.md / AGENTS.md narrative is
|
|
397
|
-
* preserved as-is. The original sot_path entry is now bound to a
|
|
398
|
-
* superseded / archived id, so phase 5b's next walk would re-emit a
|
|
399
|
-
* fresh DEC with the same content-addressed id (loop). Recording an
|
|
400
|
-
* `orphan_path` drift event surfaces the prose to the operator's
|
|
401
|
-
* attention queue so they can pick: re-cite the winner manually,
|
|
402
|
-
* promote it to a fresh DEC, or delete the orphan paragraph.
|
|
403
|
-
*
|
|
404
|
-
* The drift event includes `dec_id` pointing at the just-superseded
|
|
405
|
-
* entity so the attention surface can render context (which side won,
|
|
406
|
-
* what the orphan body looks like).
|
|
407
|
-
*/
|
|
408
360
|
function recordOrphanDriftEvents(repoRoot, refs) {
|
|
409
361
|
const ts = new Date().toISOString();
|
|
410
362
|
for (const { ref, parsed } of refs) {
|
|
@@ -436,22 +388,15 @@ function rebuildLedgers(repoRoot) {
|
|
|
436
388
|
writeDecisionsLedger({ repoRoot });
|
|
437
389
|
}
|
|
438
390
|
catch (err) {
|
|
439
|
-
log.warn({ err: err instanceof Error ? err.message : String(err) }, "decisions ledger rebuild failed
|
|
391
|
+
log.warn({ err: err instanceof Error ? err.message : String(err) }, "decisions ledger rebuild failed");
|
|
440
392
|
}
|
|
441
393
|
try {
|
|
442
394
|
writeInvariantsLedger({ repoRoot });
|
|
443
395
|
}
|
|
444
396
|
catch (err) {
|
|
445
|
-
log.warn({ err: err instanceof Error ? err.message : String(err) }, "invariants ledger rebuild failed
|
|
397
|
+
log.warn({ err: err instanceof Error ? err.message : String(err) }, "invariants ledger rebuild failed");
|
|
446
398
|
}
|
|
447
399
|
}
|
|
448
|
-
/**
|
|
449
|
-
* Drop superseded / archived losers from sot-bindings + sot-cache so
|
|
450
|
-
* Layer A's pre-filter doesn't pick them as candidates and phase 5b
|
|
451
|
-
* doesn't loop on a path bound to a now-superseded id. The orphan_path
|
|
452
|
-
* drift event (recorded separately for sot_kind="path" losers) remains
|
|
453
|
-
* the operator-facing surface to recover the orphaned prose.
|
|
454
|
-
*/
|
|
455
400
|
function cleanLosersFromSotState(repoRoot, losers) {
|
|
456
401
|
let bindings = readSotBindings(repoRoot);
|
|
457
402
|
let cache = readSotCache(repoRoot);
|
|
@@ -473,30 +418,24 @@ function cleanLosersFromSotState(repoRoot, losers) {
|
|
|
473
418
|
try {
|
|
474
419
|
writeSotBindings(repoRoot, bindings);
|
|
475
420
|
}
|
|
476
|
-
catch
|
|
477
|
-
|
|
421
|
+
catch {
|
|
422
|
+
/* ignore */
|
|
478
423
|
}
|
|
479
424
|
try {
|
|
480
425
|
writeSotCache(repoRoot, cache);
|
|
481
426
|
}
|
|
482
|
-
catch
|
|
483
|
-
|
|
427
|
+
catch {
|
|
428
|
+
/* ignore */
|
|
484
429
|
}
|
|
485
430
|
}
|
|
486
|
-
/**
|
|
487
|
-
* Bind + cache a merged entity that was just written to ground. Mirrors
|
|
488
|
-
* the bind/cache wiring in `emitFreshDec` so Layer A's pre-filter sees
|
|
489
|
-
* the merged DEC as a Tier-2 candidate immediately, instead of waiting
|
|
490
|
-
* for the next SessionStart drain to rebuild sot-cache.
|
|
491
|
-
*/
|
|
492
431
|
function bindAndCacheMergedEntity(repoRoot, mergedId, mergedBody) {
|
|
493
432
|
let bindings = readSotBindings(repoRoot);
|
|
494
433
|
bindings = bindDec(bindings, mergedId, "ledger");
|
|
495
434
|
try {
|
|
496
435
|
writeSotBindings(repoRoot, bindings);
|
|
497
436
|
}
|
|
498
|
-
catch
|
|
499
|
-
|
|
437
|
+
catch {
|
|
438
|
+
/* ignore */
|
|
500
439
|
}
|
|
501
440
|
let cache = readSotCache(repoRoot);
|
|
502
441
|
cache = setSotCacheEntry(cache, mergedId, {
|
|
@@ -510,8 +449,8 @@ function bindAndCacheMergedEntity(repoRoot, mergedId, mergedBody) {
|
|
|
510
449
|
try {
|
|
511
450
|
writeSotCache(repoRoot, cache);
|
|
512
451
|
}
|
|
513
|
-
catch
|
|
514
|
-
|
|
452
|
+
catch {
|
|
453
|
+
/* ignore */
|
|
515
454
|
}
|
|
516
455
|
}
|
|
517
456
|
function loadAlignmentPending(repoRoot, itemId) {
|
|
@@ -528,11 +467,8 @@ function loadAlignmentPending(repoRoot, itemId) {
|
|
|
528
467
|
return null;
|
|
529
468
|
}
|
|
530
469
|
const { fm, body } = parseFrontmatterRecord(raw);
|
|
531
|
-
// Block prose lives between the first ```/``` fence pair under the
|
|
532
|
-
// "## Block ..." heading. Pick the first fenced block.
|
|
533
470
|
const blockMatch = body.match(/##\s+Block[^\n]*\n+```\n([\s\S]*?)\n```/);
|
|
534
471
|
const blockProse = blockMatch?.[1]?.trim() ?? "";
|
|
535
|
-
// Existing entity body (tier2-ambiguous only) lives in a second fenced block.
|
|
536
472
|
const existingId = typeof fm["existing_id"] === "string" ? fm["existing_id"] : null;
|
|
537
473
|
let existingBody = null;
|
|
538
474
|
if (existingId !== null) {
|
|
@@ -579,7 +515,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
579
515
|
return mcpError("VALIDATION_FAILED", "tier2-ambiguous pending entry missing existing_id");
|
|
580
516
|
}
|
|
581
517
|
if (input.choice === "a") {
|
|
582
|
-
// Same — cite existing.
|
|
583
518
|
const replacement = formatBareCitation(lang, state.existingId);
|
|
584
519
|
const item = buildPendingReplaceItem(state.fm, state.blockProse, replacement);
|
|
585
520
|
if (item !== null)
|
|
@@ -597,10 +532,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
597
532
|
};
|
|
598
533
|
}
|
|
599
534
|
if (input.choice === "b") {
|
|
600
|
-
// Augments — emit sibling DEC linked via `related`. Source gets
|
|
601
|
-
// both cites stacked. (Operator-driven augments emit a DEC
|
|
602
|
-
// sibling; constraint augments still flow through the Layer A
|
|
603
|
-
// delta classifier on a future Write.)
|
|
604
535
|
const id = emitOperatorAugmentSibling(ctx.repoRoot, {
|
|
605
536
|
source_file: sourceFile,
|
|
606
537
|
source_offset: startLine,
|
|
@@ -634,7 +565,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
634
565
|
};
|
|
635
566
|
}
|
|
636
567
|
if (input.choice === "c") {
|
|
637
|
-
// New decision — emit fresh DEC, source carries new cite only.
|
|
638
568
|
const id = emitFreshDec(ctx.repoRoot, {
|
|
639
569
|
source_file: sourceFile,
|
|
640
570
|
source_offset: startLine,
|
|
@@ -665,7 +595,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
665
595
|
};
|
|
666
596
|
}
|
|
667
597
|
if (input.choice === "d") {
|
|
668
|
-
// Replace — new becomes canonical, existing superseded.
|
|
669
598
|
const id = emitFreshDec(ctx.repoRoot, {
|
|
670
599
|
source_file: sourceFile,
|
|
671
600
|
source_offset: startLine,
|
|
@@ -673,7 +602,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
673
602
|
captureSuffix: "operator-replace",
|
|
674
603
|
related: state.existingId,
|
|
675
604
|
});
|
|
676
|
-
// Mark existing as superseded.
|
|
677
605
|
const existingRef = entityRefFor(ctx.repoRoot, state.existingId);
|
|
678
606
|
const parsed = readEntity(existingRef);
|
|
679
607
|
if (parsed !== null) {
|
|
@@ -744,8 +672,6 @@ async function resolveAlignmentPending(ctx, input) {
|
|
|
744
672
|
};
|
|
745
673
|
}
|
|
746
674
|
if (input.choice === "c" || input.choice === "d") {
|
|
747
|
-
// Descriptive / none-of-these — drop the pending file. Source
|
|
748
|
-
// stays untouched (operator's narrative preserved).
|
|
749
675
|
rmSync(state.abs, { force: true });
|
|
750
676
|
return {
|
|
751
677
|
ok: true,
|
|
@@ -822,9 +748,9 @@ function firstLineOf(text) {
|
|
|
822
748
|
async function resolveConflict(ctx, input) {
|
|
823
749
|
const conflict = parseConflictFile(ctx.repoRoot, input.item_id);
|
|
824
750
|
if (conflict === null) {
|
|
825
|
-
return mcpError("FILE_NOT_FOUND", `no conflict file for item_id=${input.item_id}
|
|
751
|
+
return mcpError("FILE_NOT_FOUND", `no conflict file for item_id=${input.item_id}`);
|
|
826
752
|
}
|
|
827
|
-
return withWriteLock(ctx.repoRoot, () => {
|
|
753
|
+
return withWriteLock(ctx.repoRoot, async () => {
|
|
828
754
|
const winner = input.choice === "a" ? conflict.aRef : conflict.bRef;
|
|
829
755
|
const loser = input.choice === "a" ? conflict.bRef : conflict.aRef;
|
|
830
756
|
if (input.choice === "a" || input.choice === "b") {
|
|
@@ -832,7 +758,7 @@ async function resolveConflict(ctx, input) {
|
|
|
832
758
|
const winnerOk = setSupersedes(loser, winner);
|
|
833
759
|
const loserOk = setSupersededBy(ctx.repoRoot, loser, winner.id, "superseded");
|
|
834
760
|
if (!winnerOk || !loserOk) {
|
|
835
|
-
return mcpError("VALIDATION_FAILED", `conflict resolution failed: missing entity
|
|
761
|
+
return mcpError("VALIDATION_FAILED", `conflict resolution failed: missing entity`);
|
|
836
762
|
}
|
|
837
763
|
recordOrphanDriftEvents(ctx.repoRoot, [{ ref: loser, parsed: loserBefore }]);
|
|
838
764
|
deleteConflictFile(conflict);
|
|
@@ -850,7 +776,7 @@ async function resolveConflict(ctx, input) {
|
|
|
850
776
|
});
|
|
851
777
|
}
|
|
852
778
|
catch {
|
|
853
|
-
/*
|
|
779
|
+
/* ignore */
|
|
854
780
|
}
|
|
855
781
|
return {
|
|
856
782
|
ok: true,
|
|
@@ -895,7 +821,7 @@ async function resolveConflict(ctx, input) {
|
|
|
895
821
|
});
|
|
896
822
|
}
|
|
897
823
|
catch {
|
|
898
|
-
/*
|
|
824
|
+
/* ignore */
|
|
899
825
|
}
|
|
900
826
|
return {
|
|
901
827
|
ok: true,
|
|
@@ -908,11 +834,11 @@ async function resolveConflict(ctx, input) {
|
|
|
908
834
|
...(input.rationale !== undefined ? { rationale: input.rationale } : {}),
|
|
909
835
|
};
|
|
910
836
|
}
|
|
911
|
-
// choice === "d" — archive both.
|
|
837
|
+
// choice === "d" — archive both.
|
|
912
838
|
const aBefore = readEntity(conflict.aRef);
|
|
913
839
|
const bBefore = readEntity(conflict.bRef);
|
|
914
|
-
|
|
915
|
-
|
|
840
|
+
setSupersededBy(ctx.repoRoot, conflict.aRef, conflict.bRef.id, "archived");
|
|
841
|
+
setSupersededBy(ctx.repoRoot, conflict.bRef, conflict.aRef.id, "archived");
|
|
916
842
|
recordOrphanDriftEvents(ctx.repoRoot, [
|
|
917
843
|
{ ref: conflict.aRef, parsed: aBefore },
|
|
918
844
|
{ ref: conflict.bRef, parsed: bBefore },
|
|
@@ -938,10 +864,7 @@ async function resolveConflict(ctx, input) {
|
|
|
938
864
|
});
|
|
939
865
|
}
|
|
940
866
|
catch {
|
|
941
|
-
/*
|
|
942
|
-
}
|
|
943
|
-
if (!aOk || !bOk) {
|
|
944
|
-
log.warn({ aOk, bOk, item_id: input.item_id }, "archive-both: one or both entities missing on disk");
|
|
867
|
+
/* ignore */
|
|
945
868
|
}
|
|
946
869
|
return {
|
|
947
870
|
ok: true,
|
|
@@ -959,13 +882,10 @@ function mergeConflict(repoRoot, conflict, rationale) {
|
|
|
959
882
|
const b = readEntity(conflict.bRef);
|
|
960
883
|
if (a === null || b === null) {
|
|
961
884
|
return {
|
|
962
|
-
error: mcpError("VALIDATION_FAILED", `merge requires both entities present on disk
|
|
885
|
+
error: mcpError("VALIDATION_FAILED", `merge requires both entities present on disk`),
|
|
963
886
|
};
|
|
964
887
|
}
|
|
965
888
|
const now = new Date().toISOString();
|
|
966
|
-
// Merged entity inherits the kind of A (the freshly captured side).
|
|
967
|
-
// Mixed DEC/INV merges produce a DEC by convention — the merged
|
|
968
|
-
// entity carries combined narrative, not a single hard constraint.
|
|
969
889
|
const mergedKind = conflict.aRef.kind === "INV" && conflict.bRef.kind === "INV" ? "INV" : "DEC";
|
|
970
890
|
const mergedId = synthesizeMergedId(repoRoot, mergedKind);
|
|
971
891
|
const mergedRel = mergedKind === "DEC"
|
|
@@ -1013,20 +933,12 @@ function mergeConflict(repoRoot, conflict, rationale) {
|
|
|
1013
933
|
mergedFm["decided_by"] = "cairn-conflict-merge";
|
|
1014
934
|
}
|
|
1015
935
|
writeFileSafe(mergedAbs, `---\n${stringifyYaml(mergedFm).trimEnd()}\n---\n${mergedBody}`);
|
|
1016
|
-
// Both old entries get superseded_by → new merged id.
|
|
1017
936
|
setSupersededBy(repoRoot, conflict.aRef, mergedId, "superseded");
|
|
1018
937
|
setSupersededBy(repoRoot, conflict.bRef, mergedId, "superseded");
|
|
1019
|
-
// Bind + cache the merged entity so Layer A picks it up on the next
|
|
1020
|
-
// PostToolUse without waiting for SessionStart drain.
|
|
1021
938
|
bindAndCacheMergedEntity(repoRoot, mergedId, mergedBody);
|
|
1022
939
|
return { mergedId, mergedRel };
|
|
1023
940
|
}
|
|
1024
941
|
function synthesizeMergedId(repoRoot, kind) {
|
|
1025
|
-
// Content-addressed style — derive from the timestamp + a counter so
|
|
1026
|
-
// re-runs in the same millisecond don't collide. We don't have the
|
|
1027
|
-
// verbatim merged-body hash easily reachable here without circular
|
|
1028
|
-
// dependencies; the timestamp gives us a stable-enough seed since
|
|
1029
|
-
// merges are operator-driven and infrequent.
|
|
1030
942
|
const dir = kind === "DEC" ? decisionsDir(repoRoot) : invariantsDir(repoRoot);
|
|
1031
943
|
const existing = new Set();
|
|
1032
944
|
if (existsSync(dir)) {
|
|
@@ -1038,7 +950,7 @@ function synthesizeMergedId(repoRoot, kind) {
|
|
|
1038
950
|
}
|
|
1039
951
|
}
|
|
1040
952
|
catch {
|
|
1041
|
-
/*
|
|
953
|
+
/* ignore */
|
|
1042
954
|
}
|
|
1043
955
|
}
|
|
1044
956
|
const seed = `merge-${Date.now()}-${Math.floor(Math.random() * 1_000_000)}`;
|
|
@@ -1054,17 +966,11 @@ function hashHex(input) {
|
|
|
1054
966
|
return createHash("sha256").update(input, "utf8").digest("hex");
|
|
1055
967
|
}
|
|
1056
968
|
function resolveInvalidationEvent(_ctx, input) {
|
|
1057
|
-
// Per spec §7: A=refresh, B=continue-under-old, C=abort. The marker
|
|
1058
|
-
// stamping + scope refresh happens in the calling skill, since it
|
|
1059
|
-
// owns the session id. This tool just acknowledges the resolution
|
|
1060
|
-
// so the skill can record it.
|
|
1061
969
|
const map = {
|
|
1062
970
|
a: "refresh",
|
|
1063
971
|
b: "continue_under_old",
|
|
1064
972
|
c: "abort",
|
|
1065
973
|
};
|
|
1066
|
-
// The "d" slot is filtered out for non-conflict kinds in the top
|
|
1067
|
-
// dispatcher, so this cast is safe.
|
|
1068
974
|
const choice = input.choice;
|
|
1069
975
|
return Promise.resolve({
|
|
1070
976
|
ok: true,
|
|
@@ -1074,12 +980,6 @@ function resolveInvalidationEvent(_ctx, input) {
|
|
|
1074
980
|
});
|
|
1075
981
|
}
|
|
1076
982
|
function promoteDraftStatus(body) {
|
|
1077
|
-
// Frontmatter `status: draft*` → `status: accepted`. Best-effort
|
|
1078
|
-
// regex — covers every draft marker the init pipeline emits:
|
|
1079
|
-
// - `draft` (legacy / generic)
|
|
1080
|
-
// - `draft-from-init-docs` (phase 6)
|
|
1081
|
-
// - `draft-from-source-comment` (phase 7b)
|
|
1082
|
-
// - `draft-from-rules-merge` (phase 7c)
|
|
1083
983
|
return body.replace(/^status:\s*draft(?:-from-[a-z-]+)?\b/m, "status: accepted");
|
|
1084
984
|
}
|
|
1085
985
|
function emitEvent(ctx, kind, decId, path) {
|