@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.
- package/README.md +33 -18
- package/dist/cli.js +68527 -70592
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -10
- package/dist/config.js.map +1 -1
- package/dist/core/Config.d.ts +21 -21
- package/dist/core/Config.d.ts.map +1 -1
- package/dist/core/Config.js +33 -33
- package/dist/core/Config.js.map +1 -1
- package/dist/core/DocSummaries.d.ts +13 -1
- package/dist/core/DocSummaries.d.ts.map +1 -1
- package/dist/core/DocSummaries.js +25 -3
- package/dist/core/DocSummaries.js.map +1 -1
- package/dist/core/MarkdownLinks.bench.js +1 -1
- package/dist/core/MarkdownLinks.d.ts.map +1 -1
- package/dist/core/StampStore.d.ts +47 -0
- package/dist/core/StampStore.d.ts.map +1 -0
- package/dist/core/StampStore.js +90 -0
- package/dist/core/StampStore.js.map +1 -0
- package/dist/core/SummaryTree.bench.js +23 -14
- package/dist/core/SummaryTree.bench.js.map +1 -1
- package/dist/core/SummaryTree.d.ts +10 -1
- package/dist/core/SummaryTree.d.ts.map +1 -1
- package/dist/core/SummaryTree.js +34 -9
- package/dist/core/SummaryTree.js.map +1 -1
- package/dist/core/glob.bench.js +1 -1
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/index.js +10 -10
- package/dist/init/content.d.ts +2 -2
- package/dist/init/content.d.ts.map +1 -1
- package/dist/init/content.js +45 -15
- package/dist/init/content.js.map +1 -1
- package/dist/init/generate.d.ts +1 -1
- package/dist/init/generate.d.ts.map +1 -1
- package/dist/init/generate.js +1 -1
- package/dist/io/DocsFs.d.ts +2 -3
- package/dist/io/DocsFs.d.ts.map +1 -1
- package/dist/io/DocsFs.js +15 -5
- package/dist/io/DocsFs.js.map +1 -1
- package/dist/program/CheckLinks.d.ts.map +1 -1
- package/dist/program/CheckLinks.js +4 -4
- package/dist/program/CheckLinks.js.map +1 -1
- package/dist/program/CheckSummaries.bench.d.ts +2 -0
- package/dist/program/CheckSummaries.bench.d.ts.map +1 -0
- package/dist/program/CheckSummaries.bench.js +92 -0
- package/dist/program/CheckSummaries.bench.js.map +1 -0
- package/dist/program/CheckSummaries.d.ts +25 -5
- package/dist/program/CheckSummaries.d.ts.map +1 -1
- package/dist/program/CheckSummaries.js +143 -40
- package/dist/program/CheckSummaries.js.map +1 -1
- package/dist/program/JsonReport.d.ts.map +1 -1
- package/dist/program/JsonReport.js +2 -2
- package/dist/program/locale.d.ts.map +1 -1
- package/package.json +6 -8
- package/schema/cairn.schema.json +35 -38
package/dist/io/DocsFs.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { FileSystem, Path } from '
|
|
2
|
-
import { Context, Effect, Layer } from 'effect';
|
|
1
|
+
import { Context, Effect, FileSystem, Layer, Path } from 'effect';
|
|
3
2
|
export interface FileStat {
|
|
4
3
|
readonly mtimeMs: number;
|
|
5
4
|
readonly sizeBytes: number;
|
|
@@ -12,7 +11,7 @@ export interface DocsFsService {
|
|
|
12
11
|
readonly stat: (abs: string) => Effect.Effect<FileStat>;
|
|
13
12
|
readonly writeFile: (abs: string, content: string) => Effect.Effect<void>;
|
|
14
13
|
}
|
|
15
|
-
declare const DocsFs_base: Context.
|
|
14
|
+
declare const DocsFs_base: Context.ServiceClass<DocsFs, "DocsFs", DocsFsService>;
|
|
16
15
|
export declare class DocsFs extends DocsFs_base {
|
|
17
16
|
}
|
|
18
17
|
/** Live implementation bound to the Node filesystem. */
|
package/dist/io/DocsFs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocsFs.d.ts","sourceRoot":"","sources":["../../src/io/DocsFs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"DocsFs.d.ts","sourceRoot":"","sources":["../../src/io/DocsFs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAU,IAAI,EAAE,MAAM,QAAQ,CAAA;AAIzE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACzD,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACxD,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAClF,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACzD,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACvD,QAAQ,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;CAC1E;;AAED,qBAAa,MAAO,SAAQ,WAAkD;CAAG;AAEjF,wDAAwD;AACxD,eAAO,MAAM,UAAU,+DAwEtB,CAAA;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,UAAW,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CA2ClF,CAAA"}
|
package/dist/io/DocsFs.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Filesystem capability for the docs checkers, expressed as an Effect service
|
|
2
2
|
// so programs stay testable. `DocsFsLive` binds it to the real Node platform
|
|
3
3
|
// (via @effect/platform-node); `makeTestDocsFs` provides an in-memory layer.
|
|
4
|
-
import { FileSystem, Path } from '
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export class DocsFs extends Context.Tag('DocsFs')() {
|
|
4
|
+
import { Context, Effect, FileSystem, Layer, Option, Path } from 'effect';
|
|
5
|
+
import { toPosix } from '../core/paths.js';
|
|
6
|
+
export class DocsFs extends Context.Service()('DocsFs') {
|
|
8
7
|
}
|
|
9
8
|
/** Live implementation bound to the Node filesystem. */
|
|
10
9
|
export const DocsFsLive = Layer.effect(DocsFs, Effect.gen(function* () {
|
|
@@ -42,13 +41,24 @@ export const DocsFsLive = Layer.effect(DocsFs, Effect.gen(function* () {
|
|
|
42
41
|
mtimeMs: Option.match(info.mtime, { onNone: () => 0, onSome: (d) => d.getTime() }),
|
|
43
42
|
sizeBytes: Number(info.size),
|
|
44
43
|
})), Effect.orDie);
|
|
44
|
+
// Every existing caller wrote into a directory that was already there (a doc's
|
|
45
|
+
// own directory, always present since the doc itself lives in it). That
|
|
46
|
+
// invariant broke the moment sidecar writes started targeting a brand-new
|
|
47
|
+
// `.cairn/**` tree (StampStore.ts / CheckSummaries.ts) — the FIRST sidecar
|
|
48
|
+
// under a given directory has no directory to write into yet. `recursive:
|
|
49
|
+
// true` makes this a no-op when the directory already exists, so it's safe
|
|
50
|
+
// to do unconditionally rather than only for `.cairn/**` paths.
|
|
51
|
+
const writeFile = (abs, content) => Effect.gen(function* () {
|
|
52
|
+
yield* fs.makeDirectory(path.dirname(abs), { recursive: true });
|
|
53
|
+
yield* fs.writeFileString(abs, content);
|
|
54
|
+
}).pipe(Effect.orDie);
|
|
45
55
|
return {
|
|
46
56
|
deleteFile: (abs) => fs.remove(abs).pipe(Effect.orDie),
|
|
47
57
|
exists: (abs) => fs.exists(abs).pipe(Effect.orDie),
|
|
48
58
|
listFiles,
|
|
49
59
|
readFile: (abs) => fs.readFileString(abs).pipe(Effect.orDie),
|
|
50
60
|
stat,
|
|
51
|
-
writeFile
|
|
61
|
+
writeFile,
|
|
52
62
|
};
|
|
53
63
|
}));
|
|
54
64
|
/**
|
package/dist/io/DocsFs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocsFs.js","sourceRoot":"","sources":["../../src/io/DocsFs.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAE7E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"DocsFs.js","sourceRoot":"","sources":["../../src/io/DocsFs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckLinks.d.ts","sourceRoot":"","sources":["../../src/program/CheckLinks.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAMzC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AA+CD,kDAAkD;AAClD,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"CheckLinks.d.ts","sourceRoot":"","sources":["../../src/program/CheckLinks.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAMzC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AA+CD,kDAAkD;AAClD,eAAO,MAAM,YAAY,WAAY,eAAe,KAAG,MAA4C,CAAA;AAEnG,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,WAAY,eAAe,YAAW,iBAAiB,KAAQ,MAAM,EA8BjG,CAAA;AAED,eAAO,MAAM,UAAU,4BAIpB,cAAc,KAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CA2C5D,CAAA"}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
// ../core/MarkdownLinks.ts; filesystem access goes through the DocsFs service.
|
|
4
4
|
import * as nodePath from 'node:path';
|
|
5
5
|
import { Effect } from 'effect';
|
|
6
|
-
import { matchesAny } from
|
|
7
|
-
import { buildBasenameIndex, checkContent, stripCode } from
|
|
8
|
-
import { DocsFs } from
|
|
9
|
-
import { pick } from
|
|
6
|
+
import { matchesAny } from '../core/glob.js';
|
|
7
|
+
import { buildBasenameIndex, checkContent, stripCode } from '../core/MarkdownLinks.js';
|
|
8
|
+
import { DocsFs } from '../io/DocsFs.js';
|
|
9
|
+
import { pick } from './locale.js';
|
|
10
10
|
// POSIX path semantics (inputs are normalised to `/` at the IO boundary).
|
|
11
11
|
const path = nodePath.posix;
|
|
12
12
|
const withAncestors = (files) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckLinks.js","sourceRoot":"","sources":["../../src/program/CheckLinks.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,+EAA+E;AAE/E,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAA;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACtF,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElC,0EAA0E;AAC1E,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAA;AAuB3B,MAAM,aAAa,GAAG,CAAC,KAAwB,EAAe,EAAE;IAC9D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAS,KAAK,CAAC,CAAA;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACZ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAK;YACP,CAAC;YACD,GAAG,GAAG,MAAM,CAAA;QACd,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,wCAAwC;AACxC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AAEnH;;;;GAIG;AACH,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,MAAc,EAAE,UAAkB,EAAyC,EAAE;IAC9G,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,IAAI,GAAG,OAAO,CAAA;IAClB,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI;QACvB,CAAC,KAAK,MAAM,GAAG,EAAE,KAAK,UAAU,GAAG,CAAC;QACpC,CAAC,MAAM,MAAM,EAAE,EAAE,MAAM,UAAU,EAAE,CAAC;KAC5B,EAAE,CAAC;QACX,IAAI,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,SAAQ;QACV,CAAC;QACD,uEAAuE;QACvE,IAAI,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;YACvE,SAAQ;QACV,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChC,OAAO,GAAG,IAAI,CAAA;IAChB,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AACnC,CAAC,CAAA;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAuB,EAAU,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAEnG,oEAAoE;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"CheckLinks.js","sourceRoot":"","sources":["../../src/program/CheckLinks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckSummaries.bench.d.ts","sourceRoot":"","sources":["../../src/program/CheckSummaries.bench.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
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, isSummaryFile, summaryPathFor } from '../core/DocSummaries.js';
|
|
10
|
+
import { DIR_SUMMARY, isDirSummary } from '../core/SummaryTree.js';
|
|
11
|
+
import { isSidecarPath, metaRootFor, serializeStamp, sidecarPathFor, STAMP_VERSION } from '../core/StampStore.js';
|
|
12
|
+
import { makeTestDocsFs } from '../io/DocsFs.js';
|
|
13
|
+
import { checkSummaries } from './CheckSummaries.js';
|
|
14
|
+
const bigContent = (seed) => Array.from({ length: 40 }, (_, i) => `${seed} body line ${i} with some representative prose content`).join('\n');
|
|
15
|
+
const smallContent = (seed) => `${seed} short note`;
|
|
16
|
+
const tf = (content) => ({ content, mtimeMs: 0 });
|
|
17
|
+
/** A fully link-complete, fully sidecar-stamped tree, as `makeTestDocsFs` fixture
|
|
18
|
+
* data — the "steady state" `cairn check` sees on a clean repo. */
|
|
19
|
+
const buildFreshFixture = (base, { depth, dirsPerLevel, filesPerDir, root }) => {
|
|
20
|
+
const files = {};
|
|
21
|
+
const layout = { base, metaRoot: metaRootFor(base) };
|
|
22
|
+
const visit = (dir, level) => {
|
|
23
|
+
const docTargets = [];
|
|
24
|
+
const inputs = [];
|
|
25
|
+
for (let f = 0; f < filesPerDir; f++) {
|
|
26
|
+
const docPath = `${dir}/doc-${f}.md`;
|
|
27
|
+
const big = f % 3 !== 0;
|
|
28
|
+
const content = big ? bigContent(docPath) : smallContent(docPath);
|
|
29
|
+
files[docPath] = tf(content);
|
|
30
|
+
docTargets.push(docPath);
|
|
31
|
+
if (big) {
|
|
32
|
+
const sp = summaryPathFor(docPath);
|
|
33
|
+
files[sp] = tf(`# summary\n\nSee [source](./${docPath.slice(dir.length + 1)}).`);
|
|
34
|
+
files[sidecarPathFor(sp, layout)] = tf(serializeStamp({ sha256: hashContent(content), version: STAMP_VERSION }));
|
|
35
|
+
inputs.push(sp);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
inputs.push(docPath);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const dirTargets = [];
|
|
42
|
+
if (level < depth) {
|
|
43
|
+
for (let d = 0; d < dirsPerLevel; d++) {
|
|
44
|
+
const sub = `${dir}/sub-${d}`;
|
|
45
|
+
visit(sub, level + 1);
|
|
46
|
+
dirTargets.push(sub);
|
|
47
|
+
inputs.push(`${sub}/${DIR_SUMMARY}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const manifest = inputs
|
|
51
|
+
.map((input) => `${input.slice(dir.length + 1)}:${hashContent(files[input]?.content ?? '')}`)
|
|
52
|
+
.toSorted()
|
|
53
|
+
.join('\n');
|
|
54
|
+
const links = [...docTargets, ...dirTargets].map((t) => `- [link](${t.slice(dir.length + 1)})`).join('\n');
|
|
55
|
+
const dsp = `${dir}/${DIR_SUMMARY}`;
|
|
56
|
+
files[dsp] = tf(links);
|
|
57
|
+
files[sidecarPathFor(dsp, layout)] = tf(serializeStamp({ sha256: hashContent(manifest), version: STAMP_VERSION }));
|
|
58
|
+
};
|
|
59
|
+
visit(root, 0);
|
|
60
|
+
return files;
|
|
61
|
+
};
|
|
62
|
+
/** Same source docs, no summaries and no `.cairn/**` sidecars anywhere yet —
|
|
63
|
+
* the "first run" worst case. */
|
|
64
|
+
const sourceOnly = (files, metaRoot) => Object.fromEntries(Object.entries(files).filter(([p]) => !isSummaryFile(p) && !isDirSummary(p) && !isSidecarPath(p, metaRoot)));
|
|
65
|
+
const BASE = '/repo';
|
|
66
|
+
const SMALL = { depth: 1, dirsPerLevel: 9, filesPerDir: 10, root: '/repo/docs' };
|
|
67
|
+
const LARGE = { depth: 4, dirsPerLevel: 3, filesPerDir: 16, root: '/repo/docs' };
|
|
68
|
+
const metaRoot = metaRootFor(BASE);
|
|
69
|
+
const smallFresh = buildFreshFixture(BASE, SMALL);
|
|
70
|
+
const smallRaw = sourceOnly(smallFresh, metaRoot);
|
|
71
|
+
const largeFresh = buildFreshFixture(BASE, LARGE);
|
|
72
|
+
const largeRaw = sourceOnly(largeFresh, metaRoot);
|
|
73
|
+
const run = (files, roots) => {
|
|
74
|
+
const program = checkSummaries({ base: BASE, roots, thresholdLines: 30 });
|
|
75
|
+
const layer = makeTestDocsFs(files);
|
|
76
|
+
return Effect.runPromise(program.pipe(Effect.provide(layer)));
|
|
77
|
+
};
|
|
78
|
+
describe('checkSummaries() (real end-to-end path, sidecar I/O included)', () => {
|
|
79
|
+
bench('~100 files, first run (no summaries, no .cairn/**)', async () => {
|
|
80
|
+
await run(smallRaw, [SMALL.root]);
|
|
81
|
+
});
|
|
82
|
+
bench('~100 files, steady state (fully stamped, sidecars read from .cairn/**)', async () => {
|
|
83
|
+
await run(smallFresh, [SMALL.root]);
|
|
84
|
+
});
|
|
85
|
+
bench('~2000 files, first run (no summaries, no .cairn/**)', async () => {
|
|
86
|
+
await run(largeRaw, [LARGE.root]);
|
|
87
|
+
});
|
|
88
|
+
bench('~2000 files, steady state (fully stamped, sidecars read from .cairn/**)', async () => {
|
|
89
|
+
await run(largeFresh, [LARGE.root]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=CheckSummaries.bench.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckSummaries.bench.js","sourceRoot":"","sources":["../../src/program/CheckSummaries.bench.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,9 @@ import { DocsFs } from '../io/DocsFs.ts';
|
|
|
5
5
|
import type { Locale } from './locale.ts';
|
|
6
6
|
export { DEFAULT_STAMP_COMMAND } from '../core/Config.ts';
|
|
7
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;
|
|
8
11
|
readonly ignore?: readonly string[];
|
|
9
12
|
readonly naming?: Naming;
|
|
10
13
|
readonly requireDirSummaries?: boolean;
|
|
@@ -16,22 +19,39 @@ export interface SummaryReportOptions {
|
|
|
16
19
|
readonly stampCommand?: string;
|
|
17
20
|
}
|
|
18
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;
|
|
19
28
|
readonly missing: readonly PlanNode[];
|
|
20
29
|
readonly stamped: number;
|
|
21
30
|
}
|
|
22
|
-
/**
|
|
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. */
|
|
23
38
|
export declare const summaryExitCode: (plan: SummaryPlan) => number;
|
|
24
39
|
/** Report lines: methodology + the bottom-up update order, for a one-pass fix. */
|
|
25
40
|
export declare const formatSummaryReport: (plan: SummaryPlan, options?: SummaryReportOptions) => string[];
|
|
26
41
|
export declare const checkSummaries: (args: CheckSummariesArgs) => Effect.Effect<SummaryPlan, never, DocsFs>;
|
|
27
42
|
/** `--explain`: why each todo node is not ok (see `explainPlan` for what this can and cannot show). */
|
|
28
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>;
|
|
29
45
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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.
|
|
32
50
|
*/
|
|
33
|
-
export declare const
|
|
34
|
-
/** Delete every orphan summary (source doc gone)
|
|
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. */
|
|
35
55
|
export declare const pruneOrphans: (args: CheckSummariesArgs) => Effect.Effect<number, never, DocsFs>;
|
|
36
56
|
export { isSummaryFile } from '../core/DocSummaries.ts';
|
|
37
57
|
export { isDirSummary } from '../core/SummaryTree.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckSummaries.d.ts","sourceRoot":"","sources":["../../src/program/CheckSummaries.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CheckSummaries.d.ts","sourceRoot":"","sources":["../../src/program/CheckSummaries.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,KAAK,EAAY,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAW7E,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,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,yBAAyB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
// Effect programs for the hierarchical summary system.
|
|
2
|
-
// - `checkSummaries`
|
|
3
|
-
// - `stampSummaries`
|
|
4
|
-
// bottom-up,
|
|
2
|
+
// - `checkSummaries` -> the plan (what is missing/stale, bottom-up order).
|
|
3
|
+
// - `stampSummaries` -> (re)writes the freshness stamp of EXISTING summaries,
|
|
4
|
+
// bottom-up, into their `.cairn/**` sidecar (never into the summary's own
|
|
5
|
+
// content — see StampStore.ts).
|
|
6
|
+
// - `migrateStamps` -> one-off: strips the legacy in-content stamp from
|
|
7
|
+
// every summary, then runs the sidecar stamp pass over the stripped tree.
|
|
5
8
|
// Pure planning lives in ../core/SummaryTree.ts; freshness primitives in
|
|
6
|
-
// ../core/DocSummaries.ts
|
|
9
|
+
// ../core/DocSummaries.ts; sidecar path mapping + (de)serialisation in
|
|
10
|
+
// ../core/StampStore.ts.
|
|
7
11
|
import { Effect } from 'effect';
|
|
8
|
-
import { DEFAULT_STAMP_COMMAND } from
|
|
9
|
-
import { countLines,
|
|
10
|
-
import { nodeExpectedHash, planSummaries } from
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
12
|
+
import { DEFAULT_STAMP_COMMAND } from '../core/Config.js';
|
|
13
|
+
import { countLines, isSummaryFile, stripSourceHash } from '../core/DocSummaries.js';
|
|
14
|
+
import { isDirSummary, nodeExpectedHash, planSummaries } from '../core/SummaryTree.js';
|
|
15
|
+
import { metaRootFor, nodePathForSidecar, parseStamp, serializeStamp, sidecarPathFor, STAMP_VERSION, } from '../core/StampStore.js';
|
|
16
|
+
import { DocsFs } from '../io/DocsFs.js';
|
|
17
|
+
import { enOnly, pick } from './locale.js';
|
|
18
|
+
export { DEFAULT_STAMP_COMMAND } from '../core/Config.js';
|
|
19
|
+
const EMPTY_STAMPS = new Map();
|
|
20
|
+
const layoutFor = (base) => ({ base, metaRoot: metaRootFor(base) });
|
|
21
|
+
/** Assemble the pure planner's arguments from the program args + file map.
|
|
22
|
+
* `stamps` defaults to empty — callers that don't need freshness status (the
|
|
23
|
+
* stamp-writing pass itself) can omit it entirely and skip loading it. */
|
|
24
|
+
const toPlanArgs = (files, args, stamps = EMPTY_STAMPS) => ({
|
|
16
25
|
files,
|
|
17
26
|
...(args.ignore === undefined ? {} : { ignore: args.ignore }),
|
|
18
27
|
...(args.naming === undefined ? {} : { naming: args.naming }),
|
|
19
28
|
...(args.requireDirSummaries === undefined ? {} : { requireDirSummaries: args.requireDirSummaries }),
|
|
20
29
|
roots: args.roots,
|
|
30
|
+
stamps,
|
|
21
31
|
...(args.thresholdLines === undefined ? {} : { thresholdLines: args.thresholdLines }),
|
|
22
32
|
});
|
|
23
33
|
const readMarkdown = (roots) => Effect.gen(function* () {
|
|
@@ -31,13 +41,39 @@ const readMarkdown = (roots) => Effect.gen(function* () {
|
|
|
31
41
|
}
|
|
32
42
|
return files;
|
|
33
43
|
});
|
|
34
|
-
/**
|
|
35
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Load every stamp recorded under `.cairn/**` into a `node path -> sha256` map.
|
|
46
|
+
* A sidecar that can't be mapped back to a node path, or whose content is
|
|
47
|
+
* corrupt/merge-conflicted/hand-edited (`parseStamp` returns `null`), is simply
|
|
48
|
+
* skipped — its node then reads as `stale`/`missing`, never a crash (see
|
|
49
|
+
* StampStore.ts's own contract). Absent `.cairn/` (first run) yields an empty
|
|
50
|
+
* map via `dfs.listFiles`, also without error.
|
|
51
|
+
*/
|
|
52
|
+
const readStamps = (layout) => Effect.gen(function* () {
|
|
53
|
+
const dfs = yield* DocsFs;
|
|
54
|
+
const sidecarPaths = yield* dfs.listFiles([layout.metaRoot]);
|
|
55
|
+
const stamps = new Map();
|
|
56
|
+
for (const sidecarPath of sidecarPaths) {
|
|
57
|
+
const nodeAtPath = nodePathForSidecar(sidecarPath, layout);
|
|
58
|
+
if (nodeAtPath === null) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const record = parseStamp(yield* dfs.readFile(sidecarPath));
|
|
62
|
+
if (record !== null) {
|
|
63
|
+
stamps.set(nodeAtPath, record.sha256);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return stamps;
|
|
67
|
+
});
|
|
68
|
+
/** 0 when nothing is missing/stale, no orphan summaries, and no deleted-source
|
|
69
|
+
* stamps remain, 1 otherwise. */
|
|
70
|
+
export const summaryExitCode = (plan) => plan.todo.length > 0 || plan.orphans.length > 0 || plan.orphanStamps.length > 0 ? 1 : 0;
|
|
36
71
|
/** Report lines: methodology + the bottom-up update order, for a one-pass fix. */
|
|
37
72
|
export const formatSummaryReport = (plan, options = {}) => {
|
|
38
73
|
const locale = options.locale ?? 'en';
|
|
39
74
|
const stampCommand = options.stampCommand ?? DEFAULT_STAMP_COMMAND;
|
|
40
|
-
|
|
75
|
+
const totalOrphans = plan.orphans.length + plan.orphanStamps.length;
|
|
76
|
+
if (plan.todo.length === 0 && totalOrphans === 0) {
|
|
41
77
|
return [
|
|
42
78
|
pick(locale, {
|
|
43
79
|
en: `✅ Hierarchical summaries OK (${plan.nodes.length} summary/ies checked).`,
|
|
@@ -49,13 +85,21 @@ export const formatSummaryReport = (plan, options = {}) => {
|
|
|
49
85
|
en: ` ✗ orphan summary (source gone): ${p}`,
|
|
50
86
|
fr: ` ✗ résumé orphelin (source disparue) : ${p}`,
|
|
51
87
|
}));
|
|
88
|
+
// A `.cairn/**` sidecar with no corresponding node — its source (and possibly
|
|
89
|
+
// its summary file too) was deleted; the sidecar, never touched by hand, is
|
|
90
|
+
// what caught it (see StampStore.ts / SummaryTree.ts's `findDeletedStamps`).
|
|
91
|
+
const orphanStampLines = plan.orphanStamps.map((p) => pick(locale, {
|
|
92
|
+
en: ` ✗ deleted-source stamp (sidecar left behind): ${p}`,
|
|
93
|
+
fr: ` ✗ tampon d'une source supprimée (fichier annexe orphelin) : ${p}`,
|
|
94
|
+
}));
|
|
52
95
|
if (plan.todo.length === 0) {
|
|
53
96
|
return [
|
|
54
97
|
pick(locale, {
|
|
55
|
-
en: `❌ ${
|
|
56
|
-
fr: `❌ ${
|
|
98
|
+
en: `❌ ${totalOrphans} orphan summary/ies or stamp(s) (source doc deleted, renamed, or below threshold):`,
|
|
99
|
+
fr: `❌ ${totalOrphans} résumé(s) ou tampon(s) orphelin(s) (source supprimée, renommée, ou sous le seuil) :`,
|
|
57
100
|
}),
|
|
58
101
|
...orphanLines,
|
|
102
|
+
...orphanStampLines,
|
|
59
103
|
];
|
|
60
104
|
}
|
|
61
105
|
const lines = pick(locale, {
|
|
@@ -95,11 +139,11 @@ export const formatSummaryReport = (plan, options = {}) => {
|
|
|
95
139
|
}
|
|
96
140
|
lines.push(` - [${tag}] ${node.path} : ${reason}`);
|
|
97
141
|
}
|
|
98
|
-
if (
|
|
142
|
+
if (totalOrphans > 0) {
|
|
99
143
|
lines.push('', pick(locale, {
|
|
100
|
-
en: `${
|
|
101
|
-
fr: `${
|
|
102
|
-
}), ...orphanLines);
|
|
144
|
+
en: `${totalOrphans} orphan summary/ies or stamp(s) (source doc deleted, renamed, or below threshold):`,
|
|
145
|
+
fr: `${totalOrphans} résumé(s) ou tampon(s) orphelin(s) (source supprimée, renommée, ou sous le seuil) :`,
|
|
146
|
+
}), ...orphanLines, ...orphanStampLines);
|
|
103
147
|
}
|
|
104
148
|
return lines;
|
|
105
149
|
};
|
|
@@ -145,21 +189,58 @@ const explainPlan = (plan, files, options) => {
|
|
|
145
189
|
};
|
|
146
190
|
export const checkSummaries = (args) => Effect.gen(function* () {
|
|
147
191
|
const files = yield* readMarkdown(args.roots);
|
|
148
|
-
|
|
192
|
+
const stamps = yield* readStamps(layoutFor(args.base));
|
|
193
|
+
return planSummaries(toPlanArgs(files, args, stamps));
|
|
149
194
|
});
|
|
150
195
|
/** `--explain`: why each todo node is not ok (see `explainPlan` for what this can and cannot show). */
|
|
151
196
|
export const explainSummaries = (args, options = {}) => Effect.gen(function* () {
|
|
152
197
|
const files = yield* readMarkdown(args.roots);
|
|
153
|
-
const
|
|
198
|
+
const stamps = yield* readStamps(layoutFor(args.base));
|
|
199
|
+
const plan = planSummaries(toPlanArgs(files, args, stamps));
|
|
154
200
|
return explainPlan(plan, files, options);
|
|
155
201
|
});
|
|
156
202
|
/**
|
|
157
|
-
* Stamp every EXISTING summary with its current source/manifest hash, bottom-up
|
|
158
|
-
*
|
|
203
|
+
* Stamp every EXISTING summary with its current source/manifest hash, bottom-up,
|
|
204
|
+
* into its `.cairn/**` sidecar — never into the summary's own content. Summaries
|
|
205
|
+
* whose content has not been authored yet are returned as `missing`.
|
|
206
|
+
*
|
|
207
|
+
* ALWAYS strips a legacy in-content `<!-- source-sha256 -->` stamp first, if one
|
|
208
|
+
* is still there, before computing any hash — not just when explicitly asked to
|
|
209
|
+
* migrate. This is the actual fix for the discoverability gap a one-off
|
|
210
|
+
* `--migrate-stamps` command alone would leave: an upgrading repo's EXISTING
|
|
211
|
+
* `stampCommand` (already `cairn check --summaries-only --stamp` in every
|
|
212
|
+
* `.cairnrc.json` this tool ever scaffolded) is what a user or CI already runs
|
|
213
|
+
* — making that command self-heal means there is no new command to discover,
|
|
214
|
+
* search for, or forget to run. `--migrate-stamps` (`migrateStamps`, below)
|
|
215
|
+
* still exists as an explicit, nameable entry point for anyone who wants to run
|
|
216
|
+
* the cleanup as its own reported step, but it is no longer load-bearing.
|
|
217
|
+
*
|
|
218
|
+
* Doesn't need to load `stamps` first: this loop writes every node's hash
|
|
219
|
+
* unconditionally (not just the stale ones), so `planSummaries`' ordering is all
|
|
220
|
+
* it needs from the planner — freshness status plays no role in stamping itself.
|
|
159
221
|
*/
|
|
160
|
-
|
|
222
|
+
const stampFiles = (files, args) => Effect.gen(function* () {
|
|
161
223
|
const dfs = yield* DocsFs;
|
|
162
|
-
const
|
|
224
|
+
const layout = layoutFor(args.base);
|
|
225
|
+
// Only ever strips a SUMMARY file's own legacy stamp — never a plain source
|
|
226
|
+
// doc. A source doc's prose can legitimately contain the literal
|
|
227
|
+
// `<!-- source-sha256: <64hex> -->` text (e.g. a doc that documents cairn's
|
|
228
|
+
// OWN former stamp format, with a real-looking example) — that text is the
|
|
229
|
+
// user's content, not tool metadata, and `stampFiles` must never touch it.
|
|
230
|
+
// Restricting to `isSummaryFile`/`isDirSummary` is what keeps "the tool
|
|
231
|
+
// never writes into content" true for every file it doesn't own.
|
|
232
|
+
let migrated = 0;
|
|
233
|
+
for (const [p, content] of files) {
|
|
234
|
+
if (!isSummaryFile(p, args.naming) && !isDirSummary(p, args.naming)) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const stripped = stripSourceHash(content);
|
|
238
|
+
if (stripped !== content) {
|
|
239
|
+
files.set(p, stripped);
|
|
240
|
+
yield* dfs.writeFile(p, stripped);
|
|
241
|
+
migrated += 1;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
163
244
|
const order = planSummaries(toPlanArgs(files, args)).nodes;
|
|
164
245
|
const missing = [];
|
|
165
246
|
let stamped = 0;
|
|
@@ -170,29 +251,51 @@ export const stampSummaries = (args) => Effect.gen(function* () {
|
|
|
170
251
|
}
|
|
171
252
|
// A node's `inputs` are structurally stable (only summary CONTENT changes
|
|
172
253
|
// during stamping, never which paths feed a node) — so its hash can be
|
|
173
|
-
// recomputed directly from `inputs` + their current content.
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
254
|
+
// recomputed directly from `inputs` + their current content. Content no
|
|
255
|
+
// longer carries a stamp (that's the whole point of the sidecar), so —
|
|
256
|
+
// unlike the old in-content scheme — a child's just-written sidecar never
|
|
257
|
+
// changes ITS OWN content, and therefore never perturbs a parent's
|
|
258
|
+
// manifest hash; bottom-up order is preserved for a single-pass write, but
|
|
259
|
+
// no longer required for correctness of the hash itself.
|
|
177
260
|
const expectedHash = nodeExpectedHash({ files, inputs: node.inputs, kind: node.kind, path: node.path });
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
yield* dfs.writeFile(node.path, stampedContent);
|
|
261
|
+
const sidecarContent = serializeStamp({ sha256: expectedHash, version: STAMP_VERSION });
|
|
262
|
+
yield* dfs.writeFile(sidecarPathFor(node.path, layout), sidecarContent);
|
|
181
263
|
stamped += 1;
|
|
182
264
|
}
|
|
183
|
-
return { missing, stamped };
|
|
265
|
+
return { migrated, missing, stamped };
|
|
266
|
+
});
|
|
267
|
+
export const stampSummaries = (args) => Effect.gen(function* () {
|
|
268
|
+
const files = yield* readMarkdown(args.roots);
|
|
269
|
+
return yield* stampFiles(files, args);
|
|
184
270
|
});
|
|
185
|
-
/**
|
|
271
|
+
/**
|
|
272
|
+
* Explicit, nameable one-shot entry point (`--migrate-stamps`) for the SAME
|
|
273
|
+
* self-healing `stampFiles` already does unconditionally on every `--stamp` —
|
|
274
|
+
* kept for anyone who wants to run/report the cleanup as its own step, not
|
|
275
|
+
* because plain `--stamp` needs it to be correct.
|
|
276
|
+
*/
|
|
277
|
+
export const migrateStamps = (args) => Effect.gen(function* () {
|
|
278
|
+
const files = yield* readMarkdown(args.roots);
|
|
279
|
+
return yield* stampFiles(files, args);
|
|
280
|
+
});
|
|
281
|
+
/** Delete every orphan summary file (source doc gone) AND every orphan
|
|
282
|
+
* `.cairn/**` sidecar (deleted-source stamp — see `SummaryPlan.orphanStamps`),
|
|
283
|
+
* reporting the total count removed. */
|
|
186
284
|
export const pruneOrphans = (args) => Effect.gen(function* () {
|
|
187
285
|
const dfs = yield* DocsFs;
|
|
286
|
+
const layout = layoutFor(args.base);
|
|
188
287
|
const files = yield* readMarkdown(args.roots);
|
|
189
|
-
const
|
|
288
|
+
const stamps = yield* readStamps(layout);
|
|
289
|
+
const plan = planSummaries(toPlanArgs(files, args, stamps));
|
|
190
290
|
for (const orphan of plan.orphans) {
|
|
191
291
|
yield* dfs.deleteFile(orphan);
|
|
192
292
|
}
|
|
193
|
-
|
|
293
|
+
for (const orphanStamp of plan.orphanStamps) {
|
|
294
|
+
yield* dfs.deleteFile(sidecarPathFor(orphanStamp, layout));
|
|
295
|
+
}
|
|
296
|
+
return plan.orphans.length + plan.orphanStamps.length;
|
|
194
297
|
});
|
|
195
298
|
// Re-exported so callers can recognise summary files without importing two modules.
|
|
196
|
-
export { isSummaryFile } from
|
|
197
|
-
export { isDirSummary } from
|
|
299
|
+
export { isSummaryFile } from '../core/DocSummaries.js';
|
|
300
|
+
export { isDirSummary } from '../core/SummaryTree.js';
|
|
198
301
|
//# sourceMappingURL=CheckSummaries.js.map
|