@sledorze/cairn 0.1.0 → 0.3.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 (117) hide show
  1. package/README.md +69 -18
  2. package/dist/cli.js +69378 -70958
  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 +22 -22
  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/glob.bench.js +1 -1
  12. package/dist/core/glob.d.ts.map +1 -1
  13. package/dist/core/hashing.d.ts +3 -0
  14. package/dist/core/hashing.d.ts.map +1 -0
  15. package/dist/core/hashing.js +16 -0
  16. package/dist/core/hashing.js.map +1 -0
  17. package/dist/core/links/Anchors.d.ts +30 -0
  18. package/dist/core/links/Anchors.d.ts.map +1 -0
  19. package/dist/core/links/Anchors.js +119 -0
  20. package/dist/core/links/Anchors.js.map +1 -0
  21. package/dist/core/links/MarkdownLinks.bench.d.ts.map +1 -0
  22. package/dist/core/{MarkdownLinks.bench.js → links/MarkdownLinks.bench.js} +1 -1
  23. package/dist/core/links/MarkdownLinks.bench.js.map +1 -0
  24. package/dist/core/links/MarkdownLinks.d.ts +121 -0
  25. package/dist/core/links/MarkdownLinks.d.ts.map +1 -0
  26. package/dist/core/links/MarkdownLinks.js +228 -0
  27. package/dist/core/links/MarkdownLinks.js.map +1 -0
  28. package/dist/core/links/RefStore.d.ts +32 -0
  29. package/dist/core/links/RefStore.d.ts.map +1 -0
  30. package/dist/core/links/RefStore.js +60 -0
  31. package/dist/core/links/RefStore.js.map +1 -0
  32. package/dist/core/links/markdownFences.d.ts +10 -0
  33. package/dist/core/links/markdownFences.d.ts.map +1 -0
  34. package/dist/core/links/markdownFences.js +51 -0
  35. package/dist/core/links/markdownFences.js.map +1 -0
  36. package/dist/core/paths.d.ts +8 -0
  37. package/dist/core/paths.d.ts.map +1 -1
  38. package/dist/core/paths.js +13 -0
  39. package/dist/core/paths.js.map +1 -1
  40. package/dist/core/sidecar.d.ts +45 -0
  41. package/dist/core/sidecar.d.ts.map +1 -0
  42. package/dist/core/sidecar.js +83 -0
  43. package/dist/core/sidecar.js.map +1 -0
  44. package/dist/core/{DocSummaries.d.ts → summaries/DocSummaries.d.ts} +13 -3
  45. package/dist/core/summaries/DocSummaries.d.ts.map +1 -0
  46. package/dist/core/{DocSummaries.js → summaries/DocSummaries.js} +31 -11
  47. package/dist/core/summaries/DocSummaries.js.map +1 -0
  48. package/dist/core/summaries/StampStore.d.ts +19 -0
  49. package/dist/core/summaries/StampStore.d.ts.map +1 -0
  50. package/dist/core/summaries/StampStore.js +34 -0
  51. package/dist/core/summaries/StampStore.js.map +1 -0
  52. package/dist/core/summaries/SummaryTree.bench.d.ts.map +1 -0
  53. package/dist/core/{SummaryTree.bench.js → summaries/SummaryTree.bench.js} +24 -14
  54. package/dist/core/summaries/SummaryTree.bench.js.map +1 -0
  55. package/dist/core/{SummaryTree.d.ts → summaries/SummaryTree.d.ts} +10 -1
  56. package/dist/core/summaries/SummaryTree.d.ts.map +1 -0
  57. package/dist/core/{SummaryTree.js → summaries/SummaryTree.js} +35 -9
  58. package/dist/core/summaries/SummaryTree.js.map +1 -0
  59. package/dist/index.d.ts +5 -5
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +10 -10
  62. package/dist/index.js.map +1 -1
  63. package/dist/init/content.d.ts +2 -2
  64. package/dist/init/content.d.ts.map +1 -1
  65. package/dist/init/content.js +45 -15
  66. package/dist/init/content.js.map +1 -1
  67. package/dist/init/generate.d.ts +1 -1
  68. package/dist/init/generate.d.ts.map +1 -1
  69. package/dist/init/generate.js +1 -1
  70. package/dist/io/DocsFs.d.ts +2 -3
  71. package/dist/io/DocsFs.d.ts.map +1 -1
  72. package/dist/io/DocsFs.js +15 -5
  73. package/dist/io/DocsFs.js.map +1 -1
  74. package/dist/program/JsonReport.d.ts +2 -2
  75. package/dist/program/JsonReport.d.ts.map +1 -1
  76. package/dist/program/JsonReport.js +2 -2
  77. package/dist/program/JsonReport.js.map +1 -1
  78. package/dist/program/{CheckLinks.d.ts → links/CheckLinks.d.ts} +9 -4
  79. package/dist/program/links/CheckLinks.d.ts.map +1 -0
  80. package/dist/program/links/CheckLinks.js +243 -0
  81. package/dist/program/links/CheckLinks.js.map +1 -0
  82. package/dist/program/links/CheckRefs.d.ts +47 -0
  83. package/dist/program/links/CheckRefs.d.ts.map +1 -0
  84. package/dist/program/links/CheckRefs.js +151 -0
  85. package/dist/program/links/CheckRefs.js.map +1 -0
  86. package/dist/program/locale.d.ts.map +1 -1
  87. package/dist/program/summaries/CheckSummaries.bench.d.ts +2 -0
  88. package/dist/program/summaries/CheckSummaries.bench.d.ts.map +1 -0
  89. package/dist/program/summaries/CheckSummaries.bench.js +94 -0
  90. package/dist/program/summaries/CheckSummaries.bench.js.map +1 -0
  91. package/dist/program/summaries/CheckSummaries.d.ts +58 -0
  92. package/dist/program/summaries/CheckSummaries.d.ts.map +1 -0
  93. package/dist/program/summaries/CheckSummaries.js +302 -0
  94. package/dist/program/summaries/CheckSummaries.js.map +1 -0
  95. package/package.json +7 -8
  96. package/schema/cairn.schema.json +35 -38
  97. package/dist/core/DocSummaries.d.ts.map +0 -1
  98. package/dist/core/DocSummaries.js.map +0 -1
  99. package/dist/core/MarkdownLinks.bench.d.ts.map +0 -1
  100. package/dist/core/MarkdownLinks.bench.js.map +0 -1
  101. package/dist/core/MarkdownLinks.d.ts +0 -51
  102. package/dist/core/MarkdownLinks.d.ts.map +0 -1
  103. package/dist/core/MarkdownLinks.js +0 -115
  104. package/dist/core/MarkdownLinks.js.map +0 -1
  105. package/dist/core/SummaryTree.bench.d.ts.map +0 -1
  106. package/dist/core/SummaryTree.bench.js.map +0 -1
  107. package/dist/core/SummaryTree.d.ts.map +0 -1
  108. package/dist/core/SummaryTree.js.map +0 -1
  109. package/dist/program/CheckLinks.d.ts.map +0 -1
  110. package/dist/program/CheckLinks.js +0 -122
  111. package/dist/program/CheckLinks.js.map +0 -1
  112. package/dist/program/CheckSummaries.d.ts +0 -38
  113. package/dist/program/CheckSummaries.d.ts.map +0 -1
  114. package/dist/program/CheckSummaries.js +0 -198
  115. package/dist/program/CheckSummaries.js.map +0 -1
  116. /package/dist/core/{MarkdownLinks.bench.d.ts → links/MarkdownLinks.bench.d.ts} +0 -0
  117. /package/dist/core/{SummaryTree.bench.d.ts → summaries/SummaryTree.bench.d.ts} +0 -0
