@monoes/monomindcli 2.14.0 → 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 +5 -5
- 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 +69 -49
- 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 +26 -27
- 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 +406 -433
- 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/bin/cli.js +21 -1
- package/bin/mcp-server.js +21 -1
- package/dist/src/capabilities/cap-documents.d.ts.map +1 -1
- package/dist/src/capabilities/cap-documents.js +23 -0
- package/dist/src/capabilities/cap-documents.js.map +1 -1
- package/dist/src/commands/doc-filters.d.ts +19 -0
- package/dist/src/commands/doc-filters.d.ts.map +1 -0
- package/dist/src/commands/doc-filters.js +64 -0
- package/dist/src/commands/doc-filters.js.map +1 -0
- package/dist/src/commands/doc-library.d.ts +22 -0
- package/dist/src/commands/doc-library.d.ts.map +1 -0
- package/dist/src/commands/doc-library.js +454 -0
- package/dist/src/commands/doc-library.js.map +1 -0
- package/dist/src/commands/doc-list.d.ts +9 -0
- package/dist/src/commands/doc-list.d.ts.map +1 -0
- package/dist/src/commands/doc-list.js +99 -0
- package/dist/src/commands/doc-list.js.map +1 -0
- package/dist/src/commands/doc.d.ts.map +1 -1
- package/dist/src/commands/doc.js +51 -37
- 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 +85 -0
- package/dist/src/knowledge/capture-envelope.d.ts.map +1 -0
- package/dist/src/knowledge/capture-envelope.js +167 -0
- package/dist/src/knowledge/capture-envelope.js.map +1 -0
- package/dist/src/knowledge/capture-text.d.ts +23 -0
- package/dist/src/knowledge/capture-text.d.ts.map +1 -0
- package/dist/src/knowledge/capture-text.js +49 -0
- package/dist/src/knowledge/capture-text.js.map +1 -0
- package/dist/src/knowledge/citation.d.ts +121 -0
- package/dist/src/knowledge/citation.d.ts.map +1 -0
- package/dist/src/knowledge/citation.js +252 -0
- package/dist/src/knowledge/citation.js.map +1 -0
- 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 -148
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +25 -920
- 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/html-extract.d.ts +43 -0
- package/dist/src/knowledge/html-extract.d.ts.map +1 -0
- package/dist/src/knowledge/html-extract.js +286 -0
- package/dist/src/knowledge/html-extract.js.map +1 -0
- package/dist/src/knowledge/html-tags.d.ts +30 -0
- package/dist/src/knowledge/html-tags.d.ts.map +1 -0
- package/dist/src/knowledge/html-tags.js +229 -0
- package/dist/src/knowledge/html-tags.js.map +1 -0
- package/dist/src/knowledge/library.d.ts +106 -0
- package/dist/src/knowledge/library.d.ts.map +1 -0
- package/dist/src/knowledge/library.js +195 -0
- package/dist/src/knowledge/library.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/mhtml.d.ts +60 -0
- package/dist/src/knowledge/mhtml.d.ts.map +1 -0
- package/dist/src/knowledge/mhtml.js +154 -0
- package/dist/src/knowledge/mhtml.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/knowledge/related.d.ts +58 -0
- package/dist/src/knowledge/related.d.ts.map +1 -0
- package/dist/src/knowledge/related.js +222 -0
- package/dist/src/knowledge/related.js.map +1 -0
- package/dist/src/knowledge/section-diff.d.ts +48 -0
- package/dist/src/knowledge/section-diff.d.ts.map +1 -0
- package/dist/src/knowledge/section-diff.js +151 -0
- package/dist/src/knowledge/section-diff.js.map +1 -0
- package/dist/src/knowledge/watch.d.ts +92 -0
- package/dist/src/knowledge/watch.d.ts.map +1 -0
- package/dist/src/knowledge/watch.js +221 -0
- package/dist/src/knowledge/watch.js.map +1 -0
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +44 -87
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/browser-instrument-tools.d.ts +35 -0
- package/dist/src/mcp-tools/browser-instrument-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/browser-instrument-tools.js +359 -0
- package/dist/src/mcp-tools/browser-instrument-tools.js.map +1 -0
- package/dist/src/mcp-tools/browser-metrics.d.ts +42 -0
- package/dist/src/mcp-tools/browser-metrics.d.ts.map +1 -0
- package/dist/src/mcp-tools/browser-metrics.js +91 -0
- package/dist/src/mcp-tools/browser-metrics.js.map +1 -0
- package/dist/src/mcp-tools/browser-profile-tools.d.ts +16 -0
- package/dist/src/mcp-tools/browser-profile-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/browser-profile-tools.js +324 -0
- package/dist/src/mcp-tools/browser-profile-tools.js.map +1 -0
- package/dist/src/mcp-tools/browser-session.d.ts +68 -0
- package/dist/src/mcp-tools/browser-session.d.ts.map +1 -0
- package/dist/src/mcp-tools/browser-session.js +224 -0
- package/dist/src/mcp-tools/browser-session.js.map +1 -0
- package/dist/src/mcp-tools/browser-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/browser-tools.js +10 -176
- package/dist/src/mcp-tools/browser-tools.js.map +1 -1
- package/dist/src/mcp-tools/capture-resource-read.d.ts +115 -0
- package/dist/src/mcp-tools/capture-resource-read.d.ts.map +1 -0
- package/dist/src/mcp-tools/capture-resource-read.js +296 -0
- package/dist/src/mcp-tools/capture-resource-read.js.map +1 -0
- package/dist/src/mcp-tools/capture-resource-tools.d.ts +22 -0
- package/dist/src/mcp-tools/capture-resource-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/capture-resource-tools.js +182 -0
- package/dist/src/mcp-tools/capture-resource-tools.js.map +1 -0
- package/dist/src/mcp-tools/capture-resources.d.ts +142 -0
- package/dist/src/mcp-tools/capture-resources.d.ts.map +1 -0
- package/dist/src/mcp-tools/capture-resources.js +289 -0
- package/dist/src/mcp-tools/capture-resources.js.map +1 -0
- package/dist/src/mcp-tools/index.d.ts +3 -0
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +6 -0
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.js +9 -1
- package/dist/src/mcp-tools/knowledge-tools.js.map +1 -1
- package/dist/src/mcp-tools/resource-router.d.ts +86 -0
- package/dist/src/mcp-tools/resource-router.d.ts.map +1 -0
- package/dist/src/mcp-tools/resource-router.js +181 -0
- package/dist/src/mcp-tools/resource-router.js.map +1 -0
- package/dist/src/memory/memory-bridge.js +1 -1
- package/dist/src/memory/memory-bridge.js.map +1 -1
- 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-ledger.d.ts +7 -0
- package/dist/src/orgrt/session-ledger.d.ts.map +1 -1
- package/dist/src/orgrt/session-ledger.js +15 -0
- package/dist/src/orgrt/session-ledger.js.map +1 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +42 -10
- 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 +9 -9
|
@@ -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,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free HTML → readable Markdown-ish text (RCL-01).
|
|
3
|
+
*
|
|
4
|
+
* WHY NO DEPENDENCY — the capture path has to work in an `npx monomind`
|
|
5
|
+
* install with nothing extra resolved, and the extension already runs
|
|
6
|
+
* Readability against the live DOM. What lands here is the fallback for an
|
|
7
|
+
* archive nobody cleaned: a small, predictable extractor beats a large one we
|
|
8
|
+
* cannot install.
|
|
9
|
+
*
|
|
10
|
+
* WHY BOILERPLATE STRIPPING IS THE POINT — a site's nav, header, footer and
|
|
11
|
+
* cookie banner are byte-identical on every page. Leave them in and every
|
|
12
|
+
* document from that site chunks into near-identical text, so their embeddings
|
|
13
|
+
* cluster on the chrome rather than the article and recall collapses. Dropping
|
|
14
|
+
* a little real content is a far cheaper error than keeping the chrome.
|
|
15
|
+
*
|
|
16
|
+
* @module v1/cli/knowledge/html-extract
|
|
17
|
+
*/
|
|
18
|
+
import { decodeEntities } from './html-tags.js';
|
|
19
|
+
export { decodeEntities };
|
|
20
|
+
export interface HtmlExtractOptions {
|
|
21
|
+
/** Drop nav/header/footer/aside/cookie-banner containers. Default true. */
|
|
22
|
+
stripBoilerplate?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface ExtractedHtml {
|
|
25
|
+
/** `<title>` text, or null when the document has none. */
|
|
26
|
+
title: string | null;
|
|
27
|
+
/** Markdown-ish body text; headings as ATX, list items as `- `. */
|
|
28
|
+
text: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse `html` into a title and clean block text.
|
|
32
|
+
*
|
|
33
|
+
* Unbalanced markup is expected — real archives are full of it — so closing a
|
|
34
|
+
* tag pops back to its last matching open and a never-closed element simply
|
|
35
|
+
* stays open until its parent closes. Nothing here throws.
|
|
36
|
+
*/
|
|
37
|
+
export declare function extractHtmlDocument(html: string, opts?: HtmlExtractOptions): ExtractedHtml;
|
|
38
|
+
/**
|
|
39
|
+
* Clean text for an HTML document, with the `<title>` promoted to an `# h1`
|
|
40
|
+
* when the page has no top-level heading of its own.
|
|
41
|
+
*/
|
|
42
|
+
export declare function htmlToMarkdown(html: string, opts?: HtmlExtractOptions): string;
|
|
43
|
+
//# sourceMappingURL=html-extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-extract.d.ts","sourceRoot":"","sources":["../../../src/knowledge/html-extract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAML,cAAc,EAIf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;CACd;AAoLD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,aAAa,CAwF9F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,CAKlF"}
|