@omgbase/core 0.10.1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/src/core/read/document.d.ts +18 -5
- package/dist/src/core/read/document.js +21 -7
- package/dist/src/core/read/nodes.d.ts +7 -7
- package/dist/src/core/read/nodes.js +5 -3
- package/dist/src/core/read/reader.d.ts +11 -7
- package/dist/src/core/read/reader.js +8 -10
- package/dist/src/format/adapter.d.ts +1 -1
- package/dist/src/graph/history.d.ts +20 -14
- package/dist/src/graph/history.js +12 -12
- package/dist/src/graph/inbound-links.d.ts +4 -4
- package/dist/src/graph/inbound-links.js +4 -4
- package/dist/src/graph/link-health.d.ts +8 -8
- package/dist/src/graph/link-health.js +6 -6
- package/dist/src/graph/links.d.ts +3 -3
- package/dist/src/graph/links.js +4 -4
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/dist/src/mcp/arguments.d.ts +27 -0
- package/dist/src/mcp/arguments.js +147 -0
- package/dist/src/mcp/errors.d.ts +1 -1
- package/dist/src/mcp/graph.d.ts +16 -9
- package/dist/src/mcp/graph.js +58 -35
- package/dist/src/mcp/reference.d.ts +1 -1
- package/dist/src/mcp/reference.js +200 -111
- package/dist/src/mcp/server.d.ts +9 -1
- package/dist/src/mcp/server.js +359 -268
- package/dist/src/mutate/apply.d.ts +11 -4
- package/dist/src/mutate/apply.js +3 -2
- package/dist/src/mutate/docs.js +7 -7
- package/dist/src/mutate/macros.d.ts +4 -1
- package/dist/src/mutate/macros.js +1 -1
- package/dist/src/mutate/ops.js +2 -2
- package/dist/src/mutate/opset.d.ts +8 -5
- package/dist/src/mutate/plan-update.js +9 -8
- package/dist/src/oqx-js/context.d.ts +17 -4
- package/dist/src/oqx-js/context.js +268 -131
- package/dist/src/oqx-js/planner.d.ts +3 -3
- package/dist/src/oqx-js/planner.js +14 -15
- package/dist/src/oqx-js/root-row.d.ts +10 -3
- package/dist/src/oqx-js/root-row.js +18 -8
- package/dist/src/oqx-js/run.d.ts +6 -0
- package/dist/src/oqx-js/run.js +72 -25
- package/dist/src/oqx-js/sql/scan.js +7 -7
- package/dist/src/oqx-js/sql/translate.d.ts +12 -9
- package/dist/src/oqx-js/sql/translate.js +183 -75
- package/dist/src/oqx-js/store-index.d.ts +1 -1
- package/dist/src/oqx-js/store-index.js +28 -26
- package/dist/src/search/cel/ast.d.ts +1 -1
- package/dist/src/search/cel/compile.d.ts +1 -1
- package/dist/src/search/cel/compile.js +43 -70
- package/dist/src/search/cel/parser.js +1 -1
- package/dist/src/search/resolve.d.ts +2 -0
- package/dist/src/search/rrf.js +2 -2
- package/dist/src/search/text.d.ts +2 -2
- package/dist/src/search/text.js +1 -1
- package/dist/src/spec-versions.d.ts +6 -6
- package/dist/src/spec-versions.js +5 -5
- package/dist/src/surface-paths.d.ts +41 -8
- package/dist/src/surface-paths.js +34 -18
- package/dist/src/sync/admin.d.ts +2 -1
- package/dist/src/sync/admin.js +1 -1
- package/package.json +2 -2
|
@@ -12,7 +12,7 @@ export function defaultCtx(target) {
|
|
|
12
12
|
return { self: "d", doc: "d" };
|
|
13
13
|
if (target === "blocks")
|
|
14
14
|
return { self: "b", doc: "d" };
|
|
15
|
-
if (target === "
|
|
15
|
+
if (target === "links")
|
|
16
16
|
return { self: "e", doc: "d" };
|
|
17
17
|
return { self: "n", doc: "d" };
|
|
18
18
|
}
|
|
@@ -35,33 +35,14 @@ function jsonPath(segs) {
|
|
|
35
35
|
// blob. A field access is one of: a scalar-value expression (comparisons), or
|
|
36
36
|
// an existence/count predicate (membership, size, has, bool-context). All
|
|
37
37
|
// correlate on `<doc>.doc_id` (the correlated docs row, present on every target).
|
|
38
|
-
const PROP_SOURCES = new Set(["frontmatter", "inline", "computed"]);
|
|
38
|
+
const PROP_SOURCES = new Set(["data", "frontmatter", "inline", "computed"]);
|
|
39
39
|
// Computed properties surfaced as document intrinsics (12 §4). Engine-derived,
|
|
40
40
|
// stored as source='computed' rows keyed by their $ name. Filterable like any
|
|
41
41
|
// property (scalar ==, list(), membership) but never shadow authored keys.
|
|
42
42
|
const COMPUTED_INTRINSICS = new Set(["$title", "$tags"]);
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
// otherwise resolve to an absent frontmatter key and silently match nothing
|
|
47
|
-
// (a misleading empty). We reject it with a hint instead. `title`/`tags` are
|
|
48
|
-
// deliberately EXCLUDED: their $-forms are `computed` intrinsics that do not
|
|
49
|
-
// shadow authored frontmatter, so bare `title`/`tags` remain legitimate key
|
|
50
|
-
// access (see COMPUTED_INTRINSICS and QUERY_SYNTAX). A source-scoped form
|
|
51
|
-
// (frontmatter.path / inline.path) is an explicit request for that property
|
|
52
|
-
// and is likewise not caught — only the bare first-segment case is the trap.
|
|
53
|
-
const RESERVED_INTRINSIC_BASENAMES = new Set([
|
|
54
|
-
"id", "path", "repo", "updated_at", "content_hash", "body",
|
|
55
|
-
]);
|
|
56
|
-
// Guard the docs open namespace against reserved-intrinsic collisions. `segs`
|
|
57
|
-
// are the property key segments (after any doc./source scope has been peeled).
|
|
58
|
-
// Throws when the FIRST segment shadows an intrinsic base name.
|
|
59
|
-
function guardReservedCollision(segs) {
|
|
60
|
-
if (RESERVED_INTRINSIC_BASENAMES.has(segs[0])) {
|
|
61
|
-
const name = segs[0];
|
|
62
|
-
throw new FilterInvalid(`bare '${name}' reads a frontmatter key; did you mean the intrinsic $${name}? (use frontmatter.${name} to force the property)`, "10 §2");
|
|
63
|
-
}
|
|
64
|
-
}
|
|
43
|
+
// There is no reserved-basename guard any more (spec/surface §1.2, 3.0): the
|
|
44
|
+
// engine attributes are bare and win on collision; an authored key of the same
|
|
45
|
+
// name is reached through `data.<k>` / `frontmatter.<k>` / `inline.<k>`.
|
|
65
46
|
// Validate + join identifier segments into a dotted property key. Segments come
|
|
66
47
|
// from the lexer's identifier rule, so inlining is injection-safe (mirrors
|
|
67
48
|
// jsonPath); keeping keys param-free preserves the "fields carry no params"
|
|
@@ -81,7 +62,7 @@ function propKey(segs) {
|
|
|
81
62
|
function propRef(field, target) {
|
|
82
63
|
let segs = field.segments;
|
|
83
64
|
if (target === "docs") {
|
|
84
|
-
// Computed intrinsic (
|
|
65
|
+
// Computed intrinsic (title, tags): route to source='computed' rows.
|
|
85
66
|
if (field.intrinsic) {
|
|
86
67
|
if (segs.length === 1 && COMPUTED_INTRINSICS.has(segs[0]))
|
|
87
68
|
return { key: segs[0], source: "computed" };
|
|
@@ -97,7 +78,7 @@ function propRef(field, target) {
|
|
|
97
78
|
if (segs[0] !== "doc")
|
|
98
79
|
return null;
|
|
99
80
|
segs = segs.slice(1);
|
|
100
|
-
// doc
|
|
81
|
+
// doc.title reach-through to a computed intrinsic.
|
|
101
82
|
if (segs.length === 1 && COMPUTED_INTRINSICS.has(segs[0]))
|
|
102
83
|
return { key: segs[0], source: "computed" };
|
|
103
84
|
if (segs.length === 0 || segs[0].startsWith("$") || segs[0] === "format")
|
|
@@ -107,10 +88,6 @@ function propRef(field, target) {
|
|
|
107
88
|
const source = segs[0];
|
|
108
89
|
return { key: propKey(segs.slice(1)), source };
|
|
109
90
|
}
|
|
110
|
-
// Bare (non-`$`, non-source-scoped) key: reject a first segment that shadows
|
|
111
|
-
// a reserved intrinsic base name (path/id/repo/...) so a typo for `$path`
|
|
112
|
-
// fails loud instead of silently resolving to an absent frontmatter key.
|
|
113
|
-
guardReservedCollision(segs);
|
|
114
91
|
return { key: propKey(segs) };
|
|
115
92
|
}
|
|
116
93
|
function srcClause(source, alias = "p") {
|
|
@@ -186,13 +163,12 @@ function fieldSql(field, target, ctx) {
|
|
|
186
163
|
if (field.intrinsic) {
|
|
187
164
|
if (target === "docs") {
|
|
188
165
|
switch (head) {
|
|
189
|
-
case "
|
|
190
|
-
case "
|
|
191
|
-
case "
|
|
192
|
-
case "
|
|
193
|
-
case "$content_hash": return { expr: `lower(hex(${self}.file_hash))` };
|
|
166
|
+
case "id": return { expr: `${self}.doc_id` };
|
|
167
|
+
case "path": return { expr: `${self}.path` };
|
|
168
|
+
case "updated_at": return { expr: `(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = ${self}.current_rev)` };
|
|
169
|
+
case "hash": return { expr: `lower(hex(${self}.file_hash))` };
|
|
194
170
|
default: {
|
|
195
|
-
// Computed property intrinsic (
|
|
171
|
+
// Computed property intrinsic (title, tags) → properties row scalar.
|
|
196
172
|
const ref = propRef(field, target);
|
|
197
173
|
if (ref)
|
|
198
174
|
return { expr: propScalarExpr(ref, ctx) };
|
|
@@ -202,41 +178,24 @@ function fieldSql(field, target, ctx) {
|
|
|
202
178
|
}
|
|
203
179
|
else if (target === "nodes") {
|
|
204
180
|
switch (head) {
|
|
205
|
-
case "
|
|
206
|
-
case "
|
|
207
|
-
case "$doc_id": return { expr: `${self}.doc_id` };
|
|
208
|
-
case "$block_id": return { expr: `${self}.block_id` };
|
|
209
|
-
case "$path": return { expr: `${doc}.path` };
|
|
181
|
+
case "id": return { expr: `${self}.node_id` };
|
|
182
|
+
case "path": return { expr: `${doc}.path` };
|
|
210
183
|
default: throw new FilterInvalid(`unknown intrinsic ${head} on nodes`, "10 §2");
|
|
211
184
|
}
|
|
212
185
|
}
|
|
213
|
-
else if (target === "
|
|
186
|
+
else if (target === "links") {
|
|
214
187
|
switch (head) {
|
|
215
|
-
case "
|
|
216
|
-
case "
|
|
217
|
-
|
|
218
|
-
case "$src_block": return { expr: `${self}.src_block` };
|
|
219
|
-
case "$via": return { expr: `${self}.via_node` };
|
|
220
|
-
case "$from_commit": return { expr: `${self}.from_commit` };
|
|
221
|
-
case "$path": return { expr: `${doc}.path` }; // source document's path
|
|
222
|
-
// Meaningful destination, resolved per dst_kind (cheap correlated lookups,
|
|
223
|
-
// NULL when not applicable): the target document's path, or the external
|
|
224
|
-
// node's URI. Lets `from edges` show real targets, not opaque node ids.
|
|
225
|
-
case "$dst_path": return { expr: `(SELECT dd.path FROM docs dd WHERE dd.doc_id = ${self}.dst_node)` };
|
|
226
|
-
case "$dst_uri": return { expr: `(SELECT xn.uri FROM external_nodes xn WHERE xn.node_id = ${self}.dst_node)` };
|
|
227
|
-
default: throw new FilterInvalid(`unknown intrinsic ${head} on edges`, "10 §2");
|
|
188
|
+
case "id": return { expr: `${self}.edge_id` };
|
|
189
|
+
case "path": return { expr: `${doc}.path` }; // source document's path
|
|
190
|
+
default: throw new FilterInvalid(`unknown intrinsic ${head} on links`, "10 §2");
|
|
228
191
|
}
|
|
229
192
|
}
|
|
230
193
|
else {
|
|
231
194
|
switch (head) {
|
|
232
|
-
case "
|
|
233
|
-
case "
|
|
234
|
-
case "
|
|
235
|
-
case "
|
|
236
|
-
case "$depth": return { expr: `${self}.depth` };
|
|
237
|
-
case "$content_hash": return { expr: `lower(hex(${self}.raw_hash))` };
|
|
238
|
-
case "$body": return { expr: `${self}.text` };
|
|
239
|
-
case "$updated_at": return { expr: `(SELECT MAX(c.ts) FROM block_changes bc JOIN commits c ON c.commit_id = bc.commit_id WHERE bc.block_id = ${self}.block_id)` };
|
|
195
|
+
case "id": return { expr: `${self}.block_id` };
|
|
196
|
+
case "path": return { expr: `${doc}.path` };
|
|
197
|
+
case "hash": return { expr: `lower(hex(${self}.raw_hash))` };
|
|
198
|
+
case "updated_at": return { expr: `(SELECT MAX(c.ts) FROM block_changes bc JOIN commits c ON c.commit_id = bc.commit_id WHERE bc.block_id = ${self}.block_id)` };
|
|
240
199
|
default: throw new FilterInvalid(`unknown intrinsic ${head} on blocks`, "10 §2");
|
|
241
200
|
}
|
|
242
201
|
}
|
|
@@ -281,7 +240,7 @@ function fieldSql(field, target, ctx) {
|
|
|
281
240
|
}
|
|
282
241
|
throw new FilterInvalid(`unknown field '${segs.join(".")}' on nodes`, "10 §2");
|
|
283
242
|
}
|
|
284
|
-
if (target === "
|
|
243
|
+
if (target === "links") {
|
|
285
244
|
if (head === "predicate")
|
|
286
245
|
return { expr: `${self}.predicate` };
|
|
287
246
|
if (head === "provenance")
|
|
@@ -290,7 +249,21 @@ function fieldSql(field, target, ctx) {
|
|
|
290
249
|
return { expr: `${self}.dst_kind` };
|
|
291
250
|
if (head === "anchor")
|
|
292
251
|
return { expr: `${self}.anchor` };
|
|
293
|
-
|
|
252
|
+
// The links target's plain fields (spec/surface §1.2, 3.0): foreign keys
|
|
253
|
+
// named for what they are, the `src_field` column as `field`.
|
|
254
|
+
if (head === "doc_id")
|
|
255
|
+
return { expr: `${self}.src_doc` };
|
|
256
|
+
if (head === "block_id")
|
|
257
|
+
return { expr: `${self}.src_block` };
|
|
258
|
+
if (head === "via_id")
|
|
259
|
+
return { expr: `${self}.via_node` };
|
|
260
|
+
if (head === "dst_id")
|
|
261
|
+
return { expr: `${self}.dst_node` };
|
|
262
|
+
if (head === "dst_path")
|
|
263
|
+
return { expr: `(SELECT dd.path FROM docs dd WHERE dd.doc_id = ${self}.dst_node)` };
|
|
264
|
+
if (head === "uri")
|
|
265
|
+
return { expr: `(SELECT xn.uri FROM external_nodes xn WHERE xn.node_id = ${self}.dst_node)` };
|
|
266
|
+
if (head === "field")
|
|
294
267
|
return { expr: `${self}.src_field` };
|
|
295
268
|
if (head === "doc") {
|
|
296
269
|
// reach-through to the SOURCE document (edges join docs on src_doc).
|
|
@@ -305,7 +278,7 @@ function fieldSql(field, target, ctx) {
|
|
|
305
278
|
return { expr: propScalarExpr(ref, ctx) };
|
|
306
279
|
return { expr: `json_extract(${doc}.metadata, ${jsonPath(rest)})` };
|
|
307
280
|
}
|
|
308
|
-
throw new FilterInvalid(`unknown field '${segs.join(".")}' on
|
|
281
|
+
throw new FilterInvalid(`unknown field '${segs.join(".")}' on links`, "10 §2");
|
|
309
282
|
}
|
|
310
283
|
// blocks target
|
|
311
284
|
if (head === "type")
|
|
@@ -674,8 +647,8 @@ function compileWithin(target, ctx) {
|
|
|
674
647
|
// match their own row; docs match when any of their blocks does; nodes use the
|
|
675
648
|
// node FTS index. Aliased by the scope so it works under OQX's per-scope aliases.
|
|
676
649
|
function compileText(terms, target, ctx) {
|
|
677
|
-
if (target === "
|
|
678
|
-
throw new FilterInvalid("text(...) is not available on the
|
|
650
|
+
if (target === "links")
|
|
651
|
+
throw new FilterInvalid("text(...) is not available on the links target (links carry no text index)", "10 §5");
|
|
679
652
|
const match = sanitizeFtsQuery(terms);
|
|
680
653
|
if (match === "")
|
|
681
654
|
return { sql: "(1 = 0)", params: [] };
|
|
@@ -701,8 +674,8 @@ function compileText(terms, target, ctx) {
|
|
|
701
674
|
// threshold comparison excludes it (absence = false). The query vector + model
|
|
702
675
|
// come from ctx.semantic (the runner embedded the literal); absent ⇒ loud.
|
|
703
676
|
function compileSemantic(phrase, target, ctx) {
|
|
704
|
-
if (target === "nodes" || target === "
|
|
705
|
-
throw new FilterInvalid('semantic(...) is available on the docs and blocks targets (nodes/
|
|
677
|
+
if (target === "nodes" || target === "links") {
|
|
678
|
+
throw new FilterInvalid('semantic(...) is available on the docs and blocks targets (nodes/links have no embeddings)', "OQX semantic");
|
|
706
679
|
}
|
|
707
680
|
const resolved = ctx.semantic?.(phrase);
|
|
708
681
|
if (!resolved) {
|
|
@@ -103,7 +103,7 @@ class Parser {
|
|
|
103
103
|
while (this.peek().type === "dot") {
|
|
104
104
|
this.next();
|
|
105
105
|
// A `$`-segment after a dot is an intrinsic reach-through continuation
|
|
106
|
-
// (`doc
|
|
106
|
+
// (`doc.path`, `doc.updated_at`): the lexer emits it as a `field` token
|
|
107
107
|
// (value keeps the `$`). It is never a method receiver, so append it as a
|
|
108
108
|
// field segment directly. The compiler routes `doc.$…` to docs intrinsics.
|
|
109
109
|
if (this.peek().type === "field") {
|
package/dist/src/search/rrf.js
CHANGED
|
@@ -43,8 +43,8 @@ export function hybridSearch(store, input) {
|
|
|
43
43
|
const ftsRanks = new Map();
|
|
44
44
|
if (input.text) {
|
|
45
45
|
textSearch(store, input.repoId, input.text, { limit: 200 }).hits.forEach((h, i) => {
|
|
46
|
-
if (!ftsRanks.has(h.
|
|
47
|
-
ftsRanks.set(h.
|
|
46
|
+
if (!ftsRanks.has(h.id))
|
|
47
|
+
ftsRanks.set(h.id, i + 1);
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
const vecRanks = new Map();
|
package/dist/src/search/text.js
CHANGED
|
@@ -5,7 +5,7 @@ export function textSearch(store, repoId, queryStr, opts = {}) {
|
|
|
5
5
|
if (match === "")
|
|
6
6
|
return { hits: [], truncated: false };
|
|
7
7
|
const rows = store.db
|
|
8
|
-
.prepare(`SELECT b.block_id AS
|
|
8
|
+
.prepare(`SELECT b.block_id AS "id", b.doc_id AS doc_id, d.path AS "path", b.type AS type,
|
|
9
9
|
b.text AS text, bm25(blocks_fts) AS score
|
|
10
10
|
FROM blocks_fts
|
|
11
11
|
JOIN blocks b ON b.rowid = blocks_fts.rowid
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export declare const SPEC_VERSIONS: {
|
|
2
|
-
readonly oqx: "0.
|
|
2
|
+
readonly oqx: "0.20";
|
|
3
3
|
readonly format: "0.2";
|
|
4
4
|
readonly reconcile: "2.3";
|
|
5
5
|
readonly store: "13.5";
|
|
6
6
|
readonly properties: "1.1";
|
|
7
7
|
readonly graph: "1.1";
|
|
8
|
-
readonly search: "
|
|
9
|
-
readonly mutate: "
|
|
10
|
-
readonly sync: "
|
|
11
|
-
readonly surface: "
|
|
12
|
-
readonly cli: "
|
|
8
|
+
readonly search: "2.0";
|
|
9
|
+
readonly mutate: "2.0";
|
|
10
|
+
readonly sync: "2.0";
|
|
11
|
+
readonly surface: "3.0";
|
|
12
|
+
readonly cli: "3.0";
|
|
13
13
|
};
|
|
14
14
|
export type SpecName = keyof typeof SPEC_VERSIONS;
|
|
@@ -16,10 +16,10 @@ export const SPEC_VERSIONS = {
|
|
|
16
16
|
store: "13.5",
|
|
17
17
|
properties: "1.1",
|
|
18
18
|
graph: "1.1",
|
|
19
|
-
search: "
|
|
20
|
-
mutate: "
|
|
21
|
-
sync: "
|
|
22
|
-
surface: "
|
|
23
|
-
cli: "
|
|
19
|
+
search: "2.0",
|
|
20
|
+
mutate: "2.0",
|
|
21
|
+
sync: "2.0",
|
|
22
|
+
surface: "3.0",
|
|
23
|
+
cli: "3.0",
|
|
24
24
|
};
|
|
25
25
|
//# sourceMappingURL=spec-versions.js.map
|
|
@@ -3,22 +3,55 @@ import type { DocOpResult, DocMoveResult } from "./mutate/docs.js";
|
|
|
3
3
|
import type { RetargetHit } from "./mutate/macros.js";
|
|
4
4
|
import type { Opset } from "./mutate/opset.js";
|
|
5
5
|
import type { DocsUpdateResult } from "./mutate/plan-update.js";
|
|
6
|
+
import type { InboundLink } from "./graph/inbound-links.js";
|
|
6
7
|
import type { ObserveResult, ObserveDeleteResult } from "./sync/observe.js";
|
|
7
8
|
import type { SweepResult } from "./sync/freshness.js";
|
|
8
9
|
import type { TextSearchResult } from "./search/text.js";
|
|
9
10
|
import type { ResolveHit } from "./search/resolve.js";
|
|
10
11
|
/** `spec/mutate` §4's result: `revisions[].path` and the dry-run `diffs` keys. */
|
|
11
12
|
export declare function surfaceApplyResult<T extends ApplyResult>(res: T): T;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
export
|
|
13
|
+
/** A document operation's result on the wire (spec/surface §4, 3.0): the
|
|
14
|
+
* library's `{ docId, path, … }` (`spec/mutate` §6, unchanged there) renamed
|
|
15
|
+
* to the document's row attributes `id`/`path`, the path rooted, the
|
|
16
|
+
* dry-run `diffs` re-keyed; every other key (`committed`, `deleted`, …) as is. */
|
|
17
|
+
export type SurfaceDocOpResult<T extends DocOpResult> = Omit<T, "docId" | "path"> & {
|
|
18
|
+
id: string;
|
|
19
|
+
path: string;
|
|
20
|
+
};
|
|
21
|
+
/** `docs_create` / `docs_delete` / `docs_set_meta`. */
|
|
22
|
+
export declare function surfaceDocOpResult<T extends DocOpResult>(res: T): SurfaceDocOpResult<T>;
|
|
23
|
+
/** An inbound link on the wire (`docs_move.dangling[]`): an edge row under the
|
|
24
|
+
* `edges` target's names (spec/surface §1.2) — `doc_id`, `path` (rooted),
|
|
25
|
+
* `block_id`, `target` (as authored), `anchor`, `field?`. */
|
|
26
|
+
export interface SurfaceInboundLink {
|
|
27
|
+
doc_id: string;
|
|
28
|
+
path: string;
|
|
29
|
+
block_id: string | null;
|
|
30
|
+
target: string;
|
|
31
|
+
anchor: string | null;
|
|
32
|
+
field?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function surfaceInboundLink(l: InboundLink): SurfaceInboundLink;
|
|
35
|
+
/** `docs_move`: the document-op fields plus each dangling link (its `target`
|
|
36
|
+
* stays as authored — that is what the link says). */
|
|
37
|
+
export declare function surfaceDocMoveResult(res: DocMoveResult): Omit<SurfaceDocOpResult<DocMoveResult>, "dangling"> & {
|
|
38
|
+
dangling: SurfaceInboundLink[];
|
|
39
|
+
};
|
|
40
|
+
/** An observe outcome on the wire (spec/surface §4, 3.0): `spec/store` §5's
|
|
41
|
+
* `{ docId, path, … }` (unchanged there) renamed to the document's row
|
|
42
|
+
* attributes `id`/`path`, the path rooted. */
|
|
43
|
+
export type SurfaceObserveResult<T extends {
|
|
44
|
+
docId: string | null;
|
|
45
|
+
path: string;
|
|
46
|
+
}> = Omit<T, "docId" | "path"> & {
|
|
47
|
+
id: T["docId"];
|
|
48
|
+
path: string;
|
|
49
|
+
};
|
|
17
50
|
/** `observe` / `observe_many` outcomes. */
|
|
18
|
-
export declare function surfaceObserveResult<T extends ObserveResult>(res: T): T
|
|
51
|
+
export declare function surfaceObserveResult<T extends ObserveResult>(res: T): SurfaceObserveResult<T>;
|
|
19
52
|
/** `observe_delete`. */
|
|
20
|
-
export declare function surfaceObserveDeleteResult(res: ObserveDeleteResult): ObserveDeleteResult
|
|
21
|
-
/** `
|
|
53
|
+
export declare function surfaceObserveDeleteResult(res: ObserveDeleteResult): SurfaceObserveResult<ObserveDeleteResult>;
|
|
54
|
+
/** `blocks_search` hits (`path` rooted). */
|
|
22
55
|
export declare function surfaceTextSearch(res: TextSearchResult): TextSearchResult;
|
|
23
56
|
/** `resolve` hits: the locator is `<path>#<type>[<ordinal>]`; its path half is
|
|
24
57
|
* rooted (a locator without `#` names no path and is left alone). */
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
// The surface's
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// `
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
1
|
+
// The surface's rules applied at its boundary. Two of them:
|
|
2
|
+
//
|
|
3
|
+
// Paths (spec/surface §1 "Paths", 2.0): every path a tool or verb returns is
|
|
4
|
+
// `/`-rooted. The surface-owned readers (`core/read`, `graph/history`,
|
|
5
|
+
// `graph/link-health`, the query binding) root their own output; the results
|
|
6
|
+
// that belong to another spec — `spec/mutate`'s apply and document-operation
|
|
7
|
+
// results and opsets, `spec/store`'s observe outcomes, `spec/search`'s hits,
|
|
8
|
+
// `spec/sync`'s sweep — keep their storage-form paths in the library (their
|
|
9
|
+
// own fixtures pin them) and are re-shaped HERE.
|
|
10
|
+
//
|
|
11
|
+
// Row names (spec/surface §1.2, 3.0): a result that renders a document, block
|
|
12
|
+
// or edge row spells it the way the query binding does — `id`, `path`,
|
|
13
|
+
// `hash`, `raw`, `updated_at`, plain `doc_id`/`block_id` foreign keys. The
|
|
14
|
+
// shapes other specs own under their own names — `spec/mutate`'s document
|
|
15
|
+
// operation result `{ docId, path, … }`, `spec/store`'s observe outcome — are
|
|
16
|
+
// re-shaped HERE too (`SurfaceDocOpResult`, `SurfaceObserveResult`, …).
|
|
17
|
+
//
|
|
18
|
+
// Both the MCP server and the `omg` verbs call these, so the two clients
|
|
19
|
+
// cannot drift. Each function returns a new value; the input is not mutated.
|
|
11
20
|
import { referencePath, referenceKeyed } from "./core/paths.js";
|
|
12
21
|
/** `spec/mutate` §4's result: `revisions[].path` and the dry-run `diffs` keys. */
|
|
13
22
|
export function surfaceApplyResult(res) {
|
|
@@ -17,24 +26,31 @@ export function surfaceApplyResult(res) {
|
|
|
17
26
|
...(res.diffs ? { diffs: referenceKeyed(res.diffs) } : {}),
|
|
18
27
|
};
|
|
19
28
|
}
|
|
20
|
-
/** `docs_create` / `docs_delete` / `docs_set_meta
|
|
29
|
+
/** `docs_create` / `docs_delete` / `docs_set_meta`. */
|
|
21
30
|
export function surfaceDocOpResult(res) {
|
|
22
|
-
|
|
31
|
+
const { docId, path, ...rest } = res;
|
|
32
|
+
return { id: docId, path: referencePath(path), ...rest, ...(res.diffs ? { diffs: referenceKeyed(res.diffs) } : {}) };
|
|
23
33
|
}
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
export function surfaceInboundLink(l) {
|
|
35
|
+
const { path, ...rest } = l;
|
|
36
|
+
return { doc_id: rest.doc_id, path: referencePath(path), block_id: rest.block_id, target: rest.target, anchor: rest.anchor, ...(rest.field !== undefined ? { field: rest.field } : {}) };
|
|
37
|
+
}
|
|
38
|
+
/** `docs_move`: the document-op fields plus each dangling link (its `target`
|
|
39
|
+
* stays as authored — that is what the link says). */
|
|
26
40
|
export function surfaceDocMoveResult(res) {
|
|
27
|
-
return { ...surfaceDocOpResult(res), dangling: res.dangling.map(
|
|
41
|
+
return { ...surfaceDocOpResult(res), dangling: res.dangling.map(surfaceInboundLink) };
|
|
28
42
|
}
|
|
29
43
|
/** `observe` / `observe_many` outcomes. */
|
|
30
44
|
export function surfaceObserveResult(res) {
|
|
31
|
-
|
|
45
|
+
const { docId, path, ...rest } = res;
|
|
46
|
+
return { id: docId, path: referencePath(path), ...rest };
|
|
32
47
|
}
|
|
33
48
|
/** `observe_delete`. */
|
|
34
49
|
export function surfaceObserveDeleteResult(res) {
|
|
35
|
-
|
|
50
|
+
const { docId, path, ...rest } = res;
|
|
51
|
+
return { id: docId, path: referencePath(path), ...rest };
|
|
36
52
|
}
|
|
37
|
-
/** `
|
|
53
|
+
/** `blocks_search` hits (`path` rooted). */
|
|
38
54
|
export function surfaceTextSearch(res) {
|
|
39
55
|
return { ...res, hits: res.hits.map((h) => ({ ...h, path: referencePath(h.path) })) };
|
|
40
56
|
}
|
package/dist/src/sync/admin.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ export interface DiskStatus extends DiskDrift {
|
|
|
10
10
|
checked: boolean;
|
|
11
11
|
}
|
|
12
12
|
export interface RepoStatus {
|
|
13
|
-
|
|
13
|
+
/** the repository's own id (spec/surface §1.2, 3.0: every row names its identity `id`) */
|
|
14
|
+
id: string;
|
|
14
15
|
slug: string;
|
|
15
16
|
rootPath: string;
|
|
16
17
|
docs: number;
|
package/dist/src/sync/admin.js
CHANGED
|
@@ -18,7 +18,7 @@ export function reposStatus(store, repoId, rootPath) {
|
|
|
18
18
|
? { ...detectDiskDrift(store, repoId, rootPath), checked: true }
|
|
19
19
|
: { changed: 0, deleted: 0, untracked: 0, checked: false };
|
|
20
20
|
return {
|
|
21
|
-
repoId,
|
|
21
|
+
id: repoId,
|
|
22
22
|
slug: repo?.slug ?? "",
|
|
23
23
|
rootPath: rootPath ?? "",
|
|
24
24
|
docs: count("SELECT count(*) c FROM docs WHERE repo_id = ? AND deleted_commit IS NULL"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omgbase/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Open Markdown Graph Base — embedded engine",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
58
|
-
"@omgbase/oqx": "^0.
|
|
58
|
+
"@omgbase/oqx": "^0.20.0",
|
|
59
59
|
"better-sqlite3": "^13.0.3",
|
|
60
60
|
"mdast-util-from-markdown": "^2.0.2",
|
|
61
61
|
"mdast-util-frontmatter": "^2.0.1",
|