@@ -0,0 +1,47 @@
1
+ import { Effect } from 'effect';
2
+ import { DocsFs } from '../../io/DocsFs.ts';
3
+ import type { Locale } from '../locale.ts';
4
+ export interface CheckRefsArgs {
5
+ readonly base: string;
6
+ readonly roots: readonly string[];
7
+ }
8
+ export interface StaleRef {
9
+ readonly anchor?: string;
10
+ readonly currentHash: string;
11
+ readonly recordedHash: string;
12
+ readonly target: string;
13
+ }
14
+ export interface FileStaleRefs {
15
+ readonly file: string;
16
+ readonly refs: readonly StaleRef[];
17
+ }
18
+ export interface RefsCheckResult {
19
+ readonly checked: number;
20
+ readonly stale: readonly FileStaleRefs[];
21
+ }
22
+ export interface StampRefsResult {
23
+ readonly stamped: number;
24
+ }
25
+ /** 0 when nothing is stale, 1 otherwise — same convention as `linkExitCode`. */
26
+ export declare const refsExitCode: (result: RefsCheckResult) => number;
27
+ /**
28
+ * Record the current content hash of every real reference each scanned doc
29
+ * makes. Overwrites any previously-recorded sidecar unconditionally (same
30
+ * "stamp always writes fresh state" convention as `stampSummaries`) — a doc
31
+ * with no resolvable references gets no sidecar at all (nothing to compare
32
+ * against later, and no reason to create an empty one).
33
+ */
34
+ export declare const stampRefs: ({ base, roots }: CheckRefsArgs) => Effect.Effect<StampRefsResult, never, DocsFs>;
35
+ /**
36
+ * Compare each scanned doc's recorded reference hashes (if any) against
37
+ * current target content, reporting drift. A doc with no refs sidecar
38
+ * (never stamped, or every reference already broken/unrecordable) is
39
+ * silently skipped — nothing recorded, nothing to compare.
40
+ */
41
+ export declare const checkRefs: ({ base, roots }: CheckRefsArgs) => Effect.Effect<RefsCheckResult, never, DocsFs>;
42
+ export interface RefsReportOptions {
43
+ readonly locale?: Locale;
44
+ }
45
+ /** Human-readable report lines (pure, so it can be unit-tested). */
46
+ export declare const formatRefsReport: (result: RefsCheckResult, options?: RefsReportOptions) => string[];
47
+ //# sourceMappingURL=CheckRefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckRefs.d.ts","sourceRoot":"","sources":["../../../src/program/links/CheckRefs.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAQ/B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAK1C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,gFAAgF;AAChF,eAAO,MAAM,YAAY,WAAY,eAAe,KAAG,MAA2C,CAAA;AAyClG;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,oBAAqB,aAAa,KAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAuBnG,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,SAAS,oBAAqB,aAAa,KAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAwCnG,CAAA;AAEJ,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,WAAY,eAAe,YAAW,iBAAiB,KAAQ,MAAM,EA6BjG,CAAA"}
@@ -0,0 +1,151 @@
1
+ // Effect programs for issue #39 Scenario I: record and check reference
2
+ // content hashes. `stampRefs` records the CURRENT hash of every resolvable
3
+ // reference target a doc makes; `checkRefs` compares the CURRENT hash
4
+ // against what was last recorded, surfacing drift as "may be stale" — a
5
+ // distinct signal from `CheckLinks.ts`'s "broken": the link still resolves,
6
+ // its target just isn't what it was when the reference was authored.
7
+ //
8
+ // Deliberately does NOT touch `CheckSummaries.ts`'s stamping machinery — the
9
+ // summary-tree Merkle/manifest hash computation answers a different
10
+ // question ("does this SUMMARY still reflect its SOURCE") with its own
11
+ // careful bottom-up invariants this file has no reason to entangle with.
12
+ // `stampRefs`/`checkRefs` are opt-in (wired behind `cairn check --refs`, not
13
+ // part of the default `checks.links`/`checks.summaries` gate) — v1 of a
14
+ // scenario the issue itself parks as "ships only after A-H are solid."
15
+ import * as nodePath from 'node:path';
16
+ import { Effect } from 'effect';
17
+ import { extractReferences } from '../../core/links/MarkdownLinks.js';
18
+ import { parseRefs, refsSidecarPathFor, serializeRefs } from '../../core/links/RefStore.js';
19
+ import { hashContent } from '../../core/hashing.js';
20
+ import { isWithinBase } from '../../core/paths.js';
21
+ import { metaRootFor } from '../../core/sidecar.js';
22
+ import { DocsFs } from '../../io/DocsFs.js';
23
+ import { pick } from '../locale.js';
24
+ const path = nodePath.posix;
25
+ /** 0 when nothing is stale, 1 otherwise — same convention as `linkExitCode`. */
26
+ export const refsExitCode = (result) => (result.stale.length > 0 ? 1 : 0);
27
+ /**
28
+ * Resolve one reference target to its real, CURRENT content — bounded by
29
+ * `base` exactly like `CheckLinks.ts`'s `resolvePendingCheck` (nothing
30
+ * outside the checkout root is ever stat'd/read). `null` if the target
31
+ * doesn't currently exist or isn't readable (e.g. a directory): a target
32
+ * that no longer resolves is `CheckLinks.ts`'s "broken" concern, not this
33
+ * file's "stale" concern, so it's silently skipped here rather than
34
+ * double-reported.
35
+ */
36
+ const resolveReferenceContent = ({ base, dfs, targetAbs, }) => Effect.gen(function* () {
37
+ if (!isWithinBase(targetAbs, base)) {
38
+ return null;
39
+ }
40
+ const exists = yield* dfs.exists(targetAbs);
41
+ if (!exists) {
42
+ return null;
43
+ }
44
+ return yield* dfs.readFile(targetAbs).pipe(Effect.catchDefect(() => Effect.succeed(null)));
45
+ });
46
+ const listMdFiles = (roots) => Effect.gen(function* () {
47
+ const dfs = yield* DocsFs;
48
+ const allFiles = yield* dfs.listFiles(roots);
49
+ return allFiles.filter((f) => f.endsWith('.md'));
50
+ });
51
+ const toRecord = (ref, hash) => ref.anchor === null ? { hash, target: ref.target } : { anchor: ref.anchor, hash, target: ref.target };
52
+ /**
53
+ * Record the current content hash of every real reference each scanned doc
54
+ * makes. Overwrites any previously-recorded sidecar unconditionally (same
55
+ * "stamp always writes fresh state" convention as `stampSummaries`) — a doc
56
+ * with no resolvable references gets no sidecar at all (nothing to compare
57
+ * against later, and no reason to create an empty one).
58
+ */
59
+ export const stampRefs = ({ base, roots }) => Effect.gen(function* () {
60
+ const dfs = yield* DocsFs;
61
+ const layout = { base, metaRoot: metaRootFor(base) };
62
+ const mdFiles = yield* listMdFiles(roots);
63
+ let stamped = 0;
64
+ for (const file of mdFiles) {
65
+ const content = yield* dfs.readFile(file);
66
+ const fromDir = path.dirname(file);
67
+ const records = [];
68
+ for (const ref of extractReferences(content)) {
69
+ const targetAbs = path.resolve(fromDir, ref.target);
70
+ const targetContent = yield* resolveReferenceContent({ base, dfs, targetAbs });
71
+ if (targetContent !== null) {
72
+ records.push(toRecord(ref, hashContent(targetContent)));
73
+ }
74
+ }
75
+ if (records.length > 0) {
76
+ yield* dfs.writeFile(refsSidecarPathFor(file, layout), serializeRefs({ refs: records }));
77
+ stamped += 1;
78
+ }
79
+ }
80
+ return { stamped };
81
+ });
82
+ /**
83
+ * Compare each scanned doc's recorded reference hashes (if any) against
84
+ * current target content, reporting drift. A doc with no refs sidecar
85
+ * (never stamped, or every reference already broken/unrecordable) is
86
+ * silently skipped — nothing recorded, nothing to compare.
87
+ */
88
+ export const checkRefs = ({ base, roots }) => Effect.gen(function* () {
89
+ const dfs = yield* DocsFs;
90
+ const layout = { base, metaRoot: metaRootFor(base) };
91
+ const mdFiles = yield* listMdFiles(roots);
92
+ const stale = [];
93
+ let checked = 0;
94
+ for (const file of mdFiles) {
95
+ const sidecarPath = refsSidecarPathFor(file, layout);
96
+ const sidecarExists = yield* dfs.exists(sidecarPath);
97
+ if (!sidecarExists) {
98
+ continue;
99
+ }
100
+ const recorded = parseRefs(yield* dfs.readFile(sidecarPath));
101
+ if (recorded === null) {
102
+ continue;
103
+ }
104
+ checked += 1;
105
+ const fromDir = path.dirname(file);
106
+ const drifted = [];
107
+ for (const record of recorded.refs) {
108
+ const targetAbs = path.resolve(fromDir, record.target);
109
+ const targetContent = yield* resolveReferenceContent({ base, dfs, targetAbs });
110
+ if (targetContent === null) {
111
+ continue;
112
+ }
113
+ const currentHash = hashContent(targetContent);
114
+ if (currentHash !== record.hash) {
115
+ drifted.push(record.anchor === undefined
116
+ ? { currentHash, recordedHash: record.hash, target: record.target }
117
+ : { anchor: record.anchor, currentHash, recordedHash: record.hash, target: record.target });
118
+ }
119
+ }
120
+ if (drifted.length > 0) {
121
+ stale.push({ file, refs: drifted });
122
+ }
123
+ }
124
+ return { checked, stale };
125
+ });
126
+ /** Human-readable report lines (pure, so it can be unit-tested). */
127
+ export const formatRefsReport = (result, options = {}) => {
128
+ const locale = options.locale ?? 'en';
129
+ const lines = [];
130
+ if (result.stale.length === 0) {
131
+ lines.push(pick(locale, {
132
+ en: `✅ References OK (${result.checked} tracked doc(s)).`,
133
+ fr: `✅ Références OK (${result.checked} document(s) suivi(s)).`,
134
+ }));
135
+ return lines;
136
+ }
137
+ const total = result.stale.reduce((n, f) => n + f.refs.length, 0);
138
+ lines.push(pick(locale, {
139
+ en: `⚠️ ${total} possibly stale reference(s):`,
140
+ fr: `⚠️ ${total} référence(s) possiblement obsolète(s) :`,
141
+ }));
142
+ for (const { file, refs } of result.stale) {
143
+ lines.push(` ${file}`);
144
+ for (const ref of refs) {
145
+ const anchorSuffix = ref.anchor !== undefined ? `#${ref.anchor}` : '';
146
+ lines.push(` ~ ${ref.target}${anchorSuffix} (${ref.recordedHash.slice(0, 8)} → ${ref.currentHash.slice(0, 8)})`);
147
+ }
148
+ }
149
+ return lines;
150
+ };
151
+ //# sourceMappingURL=CheckRefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckRefs.js","sourceRoot":"","sources":["../../../src/program/links/CheckRefs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/program/locale.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,6DAA6D;AAC7D,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,QAAQ,MAAM,EAAE,QAAQ;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;CAAE,KAAG,CAAmB,CAAA;AAExG,mGAAmG;AACnG,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;CAAgC,CAAA"}
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/program/locale.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,6DAA6D;AAC7D,eAAO,MAAM,IAAI,GAAI,CAAC,UAAU,MAAM,UAAU;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;CAAE,KAAG,CAAmB,CAAA;AAExG,mGAAmG;AACnG,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,CAAC,KAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;CAAgC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CheckSummaries.bench.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckSummaries.bench.d.ts","sourceRoot":"","sources":["../../../src/program/summaries/CheckSummaries.bench.ts"],"names":[],"mappings":""}
@@ -0,0 +1,94 @@
1
+ // Measures the actual new I/O cost the sidecar move introduces: `checkSummaries`
2
+ // now does an extra `dfs.listFiles([metaRoot])` + one `readFile` per sidecar
3
+ // (`readStamps`), on top of the markdown read `planSummaries()`'s own bench
4
+ // (`SummaryTree.bench.ts`) already covers. This is the realistic end-to-end path
5
+ // (`cairn check`), not just the pure planner, so it's the number that matters for
6
+ // "does the sidecar move keep things fast."
7
+ import { Effect } from 'effect';
8
+ import { bench, describe } from 'vitest';
9
+ import { hashContent } from '../../core/hashing.js';
10
+ import { isSummaryFile, summaryPathFor } from '../../core/summaries/DocSummaries.js';
11
+ import { DIR_SUMMARY, isDirSummary } from '../../core/summaries/SummaryTree.js';
12
+ import { serializeStamp, STAMP_VERSION } from '../../core/summaries/StampStore.js';
13
+ import { isSidecarPath, metaRootFor, sidecarPathFor } from '../../core/sidecar.js';
14
+ import { makeTestDocsFs } from '../../io/DocsFs.js';
15
+ import { checkSummaries } from './CheckSummaries.js';
16
+ const bigContent = (seed) => Array.from({ length: 40 }, (_, i) => `${seed} body line ${i} with some representative prose content`).join('\n');
17
+ const smallContent = (seed) => `${seed} short note`;
18
+ const tf = (content) => ({ content, mtimeMs: 0 });
19
+ /** A fully link-complete, fully sidecar-stamped tree, as `makeTestDocsFs` fixture
20
+ * data — the "steady state" `cairn check` sees on a clean repo. */
21
+ const buildFreshFixture = (base, { depth, dirsPerLevel, filesPerDir, root }) => {
22
+ const files = {};
23
+ const layout = { base, metaRoot: metaRootFor(base) };
24
+ const visit = (dir, level) => {
25
+ const docTargets = [];
26
+ const inputs = [];
27
+ for (let f = 0; f < filesPerDir; f++) {
28
+ const docPath = `${dir}/doc-${f}.md`;
29
+ const big = f % 3 !== 0;
30
+ const content = big ? bigContent(docPath) : smallContent(docPath);
31
+ files[docPath] = tf(content);
32
+ docTargets.push(docPath);
33
+ if (big) {
34
+ const sp = summaryPathFor(docPath);
35
+ files[sp] = tf(`# summary\n\nSee [source](./${docPath.slice(dir.length + 1)}).`);
36
+ files[sidecarPathFor(sp, layout)] = tf(serializeStamp({ sha256: hashContent(content), version: STAMP_VERSION }));
37
+ inputs.push(sp);
38
+ }
39
+ else {
40
+ inputs.push(docPath);
41
+ }
42
+ }
43
+ const dirTargets = [];
44
+ if (level < depth) {
45
+ for (let d = 0; d < dirsPerLevel; d++) {
46
+ const sub = `${dir}/sub-${d}`;
47
+ visit(sub, level + 1);
48
+ dirTargets.push(sub);
49
+ inputs.push(`${sub}/${DIR_SUMMARY}`);
50
+ }
51
+ }
52
+ const manifest = inputs
53
+ .map((input) => `${input.slice(dir.length + 1)}:${hashContent(files[input]?.content ?? '')}`)
54
+ .toSorted()
55
+ .join('\n');
56
+ const links = [...docTargets, ...dirTargets].map((t) => `- [link](${t.slice(dir.length + 1)})`).join('\n');
57
+ const dsp = `${dir}/${DIR_SUMMARY}`;
58
+ files[dsp] = tf(links);
59
+ files[sidecarPathFor(dsp, layout)] = tf(serializeStamp({ sha256: hashContent(manifest), version: STAMP_VERSION }));
60
+ };
61
+ visit(root, 0);
62
+ return files;
63
+ };
64
+ /** Same source docs, no summaries and no `.cairn/**` sidecars anywhere yet —
65
+ * the "first run" worst case. */
66
+ const sourceOnly = (files, metaRoot) => Object.fromEntries(Object.entries(files).filter(([p]) => !isSummaryFile(p) && !isDirSummary(p) && !isSidecarPath(p, metaRoot)));
67
+ const BASE = '/repo';
68
+ const SMALL = { depth: 1, dirsPerLevel: 9, filesPerDir: 10, root: '/repo/docs' };
69
+ const LARGE = { depth: 4, dirsPerLevel: 3, filesPerDir: 16, root: '/repo/docs' };
70
+ const metaRoot = metaRootFor(BASE);
71
+ const smallFresh = buildFreshFixture(BASE, SMALL);
72
+ const smallRaw = sourceOnly(smallFresh, metaRoot);
73
+ const largeFresh = buildFreshFixture(BASE, LARGE);
74
+ const largeRaw = sourceOnly(largeFresh, metaRoot);
75
+ const run = (files, roots) => {
76
+ const program = checkSummaries({ base: BASE, roots, thresholdLines: 30 });
77
+ const layer = makeTestDocsFs(files);
78
+ return Effect.runPromise(program.pipe(Effect.provide(layer)));
79
+ };
80
+ describe('checkSummaries() (real end-to-end path, sidecar I/O included)', () => {
81
+ bench('~100 files, first run (no summaries, no .cairn/**)', async () => {
82
+ await run(smallRaw, [SMALL.root]);
83
+ });
84
+ bench('~100 files, steady state (fully stamped, sidecars read from .cairn/**)', async () => {
85
+ await run(smallFresh, [SMALL.root]);
86
+ });
87
+ bench('~2000 files, first run (no summaries, no .cairn/**)', async () => {
88
+ await run(largeRaw, [LARGE.root]);
89
+ });
90
+ bench('~2000 files, steady state (fully stamped, sidecars read from .cairn/**)', async () => {
91
+ await run(largeFresh, [LARGE.root]);
92
+ });
93
+ });
94
+ //# sourceMappingURL=CheckSummaries.bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckSummaries.bench.js","sourceRoot":"","sources":["../../../src/program/summaries/CheckSummaries.bench.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { Effect } from 'effect';
2
+ import type { Naming } from '../../core/summaries/DocSummaries.ts';
3
+ import type { PlanNode, SummaryPlan } from '../../core/summaries/SummaryTree.ts';
4
+ import { DocsFs } from '../../io/DocsFs.ts';
5
+ import type { Locale } from '../locale.ts';
6
+ export { DEFAULT_STAMP_COMMAND } from '../../core/Config.ts';
7
+ export interface CheckSummariesArgs {
8
+ /** Project root every root/node path and every `.cairn/**` sidecar is
9
+ * resolved under (see StampStore.ts's `MetaLayout`). Real usage: `process.cwd()`. */
10
+ readonly base: string;
11
+ readonly ignore?: readonly string[];
12
+ readonly naming?: Naming;
13
+ readonly requireDirSummaries?: boolean;
14
+ readonly roots: readonly string[];
15
+ readonly thresholdLines?: number;
16
+ }
17
+ export interface SummaryReportOptions {
18
+ readonly locale?: Locale;
19
+ readonly stampCommand?: string;
20
+ }
21
+ export interface StampResult {
22
+ /** Legacy in-content `<!-- source-sha256 -->` stamps stripped along the way —
23
+ * an ordinary `--stamp` run (the one every existing `.cairnrc.json`'s
24
+ * `stampCommand` already points to) self-heals a repo upgrading off the old
25
+ * scheme with ZERO new command to discover; this count is only surfaced so
26
+ * that self-healing is visible, not silent-and-unverifiable. */
27
+ readonly migrated: number;
28
+ readonly missing: readonly PlanNode[];
29
+ readonly stamped: number;
30
+ }
31
+ /** Alias kept for the explicit, nameable one-shot migration entry point
32
+ * (`--migrate-stamps`) — identical shape to `StampResult` now that stripping
33
+ * is unconditional in `stampFiles`, but naming it distinctly documents intent
34
+ * at the call site (`cli.ts`) and in reports. */
35
+ export type MigrateResult = StampResult;
36
+ /** 0 when nothing is missing/stale, no orphan summaries, and no deleted-source
37
+ * stamps remain, 1 otherwise. */
38
+ export declare const summaryExitCode: (plan: SummaryPlan) => number;
39
+ /** Report lines: methodology + the bottom-up update order, for a one-pass fix. */
40
+ export declare const formatSummaryReport: (plan: SummaryPlan, options?: SummaryReportOptions) => string[];
41
+ export declare const checkSummaries: (args: CheckSummariesArgs) => Effect.Effect<SummaryPlan, never, DocsFs>;
42
+ /** `--explain`: why each todo node is not ok (see `explainPlan` for what this can and cannot show). */
43
+ export declare const explainSummaries: (args: CheckSummariesArgs, options?: SummaryReportOptions) => Effect.Effect<string[], never, DocsFs>;
44
+ export declare const stampSummaries: (args: CheckSummariesArgs) => Effect.Effect<StampResult, never, DocsFs>;
45
+ /**
46
+ * Explicit, nameable one-shot entry point (`--migrate-stamps`) for the SAME
47
+ * self-healing `stampFiles` already does unconditionally on every `--stamp` —
48
+ * kept for anyone who wants to run/report the cleanup as its own step, not
49
+ * because plain `--stamp` needs it to be correct.
50
+ */
51
+ export declare const migrateStamps: (args: CheckSummariesArgs) => Effect.Effect<MigrateResult, never, DocsFs>;
52
+ /** Delete every orphan summary file (source doc gone) AND every orphan
53
+ * `.cairn/**` sidecar (deleted-source stamp — see `SummaryPlan.orphanStamps`),
54
+ * reporting the total count removed. */
55
+ export declare const pruneOrphans: (args: CheckSummariesArgs) => Effect.Effect<number, never, DocsFs>;
56
+ export { isSummaryFile } from '../../core/summaries/DocSummaries.ts';
57
+ export { isDirSummary } from '../../core/summaries/SummaryTree.ts';
58
+ //# sourceMappingURL=CheckSummaries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckSummaries.d.ts","sourceRoot":"","sources":["../../../src/program/summaries/CheckSummaries.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAA;AAGlE,OAAO,KAAK,EAAY,QAAQ,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAI1F,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,MAAM,WAAW,kBAAkB;IACjC;yFACqF;IACrF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,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,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B;;;;oEAIgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;iDAGiD;AACjD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAA;AA8DvC;iCACiC;AACjC,eAAO,MAAM,eAAe,SAAU,WAAW,KAAG,MACqC,CAAA;AAEzF,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,SAAU,WAAW,YAAW,oBAAoB,KAAQ,MAAM,EAwFjG,CAAA;AAoDD,eAAO,MAAM,cAAc,SAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAK9F,CAAA;AAEJ,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,SACrB,kBAAkB,YACf,oBAAoB,KAC5B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAMpC,CAAA;AAwEJ,eAAO,MAAM,cAAc,SAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAI9F,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,aAAa,SAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,MAAM,CAI/F,CAAA;AAEJ;;wCAEwC;AACxC,eAAO,MAAM,YAAY,SAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAcvF,CAAA;AAGJ,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA"}