@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.
Files changed (194) hide show
  1. package/.claude/helpers/control-start.cjs +10 -13
  2. package/.claude/skills/monodesign/scripts/context.mjs +4 -4
  3. package/.claude/skills/monodesign/scripts/critique-storage.mjs +1 -1
  4. package/.claude/skills/monodesign/scripts/detect-csp.mjs +1 -6
  5. package/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +16 -18
  6. package/.claude/skills/monodesign/scripts/detector/cli/main.mjs +3 -3
  7. package/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +67 -47
  8. package/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +6 -6
  9. package/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +6 -5
  10. package/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +6 -6
  11. package/.claude/skills/monodesign/scripts/detector/fix/index.mjs +3 -3
  12. package/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +1 -1
  13. package/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +1 -1
  14. package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +24 -25
  15. package/.claude/skills/monodesign/scripts/detector/shared/color.mjs +2 -2
  16. package/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +1 -1
  17. package/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +2 -2
  18. package/.claude/skills/monodesign/scripts/hook-admin.mjs +6 -6
  19. package/.claude/skills/monodesign/scripts/hook-before-edit.mjs +4 -4
  20. package/.claude/skills/monodesign/scripts/hook-lib.mjs +20 -11
  21. package/.claude/skills/monodesign/scripts/hook.mjs +1 -1
  22. package/.claude/skills/monodesign/scripts/lib/design-parser.mjs +9 -42
  23. package/.claude/skills/monodesign/scripts/lib/is-generated.mjs +1 -1
  24. package/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +5 -5
  25. package/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +1 -1
  26. package/.claude/skills/monodesign/scripts/live/event-validation.mjs +13 -13
  27. package/.claude/skills/monodesign/scripts/live/manual-apply.mjs +4 -4
  28. package/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +1 -1
  29. package/.claude/skills/monodesign/scripts/live/session-store.mjs +5 -5
  30. package/.claude/skills/monodesign/scripts/live/svelte-component.mjs +13 -13
  31. package/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +4 -4
  32. package/.claude/skills/monodesign/scripts/live/ui-core.mjs +1 -1
  33. package/.claude/skills/monodesign/scripts/live-accept.mjs +24 -24
  34. package/.claude/skills/monodesign/scripts/live-browser-dom.js +8 -7
  35. package/.claude/skills/monodesign/scripts/live-browser-session.js +8 -7
  36. package/.claude/skills/monodesign/scripts/live-browser.js +405 -432
  37. package/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +6 -6
  38. package/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +2 -2
  39. package/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +1 -1
  40. package/.claude/skills/monodesign/scripts/live-inject.mjs +7 -7
  41. package/.claude/skills/monodesign/scripts/live-insert.mjs +11 -11
  42. package/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +4 -4
  43. package/.claude/skills/monodesign/scripts/live-poll.mjs +5 -5
  44. package/.claude/skills/monodesign/scripts/live-server.mjs +10 -10
  45. package/.claude/skills/monodesign/scripts/live-wrap.mjs +31 -41
  46. package/.claude/skills/monodesign/scripts/live.mjs +5 -5
  47. package/.claude/skills/monodesign/scripts/palette.mjs +3 -1
  48. package/.claude/skills/monodesign/scripts/pin.mjs +1 -1
  49. package/dist/src/commands/doc-filters.d.ts.map +1 -1
  50. package/dist/src/commands/doc-filters.js +6 -0
  51. package/dist/src/commands/doc-filters.js.map +1 -1
  52. package/dist/src/commands/doc-library.d.ts +2 -1
  53. package/dist/src/commands/doc-library.d.ts.map +1 -1
  54. package/dist/src/commands/doc-library.js +66 -2
  55. package/dist/src/commands/doc-library.js.map +1 -1
  56. package/dist/src/commands/doc.d.ts.map +1 -1
  57. package/dist/src/commands/doc.js +2 -0
  58. package/dist/src/commands/doc.js.map +1 -1
  59. package/dist/src/commands/ui.d.ts.map +1 -1
  60. package/dist/src/commands/ui.js +60 -0
  61. package/dist/src/commands/ui.js.map +1 -1
  62. package/dist/src/knowledge/capture-envelope.d.ts +5 -0
  63. package/dist/src/knowledge/capture-envelope.d.ts.map +1 -1
  64. package/dist/src/knowledge/capture-envelope.js +2 -0
  65. package/dist/src/knowledge/capture-envelope.js.map +1 -1
  66. package/dist/src/knowledge/document-chunking.d.ts +42 -0
  67. package/dist/src/knowledge/document-chunking.d.ts.map +1 -0
  68. package/dist/src/knowledge/document-chunking.js +288 -0
  69. package/dist/src/knowledge/document-chunking.js.map +1 -0
  70. package/dist/src/knowledge/document-index.d.ts +124 -0
  71. package/dist/src/knowledge/document-index.d.ts.map +1 -0
  72. package/dist/src/knowledge/document-index.js +314 -0
  73. package/dist/src/knowledge/document-index.js.map +1 -0
  74. package/dist/src/knowledge/document-ingest.d.ts +23 -0
  75. package/dist/src/knowledge/document-ingest.d.ts.map +1 -0
  76. package/dist/src/knowledge/document-ingest.js +368 -0
  77. package/dist/src/knowledge/document-ingest.js.map +1 -0
  78. package/dist/src/knowledge/document-pipeline.d.ts +26 -208
  79. package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
  80. package/dist/src/knowledge/document-pipeline.js +25 -1104
  81. package/dist/src/knowledge/document-pipeline.js.map +1 -1
  82. package/dist/src/knowledge/document-search.d.ts +27 -0
  83. package/dist/src/knowledge/document-search.d.ts.map +1 -0
  84. package/dist/src/knowledge/document-search.js +138 -0
  85. package/dist/src/knowledge/document-search.js.map +1 -0
  86. package/dist/src/knowledge/document-store.d.ts +28 -0
  87. package/dist/src/knowledge/document-store.d.ts.map +1 -0
  88. package/dist/src/knowledge/document-store.js +61 -0
  89. package/dist/src/knowledge/document-store.js.map +1 -0
  90. package/dist/src/knowledge/document-types.d.ts +103 -0
  91. package/dist/src/knowledge/document-types.d.ts.map +1 -0
  92. package/dist/src/knowledge/document-types.js +12 -0
  93. package/dist/src/knowledge/document-types.js.map +1 -0
  94. package/dist/src/knowledge/highlights.d.ts +168 -0
  95. package/dist/src/knowledge/highlights.d.ts.map +1 -0
  96. package/dist/src/knowledge/highlights.js +311 -0
  97. package/dist/src/knowledge/highlights.js.map +1 -0
  98. package/dist/src/knowledge/lookup.d.ts +80 -0
  99. package/dist/src/knowledge/lookup.d.ts.map +1 -0
  100. package/dist/src/knowledge/lookup.js +156 -0
  101. package/dist/src/knowledge/lookup.js.map +1 -0
  102. package/dist/src/knowledge/okf-bundle.d.ts +19 -0
  103. package/dist/src/knowledge/okf-bundle.d.ts.map +1 -0
  104. package/dist/src/knowledge/okf-bundle.js +106 -0
  105. package/dist/src/knowledge/okf-bundle.js.map +1 -0
  106. package/dist/src/knowledge/profile-store.d.ts +134 -0
  107. package/dist/src/knowledge/profile-store.d.ts.map +1 -0
  108. package/dist/src/knowledge/profile-store.js +237 -0
  109. package/dist/src/knowledge/profile-store.js.map +1 -0
  110. package/dist/src/orgrt/agent-runner.d.ts +4 -0
  111. package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
  112. package/dist/src/orgrt/agent-runner.js +22 -0
  113. package/dist/src/orgrt/agent-runner.js.map +1 -1
  114. package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
  115. package/dist/src/orgrt/antigravity-runner.js +2 -1
  116. package/dist/src/orgrt/antigravity-runner.js.map +1 -1
  117. package/dist/src/orgrt/authority-mask.d.ts +32 -0
  118. package/dist/src/orgrt/authority-mask.d.ts.map +1 -0
  119. package/dist/src/orgrt/authority-mask.js +135 -0
  120. package/dist/src/orgrt/authority-mask.js.map +1 -0
  121. package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
  122. package/dist/src/orgrt/codex-runner.js +2 -1
  123. package/dist/src/orgrt/codex-runner.js.map +1 -1
  124. package/dist/src/orgrt/copilot-runner.d.ts.map +1 -1
  125. package/dist/src/orgrt/copilot-runner.js +2 -1
  126. package/dist/src/orgrt/copilot-runner.js.map +1 -1
  127. package/dist/src/orgrt/crush-runner.d.ts.map +1 -1
  128. package/dist/src/orgrt/crush-runner.js +6 -1
  129. package/dist/src/orgrt/crush-runner.js.map +1 -1
  130. package/dist/src/orgrt/daemon.d.ts +4 -0
  131. package/dist/src/orgrt/daemon.d.ts.map +1 -1
  132. package/dist/src/orgrt/daemon.js +13 -2
  133. package/dist/src/orgrt/daemon.js.map +1 -1
  134. package/dist/src/orgrt/decisions.d.ts +9 -0
  135. package/dist/src/orgrt/decisions.d.ts.map +1 -1
  136. package/dist/src/orgrt/decisions.js +32 -5
  137. package/dist/src/orgrt/decisions.js.map +1 -1
  138. package/dist/src/orgrt/file-roots.d.ts +2 -1
  139. package/dist/src/orgrt/file-roots.d.ts.map +1 -1
  140. package/dist/src/orgrt/file-roots.js +7 -3
  141. package/dist/src/orgrt/file-roots.js.map +1 -1
  142. package/dist/src/orgrt/grok-runner.d.ts.map +1 -1
  143. package/dist/src/orgrt/grok-runner.js +2 -1
  144. package/dist/src/orgrt/grok-runner.js.map +1 -1
  145. package/dist/src/orgrt/hermes-runner.d.ts.map +1 -1
  146. package/dist/src/orgrt/hermes-runner.js +2 -1
  147. package/dist/src/orgrt/hermes-runner.js.map +1 -1
  148. package/dist/src/orgrt/inbox.d.ts.map +1 -1
  149. package/dist/src/orgrt/inbox.js +70 -4
  150. package/dist/src/orgrt/inbox.js.map +1 -1
  151. package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
  152. package/dist/src/orgrt/kimicode-runner.js +2 -1
  153. package/dist/src/orgrt/kimicode-runner.js.map +1 -1
  154. package/dist/src/orgrt/opencode-runner.d.ts.map +1 -1
  155. package/dist/src/orgrt/opencode-runner.js +3 -2
  156. package/dist/src/orgrt/opencode-runner.js.map +1 -1
  157. package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -1
  158. package/dist/src/orgrt/pi-rpc-runner.js +3 -2
  159. package/dist/src/orgrt/pi-rpc-runner.js.map +1 -1
  160. package/dist/src/orgrt/pi-runner.d.ts.map +1 -1
  161. package/dist/src/orgrt/pi-runner.js +2 -1
  162. package/dist/src/orgrt/pi-runner.js.map +1 -1
  163. package/dist/src/orgrt/policy.d.ts.map +1 -1
  164. package/dist/src/orgrt/policy.js +3 -0
  165. package/dist/src/orgrt/policy.js.map +1 -1
  166. package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -1
  167. package/dist/src/orgrt/qwen-rpc-runner.js +3 -2
  168. package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -1
  169. package/dist/src/orgrt/qwen-runner.d.ts.map +1 -1
  170. package/dist/src/orgrt/qwen-runner.js +2 -1
  171. package/dist/src/orgrt/qwen-runner.js.map +1 -1
  172. package/dist/src/orgrt/role-sandbox.d.ts +21 -0
  173. package/dist/src/orgrt/role-sandbox.d.ts.map +1 -1
  174. package/dist/src/orgrt/role-sandbox.js +31 -6
  175. package/dist/src/orgrt/role-sandbox.js.map +1 -1
  176. package/dist/src/orgrt/session.d.ts.map +1 -1
  177. package/dist/src/orgrt/session.js +21 -2
  178. package/dist/src/orgrt/session.js.map +1 -1
  179. package/dist/src/orgrt/task-dag.d.ts +3 -0
  180. package/dist/src/orgrt/task-dag.d.ts.map +1 -1
  181. package/dist/src/orgrt/task-dag.js +1 -0
  182. package/dist/src/orgrt/task-dag.js.map +1 -1
  183. package/dist/src/orgrt/types.d.ts +5 -0
  184. package/dist/src/orgrt/types.d.ts.map +1 -1
  185. package/dist/src/orgrt/types.js +23 -1
  186. package/dist/src/orgrt/types.js.map +1 -1
  187. package/dist/src/ui/dashboard.html +28 -848
  188. package/dist/src/ui/human-auth.mjs +103 -0
  189. package/dist/src/ui/org-hil.mjs +86 -37
  190. package/dist/src/ui/org-runtime.mjs +21 -13
  191. package/dist/src/ui/routes-org.mjs +49 -445
  192. package/dist/src/ui/server.mjs +90 -2
  193. package/dist/tsconfig.tsbuildinfo +1 -1
  194. package/package.json +6 -6
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Highlights as atomic notes (RCL-04) — the ingest half.
3
+ *
4
+ * The extension writes `highlights.json` into the capture envelope beside
5
+ * `readable.md` (chrome-extension/highlights.js). This module turns each
6
+ * entry into a NOTE IN ITS OWN RIGHT that points back at the document it
7
+ * came from — searchable on its own terms, not buried inside a chunk of
8
+ * the page it was taken from.
9
+ *
10
+ * WHY A CHILD NOTE AND NOT A TAG ON THE PARENT. A highlight is a claim
11
+ * about what mattered, made by the reader, at a moment. Folding it into the
12
+ * parent's chunks loses all three: it stops being separately findable, it
13
+ * stops carrying its own comment, and it stops having a date. So each one
14
+ * is stored as its own entry, keyed under the parent's content hash, and
15
+ * linked back by `parent:` and `url:` tags.
16
+ *
17
+ * THE ANCHOR is the careful part. The extension measured its offsets
18
+ * against the LIVE PAGE'S TEXT; what got indexed is `readable.md`, a
19
+ * Readability pass over that same DOM. The two are close and not identical.
20
+ * So the offsets that arrive are treated as a hint and the QUOTE is treated
21
+ * as the truth: `locate` re-locates the quote in the extracted text and
22
+ * cuts a real citation anchor (`<hash12>#<start>-<end>`, citation.ts's
23
+ * shape) against the version it actually found. A highlight whose text is
24
+ * not in the document at all gets NO anchor rather than a plausible wrong
25
+ * one — the same rule citation.ts applies to a stale anchor, for the same
26
+ * reason.
27
+ *
28
+ * Everything here is as defensive as capture-envelope.ts, and for the same
29
+ * reason: `highlights.json` was written by a browser extension on a machine
30
+ * we do not control, and a malformed one must cost the capture nothing.
31
+ *
32
+ * @module v1/cli/knowledge/highlights
33
+ */
34
+ import type { CaptureProvenance } from './capture-envelope.js';
35
+ export declare const HIGHLIGHTS_FILE = "highlights.json";
36
+ /** Tag namespaces, so a highlight is findable as one and traceable to its
37
+ * parent without parsing anything. */
38
+ export declare const HIGHLIGHT_TAG = "highlight";
39
+ export declare const PARENT_TAG_PREFIX = "parent:";
40
+ export declare const URL_TAG_PREFIX = "url:";
41
+ /** The anchor as the extension measured it — offsets against the page's
42
+ * visible text, plus the quote and its neighbourhood. */
43
+ export interface HighlightAnchor {
44
+ /** A HINT. Measured against the live page, not the extracted text. */
45
+ startChar?: number;
46
+ endChar?: number;
47
+ /** The truth. What the reader actually selected. */
48
+ quote: string;
49
+ prefix?: string;
50
+ suffix?: string;
51
+ /** W3C `:~:text=` fragment, as citation.ts builds one. */
52
+ fragment?: string;
53
+ }
54
+ export interface Highlight {
55
+ id: string;
56
+ text: string;
57
+ anchor: HighlightAnchor;
58
+ createdAt?: string;
59
+ comment?: string;
60
+ color?: string;
61
+ /** The page URL pointed at this passage, as the extension wrote it. */
62
+ url?: string;
63
+ }
64
+ /** One highlight, resolved against the document it belongs to. */
65
+ export interface HighlightNote {
66
+ id: string;
67
+ /** `<scope>:<filePath>` — the parent document's own id. */
68
+ parentDocId: string;
69
+ parentPath: string;
70
+ scope: string;
71
+ /** The parent's identity URL. */
72
+ parentUrl?: string;
73
+ parentTitle?: string;
74
+ text: string;
75
+ quote: string;
76
+ comment?: string;
77
+ createdAt?: string;
78
+ color?: string;
79
+ /** `<hash12>#<start>-<end>` against the EXTRACTED text — present only
80
+ * when the quote was actually found there. */
81
+ anchor?: string;
82
+ startChar?: number;
83
+ endChar?: number;
84
+ /** The link that lands on the passage in the live page. */
85
+ citeUrl?: string;
86
+ capturedAt?: string;
87
+ /** What gets stored and embedded: the highlight, its note, its source. */
88
+ content: string;
89
+ tags: string[];
90
+ }
91
+ /** Keep only what we understand, coerced. An entry with no text is not a
92
+ * highlight and is dropped rather than carried through as an empty note. */
93
+ export declare function normalizeHighlight(raw: unknown, index?: number): Highlight | null;
94
+ /**
95
+ * readHighlights reads the `highlights.json` sitting in `dir`. Returns an
96
+ * empty list — never throws — when there is none, it is unreadable,
97
+ * oversized, not JSON, or the wrong shape entirely.
98
+ */
99
+ export declare function readHighlights(dir: string): Highlight[];
100
+ /** readHighlightsFor reads the highlights belonging to an indexed file,
101
+ * i.e. the ones in its envelope directory. */
102
+ export declare function readHighlightsFor(filePath: string): Highlight[];
103
+ /**
104
+ * locate finds a highlight's quote in the extracted text and returns its
105
+ * span there, or null.
106
+ *
107
+ * The order is the order of trustworthiness, and it is the SAME order the
108
+ * extension's own restore path uses (chrome-extension/highlights.js
109
+ * `relocate`), so a highlight that can be painted back onto the page can
110
+ * also be cited out of the archive:
111
+ *
112
+ * 1. prefix + quote + suffix — the neighbourhood, which survives the
113
+ * Readability pass dropping a nav bar above it;
114
+ * 2. the occurrence nearest the recorded offset, for a quote that appears
115
+ * more than once;
116
+ * 3. nothing. A quote that is not in the document gets no anchor. It is
117
+ * still stored as a note — the reader did read it — but a citation
118
+ * that cannot be checked is not offered as if it could.
119
+ */
120
+ export declare function locate(text: string, anchor: HighlightAnchor): {
121
+ startChar: number;
122
+ endChar: number;
123
+ } | null;
124
+ export interface ParentDocument {
125
+ filePath: string;
126
+ scope: string;
127
+ /** Hash of the EXTRACTED text — the same one the anchor binds to. */
128
+ contentHash: string;
129
+ /** The extracted text itself, when the caller has it. Without it, no
130
+ * anchor can be cut and the notes are stored unanchored. */
131
+ text?: string;
132
+ canonicalUrl?: string;
133
+ provenance?: CaptureProvenance;
134
+ }
135
+ /**
136
+ * highlightNotes turns an envelope's highlights into notes against a parent
137
+ * document. Pure: it reads nothing and writes nothing, so it is the whole
138
+ * of the interesting behaviour and the whole of what is tested.
139
+ */
140
+ export declare function highlightNotes(parent: ParentDocument, highlights: readonly Highlight[]): HighlightNote[];
141
+ export interface IngestHighlightsResult {
142
+ /** How many notes were stored. */
143
+ stored: number;
144
+ /** How many were found in the envelope at all. */
145
+ found: number;
146
+ /** How many resolved to a citable span in the extracted text. */
147
+ anchored: number;
148
+ notes: HighlightNote[];
149
+ error?: string;
150
+ }
151
+ /** The storage key for one highlight. Keyed under the PARENT'S content
152
+ * hash, so re-ingesting the same version upserts the same notes rather
153
+ * than accumulating a copy per ingest — the same discipline as the
154
+ * pipeline's `doc:<hash>:<index>` chunk keys. */
155
+ export declare function highlightKey(parentContentHash: string, id: string): string;
156
+ /**
157
+ * ingestHighlights stores an envelope's highlights as notes linked to the
158
+ * parent document.
159
+ *
160
+ * Reports rather than throws: a capture whose highlights could not be
161
+ * stored is still a perfectly good capture, and failing the whole ingest
162
+ * over the annotations would lose the page as well as the notes.
163
+ */
164
+ export declare function ingestHighlights(parent: ParentDocument, opts?: {
165
+ highlights?: readonly Highlight[];
166
+ dbPath?: string;
167
+ }): Promise<IngestHighlightsResult>;
168
+ //# sourceMappingURL=highlights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.d.ts","sourceRoot":"","sources":["../../../src/knowledge/highlights.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Highlights as atomic notes (RCL-04) — the ingest half.
3
+ *
4
+ * The extension writes `highlights.json` into the capture envelope beside
5
+ * `readable.md` (chrome-extension/highlights.js). This module turns each
6
+ * entry into a NOTE IN ITS OWN RIGHT that points back at the document it
7
+ * came from — searchable on its own terms, not buried inside a chunk of
8
+ * the page it was taken from.
9
+ *
10
+ * WHY A CHILD NOTE AND NOT A TAG ON THE PARENT. A highlight is a claim
11
+ * about what mattered, made by the reader, at a moment. Folding it into the
12
+ * parent's chunks loses all three: it stops being separately findable, it
13
+ * stops carrying its own comment, and it stops having a date. So each one
14
+ * is stored as its own entry, keyed under the parent's content hash, and
15
+ * linked back by `parent:` and `url:` tags.
16
+ *
17
+ * THE ANCHOR is the careful part. The extension measured its offsets
18
+ * against the LIVE PAGE'S TEXT; what got indexed is `readable.md`, a
19
+ * Readability pass over that same DOM. The two are close and not identical.
20
+ * So the offsets that arrive are treated as a hint and the QUOTE is treated
21
+ * as the truth: `locate` re-locates the quote in the extracted text and
22
+ * cuts a real citation anchor (`<hash12>#<start>-<end>`, citation.ts's
23
+ * shape) against the version it actually found. A highlight whose text is
24
+ * not in the document at all gets NO anchor rather than a plausible wrong
25
+ * one — the same rule citation.ts applies to a stale anchor, for the same
26
+ * reason.
27
+ *
28
+ * Everything here is as defensive as capture-envelope.ts, and for the same
29
+ * reason: `highlights.json` was written by a browser extension on a machine
30
+ * we do not control, and a malformed one must cost the capture nothing.
31
+ *
32
+ * @module v1/cli/knowledge/highlights
33
+ */
34
+ import * as fs from 'node:fs';
35
+ import * as path from 'node:path';
36
+ import { citationAnchor, citationUrl, passageQuote } from './citation.js';
37
+ export const HIGHLIGHTS_FILE = 'highlights.json';
38
+ /** Tag namespaces, so a highlight is findable as one and traceable to its
39
+ * parent without parsing anything. */
40
+ export const HIGHLIGHT_TAG = 'highlight';
41
+ export const PARENT_TAG_PREFIX = 'parent:';
42
+ export const URL_TAG_PREFIX = 'url:';
43
+ const MAX_FILE_BYTES = 2 * 1024 * 1024;
44
+ const MAX_HIGHLIGHTS = 500;
45
+ const MAX_TEXT = 4000;
46
+ const MAX_COMMENT = 2000;
47
+ // ── Reading ────────────────────────────────────────────────────────
48
+ const str = (v, max) => {
49
+ if (typeof v !== 'string')
50
+ return undefined;
51
+ const trimmed = v.trim().slice(0, max).trim();
52
+ return trimmed ? trimmed : undefined;
53
+ };
54
+ const int = (v) => {
55
+ const n = typeof v === 'number' ? v : Number.NaN;
56
+ return Number.isFinite(n) && n >= 0 ? Math.floor(n) : undefined;
57
+ };
58
+ /** Keep only what we understand, coerced. An entry with no text is not a
59
+ * highlight and is dropped rather than carried through as an empty note. */
60
+ export function normalizeHighlight(raw, index = 0) {
61
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
62
+ return null;
63
+ const o = raw;
64
+ const text = str(o.text, MAX_TEXT);
65
+ if (!text)
66
+ return null;
67
+ const rawAnchor = o.anchor && typeof o.anchor === 'object' && !Array.isArray(o.anchor)
68
+ ? o.anchor
69
+ : {};
70
+ const quote = str(rawAnchor.quote, MAX_TEXT) ?? text;
71
+ const anchor = { quote };
72
+ const start = int(rawAnchor.startChar);
73
+ const end = int(rawAnchor.endChar);
74
+ if (start !== undefined)
75
+ anchor.startChar = start;
76
+ if (end !== undefined && (start === undefined || end >= start))
77
+ anchor.endChar = end;
78
+ const prefix = str(rawAnchor.prefix, 200);
79
+ const suffix = str(rawAnchor.suffix, 200);
80
+ const fragment = str(rawAnchor.fragment, 4000);
81
+ if (prefix)
82
+ anchor.prefix = prefix;
83
+ if (suffix)
84
+ anchor.suffix = suffix;
85
+ if (fragment)
86
+ anchor.fragment = fragment;
87
+ return {
88
+ id: str(o.id, 128) ?? `hl-${index}`,
89
+ text,
90
+ anchor,
91
+ ...(str(o.createdAt, 64) ? { createdAt: str(o.createdAt, 64) } : {}),
92
+ ...(str(o.comment, MAX_COMMENT) ? { comment: str(o.comment, MAX_COMMENT) } : {}),
93
+ ...(str(o.color, 32) ? { color: str(o.color, 32) } : {}),
94
+ ...(str(o.url, 4000) ? { url: str(o.url, 4000) } : {}),
95
+ };
96
+ }
97
+ /**
98
+ * readHighlights reads the `highlights.json` sitting in `dir`. Returns an
99
+ * empty list — never throws — when there is none, it is unreadable,
100
+ * oversized, not JSON, or the wrong shape entirely.
101
+ */
102
+ export function readHighlights(dir) {
103
+ const file = path.join(path.resolve(dir), HIGHLIGHTS_FILE);
104
+ try {
105
+ if (!fs.existsSync(file))
106
+ return [];
107
+ if (fs.statSync(file).size > MAX_FILE_BYTES)
108
+ return [];
109
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
110
+ const list = Array.isArray(parsed) ? parsed : parsed?.highlights;
111
+ if (!Array.isArray(list))
112
+ return [];
113
+ const out = [];
114
+ const seen = new Set();
115
+ for (const [i, raw] of list.slice(0, MAX_HIGHLIGHTS).entries()) {
116
+ const h = normalizeHighlight(raw, i);
117
+ if (!h || seen.has(h.id))
118
+ continue;
119
+ seen.add(h.id);
120
+ out.push(h);
121
+ }
122
+ return out;
123
+ }
124
+ catch {
125
+ return [];
126
+ }
127
+ }
128
+ /** readHighlightsFor reads the highlights belonging to an indexed file,
129
+ * i.e. the ones in its envelope directory. */
130
+ export function readHighlightsFor(filePath) {
131
+ return readHighlights(path.dirname(path.resolve(filePath)));
132
+ }
133
+ // ── Resolving ──────────────────────────────────────────────────────
134
+ /**
135
+ * locate finds a highlight's quote in the extracted text and returns its
136
+ * span there, or null.
137
+ *
138
+ * The order is the order of trustworthiness, and it is the SAME order the
139
+ * extension's own restore path uses (chrome-extension/highlights.js
140
+ * `relocate`), so a highlight that can be painted back onto the page can
141
+ * also be cited out of the archive:
142
+ *
143
+ * 1. prefix + quote + suffix — the neighbourhood, which survives the
144
+ * Readability pass dropping a nav bar above it;
145
+ * 2. the occurrence nearest the recorded offset, for a quote that appears
146
+ * more than once;
147
+ * 3. nothing. A quote that is not in the document gets no anchor. It is
148
+ * still stored as a note — the reader did read it — but a citation
149
+ * that cannot be checked is not offered as if it could.
150
+ */
151
+ export function locate(text, anchor) {
152
+ const haystack = String(text ?? '');
153
+ const quote = String(anchor?.quote ?? '');
154
+ if (!quote || !haystack)
155
+ return null;
156
+ if (anchor.prefix || anchor.suffix) {
157
+ const window = `${anchor.prefix ?? ''}${quote}${anchor.suffix ?? ''}`;
158
+ const at = haystack.indexOf(window);
159
+ if (at !== -1) {
160
+ const start = at + (anchor.prefix ?? '').length;
161
+ return { startChar: start, endChar: start + quote.length };
162
+ }
163
+ }
164
+ const hint = anchor.startChar;
165
+ let best = -1;
166
+ let bestDistance = Number.POSITIVE_INFINITY;
167
+ for (let at = haystack.indexOf(quote); at !== -1; at = haystack.indexOf(quote, at + 1)) {
168
+ if (hint === undefined) {
169
+ best = at;
170
+ break;
171
+ }
172
+ const distance = Math.abs(at - hint);
173
+ if (distance < bestDistance) {
174
+ best = at;
175
+ bestDistance = distance;
176
+ }
177
+ }
178
+ if (best === -1)
179
+ return null;
180
+ return { startChar: best, endChar: best + quote.length };
181
+ }
182
+ /** A note's stored body: the passage, the reader's comment, and where it
183
+ * came from — so a search hit is legible without another lookup. */
184
+ function noteContent(note) {
185
+ const lines = [note.text];
186
+ if (note.comment)
187
+ lines.push('', `Note: ${note.comment}`);
188
+ const source = note.parentTitle || note.parentUrl;
189
+ if (source)
190
+ lines.push('', `— ${source}`);
191
+ return lines.join('\n');
192
+ }
193
+ /**
194
+ * highlightNotes turns an envelope's highlights into notes against a parent
195
+ * document. Pure: it reads nothing and writes nothing, so it is the whole
196
+ * of the interesting behaviour and the whole of what is tested.
197
+ */
198
+ export function highlightNotes(parent, highlights) {
199
+ const parentDocId = `${parent.scope}:${parent.filePath}`;
200
+ const parentUrl = parent.canonicalUrl ?? parent.provenance?.canonicalUrl ?? parent.provenance?.url;
201
+ const parentTitle = parent.provenance?.title;
202
+ const capturedAt = parent.provenance?.capturedAt;
203
+ return highlights.map((h) => {
204
+ const span = parent.text ? locate(parent.text, h.anchor) : null;
205
+ const note = {
206
+ id: h.id,
207
+ parentDocId,
208
+ parentPath: parent.filePath,
209
+ scope: parent.scope,
210
+ ...(parentUrl ? { parentUrl } : {}),
211
+ ...(parentTitle ? { parentTitle } : {}),
212
+ text: h.text,
213
+ quote: passageQuote(h.text),
214
+ ...(h.comment ? { comment: h.comment } : {}),
215
+ ...(h.createdAt ? { createdAt: h.createdAt } : {}),
216
+ ...(h.color ? { color: h.color } : {}),
217
+ ...(span
218
+ ? {
219
+ anchor: citationAnchor(parent.contentHash, span.startChar, span.endChar),
220
+ startChar: span.startChar,
221
+ endChar: span.endChar,
222
+ }
223
+ : {}),
224
+ // The extension already built a text-fragment link; prefer it, and
225
+ // fall back to building one the same way citation.ts does.
226
+ ...(h.url
227
+ ? { citeUrl: h.url }
228
+ : parentUrl
229
+ ? { citeUrl: citationUrl(parentUrl, h.text) }
230
+ : {}),
231
+ ...(capturedAt ? { capturedAt } : {}),
232
+ content: '',
233
+ tags: [
234
+ HIGHLIGHT_TAG,
235
+ `${PARENT_TAG_PREFIX}${parentDocId}`,
236
+ ...(parentUrl ? [`${URL_TAG_PREFIX}${parentUrl}`] : []),
237
+ ...(h.color ? [`color:${h.color}`] : []),
238
+ ],
239
+ };
240
+ note.content = noteContent(note);
241
+ return note;
242
+ });
243
+ }
244
+ const KNOWLEDGE_NS_PREFIX = 'knowledge:';
245
+ /** The storage key for one highlight. Keyed under the PARENT'S content
246
+ * hash, so re-ingesting the same version upserts the same notes rather
247
+ * than accumulating a copy per ingest — the same discipline as the
248
+ * pipeline's `doc:<hash>:<index>` chunk keys. */
249
+ export function highlightKey(parentContentHash, id) {
250
+ return `highlight:${parentContentHash}:${id}`;
251
+ }
252
+ async function getBridge() {
253
+ try {
254
+ return (await import('../memory/memory-bridge.js'));
255
+ }
256
+ catch {
257
+ return null;
258
+ }
259
+ }
260
+ /**
261
+ * ingestHighlights stores an envelope's highlights as notes linked to the
262
+ * parent document.
263
+ *
264
+ * Reports rather than throws: a capture whose highlights could not be
265
+ * stored is still a perfectly good capture, and failing the whole ingest
266
+ * over the annotations would lose the page as well as the notes.
267
+ */
268
+ export async function ingestHighlights(parent, opts = {}) {
269
+ const highlights = opts.highlights ?? readHighlightsFor(parent.filePath);
270
+ const notes = highlightNotes(parent, highlights);
271
+ const anchored = notes.filter((n) => n.anchor).length;
272
+ const base = {
273
+ stored: 0,
274
+ found: highlights.length,
275
+ anchored,
276
+ notes,
277
+ };
278
+ if (!notes.length)
279
+ return base;
280
+ const bridge = await getBridge();
281
+ if (!bridge)
282
+ return { ...base, error: 'memory bridge unavailable — no highlights stored' };
283
+ let stored = 0;
284
+ for (const note of notes) {
285
+ try {
286
+ const result = await bridge.bridgeStoreEntry({
287
+ key: highlightKey(parent.contentHash, note.id),
288
+ value: note.content,
289
+ namespace: `${KNOWLEDGE_NS_PREFIX}${parent.scope}`,
290
+ generateEmbeddingFlag: true,
291
+ tags: note.tags,
292
+ upsert: true,
293
+ ...(opts.dbPath ? { dbPath: opts.dbPath } : {}),
294
+ });
295
+ if (result?.success)
296
+ stored++;
297
+ }
298
+ catch {
299
+ // One note failing is not the others' problem, and the count below
300
+ // reports the shortfall honestly.
301
+ }
302
+ }
303
+ return {
304
+ ...base,
305
+ stored,
306
+ ...(stored === notes.length
307
+ ? {}
308
+ : { error: `stored ${stored}/${notes.length} highlights — re-ingest to repair` }),
309
+ };
310
+ }
311
+ //# sourceMappingURL=highlights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.js","sourceRoot":"","sources":["../../../src/knowledge/highlights.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * "Have I already saved this?" (RCL-02) — one URL in, one answer out.
3
+ *
4
+ * The browser extension asks this on every navigation. That is the only
5
+ * thing that shapes this module:
6
+ *
7
+ * - it NEVER throws. An empty store, a store that has never been written,
8
+ * a URL that is not a URL — all of them are `{saved: false}`, because a
9
+ * page load must not be able to fail on a badge;
10
+ * - it is a pure read. No embedder, no subprocess, no index write. The
11
+ * answer comes off the metadata log, which is a file read;
12
+ * - it answers the WHOLE question in one call. `doc list` can already say
13
+ * that a URL is present, but not what note was written at save time —
14
+ * and "you saved this, and here is why you said you were saving it" is
15
+ * the entire value of the badge over a bookmark.
16
+ *
17
+ * Identity is `captureIdentityUrl`'s rule and nothing else: canonical URL
18
+ * when the capturer resolved one, fragment stripped, nothing else rewritten.
19
+ * Matching more loosely than the ingest side would make the badge claim
20
+ * pages are saved that cannot actually be found again.
21
+ *
22
+ * @module v1/cli/knowledge/lookup
23
+ */
24
+ /** What the badge and the "already saved" panel render. */
25
+ export interface UrlLookup {
26
+ saved: boolean;
27
+ /** The identity URL the lookup was performed against. */
28
+ url: string;
29
+ title?: string;
30
+ site?: string;
31
+ /** When the page was captured (not when it was indexed). */
32
+ capturedAt?: string;
33
+ /** RCL-06: 1 for a first save, +1 per stored revision. 0 when unsaved. */
34
+ versions: number;
35
+ /** The note written at save time (CLIP-07) — the reason it was kept. */
36
+ note?: string;
37
+ tags: string[];
38
+ collection?: string;
39
+ source?: string;
40
+ /** The indexed file (`…/readable.md`). */
41
+ filePath?: string;
42
+ /** The capture envelope directory holding it — what "open the archived
43
+ * copy" opens. Absent when the document is an ordinary file on disk. */
44
+ envelope?: string;
45
+ scope?: string;
46
+ contentHash?: string;
47
+ /** RCL-04: how many highlight notes were saved on this page. */
48
+ highlights?: number;
49
+ }
50
+ export interface LookupOptions {
51
+ rootDir?: string;
52
+ scope?: string;
53
+ /** Skip the `highlights.json` read. The badge path does not need it. */
54
+ withHighlights?: boolean;
55
+ }
56
+ /**
57
+ * identityUrl mirrors `captureIdentityUrl` for a raw URL rather than a
58
+ * provenance record: drop the fragment, trim, rewrite nothing else.
59
+ *
60
+ * Duplicated deliberately rather than reshaping the URL into a fake
61
+ * `CaptureProvenance` to borrow that function — the two callers mean
62
+ * different things ("the URL a tab is on" vs. "what this capture is of")
63
+ * and only happen to agree on the rule.
64
+ */
65
+ export declare function identityUrl(raw: string | undefined): string;
66
+ /** The envelope directory for an indexed file, or undefined when the file
67
+ * is not inside one. */
68
+ export declare function envelopeFor(filePath: string | undefined): string | undefined;
69
+ /**
70
+ * lookupUrl answers whether this URL is in the store, and what is known
71
+ * about it. `rootDir` is the store to look in; pass the global brain's root
72
+ * to ask the personal store.
73
+ */
74
+ export declare function lookupUrl(rawUrl: string, opts?: LookupOptions): UrlLookup;
75
+ /**
76
+ * lookupUrls answers a batch in one pass over the metadata, for a caller
77
+ * with several tabs to ask about. Same rules, same guarantees.
78
+ */
79
+ export declare function lookupUrls(urls: readonly string[], opts?: LookupOptions): UrlLookup[];
80
+ //# sourceMappingURL=lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../../src/knowledge/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAaH,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;6EACyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAID;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI3D;AAwBD;yBACyB;AACzB,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAQ5E;AAMD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,SAAS,CA8D7E;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,aAAkB,GAAG,SAAS,EAAE,CAEzF"}