@sledorze/cairn 0.1.0 → 0.2.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.
Files changed (57) hide show
  1. package/README.md +33 -18
  2. package/dist/cli.js +68527 -70592
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +10 -10
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/Config.d.ts +21 -21
  8. package/dist/core/Config.d.ts.map +1 -1
  9. package/dist/core/Config.js +33 -33
  10. package/dist/core/Config.js.map +1 -1
  11. package/dist/core/DocSummaries.d.ts +13 -1
  12. package/dist/core/DocSummaries.d.ts.map +1 -1
  13. package/dist/core/DocSummaries.js +25 -3
  14. package/dist/core/DocSummaries.js.map +1 -1
  15. package/dist/core/MarkdownLinks.bench.js +1 -1
  16. package/dist/core/MarkdownLinks.d.ts.map +1 -1
  17. package/dist/core/StampStore.d.ts +47 -0
  18. package/dist/core/StampStore.d.ts.map +1 -0
  19. package/dist/core/StampStore.js +90 -0
  20. package/dist/core/StampStore.js.map +1 -0
  21. package/dist/core/SummaryTree.bench.js +23 -14
  22. package/dist/core/SummaryTree.bench.js.map +1 -1
  23. package/dist/core/SummaryTree.d.ts +10 -1
  24. package/dist/core/SummaryTree.d.ts.map +1 -1
  25. package/dist/core/SummaryTree.js +34 -9
  26. package/dist/core/SummaryTree.js.map +1 -1
  27. package/dist/core/glob.bench.js +1 -1
  28. package/dist/core/glob.d.ts.map +1 -1
  29. package/dist/core/paths.d.ts.map +1 -1
  30. package/dist/index.js +10 -10
  31. package/dist/init/content.d.ts +2 -2
  32. package/dist/init/content.d.ts.map +1 -1
  33. package/dist/init/content.js +45 -15
  34. package/dist/init/content.js.map +1 -1
  35. package/dist/init/generate.d.ts +1 -1
  36. package/dist/init/generate.d.ts.map +1 -1
  37. package/dist/init/generate.js +1 -1
  38. package/dist/io/DocsFs.d.ts +2 -3
  39. package/dist/io/DocsFs.d.ts.map +1 -1
  40. package/dist/io/DocsFs.js +15 -5
  41. package/dist/io/DocsFs.js.map +1 -1
  42. package/dist/program/CheckLinks.d.ts.map +1 -1
  43. package/dist/program/CheckLinks.js +4 -4
  44. package/dist/program/CheckLinks.js.map +1 -1
  45. package/dist/program/CheckSummaries.bench.d.ts +2 -0
  46. package/dist/program/CheckSummaries.bench.d.ts.map +1 -0
  47. package/dist/program/CheckSummaries.bench.js +92 -0
  48. package/dist/program/CheckSummaries.bench.js.map +1 -0
  49. package/dist/program/CheckSummaries.d.ts +25 -5
  50. package/dist/program/CheckSummaries.d.ts.map +1 -1
  51. package/dist/program/CheckSummaries.js +143 -40
  52. package/dist/program/CheckSummaries.js.map +1 -1
  53. package/dist/program/JsonReport.d.ts.map +1 -1
  54. package/dist/program/JsonReport.js +2 -2
  55. package/dist/program/locale.d.ts.map +1 -1
  56. package/package.json +6 -8
  57. package/schema/cairn.schema.json +35 -38
