@omgbase/core 0.1.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/LICENSE +21 -0
- package/dist/src/cli/eval-matcher.d.ts +13 -0
- package/dist/src/cli/eval-matcher.js +36 -0
- package/dist/src/core/attach.d.ts +5 -0
- package/dist/src/core/attach.js +38 -0
- package/dist/src/core/cursor.d.ts +11 -0
- package/dist/src/core/cursor.js +35 -0
- package/dist/src/core/hash.d.ts +23 -0
- package/dist/src/core/hash.js +82 -0
- package/dist/src/core/ids.d.ts +6 -0
- package/dist/src/core/ids.js +26 -0
- package/dist/src/core/index.d.ts +1 -0
- package/dist/src/core/index.js +2 -0
- package/dist/src/core/ingest.d.ts +43 -0
- package/dist/src/core/ingest.js +287 -0
- package/dist/src/core/order-key.d.ts +8 -0
- package/dist/src/core/order-key.js +72 -0
- package/dist/src/core/parse/parse.d.ts +3 -0
- package/dist/src/core/parse/parse.js +104 -0
- package/dist/src/core/parse/render.d.ts +3 -0
- package/dist/src/core/parse/render.js +20 -0
- package/dist/src/core/parse/tree.d.ts +8 -0
- package/dist/src/core/parse/tree.js +43 -0
- package/dist/src/core/parse/types.d.ts +52 -0
- package/dist/src/core/parse/types.js +9 -0
- package/dist/src/core/read/document.d.ts +107 -0
- package/dist/src/core/read/document.js +191 -0
- package/dist/src/core/read/nodes.d.ts +47 -0
- package/dist/src/core/read/nodes.js +102 -0
- package/dist/src/core/read/outline.d.ts +12 -0
- package/dist/src/core/read/outline.js +76 -0
- package/dist/src/core/read/reader.d.ts +125 -0
- package/dist/src/core/read/reader.js +206 -0
- package/dist/src/core/read/refs.d.ts +15 -0
- package/dist/src/core/read/refs.js +51 -0
- package/dist/src/core/store/edges.d.ts +26 -0
- package/dist/src/core/store/edges.js +101 -0
- package/dist/src/core/store/fts.d.ts +10 -0
- package/dist/src/core/store/fts.js +22 -0
- package/dist/src/core/store/gc.d.ts +18 -0
- package/dist/src/core/store/gc.js +69 -0
- package/dist/src/core/store/nodes.d.ts +5 -0
- package/dist/src/core/store/nodes.js +57 -0
- package/dist/src/core/store/properties.d.ts +38 -0
- package/dist/src/core/store/properties.js +177 -0
- package/dist/src/core/store/rebuild.d.ts +3 -0
- package/dist/src/core/store/rebuild.js +29 -0
- package/dist/src/core/store/schema.d.ts +9 -0
- package/dist/src/core/store/schema.js +386 -0
- package/dist/src/core/store/sections.d.ts +2 -0
- package/dist/src/core/store/sections.js +29 -0
- package/dist/src/core/store/store.d.ts +24 -0
- package/dist/src/core/store/store.js +164 -0
- package/dist/src/core/store/writers.d.ts +52 -0
- package/dist/src/core/store/writers.js +89 -0
- package/dist/src/core/vec.d.ts +10 -0
- package/dist/src/core/vec.js +33 -0
- package/dist/src/format/adapter.d.ts +97 -0
- package/dist/src/format/adapter.js +14 -0
- package/dist/src/format/index.d.ts +6 -0
- package/dist/src/format/index.js +15 -0
- package/dist/src/format/json.d.ts +3 -0
- package/dist/src/format/json.js +324 -0
- package/dist/src/format/markdown.d.ts +5 -0
- package/dist/src/format/markdown.js +217 -0
- package/dist/src/format/registry.d.ts +6 -0
- package/dist/src/format/registry.js +24 -0
- package/dist/src/format/yaml.d.ts +5 -0
- package/dist/src/format/yaml.js +413 -0
- package/dist/src/graph/extract.d.ts +38 -0
- package/dist/src/graph/extract.js +242 -0
- package/dist/src/graph/history.d.ts +103 -0
- package/dist/src/graph/history.js +210 -0
- package/dist/src/graph/inbound-links.d.ts +33 -0
- package/dist/src/graph/inbound-links.js +130 -0
- package/dist/src/graph/link-destinations.d.ts +22 -0
- package/dist/src/graph/link-destinations.js +84 -0
- package/dist/src/graph/link-health.d.ts +79 -0
- package/dist/src/graph/link-health.js +146 -0
- package/dist/src/graph/links.d.ts +23 -0
- package/dist/src/graph/links.js +42 -0
- package/dist/src/index.d.ts +60 -0
- package/dist/src/index.js +70 -0
- package/dist/src/mcp/errors.d.ts +17 -0
- package/dist/src/mcp/errors.js +18 -0
- package/dist/src/mcp/graph.d.ts +63 -0
- package/dist/src/mcp/graph.js +212 -0
- package/dist/src/mcp/reference.d.ts +1 -0
- package/dist/src/mcp/reference.js +227 -0
- package/dist/src/mcp/server.d.ts +30 -0
- package/dist/src/mcp/server.js +1076 -0
- package/dist/src/mcp/stdio.d.ts +13 -0
- package/dist/src/mcp/stdio.js +24 -0
- package/dist/src/migrate/mrplex.d.ts +27 -0
- package/dist/src/migrate/mrplex.js +29 -0
- package/dist/src/mutate/apply.d.ts +83 -0
- package/dist/src/mutate/apply.js +302 -0
- package/dist/src/mutate/doc-store.d.ts +49 -0
- package/dist/src/mutate/doc-store.js +71 -0
- package/dist/src/mutate/docs.d.ts +60 -0
- package/dist/src/mutate/docs.js +232 -0
- package/dist/src/mutate/known-ids.d.ts +12 -0
- package/dist/src/mutate/known-ids.js +154 -0
- package/dist/src/mutate/load.d.ts +3 -0
- package/dist/src/mutate/load.js +66 -0
- package/dist/src/mutate/lower.d.ts +32 -0
- package/dist/src/mutate/lower.js +232 -0
- package/dist/src/mutate/macros.d.ts +91 -0
- package/dist/src/mutate/macros.js +230 -0
- package/dist/src/mutate/ops.d.ts +40 -0
- package/dist/src/mutate/ops.js +513 -0
- package/dist/src/mutate/opset.d.ts +92 -0
- package/dist/src/mutate/opset.js +79 -0
- package/dist/src/mutate/plan-update.d.ts +51 -0
- package/dist/src/mutate/plan-update.js +187 -0
- package/dist/src/mutate/tree.d.ts +46 -0
- package/dist/src/mutate/tree.js +167 -0
- package/dist/src/oqx/run.d.ts +1 -0
- package/dist/src/oqx/run.js +6 -0
- package/dist/src/oqx-js/context.d.ts +23 -0
- package/dist/src/oqx-js/context.js +564 -0
- package/dist/src/oqx-js/planner.d.ts +10 -0
- package/dist/src/oqx-js/planner.js +91 -0
- package/dist/src/oqx-js/run.d.ts +41 -0
- package/dist/src/oqx-js/run.js +332 -0
- package/dist/src/oqx-js/sql/translate.d.ts +27 -0
- package/dist/src/oqx-js/sql/translate.js +290 -0
- package/dist/src/reconcile/crossdoc.d.ts +34 -0
- package/dist/src/reconcile/crossdoc.js +76 -0
- package/dist/src/reconcile/eval/generator.d.ts +21 -0
- package/dist/src/reconcile/eval/generator.js +129 -0
- package/dist/src/reconcile/eval/metrics.d.ts +32 -0
- package/dist/src/reconcile/eval/metrics.js +74 -0
- package/dist/src/reconcile/flatten.d.ts +12 -0
- package/dist/src/reconcile/flatten.js +37 -0
- package/dist/src/reconcile/phase5.d.ts +8 -0
- package/dist/src/reconcile/phase5.js +167 -0
- package/dist/src/reconcile/phase6a.d.ts +2 -0
- package/dist/src/reconcile/phase6a.js +159 -0
- package/dist/src/reconcile/phases.d.ts +28 -0
- package/dist/src/reconcile/phases.js +0 -0
- package/dist/src/reconcile/reconcile.d.ts +21 -0
- package/dist/src/reconcile/reconcile.js +115 -0
- package/dist/src/reconcile/similarity.d.ts +7 -0
- package/dist/src/reconcile/similarity.js +41 -0
- package/dist/src/reconcile/types.d.ts +46 -0
- package/dist/src/reconcile/types.js +19 -0
- package/dist/src/search/cel/ast.d.ts +74 -0
- package/dist/src/search/cel/ast.js +3 -0
- package/dist/src/search/cel/compile.d.ts +60 -0
- package/dist/src/search/cel/compile.js +836 -0
- package/dist/src/search/cel/lexer.d.ts +9 -0
- package/dist/src/search/cel/lexer.js +139 -0
- package/dist/src/search/cel/parser.d.ts +7 -0
- package/dist/src/search/cel/parser.js +219 -0
- package/dist/src/search/drain.d.ts +39 -0
- package/dist/src/search/drain.js +97 -0
- package/dist/src/search/embeddings.d.ts +131 -0
- package/dist/src/search/embeddings.js +263 -0
- package/dist/src/search/external.d.ts +13 -0
- package/dist/src/search/external.js +177 -0
- package/dist/src/search/fts-query.d.ts +1 -0
- package/dist/src/search/fts-query.js +64 -0
- package/dist/src/search/provider.d.ts +17 -0
- package/dist/src/search/provider.js +13 -0
- package/dist/src/search/resolve.d.ts +18 -0
- package/dist/src/search/resolve.js +23 -0
- package/dist/src/search/rrf.d.ts +36 -0
- package/dist/src/search/rrf.js +84 -0
- package/dist/src/search/tasks.d.ts +12 -0
- package/dist/src/search/tasks.js +131 -0
- package/dist/src/search/text.d.ts +16 -0
- package/dist/src/search/text.js +21 -0
- package/dist/src/search/vector.d.ts +18 -0
- package/dist/src/search/vector.js +49 -0
- package/dist/src/sync/admin.d.ts +59 -0
- package/dist/src/sync/admin.js +53 -0
- package/dist/src/sync/attach.d.ts +13 -0
- package/dist/src/sync/attach.js +29 -0
- package/dist/src/sync/checkpoint.d.ts +21 -0
- package/dist/src/sync/checkpoint.js +52 -0
- package/dist/src/sync/driver.d.ts +25 -0
- package/dist/src/sync/driver.js +80 -0
- package/dist/src/sync/external-source.d.ts +14 -0
- package/dist/src/sync/external-source.js +137 -0
- package/dist/src/sync/freshness.d.ts +42 -0
- package/dist/src/sync/freshness.js +152 -0
- package/dist/src/sync/fs-util.d.ts +12 -0
- package/dist/src/sync/fs-util.js +55 -0
- package/dist/src/sync/git-heuristics.d.ts +6 -0
- package/dist/src/sync/git-heuristics.js +16 -0
- package/dist/src/sync/observe.d.ts +63 -0
- package/dist/src/sync/observe.js +84 -0
- package/dist/src/sync/plugin.d.ts +54 -0
- package/dist/src/sync/plugin.js +12 -0
- package/dist/src/sync/reconciling-ingest.d.ts +12 -0
- package/dist/src/sync/reconciling-ingest.js +209 -0
- package/dist/src/sync/recovery.d.ts +6 -0
- package/dist/src/sync/recovery.js +34 -0
- package/dist/src/sync/settings.d.ts +18 -0
- package/dist/src/sync/settings.js +58 -0
- package/dist/src/sync/sources.d.ts +37 -0
- package/dist/src/sync/sources.js +75 -0
- package/dist/src/sync/tombstone.d.ts +9 -0
- package/dist/src/sync/tombstone.js +55 -0
- package/dist/src/sync/watch-lease.d.ts +14 -0
- package/dist/src/sync/watch-lease.js +91 -0
- package/dist/src/sync/watcher.d.ts +19 -0
- package/dist/src/sync/watcher.js +34 -0
- package/dist/src/sync/workspace.d.ts +34 -0
- package/dist/src/sync/workspace.js +120 -0
- package/dist/src/sync/writer-lock.d.ts +16 -0
- package/dist/src/sync/writer-lock.js +121 -0
- package/package.json +80 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { loadDocBlocks, blockRaw } from "./reader.js";
|
|
2
|
+
function firstWords(text, n) {
|
|
3
|
+
const w = text.split(/\s+/).filter(Boolean);
|
|
4
|
+
return w.length <= n ? w.join(" ") : w.slice(0, n).join(" ") + "…";
|
|
5
|
+
}
|
|
6
|
+
function project(store, node, resolution, includeChildren) {
|
|
7
|
+
const out = { id: node.blockId, type: node.type };
|
|
8
|
+
switch (resolution) {
|
|
9
|
+
case "skeleton":
|
|
10
|
+
out.label = node.type === "heading" ? node.text : node.type;
|
|
11
|
+
break;
|
|
12
|
+
case "outline":
|
|
13
|
+
out.label = firstWords(node.text, 10);
|
|
14
|
+
break;
|
|
15
|
+
case "text":
|
|
16
|
+
out.text = node.text;
|
|
17
|
+
break;
|
|
18
|
+
case "raw":
|
|
19
|
+
out.raw = blockRaw(store, node.rawHashHex);
|
|
20
|
+
out.content_hash = node.rawHashHex;
|
|
21
|
+
break;
|
|
22
|
+
case "full":
|
|
23
|
+
out.raw = blockRaw(store, node.rawHashHex);
|
|
24
|
+
out.content_hash = node.rawHashHex;
|
|
25
|
+
out.text = node.text;
|
|
26
|
+
out.attrs = node.attrs;
|
|
27
|
+
out.placement = { parent: node.parentBlock, ordinal: node.ordinal, depth: node.depth };
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (includeChildren && node.children.length > 0) {
|
|
31
|
+
out.children = node.children.map((c) => project(store, c, resolution, true));
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function findBlock(roots, blockId) {
|
|
36
|
+
for (const n of roots) {
|
|
37
|
+
if (n.blockId === blockId)
|
|
38
|
+
return n;
|
|
39
|
+
const found = findBlock(n.children, blockId);
|
|
40
|
+
if (found)
|
|
41
|
+
return found;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/** Fetch a single block subtree at a resolution. Returns null if missing. */
|
|
46
|
+
export function nodesGet(store, docId, blockId, opts = {}) {
|
|
47
|
+
const roots = loadDocBlocks(store, docId);
|
|
48
|
+
const node = findBlock(roots, blockId);
|
|
49
|
+
if (!node)
|
|
50
|
+
return null;
|
|
51
|
+
const includeChildren = opts.include?.includes("children") ?? true;
|
|
52
|
+
return project(store, node, opts.resolution ?? "full", includeChildren);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Fetch up to 100 blocks by id, with budget truncation (06 §3). Block ids are
|
|
56
|
+
* globally unique, so `docId` is an optional SCOPE, not a requirement: with
|
|
57
|
+
* `null` each id is resolved to its owning document (`blocks.doc_id`), the ids
|
|
58
|
+
* are grouped by doc, each doc's forest is loaded once, and the nodes come back
|
|
59
|
+
* in request order. With a `docId`, ids from other documents count as
|
|
60
|
+
* `unresolved` (the caller asked for that doc's blocks).
|
|
61
|
+
*/
|
|
62
|
+
export function nodesGetMany(store, docId, blockIds, opts = {}) {
|
|
63
|
+
const capped = blockIds.slice(0, 100);
|
|
64
|
+
const budget = opts.budgetTokens ?? Infinity;
|
|
65
|
+
const resolution = opts.resolution ?? "text";
|
|
66
|
+
// id → owning doc for every requested id that is a live block (one query).
|
|
67
|
+
const owner = new Map();
|
|
68
|
+
if (capped.length > 0) {
|
|
69
|
+
const rows = store.db
|
|
70
|
+
.prepare(`SELECT block_id, doc_id FROM blocks WHERE deleted_commit IS NULL AND block_id IN (${capped.map(() => "?").join(",")})`)
|
|
71
|
+
.all(...capped);
|
|
72
|
+
for (const r of rows)
|
|
73
|
+
if (docId === null || r.doc_id === docId)
|
|
74
|
+
owner.set(r.block_id, r.doc_id);
|
|
75
|
+
}
|
|
76
|
+
// Load each involved document's forest once.
|
|
77
|
+
const forests = new Map();
|
|
78
|
+
for (const d of new Set(owner.values()))
|
|
79
|
+
forests.set(d, loadDocBlocks(store, d));
|
|
80
|
+
const nodes = [];
|
|
81
|
+
const unresolved = [];
|
|
82
|
+
let tokens = 0;
|
|
83
|
+
let truncated = blockIds.length > 100;
|
|
84
|
+
for (const id of capped) {
|
|
85
|
+
const d = owner.get(id);
|
|
86
|
+
const node = d ? findBlock(forests.get(d), id) : null;
|
|
87
|
+
if (!node) {
|
|
88
|
+
unresolved.push(id);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const projected = project(store, node, resolution, false);
|
|
92
|
+
const cost = Math.ceil(JSON.stringify(projected).length / 4);
|
|
93
|
+
if (tokens + cost > budget) {
|
|
94
|
+
truncated = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
tokens += cost;
|
|
98
|
+
nodes.push(projected);
|
|
99
|
+
}
|
|
100
|
+
return { nodes, truncated, unresolved };
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=nodes.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Store } from "../store/store.js";
|
|
2
|
+
export interface OutlineResult {
|
|
3
|
+
text: string;
|
|
4
|
+
truncated: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface OutlineOptions {
|
|
7
|
+
resolution?: "skeleton" | "outline";
|
|
8
|
+
depth?: number;
|
|
9
|
+
budgetTokens?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Render a document outline in the frozen wire format. */
|
|
12
|
+
export declare function docsOutline(store: Store, docId: string, opts?: OutlineOptions): OutlineResult;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { loadDocBlocks } from "./reader.js";
|
|
2
|
+
// Outline wire format (06 §6). Each line:
|
|
3
|
+
// <block-id> <type-abbr> <label> [§ for section-owning headings]
|
|
4
|
+
// The full block id (b_…) is emitted inline so it can be used directly in
|
|
5
|
+
// follow-up ops without a separate alias→id lookup table.
|
|
6
|
+
const TYPE_ABBR = {
|
|
7
|
+
heading: "h",
|
|
8
|
+
paragraph: "p",
|
|
9
|
+
list: "ul",
|
|
10
|
+
list_item: "li",
|
|
11
|
+
task: "li",
|
|
12
|
+
blockquote: "bq",
|
|
13
|
+
code_fence: "code",
|
|
14
|
+
table: "tbl",
|
|
15
|
+
table_row: "tr",
|
|
16
|
+
thematic_break: "hr",
|
|
17
|
+
html_block: "html",
|
|
18
|
+
opaque: "raw",
|
|
19
|
+
};
|
|
20
|
+
function typeLabel(node) {
|
|
21
|
+
if (node.type === "heading")
|
|
22
|
+
return `h${node.attrs.level ?? ""}`;
|
|
23
|
+
return TYPE_ABBR[node.type] ?? node.type;
|
|
24
|
+
}
|
|
25
|
+
// Structural containers carry no label of their own; their content is in
|
|
26
|
+
// children (matches the frozen format example, 06 §6: `b03 ul` has no label).
|
|
27
|
+
const CONTAINER_TYPES = new Set(["list", "blockquote", "table"]);
|
|
28
|
+
function labelFor(node) {
|
|
29
|
+
if (CONTAINER_TYPES.has(node.type))
|
|
30
|
+
return "";
|
|
31
|
+
if (node.type === "task") {
|
|
32
|
+
const glyph = node.attrs.checked ? "☑" : "☐";
|
|
33
|
+
return `${glyph} ${truncateWords(node.text, 10)}`;
|
|
34
|
+
}
|
|
35
|
+
return truncateWords(node.text, 10);
|
|
36
|
+
}
|
|
37
|
+
function truncateWords(text, n) {
|
|
38
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
39
|
+
if (words.length <= n)
|
|
40
|
+
return words.join(" ");
|
|
41
|
+
return words.slice(0, n).join(" ") + "…";
|
|
42
|
+
}
|
|
43
|
+
/** Render a document outline in the frozen wire format. */
|
|
44
|
+
export function docsOutline(store, docId, opts = {}) {
|
|
45
|
+
const roots = loadDocBlocks(store, docId);
|
|
46
|
+
const resolution = opts.resolution ?? "outline";
|
|
47
|
+
const maxDepth = opts.depth ?? Infinity;
|
|
48
|
+
const budget = opts.budgetTokens ?? Infinity;
|
|
49
|
+
const lines = [];
|
|
50
|
+
let tokens = 0;
|
|
51
|
+
let truncated = false;
|
|
52
|
+
const walk = (nodes, indent) => {
|
|
53
|
+
for (const node of nodes) {
|
|
54
|
+
if (truncated)
|
|
55
|
+
return;
|
|
56
|
+
if (indent > maxDepth)
|
|
57
|
+
continue;
|
|
58
|
+
const pad = " ".repeat(indent);
|
|
59
|
+
const sectionMark = node.type === "heading" ? " §" : "";
|
|
60
|
+
const label = resolution === "skeleton" ? "" : labelFor(node);
|
|
61
|
+
const line = `${pad}${node.blockId} ${typeLabel(node).padEnd(4)} ${label}${sectionMark}`.trimEnd();
|
|
62
|
+
const lineTokens = Math.ceil(line.length / 4);
|
|
63
|
+
if (tokens + lineTokens > budget) {
|
|
64
|
+
truncated = true;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
tokens += lineTokens;
|
|
68
|
+
lines.push(line);
|
|
69
|
+
if (node.children.length > 0)
|
|
70
|
+
walk(node.children, indent + 1);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
walk(roots, 0);
|
|
74
|
+
return { text: lines.join("\n"), truncated };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=outline.js.map
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { Store } from "../store/store.js";
|
|
2
|
+
/** One row of the `ls` / docs_list surface: a live document with its block
|
|
3
|
+
* count and last-commit timestamp. */
|
|
4
|
+
export interface DocListRow {
|
|
5
|
+
path: string;
|
|
6
|
+
blocks: number;
|
|
7
|
+
ts: string | null;
|
|
8
|
+
}
|
|
9
|
+
/** A page of the docs_list surface. Honors the uniform list contract (mcp-api
|
|
10
|
+
* §1): `truncated` is honest, and when true `cursor` resumes after the last
|
|
11
|
+
* item returned. */
|
|
12
|
+
export interface DocListPage {
|
|
13
|
+
items: DocListRow[];
|
|
14
|
+
truncated: boolean;
|
|
15
|
+
cursor: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface DocListOptions {
|
|
18
|
+
/** Simple LIKE match on the path (`*` → any run, ACROSS `/`). */
|
|
19
|
+
pathGlob?: string;
|
|
20
|
+
/** Max rows per page (default DOCS_LIST_DEFAULT_LIMIT). */
|
|
21
|
+
limit?: number;
|
|
22
|
+
/** Resume after a previous page's `cursor`. */
|
|
23
|
+
cursor?: string | null;
|
|
24
|
+
/** Cap the page's estimated size (~4 chars/token); at least one row is always
|
|
25
|
+
* returned so a paging client makes progress. */
|
|
26
|
+
budgetTokens?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare const DOCS_LIST_DEFAULT_LIMIT = 200;
|
|
29
|
+
/** List a repo's live documents (path, block count, last-commit ts), ordered by
|
|
30
|
+
* path, as a page: `{ items, truncated, cursor }`. `pathGlob` is a simple LIKE
|
|
31
|
+
* match (`*` → `%`). Backs `omg ls` and the `docs_list` MCP tool (one
|
|
32
|
+
* implementation for both surfaces). For a directory-aware summary use
|
|
33
|
+
* `docsTree`. */
|
|
34
|
+
export declare function docsList(store: Store, repoId: string, opts?: DocListOptions): DocListPage;
|
|
35
|
+
/** One entry of the docs_tree surface: a live document (`kind: "doc"`) or a
|
|
36
|
+
* collapsed directory (`kind: "dir"`, path ends in `/`) at the requested
|
|
37
|
+
* depth. `docs`/`blocks` are totals under the entry (a doc counts 1 doc);
|
|
38
|
+
* `ts` is the latest last-commit timestamp under it. */
|
|
39
|
+
export interface DocTreeEntry {
|
|
40
|
+
path: string;
|
|
41
|
+
kind: "dir" | "doc";
|
|
42
|
+
docs: number;
|
|
43
|
+
blocks: number;
|
|
44
|
+
ts: string | null;
|
|
45
|
+
}
|
|
46
|
+
export interface DocTreePage {
|
|
47
|
+
/** The normalized directory prefix the tree was taken under (`""` = root;
|
|
48
|
+
* otherwise ends in `/`). */
|
|
49
|
+
prefix: string;
|
|
50
|
+
depth: number;
|
|
51
|
+
/** Totals over EVERYTHING under `prefix`, regardless of paging. */
|
|
52
|
+
total: {
|
|
53
|
+
docs: number;
|
|
54
|
+
blocks: number;
|
|
55
|
+
};
|
|
56
|
+
entries: DocTreeEntry[];
|
|
57
|
+
truncated: boolean;
|
|
58
|
+
cursor: string | null;
|
|
59
|
+
}
|
|
60
|
+
export interface DocTreeOptions {
|
|
61
|
+
/** Directory to take the tree under (`projects` or `projects/`; leading `/`
|
|
62
|
+
* tolerated). Omit for the repo root. */
|
|
63
|
+
path?: string;
|
|
64
|
+
/** How many path segments below `prefix` to expand before collapsing
|
|
65
|
+
* (default 1 = immediate children, like `tree -L 1`). */
|
|
66
|
+
depth?: number;
|
|
67
|
+
limit?: number;
|
|
68
|
+
cursor?: string | null;
|
|
69
|
+
budgetTokens?: number;
|
|
70
|
+
}
|
|
71
|
+
export declare const DOCS_TREE_DEFAULT_LIMIT = 200;
|
|
72
|
+
/** Normalize a tree prefix: no leading `/`, and either empty or ending in `/`. */
|
|
73
|
+
export declare function normalizeTreePrefix(path: string | undefined): string;
|
|
74
|
+
/** The path-separator-aware orientation read (`tree -L depth` + `du`): every
|
|
75
|
+
* live doc under `path` is collapsed at `depth` segments into one entry per
|
|
76
|
+
* directory (with doc/block totals + latest ts) or listed as a doc when it is
|
|
77
|
+
* shallow enough. Entries are ordered by path; dirs carry a trailing `/`. The
|
|
78
|
+
* result is paged under the same limit/cursor/budget contract as docsList,
|
|
79
|
+
* and always carries `total` for the whole prefix so an agent sees the size of
|
|
80
|
+
* what it is looking at even when the page is cut. Backs the `docs_tree` MCP
|
|
81
|
+
* tool. */
|
|
82
|
+
export declare function docsTree(store: Store, repoId: string, opts?: DocTreeOptions): DocTreePage;
|
|
83
|
+
export interface BlockNode {
|
|
84
|
+
blockId: string;
|
|
85
|
+
docId: string;
|
|
86
|
+
parentBlock: string | null;
|
|
87
|
+
ordinal: number;
|
|
88
|
+
depth: number;
|
|
89
|
+
type: string;
|
|
90
|
+
attrs: Record<string, unknown>;
|
|
91
|
+
text: string;
|
|
92
|
+
rawHashHex: string;
|
|
93
|
+
children: BlockNode[];
|
|
94
|
+
}
|
|
95
|
+
/** Load a document's live blocks as a containment forest, ordered. */
|
|
96
|
+
export declare function loadDocBlocks(store: Store, docId: string): BlockNode[];
|
|
97
|
+
/** Retrieve the raw source bytes for a block by its raw_hash. */
|
|
98
|
+
export declare function blockRaw(store: Store, rawHashHex: string): string;
|
|
99
|
+
export interface DocInfo {
|
|
100
|
+
docId: string;
|
|
101
|
+
repoId: string;
|
|
102
|
+
path: string;
|
|
103
|
+
format: string;
|
|
104
|
+
currentRev: string | null;
|
|
105
|
+
}
|
|
106
|
+
export declare function findDoc(store: Store, ref: {
|
|
107
|
+
docId?: string;
|
|
108
|
+
repoId?: string;
|
|
109
|
+
path?: string;
|
|
110
|
+
}): DocInfo | null;
|
|
111
|
+
/**
|
|
112
|
+
* Resolve a single `doc` ref that may be EITHER a minted document id (`d_…`) OR
|
|
113
|
+
* a repo-relative path — the id-or-path symmetry every doc-ref surface expects
|
|
114
|
+
* (docs_read/outline/read_at, diff, apply's insert.doc, graph seeds, docHistory).
|
|
115
|
+
* This is the ONE dispatch those call sites route through so the "path in the
|
|
116
|
+
* doc field" trap can't recur per-tool.
|
|
117
|
+
*
|
|
118
|
+
* A `d_`-shaped id is looked up by id ONLY — if it doesn't exist we return null
|
|
119
|
+
* (the caller fails loud) rather than falling through to a path lookup that
|
|
120
|
+
* would also miss and confusingly report a path-not-found for a d_ value.
|
|
121
|
+
* Anything else is treated as a path. Returns null when unresolvable; callers
|
|
122
|
+
* throw a clear doc_missing/target_missing so an unresolvable ref is never a
|
|
123
|
+
* silent empty result.
|
|
124
|
+
*/
|
|
125
|
+
export declare function findDocByRef(store: Store, repoId: string, ref: string): DocInfo | null;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { isValidId } from "../ids.js";
|
|
2
|
+
import { encodeCursor, decodeCursor } from "../cursor.js";
|
|
3
|
+
export const DOCS_LIST_DEFAULT_LIMIT = 200;
|
|
4
|
+
/** Escape a user glob into a LIKE pattern (`*` → `%`; literal `%`/`_` escaped). */
|
|
5
|
+
function globToLike(glob) {
|
|
6
|
+
return glob.replace(/[%_\\]/g, "\\$&").replace(/\*/g, "%");
|
|
7
|
+
}
|
|
8
|
+
/** Live docs of a repo (path, live block count, last-commit ts) whose path
|
|
9
|
+
* matches `like`, ordered by path, optionally resuming strictly after `after`
|
|
10
|
+
* and capped at `limit`. The one query behind docs_list and docs_tree. */
|
|
11
|
+
function liveDocRows(store, repoId, like, after, limit) {
|
|
12
|
+
const params = [repoId, like];
|
|
13
|
+
let where = "";
|
|
14
|
+
if (after !== null) {
|
|
15
|
+
where += " AND d.path > ?";
|
|
16
|
+
params.push(after);
|
|
17
|
+
}
|
|
18
|
+
let tail = "";
|
|
19
|
+
if (limit !== null) {
|
|
20
|
+
tail = " LIMIT ?";
|
|
21
|
+
params.push(limit);
|
|
22
|
+
}
|
|
23
|
+
return store.db
|
|
24
|
+
.prepare(`SELECT d.path AS path,
|
|
25
|
+
(SELECT count(*) FROM blocks b WHERE b.doc_id = d.doc_id AND b.deleted_commit IS NULL) AS blocks,
|
|
26
|
+
(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = d.current_rev) AS ts
|
|
27
|
+
FROM docs d
|
|
28
|
+
WHERE d.repo_id = ? AND d.deleted_commit IS NULL AND d.path LIKE ? ESCAPE '\\'${where}
|
|
29
|
+
ORDER BY d.path${tail}`)
|
|
30
|
+
.all(...params);
|
|
31
|
+
}
|
|
32
|
+
// Path-keyset cursors for the path-ordered list surfaces: the shared kernel
|
|
33
|
+
// encoding (core/cursor.ts) with a one-part tuple.
|
|
34
|
+
function encodePathCursor(path) {
|
|
35
|
+
return encodeCursor([path]);
|
|
36
|
+
}
|
|
37
|
+
function decodePathCursor(cursor) {
|
|
38
|
+
return decodeCursor(cursor, "docs_list/docs_tree", 1)[0];
|
|
39
|
+
}
|
|
40
|
+
/** Page an already path-ordered row set under a limit + token budget, issuing
|
|
41
|
+
* a keyset cursor when it stops early. Shared by docs_list and docs_tree. */
|
|
42
|
+
function pagePathOrdered(rows, limit, budgetTokens, moreBeyond) {
|
|
43
|
+
const budget = budgetTokens ?? Infinity;
|
|
44
|
+
const items = [];
|
|
45
|
+
let tokens = 0;
|
|
46
|
+
let truncated = moreBeyond;
|
|
47
|
+
for (const row of rows) {
|
|
48
|
+
if (items.length >= limit) {
|
|
49
|
+
truncated = true;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
const cost = Math.ceil(JSON.stringify(row).length / 4);
|
|
53
|
+
if (items.length > 0 && tokens + cost > budget) {
|
|
54
|
+
truncated = true;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
tokens += cost;
|
|
58
|
+
items.push(row);
|
|
59
|
+
}
|
|
60
|
+
const last = items[items.length - 1];
|
|
61
|
+
return { items, truncated, cursor: truncated && last ? encodePathCursor(last.path) : null };
|
|
62
|
+
}
|
|
63
|
+
/** List a repo's live documents (path, block count, last-commit ts), ordered by
|
|
64
|
+
* path, as a page: `{ items, truncated, cursor }`. `pathGlob` is a simple LIKE
|
|
65
|
+
* match (`*` → `%`). Backs `omg ls` and the `docs_list` MCP tool (one
|
|
66
|
+
* implementation for both surfaces). For a directory-aware summary use
|
|
67
|
+
* `docsTree`. */
|
|
68
|
+
export function docsList(store, repoId, opts = {}) {
|
|
69
|
+
const like = opts.pathGlob ? globToLike(opts.pathGlob) : "%";
|
|
70
|
+
const limit = Math.max(1, Math.floor(opts.limit ?? DOCS_LIST_DEFAULT_LIMIT));
|
|
71
|
+
const after = opts.cursor ? decodePathCursor(opts.cursor) : null;
|
|
72
|
+
// Fetch one past the limit so `truncated` is a fact, not a guess.
|
|
73
|
+
const rows = liveDocRows(store, repoId, like, after, limit + 1);
|
|
74
|
+
const moreBeyond = rows.length > limit;
|
|
75
|
+
return pagePathOrdered(rows.slice(0, limit), limit, opts.budgetTokens, moreBeyond);
|
|
76
|
+
}
|
|
77
|
+
export const DOCS_TREE_DEFAULT_LIMIT = 200;
|
|
78
|
+
/** Normalize a tree prefix: no leading `/`, and either empty or ending in `/`. */
|
|
79
|
+
export function normalizeTreePrefix(path) {
|
|
80
|
+
const trimmed = (path ?? "").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
81
|
+
return trimmed === "" ? "" : trimmed + "/";
|
|
82
|
+
}
|
|
83
|
+
/** The path-separator-aware orientation read (`tree -L depth` + `du`): every
|
|
84
|
+
* live doc under `path` is collapsed at `depth` segments into one entry per
|
|
85
|
+
* directory (with doc/block totals + latest ts) or listed as a doc when it is
|
|
86
|
+
* shallow enough. Entries are ordered by path; dirs carry a trailing `/`. The
|
|
87
|
+
* result is paged under the same limit/cursor/budget contract as docsList,
|
|
88
|
+
* and always carries `total` for the whole prefix so an agent sees the size of
|
|
89
|
+
* what it is looking at even when the page is cut. Backs the `docs_tree` MCP
|
|
90
|
+
* tool. */
|
|
91
|
+
export function docsTree(store, repoId, opts = {}) {
|
|
92
|
+
const prefix = normalizeTreePrefix(opts.path);
|
|
93
|
+
const depth = Math.max(1, Math.floor(opts.depth ?? 1));
|
|
94
|
+
const limit = Math.max(1, Math.floor(opts.limit ?? DOCS_TREE_DEFAULT_LIMIT));
|
|
95
|
+
const like = prefix === "" ? "%" : globToLike(prefix) + "%";
|
|
96
|
+
const rows = liveDocRows(store, repoId, like, null, null);
|
|
97
|
+
const byPath = new Map();
|
|
98
|
+
const total = { docs: 0, blocks: 0 };
|
|
99
|
+
for (const row of rows) {
|
|
100
|
+
total.docs += 1;
|
|
101
|
+
total.blocks += row.blocks;
|
|
102
|
+
const segs = row.path.slice(prefix.length).split("/");
|
|
103
|
+
if (segs.length <= depth) {
|
|
104
|
+
byPath.set(row.path, { path: row.path, kind: "doc", docs: 1, blocks: row.blocks, ts: row.ts });
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const dir = prefix + segs.slice(0, depth).join("/") + "/";
|
|
108
|
+
const cur = byPath.get(dir);
|
|
109
|
+
if (cur) {
|
|
110
|
+
cur.docs += 1;
|
|
111
|
+
cur.blocks += row.blocks;
|
|
112
|
+
if (row.ts !== null && (cur.ts === null || row.ts > cur.ts))
|
|
113
|
+
cur.ts = row.ts;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
byPath.set(dir, { path: dir, kind: "dir", docs: 1, blocks: row.blocks, ts: row.ts });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
let entries = [...byPath.values()].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
120
|
+
if (opts.cursor) {
|
|
121
|
+
const after = decodePathCursor(opts.cursor);
|
|
122
|
+
entries = entries.filter((e) => e.path > after);
|
|
123
|
+
}
|
|
124
|
+
const { items, truncated, cursor } = pagePathOrdered(entries, limit, opts.budgetTokens, false);
|
|
125
|
+
return { prefix, depth, total, entries: items, truncated, cursor };
|
|
126
|
+
}
|
|
127
|
+
function toNode(r) {
|
|
128
|
+
return {
|
|
129
|
+
blockId: r.block_id,
|
|
130
|
+
docId: r.doc_id,
|
|
131
|
+
parentBlock: r.parent_block,
|
|
132
|
+
ordinal: r.ordinal,
|
|
133
|
+
depth: r.depth,
|
|
134
|
+
type: r.type,
|
|
135
|
+
attrs: JSON.parse(r.attrs),
|
|
136
|
+
text: r.text,
|
|
137
|
+
rawHashHex: r.raw_hash.toString("hex"),
|
|
138
|
+
children: [],
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** Load a document's live blocks as a containment forest, ordered. */
|
|
142
|
+
export function loadDocBlocks(store, docId) {
|
|
143
|
+
const rows = store.db
|
|
144
|
+
.prepare(`SELECT block_id, doc_id, parent_block, order_key, ordinal, depth, type, attrs, text, raw_hash
|
|
145
|
+
FROM blocks WHERE doc_id = ? AND deleted_commit IS NULL
|
|
146
|
+
ORDER BY parent_block, order_key`)
|
|
147
|
+
.all(docId);
|
|
148
|
+
const byId = new Map();
|
|
149
|
+
for (const r of rows)
|
|
150
|
+
byId.set(r.block_id, toNode(r));
|
|
151
|
+
const roots = [];
|
|
152
|
+
// Preserve order_key ordering by iterating rows (already sorted).
|
|
153
|
+
for (const r of rows) {
|
|
154
|
+
const node = byId.get(r.block_id);
|
|
155
|
+
if (r.parent_block && byId.has(r.parent_block)) {
|
|
156
|
+
byId.get(r.parent_block).children.push(node);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
roots.push(node);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return roots;
|
|
163
|
+
}
|
|
164
|
+
/** Retrieve the raw source bytes for a block by its raw_hash. */
|
|
165
|
+
export function blockRaw(store, rawHashHex) {
|
|
166
|
+
const row = store.db.prepare("SELECT bytes FROM blobs WHERE hash = ?").get(Buffer.from(rawHashHex, "hex"));
|
|
167
|
+
return row ? row.bytes.toString("utf8") : "";
|
|
168
|
+
}
|
|
169
|
+
export function findDoc(store, ref) {
|
|
170
|
+
let row;
|
|
171
|
+
if (ref.docId) {
|
|
172
|
+
row = store.db.prepare("SELECT doc_id, repo_id, path, format, current_rev FROM docs WHERE doc_id = ? AND deleted_commit IS NULL").get(ref.docId);
|
|
173
|
+
}
|
|
174
|
+
else if (ref.repoId && ref.path) {
|
|
175
|
+
row = store.db.prepare("SELECT doc_id, repo_id, path, format, current_rev FROM docs WHERE repo_id = ? AND path = ? AND deleted_commit IS NULL").get(ref.repoId, ref.path);
|
|
176
|
+
}
|
|
177
|
+
if (!row)
|
|
178
|
+
return null;
|
|
179
|
+
return {
|
|
180
|
+
docId: row.doc_id,
|
|
181
|
+
repoId: row.repo_id,
|
|
182
|
+
path: row.path,
|
|
183
|
+
format: row.format ?? "markdown",
|
|
184
|
+
currentRev: row.current_rev ?? null,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Resolve a single `doc` ref that may be EITHER a minted document id (`d_…`) OR
|
|
189
|
+
* a repo-relative path — the id-or-path symmetry every doc-ref surface expects
|
|
190
|
+
* (docs_read/outline/read_at, diff, apply's insert.doc, graph seeds, docHistory).
|
|
191
|
+
* This is the ONE dispatch those call sites route through so the "path in the
|
|
192
|
+
* doc field" trap can't recur per-tool.
|
|
193
|
+
*
|
|
194
|
+
* A `d_`-shaped id is looked up by id ONLY — if it doesn't exist we return null
|
|
195
|
+
* (the caller fails loud) rather than falling through to a path lookup that
|
|
196
|
+
* would also miss and confusingly report a path-not-found for a d_ value.
|
|
197
|
+
* Anything else is treated as a path. Returns null when unresolvable; callers
|
|
198
|
+
* throw a clear doc_missing/target_missing so an unresolvable ref is never a
|
|
199
|
+
* silent empty result.
|
|
200
|
+
*/
|
|
201
|
+
export function findDocByRef(store, repoId, ref) {
|
|
202
|
+
if (isValidId(ref, "d"))
|
|
203
|
+
return findDoc(store, { docId: ref });
|
|
204
|
+
return findDoc(store, { repoId, path: ref });
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Store } from "../store/store.js";
|
|
2
|
+
export interface ResolvedRef {
|
|
3
|
+
kind: "block" | "document";
|
|
4
|
+
docId: string;
|
|
5
|
+
blockId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a node reference within a repo. Accepts:
|
|
9
|
+
* - a block id (prefix "b") → { block, docId, blockId }
|
|
10
|
+
* - a document id (prefix "d") → { document, docId }
|
|
11
|
+
* - a projected node id ("n_…") → its block, or its doc when block-less
|
|
12
|
+
* - a repo-relative document path → { document, docId }
|
|
13
|
+
* Returns null when nothing matches.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveRef(store: Store, repoId: string, ref: string): ResolvedRef | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { prefixOf } from "../ids.js";
|
|
2
|
+
import { findDoc } from "./reader.js";
|
|
3
|
+
// Node ids are content-hash derived (`n_` + 12 hex chars, see core/store/nodes),
|
|
4
|
+
// not the 7-char minted scheme prefixOf recognizes — match them explicitly.
|
|
5
|
+
const NODE_ID_RE = /^n_[0-9a-f]{12}$/;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a node reference within a repo. Accepts:
|
|
8
|
+
* - a block id (prefix "b") → { block, docId, blockId }
|
|
9
|
+
* - a document id (prefix "d") → { document, docId }
|
|
10
|
+
* - a projected node id ("n_…") → its block, or its doc when block-less
|
|
11
|
+
* - a repo-relative document path → { document, docId }
|
|
12
|
+
* Returns null when nothing matches.
|
|
13
|
+
*/
|
|
14
|
+
export function resolveRef(store, repoId, ref) {
|
|
15
|
+
// A projected-node id (e.g. an OQX `from nodes` hit) dereferences to the block
|
|
16
|
+
// it was projected from — so a node hit is a first-class argument to the same
|
|
17
|
+
// read/write commands a block id is. Block-less nodes (or nodes whose block is
|
|
18
|
+
// no longer live) fall back to their document.
|
|
19
|
+
if (NODE_ID_RE.test(ref)) {
|
|
20
|
+
const node = store.db
|
|
21
|
+
.prepare("SELECT doc_id, block_id FROM nodes WHERE node_id = ?")
|
|
22
|
+
.get(ref);
|
|
23
|
+
if (!node)
|
|
24
|
+
return null;
|
|
25
|
+
if (node.block_id) {
|
|
26
|
+
const live = store.db
|
|
27
|
+
.prepare("SELECT 1 FROM blocks WHERE block_id = ? AND deleted_commit IS NULL")
|
|
28
|
+
.get(node.block_id);
|
|
29
|
+
if (live)
|
|
30
|
+
return { kind: "block", docId: node.doc_id, blockId: node.block_id };
|
|
31
|
+
}
|
|
32
|
+
return { kind: "document", docId: node.doc_id };
|
|
33
|
+
}
|
|
34
|
+
const prefix = prefixOf(ref);
|
|
35
|
+
if (prefix === "b") {
|
|
36
|
+
const row = store.db
|
|
37
|
+
.prepare("SELECT doc_id FROM blocks WHERE block_id = ? AND deleted_commit IS NULL")
|
|
38
|
+
.get(ref);
|
|
39
|
+
if (!row)
|
|
40
|
+
return null;
|
|
41
|
+
return { kind: "block", docId: row.doc_id, blockId: ref };
|
|
42
|
+
}
|
|
43
|
+
if (prefix === "d") {
|
|
44
|
+
const info = findDoc(store, { docId: ref });
|
|
45
|
+
return info ? { kind: "document", docId: info.docId } : null;
|
|
46
|
+
}
|
|
47
|
+
// Otherwise treat it as a document path.
|
|
48
|
+
const info = findDoc(store, { repoId, path: ref });
|
|
49
|
+
return info ? { kind: "document", docId: info.docId } : null;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=refs.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Database } from "better-sqlite3";
|
|
2
|
+
export interface ResolvedEdge {
|
|
3
|
+
srcDoc: string;
|
|
4
|
+
srcBlock: string | null;
|
|
5
|
+
srcField: string | null;
|
|
6
|
+
predicate: string;
|
|
7
|
+
dstKind: "document" | "block" | "external" | "collection";
|
|
8
|
+
dstNode: string;
|
|
9
|
+
anchor: string | null;
|
|
10
|
+
provenance: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reconcile the extracted edge set for a document against its currently-open
|
|
14
|
+
* rows: close rows no longer present (to_commit = this), open rows that are new
|
|
15
|
+
* (from_commit = this), leave unchanged rows untouched. Then recompute the
|
|
16
|
+
* doc_edges rollup for the doc. All within the caller's transaction.
|
|
17
|
+
*/
|
|
18
|
+
export declare function maintainEdges(db: Database, repoId: string, srcDoc: string, commitId: string, edges: ResolvedEdge[]): void;
|
|
19
|
+
export declare function adoptPhantoms(db: Database, path: string, realDocId: string): void;
|
|
20
|
+
/** Recompute the doc_edges rollup for one document from its open edges. */
|
|
21
|
+
export declare function rebuildDocEdges(db: Database, srcDoc: string): void;
|
|
22
|
+
export declare function resolveExternal(db: Database, repoId: string, uri: string): string;
|
|
23
|
+
export declare function resolveDocPath(db: Database, repoId: string, path: string): {
|
|
24
|
+
id: string;
|
|
25
|
+
phantom: boolean;
|
|
26
|
+
};
|