@plebeiantech/lat.md 0.12.3-fork.1

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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/src/cli/check-frontmatter.d.ts +12 -0
  4. package/dist/src/cli/check-frontmatter.js +44 -0
  5. package/dist/src/cli/check-mode.d.ts +6 -0
  6. package/dist/src/cli/check-mode.js +303 -0
  7. package/dist/src/cli/check-status.d.ts +74 -0
  8. package/dist/src/cli/check-status.js +217 -0
  9. package/dist/src/cli/check.d.ts +45 -0
  10. package/dist/src/cli/check.js +777 -0
  11. package/dist/src/cli/checklist-menu.d.ts +12 -0
  12. package/dist/src/cli/checklist-menu.js +111 -0
  13. package/dist/src/cli/comment-guard.d.ts +16 -0
  14. package/dist/src/cli/comment-guard.js +111 -0
  15. package/dist/src/cli/comment-reminder.d.ts +62 -0
  16. package/dist/src/cli/comment-reminder.js +210 -0
  17. package/dist/src/cli/context.d.ts +11 -0
  18. package/dist/src/cli/context.js +58 -0
  19. package/dist/src/cli/expand.d.ts +8 -0
  20. package/dist/src/cli/expand.js +94 -0
  21. package/dist/src/cli/gen-index.d.ts +45 -0
  22. package/dist/src/cli/gen-index.js +235 -0
  23. package/dist/src/cli/gen.d.ts +6 -0
  24. package/dist/src/cli/gen.js +42 -0
  25. package/dist/src/cli/graph.d.ts +7 -0
  26. package/dist/src/cli/graph.js +47 -0
  27. package/dist/src/cli/hook.d.ts +1 -0
  28. package/dist/src/cli/hook.js +432 -0
  29. package/dist/src/cli/index.d.ts +2 -0
  30. package/dist/src/cli/index.js +307 -0
  31. package/dist/src/cli/init.d.ts +9 -0
  32. package/dist/src/cli/init.js +1031 -0
  33. package/dist/src/cli/link-scheme.d.ts +54 -0
  34. package/dist/src/cli/link-scheme.js +101 -0
  35. package/dist/src/cli/locate.d.ts +2 -0
  36. package/dist/src/cli/locate.js +17 -0
  37. package/dist/src/cli/refs.d.ts +22 -0
  38. package/dist/src/cli/refs.js +229 -0
  39. package/dist/src/cli/reindex.d.ts +13 -0
  40. package/dist/src/cli/reindex.js +136 -0
  41. package/dist/src/cli/search.d.ts +36 -0
  42. package/dist/src/cli/search.js +217 -0
  43. package/dist/src/cli/section.d.ts +43 -0
  44. package/dist/src/cli/section.js +252 -0
  45. package/dist/src/cli/select-menu.d.ts +13 -0
  46. package/dist/src/cli/select-menu.js +100 -0
  47. package/dist/src/cli/templates.d.ts +1 -0
  48. package/dist/src/cli/templates.js +15 -0
  49. package/dist/src/cli/ui.d.ts +11 -0
  50. package/dist/src/cli/ui.js +34 -0
  51. package/dist/src/code-refs.d.ts +17 -0
  52. package/dist/src/code-refs.js +277 -0
  53. package/dist/src/config.d.ts +29 -0
  54. package/dist/src/config.js +83 -0
  55. package/dist/src/context.d.ts +23 -0
  56. package/dist/src/context.js +11 -0
  57. package/dist/src/extensions/wiki-link/from-markdown.d.ts +5 -0
  58. package/dist/src/extensions/wiki-link/from-markdown.js +34 -0
  59. package/dist/src/extensions/wiki-link/index.d.ts +4 -0
  60. package/dist/src/extensions/wiki-link/index.js +3 -0
  61. package/dist/src/extensions/wiki-link/syntax.d.ts +14 -0
  62. package/dist/src/extensions/wiki-link/syntax.js +121 -0
  63. package/dist/src/extensions/wiki-link/to-markdown.d.ts +5 -0
  64. package/dist/src/extensions/wiki-link/to-markdown.js +28 -0
  65. package/dist/src/extensions/wiki-link/types.d.ts +34 -0
  66. package/dist/src/extensions/wiki-link/types.js +1 -0
  67. package/dist/src/format.d.ts +8 -0
  68. package/dist/src/format.js +43 -0
  69. package/dist/src/graph-export.d.ts +60 -0
  70. package/dist/src/graph-export.js +309 -0
  71. package/dist/src/init-version.d.ts +10 -0
  72. package/dist/src/init-version.js +49 -0
  73. package/dist/src/knowledge/bd.d.ts +2 -0
  74. package/dist/src/knowledge/bd.js +107 -0
  75. package/dist/src/knowledge/claude-memory.d.ts +13 -0
  76. package/dist/src/knowledge/claude-memory.js +204 -0
  77. package/dist/src/knowledge/cq.d.ts +2 -0
  78. package/dist/src/knowledge/cq.js +74 -0
  79. package/dist/src/knowledge/index.d.ts +49 -0
  80. package/dist/src/knowledge/index.js +271 -0
  81. package/dist/src/knowledge/ranking.d.ts +17 -0
  82. package/dist/src/knowledge/ranking.js +62 -0
  83. package/dist/src/knowledge/session.d.ts +46 -0
  84. package/dist/src/knowledge/session.js +203 -0
  85. package/dist/src/knowledge/types.d.ts +47 -0
  86. package/dist/src/knowledge/types.js +10 -0
  87. package/dist/src/lattice.d.ts +108 -0
  88. package/dist/src/lattice.js +816 -0
  89. package/dist/src/mcp/server.d.ts +1 -0
  90. package/dist/src/mcp/server.js +58 -0
  91. package/dist/src/parser.d.ts +3 -0
  92. package/dist/src/parser.js +18 -0
  93. package/dist/src/search/db.d.ts +16 -0
  94. package/dist/src/search/db.js +54 -0
  95. package/dist/src/search/embedder.d.ts +25 -0
  96. package/dist/src/search/embedder.js +58 -0
  97. package/dist/src/search/index.d.ts +9 -0
  98. package/dist/src/search/index.js +66 -0
  99. package/dist/src/search/search.d.ts +9 -0
  100. package/dist/src/search/search.js +16 -0
  101. package/dist/src/source-parser.d.ts +27 -0
  102. package/dist/src/source-parser.js +916 -0
  103. package/dist/src/untrusted.d.ts +24 -0
  104. package/dist/src/untrusted.js +97 -0
  105. package/dist/src/version.d.ts +7 -0
  106. package/dist/src/version.js +39 -0
  107. package/dist/src/view/client/assets/index-B0n0u03y.css +1 -0
  108. package/dist/src/view/client/assets/index-xm2_px4q.js +23 -0
  109. package/dist/src/view/client/index.html +14 -0
  110. package/dist/src/view/diagnostics.d.ts +5 -0
  111. package/dist/src/view/diagnostics.js +171 -0
  112. package/dist/src/view/git-diff.d.ts +3 -0
  113. package/dist/src/view/git-diff.js +255 -0
  114. package/dist/src/view/git.d.ts +22 -0
  115. package/dist/src/view/git.js +193 -0
  116. package/dist/src/view/highlight.d.ts +2 -0
  117. package/dist/src/view/highlight.js +3767 -0
  118. package/dist/src/view/markdown.d.ts +22 -0
  119. package/dist/src/view/markdown.js +322 -0
  120. package/dist/src/view/protocol.d.ts +89 -0
  121. package/dist/src/view/protocol.js +1 -0
  122. package/dist/src/view/references.d.ts +62 -0
  123. package/dist/src/view/references.js +345 -0
  124. package/dist/src/view/repository.d.ts +12 -0
  125. package/dist/src/view/repository.js +167 -0
  126. package/dist/src/view/search.d.ts +14 -0
  127. package/dist/src/view/search.js +64 -0
  128. package/dist/src/view/server.d.ts +20 -0
  129. package/dist/src/view/server.js +233 -0
  130. package/dist/src/view/store.d.ts +57 -0
  131. package/dist/src/view/store.js +404 -0
  132. package/dist/src/walk.d.ts +18 -0
  133. package/dist/src/walk.js +27 -0
  134. package/package.json +85 -0
  135. package/templates/AGENTS.md +118 -0
  136. package/templates/README +1 -0
  137. package/templates/cursor-rules.md +77 -0
  138. package/templates/init/lat.md +1 -0
  139. package/templates/logo-dark.svg +182 -0
  140. package/templates/logo-light.svg +182 -0
  141. package/templates/logo.txt +7 -0
  142. package/templates/opencode-plugin.ts +180 -0
  143. package/templates/pi-extension.ts +364 -0
  144. package/templates/skill/SKILL.md +189 -0
