@isaacriehm/cairn-core 0.25.0 → 0.26.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.
@@ -18,6 +18,16 @@ export declare function loadConfigDoc(repoRoot: string): Document | null;
18
18
  export declare function readConfigPin(repoRoot: string, doc?: Document | null): string | null;
19
19
  /** Set the `cairn_version` pin. No-op (returns false) when already equal. */
20
20
  export declare function writeConfigPin(repoRoot: string, version: string): boolean;
21
+ /**
22
+ * Write a mutated config `Document` back to disk. The migration system was
23
+ * built for top-level key edits (drop a dead key, set the pin); content
24
+ * migrations that need to repair a NESTED structure (e.g. collapse a
25
+ * workspace's `componentDirs`) mutate the `Document` via `loadConfigDoc` +
26
+ * `doc.getIn` / `doc.setIn` and persist with this. Whole-file rewrite under
27
+ * the caller's migrate lock; key order + comments are preserved by the yaml
28
+ * Document API. Returns false when the config is absent.
29
+ */
30
+ export declare function writeConfigDoc(repoRoot: string, doc: Document): boolean;
21
31
  /** Which of `keys` are present as top-level config keys. */
22
32
  export declare function configHasKeys(repoRoot: string, keys: readonly string[], doc?: Document | null): string[];
23
33
  /** Delete top-level `keys`; returns the keys actually removed. */
@@ -46,6 +46,22 @@ export function writeConfigPin(repoRoot, version) {
46
46
  writeFileSync(p, doc.toString(), "utf8");
47
47
  return true;
48
48
  }
49
+ /**
50
+ * Write a mutated config `Document` back to disk. The migration system was
51
+ * built for top-level key edits (drop a dead key, set the pin); content
52
+ * migrations that need to repair a NESTED structure (e.g. collapse a
53
+ * workspace's `componentDirs`) mutate the `Document` via `loadConfigDoc` +
54
+ * `doc.getIn` / `doc.setIn` and persist with this. Whole-file rewrite under
55
+ * the caller's migrate lock; key order + comments are preserved by the yaml
56
+ * Document API. Returns false when the config is absent.
57
+ */
58
+ export function writeConfigDoc(repoRoot, doc) {
59
+ const p = configPath(repoRoot);
60
+ if (!existsSync(p))
61
+ return false;
62
+ writeFileSync(p, doc.toString(), "utf8");
63
+ return true;
64
+ }
49
65
  /** Which of `keys` are present as top-level config keys. */
