@isaacriehm/cairn-core 0.19.1 → 0.22.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/dist/.tsbuildinfo +1 -1
- package/dist/align-undo/log.js +3 -2
- package/dist/align-undo/log.js.map +1 -1
- package/dist/attention/index.d.ts +0 -2
- package/dist/attention/index.js +0 -2
- package/dist/attention/index.js.map +1 -1
- package/dist/attention/restore.d.ts +1 -1
- package/dist/attention/restore.js +1 -1
- package/dist/attention/source-strip.d.ts +2 -2
- package/dist/attention/source-strip.js +4 -3
- package/dist/attention/source-strip.js.map +1 -1
- package/dist/components/audit.d.ts +7 -1
- package/dist/components/audit.js +144 -72
- package/dist/components/audit.js.map +1 -1
- package/dist/components/emit.js +33 -6
- package/dist/components/emit.js.map +1 -1
- package/dist/components/freshness.d.ts +51 -0
- package/dist/components/freshness.js +121 -0
- package/dist/components/freshness.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/reconfirm.d.ts +64 -0
- package/dist/components/reconfirm.js +204 -0
- package/dist/components/reconfirm.js.map +1 -0
- package/dist/context/handoff-builder.js +3 -3
- package/dist/context/handoff-builder.js.map +1 -1
- package/dist/context/task-summary.js +2 -2
- package/dist/context/task-summary.js.map +1 -1
- package/dist/doctor/index.js +102 -9
- package/dist/doctor/index.js.map +1 -1
- package/dist/events/paths.js +2 -2
- package/dist/events/paths.js.map +1 -1
- package/dist/fix-align/sentinel.js +2 -3
- package/dist/fix-align/sentinel.js.map +1 -1
- package/dist/gc/attested-commits.js +2 -2
- package/dist/gc/attested-commits.js.map +1 -1
- package/dist/gc/canary.js +2 -3
- package/dist/gc/canary.js.map +1 -1
- package/dist/gc/citation-integrity.d.ts +4 -5
- package/dist/gc/citation-integrity.js +11 -33
- package/dist/gc/citation-integrity.js.map +1 -1
- package/dist/gc/classify.js +3 -16
- package/dist/gc/classify.js.map +1 -1
- package/dist/gc/completion-integrity.js +4 -3
- package/dist/gc/completion-integrity.js.map +1 -1
- package/dist/gc/entity-orphan.js +66 -12
- package/dist/gc/entity-orphan.js.map +1 -1
- package/dist/gc/ghost-anchor.d.ts +57 -0
- package/dist/gc/ghost-anchor.js +171 -0
- package/dist/gc/ghost-anchor.js.map +1 -0
- package/dist/gc/index.d.ts +2 -0
- package/dist/gc/index.js +1 -0
- package/dist/gc/index.js.map +1 -1
- package/dist/gc/sweep.d.ts +1 -1
- package/dist/gc/sweep.js +13 -1
- package/dist/gc/sweep.js.map +1 -1
- package/dist/gc/types.d.ts +1 -1
- package/dist/hooks/bypass-detection.js +3 -2
- package/dist/hooks/bypass-detection.js.map +1 -1
- package/dist/hooks/defer.js +3 -2
- package/dist/hooks/defer.js.map +1 -1
- package/dist/hooks/ghost-backup.d.ts +37 -0
- package/dist/hooks/ghost-backup.js +82 -0
- package/dist/hooks/ghost-backup.js.map +1 -0
- package/dist/hooks/post-tool-use/allowlist-reader.js +2 -2
- package/dist/hooks/post-tool-use/allowlist-reader.js.map +1 -1
- package/dist/hooks/post-tool-use/ask-user-blocked.d.ts +1 -2
- package/dist/hooks/post-tool-use/ask-user-blocked.js +3 -4
- package/dist/hooks/post-tool-use/ask-user-blocked.js.map +1 -1
- package/dist/hooks/post-tool-use/citation-scanner.d.ts +9 -7
- package/dist/hooks/post-tool-use/citation-scanner.js +9 -14
- package/dist/hooks/post-tool-use/citation-scanner.js.map +1 -1
- package/dist/hooks/post-tool-use/legend-builder.d.ts +2 -2
- package/dist/hooks/post-tool-use/legend-builder.js +1 -19
- package/dist/hooks/post-tool-use/legend-builder.js.map +1 -1
- package/dist/hooks/post-tool-use/post-write.js +18 -1
- package/dist/hooks/post-tool-use/post-write.js.map +1 -1
- package/dist/hooks/post-tool-use/read-enricher.d.ts +2 -2
- package/dist/hooks/post-tool-use/read-enricher.js +4 -6
- package/dist/hooks/post-tool-use/read-enricher.js.map +1 -1
- package/dist/hooks/post-tool-use/sot-align.js +29 -3
- package/dist/hooks/post-tool-use/sot-align.js.map +1 -1
- package/dist/hooks/post-tool-use/write-guardian.d.ts +1 -5
- package/dist/hooks/post-tool-use/write-guardian.js +25 -18
- package/dist/hooks/post-tool-use/write-guardian.js.map +1 -1
- package/dist/hooks/runners/context-threshold.js +3 -3
- package/dist/hooks/runners/context-threshold.js.map +1 -1
- package/dist/hooks/runners/payload.js +2 -1
- package/dist/hooks/runners/payload.js.map +1 -1
- package/dist/hooks/runners/phase-ready-surface.js +3 -2
- package/dist/hooks/runners/phase-ready-surface.js.map +1 -1
- package/dist/hooks/runners/session-start.js +103 -4
- package/dist/hooks/runners/session-start.js.map +1 -1
- package/dist/hooks/runners/stop.js +46 -42
- package/dist/hooks/runners/stop.js.map +1 -1
- package/dist/hooks/runners/user-prompt-submit.d.ts +2 -2
- package/dist/hooks/runners/user-prompt-submit.js +4 -9
- package/dist/hooks/runners/user-prompt-submit.js.map +1 -1
- package/dist/hooks/seed-attested.js +3 -2
- package/dist/hooks/seed-attested.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/init/baseline-audit.js +3 -3
- package/dist/init/baseline-audit.js.map +1 -1
- package/dist/init/claude-rule.js +13 -1
- package/dist/init/claude-rule.js.map +1 -1
- package/dist/init/curator/corpus.d.ts +1 -0
- package/dist/init/curator/corpus.js +6 -2
- package/dist/init/curator/corpus.js.map +1 -1
- package/dist/init/curator/emit.js +2 -3
- package/dist/init/curator/emit.js.map +1 -1
- package/dist/init/detect-components.d.ts +3 -2
- package/dist/init/detect-components.js +33 -15
- package/dist/init/detect-components.js.map +1 -1
- package/dist/init/detect.d.ts +1 -5
- package/dist/init/detect.js +157 -143
- package/dist/init/detect.js.map +1 -1
- package/dist/init/eta-calibration.js +2 -2
- package/dist/init/eta-calibration.js.map +1 -1
- package/dist/init/glob-inference.js +24 -0
- package/dist/init/glob-inference.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/init.d.ts +8 -0
- package/dist/init/init.js +16 -20
- package/dist/init/init.js.map +1 -1
- package/dist/init/mapper-merge.d.ts +1 -4
- package/dist/init/mapper-merge.js +4 -17
- package/dist/init/mapper-merge.js.map +1 -1
- package/dist/init/mapper-parallel.js +1 -1
- package/dist/init/mapper-parallel.js.map +1 -1
- package/dist/init/mapper-prompts.d.ts +1 -23
- package/dist/init/mapper-prompts.js +1 -25
- package/dist/init/mapper-prompts.js.map +1 -1
- package/dist/init/mapper.d.ts +0 -6
- package/dist/init/mapper.js +2 -5
- package/dist/init/mapper.js.map +1 -1
- package/dist/init/module-slicer.js +3 -24
- package/dist/init/module-slicer.js.map +1 -1
- package/dist/init/multi-dev/install.js +24 -0
- package/dist/init/multi-dev/install.js.map +1 -1
- package/dist/init/overlay.js +5 -16
- package/dist/init/overlay.js.map +1 -1
- package/dist/init/phases/11-baseline.js +1 -1
- package/dist/init/phases/11-baseline.js.map +1 -1
- package/dist/init/phases/4-seed.js +7 -5
- package/dist/init/phases/4-seed.js.map +1 -1
- package/dist/init/phases/9a-walker.js +4 -0
- package/dist/init/phases/9a-walker.js.map +1 -1
- package/dist/init/phases/9b-curate.d.ts +1 -0
- package/dist/init/phases/9b-curate.js +6 -2
- package/dist/init/phases/9b-curate.js.map +1 -1
- package/dist/init/phases/9d-comp-walk.js +3 -3
- package/dist/init/phases/9d-comp-walk.js.map +1 -1
- package/dist/init/phases/9e-comp-annotate.js +63 -3
- package/dist/init/phases/9e-comp-annotate.js.map +1 -1
- package/dist/init/phases/index.d.ts +0 -1
- package/dist/init/phases/index.js +0 -1
- package/dist/init/phases/index.js.map +1 -1
- package/dist/init/phases/mapper-output-io.d.ts +1 -1
- package/dist/init/phases/mapper-output-io.js +3 -2
- package/dist/init/phases/mapper-output-io.js.map +1 -1
- package/dist/init/phases/state-io.d.ts +1 -1
- package/dist/init/phases/state-io.js +3 -2
- package/dist/init/phases/state-io.js.map +1 -1
- package/dist/init/phases/types.d.ts +20 -8
- package/dist/init/phases/types.js +0 -1
- package/dist/init/phases/types.js.map +1 -1
- package/dist/init/progress.d.ts +1 -0
- package/dist/init/progress.js +3 -1
- package/dist/init/progress.js.map +1 -1
- package/dist/init/rules-merge/ingest.js +3 -3
- package/dist/init/rules-merge/ingest.js.map +1 -1
- package/dist/init/seed.js +54 -5
- package/dist/init/seed.js.map +1 -1
- package/dist/init/source-comments/strip-replace.d.ts +1 -2
- package/dist/init/source-comments/strip-replace.js +19 -3
- package/dist/init/source-comments/strip-replace.js.map +1 -1
- package/dist/init/source-comments/walker.js +8 -79
- package/dist/init/source-comments/walker.js.map +1 -1
- package/dist/init/types.d.ts +8 -16
- package/dist/init/walker.d.ts +1 -1
- package/dist/init/walker.js +1 -1
- package/dist/join/index.d.ts +9 -0
- package/dist/join/index.js +82 -25
- package/dist/join/index.js.map +1 -1
- package/dist/lock.js +4 -3
- package/dist/lock.js.map +1 -1
- package/dist/mcp/bootstrap-guard.js +10 -1
- package/dist/mcp/bootstrap-guard.js.map +1 -1
- package/dist/mcp/schemas.d.ts +26 -4
- package/dist/mcp/schemas.js +23 -1
- package/dist/mcp/schemas.js.map +1 -1
- package/dist/mcp/serve.js +9 -0
- package/dist/mcp/serve.js.map +1 -1
- package/dist/mcp/server.js +3 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/telemetry.js +4 -3
- package/dist/mcp/telemetry.js.map +1 -1
- package/dist/mcp/tools/component-reconfirm.d.ts +7 -0
- package/dist/mcp/tools/component-reconfirm.js +39 -0
- package/dist/mcp/tools/component-reconfirm.js.map +1 -0
- package/dist/mcp/tools/component-register.d.ts +15 -0
- package/dist/mcp/tools/component-register.js +65 -0
- package/dist/mcp/tools/component-register.js.map +1 -0
- package/dist/mcp/tools/decision-get.js +2 -2
- package/dist/mcp/tools/decision-get.js.map +1 -1
- package/dist/mcp/tools/index.js +5 -6
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/init-phases.d.ts +2 -0
- package/dist/mcp/tools/init-phases.js +21 -5
- package/dist/mcp/tools/init-phases.js.map +1 -1
- package/dist/mcp/tools/mission-advance.d.ts +3 -4
- package/dist/mcp/tools/mission-advance.js +15 -19
- package/dist/mcp/tools/mission-advance.js.map +1 -1
- package/dist/mcp/tools/mission-resume.js +3 -3
- package/dist/mcp/tools/mission-resume.js.map +1 -1
- package/dist/mcp/tools/record-decision.js +17 -9
- package/dist/mcp/tools/record-decision.js.map +1 -1
- package/dist/mcp/tools/resolve-attention.js +70 -34
- package/dist/mcp/tools/resolve-attention.js.map +1 -1
- package/dist/mcp/tools/resume.js +3 -2
- package/dist/mcp/tools/resume.js.map +1 -1
- package/dist/mcp/tools/search.js +2 -2
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/mcp/tools/task-complete.js +2 -3
- package/dist/mcp/tools/task-complete.js.map +1 -1
- package/dist/mcp/tools/task-create.js +2 -2
- package/dist/mcp/tools/task-create.js.map +1 -1
- package/dist/migrate/config-io.d.ts +24 -0
- package/dist/migrate/config-io.js +73 -0
- package/dist/migrate/config-io.js.map +1 -0
- package/dist/migrate/gitignore.d.ts +28 -0
- package/dist/migrate/gitignore.js +82 -0
- package/dist/migrate/gitignore.js.map +1 -0
- package/dist/migrate/index.d.ts +6 -0
- package/dist/migrate/index.js +6 -0
- package/dist/migrate/index.js.map +1 -0
- package/dist/migrate/migrations/0001-drop-dead-config-fields.d.ts +12 -0
- package/dist/migrate/migrations/0001-drop-dead-config-fields.js +39 -0
- package/dist/migrate/migrations/0001-drop-dead-config-fields.js.map +1 -0
- package/dist/migrate/migrations/0002-backfill-gitignore.d.ts +14 -0
- package/dist/migrate/migrations/0002-backfill-gitignore.js +40 -0
- package/dist/migrate/migrations/0002-backfill-gitignore.js.map +1 -0
- package/dist/migrate/registry.d.ts +9 -0
- package/dist/migrate/registry.js +11 -0
- package/dist/migrate/registry.js.map +1 -0
- package/dist/migrate/runner.d.ts +45 -0
- package/dist/migrate/runner.js +177 -0
- package/dist/migrate/runner.js.map +1 -0
- package/dist/migrate/semver.d.ts +11 -0
- package/dist/migrate/semver.js +35 -0
- package/dist/migrate/semver.js.map +1 -0
- package/dist/migrate/types.d.ts +47 -0
- package/dist/migrate/types.js +13 -0
- package/dist/migrate/types.js.map +1 -0
- package/dist/missions/task-link.js +7 -8
- package/dist/missions/task-link.js.map +1 -1
- package/dist/paths/index.d.ts +12 -1
- package/dist/paths/index.js +17 -3
- package/dist/paths/index.js.map +1 -1
- package/dist/sensors/catalog.js +6 -11
- package/dist/sensors/catalog.js.map +1 -1
- package/dist/sensors/decisions.js +55 -19
- package/dist/sensors/decisions.js.map +1 -1
- package/dist/sensors/diff.d.ts +12 -0
- package/dist/sensors/diff.js +103 -0
- package/dist/sensors/diff.js.map +1 -1
- package/dist/sensors/index.d.ts +4 -5
- package/dist/sensors/index.js +2 -3
- package/dist/sensors/index.js.map +1 -1
- package/dist/sensors/runner.d.ts +34 -37
- package/dist/sensors/runner.js +63 -53
- package/dist/sensors/runner.js.map +1 -1
- package/dist/sensors/stub-catalog.d.ts +6 -3
- package/dist/sensors/stub-catalog.js +7 -19
- package/dist/sensors/stub-catalog.js.map +1 -1
- package/dist/sensors/types.d.ts +11 -55
- package/dist/sensors/types.js +4 -8
- package/dist/sensors/types.js.map +1 -1
- package/dist/session-start/build.js +36 -21
- package/dist/session-start/build.js.map +1 -1
- package/dist/session-start/templates.d.ts +1 -1
- package/dist/session-start/templates.js +1 -1
- package/dist/status-line/event-queue.js +2 -1
- package/dist/status-line/event-queue.js.map +1 -1
- package/dist/status-line/reader.js +5 -5
- package/dist/status-line/reader.js.map +1 -1
- package/dist/status-line/writer.js +2 -1
- package/dist/status-line/writer.js.map +1 -1
- package/dist/tasks/lifecycle.d.ts +3 -4
- package/dist/tasks/lifecycle.js +19 -21
- package/dist/tasks/lifecycle.js.map +1 -1
- package/dist/trace/index.js +2 -2
- package/dist/trace/index.js.map +1 -1
- package/dist/update-check.d.ts +28 -0
- package/dist/update-check.js +137 -0
- package/dist/update-check.js.map +1 -0
- package/package.json +2 -2
- package/templates/.cairn/git-hooks/commit-msg +33 -5
- package/templates/.cairn/git-hooks/post-commit +13 -3
- package/templates/.cairn/git-hooks/pre-commit +48 -22
- package/templates/.github/workflows/cairn-check.yml +8 -0
- package/dist/attention/bulk-accept.d.ts +0 -78
- package/dist/attention/bulk-accept.js +0 -348
- package/dist/attention/bulk-accept.js.map +0 -1
- package/dist/attention/serve/api.d.ts +0 -24
- package/dist/attention/serve/api.js +0 -383
- package/dist/attention/serve/api.js.map +0 -1
- package/dist/attention/serve/index.d.ts +0 -63
- package/dist/attention/serve/index.js +0 -219
- package/dist/attention/serve/index.js.map +0 -1
- package/dist/hooks/read-enrich.d.ts +0 -6
- package/dist/hooks/read-enrich.js +0 -11
- package/dist/hooks/read-enrich.js.map +0 -1
- package/dist/hooks/write-guard.d.ts +0 -6
- package/dist/hooks/write-guard.js +0 -11
- package/dist/hooks/write-guard.js.map +0 -1
- package/dist/init/phases/12-strip.d.ts +0 -10
- package/dist/init/phases/12-strip.js +0 -88
- package/dist/init/phases/12-strip.js.map +0 -1
- package/dist/mcp/tools/attention-serve.d.ts +0 -23
- package/dist/mcp/tools/attention-serve.js +0 -84
- package/dist/mcp/tools/attention-serve.js.map +0 -1
- package/dist/mcp/tools/attention-wait.d.ts +0 -18
- package/dist/mcp/tools/attention-wait.js +0 -84
- package/dist/mcp/tools/attention-wait.js.map +0 -1
- package/dist/mcp/tools/bulk-accept-attention.d.ts +0 -22
- package/dist/mcp/tools/bulk-accept-attention.js +0 -84
- package/dist/mcp/tools/bulk-accept-attention.js.map +0 -1
- package/dist/sensors/attestation.d.ts +0 -44
- package/dist/sensors/attestation.js +0 -262
- package/dist/sensors/attestation.js.map +0 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `.cairn/.gitignore` remediation — used by `cairn fix gitignore` AND
|
|
3
|
+
* the `0002-backfill-gitignore` migration.
|
|
4
|
+
*
|
|
5
|
+
* Cairn added gitignored derived/per-clone state across several releases
|
|
6
|
+
* (v0.11.3 tasks/missions, v0.15.0 derived ground indexes, v0.18.0 component
|
|
7
|
+
* index). A repo adopted before an entry landed both (a) lacks the ignore line
|
|
8
|
+
* and (b) may have COMMITTED the derived state, which then churns on every
|
|
9
|
+
* clone. Remediation = bring `.cairn/.gitignore` current (merge — never clobber
|
|
10
|
+
* operator lines) and `git rm --cached` any now-ignored, already-tracked paths.
|
|
11
|
+
* Idempotent: a second run adds nothing and untracks nothing.
|
|
12
|
+
*/
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { cairnDir, writeFileSafe } from "@isaacriehm/cairn-state";
|
|
17
|
+
import { templatesRoot } from "../init/seed.js";
|
|
18
|
+
/** Non-comment, non-blank trimmed lines. */
|
|
19
|
+
function entryLines(text) {
|
|
20
|
+
return text
|
|
21
|
+
.split("\n")
|
|
22
|
+
.map((l) => l.trim())
|
|
23
|
+
.filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
24
|
+
}
|
|
25
|
+
/** Of the template entries, the tracked-in-git file paths under them. */
|
|
26
|
+
function trackedUnder(repoRoot, entries) {
|
|
27
|
+
if (entries.length === 0)
|
|
28
|
+
return [];
|
|
29
|
+
const targets = entries.map((e) => join(".cairn", e));
|
|
30
|
+
try {
|
|
31
|
+
const out = execFileSync("git", ["ls-files", "-z", "--", ...targets], {
|
|
32
|
+
cwd: repoRoot,
|
|
33
|
+
encoding: "utf8",
|
|
34
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
35
|
+
});
|
|
36
|
+
return out.split("\0").filter((p) => p.length > 0);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Bring `.cairn/.gitignore` current with the bundled template and (apply mode)
|
|
44
|
+
* untrack any now-ignored committed state. `apply: false` is a pure read used
|
|
45
|
+
* by the migration's `detect()`.
|
|
46
|
+
*/
|
|
47
|
+
export function remediateGitignore(repoRoot, opts) {
|
|
48
|
+
const result = { changed: false, addedEntries: [], untracked: [] };
|
|
49
|
+
const templatePath = join(templatesRoot(), ".cairn", ".gitignore");
|
|
50
|
+
const gitignorePath = cairnDir(repoRoot, ".gitignore");
|
|
51
|
+
if (!existsSync(templatePath) || !existsSync(gitignorePath))
|
|
52
|
+
return result;
|
|
53
|
+
const template = readFileSync(templatePath, "utf8");
|
|
54
|
+
const current = readFileSync(gitignorePath, "utf8");
|
|
55
|
+
const have = new Set(entryLines(current));
|
|
56
|
+
const templateEntries = entryLines(template);
|
|
57
|
+
result.addedEntries = templateEntries.filter((e) => !have.has(e));
|
|
58
|
+
result.untracked = trackedUnder(repoRoot, templateEntries);
|
|
59
|
+
result.changed = result.addedEntries.length > 0 || result.untracked.length > 0;
|
|
60
|
+
if (!opts.apply || !result.changed)
|
|
61
|
+
return result;
|
|
62
|
+
if (result.addedEntries.length > 0) {
|
|
63
|
+
const sep = current.endsWith("\n") ? "" : "\n";
|
|
64
|
+
const block = `${sep}\n# --- backfilled by cairn migrate (0002-backfill-gitignore) ---\n` +
|
|
65
|
+
`${result.addedEntries.join("\n")}\n`;
|
|
66
|
+
writeFileSafe(gitignorePath, current + block);
|
|
67
|
+
}
|
|
68
|
+
if (result.untracked.length > 0) {
|
|
69
|
+
// Untrack so the committed derived state drops out of the index. The
|
|
70
|
+
// working-tree copy stays (rebuildDerived rewrites it); only the tracking
|
|
71
|
+
// is removed. Best-effort — a git failure leaves the file ignored anyway.
|
|
72
|
+
const targets = result.untracked.slice();
|
|
73
|
+
try {
|
|
74
|
+
execFileSync("git", ["rm", "--cached", "-r", "--ignore-unmatch", "--", ...targets], { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
/* best-effort */
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/migrate/gitignore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { Migration, MigrationClass, MigrationResult } from "./types.js";
|
|
2
|
+
export { MIGRATIONS } from "./registry.js";
|
|
3
|
+
export { runMigrations, type RunMigrationsArgs, type RunMigrationsResult, type MigrationOutcome, type MigrationStatus, } from "./runner.js";
|
|
4
|
+
export { readConfigPin } from "./config-io.js";
|
|
5
|
+
export { remediateGitignore, type GitignoreRemediation } from "./gitignore.js";
|
|
6
|
+
export { semverCmp, semverGt, semverLte } from "./semver.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { MIGRATIONS } from "./registry.js";
|
|
2
|
+
export { runMigrations, } from "./runner.js";
|
|
3
|
+
export { readConfigPin } from "./config-io.js";
|
|
4
|
+
export { remediateGitignore } from "./gitignore.js";
|
|
5
|
+
export { semverCmp, semverGt, semverLte } from "./semver.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrate/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,aAAa,GAKd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAA6B,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0001 — drop dead `config.yaml` fields.
|
|
3
|
+
*
|
|
4
|
+
* These keys were written at adoption but have no runtime reader (audit
|
|
5
|
+
* Tier 2 + the proposed-sensors GUT). Removing them from existing adopters
|
|
6
|
+
* is value-preserving (nothing consumes them), so this is a `safe` migration.
|
|
7
|
+
* New adoptions stop emitting them at the source (init/overlay.ts).
|
|
8
|
+
*/
|
|
9
|
+
import type { Migration } from "../types.js";
|
|
10
|
+
/** Top-level config keys with no runtime consumer. */
|
|
11
|
+
export declare const DEAD_CONFIG_KEYS: readonly ["detected_sensor_commands", "mapper_proposed_sensors", "mapper_notes", "key_modules", "stack_signatures", "hook_capability", "start_command", "origin_url"];
|
|
12
|
+
export declare const dropDeadConfigFields: Migration;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0001 — drop dead `config.yaml` fields.
|
|
3
|
+
*
|
|
4
|
+
* These keys were written at adoption but have no runtime reader (audit
|
|
5
|
+
* Tier 2 + the proposed-sensors GUT). Removing them from existing adopters
|
|
6
|
+
* is value-preserving (nothing consumes them), so this is a `safe` migration.
|
|
7
|
+
* New adoptions stop emitting them at the source (init/overlay.ts).
|
|
8
|
+
*/
|
|
9
|
+
import { configHasKeys, deleteConfigKeys } from "../config-io.js";
|
|
10
|
+
/** Top-level config keys with no runtime consumer. */
|
|
11
|
+
export const DEAD_CONFIG_KEYS = [
|
|
12
|
+
"detected_sensor_commands",
|
|
13
|
+
"mapper_proposed_sensors",
|
|
14
|
+
"mapper_notes",
|
|
15
|
+
"key_modules",
|
|
16
|
+
"stack_signatures",
|
|
17
|
+
"hook_capability",
|
|
18
|
+
"start_command",
|
|
19
|
+
"origin_url",
|
|
20
|
+
];
|
|
21
|
+
export const dropDeadConfigFields = {
|
|
22
|
+
id: "0001-drop-dead-config-fields",
|
|
23
|
+
introducedIn: "0.21.0",
|
|
24
|
+
describe: "Remove unconsumed config.yaml keys (detected_sensor_commands, mapper_proposed_sensors, mapper_notes, key_modules, stack_signatures, hook_capability, start_command, origin_url)",
|
|
25
|
+
class: "safe",
|
|
26
|
+
detect(repoRoot, doc) {
|
|
27
|
+
return configHasKeys(repoRoot, DEAD_CONFIG_KEYS, doc).length > 0;
|
|
28
|
+
},
|
|
29
|
+
apply(repoRoot) {
|
|
30
|
+
const removed = deleteConfigKeys(repoRoot, DEAD_CONFIG_KEYS);
|
|
31
|
+
return {
|
|
32
|
+
changed: removed.length > 0,
|
|
33
|
+
detail: removed.length > 0
|
|
34
|
+
? `removed ${removed.length} dead config key(s): ${removed.join(", ")}`
|
|
35
|
+
: "no dead config keys present",
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=0001-drop-dead-config-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0001-drop-dead-config-fields.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0001-drop-dead-config-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAElE,sDAAsD;AACtD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,0BAA0B;IAC1B,yBAAyB;IACzB,cAAc;IACd,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,eAAe;IACf,YAAY;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAAc;IAC7C,EAAE,EAAE,8BAA8B;IAClC,YAAY,EAAE,QAAQ;IACtB,QAAQ,EAAE,iLAAiL;IAC3L,KAAK,EAAE,MAAM;IACb,MAAM,CAAC,QAAgB,EAAE,GAAsB;QAC7C,OAAO,aAAa,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,CAAC,QAAgB;QACpB,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC7D,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC;YAC3B,MAAM,EACJ,OAAO,CAAC,MAAM,GAAG,CAAC;gBAChB,CAAC,CAAC,WAAW,OAAO,CAAC,MAAM,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACvE,CAAC,CAAC,6BAA6B;SACpC,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0002 — backfill `.cairn/.gitignore` + untrack committed derived state.
|
|
3
|
+
*
|
|
4
|
+
* Repos adopted before the relevant releases (tasks/missions v0.11.3, derived
|
|
5
|
+
* ground indexes v0.15.0, component index v0.18.0) lack the ignore lines and
|
|
6
|
+
* may have COMMITTED per-clone derived state that then churns across clones.
|
|
7
|
+
*
|
|
8
|
+
* `review` (not `safe`): apply runs `git rm --cached`, mutating the git index —
|
|
9
|
+
* a VCS change the operator confirms via `cairn migrate --all`, never silently
|
|
10
|
+
* at SessionStart. Detect/apply share `remediateGitignore` with the
|
|
11
|
+
* `cairn fix gitignore` CLI, and both are idempotent.
|
|
12
|
+
*/
|
|
13
|
+
import type { Migration } from "../types.js";
|
|
14
|
+
export declare const backfillGitignore: Migration;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0002 — backfill `.cairn/.gitignore` + untrack committed derived state.
|
|
3
|
+
*
|
|
4
|
+
* Repos adopted before the relevant releases (tasks/missions v0.11.3, derived
|
|
5
|
+
* ground indexes v0.15.0, component index v0.18.0) lack the ignore lines and
|
|
6
|
+
* may have COMMITTED per-clone derived state that then churns across clones.
|
|
7
|
+
*
|
|
8
|
+
* `review` (not `safe`): apply runs `git rm --cached`, mutating the git index —
|
|
9
|
+
* a VCS change the operator confirms via `cairn migrate --all`, never silently
|
|
10
|
+
* at SessionStart. Detect/apply share `remediateGitignore` with the
|
|
11
|
+
* `cairn fix gitignore` CLI, and both are idempotent.
|
|
12
|
+
*/
|
|
13
|
+
import { remediateGitignore } from "../gitignore.js";
|
|
14
|
+
export const backfillGitignore = {
|
|
15
|
+
id: "0002-backfill-gitignore",
|
|
16
|
+
// Ships in 0.22.0 → runs for every pin < 0.22.0 (catches 0.21 adopters who
|
|
17
|
+
// upgraded from <0.15 and got 0001 but never a gitignore backfill). Bump in
|
|
18
|
+
// lockstep with the release that lands this.
|
|
19
|
+
introducedIn: "0.22.0",
|
|
20
|
+
describe: "Backfill .cairn/.gitignore (derived ground indexes, component index, per-clone state) and untrack derived state committed before it was gitignored — repos adopted before v0.15.0/v0.18.0",
|
|
21
|
+
class: "review",
|
|
22
|
+
detect(repoRoot) {
|
|
23
|
+
return remediateGitignore(repoRoot, { apply: false }).changed;
|
|
24
|
+
},
|
|
25
|
+
apply(repoRoot) {
|
|
26
|
+
const r = remediateGitignore(repoRoot, { apply: true });
|
|
27
|
+
const parts = [];
|
|
28
|
+
if (r.addedEntries.length > 0) {
|
|
29
|
+
parts.push(`added ${r.addedEntries.length} ignore entr${r.addedEntries.length === 1 ? "y" : "ies"}`);
|
|
30
|
+
}
|
|
31
|
+
if (r.untracked.length > 0) {
|
|
32
|
+
parts.push(`untracked ${r.untracked.length} committed derived file(s)`);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
changed: r.changed,
|
|
36
|
+
detail: r.changed ? parts.join("; ") : "nothing to backfill",
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=0002-backfill-gitignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0002-backfill-gitignore.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0002-backfill-gitignore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,EAAE,EAAE,yBAAyB;IAC7B,2EAA2E;IAC3E,4EAA4E;IAC5E,6CAA6C;IAC7C,YAAY,EAAE,QAAQ;IACtB,QAAQ,EACN,2LAA2L;IAC7L,KAAK,EAAE,QAAQ;IACf,MAAM,CAAC,QAAgB;QACrB,OAAO,kBAAkB,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IAChE,CAAC;IACD,KAAK,CAAC,QAAgB;QACpB,MAAM,CAAC,GAAG,kBAAkB,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CACR,SAAS,CAAC,CAAC,YAAY,CAAC,MAAM,eAAe,CAAC,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CACzF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,MAAM,4BAA4B,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,qBAAqB;SAC7D,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered migration registry. New migrations append here, tagged with the
|
|
3
|
+
* `introducedIn` version that requires their state shape.
|
|
4
|
+
*
|
|
5
|
+
* Release gate: any release that changes the `.cairn/` contract must ship a
|
|
6
|
+
* migration here and link it from CHANGELOG.
|
|
7
|
+
*/
|
|
8
|
+
import type { Migration } from "./types.js";
|
|
9
|
+
export declare const MIGRATIONS: readonly Migration[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered migration registry. New migrations append here, tagged with the
|
|
3
|
+
* `introducedIn` version that requires their state shape.
|
|
4
|
+
*
|
|
5
|
+
* Release gate: any release that changes the `.cairn/` contract must ship a
|
|
6
|
+
* migration here and link it from CHANGELOG.
|
|
7
|
+
*/
|
|
8
|
+
import { dropDeadConfigFields } from "./migrations/0001-drop-dead-config-fields.js";
|
|
9
|
+
import { backfillGitignore } from "./migrations/0002-backfill-gitignore.js";
|
|
10
|
+
export const MIGRATIONS = [dropDeadConfigFields, backfillGitignore];
|
|
11
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/migrate/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAE5E,MAAM,CAAC,MAAM,UAAU,GAAyB,CAAC,oBAAoB,EAAE,iBAAiB,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration runner — select, apply, stamp.
|
|
3
|
+
*
|
|
4
|
+
* Selection: migrations whose `introducedIn` is in `(pin, current]` and whose
|
|
5
|
+
* `detect()` still reports the repo needs them. `safe` migrations auto-apply;
|
|
6
|
+
* `review` migrations are queued for the operator unless `includeReview`.
|
|
7
|
+
*
|
|
8
|
+
* The `cairn_version` pin is an optimization, not the source of truth —
|
|
9
|
+
* `detect()` carries correctness, so a wrong/absent pin never causes a
|
|
10
|
+
* re-mutation. On success the pin advances to the highest fully-applied
|
|
11
|
+
* version (and all the way to `current` when nothing is left pending), which
|
|
12
|
+
* is what turns the frozen `cairn_version` pin into a live one.
|
|
13
|
+
*
|
|
14
|
+
* Concurrency: the apply phase holds `.migrate-lock`; a second session bails
|
|
15
|
+
* cleanly (`ran: false`) rather than racing.
|
|
16
|
+
*/
|
|
17
|
+
import type { MigrationClass } from "./types.js";
|
|
18
|
+
export type MigrationStatus = "applied" | "noop" | "queued" | "failed" | "would-apply" | "would-queue";
|
|
19
|
+
export interface MigrationOutcome {
|
|
20
|
+
id: string;
|
|
21
|
+
class: MigrationClass;
|
|
22
|
+
status: MigrationStatus;
|
|
23
|
+
detail: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RunMigrationsArgs {
|
|
26
|
+
repoRoot: string;
|
|
27
|
+
/** Report what would run; apply nothing, write nothing. */
|
|
28
|
+
dryRun?: boolean;
|
|
29
|
+
/** Auto-apply `review`-class too (operator-confirmed `cairn migrate --all`). */
|
|
30
|
+
includeReview?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface RunMigrationsResult {
|
|
33
|
+
/** False only when another process held the migrate lock. */
|
|
34
|
+
ran: boolean;
|
|
35
|
+
/** Pin before the run (`0.0.0` when absent). */
|
|
36
|
+
pin: string;
|
|
37
|
+
/** Current CLI version. */
|
|
38
|
+
current: string;
|
|
39
|
+
/** Pin after the run, or null when unchanged / not written. */
|
|
40
|
+
newPin: string | null;
|
|
41
|
+
outcomes: MigrationOutcome[];
|
|
42
|
+
/** `review`-class migration ids that still need the operator. */
|
|
43
|
+
pendingReview: string[];
|
|
44
|
+
}
|
|
45
|
+
export declare function runMigrations(args: RunMigrationsArgs): Promise<RunMigrationsResult>;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration runner — select, apply, stamp.
|
|
3
|
+
*
|
|
4
|
+
* Selection: migrations whose `introducedIn` is in `(pin, current]` and whose
|
|
5
|
+
* `detect()` still reports the repo needs them. `safe` migrations auto-apply;
|
|
6
|
+
* `review` migrations are queued for the operator unless `includeReview`.
|
|
7
|
+
*
|
|
8
|
+
* The `cairn_version` pin is an optimization, not the source of truth —
|
|
9
|
+
* `detect()` carries correctness, so a wrong/absent pin never causes a
|
|
10
|
+
* re-mutation. On success the pin advances to the highest fully-applied
|
|
11
|
+
* version (and all the way to `current` when nothing is left pending), which
|
|
12
|
+
* is what turns the frozen `cairn_version` pin into a live one.
|
|
13
|
+
*
|
|
14
|
+
* Concurrency: the apply phase holds `.migrate-lock`; a second session bails
|
|
15
|
+
* cleanly (`ran: false`) rather than racing.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
import { VERSION } from "../index.js";
|
|
19
|
+
import { logger } from "../logger.js";
|
|
20
|
+
import { acquireOperationLock, OperationLockHeldError } from "../lock.js";
|
|
21
|
+
import { loadConfigDoc, readConfigPin, writeConfigPin } from "./config-io.js";
|
|
22
|
+
import { MIGRATIONS } from "./registry.js";
|
|
23
|
+
import { semverCmp, semverGt, semverLte } from "./semver.js";
|
|
24
|
+
import { cairnDir } from "@isaacriehm/cairn-state";
|
|
25
|
+
const log = logger("migrate.runner");
|
|
26
|
+
function needs(m, repoRoot, doc) {
|
|
27
|
+
try {
|
|
28
|
+
return m.detect(repoRoot, doc);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
log.warn({ migration: m.id, err: err instanceof Error ? err.message : String(err) }, "migration detect() threw — skipping");
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Migrations introduced in `(pin, current]` that still report needed. `doc` is
|
|
37
|
+
* the once-parsed `config.yaml` shared across this read-only selection pass.
|
|
38
|
+
*/
|
|
39
|
+
function selectCandidates(repoRoot, pin, current, doc) {
|
|
40
|
+
return MIGRATIONS.filter((m) => semverGt(m.introducedIn, pin) && semverLte(m.introducedIn, current))
|
|
41
|
+
.filter((m) => needs(m, repoRoot, doc))
|
|
42
|
+
.slice()
|
|
43
|
+
.sort((a, b) => semverCmp(a.introducedIn, b.introducedIn) || a.id.localeCompare(b.id));
|
|
44
|
+
}
|
|
45
|
+
export async function runMigrations(args) {
|
|
46
|
+
const { repoRoot } = args;
|
|
47
|
+
const current = VERSION;
|
|
48
|
+
const dryRun = args.dryRun === true;
|
|
49
|
+
const includeReview = args.includeReview === true;
|
|
50
|
+
// Never act on an unadopted repo — guards against any caller (notably the
|
|
51
|
+
// defensive MCP-boot run) creating `.cairn/` via the lock's mkdir.
|
|
52
|
+
if (!existsSync(cairnDir(repoRoot, "config.yaml"))) {
|
|
53
|
+
return { ran: true, pin: "0.0.0", current, newPin: null, outcomes: [], pendingReview: [] };
|
|
54
|
+
}
|
|
55
|
+
// Parse config.yaml once for the whole read-only selection phase (pin read +
|
|
56
|
+
// each candidate's detect). The apply phase re-reads fresh, since a migration
|
|
57
|
+
// may mutate the file mid-run.
|
|
58
|
+
const doc = loadConfigDoc(repoRoot);
|
|
59
|
+
const pin = readConfigPin(repoRoot, doc) ?? "0.0.0";
|
|
60
|
+
const candidates = selectCandidates(repoRoot, pin, current, doc);
|
|
61
|
+
// Nothing pending: make the pin live if it's merely stale, else no-op.
|
|
62
|
+
if (candidates.length === 0) {
|
|
63
|
+
if (semverCmp(pin, current) >= 0) {
|
|
64
|
+
return { ran: true, pin, current, newPin: null, outcomes: [], pendingReview: [] };
|
|
65
|
+
}
|
|
66
|
+
if (dryRun) {
|
|
67
|
+
return { ran: true, pin, current, newPin: current, outcomes: [], pendingReview: [] };
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const wrote = await acquireOperationLock(repoRoot, ".migrate-lock", () => writeConfigPin(repoRoot, current));
|
|
71
|
+
return {
|
|
72
|
+
ran: true,
|
|
73
|
+
pin,
|
|
74
|
+
current,
|
|
75
|
+
newPin: wrote ? current : null,
|
|
76
|
+
outcomes: [],
|
|
77
|
+
pendingReview: [],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
if (err instanceof OperationLockHeldError) {
|
|
82
|
+
return { ran: false, pin, current, newPin: null, outcomes: [], pendingReview: [] };
|
|
83
|
+
}
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (dryRun) {
|
|
88
|
+
const outcomes = candidates.map((m) => ({
|
|
89
|
+
id: m.id,
|
|
90
|
+
class: m.class,
|
|
91
|
+
status: m.class === "review" && !includeReview ? "would-queue" : "would-apply",
|
|
92
|
+
detail: m.describe,
|
|
93
|
+
}));
|
|
94
|
+
const pendingReview = candidates
|
|
95
|
+
.filter((m) => m.class === "review" && !includeReview)
|
|
96
|
+
.map((m) => m.id);
|
|
97
|
+
return { ran: true, pin, current, newPin: null, outcomes, pendingReview };
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return await acquireOperationLock(repoRoot, ".migrate-lock", () => applyCandidates({ repoRoot, pin, current, candidates, includeReview }));
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (err instanceof OperationLockHeldError) {
|
|
104
|
+
return { ran: false, pin, current, newPin: null, outcomes: [], pendingReview: [] };
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function applyCandidates(args) {
|
|
110
|
+
const { repoRoot, pin, current, candidates, includeReview } = args;
|
|
111
|
+
const outcomes = [];
|
|
112
|
+
const pendingReview = [];
|
|
113
|
+
let firstUnresolved = -1;
|
|
114
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
115
|
+
const m = candidates[i];
|
|
116
|
+
if (m === undefined)
|
|
117
|
+
continue;
|
|
118
|
+
// Re-check under the lock for idempotency under concurrency.
|
|
119
|
+
if (!needs(m, repoRoot)) {
|
|
120
|
+
outcomes.push({ id: m.id, class: m.class, status: "noop", detail: "already satisfied" });
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (m.class === "review" && !includeReview) {
|
|
124
|
+
outcomes.push({ id: m.id, class: m.class, status: "queued", detail: m.describe });
|
|
125
|
+
pendingReview.push(m.id);
|
|
126
|
+
if (firstUnresolved === -1)
|
|
127
|
+
firstUnresolved = i;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const r = m.apply(repoRoot);
|
|
132
|
+
outcomes.push({
|
|
133
|
+
id: m.id,
|
|
134
|
+
class: m.class,
|
|
135
|
+
status: r.changed ? "applied" : "noop",
|
|
136
|
+
detail: r.detail,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
outcomes.push({
|
|
141
|
+
id: m.id,
|
|
142
|
+
class: m.class,
|
|
143
|
+
status: "failed",
|
|
144
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
145
|
+
});
|
|
146
|
+
if (firstUnresolved === -1)
|
|
147
|
+
firstUnresolved = i;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Advance the pin to the highest version with no unresolved predecessor.
|
|
151
|
+
let target = pin;
|
|
152
|
+
if (firstUnresolved === -1) {
|
|
153
|
+
target = current;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
for (let i = 0; i < firstUnresolved; i++) {
|
|
157
|
+
const m = candidates[i];
|
|
158
|
+
if (m !== undefined && semverGt(m.introducedIn, target))
|
|
159
|
+
target = m.introducedIn;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let newPin = null;
|
|
163
|
+
if (semverCmp(target, pin) > 0) {
|
|
164
|
+
if (writeConfigPin(repoRoot, target))
|
|
165
|
+
newPin = target;
|
|
166
|
+
}
|
|
167
|
+
log.info({
|
|
168
|
+
pin,
|
|
169
|
+
current,
|
|
170
|
+
new_pin: newPin,
|
|
171
|
+
applied: outcomes.filter((o) => o.status === "applied").length,
|
|
172
|
+
queued: pendingReview.length,
|
|
173
|
+
failed: outcomes.filter((o) => o.status === "failed").length,
|
|
174
|
+
}, "migrations run");
|
|
175
|
+
return { ran: true, pin, current, newPin, outcomes, pendingReview };
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/migrate/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAuCrC,SAAS,KAAK,CAAC,CAAY,EAAE,QAAgB,EAAE,GAAsB;IACnE,IAAI,CAAC;QACH,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC1E,qCAAqC,CACtC,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACvB,QAAgB,EAChB,GAAW,EACX,OAAe,EACf,GAAsB;IAEtB,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC,CAC3E;SACE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;SACtC,KAAK,EAAE;SACP,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,SAAS,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CACxE,CAAC;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAuB;IAEvB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC;IACxB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC;IAElD,0EAA0E;IAC1E,mEAAmE;IACnE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;IAC7F,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,+BAA+B;IAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC;IAEpD,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAEjE,uEAAuE;IACvE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACpF,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACvF,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,CACvE,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAClC,CAAC;YACF,OAAO;gBACL,GAAG,EAAE,IAAI;gBACT,GAAG;gBACH,OAAO;gBACP,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;gBAC9B,QAAQ,EAAE,EAAE;gBACZ,aAAa,EAAE,EAAE;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;gBAC1C,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;YACrF,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,QAAQ,GAAuB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1D,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EACJ,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa;YACxE,MAAM,EAAE,CAAC,CAAC,QAAQ;SACnB,CAAC,CAAC,CAAC;QACJ,MAAM,aAAa,GAAG,UAAU;aAC7B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC;aACrD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpB,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,CAChE,eAAe,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CACvE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;YAC1C,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACrF,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAMxB;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IACnE,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,IAAI,eAAe,GAAG,CAAC,CAAC,CAAC;IAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,6DAA6D;QAC7D,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACzF,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClF,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,IAAI,eAAe,KAAK,CAAC,CAAC;gBAAE,eAAe,GAAG,CAAC,CAAC;YAChD,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;gBACtC,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;YACH,IAAI,eAAe,KAAK,CAAC,CAAC;gBAAE,eAAe,GAAG,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,OAAO,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC;gBAAE,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC;QACnF,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,IAAI,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC;YAAE,MAAM,GAAG,MAAM,CAAC;IACxD,CAAC;IAED,GAAG,CAAC,IAAI,CACN;QACE,GAAG;QACH,OAAO;QACP,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM;QAC9D,MAAM,EAAE,aAAa,CAAC,MAAM;QAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM;KAC7D,EACD,gBAAgB,CACjB,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal semver comparison for migration selection. No external dep.
|
|
3
|
+
*
|
|
4
|
+
* Parses `MAJOR.MINOR.PATCH` (ignoring any `-prerelease` / `+build` suffix)
|
|
5
|
+
* and compares numerically. Non-conforming strings sort as `0.0.0`, which is
|
|
6
|
+
* the conservative choice for an absent / malformed pin (everything pending).
|
|
7
|
+
*/
|
|
8
|
+
/** -1 if a<b, 0 if equal, 1 if a>b. */
|
|
9
|
+
export declare function semverCmp(a: string, b: string): number;
|
|
10
|
+
export declare function semverGt(a: string, b: string): boolean;
|
|
11
|
+
export declare function semverLte(a: string, b: string): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal semver comparison for migration selection. No external dep.
|
|
3
|
+
*
|
|
4
|
+
* Parses `MAJOR.MINOR.PATCH` (ignoring any `-prerelease` / `+build` suffix)
|
|
5
|
+
* and compares numerically. Non-conforming strings sort as `0.0.0`, which is
|
|
6
|
+
* the conservative choice for an absent / malformed pin (everything pending).
|
|
7
|
+
*/
|
|
8
|
+
function parse(v) {
|
|
9
|
+
const core = v.trim().split(/[-+]/)[0] ?? "";
|
|
10
|
+
const parts = core.split(".");
|
|
11
|
+
const n = (i) => {
|
|
12
|
+
const x = Number.parseInt(parts[i] ?? "0", 10);
|
|
13
|
+
return Number.isFinite(x) ? x : 0;
|
|
14
|
+
};
|
|
15
|
+
return [n(0), n(1), n(2)];
|
|
16
|
+
}
|
|
17
|
+
/** -1 if a<b, 0 if equal, 1 if a>b. */
|
|
18
|
+
export function semverCmp(a, b) {
|
|
19
|
+
const pa = parse(a);
|
|
20
|
+
const pb = parse(b);
|
|
21
|
+
for (let i = 0; i < 3; i++) {
|
|
22
|
+
const x = pa[i] ?? 0;
|
|
23
|
+
const y = pb[i] ?? 0;
|
|
24
|
+
if (x !== y)
|
|
25
|
+
return x < y ? -1 : 1;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
export function semverGt(a, b) {
|
|
30
|
+
return semverCmp(a, b) > 0;
|
|
31
|
+
}
|
|
32
|
+
export function semverLte(a, b) {
|
|
33
|
+
return semverCmp(a, b) <= 0;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=semver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.js","sourceRoot":"","sources":["../../src/migrate/semver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,SAAS,KAAK,CAAC,CAAS;IACtB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,CAAC,CAAS,EAAU,EAAE;QAC9B,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IACF,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,CAAS;IAC3C,OAAO,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,OAAO,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coded `.cairn/` migration registry — types.
|
|
3
|
+
*
|
|
4
|
+
* Cairn upgrades constantly but on-disk `.cairn/` state does not move with
|
|
5
|
+
* it. A migration is a versioned, idempotent repair: detect whether a repo
|
|
6
|
+
* still needs the new state shape, then apply it. The runner selects pending
|
|
7
|
+
* migrations by semver against the `cairn_version` pin, applies the `safe`
|
|
8
|
+
* class automatically, and surfaces the `review` class for operator triage.
|
|
9
|
+
*
|
|
10
|
+
* See docs/MIGRATION_FEATURE_EVAL.md.
|
|
11
|
+
*/
|
|
12
|
+
export interface MigrationResult {
|
|
13
|
+
/** True when apply() actually mutated `.cairn/`. */
|
|
14
|
+
changed: boolean;
|
|
15
|
+
/** One-line human summary of what changed (or why nothing did). */
|
|
16
|
+
detail: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `safe` — additive or derived-only: add a missing default key, drop an
|
|
20
|
+
* unconsumed key, rebuild a gitignored derived index, stamp a
|
|
21
|
+
* marker. Auto-applied silently (incl. at SessionStart).
|
|
22
|
+
* `review` — rewrites source, drops data, or makes a judgement call (brand
|
|
23
|
+
* re-derive, source strip). Never auto-applied; surfaced for the
|
|
24
|
+
* operator to run via `cairn migrate`.
|
|
25
|
+
*/
|
|
26
|
+
export type MigrationClass = "safe" | "review";
|
|
27
|
+
export interface Migration {
|
|
28
|
+
/** Stable id, e.g. "0001-drop-dead-config-fields". */
|
|
29
|
+
id: string;
|
|
30
|
+
/** Semver of the Cairn release that REQUIRES this state shape. */
|
|
31
|
+
introducedIn: string;
|
|
32
|
+
/** One-line description, surfaced to the operator + linkable from CHANGELOG. */
|
|
33
|
+
describe: string;
|
|
34
|
+
class: MigrationClass;
|
|
35
|
+
/**
|
|
36
|
+
* Idempotent: true when this repo still needs the migration. The runner may
|
|
37
|
+
* pass `doc` — `config.yaml` parsed once for the whole selection phase — so a
|
|
38
|
+
* config-shape detect can skip re-parsing. Migrations that read other state
|
|
39
|
+
* ignore it. Never passed during the post-apply re-check (the file may have
|
|
40
|
+
* changed), so a detect handed no `doc` must read fresh.
|
|
41
|
+
*/
|
|
42
|
+
detect(repoRoot: string, doc?: ConfigDoc | null): boolean;
|
|
43
|
+
/** Apply. Must be idempotent and atomic per migration. */
|
|
44
|
+
apply(repoRoot: string): MigrationResult;
|
|
45
|
+
}
|
|
46
|
+
/** Opaque parsed-`config.yaml` handle threaded through `detect` (yaml Document). */
|
|
47
|
+
export type ConfigDoc = import("yaml").Document;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coded `.cairn/` migration registry — types.
|
|
3
|
+
*
|
|
4
|
+
* Cairn upgrades constantly but on-disk `.cairn/` state does not move with
|
|
5
|
+
* it. A migration is a versioned, idempotent repair: detect whether a repo
|
|
6
|
+
* still needs the new state shape, then apply it. The runner selects pending
|
|
7
|
+
* migrations by semver against the `cairn_version` pin, applies the `safe`
|
|
8
|
+
* class automatically, and surfaces the `review` class for operator triage.
|
|
9
|
+
*
|
|
10
|
+
* See docs/MIGRATION_FEATURE_EVAL.md.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/migrate/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|