@@ -0,0 +1,90 @@
1
+ // The hidden, hierarchy-mirroring metadata tree that replaces the in-content
2
+ // `<!-- source-sha256: H -->` stamp (see AGENTS.md / issue #35).
3
+ //
4
+ // Every summarizable node keeps its authored prose stamp-free; instead, a sidecar
5
+ // JSON file under `<base>/.cairn/` mirrors the node's path 1:1 and carries the
6
+ // freshness hash. This module is pure (no IO): path mapping + (de)serialisation
7
+ // only. `program/CheckSummaries.ts` is the impure edge that reads/writes sidecars
8
+ // via `DocsFs`.
9
+ //
10
+ // Two invariants this module enforces:
11
+ // - every node path handed to `sidecarPathFor` must live under `base` (real
12
+ // usage: `base` is the project root, every root/node resolved under it) —
13
+ // violating this is a programming error, not a data error, so it throws;
14
+ // - the sidecar record is decoded LENIENTLY: unknown keys are ignored rather
15
+ // than rejected, so a future, richer sidecar (e.g. #29's per-instance
16
+ // manifests) still reads on an older binary that only knows `sha256`/`version`
17
+ // — the whole point of moving tracking data out of content is to let it grow
18
+ // without ever touching a content file, and a schema that breaks forward
19
+ // compatibility would defeat that.
20
+ import * as nodePath from 'node:path';
21
+ import { Result, Schema } from 'effect';
22
+ // POSIX path semantics so sidecar paths are identical on every OS, matching
23
+ // SummaryTree.ts's own rationale for the same choice.
24
+ const path = nodePath.posix;
25
+ /** The hidden directory name every metadata tree lives under, relative to `base`. */
26
+ export const META_DIR = '.cairn';
27
+ /** Bumped only if the sidecar's own shape changes incompatibly (never for adding
28
+ * an optional field — `decodeStamp` already tolerates unknown keys). */
29
+ export const STAMP_VERSION = 1;
30
+ const StampRecordSchema = Schema.Struct({
31
+ sha256: Schema.String,
32
+ version: Schema.Number,
33
+ });
34
+ const decodeStamp = Schema.decodeUnknownResult(StampRecordSchema);
35
+ /** The sidecar's on-disk JSON form. Trailing newline for a clean git diff. */
36
+ export const serializeStamp = (record) => `${JSON.stringify(record, null, 2)}\n`;
37
+ /**
38
+ * Read a sidecar's `StampRecord` back, or `null` if it's missing/corrupt/
39
+ * malformed/hand-edited/merge-conflicted — this must NEVER throw. A stamp that
40
+ * can't be trusted is exactly equivalent to no stamp: the node it covers reads
41
+ * as stale, not as a crash (see AGENTS.md's note on treating an unparsable
42
+ * stamp the same as a missing one).
43
+ */
44
+ export const parseStamp = (content) => {
45
+ let json;
46
+ try {
47
+ json = JSON.parse(content);
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ const decoded = decodeStamp(json);
53
+ return Result.isSuccess(decoded) ? decoded.success : null;
54
+ };
55
+ export const metaRootFor = (base) => path.join(base, META_DIR);
56
+ /** True for any path inside the hidden metadata tree — used to keep `.cairn/**`
57
+ * out of the set of markdown source files a plan considers. */
58
+ export const isSidecarPath = (candidate, metaRoot) => candidate === metaRoot || candidate.startsWith(`${metaRoot}/`);
59
+ /**
60
+ * `<base>/docs/a.summary.md` -> `<metaRoot>/docs/a.summary.md.json`. Throws if
61
+ * `nodeAtPath` isn't under `base` — every real node path is (roots are always
62
+ * resolved under the project root before a plan ever runs), so this signals a
63
+ * caller bug, not a runtime data condition to recover from.
64
+ */
65
+ export const sidecarPathFor = (nodeAtPath, layout) => {
66
+ const rel = path.relative(layout.base, nodeAtPath);
67
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
68
+ throw new Error(`sidecarPathFor: "${nodeAtPath}" is not under base "${layout.base}"`);
69
+ }
70
+ return `${path.join(layout.metaRoot, rel)}.json`;
71
+ };
72
+ /**
73
+ * The inverse of `sidecarPathFor`: given a sidecar's own path (e.g. found by
74
+ * listing `.cairn/**`), recover the node path it mirrors. Returns `null` for a
75
+ * path that isn't a well-formed sidecar under `metaRoot` (not `.json`, or
76
+ * outside the tree) rather than throwing — unlike `sidecarPathFor`, this reads
77
+ * data that could plausibly be malformed (a stray non-JSON file dropped into
78
+ * `.cairn/` by hand), so `null` is the right "not a sidecar" signal, not a crash.
79
+ */
80
+ export const nodePathForSidecar = (sidecarPath, layout) => {
81
+ if (!isSidecarPath(sidecarPath, layout.metaRoot) || !sidecarPath.endsWith('.json')) {
82
+ return null;
83
+ }
84
+ const rel = path.relative(layout.metaRoot, sidecarPath);
85
+ if (rel.startsWith('..')) {
86
+ return null;
87
+ }
88
+ return path.join(layout.base, rel.slice(0, -'.json'.length));
89
+ };
90
+ //# sourceMappingURL=StampStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StampStore.js","sourceRoot":"","sources":["../../src/core/StampStore.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iEAAiE;AACjE,EAAE;AACF,kFAAkF;AAClF,+EAA+E;AAC/E,gFAAgF;AAChF,kFAAkF;AAClF,gBAAgB;AAChB,EAAE;AACF,uCAAuC;AACvC,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,yEAAyE;AACzE,kFAAkF;AAClF,gFAAgF;AAChF,4EAA4E;AAC5E,sCAAsC;AAEtC,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAA;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,4EAA4E;AAC5E,sDAAsD;AACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAA;AAE3B,qFAAqF;AACrF,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAA;AAOhC;wEACwE;AACxE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAA;AAE9B,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAA;AAEjE,8EAA8E;AAC9E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAmB,EAAU,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AAErG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAsB,EAAE;IAChE,IAAI,IAAa,CAAA;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IACjC,OAAO,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;AAC3D,CAAC,CAAA;AAUD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AAE9E;+DAC+D;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAE,QAAgB,EAAW,EAAE,CAC5E,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAA;AAEhE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAkB,EAAE,MAAkB,EAAU,EAAE;IAC/E,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IAClD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,oBAAoB,UAAU,wBAAwB,MAAM,CAAC,IAAI,GAAG,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;AAClD,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,WAAmB,EAAE,MAAkB,EAAiB,EAAE;IAC3F,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACnF,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;IACvD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;AAC9D,CAAC,CAAA"}
@@ -1,13 +1,18 @@
1
1
  import * as nodePath from 'node:path';
2
2
  import { bench, describe } from 'vitest';
3
- import { hashContent, isSummaryFile, sourceHashTag, summaryPathFor } from "./DocSummaries.js";
4
- import { DIR_SUMMARY, isDirSummary, planSummaries } from "./SummaryTree.js";
3
+ import { hashContent, isSummaryFile, summaryPathFor } from './DocSummaries.js';
4
+ import { DIR_SUMMARY, isDirSummary, planSummaries } from './SummaryTree.js';
5
5
  const path = nodePath.posix;
6
6
  const bigContent = (seed) => Array.from({ length: 40 }, (_, i) => `${seed} body line ${i} with some representative prose content`).join('\n');
7
7
  const smallContent = (seed) => `${seed} short note`;
