@monoes/monomindcli 2.14.1 → 2.15.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/.claude/helpers/control-start.cjs +10 -13
- package/.claude/skills/monodesign/scripts/context.mjs +4 -4
- package/.claude/skills/monodesign/scripts/critique-storage.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detect-csp.mjs +1 -6
- package/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +16 -18
- package/.claude/skills/monodesign/scripts/detector/cli/main.mjs +3 -3
- package/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +67 -47
- package/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +6 -6
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +6 -5
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +6 -6
- package/.claude/skills/monodesign/scripts/detector/fix/index.mjs +3 -3
- package/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +24 -25
- package/.claude/skills/monodesign/scripts/detector/shared/color.mjs +2 -2
- package/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +2 -2
- package/.claude/skills/monodesign/scripts/hook-admin.mjs +6 -6
- package/.claude/skills/monodesign/scripts/hook-before-edit.mjs +4 -4
- package/.claude/skills/monodesign/scripts/hook-lib.mjs +20 -11
- package/.claude/skills/monodesign/scripts/hook.mjs +1 -1
- package/.claude/skills/monodesign/scripts/lib/design-parser.mjs +9 -42
- package/.claude/skills/monodesign/scripts/lib/is-generated.mjs +1 -1
- package/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +5 -5
- package/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live/event-validation.mjs +13 -13
- package/.claude/skills/monodesign/scripts/live/manual-apply.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live/session-store.mjs +5 -5
- package/.claude/skills/monodesign/scripts/live/svelte-component.mjs +13 -13
- package/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live/ui-core.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live-accept.mjs +24 -24
- package/.claude/skills/monodesign/scripts/live-browser-dom.js +8 -7
- package/.claude/skills/monodesign/scripts/live-browser-session.js +8 -7
- package/.claude/skills/monodesign/scripts/live-browser.js +405 -432
- package/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +6 -6
- package/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +2 -2
- package/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live-inject.mjs +7 -7
- package/.claude/skills/monodesign/scripts/live-insert.mjs +11 -11
- package/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live-poll.mjs +5 -5
- package/.claude/skills/monodesign/scripts/live-server.mjs +10 -10
- package/.claude/skills/monodesign/scripts/live-wrap.mjs +31 -41
- package/.claude/skills/monodesign/scripts/live.mjs +5 -5
- package/.claude/skills/monodesign/scripts/palette.mjs +3 -1
- package/.claude/skills/monodesign/scripts/pin.mjs +1 -1
- package/dist/src/commands/doc-filters.d.ts.map +1 -1
- package/dist/src/commands/doc-filters.js +6 -0
- package/dist/src/commands/doc-filters.js.map +1 -1
- package/dist/src/commands/doc-library.d.ts +2 -1
- package/dist/src/commands/doc-library.d.ts.map +1 -1
- package/dist/src/commands/doc-library.js +66 -2
- package/dist/src/commands/doc-library.js.map +1 -1
- package/dist/src/commands/doc.d.ts.map +1 -1
- package/dist/src/commands/doc.js +2 -0
- package/dist/src/commands/doc.js.map +1 -1
- package/dist/src/commands/ui.d.ts.map +1 -1
- package/dist/src/commands/ui.js +60 -0
- package/dist/src/commands/ui.js.map +1 -1
- package/dist/src/knowledge/capture-envelope.d.ts +5 -0
- package/dist/src/knowledge/capture-envelope.d.ts.map +1 -1
- package/dist/src/knowledge/capture-envelope.js +2 -0
- package/dist/src/knowledge/capture-envelope.js.map +1 -1
- package/dist/src/knowledge/document-chunking.d.ts +42 -0
- package/dist/src/knowledge/document-chunking.d.ts.map +1 -0
- package/dist/src/knowledge/document-chunking.js +288 -0
- package/dist/src/knowledge/document-chunking.js.map +1 -0
- package/dist/src/knowledge/document-index.d.ts +124 -0
- package/dist/src/knowledge/document-index.d.ts.map +1 -0
- package/dist/src/knowledge/document-index.js +314 -0
- package/dist/src/knowledge/document-index.js.map +1 -0
- package/dist/src/knowledge/document-ingest.d.ts +23 -0
- package/dist/src/knowledge/document-ingest.d.ts.map +1 -0
- package/dist/src/knowledge/document-ingest.js +368 -0
- package/dist/src/knowledge/document-ingest.js.map +1 -0
- package/dist/src/knowledge/document-pipeline.d.ts +26 -208
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +25 -1104
- package/dist/src/knowledge/document-pipeline.js.map +1 -1
- package/dist/src/knowledge/document-search.d.ts +27 -0
- package/dist/src/knowledge/document-search.d.ts.map +1 -0
- package/dist/src/knowledge/document-search.js +138 -0
- package/dist/src/knowledge/document-search.js.map +1 -0
- package/dist/src/knowledge/document-store.d.ts +28 -0
- package/dist/src/knowledge/document-store.d.ts.map +1 -0
- package/dist/src/knowledge/document-store.js +61 -0
- package/dist/src/knowledge/document-store.js.map +1 -0
- package/dist/src/knowledge/document-types.d.ts +103 -0
- package/dist/src/knowledge/document-types.d.ts.map +1 -0
- package/dist/src/knowledge/document-types.js +12 -0
- package/dist/src/knowledge/document-types.js.map +1 -0
- package/dist/src/knowledge/highlights.d.ts +168 -0
- package/dist/src/knowledge/highlights.d.ts.map +1 -0
- package/dist/src/knowledge/highlights.js +311 -0
- package/dist/src/knowledge/highlights.js.map +1 -0
- package/dist/src/knowledge/lookup.d.ts +80 -0
- package/dist/src/knowledge/lookup.d.ts.map +1 -0
- package/dist/src/knowledge/lookup.js +156 -0
- package/dist/src/knowledge/lookup.js.map +1 -0
- package/dist/src/knowledge/okf-bundle.d.ts +19 -0
- package/dist/src/knowledge/okf-bundle.d.ts.map +1 -0
- package/dist/src/knowledge/okf-bundle.js +106 -0
- package/dist/src/knowledge/okf-bundle.js.map +1 -0
- package/dist/src/knowledge/profile-store.d.ts +134 -0
- package/dist/src/knowledge/profile-store.d.ts.map +1 -0
- package/dist/src/knowledge/profile-store.js +237 -0
- package/dist/src/knowledge/profile-store.js.map +1 -0
- package/dist/src/orgrt/agent-runner.d.ts +4 -0
- package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
- package/dist/src/orgrt/agent-runner.js +22 -0
- package/dist/src/orgrt/agent-runner.js.map +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
- package/dist/src/orgrt/antigravity-runner.js +2 -1
- package/dist/src/orgrt/antigravity-runner.js.map +1 -1
- package/dist/src/orgrt/authority-mask.d.ts +32 -0
- package/dist/src/orgrt/authority-mask.d.ts.map +1 -0
- package/dist/src/orgrt/authority-mask.js +135 -0
- package/dist/src/orgrt/authority-mask.js.map +1 -0
- package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
- package/dist/src/orgrt/codex-runner.js +2 -1
- package/dist/src/orgrt/codex-runner.js.map +1 -1
- package/dist/src/orgrt/copilot-runner.d.ts.map +1 -1
- package/dist/src/orgrt/copilot-runner.js +2 -1
- package/dist/src/orgrt/copilot-runner.js.map +1 -1
- package/dist/src/orgrt/crush-runner.d.ts.map +1 -1
- package/dist/src/orgrt/crush-runner.js +6 -1
- package/dist/src/orgrt/crush-runner.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts +4 -0
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +13 -2
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/decisions.d.ts +9 -0
- package/dist/src/orgrt/decisions.d.ts.map +1 -1
- package/dist/src/orgrt/decisions.js +32 -5
- package/dist/src/orgrt/decisions.js.map +1 -1
- package/dist/src/orgrt/file-roots.d.ts +2 -1
- package/dist/src/orgrt/file-roots.d.ts.map +1 -1
- package/dist/src/orgrt/file-roots.js +7 -3
- package/dist/src/orgrt/file-roots.js.map +1 -1
- package/dist/src/orgrt/grok-runner.d.ts.map +1 -1
- package/dist/src/orgrt/grok-runner.js +2 -1
- package/dist/src/orgrt/grok-runner.js.map +1 -1
- package/dist/src/orgrt/hermes-runner.d.ts.map +1 -1
- package/dist/src/orgrt/hermes-runner.js +2 -1
- package/dist/src/orgrt/hermes-runner.js.map +1 -1
- package/dist/src/orgrt/inbox.d.ts.map +1 -1
- package/dist/src/orgrt/inbox.js +70 -4
- package/dist/src/orgrt/inbox.js.map +1 -1
- package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/kimicode-runner.js +2 -1
- package/dist/src/orgrt/kimicode-runner.js.map +1 -1
- package/dist/src/orgrt/opencode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/opencode-runner.js +3 -2
- package/dist/src/orgrt/opencode-runner.js.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.js +3 -2
- package/dist/src/orgrt/pi-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/pi-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-runner.js +2 -1
- package/dist/src/orgrt/pi-runner.js.map +1 -1
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +3 -0
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.js +3 -2
- package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/qwen-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-runner.js +2 -1
- package/dist/src/orgrt/qwen-runner.js.map +1 -1
- package/dist/src/orgrt/role-sandbox.d.ts +21 -0
- package/dist/src/orgrt/role-sandbox.d.ts.map +1 -1
- package/dist/src/orgrt/role-sandbox.js +31 -6
- package/dist/src/orgrt/role-sandbox.js.map +1 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +21 -2
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +3 -0
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +1 -0
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +5 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +23 -1
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/ui/dashboard.html +28 -848
- package/dist/src/ui/human-auth.mjs +103 -0
- package/dist/src/ui/org-hil.mjs +86 -37
- package/dist/src/ui/org-runtime.mjs +21 -13
- package/dist/src/ui/routes-org.mjs +49 -445
- package/dist/src/ui/server.mjs +90 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document chunking — turning a document's extracted text into the enriched
|
|
3
|
+
* chunks that get embedded and stored.
|
|
4
|
+
*
|
|
5
|
+
* Two passes, in this order:
|
|
6
|
+
* 1. CHUNK — split on heading/paragraph boundaries (shared `@monoes/memory`
|
|
7
|
+
* chunker, with an inline fallback kept byte-identical to it).
|
|
8
|
+
* 2. ENRICH — replace each chunk's leaf-heading prefix with a situating blurb
|
|
9
|
+
* (doc title + full heading path + summary) so the embedding model can tell
|
|
10
|
+
* two identically-titled sections of different documents apart.
|
|
11
|
+
*
|
|
12
|
+
* Split out of document-pipeline.ts. Pure string work: no fs, no network, no
|
|
13
|
+
* store access — which is what makes chunk spans reproducible at citation time
|
|
14
|
+
* (`chunkSpans`) without re-reading anything.
|
|
15
|
+
*
|
|
16
|
+
* @module v1/cli/knowledge/document-chunking
|
|
17
|
+
*/
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
const DEFAULT_CHUNK_SIZE = 3200;
|
|
20
|
+
const DEFAULT_OVERLAP = 400;
|
|
21
|
+
// Inline fallback identical to @monoes/memory's knowledge/document-chunker.ts —
|
|
22
|
+
// used only if the dynamic import below fails (package not installed/built).
|
|
23
|
+
// Keep in sync if the shared chunker's boundary-snapping logic changes.
|
|
24
|
+
const HEADING_LINE_RE = /^#{1,6} /;
|
|
25
|
+
const FENCE_LINE_RE = /^\s{0,3}(`{3,}|~{3,})/;
|
|
26
|
+
function fenceTogglesInline(text) {
|
|
27
|
+
const toggles = [];
|
|
28
|
+
let lineStart = 0;
|
|
29
|
+
while (lineStart <= text.length) {
|
|
30
|
+
const eol = text.indexOf('\n', lineStart);
|
|
31
|
+
const line = text.slice(lineStart, eol === -1 ? undefined : eol);
|
|
32
|
+
if (FENCE_LINE_RE.test(line))
|
|
33
|
+
toggles.push(lineStart);
|
|
34
|
+
if (eol === -1)
|
|
35
|
+
break;
|
|
36
|
+
lineStart = eol + 1;
|
|
37
|
+
}
|
|
38
|
+
return toggles;
|
|
39
|
+
}
|
|
40
|
+
function inFenceInline(toggles, pos) {
|
|
41
|
+
let lo = 0, hi = toggles.length;
|
|
42
|
+
while (lo < hi) {
|
|
43
|
+
const mid = (lo + hi) >> 1;
|
|
44
|
+
if (toggles[mid] <= pos)
|
|
45
|
+
lo = mid + 1;
|
|
46
|
+
else
|
|
47
|
+
hi = mid;
|
|
48
|
+
}
|
|
49
|
+
return (lo & 1) === 1;
|
|
50
|
+
}
|
|
51
|
+
function lastHeadingBefore(text, pos, toggles) {
|
|
52
|
+
let i = text.lastIndexOf('\n#', pos - 1);
|
|
53
|
+
while (i !== -1) {
|
|
54
|
+
const eol = text.indexOf('\n', i + 1);
|
|
55
|
+
const line = text.slice(i + 1, eol === -1 ? undefined : eol);
|
|
56
|
+
if (HEADING_LINE_RE.test(line) && !inFenceInline(toggles, i + 1))
|
|
57
|
+
return line.replace(/^#+ /, '').trim();
|
|
58
|
+
i = i > 0 ? text.lastIndexOf('\n#', i - 1) : -1; // fromIndex -1 clamps to 0 — would loop on a match at 0
|
|
59
|
+
}
|
|
60
|
+
const firstEol = text.indexOf('\n');
|
|
61
|
+
const firstLine = firstEol === -1 ? text : text.slice(0, firstEol);
|
|
62
|
+
return HEADING_LINE_RE.test(firstLine) &&
|
|
63
|
+
!inFenceInline(toggles, 0) &&
|
|
64
|
+
firstEol !== -1 &&
|
|
65
|
+
firstEol < pos
|
|
66
|
+
? firstLine.replace(/^#+ /, '').trim()
|
|
67
|
+
: null;
|
|
68
|
+
}
|
|
69
|
+
function chunkDocumentInline(docId, text) {
|
|
70
|
+
if (text.includes('\r\n'))
|
|
71
|
+
text = text.replace(/\r\n/g, '\n');
|
|
72
|
+
if (text.length === 0)
|
|
73
|
+
return [];
|
|
74
|
+
const toggles = fenceTogglesInline(text);
|
|
75
|
+
const chunks = [];
|
|
76
|
+
let startChar = 0;
|
|
77
|
+
let chunkIndex = 0;
|
|
78
|
+
while (startChar < text.length) {
|
|
79
|
+
let endChar = Math.min(startChar + DEFAULT_CHUNK_SIZE, text.length);
|
|
80
|
+
let brokeAtHeading = false;
|
|
81
|
+
if (endChar < text.length) {
|
|
82
|
+
const windowStart = Math.max(startChar, endChar - Math.floor(DEFAULT_CHUNK_SIZE * 0.2));
|
|
83
|
+
const window = text.slice(windowStart, endChar);
|
|
84
|
+
let h = window.lastIndexOf('\n#');
|
|
85
|
+
while (h !== -1) {
|
|
86
|
+
const eol = window.indexOf('\n', h + 1);
|
|
87
|
+
const line = window.slice(h + 1, eol === -1 ? undefined : eol);
|
|
88
|
+
if (HEADING_LINE_RE.test(line) &&
|
|
89
|
+
windowStart + h > startChar &&
|
|
90
|
+
!inFenceInline(toggles, windowStart + h + 1))
|
|
91
|
+
break;
|
|
92
|
+
h = h > 0 ? window.lastIndexOf('\n#', h - 1) : -1;
|
|
93
|
+
}
|
|
94
|
+
if (h !== -1 && windowStart + h > startChar) {
|
|
95
|
+
endChar = windowStart + h + 1;
|
|
96
|
+
brokeAtHeading = true;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
let lastParagraph = window.lastIndexOf('\n\n');
|
|
100
|
+
while (lastParagraph > 0 && inFenceInline(toggles, windowStart + lastParagraph + 1)) {
|
|
101
|
+
lastParagraph = window.lastIndexOf('\n\n', lastParagraph - 1);
|
|
102
|
+
}
|
|
103
|
+
if (lastParagraph === 0 && inFenceInline(toggles, windowStart + 1))
|
|
104
|
+
lastParagraph = -1;
|
|
105
|
+
if (lastParagraph !== -1)
|
|
106
|
+
endChar = windowStart + lastParagraph + 2;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
let chunkText = text.slice(startChar, endChar);
|
|
110
|
+
const heading = lastHeadingBefore(text, startChar + 1, toggles);
|
|
111
|
+
if (heading && !HEADING_LINE_RE.test(chunkText.trimStart()))
|
|
112
|
+
chunkText = `§ ${heading}\n${chunkText}`;
|
|
113
|
+
chunks.push({
|
|
114
|
+
chunkId: `${docId}:${chunkIndex}`,
|
|
115
|
+
docId,
|
|
116
|
+
text: chunkText,
|
|
117
|
+
startChar,
|
|
118
|
+
endChar,
|
|
119
|
+
chunkIndex,
|
|
120
|
+
});
|
|
121
|
+
chunkIndex++;
|
|
122
|
+
if (endChar >= text.length)
|
|
123
|
+
break;
|
|
124
|
+
startChar += brokeAtHeading
|
|
125
|
+
? Math.max(1, endChar - startChar)
|
|
126
|
+
: Math.max(1, endChar - startChar - DEFAULT_OVERLAP);
|
|
127
|
+
}
|
|
128
|
+
return chunks;
|
|
129
|
+
}
|
|
130
|
+
export async function chunkDocument(docId, text) {
|
|
131
|
+
try {
|
|
132
|
+
const mod = await import('@monoes/memory');
|
|
133
|
+
return mod.chunkDocument(docId, text, DEFAULT_CHUNK_SIZE, DEFAULT_OVERLAP);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return chunkDocumentInline(docId, text);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// ── Contextual chunk enrichment (item 6a) ─────────────────────────
|
|
140
|
+
// Prepend a situating blurb per chunk before embedding: full heading
|
|
141
|
+
// path + doc title + doc summary. No LLM, no network.
|
|
142
|
+
//
|
|
143
|
+
// The `§ heading` prefix `chunkDocumentInline` writes provides only the nearest
|
|
144
|
+
// leaf heading. This replaces it with doc-level context so the embedding
|
|
145
|
+
// model can distinguish "Memory Coordination" in a hooks doc from
|
|
146
|
+
// "Memory Coordination" in a concepts doc.
|
|
147
|
+
//
|
|
148
|
+
// Applied at INGEST TIME (after chunking, before embedding), so:
|
|
149
|
+
// - Works identically regardless of which chunker ran (inline or @monoes/memory)
|
|
150
|
+
// - Works identically for both better-sqlite3 and sql.js (pure string ops)
|
|
151
|
+
// - Zero dependencies, zero network
|
|
152
|
+
const SECTION_PREFIX_RE = /^§ [^\n]+\n/;
|
|
153
|
+
/** Cap on the situating summary prepended to each chunk, ellipsis included. */
|
|
154
|
+
const SUMMARY_MAX_CHARS = 120;
|
|
155
|
+
function extractDocTitle(text, filePath) {
|
|
156
|
+
const eol = text.indexOf('\n');
|
|
157
|
+
const first = eol === -1 ? text : text.slice(0, eol);
|
|
158
|
+
return HEADING_LINE_RE.test(first)
|
|
159
|
+
? first.replace(/^#+ /, '').trim()
|
|
160
|
+
: path.basename(filePath, path.extname(filePath)).replace(/[-_]/g, ' ');
|
|
161
|
+
}
|
|
162
|
+
function extractDocSummary(text) {
|
|
163
|
+
const lines = text.split('\n');
|
|
164
|
+
let inFence = false;
|
|
165
|
+
const parts = [];
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
if (FENCE_LINE_RE.test(line)) {
|
|
168
|
+
inFence = !inFence;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (inFence)
|
|
172
|
+
continue;
|
|
173
|
+
if (HEADING_LINE_RE.test(line)) {
|
|
174
|
+
if (parts.length > 0)
|
|
175
|
+
break;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const t = line.trim();
|
|
179
|
+
if (!t || /^[|=-]/.test(t)) {
|
|
180
|
+
if (parts.length > 0)
|
|
181
|
+
break;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
parts.push(t.startsWith('>') ? t.replace(/^>\s*/, '') : t);
|
|
185
|
+
}
|
|
186
|
+
const joined = parts.join(' ');
|
|
187
|
+
// Truncate with an ellipsis so a clipped summary is visibly clipped. The bare
|
|
188
|
+
// 150-char slice this replaces gave no signal that anything was cut, which
|
|
189
|
+
// read as a complete sentence to both a human and the embedding model.
|
|
190
|
+
return joined.length > SUMMARY_MAX_CHARS
|
|
191
|
+
? `${joined.slice(0, SUMMARY_MAX_CHARS - 3).trimEnd()}...`
|
|
192
|
+
: joined;
|
|
193
|
+
}
|
|
194
|
+
function buildHeadingHierarchy(text, toggles) {
|
|
195
|
+
const out = [];
|
|
196
|
+
const eol0 = text.indexOf('\n');
|
|
197
|
+
const line0 = eol0 === -1 ? text : text.slice(0, eol0);
|
|
198
|
+
const firstLevel = line0.match(/^(#{1,6}) /)?.[1]?.length;
|
|
199
|
+
if (firstLevel !== undefined && !inFenceInline(toggles, 0)) {
|
|
200
|
+
out.push({
|
|
201
|
+
level: firstLevel,
|
|
202
|
+
text: line0.replace(/^#+ /, '').trim(),
|
|
203
|
+
offset: 0,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
let i = text.indexOf('\n#', 0);
|
|
207
|
+
while (i !== -1) {
|
|
208
|
+
const ls = i + 1;
|
|
209
|
+
const e = text.indexOf('\n', ls);
|
|
210
|
+
const line = text.slice(ls, e === -1 ? undefined : e);
|
|
211
|
+
const level = line.match(/^(#{1,6}) /)?.[1]?.length;
|
|
212
|
+
if (level !== undefined && !inFenceInline(toggles, ls)) {
|
|
213
|
+
out.push({
|
|
214
|
+
level,
|
|
215
|
+
text: line.replace(/^#+ /, '').trim(),
|
|
216
|
+
offset: ls,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
i = text.indexOf('\n#', ls);
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
function headingPathAt(hierarchy, pos) {
|
|
224
|
+
const stack = [];
|
|
225
|
+
for (const h of hierarchy) {
|
|
226
|
+
if (h.offset >= pos)
|
|
227
|
+
break;
|
|
228
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= h.level)
|
|
229
|
+
stack.pop();
|
|
230
|
+
stack.push(h);
|
|
231
|
+
}
|
|
232
|
+
return stack.map((s) => s.text);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Replace each chunk's `§ heading` prefix with a richer situating blurb:
|
|
236
|
+
* § <doc title> · <full heading path>
|
|
237
|
+
* <doc summary for non-first chunks>
|
|
238
|
+
*
|
|
239
|
+
* First chunks that start with their own heading are left untouched (the
|
|
240
|
+
* heading IS the context). The summary line is omitted for the first
|
|
241
|
+
* chunk since it is adjacent to the summary text anyway.
|
|
242
|
+
*/
|
|
243
|
+
export function enrichChunks(chunks, fullText, filePath) {
|
|
244
|
+
if (chunks.length === 0)
|
|
245
|
+
return chunks;
|
|
246
|
+
const toggles = fenceTogglesInline(fullText);
|
|
247
|
+
const hierarchy = buildHeadingHierarchy(fullText, toggles);
|
|
248
|
+
const title = extractDocTitle(fullText, filePath);
|
|
249
|
+
const summary = extractDocSummary(fullText);
|
|
250
|
+
return chunks.map((c) => {
|
|
251
|
+
let text = c.text;
|
|
252
|
+
// First chunk starting with its own heading — the heading IS the context
|
|
253
|
+
if (c.chunkIndex === 0 && HEADING_LINE_RE.test(text.trimStart()))
|
|
254
|
+
return c;
|
|
255
|
+
// Strip the old § leaf-heading prefix; we replace it with a richer one
|
|
256
|
+
text = text.replace(SECTION_PREFIX_RE, '');
|
|
257
|
+
const hpath = headingPathAt(hierarchy, c.startChar + 1);
|
|
258
|
+
const parts = [];
|
|
259
|
+
// Title + full heading path
|
|
260
|
+
if (hpath.length > 0 && hpath[0] !== title) {
|
|
261
|
+
parts.push(`§ ${title} · ${hpath.join(' > ')}`);
|
|
262
|
+
}
|
|
263
|
+
else if (hpath.length > 1) {
|
|
264
|
+
parts.push(`§ ${hpath.join(' > ')}`);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
parts.push(`§ ${title}`);
|
|
268
|
+
}
|
|
269
|
+
// Summary for non-first chunks — they are far from the doc intro
|
|
270
|
+
if (c.chunkIndex > 0 && summary) {
|
|
271
|
+
const snip = summary.length > 120 ? `${summary.slice(0, 117)}...` : summary;
|
|
272
|
+
parts.push(snip);
|
|
273
|
+
}
|
|
274
|
+
return { ...c, text: `${parts.join('\n')}\n${text}` };
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/** Chunk spans for a text, using the SAME chunker the ingest used — this is
|
|
278
|
+
* what makes a chunk index resolvable back to a character range without
|
|
279
|
+
* storing the text twice. */
|
|
280
|
+
export async function chunkSpans(text) {
|
|
281
|
+
const chunks = await chunkDocument('cite', text);
|
|
282
|
+
return chunks.map((c) => ({
|
|
283
|
+
chunkIndex: c.chunkIndex,
|
|
284
|
+
startChar: c.startChar,
|
|
285
|
+
endChar: c.endChar,
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=document-chunking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-chunking.js","sourceRoot":"","sources":["../../../src/knowledge/document-chunking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document index — the append-only metadata log that records which
|
|
3
|
+
* documents are indexed, at which version, and whether that is still true.
|
|
4
|
+
*
|
|
5
|
+
* The log (`.monomind/knowledge/doc-metadata.jsonl`) is the pipeline's source
|
|
6
|
+
* of truth. Everything here reads or writes it:
|
|
7
|
+
*
|
|
8
|
+
* - WRITE: append a version record, tombstone a removed one.
|
|
9
|
+
* - READ: the last-wins live view, the full history, and lookups by path,
|
|
10
|
+
* canonical URL or `<scope>:<path>` docId.
|
|
11
|
+
* - JUDGE: which content hashes are current, which chunk keys are therefore
|
|
12
|
+
* superseded, and which indexed files no longer exist on disk.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here touches the vector store. Removal tombstones metadata and lets
|
|
15
|
+
* the superseded filter hide the chunks — mark, don't destroy.
|
|
16
|
+
*
|
|
17
|
+
* Split out of document-pipeline.ts.
|
|
18
|
+
*
|
|
19
|
+
* @module v1/cli/knowledge/document-index
|
|
20
|
+
*/
|
|
21
|
+
import type { DocumentMeta, ReconcileReport } from './document-types.js';
|
|
22
|
+
export declare const METADATA_FILE = "doc-metadata.jsonl";
|
|
23
|
+
export declare function metadataPath(rootDir: string): string;
|
|
24
|
+
/** Every record ever appended, in order, including superseded versions and
|
|
25
|
+
* removal tombstones. Reads the path directly instead of via `metadataPath`,
|
|
26
|
+
* which mkdir's. */
|
|
27
|
+
export declare function readMetadataLog(rootDir: string): DocumentMeta[];
|
|
28
|
+
export declare function readMetadata(rootDir: string): DocumentMeta[];
|
|
29
|
+
export declare function appendMetadata(rootDir: string, meta: DocumentMeta): void;
|
|
30
|
+
export declare function removeMetadataEntry(rootDir: string, filePath: string, scope: string): void;
|
|
31
|
+
/** Content hashes of the documents currently indexed under `rootDir`. */
|
|
32
|
+
export declare function liveContentHashes(rootDir: string): Set<string>;
|
|
33
|
+
/** True when a metadata log exists under `rootDir`.
|
|
34
|
+
*
|
|
35
|
+
* An empty live-hash set has two very different causes: the log is missing (we
|
|
36
|
+
* cannot judge what is current) or the log exists and every document has been
|
|
37
|
+
* removed (nothing is current). Collapsing them made `doc remove` of the LAST
|
|
38
|
+
* document a no-op — the tombstoned chunks came straight back in search.
|
|
39
|
+
*
|
|
40
|
+
* Reads the path directly instead of via `metadataPath`, which mkdir's. */
|
|
41
|
+
export declare function hasKnowledgeMetadata(rootDir: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* True when `key` is a document chunk whose version is no longer current.
|
|
44
|
+
* Non-`doc:` keys are never superseded. When no metadata is available nothing
|
|
45
|
+
* is filtered, because "no metadata" must not read as "everything is stale".
|
|
46
|
+
*
|
|
47
|
+
* `metadataPresent` defaults to the old `live.size > 0` heuristic so existing
|
|
48
|
+
* two-argument callers keep their exact behaviour; pass `hasKnowledgeMetadata`
|
|
49
|
+
* to also filter correctly once the last document has been removed.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isSupersededKey(key: string, live: Set<string>, metadataPresent?: boolean): boolean;
|
|
52
|
+
export declare function supersededOverfetchLimit(limit: number, live: Set<string>): number;
|
|
53
|
+
export declare function listDocuments(rootDir?: string, scope?: string): DocumentMeta[];
|
|
54
|
+
/**
|
|
55
|
+
* Every recorded version of one document, oldest first (RCL-06).
|
|
56
|
+
*
|
|
57
|
+
* `target` is either an indexed file path or a capture's `canonicalUrl`. Read
|
|
58
|
+
* from the append-only log rather than the last-wins view, which is how a
|
|
59
|
+
* superseded version stays addressable after its record has been replaced or
|
|
60
|
+
* tombstoned.
|
|
61
|
+
*
|
|
62
|
+
* Best-effort by design: `readMetadata` compacts the log once it passes 1MB
|
|
63
|
+
* and keeps only live records, so history older than a compaction is gone.
|
|
64
|
+
* The `supersedes` pointer on each record is the durable part.
|
|
65
|
+
*/
|
|
66
|
+
export declare function listDocumentVersions(rootDir?: string, target?: string, scope?: string): DocumentMeta[];
|
|
67
|
+
/**
|
|
68
|
+
* The indexed record for whatever a caller wrote down: a file path, a
|
|
69
|
+
* capture's `canonicalUrl` (fragment ignored), or the `<scope>:<path>` docId.
|
|
70
|
+
*
|
|
71
|
+
* Live records win. A superseded version is only reached through the
|
|
72
|
+
* append-only log, and only when nothing live matches — otherwise citing a
|
|
73
|
+
* re-captured page would resolve against the version it replaced.
|
|
74
|
+
*/
|
|
75
|
+
export declare function findDocumentRecord(rootDir?: string, target?: string, scope?: string): DocumentMeta | undefined;
|
|
76
|
+
export declare function removeDocument(filePath: string, scope?: string, rootDir?: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* True for macOS AppleDouble sidecars (`._name`).
|
|
79
|
+
*
|
|
80
|
+
* Matches on the BASENAME PREFIX only. A legitimate document may contain `._`
|
|
81
|
+
* elsewhere in its name (`v1._2-release.md`), or live under a dot-directory
|
|
82
|
+
* that is deliberately indexed (`.monodesign/` critique snapshots), and
|
|
83
|
+
* neither may be rejected.
|
|
84
|
+
*/
|
|
85
|
+
export declare function isResourceFork(filePath: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Reconcile the document index against the filesystem: find index entries whose
|
|
88
|
+
* source file no longer exists and, only when explicitly asked, tombstone them.
|
|
89
|
+
*
|
|
90
|
+
* WHY — `removeDocument` only ever tombstoned metadata, and nothing has ever
|
|
91
|
+
* compared the index against the disk, so a deleted file stayed searchable
|
|
92
|
+
* forever. Measured 2026-07-28: 109 of 257 live entries (42.4%) had no file
|
|
93
|
+
* behind them, including `docs/concepts/memory.md`. The Second Brain was
|
|
94
|
+
* answering questions from documents the user had deleted.
|
|
95
|
+
*
|
|
96
|
+
* WHY IT IS THIS CAUTIOUS — "drop the index entry when the file is missing" is
|
|
97
|
+
* a rule with a known catastrophic reading. A missing file is also an unmounted
|
|
98
|
+
* volume, a checked-out branch, a partial clone, or a permissions failure. Two
|
|
99
|
+
* guards were tried against real data and REJECTED; they are recorded here so
|
|
100
|
+
* they are not re-proposed:
|
|
101
|
+
*
|
|
102
|
+
* - "abort if >50% of entries are missing" — the real, legitimate missing
|
|
103
|
+
* fraction was 42.4%, so the threshold never fires in the one case we have.
|
|
104
|
+
* Any threshold that would have blocked this reconcile is fitted to nothing.
|
|
105
|
+
* - "only reconcile when the parent directory still exists" — 26 of the 109
|
|
106
|
+
* missing files had no parent directory, because `docs/concepts`,
|
|
107
|
+
* `docs/adrs` and `docs/commands` were legitimately deleted wholesale. A
|
|
108
|
+
* deleted directory and an unmounted volume are indistinguishable there.
|
|
109
|
+
*
|
|
110
|
+
* What does discriminate is the ROOT. An intact, readable root carrying a
|
|
111
|
+
* metadata log means the tree is genuinely present, so a missing file is
|
|
112
|
+
* genuinely gone. A missing root means nothing beneath it is knowable and
|
|
113
|
+
* nothing may be removed — hence throw rather than reconcile.
|
|
114
|
+
*
|
|
115
|
+
* Removal tombstones metadata; it does not delete store rows. Chunks stay on
|
|
116
|
+
* disk and fall out of search through the existing superseded filter, which
|
|
117
|
+
* keeps this consistent with the mark-don't-destroy rule and leaves the whole
|
|
118
|
+
* operation reversible from the archive.
|
|
119
|
+
*/
|
|
120
|
+
export declare function reconcileIndex(rootDir?: string, opts?: {
|
|
121
|
+
scope?: string;
|
|
122
|
+
apply?: boolean;
|
|
123
|
+
}): Promise<ReconcileReport>;
|
|
124
|
+
//# sourceMappingURL=document-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-index.d.ts","sourceRoot":"","sources":["../../../src/knowledge/document-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEzE,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAIlD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;qBAEqB;AACrB,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAa/D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAoC5D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAExE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAa1F;AAkBD,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAI9D;AAED;;;;;;;2EAO2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EACjB,eAAe,UAAgB,GAC9B,OAAO,CAIT;AAQD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAGjF;AAID,wBAAgB,aAAa,CAAC,OAAO,SAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAGxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,SAAmB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,EAAE,CAUhB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,SAAmB,EAC1B,MAAM,SAAK,EACX,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,GAAG,SAAS,CA0B1B;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAW,EAChB,OAAO,SAAmB,GACzB,OAAO,CAAC,IAAI,CAAC,CAIf;AAID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,cAAc,CAClC,OAAO,SAAmB,EAC1B,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzC,OAAO,CAAC,eAAe,CAAC,CAwC1B"}
|