50
66
  export function configHasKeys(repoRoot, keys, doc) {
51
67
  const d = doc !== undefined ? doc : loadConfigDoc(repoRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"config-io.js","sourceRoot":"","sources":["../../src/migrate/config-io.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-io.js","sourceRoot":"","sources":["../../src/migrate/config-io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 0005 — demote auto-filled brand drafts back to `status: draft`.
3
+ *
4
+ * Before 0.25.0, the adoption brand step DEFAULTED to auto-fill and, on
5
+ * apply, flipped each written file `draft → current`. SessionStart then
6
+ * injected every `current` brand file as authoritative voice — so a
7
+ * generic, machine-written first draft (or the mechanical fallback when
8
+ * the Haiku derive timed out) burned context every session as if the
9
+ * operator had confirmed it.
10
+ *
11
+ * 0.25.0 fixed this going forward (auto-fill writes `draft`; SessionStart
12
+ * injects only confirmed brand). This migration repairs EXISTING repos:
13
+ * it finds brand/product docs that are provably auto-generated yet marked
14
+ * `current`/`accepted`, and demotes them to `draft` so they stop being
15
+ * injected. Operator-written brand is left alone; a demoted file is one
16
+ * frontmatter edit (or a re-run of brand setup) away from `current` again.
17
+ *
18
+ * `review`-class: it rewrites committed ground state, so it surfaces for
19
+ * the operator and applies via `cairn migrate` — never silently.
20
+ *
21
+ * Ships in 0.26.0, so `introducedIn` is 0.26.0 (not 0.25.0): a repo whose
22
+ * pin already advanced to 0.25.0 must still re-evaluate it. `detect()`
23
+ * carries correctness.
24
+ */
25
+ import type { Migration } from "../types.js";
26
+ export declare const demoteAutofilledBrand: Migration;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * 0005 — demote auto-filled brand drafts back to `status: draft`.
3
+ *
4
+ * Before 0.25.0, the adoption brand step DEFAULTED to auto-fill and, on
5
+ * apply, flipped each written file `draft → current`. SessionStart then
6
+ * injected every `current` brand file as authoritative voice — so a
7
+ * generic, machine-written first draft (or the mechanical fallback when
8
+ * the Haiku derive timed out) burned context every session as if the
9
+ * operator had confirmed it.
10
+ *
11
+ * 0.25.0 fixed this going forward (auto-fill writes `draft`; SessionStart
12
+ * injects only confirmed brand). This migration repairs EXISTING repos:
13
+ * it finds brand/product docs that are provably auto-generated yet marked
14
+ * `current`/`accepted`, and demotes them to `draft` so they stop being
15
+ * injected. Operator-written brand is left alone; a demoted file is one
16
+ * frontmatter edit (or a re-run of brand setup) away from `current` again.
17
+ *
18
+ * `review`-class: it rewrites committed ground state, so it surfaces for
19
+ * the operator and applies via `cairn migrate` — never silently.
20
+ *
21
+ * Ships in 0.26.0, so `introducedIn` is 0.26.0 (not 0.25.0): a repo whose
22
+ * pin already advanced to 0.25.0 must still re-evaluate it. `detect()`
23
+ * carries correctness.
24
+ */
25
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
26
+ import { cairnDir, parseFrontmatter } from "@isaacriehm/cairn-state";
27
+ /** Distinctive substrings only the pre-0.25.0 mechanical fallback emits. */
28
+ const VOICE_MARKER = "Match the existing tone in CLAUDE.md / AGENTS.md if those files set a register";
29
+ const AVOID_MARKER = 'Marketing fluff ("world-class", "revolutionary", "game-changing")';
30
+ const PERSONAS_MARKER = "Refine when adding consumer-facing or external personas";
31
+ function brandDocs(repoRoot) {
32
+ return [
33
+ { rel: "brand/overview.md", abs: cairnDir(repoRoot, "ground", "brand", "overview.md") },
34
+ { rel: "brand/voice.md", abs: cairnDir(repoRoot, "ground", "brand", "voice.md") },
35
+ { rel: "product/positioning.md", abs: cairnDir(repoRoot, "ground", "product", "positioning.md") },
36
+ { rel: "product/personas.yaml", abs: cairnDir(repoRoot, "ground", "product", "personas.yaml") },
37
+ ];
38
+ }
39
+ function readDoc(abs) {
40
+ if (!existsSync(abs))
41
+ return null;
42
+ let raw;
43
+ try {
44
+ raw = readFileSync(abs, "utf8");
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ // personas.yaml is pure YAML (status as a top-level key, no `---` fence);
50
+ // the brand .md files use frontmatter. parseFrontmatter handles the .md;
51
+ // for the .yaml fall back to a status-line scan over the whole text.
52
+ const parsed = parseFrontmatter(raw);
53
+ const fm = (parsed.frontmatter ?? {});
54
+ let status = typeof fm["status"] === "string" ? fm["status"] : null;
55
+ if (status === null) {
56
+ const m = raw.match(/^status:\s*(\S+)\s*$/m);
57
+ status = m?.[1] ?? null;
58
+ }
59
+ return { status, body: parsed.body, raw };
60
+ }
61
+ const CONFIRMED = new Set(["current", "accepted"]);
62
+ /** Strip headings + collapse whitespace, matching SessionStart's dedup. */
63
+ function normalize(s) {
64
+ return s
65
+ .replace(/^\s*#{1,6}\s+.*$/gm, "")
66
+ .replace(/\s+/g, " ")
67
+ .trim();
68
+ }
69
+ /**
70
+ * Repo-relative labels of confirmed brand docs that are provably the
71
+ * pre-0.25.0 auto-fill output:
72
+ * - voice.md carrying a mechanical-default marker,
73
+ * - personas.yaml carrying the placeholder marker,
74
+ * - overview.md and positioning.md whose bodies are byte-identical
75
+ * (auto-fill wrote the same domain summary to both; a hand-written
76
+ * pair would diverge).
77
+ */
78
+ function autofilledConfirmed(repoRoot) {
79
+ const docs = brandDocs(repoRoot);
80
+ const byRel = new Map();
81
+ for (const d of docs)
82
+ byRel.set(d.rel, readDoc(d.abs));
83
+ const hits = new Set();
84
+ const confirmed = (rel) => {
85
+ const p = byRel.get(rel) ?? null;
86
+ return p !== null && p.status !== null && CONFIRMED.has(p.status) ? p : null;
87
+ };
88
+ const voice = confirmed("brand/voice.md");
89
+ if (voice && (voice.body.includes(VOICE_MARKER) || voice.body.includes(AVOID_MARKER))) {
90
+ hits.add("brand/voice.md");
91
+ }
92
+ const personas = confirmed("product/personas.yaml");
93
+ if (personas && personas.raw.includes(PERSONAS_MARKER)) {
94
+ hits.add("product/personas.yaml");
95
+ }
96
+ const overview = confirmed("brand/overview.md");
97
+ const positioning = confirmed("product/positioning.md");
98
+ if (overview &&
99
+ positioning &&
100
+ normalize(overview.body).length > 0 &&
101
+ normalize(overview.body) === normalize(positioning.body)) {
102
+ hits.add("brand/overview.md");
103
+ hits.add("product/positioning.md");
104
+ }
105
+ return [...hits];
106
+ }
107
+ /** Rewrite the first `status: current|accepted` line to `status: draft`. */
108
+ function demoteToDraft(abs) {
109
+ let raw;
110
+ try {
111
+ raw = readFileSync(abs, "utf8");
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ const next = raw.replace(/^status:\s*(current|accepted)\s*$/m, "status: draft");
117
+ if (next === raw)
118
+ return false;
119
+ try {
120
+ writeFileSync(abs, next, "utf8");
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ return true;
126
+ }
127
+ export const demoteAutofilledBrand = {
128
+ id: "0005-demote-autofilled-brand",
129
+ introducedIn: "0.26.0",
130
+ describe: "Demote auto-generated brand drafts (marked confirmed before 0.25.0) back to status: draft so generic voice/positioning stops being injected every session",
131
+ class: "review",
132
+ detect(repoRoot) {
133
+ return autofilledConfirmed(repoRoot).length > 0;
134
+ },
135
+ apply(repoRoot) {
136
+ const docs = brandDocs(repoRoot);
137
+ const relToAbs = new Map(docs.map((d) => [d.rel, d.abs]));
138
+ const targets = autofilledConfirmed(repoRoot);
139
+ const demoted = [];
140
+ for (const rel of targets) {
141
+ const abs = relToAbs.get(rel);
142
+ if (abs !== undefined && demoteToDraft(abs))
143
+ demoted.push(rel);
144
+ }
145
+ return {
146
+ changed: demoted.length > 0,
147
+ detail: demoted.length > 0
148
+ ? `demoted ${demoted.length} auto-generated brand doc(s) to draft: ${demoted.join(", ")} — review and set status: current on any you actually wrote`
149
+ : "no auto-generated confirmed brand docs found",
150
+ };
151
+ },
152
+ };
153
+ //# sourceMappingURL=0005-demote-autofilled-brand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"0005-demote-autofilled-brand.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0005-demote-autofilled-brand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 0006 — prune junk Layer-A (sot-align) invariants from existing repos.
3
+ *
4
+ * Before 0.23.0 the sot-align hook minted an "invariant" from almost any
5
+ * prose block — banners, separators, class/endpoint descriptions, test
6
+ * notes — with no structural pre-filter. On a repo adopted in that era the
7
+ * invariants ledger was ~97% junk, and every junk entry is surfaced + can
8
+ * be cited. 0.23.0 added the creation gate so NEW invariants are real, and
9
+ * shipped `cairn invariants prune` to clean the old ones — but existing
10
+ * adopters had to know to run it by hand. This migration surfaces it.
11
+ *
12
+ * `detect`/`apply` wrap the same `pruneInvariants` surgical core the CLI
13
+ * uses: it touches ONLY `capture_source: layer-a-sot-align` invariants
14
+ * whose statement has no constraint shape — the exact bar the creation
15
+ * gate now applies — and archives them to `.cairn/ground/.archive/`
16
+ * (recoverable), rebuilding the ledger once at the end. Curated DEC/INV
17
+ * are never touched.
18
+ *
19
+ * `review`-class: it archives committed ground state, so it surfaces for
20
+ * the operator and applies via `cairn migrate`. Ships in 0.26.0, so
21
+ * `introducedIn` is 0.26.0 — a repo pinned past 0.23.0 must still
22
+ * re-evaluate it; `detect()` carries correctness.
23
+ */
24
+ import type { Migration } from "../types.js";
25
+ export declare const pruneSotAlignInvariants: Migration;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 0006 — prune junk Layer-A (sot-align) invariants from existing repos.
3
+ *
4
+ * Before 0.23.0 the sot-align hook minted an "invariant" from almost any
5
+ * prose block — banners, separators, class/endpoint descriptions, test
6
+ * notes — with no structural pre-filter. On a repo adopted in that era the
7
+ * invariants ledger was ~97% junk, and every junk entry is surfaced + can
8
+ * be cited. 0.23.0 added the creation gate so NEW invariants are real, and
9
+ * shipped `cairn invariants prune` to clean the old ones — but existing
10
+ * adopters had to know to run it by hand. This migration surfaces it.
11
+ *
12
+ * `detect`/`apply` wrap the same `pruneInvariants` surgical core the CLI
13
+ * uses: it touches ONLY `capture_source: layer-a-sot-align` invariants
14
+ * whose statement has no constraint shape — the exact bar the creation
15
+ * gate now applies — and archives them to `.cairn/ground/.archive/`
16
+ * (recoverable), rebuilding the ledger once at the end. Curated DEC/INV
17
+ * are never touched.
18
+ *
19
+ * `review`-class: it archives committed ground state, so it surfaces for
20
+ * the operator and applies via `cairn migrate`. Ships in 0.26.0, so
21
+ * `introducedIn` is 0.26.0 — a repo pinned past 0.23.0 must still
22
+ * re-evaluate it; `detect()` carries correctness.
23
+ */
24
+ import { pruneInvariants } from "../../invariants/prune.js";
25
+ export const pruneSotAlignInvariants = {
26
+ id: "0006-prune-sot-align-invariants",
27
+ introducedIn: "0.26.0",
28
+ describe: "Archive junk Layer-A (sot-align) invariants minted before the 0.23.0 creation gate — only shapeless sot-align entries; curated DEC/INV untouched",
29
+ class: "review",
30
+ detect(repoRoot) {
31
+ try {
32
+ return pruneInvariants({ repoRoot, dryRun: true }).pruned.length > 0;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ },
38
+ apply(repoRoot) {
39
+ const result = pruneInvariants({ repoRoot });
40
+ const n = result.pruned.length;
41
+ return {
42
+ changed: n > 0,
43
+ detail: n > 0
44
+ ? `archived ${n} shapeless sot-align invariant(s) of ${result.sotAlignTotal} eligible (${result.kept} kept) → .cairn/ground/.archive/`
45
+ : "no junk sot-align invariants found",
46
+ };
47
+ },
48
+ };
49
+ //# sourceMappingURL=0006-prune-sot-align-invariants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"0006-prune-sot-align-invariants.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0006-prune-sot-align-invariants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,MAAM,CAAC,MAAM,uBAAuB,GAAc;IAChD,EAAE,EAAE,iCAAiC;IACrC,YAAY,EAAE,QAAQ;IACtB,QAAQ,EACN,kJAAkJ;IACpJ,KAAK,EAAE,QAAQ;IACf,MAAM,CAAC,QAAgB;QACrB,IAAI,CAAC;YACH,OAAO,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,KAAK,CAAC,QAAgB;QACpB,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC/B,OAAO;YACL,OAAO,EAAE,CAAC,GAAG,CAAC;YACd,MAAM,EACJ,CAAC,GAAG,CAAC;gBACH,CAAC,CAAC,YAAY,CAAC,wCAAwC,MAAM,CAAC,aAAa,cAAc,MAAM,CAAC,IAAI,kCAAkC;gBACtI,CAAC,CAAC,oCAAoC;SAC3C,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 0007 — collapse redundant nested `componentDirs`.
3
+ *
4
+ * The pre-0.22.4 component-layout detector could enumerate a directory AND
5
+ * its sub-directories (and even individual leaf component folders) as
6
+ * separate `componentDirs`. On a repo adopted in that era a workspace's
7
+ * `componentDirs` can carry dozens of entries where a directory is already
8
+ * covered by an ancestor that is also listed — e.g. both `a/b` and
9
+ * `a/b/c`, plus `a/b/c/Leaf`.
10
+ *
11
+ * The component walk recurses (`walkFs`) and collection dedups visited
12
+ * files (`collectComponents`'s `seen` set), so the redundant entries change
13
+ * nothing at runtime — they are pure config bloat. This migration removes
14
+ * any `componentDir` that is a descendant (or exact duplicate) of another
15
+ * `componentDir` in the same workspace, keeping only the shallowest
16
+ * ancestors. The collected component set is byte-identical afterward.
17
+ *
18
+ * `review`-class: it rewrites the operator's curated `config.yaml`, so it
19
+ * surfaces the count and applies via `cairn migrate` rather than silently
20
+ * rewriting their list. Ships in 0.26.0 → `introducedIn` 0.26.0; `detect()`
21
+ * carries correctness for any older pin.
22
+ */
23
+ import type { Migration } from "../types.js";
24
+ export declare const collapseComponentDirs: Migration;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * 0007 — collapse redundant nested `componentDirs`.
3
+ *
4
+ * The pre-0.22.4 component-layout detector could enumerate a directory AND
5
+ * its sub-directories (and even individual leaf component folders) as
6
+ * separate `componentDirs`. On a repo adopted in that era a workspace's
7
+ * `componentDirs` can carry dozens of entries where a directory is already
8
+ * covered by an ancestor that is also listed — e.g. both `a/b` and
9
+ * `a/b/c`, plus `a/b/c/Leaf`.
10
+ *
11
+ * The component walk recurses (`walkFs`) and collection dedups visited
12
+ * files (`collectComponents`'s `seen` set), so the redundant entries change
13
+ * nothing at runtime — they are pure config bloat. This migration removes
14
+ * any `componentDir` that is a descendant (or exact duplicate) of another
15
+ * `componentDir` in the same workspace, keeping only the shallowest
16
+ * ancestors. The collected component set is byte-identical afterward.
17
+ *
18
+ * `review`-class: it rewrites the operator's curated `config.yaml`, so it
19
+ * surfaces the count and applies via `cairn migrate` rather than silently
20
+ * rewriting their list. Ships in 0.26.0 → `introducedIn` 0.26.0; `detect()`
21
+ * carries correctness for any older pin.
22
+ */
23
+ import { loadConfigDoc, writeConfigDoc } from "../config-io.js";
24
+ function normDir(d) {
25
+ return d.replace(/\\/g, "/").replace(/\/+$/, "");
26
+ }
27
+ /**
28
+ * Keep only the shallowest ancestor dirs (original order, deduped). A dir
29
+ * is dropped when another kept dir equals it or is a path-prefix ancestor.
30
+ */
31
+ function collapseDirs(dirs) {
32
+ const norm = dirs
33
+ .filter((d) => typeof d === "string")
34
+ .map(normDir)
35
+ .filter((d) => d.length > 0);
36
+ // Shallowest-first so an ancestor is always seen before its descendants.
37
+ const ancestors = [];
38
+ const byDepth = [...new Set(norm)].sort((a, b) => {
39
+ const da = a.split("/").length;
40
+ const db = b.split("/").length;
41
+ return da - db || a.localeCompare(b);
42
+ });
43
+ for (const d of byDepth) {
44
+ if (!ancestors.some((k) => d === k || d.startsWith(`${k}/`)))
45
+ ancestors.push(d);
46
+ }
47
+ // Re-emit in the config's original order, deduped, ancestors only.
48
+ const keep = new Set(ancestors);
49
+ const seen = new Set();
50
+ const kept = [];
51
+ for (const d of norm) {
52
+ if (keep.has(d) && !seen.has(d)) {
53
+ seen.add(d);
54
+ kept.push(d);
55
+ }
56
+ }
57
+ return { kept, removed: norm.length - kept.length };
58
+ }
59
+ /** Every `componentDirs` array in the config — per-workspace, or the flat single-app form. */
60
+ function dirLists(components) {
61
+ if (components === null || typeof components !== "object")
62
+ return [];
63
+ const c = components;
64
+ const out = [];
65
+ const workspaces = c["workspaces"];
66
+ if (workspaces !== null && typeof workspaces === "object") {
67
+ for (const [ws, cfg] of Object.entries(workspaces)) {
68
+ const dirs = cfg?.["componentDirs"];
69
+ if (Array.isArray(dirs)) {
70
+ out.push({ path: ["components", "workspaces", ws, "componentDirs"], dirs: dirs });
71
+ }
72
+ }
73
+ }
74
+ if (Array.isArray(c["componentDirs"])) {
75
+ out.push({ path: ["components", "componentDirs"], dirs: c["componentDirs"] });
76
+ }
77
+ return out;
78
+ }
79
+ function readComponents(repoRoot) {
80
+ const doc = loadConfigDoc(repoRoot);
81
+ if (doc === null)
82
+ return null;
83
+ const node = doc.getIn(["components"]);
84
+ if (node === undefined || node === null)
85
+ return null;
86
+ try {
87
+ return typeof node.toJSON === "function"
88
+ ? node.toJSON()
89
+ : node;
90
+ }
91
+ catch {
92
+ return null;
93
+ }
94
+ }
95
+ export const collapseComponentDirs = {
96
+ id: "0007-collapse-component-dirs",
97
+ introducedIn: "0.26.0",
98
+ describe: "Collapse redundant nested componentDirs in config.yaml (a dir already covered by a listed ancestor) — value-preserving config tidy",
99
+ class: "review",
100
+ detect(repoRoot) {
101
+ return dirLists(readComponents(repoRoot)).some((l) => collapseDirs(l.dirs).removed > 0);
102
+ },
103
+ apply(repoRoot) {
104
+ const doc = loadConfigDoc(repoRoot);
105
+ if (doc === null)
106
+ return { changed: false, detail: "no config.yaml" };
107
+ const node = doc.getIn(["components"]);
108
+ const components = node !== undefined && node !== null && typeof node.toJSON === "function"
109
+ ? node.toJSON()
110
+ : null;
111
+ let totalRemoved = 0;
112
+ const touched = [];
113
+ for (const list of dirLists(components)) {
114
+ const { kept, removed } = collapseDirs(list.dirs);
115
+ if (removed > 0) {
116
+ doc.setIn(list.path, kept);
117
+ totalRemoved += removed;
118
+ const ws = list.path.length === 4 ? String(list.path[2]) : "components";
119
+ touched.push(`${ws} (−${removed})`);
120
+ }
121
+ }
122
+ if (totalRemoved === 0)
123
+ return { changed: false, detail: "no redundant componentDirs" };
124
+ writeConfigDoc(repoRoot, doc);
125
+ return {
126
+ changed: true,
127
+ detail: `collapsed ${totalRemoved} redundant componentDir(s): ${touched.join(", ")}`,
128
+ };
129
+ },
130
+ };
131
+ //# sourceMappingURL=0007-collapse-component-dirs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"0007-collapse-component-dirs.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0007-collapse-component-dirs.ts"],"names":[],"mappings":"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"}
@@ -9,10 +9,16 @@ import { dropDeadConfigFields } from "./migrations/0001-drop-dead-config-fields.
9
9
  import { backfillGitignore } from "./migrations/0002-backfill-gitignore.js";
10
10
  import { pruneScaffolding } from "./migrations/0003-prune-scaffolding.js";
11
11
  import { dropGlobSettings } from "./migrations/0004-drop-glob-settings.js";
12
+ import { demoteAutofilledBrand } from "./migrations/0005-demote-autofilled-brand.js";
13
+ import { pruneSotAlignInvariants } from "./migrations/0006-prune-sot-align-invariants.js";
14
+ import { collapseComponentDirs } from "./migrations/0007-collapse-component-dirs.js";
12
15
  export const MIGRATIONS = [
13
16
  dropDeadConfigFields,
14
17
  backfillGitignore,
15
18
  pruneScaffolding,
16
19
  dropGlobSettings,
20
+ demoteAutofilledBrand,
21
+ pruneSotAlignInvariants,
22
+ collapseComponentDirs,
17
23
  ];
18
24
  //# sourceMappingURL=registry.js.map
@@ -1 +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;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAE3E,MAAM,CAAC,MAAM,UAAU,GAAyB;IAC9C,oBAAoB;IACpB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;CACjB,CAAC"}
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;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,MAAM,CAAC,MAAM,UAAU,GAAyB;IAC9C,oBAAoB;IACpB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,qBAAqB;IACrB,uBAAuB;IACvB,qBAAqB;CACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isaacriehm/cairn-core",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Cairn core — state + context layer. Curated `.cairn/ground/` (decisions, §INV invariants, canonical-map, brand, quality-grades), MCP server, init wizard, hook runners, sensors, GC drift sweep.",
5
5
  "author": "Isaac Riehm",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "simple-git": "^3.36.0",
40
40
  "yaml": "^2.9.0",
41
41
  "zod": "^4.4.3",
42
- "@isaacriehm/cairn-state": "0.25.0"
42
+ "@isaacriehm/cairn-state": "0.26.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/cli-progress": "^3.11.6",