8
- /** A fully stamped, link-complete tree: `planSummaries` on it reports every node `ok`. */
9
- const buildFreshTree = ({ depth, dirsPerLevel, filesPerDir, root }) => {
8
+ /** A fully link-complete tree (no stamps embedded freshness lives in a
9
+ * separate `stamps` map now, see `StampStore.ts` / `SummaryTree.ts`'s
10
+ * `PlanArgs.stamps`), plus the stamps map a real `.cairn/**` sidecar store
11
+ * would hold for it. `planSummaries({files, stamps, ...})` on the pair reports
12
+ * every node `ok` — this is `buildFreshTree`'s "steady state" fixture. */
13
+ const buildFreshTree = ({ depth, dirsPerLevel, filesPerDir, root, }) => {
10
14
  const files = new Map();
15
+ const stamps = new Map();
11
16
  const visit = (dir, level) => {
12
17
  const docTargets = [];
13
18
  const inputs = [];
@@ -19,7 +24,9 @@ const buildFreshTree = ({ depth, dirsPerLevel, filesPerDir, root }) => {
19
24
  docTargets.push(docPath);
20
25
  if (big) {
21
26
  const sp = summaryPathFor(docPath);
22
- files.set(sp, `${sourceHashTag(hashContent(content))}\n\n# summary\n\nSee [source](./${path.basename(docPath)}).`);
27
+ const summaryContent = `# summary\n\nSee [source](./${path.basename(docPath)}).`;
28
+ files.set(sp, summaryContent);
29
+ stamps.set(sp, hashContent(content));
23
30
  inputs.push(sp);
24
31
  }
25
32
  else {
@@ -40,31 +47,33 @@ const buildFreshTree = ({ depth, dirsPerLevel, filesPerDir, root }) => {
40
47
  .toSorted()
41
48
  .join('\n');
42
49
  const links = [...docTargets, ...dirTargets].map((t) => `- [link](${path.relative(dir, t)})`).join('\n');
43
- files.set(`${dir}/${DIR_SUMMARY}`, `${sourceHashTag(hashContent(manifest))}\n\n${links}`);
50
+ files.set(`${dir}/${DIR_SUMMARY}`, links);
51
+ stamps.set(`${dir}/${DIR_SUMMARY}`, hashContent(manifest));
44
52
  };
45
53
  visit(root, 0);
46
- return files;
54
+ return { files, stamps };
47
55
  };
48
- /** Same source docs, no summaries anywhere yet — the "first run" worst case. */
56
+ /** Same source docs, no summaries anywhere yet — the "first run" worst case
57
+ * (no stamps either, matching an empty/not-yet-populated `.cairn/**`). */
49
58
  const sourceOnly = (files) => new Map([...files].filter(([p]) => !isSummaryFile(p) && !isDirSummary(p)));
50
59
  const SMALL = { depth: 1, dirsPerLevel: 9, filesPerDir: 10, root: '/repo/docs' };
51
60
  const LARGE = { depth: 4, dirsPerLevel: 3, filesPerDir: 16, root: '/repo/docs' };
52
61
  const smallFresh = buildFreshTree(SMALL);
53
- const smallRaw = sourceOnly(smallFresh);
62
+ const smallRaw = sourceOnly(smallFresh.files);
54
63
  const largeFresh = buildFreshTree(LARGE);
55
- const largeRaw = sourceOnly(largeFresh);
64
+ const largeRaw = sourceOnly(largeFresh.files);
56
65
  describe('planSummaries()', () => {
57
- bench('~100 files, flat/shallow, first run (no summaries)', () => {
66
+ bench('~100 files, flat/shallow, first run (no summaries, no stamps)', () => {
58
67
  planSummaries({ files: smallRaw, roots: [SMALL.root] });
59
68
  });
60
69
  bench('~100 files, flat/shallow, steady state (fully stamped)', () => {
61
- planSummaries({ files: smallFresh, roots: [SMALL.root] });
70
+ planSummaries({ files: smallFresh.files, roots: [SMALL.root], stamps: smallFresh.stamps });
62
71
  });
63
- bench('~2000 files, deep/nested, first run (no summaries)', () => {
72
+ bench('~2000 files, deep/nested, first run (no summaries, no stamps)', () => {
64
73
  planSummaries({ files: largeRaw, roots: [LARGE.root] });
65
74
  });
66
75
  bench('~2000 files, deep/nested, steady state (fully stamped)', () => {
67
- planSummaries({ files: largeFresh, roots: [LARGE.root] });
76
+ planSummaries({ files: largeFresh.files, roots: [LARGE.root], stamps: largeFresh.stamps });
68
77
  });
69
78
  });
70
79
  //# sourceMappingURL=SummaryTree.bench.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SummaryTree.bench.js","sourceRoot":"","sources":["../../src/core/SummaryTree.bench.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SummaryTree.bench.js","sourceRoot":"","sources":["../../src/core/SummaryTree.bench.ts"],"names":[],"mappings":"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"}
@@ -16,11 +16,20 @@ export interface PlanArgs {
16
16
  readonly naming?: Naming;
17
17
  readonly requireDirSummaries?: boolean;
18
18
  readonly roots: readonly string[];
19
+ /** Node path -> recorded hash, loaded from `.cairn/**` sidecars. Optional and
20
+ * defaults to empty — an absent/not-yet-populated stamp store degrades every
21
+ * node to `stale`/`missing`, the correct first-run behaviour, never a crash. */
22
+ readonly stamps?: ReadonlyMap<string, string>;
19
23
  readonly thresholdLines?: number;
20
24
  }
21
25
  export interface SummaryPlan {
22
26
  readonly nodes: readonly PlanNode[];
23
27
  readonly orphans: readonly string[];
28
+ /** A `.cairn/**` sidecar whose node no longer exists — its source doc (and
29
+ * possibly its summary file too) was deleted, renamed, or dropped below the
30
+ * size threshold. See `findDeletedStamps` for why this is distinct from
31
+ * `orphans`. */
32
+ readonly orphanStamps: readonly string[];
24
33
  readonly todo: readonly PlanNode[];
25
34
  }
26
35
  /** True when `p` is a directory summary under the configured naming. */
@@ -41,5 +50,5 @@ export interface NodeHashArgs {
41
50
  */
42
51
  export declare const nodeExpectedHash: ({ files, inputs, kind, path: nodeAtPath }: NodeHashArgs) => string;
43
52
  /** Compute the full hierarchical summary plan from the current file contents. */
44
- export declare const planSummaries: ({ files, ignore, naming, requireDirSummaries, roots, thresholdLines, }: PlanArgs) => SummaryPlan;
53
+ export declare const planSummaries: ({ files, ignore, naming, requireDirSummaries, roots, stamps, thresholdLines, }: PlanArgs) => SummaryPlan;
45
54
  //# sourceMappingURL=SummaryTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SummaryTree.d.ts","sourceRoot":"","sources":["../../src/core/SummaryTree.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAgB9D,6CAA6C;AAC7C,eAAO,MAAM,WAAW,QAA4B,CAAA;AAEpD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;CACnC;AAID,wEAAwE;AACxE,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,EAAE,SAAQ,MAAuB,KAAG,OACV,CAAA;AA2BhE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,2CAA2C,YAAY,KAAG,MAU1F,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,aAAa,GAAI,wEAO3B,QAAQ,KAAG,WAiHb,CAAA"}
1
+ {"version":3,"file":"SummaryTree.d.ts","sourceRoot":"","sources":["../../src/core/SummaryTree.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAS9D,6CAA6C;AAC7C,eAAO,MAAM,WAAW,QAA4B,CAAA;AAEpD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC;;oFAEgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC;;;oBAGgB;IAChB,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;CACnC;AAMD,wEAAwE;AACxE,eAAO,MAAM,YAAY,MAAO,MAAM,WAAU,MAAM,KAAoB,OACV,CAAA;AA2BhE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,8CAA+C,YAAY,KAAG,MAU1F,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,aAAa,mFAQvB,QAAQ,KAAG,WA2Hb,CAAA"}
@@ -6,10 +6,15 @@
6
6
  // direct docs (or their summary when the doc is big) AND the `_SUMMARY.md`
7
7
  // of its direct sub-directories.
8
8
  //
9
- // Freshness is content-hash based (clone/CI-proof, unlike mtime). Each summary
10
- // embeds `<!-- source-sha256: H -->`:
9
+ // Freshness is content-hash based (clone/CI-proof, unlike mtime). Each summary's
10
+ // hash H is recorded in a hidden sidecar under `.cairn/` (see StampStore.ts),
11
+ // never inside the summary's own content:
11
12
  // - file summary -> H = hash(source doc content)
12
13
  // - dir summary -> H = hash(manifest of its inputs' relative-path:content-hash)
14
+ // `planSummaries` never reads or writes a sidecar itself — it's handed the
15
+ // already-loaded `stamps` map (node path -> recorded hash) as a plain value, so
16
+ // this whole module stays pure and storage-agnostic; `program/CheckSummaries.ts`
17
+ // is the impure edge that loads `stamps` from `.cairn/**` via `DocsFs`.
13
18
  //
14
19
  // `planSummaries` returns every expected summary with its status and, crucially,
15
20
  // the bottom-up order in which to (re)generate them so a single pass converges:
@@ -19,14 +24,15 @@
19
24
  // Filenames (`naming`), the line threshold, ignored globs and whether directory
20
25
  // summaries are required are all configurable; defaults reproduce the original.
21
26
  import * as nodePath from 'node:path';
22
- import { countLines, DEFAULT_NAMING, extractSourceHash, hashContent, isSummaryFile, summaryPathFor, } from "./DocSummaries.js";
23
- import { matchesAny } from "./glob.js";
24
- import { extractLinks, isCheckableTarget, stripAnchor, stripCode } from "./MarkdownLinks.js";
27
+ import { countLines, DEFAULT_NAMING, hashContent, isSummaryFile, summaryPathFor } from './DocSummaries.js';
28
+ import { matchesAny } from './glob.js';
29
+ import { extractLinks, isCheckableTarget, stripAnchor, stripCode } from './MarkdownLinks.js';
25
30
  // POSIX path semantics so the plan is identical on every OS (inputs normalised
26
31
  // to `/` at the IO boundary).
27
32
  const path = nodePath.posix;
28
33
  /** Default per-directory digest filename. */
29
34
  export const DIR_SUMMARY = DEFAULT_NAMING.dirSummary;
35
+ const EMPTY_STAMPS = new Map();
30
36
  const DEFAULT_THRESHOLD_LINES = 30;
31
37
  /** True when `p` is a directory summary under the configured naming. */
32
38
  export const isDirSummary = (p, naming = DEFAULT_NAMING) => p === naming.dirSummary || p.endsWith(`/${naming.dirSummary}`);
@@ -73,9 +79,9 @@ export const nodeExpectedHash = ({ files, inputs, kind, path: nodeAtPath }) => {
73
79
  return hashContent(manifest);
74
80
  };
75
81
  /** Compute the full hierarchical summary plan from the current file contents. */
76
- export const planSummaries = ({ files, ignore = [], naming = DEFAULT_NAMING, requireDirSummaries = true, roots, thresholdLines = DEFAULT_THRESHOLD_LINES, }) => {
82
+ export const planSummaries = ({ files, ignore = [], naming = DEFAULT_NAMING, requireDirSummaries = true, roots, stamps = EMPTY_STAMPS, thresholdLines = DEFAULT_THRESHOLD_LINES, }) => {
77
83
  const allPaths = [...files.keys()];
78
- const recorded = (p) => (files.has(p) ? extractSourceHash(files.get(p) ?? '') : null);
84
+ const recorded = (p) => stamps.get(p) ?? null;
79
85
  const sourceDocs = allPaths.filter((p) => p.endsWith('.md') && !isSummaryFile(p, naming) && !isDirSummary(p, naming) && !matchesAny(p, ignore));
80
86
  // Computed once per doc up front (a Set lookup below) rather than via a
81
87
  // countLines() call at each of the two sites that ask "is this doc big" — the
@@ -103,7 +109,12 @@ export const planSummaries = ({ files, ignore = [], naming = DEFAULT_NAMING, req
103
109
  }
104
110
  if (!requireDirSummaries) {
105
111
  const orphans = findOrphans({ files, ignore, naming, nodes: fileNodes, requireDirSummaries });
106
- return { nodes: fileNodes, orphans, todo: fileNodes.filter((n) => n.status !== 'ok') };
112
+ const orphanStamps = findDeletedStamps({
113
+ expectedNodePaths: new Set(fileNodes.map((n) => n.path)),
114
+ ignore,
115
+ stampNodePaths: stamps.keys(),
116
+ });
117
+ return { nodes: fileNodes, orphanStamps, orphans, todo: fileNodes.filter((n) => n.status !== 'ok') };
107
118
  }
108
119
  // --- directories in scope ---
109
120
  const inScope = (d) => roots.some((r) => d === r || d.startsWith(`${r}/`));
@@ -177,8 +188,22 @@ export const planSummaries = ({ files, ignore = [], naming = DEFAULT_NAMING, req
177
188
  dirNodes.sort((a, b) => depth(b.path) - depth(a.path) || a.path.localeCompare(b.path));
178
189
  const nodes = [...fileNodes, ...dirNodes];
179
190
  const orphans = findOrphans({ files, ignore, naming, nodes, requireDirSummaries });
180
- return { nodes, orphans, todo: nodes.filter((n) => n.status !== 'ok') };
191
+ const orphanStamps = findDeletedStamps({
192
+ expectedNodePaths: new Set(nodes.map((n) => n.path)),
193
+ ignore,
194
+ stampNodePaths: stamps.keys(),
195
+ });
196
+ return { nodes, orphanStamps, orphans, todo: nodes.filter((n) => n.status !== 'ok') };
181
197
  };
198
+ /**
199
+ * A `.cairn/**` sidecar (see StampStore.ts) whose node no longer corresponds to
200
+ * any expected node. Unlike `findOrphans` (which only sees a leftover summary
201
+ * FILE still on disk), a sidecar is written exclusively by the tool and never
202
+ * touched by hand — so it remains as evidence even when the summary file
203
+ * itself was deleted alongside its source, catching a deletion `findOrphans`
204
+ * alone would miss entirely.
205
+ */
206
+ const findDeletedStamps = ({ expectedNodePaths, ignore, stampNodePaths }) => [...stampNodePaths].filter((p) => !expectedNodePaths.has(p) && !matchesAny(p, ignore)).toSorted();
182
207
  /**
183
208
  * A `.summary.md`/`_SUMMARY.md` on disk that no longer corresponds to any
184
209
  * expected node — its source doc was deleted, renamed, or (for file summaries)
@@ -1 +1 @@
1
- {"version":3,"file":"SummaryTree.js","sourceRoot":"","sources":["../../src/core/SummaryTree.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SummaryTree.js","sourceRoot":"","sources":["../../src/core/SummaryTree.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { bench, describe } from 'vitest';
2
- import { globToRegExp, matchesAny, matchesGlob } from "./glob.js";
2
+ import { globToRegExp, matchesAny, matchesGlob } from './glob.js';
3
3
  const DIRS = ['src', 'docs', 'lib', 'packages', 'apps', 'test', 'scripts', 'vendor'];
4
4
  const SUBDIRS = ['core', 'utils', 'components', 'services', 'models', 'fixtures'];
5
5
  const EXTS = ['ts', 'tsx', 'md', 'json', 'css', 'tmp'];
@@ -1 +1 @@
1
- {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/core/glob.ts"],"names":[],"mappings":"AAWA,8CAA8C;AAC9C,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,MAQ9C,CAAA;AA4BD,mDAAmD;AACnD,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,OAA2C,CAAA;AAEvG,2DAA2D;AAC3D,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,UAAU,SAAS,MAAM,EAAE,KAAG,OACf,CAAA"}
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/core/glob.ts"],"names":[],"mappings":"AAWA,8CAA8C;AAC9C,eAAO,MAAM,YAAY,YAAa,MAAM,KAAG,MAQ9C,CAAA;AA4BD,mDAAmD;AACnD,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,MAAM,KAAG,OAA2C,CAAA;AAEvG,2DAA2D;AAC3D,eAAO,MAAM,UAAU,SAAU,MAAM,YAAY,SAAS,MAAM,EAAE,KAAG,OACf,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAIA,qDAAqD;AACrD,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,KAAG,MAAiC,CAAA"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAIA,qDAAqD;AACrD,eAAO,MAAM,OAAO,MAAO,MAAM,KAAG,MAAiC,CAAA"}
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  // Public API surface. The CLI (`cairn`) is the primary entrypoint, but the pure
2
2
  // planners and Effect programs are exported for programmatic use and testing.
3
- export * from "./core/DocSummaries.js";
4
- export * from "./core/glob.js";
5
- export * from "./core/MarkdownLinks.js";
6
- export * from "./core/SummaryTree.js";
7
- export * from "./io/DocsFs.js";
8
- export * from "./program/CheckLinks.js";
9
- export * from "./program/CheckSummaries.js";
10
- export * from "./program/locale.js";
11
- export * from "./config.js";
12
- export { runInit } from "./init/generate.js";
3
+ export * from './core/DocSummaries.js';
4
+ export * from './core/glob.js';
5
+ export * from './core/MarkdownLinks.js';
6
+ export * from './core/SummaryTree.js';
7
+ export * from './io/DocsFs.js';
8
+ export * from './program/CheckLinks.js';
9
+ export * from './program/CheckSummaries.js';
10
+ export * from './program/locale.js';
11
+ export * from './config.js';
12
+ export { runInit } from './init/generate.js';
13
13
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,3 @@
1
- export declare const CONVENTION_BODY = "# Documentation summary convention\n\nThis repo enforces a **hierarchical, content-hashed documentation summary** tree.\nCI runs `cairn check` and **fails the merge** if any summary is missing,\nstale, or a link is broken. Treat green `check` as a hard requirement, not a nicety.\n\n## The invariant\n\n1. **File summaries** \u2014 every Markdown file longer than the threshold (default 30\n lines) has a sibling `X.summary.md`: a fast-to-read digest of the CURRENT content\n of `X.md`.\n2. **Directory summaries** \u2014 every in-scope directory has a `_SUMMARY.md` that\n aggregates its direct docs (each doc's `.summary.md` if the doc is big, else the\n doc itself) plus the `_SUMMARY.md` of each direct sub-directory. It links to\n **every** direct child file and sub-directory (link-completeness).\n3. **Freshness by content hash** \u2014 each summary's first line is\n `<!-- source-sha256: <64-hex> -->`. The checker recomputes the source hash;\n mismatch = stale, absent = missing. This survives git clone and CI (mtime does not).\n4. **Bottom-up in one pass** \u2014 a directory summary hashes a manifest of its children's\n hashes (a Merkle tree), so (re)write leaves-first: file summaries, then directories\n deepest-first, then stamp.\n\n## Workflow when you edit docs\n\nWhen you create or edit any doc:\n\n1. If the doc is longer than the threshold, create or update its `X.summary.md` to\n reflect the new content.\n2. Update the `_SUMMARY.md` of every affected directory, walking **up** the tree\n leaves-first, and keep a link to every child file and sub-directory.\n3. Run the stamp command to (re)write the `source-sha256` hashes bottom-up:\n `npx cairn check --summaries-only --stamp`.\n4. Run `npx cairn check` and ensure it exits 0 (green) before you finish.\n\n## Commands\n\n- `npx cairn check` \u2014 check summaries + links (exit 1 on any problem).\n- `npx cairn check --summaries-only` / `--links-only`.\n- `npx cairn check --links-only --fix` \u2014 auto-repair unambiguous dead links.\n- `npx cairn check --summaries-only --stamp` \u2014 write stamps of EXISTING\n summaries bottom-up. It does **not** author prose; you write the content, then stamp.\n\nYou author the prose. The tool only verifies and stamps.\n";
2
- export declare const SKILL_BODY = "# Writing good documentation summaries\n\nUse this when you author or refresh the summary tree that `cairn`\nenforces. It covers *how* to write summaries that are worth reading, and the exact\nmechanical order to (re)generate them so `check` goes green in one pass.\n\n## Two kinds of summary \u2014 do not conflate them\n\n**A file summary (`X.summary.md`) condenses ONE document.**\nGoal: a reader grasps what `X.md` says in ~10 seconds.\n\n- Faithful to the source \u2014 never invent, never contradict, never add claims the doc\n doesn't make. It is a digest, not commentary.\n- Front-load the thesis and the hard numbers. Lead with the conclusion, the decision,\n the metric \u2014 not the background.\n- Bullet-dense, no fluff. Drop hedging, transitions, and restated headings.\n- If the source changes, the summary changes. A summary that no longer matches its\n source is a bug the checker will catch.\n\n**A directory summary (`_SUMMARY.md`) is a MAP, not a digest.**\nGoal: a reader knows what lives in this directory and where to go next.\n\n- A short orientation paragraph (1-3 sentences): what this directory is about.\n- Then one line per direct child \u2014 file **and** sub-directory \u2014 each with a Markdown\n link and a few-word hook describing what's behind it.\n- For a big doc, link and hook its `.summary.md`; for a small doc, link the doc itself.\n- For a sub-directory, link its `_SUMMARY.md`.\n- **Link-completeness:** every direct child must appear as a link. A missing link fails\n `check`. When you add or remove a child, update the parent's `_SUMMARY.md`.\n\n## Why leaves-first \u2014 the Merkle mental model\n\nEach summary is stamped with `<!-- source-sha256: <hex> -->` over its source. A\ndirectory summary's source is a **manifest of its children's hashes**, so a child's\nhash must be settled before its parent can be stamped. Think of it as a Merkle tree:\nchange a leaf and every hash on the path to the root must be recomputed. If you stamp\ntop-down, parents capture stale child hashes and `check` stays red.\n\n## The bottom-up procedure\n\n1. **Author leaves first.** For every doc over the threshold, write/refresh its\n `X.summary.md`. Get the prose right before touching any directory.\n2. **Author directories deepest-first.** Walk from the deepest directories up to the\n roots. For each, write its `_SUMMARY.md`: orientation paragraph, then a linked line\n for every direct child (child `.summary.md` or doc, and each sub-dir's `_SUMMARY.md`).\n3. **Stamp mechanically.** Run `npx cairn check --summaries-only --stamp`.\n It rewrites every `source-sha256` bottom-up. **Never hand-edit a sha256** \u2014 it is\n computed, not authored; a hand-typed hash is always wrong.\n4. **Verify.** Run `npx cairn check` and confirm exit 0.\n\n## Tiny examples\n\nA **file summary** (`guides/getting-started.summary.md`):\n\n```markdown\n<!-- source-sha256: 0000...(stamped by the tool) -->\n# Getting started \u2014 summary\n\n- Install as a dev dependency, then run the init command.\n- Configure via a single rc file; every option has a sensible default.\n- First run scaffolds an example and prints the next command to run.\n```\n\nA **directory summary** (`guides/_SUMMARY.md`):\n\n```markdown\n<!-- source-sha256: 0000...(stamped by the tool) -->\n# Guides\n\nHow-to guides for everyday tasks, in reading order.\n\n- [getting-started](./getting-started.summary.md) \u2014 install, configure, first run\n- [configuration](./configuration.md) \u2014 every rc option, with its default\n- [advanced/](./advanced/_SUMMARY.md) \u2014 recipes for larger setups\n```\n\nKeep summaries short, keep links complete, stamp last, verify green.\n";
1
+ export declare const CONVENTION_BODY = "# Documentation summary convention\n\nThis repo enforces a **hierarchical, content-hashed documentation summary** tree.\nCI runs `cairn check` and **fails the merge** if any summary is missing,\nstale, or a link is broken. Treat green `check` as a hard requirement, not a nicety.\n\n## The invariant\n\n1. **File summaries** \u2014 every Markdown file longer than the threshold (default 30\n lines) has a sibling `X.summary.md`: a fast-to-read digest of the CURRENT content\n of `X.md`.\n2. **Directory summaries** \u2014 every in-scope directory has a `_SUMMARY.md` that\n aggregates its direct docs (each doc's `.summary.md` if the doc is big, else the\n doc itself) plus the `_SUMMARY.md` of each direct sub-directory. It links to\n **every** direct child file and sub-directory (link-completeness).\n3. **Freshness by content hash, tracked OUTSIDE your docs** \u2014 each summary's hash is\n recorded in a hidden sidecar under `.cairn/`, one JSON file mirroring each summary's\n path (e.g. `.cairn/docs/a.summary.md.json`). The checker recomputes the source hash\n and compares it to the sidecar; mismatch = stale, absent = missing. This survives git\n clone and CI (mtime does not), and it means the tracking system leaves **zero bytes**\n in the docs you write \u2014 no stamp comment to see, ignore, or accidentally hand-edit.\n Commit `.cairn/` alongside your docs; it's not gitignored.\n4. **Bottom-up in one pass** \u2014 a directory summary hashes a manifest of its children's\n hashes (a Merkle tree), so (re)write leaves-first: file summaries, then directories\n deepest-first, then stamp.\n5. **Deletions are caught too** \u2014 a sidecar left behind with no matching doc (its source\n was deleted or renamed) is flagged as a deleted-source stamp; `--prune` removes both\n the leftover summary and its sidecar.\n\n## Upgrading from an older cairn (legacy `<!-- source-sha256 -->` stamp)\n\n**Nothing special to do \u2014 do not go looking for a migration step.** If a summary still\ncarries the old in-content `<!-- source-sha256: ... -->` comment, the ordinary stamp\ncommand (`npx cairn check --summaries-only --stamp`) strips it and writes the\n`.cairn/` sidecar in the same run, automatically. There is no separate command to\ndiscover or remember: whatever `stampCommand` this repo already runs already does it.\n(`--migrate-stamps` also exists, purely as an optional explicit/reportable alias for\nthe same self-healing behaviour \u2014 never required.)\n\n## Workflow when you edit docs\n\nWhen you create or edit any doc:\n\n1. If the doc is longer than the threshold, create or update its `X.summary.md` to\n reflect the new content.\n2. Update the `_SUMMARY.md` of every affected directory, walking **up** the tree\n leaves-first, and keep a link to every child file and sub-directory.\n3. Run the stamp command to (re)write the sidecar hashes under `.cairn/` bottom-up:\n `npx cairn check --summaries-only --stamp`.\n4. Run `npx cairn check` and ensure it exits 0 (green) before you finish.\n5. Commit your doc changes **together with** the `.cairn/` sidecar changes \u2014 a doc\n edit without its matching sidecar update is exactly what `check` is designed to catch.\n\n## Commands\n\n- `npx cairn check` \u2014 check summaries + links (exit 1 on any problem).\n- `npx cairn check --summaries-only` / `--links-only`.\n- `npx cairn check --links-only --fix` \u2014 auto-repair unambiguous dead links.\n- `npx cairn check --summaries-only --stamp` \u2014 write the `.cairn/` sidecar hash of\n EXISTING summaries bottom-up. It does **not** author prose; you write the content,\n then stamp.\n- `npx cairn check --prune` \u2014 delete orphan summaries and orphan `.cairn/` sidecars\n (source doc deleted, renamed, or below threshold).\n- `npx cairn check --migrate-stamps` \u2014 optional: the same self-healing `--stamp`\n already does for a legacy in-content stamp, as its own named/reported step. Never\n required.\n\nYou author the prose. The tool only verifies and stamps \u2014 and it never touches your prose to do it.\n";
2
+ export declare const SKILL_BODY = "# Writing good documentation summaries\n\nUse this when you author or refresh the summary tree that `cairn`\nenforces. It covers *how* to write summaries that are worth reading, and the exact\nmechanical order to (re)generate them so `check` goes green in one pass.\n\n## Two kinds of summary \u2014 do not conflate them\n\n**A file summary (`X.summary.md`) condenses ONE document.**\nGoal: a reader grasps what `X.md` says in ~10 seconds.\n\n- Faithful to the source \u2014 never invent, never contradict, never add claims the doc\n doesn't make. It is a digest, not commentary.\n- Front-load the thesis and the hard numbers. Lead with the conclusion, the decision,\n the metric \u2014 not the background.\n- Bullet-dense, no fluff. Drop hedging, transitions, and restated headings.\n- If the source changes, the summary changes. A summary that no longer matches its\n source is a bug the checker will catch.\n\n**A directory summary (`_SUMMARY.md`) is a MAP, not a digest.**\nGoal: a reader knows what lives in this directory and where to go next.\n\n- A short orientation paragraph (1-3 sentences): what this directory is about.\n- Then one line per direct child \u2014 file **and** sub-directory \u2014 each with a Markdown\n link and a few-word hook describing what's behind it.\n- For a big doc, link and hook its `.summary.md`; for a small doc, link the doc itself.\n- For a sub-directory, link its `_SUMMARY.md`.\n- **Link-completeness:** every direct child must appear as a link. A missing link fails\n `check`. When you add or remove a child, update the parent's `_SUMMARY.md`.\n\n## Why leaves-first \u2014 the Merkle mental model\n\nEach summary's hash is stamped into a hidden sidecar under `.cairn/` (never into the\nsummary's own content \u2014 that's what keeps the docs you write free of tool bytes). A\ndirectory summary's source is a **manifest of its children's hashes**, so a child's\nhash must be settled before its parent can be stamped. Think of it as a Merkle tree:\nchange a leaf and every hash on the path to the root must be recomputed. If you stamp\ntop-down, parents capture stale child hashes and `check` stays red.\n\n## The bottom-up procedure\n\n1. **Author leaves first.** For every doc over the threshold, write/refresh its\n `X.summary.md`. Get the prose right before touching any directory.\n2. **Author directories deepest-first.** Walk from the deepest directories up to the\n roots. For each, write its `_SUMMARY.md`: orientation paragraph, then a linked line\n for every direct child (child `.summary.md` or doc, and each sub-dir's `_SUMMARY.md`).\n3. **Stamp mechanically.** Run `npx cairn check --summaries-only --stamp`.\n It rewrites every `.cairn/` sidecar hash bottom-up. **Never hand-edit a sidecar** \u2014 it\n is computed, not authored; a hand-typed hash is always wrong.\n4. **Verify.** Run `npx cairn check` and confirm exit 0.\n\n## Tiny examples\n\nA **file summary** (`guides/getting-started.summary.md`) \u2014 pure prose, no stamp inside it:\n\n```markdown\n# Getting started \u2014 summary\n\n- Install as a dev dependency, then run the init command.\n- Configure via a single rc file; every option has a sensible default.\n- First run scaffolds an example and prints the next command to run.\n```\n\nIts hash lives in `.cairn/guides/getting-started.summary.md.json` (stamped by the tool):\n\n```json\n{\"sha256\":\"0000...(stamped by the tool)\",\"version\":1}\n```\n\nA **directory summary** (`guides/_SUMMARY.md`) \u2014 also stamp-free:\n\n```markdown\n# Guides\n\nHow-to guides for everyday tasks, in reading order.\n\n- [getting-started](./getting-started.summary.md) \u2014 install, configure, first run\n- [configuration](./configuration.md) \u2014 every rc option, with its default\n- [advanced/](./advanced/_SUMMARY.md) \u2014 recipes for larger setups\n```\n\nKeep summaries short, keep links complete, stamp last, verify green.\n";
3
3
  //# sourceMappingURL=content.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/init/content.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,8tEA2C3B,CAAA;AAED,eAAO,MAAM,UAAU,gnHA6EtB,CAAA"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/init/content.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,kgIAoE3B,CAAA;AAED,eAAO,MAAM,UAAU,i1HAkFtB,CAAA"}
@@ -17,12 +17,29 @@ stale, or a link is broken. Treat green \`check\` as a hard requirement, not a n
17
17
  aggregates its direct docs (each doc's \`.summary.md\` if the doc is big, else the
18
18
  doc itself) plus the \`_SUMMARY.md\` of each direct sub-directory. It links to
19
19
  **every** direct child file and sub-directory (link-completeness).
20
- 3. **Freshness by content hash** — each summary's first line is
21
- \`<!-- source-sha256: <64-hex> -->\`. The checker recomputes the source hash;
22
- mismatch = stale, absent = missing. This survives git clone and CI (mtime does not).
20
+ 3. **Freshness by content hash, tracked OUTSIDE your docs** — each summary's hash is
21
+ recorded in a hidden sidecar under \`.cairn/\`, one JSON file mirroring each summary's
22
+ path (e.g. \`.cairn/docs/a.summary.md.json\`). The checker recomputes the source hash
23
+ and compares it to the sidecar; mismatch = stale, absent = missing. This survives git
24
+ clone and CI (mtime does not), and it means the tracking system leaves **zero bytes**
25
+ in the docs you write — no stamp comment to see, ignore, or accidentally hand-edit.
26
+ Commit \`.cairn/\` alongside your docs; it's not gitignored.
23
27
  4. **Bottom-up in one pass** — a directory summary hashes a manifest of its children's
24
28
  hashes (a Merkle tree), so (re)write leaves-first: file summaries, then directories
25
29
  deepest-first, then stamp.
30
+ 5. **Deletions are caught too** — a sidecar left behind with no matching doc (its source
31
+ was deleted or renamed) is flagged as a deleted-source stamp; \`--prune\` removes both
32
+ the leftover summary and its sidecar.
33
+
34
+ ## Upgrading from an older cairn (legacy \`<!-- source-sha256 -->\` stamp)
35
+
36
+ **Nothing special to do — do not go looking for a migration step.** If a summary still
37
+ carries the old in-content \`<!-- source-sha256: ... -->\` comment, the ordinary stamp
38
+ command (\`npx cairn check --summaries-only --stamp\`) strips it and writes the
39
+ \`.cairn/\` sidecar in the same run, automatically. There is no separate command to
40
+ discover or remember: whatever \`stampCommand\` this repo already runs already does it.
41
+ (\`--migrate-stamps\` also exists, purely as an optional explicit/reportable alias for
42
+ the same self-healing behaviour — never required.)
26
43
 
27
44
  ## Workflow when you edit docs
28
45
 
@@ -32,19 +49,27 @@ When you create or edit any doc:
32
49
  reflect the new content.
33
50
  2. Update the \`_SUMMARY.md\` of every affected directory, walking **up** the tree
34
51
  leaves-first, and keep a link to every child file and sub-directory.
35
- 3. Run the stamp command to (re)write the \`source-sha256\` hashes bottom-up:
52
+ 3. Run the stamp command to (re)write the sidecar hashes under \`.cairn/\` bottom-up:
36
53
  \`npx cairn check --summaries-only --stamp\`.
37
54
  4. Run \`npx cairn check\` and ensure it exits 0 (green) before you finish.
55
+ 5. Commit your doc changes **together with** the \`.cairn/\` sidecar changes — a doc
56
+ edit without its matching sidecar update is exactly what \`check\` is designed to catch.
38
57
 
39
58
  ## Commands
40
59
 
41
60
  - \`npx cairn check\` — check summaries + links (exit 1 on any problem).
42
61
  - \`npx cairn check --summaries-only\` / \`--links-only\`.
43
62
  - \`npx cairn check --links-only --fix\` — auto-repair unambiguous dead links.
44
- - \`npx cairn check --summaries-only --stamp\` — write stamps of EXISTING
45
- summaries bottom-up. It does **not** author prose; you write the content, then stamp.
46
-
47
- You author the prose. The tool only verifies and stamps.
63
+ - \`npx cairn check --summaries-only --stamp\` — write the \`.cairn/\` sidecar hash of
64
+ EXISTING summaries bottom-up. It does **not** author prose; you write the content,
65
+ then stamp.
66
+ - \`npx cairn check --prune\` delete orphan summaries and orphan \`.cairn/\` sidecars
67
+ (source doc deleted, renamed, or below threshold).
68
+ - \`npx cairn check --migrate-stamps\` — optional: the same self-healing \`--stamp\`
69
+ already does for a legacy in-content stamp, as its own named/reported step. Never
70
+ required.
71
+
72
+ You author the prose. The tool only verifies and stamps — and it never touches your prose to do it.
48
73
  `;
49
74
  export const SKILL_BODY = `# Writing good documentation summaries
50
75
 
@@ -78,7 +103,8 @@ Goal: a reader knows what lives in this directory and where to go next.
78
103
 
79
104
  ## Why leaves-first — the Merkle mental model
80
105
 
81
- Each summary is stamped with \`<!-- source-sha256: <hex> -->\` over its source. A
106
+ Each summary's hash is stamped into a hidden sidecar under \`.cairn/\` (never into the
107
+ summary's own content — that's what keeps the docs you write free of tool bytes). A
82
108
  directory summary's source is a **manifest of its children's hashes**, so a child's
83
109
  hash must be settled before its parent can be stamped. Think of it as a Merkle tree:
84
110
  change a leaf and every hash on the path to the root must be recomputed. If you stamp
@@ -92,16 +118,15 @@ top-down, parents capture stale child hashes and \`check\` stays red.
92
118
  roots. For each, write its \`_SUMMARY.md\`: orientation paragraph, then a linked line
93
119
  for every direct child (child \`.summary.md\` or doc, and each sub-dir's \`_SUMMARY.md\`).
94
120
  3. **Stamp mechanically.** Run \`npx cairn check --summaries-only --stamp\`.
95
- It rewrites every \`source-sha256\` bottom-up. **Never hand-edit a sha256** — it is
96
- computed, not authored; a hand-typed hash is always wrong.
121
+ It rewrites every \`.cairn/\` sidecar hash bottom-up. **Never hand-edit a sidecar** — it
122
+ is computed, not authored; a hand-typed hash is always wrong.
97
123
  4. **Verify.** Run \`npx cairn check\` and confirm exit 0.
98
124
 
99
125
  ## Tiny examples
100
126
 
101
- A **file summary** (\`guides/getting-started.summary.md\`):
127
+ A **file summary** (\`guides/getting-started.summary.md\`) — pure prose, no stamp inside it:
102
128
 
103
129
  \`\`\`markdown
104
- <!-- source-sha256: 0000...(stamped by the tool) -->
105
130
  # Getting started — summary
106
131
 
107
132
  - Install as a dev dependency, then run the init command.
@@ -109,10 +134,15 @@ A **file summary** (\`guides/getting-started.summary.md\`):
109
134
  - First run scaffolds an example and prints the next command to run.
110
135
  \`\`\`
111
136
 
112
- A **directory summary** (\`guides/_SUMMARY.md\`):
137
+ Its hash lives in \`.cairn/guides/getting-started.summary.md.json\` (stamped by the tool):
138
+
139
+ \`\`\`json
140
+ {"sha256":"0000...(stamped by the tool)","version":1}
141
+ \`\`\`
142
+
143
+ A **directory summary** (\`guides/_SUMMARY.md\`) — also stamp-free:
113
144
 
114
145
  \`\`\`markdown
115
- <!-- source-sha256: 0000...(stamped by the tool) -->
116
146
  # Guides
117
147
 
118
148
  How-to guides for everyday tasks, in reading order.
@@ -1 +1 @@
1
- {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/init/content.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,oEAAoE;AACpE,4EAA4E;AAC5E,iCAAiC;AAEjC,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C9B,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EzB,CAAA"}
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/init/content.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,oEAAoE;AACpE,4EAA4E;AAC5E,iCAAiC;AAEjC,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoE9B,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkFzB,CAAA"}
@@ -1,4 +1,4 @@
1
- export declare const AGENT_TARGETS: readonly ["agents", "all", "claude", "copilot", "opencode"];
1
+ export declare const AGENT_TARGETS: readonly ['agents', 'all', 'claude', 'copilot', 'opencode'];
2
2
  export type AgentTarget = (typeof AGENT_TARGETS)[number];
3
3
  export interface InitArgs {
4
4
  readonly agent: AgentTarget;
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/init/generate.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,aAAa,6DAA8D,CAAA;AACxF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AA2FD,4EAA4E;AAC5E,eAAO,MAAM,OAAO,GAAI,uBAAuB,QAAQ,KAAG,UA6BzD,CAAA"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/init/generate.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,aAAa,YAAI,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAU,CAAA;AACxF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AA2FD,4EAA4E;AAC5E,eAAO,MAAM,OAAO,0BAA2B,QAAQ,KAAG,UA6BzD,CAAA"}
@@ -12,7 +12,7 @@
12
12
  // Plus a starter .cairnrc.json (only when absent).
13
13
  import * as fs from 'node:fs';
14
14
  import * as path from 'node:path';
15
- import { CONVENTION_BODY, SKILL_BODY } from "./content.js";
15
+ import { CONVENTION_BODY, SKILL_BODY } from './content.js';
16
16
  // Single source of truth for valid `--agent` values, so the CLI's choice list
17
17
  // (src/cli.ts) can never drift from what `runInit` actually understands.
18
18
  export const AGENT_TARGETS = ['agents', 'all', 'claude', 'copilot', 'opencode'];