@@ -0,0 +1,217 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { dirname, relative } from 'node:path';
4
+ import { listLatticeFiles, parseFrontmatter } from '../lattice.js';
5
+ import { toPosix } from '../walk.js';
6
+ import { quoteUntrusted } from '../untrusted.js';
7
+ import { fencedLineMask } from './gen-index.js';
8
+ /**
9
+ * Who wrote a document, and whether a person has checked it.
10
+ *
11
+ * lat.md states that agents write the graph. Without this field an unmarked
12
+ * claim written by an agent reaches the model carrying exactly the authority
13
+ * of one a person read and approved.
14
+ */
15
+ export const DOC_STATUSES = ['human-reviewed', 'agent-extracted'];
16
+ /**
17
+ * The shortest `reviewed-hash` prefix that is accepted as a match. A full
18
+ * SHA-256 is 64 hex characters and unpleasant to keep in frontmatter, so an
19
+ * author may record an abbreviated form. Eight characters is 32 bits — far
20
+ * past accidental collision for the handful of revisions one document sees,
21
+ * and this value is a staleness signal, not a security boundary.
22
+ */
23
+ const MIN_HASH_PREFIX = 8;
24
+ const HEX = /^[0-9a-f]+$/i;
25
+ /**
26
+ * Read the provenance fields out of a document's frontmatter.
27
+ *
28
+ * Fields live under the top-level `lat:` mapping, so they are read off
29
+ * `LatFrontmatter.raw` rather than being promoted to named fields. Adding a
30
+ * named field would mean editing `parseFrontmatter`, and keeping that function
31
+ * closed to per-feature edits is the whole reason `raw` exists.
32
+ */
33
+ export function readProvenance(content) {
34
+ const raw = parseFrontmatter(content).raw;
35
+ const result = {};
36
+ const status = raw['status'];
37
+ if (typeof status === 'string')
38
+ result.status = status;
39
+ const hash = raw['reviewed-hash'];
40
+ if (typeof hash === 'string')
41
+ result.reviewedHash = hash;
42
+ else if (typeof hash === 'number')
43
+ result.reviewedHash = String(hash);
44
+ return result;
45
+ }
46
+ /**
47
+ * Hash the prose a review actually covered.
48
+ *
49
+ * A plain `status` field becomes a lie the moment an agent edits the document:
50
+ * the field still says a person checked the text, but the text is no longer
51
+ * the text that person read. Capturing the content at review time turns that
52
+ * silent failure into a check.
53
+ *
54
+ * Frontmatter is excluded deliberately: adding an unrelated frontmatter key
55
+ * does not change a single claim in the prose, and invalidating a review for
56
+ * it would train authors to re-stamp the hash without re-reading — which
57
+ * costs the field its meaning.
58
+ *
59
+ * Heading TEXT is excluded for the same reason — re-titling a section changes
60
+ * no claim in the prose. But a heading LINE is not: adding or removing a
61
+ * heading changes the document's structure (a new section exists that no one
62
+ * has reviewed), and that must flip the hash even though no non-heading line
63
+ * changed. So each heading line is reduced to its `#` marker (which carries
64
+ * its level and position) rather than dropped outright — retitling a section
65
+ * leaves the marker alone, but appending or removing a heading changes the
66
+ * sequence of markers and therefore the hash. (Swapping two headings of the
67
+ * same level produces the same marker sequence and is not detected — a
68
+ * narrower version of the blind spot this fix closes.)
69
+ */
70
+ export function hashReviewedBody(content) {
71
+ // Normalize line endings BEFORE stripping frontmatter: the delimiter regex
72
+ // is written with bare \n, so on a CRLF-saved document it would not match
73
+ // and the whole frontmatter block — reviewed-hash included — would be
74
+ // hashed as body, making every such review spuriously stale.
75
+ const normalized = content.replace(/\r\n/g, '\n');
76
+ const withoutFrontmatter = normalized.replace(/^---\n[\s\S]*?\n---\n?/, '');
77
+ const lines = withoutFrontmatter.split('\n');
78
+ // A `#`-prefixed line inside a fenced code block is a shell comment, not a
79
+ // heading. Collapsing it would hand an editor a free, unhashed rewrite slot
80
+ // in every fenced example. The same mask the index reader and writer share.
81
+ const fenced = fencedLineMask(lines);
82
+ const body = lines
83
+ .map((line, i) => {
84
+ if (fenced[i])
85
+ return line;
86
+ const heading = /^(#{1,6})\s/.exec(line);
87
+ return heading ? heading[1] : line;
88
+ })
89
+ // Trailing whitespace is invisible in a diff and must not flip a review.
90
+ .map((line) => line.replace(/[ \t]+$/, ''))
91
+ .join('\n')
92
+ .trim();
93
+ return createHash('sha256').update(body, 'utf-8').digest('hex');
94
+ }
95
+ function hashMatches(recorded, actual) {
96
+ const want = recorded.trim().toLowerCase();
97
+ if (want.length < MIN_HASH_PREFIX || !HEX.test(want))
98
+ return false;
99
+ return actual.startsWith(want);
100
+ }
101
+ /**
102
+ * The one-line provenance annotation for `lat section` and `lat search`, or
103
+ * null when the document says nothing about its provenance.
104
+ *
105
+ * A document with no `status` produces nothing at all. Most documents in most
106
+ * repositories have no status, and a line on every one of them would be noise
107
+ * that readers learn to skip — which would cost the warning its force on the
108
+ * documents that do carry one.
109
+ */
110
+ export function provenanceNote(content) {
111
+ const { status, reviewedHash } = readProvenance(content);
112
+ if (status === undefined)
113
+ return null;
114
+ if (status === 'agent-extracted') {
115
+ return {
116
+ kind: 'unreviewed',
117
+ text: '[unreviewed -- written by an agent, not checked by a person]',
118
+ };
119
+ }
120
+ if (status === 'human-reviewed') {
121
+ // No hash means an older tree that predates the field. Saying nothing is
122
+ // deliberate: an upgrade must not repaint an existing graph with warnings.
123
+ if (reviewedHash === undefined) {
124
+ return { kind: 'reviewed', text: '[human-reviewed]' };
125
+ }
126
+ if (hashMatches(reviewedHash, hashReviewedBody(content))) {
127
+ return { kind: 'reviewed', text: '[human-reviewed]' };
128
+ }
129
+ return {
130
+ kind: 'stale',
131
+ text: '[stale review -- the text changed after a person checked it]',
132
+ };
133
+ }
134
+ // An unknown value is repository text and is quoted as such. `lat check
135
+ // status` reports it; the reader is told only that it means nothing here.
136
+ return {
137
+ kind: 'unreviewed',
138
+ text: `[unrecognized status ${quoteUntrusted(status, 40)} -- treat as unreviewed]`,
139
+ };
140
+ }
141
+ /** Colourize a note for terminal output. */
142
+ export function formatProvenanceNote(note, s) {
143
+ if (note.kind === 'reviewed')
144
+ return s.green(note.text);
145
+ return s.yellow(note.text);
146
+ }
147
+ /**
148
+ * Report documents whose recorded review no longer describes their text.
149
+ *
150
+ * This is a static validation. It needs no history and no database, and it
151
+ * catches most of what a temporal graph would answer.
152
+ */
153
+ export async function checkStatus(latticeDir, projectRoot = dirname(latticeDir)) {
154
+ const files = await listLatticeFiles(latticeDir);
155
+ const errors = [];
156
+ for (const file of files) {
157
+ const content = await readFile(file, 'utf-8');
158
+ const relPath = relative(process.cwd(), file);
159
+ const target = toPosix(relative(projectRoot, file)).replace(/\.md$/, '');
160
+ const { status, reviewedHash } = readProvenance(content);
161
+ if (status === undefined) {
162
+ if (reviewedHash !== undefined) {
163
+ errors.push({
164
+ file: relPath,
165
+ line: 1,
166
+ target,
167
+ message: `document records a reviewed-hash but no status — add "status: human-reviewed", or drop the hash`,
168
+ });
169
+ }
170
+ continue;
171
+ }
172
+ if (!DOC_STATUSES.includes(status)) {
173
+ errors.push({
174
+ file: relPath,
175
+ line: 1,
176
+ target,
177
+ message: `document declares unknown status ${quoteUntrusted(status, 40)} — use one of: human-reviewed, agent-extracted`,
178
+ });
179
+ continue;
180
+ }
181
+ if (status === 'agent-extracted') {
182
+ if (reviewedHash !== undefined) {
183
+ errors.push({
184
+ file: relPath,
185
+ line: 1,
186
+ target,
187
+ message: `document is agent-extracted but records a reviewed-hash — a hash records that a person checked the text, so set "status: human-reviewed" or drop the hash`,
188
+ });
189
+ }
190
+ continue;
191
+ }
192
+ // human-reviewed. No hash is not an error: existing trees must not turn
193
+ // red on upgrade. It simply buys no staleness detection.
194
+ if (reviewedHash === undefined)
195
+ continue;
196
+ const actual = hashReviewedBody(content);
197
+ const recorded = reviewedHash.trim().toLowerCase();
198
+ if (!HEX.test(recorded) || recorded.length < MIN_HASH_PREFIX) {
199
+ errors.push({
200
+ file: relPath,
201
+ line: 1,
202
+ target,
203
+ message: `reviewed-hash must be at least ${MIN_HASH_PREFIX} hex characters — record "reviewed-hash: ${actual}"`,
204
+ });
205
+ continue;
206
+ }
207
+ if (!actual.startsWith(recorded)) {
208
+ errors.push({
209
+ file: relPath,
210
+ line: 1,
211
+ target,
212
+ message: `stale review — the text changed after it was reviewed. Re-read it, then record "reviewed-hash: ${actual}"`,
213
+ });
214
+ }
215
+ }
216
+ return errors;
217
+ }
@@ -0,0 +1,45 @@
1
+ import type { CmdContext, CmdResult } from '../context.js';
2
+ export type CheckError = {
3
+ file: string;
4
+ line: number;
5
+ target: string;
6
+ message: string;
7
+ };
8
+ /** Format an ambiguous-ref error as structured markdown-like text. */
9
+ export declare function ambiguousRefMessage(target: string, candidates: string[], suggested: string | null): string;
10
+ /** File counts grouped by extension (e.g. { ".ts": 5, ".py": 2 }). */
11
+ export type FileStats = Record<string, number>;
12
+ export type CheckResult = {
13
+ errors: CheckError[];
14
+ files: FileStats;
15
+ };
16
+ /**
17
+ * Try resolving a wiki link target as a source code reference.
18
+ * Returns null if the reference is valid, or an error message string.
19
+ */
20
+ export declare function sourceRefError(target: string, projectRoot: string): Promise<string | null>;
21
+ export declare function checkMd(latticeDir: string, projectRoot?: string): Promise<CheckResult>;
22
+ export declare function checkLinks(latticeDir: string): Promise<CheckError[]>;
23
+ export declare function checkCodeRefs(latticeDir: string, projectRoot?: string): Promise<CheckResult>;
24
+ export type IndexError = {
25
+ dir: string;
26
+ message: string;
27
+ snippet?: string;
28
+ };
29
+ export type CheckIndexOptions = {
30
+ /**
31
+ * Generate/rewrite index files instead of reporting errors for them.
32
+ * Non-.md-file errors are still reported — --fix only ever writes markdown.
33
+ */
34
+ fix?: boolean;
35
+ };
36
+ export declare function checkIndex(latticeDir: string, opts?: CheckIndexOptions): Promise<IndexError[]>;
37
+ export declare function checkSections(latticeDir: string, projectRoot?: string): Promise<CheckError[]>;
38
+ export declare function checkAllCommand(ctx: CmdContext, opts?: CheckIndexOptions): Promise<CmdResult>;
39
+ export declare function checkMdCommand(ctx: CmdContext): Promise<CmdResult>;
40
+ export declare function checkLinksCommand(ctx: CmdContext): Promise<CmdResult>;
41
+ export declare function checkCodeRefsCommand(ctx: CmdContext): Promise<CmdResult>;
42
+ export declare function checkIndexCommand(ctx: CmdContext, opts?: CheckIndexOptions): Promise<CmdResult>;
43
+ export declare function checkSectionsCommand(ctx: CmdContext): Promise<CmdResult>;
44
+ export declare function checkModeCommand(ctx: CmdContext): Promise<CmdResult>;
45
+ export declare function checkStatusCommand(ctx: CmdContext): Promise<CmdResult>;