ctxr-cli 0.23.0 → 0.25.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 +65 -5
- package/dist/commands/graph-diff.d.ts +33 -0
- package/dist/commands/graph-diff.d.ts.map +1 -0
- package/dist/commands/graph-diff.js +52 -0
- package/dist/commands/graph-diff.js.map +1 -0
- package/dist/commands/land.d.ts +50 -0
- package/dist/commands/land.d.ts.map +1 -0
- package/dist/commands/land.js +414 -0
- package/dist/commands/land.js.map +1 -0
- package/dist/commands/publish-check.d.ts +6 -0
- package/dist/commands/publish-check.d.ts.map +1 -1
- package/dist/commands/publish-check.js +78 -3
- package/dist/commands/publish-check.js.map +1 -1
- package/dist/commands/publish-gather.d.ts.map +1 -1
- package/dist/commands/publish-gather.js +4 -1
- package/dist/commands/publish-gather.js.map +1 -1
- package/dist/commands/publish-new.d.ts +5 -0
- package/dist/commands/publish-new.d.ts.map +1 -1
- package/dist/commands/publish-new.js +30 -10
- package/dist/commands/publish-new.js.map +1 -1
- package/dist/commands/publish-stamp.d.ts +32 -0
- package/dist/commands/publish-stamp.d.ts.map +1 -0
- package/dist/commands/publish-stamp.js +78 -0
- package/dist/commands/publish-stamp.js.map +1 -0
- package/dist/commands/publish-urls.d.ts +13 -0
- package/dist/commands/publish-urls.d.ts.map +1 -1
- package/dist/commands/publish-urls.js +23 -6
- package/dist/commands/publish-urls.js.map +1 -1
- package/dist/commands/review-list.d.ts +34 -0
- package/dist/commands/review-list.d.ts.map +1 -0
- package/dist/commands/review-list.js +49 -0
- package/dist/commands/review-list.js.map +1 -0
- package/dist/commands/serve.d.ts +3 -6
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +106 -9
- package/dist/commands/serve.js.map +1 -1
- package/dist/config/schema.d.ts +40 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +39 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/approval/decision.d.ts +73 -0
- package/dist/core/approval/decision.d.ts.map +1 -0
- package/dist/core/approval/decision.js +166 -0
- package/dist/core/approval/decision.js.map +1 -0
- package/dist/core/approval/file-diff.d.ts +32 -0
- package/dist/core/approval/file-diff.d.ts.map +1 -0
- package/dist/core/approval/file-diff.js +83 -0
- package/dist/core/approval/file-diff.js.map +1 -0
- package/dist/core/approval/identity.d.ts +34 -0
- package/dist/core/approval/identity.d.ts.map +1 -0
- package/dist/core/approval/identity.js +105 -0
- package/dist/core/approval/identity.js.map +1 -0
- package/dist/core/approval/landing-record.d.ts +17 -0
- package/dist/core/approval/landing-record.d.ts.map +1 -0
- package/dist/core/approval/landing-record.js +30 -0
- package/dist/core/approval/landing-record.js.map +1 -0
- package/dist/core/approval/resolver.d.ts +15 -0
- package/dist/core/approval/resolver.d.ts.map +1 -0
- package/dist/core/approval/resolver.js +41 -0
- package/dist/core/approval/resolver.js.map +1 -0
- package/dist/core/approval/sessions.d.ts +36 -0
- package/dist/core/approval/sessions.d.ts.map +1 -0
- package/dist/core/approval/sessions.js +76 -0
- package/dist/core/approval/sessions.js.map +1 -0
- package/dist/core/browse/approve.d.ts +45 -0
- package/dist/core/browse/approve.d.ts.map +1 -0
- package/dist/core/browse/approve.js +239 -0
- package/dist/core/browse/approve.js.map +1 -0
- package/dist/core/browse/diagram-assets.d.ts +15 -0
- package/dist/core/browse/diagram-assets.d.ts.map +1 -0
- package/dist/core/browse/diagram-assets.js +35 -0
- package/dist/core/browse/diagram-assets.js.map +1 -0
- package/dist/core/browse/page-url.d.ts +22 -0
- package/dist/core/browse/page-url.d.ts.map +1 -1
- package/dist/core/browse/page-url.js +31 -0
- package/dist/core/browse/page-url.js.map +1 -1
- package/dist/core/browse/render.d.ts +10 -1
- package/dist/core/browse/render.d.ts.map +1 -1
- package/dist/core/browse/render.js +23 -1
- package/dist/core/browse/render.js.map +1 -1
- package/dist/core/browse/review.d.ts +21 -0
- package/dist/core/browse/review.d.ts.map +1 -0
- package/dist/core/browse/review.js +52 -0
- package/dist/core/browse/review.js.map +1 -0
- package/dist/core/browse/templates.d.ts +4 -1
- package/dist/core/browse/templates.d.ts.map +1 -1
- package/dist/core/browse/templates.js +18 -2
- package/dist/core/browse/templates.js.map +1 -1
- package/dist/core/checks/organize-checks.d.ts +17 -0
- package/dist/core/checks/organize-checks.d.ts.map +1 -1
- package/dist/core/checks/organize-checks.js +116 -0
- package/dist/core/checks/organize-checks.js.map +1 -1
- package/dist/core/errors.d.ts +67 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +160 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/forge/credentials.d.ts +69 -0
- package/dist/core/forge/credentials.d.ts.map +1 -0
- package/dist/core/forge/credentials.js +197 -0
- package/dist/core/forge/credentials.js.map +1 -0
- package/dist/core/forge/github.d.ts +73 -0
- package/dist/core/forge/github.d.ts.map +1 -0
- package/dist/core/forge/github.js +101 -0
- package/dist/core/forge/github.js.map +1 -0
- package/dist/core/git/exec.d.ts +25 -0
- package/dist/core/git/exec.d.ts.map +1 -1
- package/dist/core/git/exec.js +100 -2
- package/dist/core/git/exec.js.map +1 -1
- package/dist/core/graph/diff-block.d.ts +6 -0
- package/dist/core/graph/diff-block.d.ts.map +1 -0
- package/dist/core/graph/diff-block.js +63 -0
- package/dist/core/graph/diff-block.js.map +1 -0
- package/dist/core/graph/diff-document.d.ts +38 -0
- package/dist/core/graph/diff-document.d.ts.map +1 -0
- package/dist/core/graph/diff-document.js +117 -0
- package/dist/core/graph/diff-document.js.map +1 -0
- package/dist/core/graph/diff.d.ts +123 -0
- package/dist/core/graph/diff.d.ts.map +1 -0
- package/dist/core/graph/diff.js +253 -0
- package/dist/core/graph/diff.js.map +1 -0
- package/dist/core/graph/tree.d.ts +24 -0
- package/dist/core/graph/tree.d.ts.map +1 -0
- package/dist/core/graph/tree.js +45 -0
- package/dist/core/graph/tree.js.map +1 -0
- package/dist/core/notes/list.d.ts +10 -0
- package/dist/core/notes/list.d.ts.map +1 -1
- package/dist/core/notes/list.js +35 -12
- package/dist/core/notes/list.js.map +1 -1
- package/dist/core/publish/filing.d.ts +12 -12
- package/dist/core/publish/filing.d.ts.map +1 -1
- package/dist/core/publish/filing.js +20 -18
- package/dist/core/publish/filing.js.map +1 -1
- package/dist/core/publish/lifespan.d.ts +37 -0
- package/dist/core/publish/lifespan.d.ts.map +1 -0
- package/dist/core/publish/lifespan.js +59 -0
- package/dist/core/publish/lifespan.js.map +1 -0
- package/dist/core/publish/represents.d.ts +72 -0
- package/dist/core/publish/represents.d.ts.map +1 -0
- package/dist/core/publish/represents.js +83 -0
- package/dist/core/publish/represents.js.map +1 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +60 -4
- package/dist/run.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
- package/templates/approve/approve-button.md +1 -0
- package/templates/approve/author-heading.md +1 -0
- package/templates/approve/author-note.md +1 -0
- package/templates/approve/comment-label.md +1 -0
- package/templates/approve/comment-required.md +1 -0
- package/templates/approve/commits-heading.md +1 -0
- package/templates/approve/decision-heading.md +1 -0
- package/templates/approve/decision-note.md +1 -0
- package/templates/approve/diff-binary.md +1 -0
- package/templates/approve/diff-empty.md +1 -0
- package/templates/approve/diff-heading.md +1 -0
- package/templates/approve/facts-heading.md +1 -0
- package/templates/approve/forge-unreachable.md +1 -0
- package/templates/approve/github-app-manifest.json +15 -0
- package/templates/approve/head-missing.md +1 -0
- package/templates/approve/index-empty.md +1 -0
- package/templates/approve/index-heading.md +1 -0
- package/templates/approve/index-intro.md +1 -0
- package/templates/approve/landed.md +1 -0
- package/templates/approve/moved-head.md +1 -0
- package/templates/approve/no-pull.md +1 -0
- package/templates/approve/not-open.md +1 -0
- package/templates/approve/pages-heading.md +1 -0
- package/templates/approve/pages-note.md +1 -0
- package/templates/approve/record-failed.md +1 -0
- package/templates/approve/request-changes-button.md +1 -0
- package/templates/approve/state-line.md +1 -0
- package/templates/conventions/baseline-conventions.md +6 -0
- package/templates/graph/knowledge-changes/archived-item.md +1 -0
- package/templates/graph/knowledge-changes/archived.md +1 -0
- package/templates/graph/knowledge-changes/bare-route.md +2 -0
- package/templates/graph/knowledge-changes/block.md +10 -0
- package/templates/graph/knowledge-changes/counts.md +1 -0
- package/templates/graph/knowledge-changes/dangling-item.md +1 -0
- package/templates/graph/knowledge-changes/dangling.md +1 -0
- package/templates/graph/knowledge-changes/empty.md +1 -0
- package/templates/graph/knowledge-changes/reason-ambiguous.md +1 -0
- package/templates/graph/knowledge-changes/reason-not_found.md +1 -0
- package/templates/graph/knowledge-changes/review.md +4 -0
- package/templates/graph/review/moved-head.md +1 -0
- package/templates/land/resolver.md +12 -0
- package/templates/serve/diagrams.mjs +136 -0
- package/templates/serve/shell.html +1 -1
- package/templates/serve/style.css +90 -0
- package/templates/skills/ctxr-land.md +37 -31
- package/templates/skills/ctxr-organize-audit.md +19 -0
- package/templates/skills/ctxr-publish.md +100 -45
- package/templates/skills/ctxr-second-opinion/run.mjs +28 -17
- package/templates/skills/ctxr-second-opinion.md +19 -14
- package/templates/skills/ctxr-session-lifecycle.md +9 -0
- package/templates/skills/ctxr-submit.md +28 -17
|
@@ -22,6 +22,13 @@ export interface Filing {
|
|
|
22
22
|
/** The segment naming the subject note, present only when D3 inserts one. */
|
|
23
23
|
subject_segment: string | null;
|
|
24
24
|
moves: FilingMove[];
|
|
25
|
+
/**
|
|
26
|
+
* Why no path derives, when `prefix` is null: no folder path names the
|
|
27
|
+
* subject (`store-root`), or the derived path's first segment is the one
|
|
28
|
+
* reserved for disposable pages (`reserved-segment`,
|
|
29
|
+
* two-kinds-of-published-page D2). Null whenever a path derives.
|
|
30
|
+
*/
|
|
31
|
+
no_path_reason: 'store-root' | 'reserved-segment' | null;
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Re-exported from `core/slug.ts`, which owns the one normalization rule; the
|
|
@@ -30,18 +37,11 @@ export interface Filing {
|
|
|
30
37
|
*/
|
|
31
38
|
export { slugifyPath, slugifySegment };
|
|
32
39
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* just told the author to create.
|
|
39
|
-
*
|
|
40
|
-
* D3: the segment naming the subject note is inserted exactly when that subject
|
|
41
|
-
* already has a page, so a one-page subject stays shallow and a multi-page one
|
|
42
|
-
* collects; and when the folder path is empty, so a subject at the store root
|
|
43
|
-
* still yields a path one level deep and satisfies `checkPageLocation`'s floor
|
|
44
|
-
* by construction.
|
|
40
|
+
* two-kinds-of-published-page D2: the first segment under the publish path
|
|
41
|
+
* named `disposable` is reserved for disposable pages, and a store folder named
|
|
42
|
+
* "Disposable" slugifies to exactly it. A path derived into it is reported as no
|
|
43
|
+
* path at all, with the reservation as the reason — the existing "no path
|
|
44
|
+
* derives" outcome with a second reason, so gather still gates nothing.
|
|
45
45
|
*/
|
|
46
46
|
export declare function deriveFiling(storeRoot: string, publishPath: string, subject: FilingSubject): Promise<Filing>;
|
|
47
47
|
//# sourceMappingURL=filing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filing.d.ts","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"filing.d.ts","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIzD,8GAA8G;AAC9G,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,oHAAoH;IACpH,UAAU,EAAE,aAAa,GAAG,WAAW,CAAC;CACzC;AAED,MAAM,WAAW,MAAM;IACrB,kHAAkH;IAClH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oGAAoG;IACpG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uHAAuH;IACvH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;;;;;OAKG;IACH,cAAc,EAAE,YAAY,GAAG,kBAAkB,GAAG,IAAI,CAAC;CAC1D;AAED;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AAsGvC;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAOlH"}
|
|
@@ -2,9 +2,9 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import { readFile, readdir } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { PUBLISH_INDEX_FILE } from '../browse/routes.js';
|
|
5
|
-
import { extractLinkTargets } from '../graph/model.js';
|
|
6
|
-
import { parseNoteText } from '../notes/parse.js';
|
|
7
5
|
import { slugifyPath, slugifySegment } from '../slug.js';
|
|
6
|
+
import { DISPOSABLE_SEGMENT } from './lifespan.js';
|
|
7
|
+
import { readLeadLink } from './represents.js';
|
|
8
8
|
/**
|
|
9
9
|
* Re-exported from `core/slug.ts`, which owns the one normalization rule; the
|
|
10
10
|
* filing module was where it was first written and is still where most callers
|
|
@@ -47,10 +47,10 @@ async function readmeLeadsWithStem(absolutePageDirectory, stem) {
|
|
|
47
47
|
catch {
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
|
-
//
|
|
51
|
-
// `publish check`
|
|
52
|
-
//
|
|
53
|
-
return
|
|
50
|
+
// two-kinds-of-published-page D4: the one reading of a README's lead link,
|
|
51
|
+
// shared with `publish check`'s represented-note check so the two cannot
|
|
52
|
+
// diverge on whose page a page is.
|
|
53
|
+
return readLeadLink(raw, readmePath)?.target === stem;
|
|
54
54
|
}
|
|
55
55
|
async function pagesForNote(publishRoot, group, subjectSlug, noteStem) {
|
|
56
56
|
const subjectDirectory = group === '' ? subjectSlug : `${group}/${subjectSlug}`;
|
|
@@ -69,20 +69,22 @@ async function pagesForNote(publishRoot, group, subjectSlug, noteStem) {
|
|
|
69
69
|
return found;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* just told the author to create.
|
|
78
|
-
*
|
|
79
|
-
* D3: the segment naming the subject note is inserted exactly when that subject
|
|
80
|
-
* already has a page, so a one-page subject stays shallow and a multi-page one
|
|
81
|
-
* collects; and when the folder path is empty, so a subject at the store root
|
|
82
|
-
* still yields a path one level deep and satisfies `checkPageLocation`'s floor
|
|
83
|
-
* by construction.
|
|
72
|
+
* two-kinds-of-published-page D2: the first segment under the publish path
|
|
73
|
+
* named `disposable` is reserved for disposable pages, and a store folder named
|
|
74
|
+
* "Disposable" slugifies to exactly it. A path derived into it is reported as no
|
|
75
|
+
* path at all, with the reservation as the reason — the existing "no path
|
|
76
|
+
* derives" outcome with a second reason, so gather still gates nothing.
|
|
84
77
|
*/
|
|
85
78
|
export async function deriveFiling(storeRoot, publishPath, subject) {
|
|
79
|
+
const filing = await deriveUnreservedFiling(storeRoot, publishPath, subject);
|
|
80
|
+
if (filing.prefix === null)
|
|
81
|
+
return { ...filing, no_path_reason: 'store-root' };
|
|
82
|
+
if (filing.prefix.split('/')[0] === DISPOSABLE_SEGMENT) {
|
|
83
|
+
return { prefix: null, path: null, group: filing.group, subject_segment: null, moves: [], no_path_reason: 'reserved-segment' };
|
|
84
|
+
}
|
|
85
|
+
return { ...filing, no_path_reason: null };
|
|
86
|
+
}
|
|
87
|
+
async function deriveUnreservedFiling(storeRoot, publishPath, subject) {
|
|
86
88
|
const publishPrefix = publishPath.split(path.sep).join('/').replace(/\/+$/, '');
|
|
87
89
|
const publishRoot = path.join(storeRoot, ...publishPrefix.split('/'));
|
|
88
90
|
const group = slugifyPath(subject.directory);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filing.js","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"filing.js","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* two-kinds-of-published-page: a page's lifespan, read from where it is filed
|
|
3
|
+
* and from nothing else (design.md D3). A page whose folder's first segment
|
|
4
|
+
* under the configured publish path is `disposable` is disposable; every
|
|
5
|
+
* other page is permanent, so every page that predates this change is
|
|
6
|
+
* permanent without being touched.
|
|
7
|
+
*/
|
|
8
|
+
export type PageLifespan = 'permanent' | 'disposable';
|
|
9
|
+
/**
|
|
10
|
+
* D2: a fixed segment, not a config key — a key would have to be opt-in with
|
|
11
|
+
* no shipped default, which makes the feature off in every store. The plain
|
|
12
|
+
* word can collide with a store folder named "Disposable" (it slugifies to
|
|
13
|
+
* exactly this), so the name is RESERVED rather than unreachable: `publish new`
|
|
14
|
+
* refuses a slug spelled into it without `--disposable`, `publish gather`
|
|
15
|
+
* derives no filing path into it, and `publish check` reads anything filed
|
|
16
|
+
* there as disposable and fails its shape. `_disposable` would have made the
|
|
17
|
+
* collision structurally impossible, and lost on how it reads in a URL.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DISPOSABLE_SEGMENT = "disposable";
|
|
20
|
+
/** D6: the window after which lint lists a disposable page as a removal candidate. A code constant, not config. */
|
|
21
|
+
export declare const DISPOSABLE_REVIEW_DAYS = 30;
|
|
22
|
+
/**
|
|
23
|
+
* The lifespan of a page (or any file under it), given its store-relative
|
|
24
|
+
* path. `null` when the path is not under the configured publish path — such
|
|
25
|
+
* a file is not a published page and has no lifespan.
|
|
26
|
+
*/
|
|
27
|
+
export declare function lifespanOf(relativePath: string, publishPath: string): PageLifespan | null;
|
|
28
|
+
/**
|
|
29
|
+
* The calendar date leading a disposable page's folder name, as `YYYY-MM-DD`,
|
|
30
|
+
* or `null` when the name carries none or the date is not a real one
|
|
31
|
+
* (`2026-13-45`, `2026-02-30`). Round-tripping through `Date.UTC` is what
|
|
32
|
+
* rejects a day the month does not have.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseDisposableDate(folderName: string): string | null;
|
|
35
|
+
/** Whole days from `date` to `today`, both `YYYY-MM-DD`. */
|
|
36
|
+
export declare function daysBetween(date: string, today: string): number;
|
|
37
|
+
//# sourceMappingURL=lifespan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifespan.d.ts","sourceRoot":"","sources":["../../../src/core/publish/lifespan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;AAEtD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAE/C,mHAAmH;AACnH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAMzC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAMzF;AAKD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOrE;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* two-kinds-of-published-page: a page's lifespan, read from where it is filed
|
|
3
|
+
* and from nothing else (design.md D3). A page whose folder's first segment
|
|
4
|
+
* under the configured publish path is `disposable` is disposable; every
|
|
5
|
+
* other page is permanent, so every page that predates this change is
|
|
6
|
+
* permanent without being touched.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* D2: a fixed segment, not a config key — a key would have to be opt-in with
|
|
10
|
+
* no shipped default, which makes the feature off in every store. The plain
|
|
11
|
+
* word can collide with a store folder named "Disposable" (it slugifies to
|
|
12
|
+
* exactly this), so the name is RESERVED rather than unreachable: `publish new`
|
|
13
|
+
* refuses a slug spelled into it without `--disposable`, `publish gather`
|
|
14
|
+
* derives no filing path into it, and `publish check` reads anything filed
|
|
15
|
+
* there as disposable and fails its shape. `_disposable` would have made the
|
|
16
|
+
* collision structurally impossible, and lost on how it reads in a URL.
|
|
17
|
+
*/
|
|
18
|
+
export const DISPOSABLE_SEGMENT = 'disposable';
|
|
19
|
+
/** D6: the window after which lint lists a disposable page as a removal candidate. A code constant, not config. */
|
|
20
|
+
export const DISPOSABLE_REVIEW_DAYS = 30;
|
|
21
|
+
function normalizedPrefix(publishPath) {
|
|
22
|
+
return publishPath.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The lifespan of a page (or any file under it), given its store-relative
|
|
26
|
+
* path. `null` when the path is not under the configured publish path — such
|
|
27
|
+
* a file is not a published page and has no lifespan.
|
|
28
|
+
*/
|
|
29
|
+
export function lifespanOf(relativePath, publishPath) {
|
|
30
|
+
const prefix = normalizedPrefix(publishPath);
|
|
31
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
32
|
+
if (!normalized.startsWith(`${prefix}/`))
|
|
33
|
+
return null;
|
|
34
|
+
const firstSegment = normalized.slice(prefix.length + 1).split('/')[0];
|
|
35
|
+
return firstSegment === DISPOSABLE_SEGMENT ? 'disposable' : 'permanent';
|
|
36
|
+
}
|
|
37
|
+
/** The `YYYY-MM-DD-` lead a disposable page's folder name carries, stamped by `ctxr publish new --disposable`. */
|
|
38
|
+
const DISPOSABLE_DATE_RE = /^(\d{4})-(\d{2})-(\d{2})-./;
|
|
39
|
+
/**
|
|
40
|
+
* The calendar date leading a disposable page's folder name, as `YYYY-MM-DD`,
|
|
41
|
+
* or `null` when the name carries none or the date is not a real one
|
|
42
|
+
* (`2026-13-45`, `2026-02-30`). Round-tripping through `Date.UTC` is what
|
|
43
|
+
* rejects a day the month does not have.
|
|
44
|
+
*/
|
|
45
|
+
export function parseDisposableDate(folderName) {
|
|
46
|
+
const match = DISPOSABLE_DATE_RE.exec(folderName);
|
|
47
|
+
if (!match)
|
|
48
|
+
return null;
|
|
49
|
+
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
50
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
51
|
+
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day)
|
|
52
|
+
return null;
|
|
53
|
+
return `${match[1]}-${match[2]}-${match[3]}`;
|
|
54
|
+
}
|
|
55
|
+
/** Whole days from `date` to `today`, both `YYYY-MM-DD`. */
|
|
56
|
+
export function daysBetween(date, today) {
|
|
57
|
+
return Math.round((Date.parse(`${today}T00:00:00Z`) - Date.parse(`${date}T00:00:00Z`)) / 86_400_000);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=lifespan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifespan.js","sourceRoot":"","sources":["../../../src/core/publish/lifespan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAE/C,mHAAmH;AACnH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC,SAAS,gBAAgB,CAAC,WAAmB;IAC3C,OAAO,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,YAAoB,EAAE,WAAmB;IAClE,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,OAAO,YAAY,KAAK,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1E,CAAC;AAED,kHAAkH;AAClH,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;AAExD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAkB;IACpD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACjH,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAAa;IACrD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Note } from '../notes/list.js';
|
|
2
|
+
/**
|
|
3
|
+
* two-kinds-of-published-page design.md D4: the note a permanent page
|
|
4
|
+
* represents is the FIRST wikilink in its README's body, frontmatter
|
|
5
|
+
* excluded. `filing.ts` reads the same link to decide whose page a page is,
|
|
6
|
+
* so the reading lives here once and both call it — a page `gather` counts as
|
|
7
|
+
* a subject's and a page `check` says represents that subject cannot disagree.
|
|
8
|
+
*/
|
|
9
|
+
export interface LeadLink {
|
|
10
|
+
/** The wikilink target as written: the stem before any `|alias` or `#heading`. */
|
|
11
|
+
target: string;
|
|
12
|
+
/** Zero-based index of the raw README line holding it, frontmatter lines counted. */
|
|
13
|
+
line: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parsed rather than grepped so frontmatter is excluded, matching how the graph
|
|
17
|
+
* resolves a wikilink. `extractLinkTargets` reports occurrences in body order,
|
|
18
|
+
* so the first line that yields one holds the lead.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readLeadLink(readmeRaw: string, readmePath: string): LeadLink | null;
|
|
21
|
+
export type RepresentedResolution = {
|
|
22
|
+
note: Note;
|
|
23
|
+
} | {
|
|
24
|
+
none: true;
|
|
25
|
+
} | {
|
|
26
|
+
ambiguous: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* By filename stem, through the one stem index every wikilink resolution in the
|
|
30
|
+
* system reads (`buildStemIndex`): exactly one note resolves, zero or two-plus
|
|
31
|
+
* do not. The candidates are named so the author can qualify the link.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveRepresented(notes: readonly Note[], stem: string): RepresentedResolution;
|
|
34
|
+
export declare function readHashMarker(line: string): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* D5: the marker is written once and never overwritten. A line that already
|
|
37
|
+
* carries one comes back unchanged — confirming a page against a changed note
|
|
38
|
+
* takes removing the marker by hand and stamping again.
|
|
39
|
+
*/
|
|
40
|
+
export declare function appendHashMarker(line: string, hash: string): string;
|
|
41
|
+
/** The represented note's hash — `contentHashOfBody`, imported and never re-spelled. */
|
|
42
|
+
export declare function representedNoteHash(note: Note): string;
|
|
43
|
+
export type Representation = {
|
|
44
|
+
status: 'no-link';
|
|
45
|
+
} | {
|
|
46
|
+
status: 'not-found';
|
|
47
|
+
target: string;
|
|
48
|
+
} | {
|
|
49
|
+
status: 'ambiguous';
|
|
50
|
+
target: string;
|
|
51
|
+
candidates: string[];
|
|
52
|
+
} | {
|
|
53
|
+
status: 'not-stamped';
|
|
54
|
+
note: string;
|
|
55
|
+
hash: string;
|
|
56
|
+
lead: LeadLink;
|
|
57
|
+
} | {
|
|
58
|
+
status: 'stale';
|
|
59
|
+
note: string;
|
|
60
|
+
hash: string;
|
|
61
|
+
recorded: string;
|
|
62
|
+
lead: LeadLink;
|
|
63
|
+
} | {
|
|
64
|
+
status: 'current';
|
|
65
|
+
note: string;
|
|
66
|
+
hash: string;
|
|
67
|
+
lead: LeadLink;
|
|
68
|
+
};
|
|
69
|
+
/** Where a permanent page stands against its note — one reading for `publish check`, `publish stamp` and lint. */
|
|
70
|
+
export declare function assessRepresentation(readmeRaw: string, readmePath: string, notes: readonly Note[]): Representation;
|
|
71
|
+
export declare function readReadme(readmeAbsolutePath: string): Promise<string | null>;
|
|
72
|
+
//# sourceMappingURL=represents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"represents.d.ts","sourceRoot":"","sources":["../../../src/core/publish/represents.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CASnF;AAED,MAAM,MAAM,qBAAqB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9F;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAK9F;AAKD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnE;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEtD;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACrE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACjF;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEtE,kHAAkH;AAClH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,cAAc,CAWlH;AAED,wBAAsB,UAAU,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOnF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { contentHashOfBody } from '../content/canonicalize.js';
|
|
3
|
+
import { buildStemIndex, extractLinkTargets } from '../graph/model.js';
|
|
4
|
+
import { parseNoteText } from '../notes/parse.js';
|
|
5
|
+
/**
|
|
6
|
+
* Parsed rather than grepped so frontmatter is excluded, matching how the graph
|
|
7
|
+
* resolves a wikilink. `extractLinkTargets` reports occurrences in body order,
|
|
8
|
+
* so the first line that yields one holds the lead.
|
|
9
|
+
*/
|
|
10
|
+
export function readLeadLink(readmeRaw, readmePath) {
|
|
11
|
+
const { body } = parseNoteText(readmeRaw, readmePath);
|
|
12
|
+
const frontmatterLines = readmeRaw.slice(0, readmeRaw.length - body.length).split('\n').length - 1;
|
|
13
|
+
const lines = body.split('\n');
|
|
14
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15
|
+
const target = extractLinkTargets(lines[i])[0];
|
|
16
|
+
if (target !== undefined)
|
|
17
|
+
return { target, line: frontmatterLines + i };
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* By filename stem, through the one stem index every wikilink resolution in the
|
|
23
|
+
* system reads (`buildStemIndex`): exactly one note resolves, zero or two-plus
|
|
24
|
+
* do not. The candidates are named so the author can qualify the link.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveRepresented(notes, stem) {
|
|
27
|
+
const paths = buildStemIndex(notes).get(stem) ?? [];
|
|
28
|
+
if (paths.length === 0)
|
|
29
|
+
return { none: true };
|
|
30
|
+
if (paths.length > 1)
|
|
31
|
+
return { ambiguous: [...paths].sort() };
|
|
32
|
+
return { note: notes.find((note) => note.path === paths[0]) };
|
|
33
|
+
}
|
|
34
|
+
/** The catalog's frozen-hash form, so an agent that has learned one has learned both (D5). */
|
|
35
|
+
const HASH_MARKER_RE = /\s*<!-- hash:([0-9a-f]{16}) -->/;
|
|
36
|
+
export function readHashMarker(line) {
|
|
37
|
+
return HASH_MARKER_RE.exec(line)?.[1] ?? null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* D5: the marker is written once and never overwritten. A line that already
|
|
41
|
+
* carries one comes back unchanged — confirming a page against a changed note
|
|
42
|
+
* takes removing the marker by hand and stamping again.
|
|
43
|
+
*/
|
|
44
|
+
export function appendHashMarker(line, hash) {
|
|
45
|
+
if (readHashMarker(line) !== null)
|
|
46
|
+
return line;
|
|
47
|
+
// A CRLF file's line keeps its `\r`, so nothing but the marker changes.
|
|
48
|
+
const ending = line.endsWith('\r') ? '\r' : '';
|
|
49
|
+
return `${line.replace(/\s+$/, '')} <!-- hash:${hash} -->${ending}`;
|
|
50
|
+
}
|
|
51
|
+
/** The represented note's hash — `contentHashOfBody`, imported and never re-spelled. */
|
|
52
|
+
export function representedNoteHash(note) {
|
|
53
|
+
return contentHashOfBody(note.body);
|
|
54
|
+
}
|
|
55
|
+
/** Where a permanent page stands against its note — one reading for `publish check`, `publish stamp` and lint. */
|
|
56
|
+
export function assessRepresentation(readmeRaw, readmePath, notes) {
|
|
57
|
+
const lead = readLeadLink(readmeRaw, readmePath);
|
|
58
|
+
if (lead === null)
|
|
59
|
+
return { status: 'no-link' };
|
|
60
|
+
const resolved = resolveRepresented(notes, lead.target);
|
|
61
|
+
if ('none' in resolved)
|
|
62
|
+
return { status: 'not-found', target: lead.target };
|
|
63
|
+
if ('ambiguous' in resolved)
|
|
64
|
+
return { status: 'ambiguous', target: lead.target, candidates: resolved.ambiguous };
|
|
65
|
+
const hash = representedNoteHash(resolved.note);
|
|
66
|
+
const recorded = readHashMarker(readmeRaw.split('\n')[lead.line]);
|
|
67
|
+
if (recorded === null)
|
|
68
|
+
return { status: 'not-stamped', note: resolved.note.path, hash, lead };
|
|
69
|
+
if (recorded !== hash)
|
|
70
|
+
return { status: 'stale', note: resolved.note.path, hash, recorded, lead };
|
|
71
|
+
return { status: 'current', note: resolved.note.path, hash, lead };
|
|
72
|
+
}
|
|
73
|
+
export async function readReadme(readmeAbsolutePath) {
|
|
74
|
+
try {
|
|
75
|
+
return await readFile(readmeAbsolutePath, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
if (err.code === 'ENOENT')
|
|
79
|
+
return null;
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=represents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"represents.js","sourceRoot":"","sources":["../../../src/core/publish/represents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAgBlD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,UAAkB;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACnG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,CAAC,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAsB,EAAE,IAAY;IACrE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAC9D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC;AACjE,CAAC;AAED,8FAA8F;AAC9F,MAAM,cAAc,GAAG,iCAAiC,CAAC;AAEzD,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAY;IACzD,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/C,wEAAwE;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,IAAI,OAAO,MAAM,EAAE,CAAC;AACtE,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAAC,IAAU;IAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAUD,kHAAkH;AAClH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,UAAkB,EAAE,KAAsB;IAChG,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,MAAM,IAAI,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5E,IAAI,WAAW,IAAI,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;IACjH,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC;IACnE,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9F,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAClG,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,kBAA0B;IACzD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AAuIpE,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAymBjF"}
|
package/dist/run.js
CHANGED
|
@@ -6,9 +6,11 @@ import * as adaptersGenerateCommand from './commands/adapters-generate.js';
|
|
|
6
6
|
import * as archiveCommand from './commands/archive.js';
|
|
7
7
|
import * as doctorCommand from './commands/doctor.js';
|
|
8
8
|
import * as ingestCommand from './commands/ingest.js';
|
|
9
|
+
import * as landCommand from './commands/land.js';
|
|
9
10
|
import * as lintCommand from './commands/lint.js';
|
|
10
11
|
import * as contextGatherCommand from './commands/context-gather.js';
|
|
11
12
|
import * as graphBuildCommand from './commands/graph-build.js';
|
|
13
|
+
import * as graphDiffCommand from './commands/graph-diff.js';
|
|
12
14
|
import * as entryAppendCommand from './commands/entry-append.js';
|
|
13
15
|
import * as graphQueryCommand from './commands/graph-query.js';
|
|
14
16
|
import * as initCommand from './commands/init.js';
|
|
@@ -16,6 +18,8 @@ import * as publishGatherCommand from './commands/publish-gather.js';
|
|
|
16
18
|
import * as publishCheckCommand from './commands/publish-check.js';
|
|
17
19
|
import * as publishUrlsCommand from './commands/publish-urls.js';
|
|
18
20
|
import * as publishNewCommand from './commands/publish-new.js';
|
|
21
|
+
import * as publishStampCommand from './commands/publish-stamp.js';
|
|
22
|
+
import * as reviewListCommand from './commands/review-list.js';
|
|
19
23
|
import * as sessionCaptureCommand from './commands/session-capture.js';
|
|
20
24
|
import * as sessionListCommand from './commands/session-list.js';
|
|
21
25
|
import * as serveCommand from './commands/serve.js';
|
|
@@ -282,6 +286,23 @@ export async function run(argv, env) {
|
|
|
282
286
|
return graphBuildCommand.execute(store, { emitRecords: cmdOpts.emitRecords });
|
|
283
287
|
});
|
|
284
288
|
});
|
|
289
|
+
graphCommand
|
|
290
|
+
.command('diff')
|
|
291
|
+
.description('how the knowledge changed between two commits: notes, links, dangling links, inbound links, rollups and newly cited sources — read from git, writing nothing')
|
|
292
|
+
.option('--since <ref>', 'compare from the merge base of this ref and the head (required)')
|
|
293
|
+
.option('--until <ref>', 'the head commit to compare (default: HEAD)')
|
|
294
|
+
.option('--format <form>', `the human output: ${graphDiffCommand.GRAPH_DIFF_FORMATS.join(' or ')} (markdown is the pull request's Knowledge changes block; not with --json)`)
|
|
295
|
+
.action(async (cmdOpts, cmd) => {
|
|
296
|
+
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
297
|
+
const flags = { since: cmdOpts.since, until: cmdOpts.until, format: cmdOpts.format };
|
|
298
|
+
// review-the-knowledge-diff (D9): `--format markdown` is the whole stdout — the
|
|
299
|
+
// block rides as the human summary, which the reporter writes verbatim and alone.
|
|
300
|
+
result = await runCommand('graph.diff', runEnv, jsonMode, async () => {
|
|
301
|
+
graphDiffCommand.checkFlags(flags, jsonMode);
|
|
302
|
+
const store = await openStore(runEnv, { root });
|
|
303
|
+
return graphDiffCommand.execute(store, flags, jsonMode);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
285
306
|
const graphQueryCommandGroup = graphCommand.command('query').description('query the built graph');
|
|
286
307
|
graphQueryCommandGroup
|
|
287
308
|
.command('neighbors <node>')
|
|
@@ -499,17 +520,28 @@ export async function run(argv, env) {
|
|
|
499
520
|
});
|
|
500
521
|
publishCommand
|
|
501
522
|
.command('new <slug>')
|
|
502
|
-
.description('scaffold a page folder with a sibling README, and name the address it is served at — the slug may name a path of folders under the publish path — refusing a reserved or already-existing slug')
|
|
503
|
-
.
|
|
523
|
+
.description('scaffold a page folder with a sibling README, and name the address it is served at and its lifespan — the slug may name a path of folders under the publish path — refusing a reserved or already-existing slug; with --disposable, a throwaway page at disposable/<today>-<slug>')
|
|
524
|
+
.option('--disposable', 'scaffold a disposable page at disposable/<YYYY-MM-DD>-<slug>, dated today by the command (two-kinds-of-published-page)')
|
|
525
|
+
.action(async (slug, cmdOpts, cmd) => {
|
|
504
526
|
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
505
527
|
result = await runCommand('publish.new', runEnv, jsonMode, async () => {
|
|
506
528
|
const store = await openStore(runEnv, { root });
|
|
507
|
-
return publishNewCommand.execute(store, { slug });
|
|
529
|
+
return publishNewCommand.execute(store, { slug, disposable: cmdOpts.disposable === true });
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
publishCommand
|
|
533
|
+
.command('stamp <path>')
|
|
534
|
+
.description("record the hash of the note a permanent page represents (its README's lead link) as a marker on that line — once; never overwrites a marker, and refuses a disposable page")
|
|
535
|
+
.action(async (pagePath, _cmdOpts, cmd) => {
|
|
536
|
+
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
537
|
+
result = await runCommand('publish.stamp', runEnv, jsonMode, async () => {
|
|
538
|
+
const store = await openStore(runEnv, { root });
|
|
539
|
+
return publishStampCommand.execute(store, { path: pagePath });
|
|
508
540
|
});
|
|
509
541
|
});
|
|
510
542
|
publishCommand
|
|
511
543
|
.command('check <path>')
|
|
512
|
-
.description(
|
|
544
|
+
.description("the mechanized structural checks a published page must pass (no external references, viewport meta, print rule, provenance, sibling README, script syntax; a disposable page's shape; a permanent page's represented note and its hash), and the page's address and lifespan")
|
|
513
545
|
.action(async (pagePath, _cmdOpts, cmd) => {
|
|
514
546
|
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
515
547
|
result = await runCommand('publish.check', runEnv, jsonMode, async () => {
|
|
@@ -585,6 +617,30 @@ export async function run(argv, env) {
|
|
|
585
617
|
return verifyCommand.execute(runEnv, store, { portable: cmdOpts.portable });
|
|
586
618
|
});
|
|
587
619
|
});
|
|
620
|
+
program
|
|
621
|
+
.command('land')
|
|
622
|
+
.description('land a session pull request: check consent for its head, catch it up with the default branch, merge, confirm, sync the canonical clone, and remove the worktree')
|
|
623
|
+
.argument('[pr]', 'the pull request number to land', (v) => Number.parseInt(v, 10))
|
|
624
|
+
.option('--pending', 'land every open session pull request whose current head carries an approval from the approval page')
|
|
625
|
+
.option('--confirm', 'the caller already has an explicit go for this pull request; land it without a recorded approval')
|
|
626
|
+
.action(async (pr, cmdOpts, cmd) => {
|
|
627
|
+
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
628
|
+
result = await runCommand('land', runEnv, jsonMode, async () => {
|
|
629
|
+
const store = await openStore(runEnv, { root });
|
|
630
|
+
return landCommand.execute(runEnv, store, { pr, pending: Boolean(cmdOpts.pending), confirm: Boolean(cmdOpts.confirm) });
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
const reviewCommand = program.command('review').description('read the decisions people made on session pull requests from the approval page');
|
|
634
|
+
reviewCommand
|
|
635
|
+
.command('list')
|
|
636
|
+
.description('report each open session pull request with its decision state: awaiting, approved, changes-requested, needs-reapproval or blocked')
|
|
637
|
+
.action(async (_cmdOpts, cmd) => {
|
|
638
|
+
const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
|
|
639
|
+
result = await runCommand('review.list', runEnv, jsonMode, async () => {
|
|
640
|
+
const store = await openStore(runEnv, { root });
|
|
641
|
+
return reviewListCommand.execute(runEnv, store);
|
|
642
|
+
});
|
|
643
|
+
});
|
|
588
644
|
const sessionCommand = program.command('session').description('manage session worktrees');
|
|
589
645
|
sessionCommand
|
|
590
646
|
.command('start')
|