@omgbase/core 0.10.0 → 0.11.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/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 +215 -121
- 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 +71 -24
- 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
|
@@ -77,12 +77,19 @@ export interface ApplyRequest {
|
|
|
77
77
|
export interface OpResult {
|
|
78
78
|
ids: string[];
|
|
79
79
|
}
|
|
80
|
+
/** One touched document in an apply result (spec/mutate §4, 2.0): its row
|
|
81
|
+
* attributes `id`, `path` (the storage form here; the surface roots it) and
|
|
82
|
+
* `hash` — the hex sha256 of the rendered bytes, i.e. the hash the committed
|
|
83
|
+
* revision carries (a dry run reports the hash it would carry). The same
|
|
84
|
+
* three keys a `changes_since` revision carries. */
|
|
85
|
+
export interface ApplyRevision {
|
|
86
|
+
id: string;
|
|
87
|
+
path: string;
|
|
88
|
+
hash: string;
|
|
89
|
+
}
|
|
80
90
|
export interface ApplyResult {
|
|
81
91
|
results: OpResult[];
|
|
82
|
-
revisions:
|
|
83
|
-
doc: string;
|
|
84
|
-
path: string;
|
|
85
|
-
}[];
|
|
92
|
+
revisions: ApplyRevision[];
|
|
86
93
|
diffs?: Record<string, {
|
|
87
94
|
before: string;
|
|
88
95
|
after: string;
|
package/dist/src/mutate/apply.js
CHANGED
|
@@ -152,8 +152,9 @@ export function apply(store, req) {
|
|
|
152
152
|
const revisions = [];
|
|
153
153
|
const diffs = {};
|
|
154
154
|
for (const [docId, d] of loaded) {
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
const after = renderDoc(d);
|
|
156
|
+
diffs[d.path] = { before: before.get(docId) ?? "", after };
|
|
157
|
+
revisions.push({ id: docId, path: d.path, hash: sha256(after).toString("hex") });
|
|
157
158
|
}
|
|
158
159
|
if (req.dryRun) {
|
|
159
160
|
return { results, revisions, diffs, committed: false };
|
package/dist/src/mutate/docs.js
CHANGED
|
@@ -121,9 +121,9 @@ export function docsMove(store, ctx, docRef, toPath, opts = {}) {
|
|
|
121
121
|
db.prepare("UPDATE edges SET dst_node = ? WHERE dst_node = ? AND to_commit IS NULL AND src_doc != ?").run(phantom, info.docId, info.docId);
|
|
122
122
|
const selfEdge = db.prepare("UPDATE edges SET dst_node = ? WHERE dst_node = ? AND to_commit IS NULL AND src_doc = ? AND src_block = ? AND anchor IS ?");
|
|
123
123
|
for (const l of inbound) {
|
|
124
|
-
if (l.
|
|
124
|
+
if (l.doc_id !== info.docId || l.block_id === null)
|
|
125
125
|
continue;
|
|
126
|
-
selfEdge.run(phantom, info.docId, info.docId, l.
|
|
126
|
+
selfEdge.run(phantom, info.docId, info.docId, l.block_id, l.anchor);
|
|
127
127
|
affected.add(info.docId);
|
|
128
128
|
}
|
|
129
129
|
for (const d of affected)
|
|
@@ -172,8 +172,8 @@ function applyCtx(ctx) {
|
|
|
172
172
|
function planInboundRetarget(store, docId, fromPath, toRel, inbound) {
|
|
173
173
|
const byBlock = new Map();
|
|
174
174
|
for (const l of inbound)
|
|
175
|
-
if (l.
|
|
176
|
-
byBlock.set(l.
|
|
175
|
+
if (l.block_id !== null && !byBlock.has(l.block_id))
|
|
176
|
+
byBlock.set(l.block_id, l);
|
|
177
177
|
// A container's raw includes its children's raw, so a link inside a list item
|
|
178
178
|
// is reported for BOTH the list and the item. Rewrite the deepest block only:
|
|
179
179
|
// updating the container would re-parse (and re-identify) its children, and
|
|
@@ -202,17 +202,17 @@ function planInboundRetarget(store, docId, fromPath, toRel, inbound) {
|
|
|
202
202
|
// Match against the directory the link was RESOLVED in (the source's path at
|
|
203
203
|
// extraction time); write relative forms against the source's CURRENT
|
|
204
204
|
// directory — they differ only for links inside the moved doc itself.
|
|
205
|
-
const writeDir = src.
|
|
205
|
+
const writeDir = src.doc_id === docId ? dirOf(toRel) : dirOf(src.path);
|
|
206
206
|
const newRaw = retargetLinksInRaw(row.bytes.toString("utf8"), dirOf(src.path), writeDir, fromPath, toRel);
|
|
207
207
|
if (newRaw === null)
|
|
208
208
|
continue;
|
|
209
209
|
ops.push({ op: "update", block: blockId, markdown: newRaw, expect: { content_hash: row.raw_hash.toString("hex") } });
|
|
210
210
|
blocks.push(blockId);
|
|
211
|
-
docs.add(src.
|
|
211
|
+
docs.add(src.doc_id);
|
|
212
212
|
}
|
|
213
213
|
// Containers whose rewritten child covered them count as rewritten too.
|
|
214
214
|
const rewritten = new Set([...blocks, ...containers]);
|
|
215
|
-
const dangling = inbound.filter((l) => l.
|
|
215
|
+
const dangling = inbound.filter((l) => l.block_id === null || !rewritten.has(l.block_id));
|
|
216
216
|
return { ops, blocks, docs: [...docs], dangling };
|
|
217
217
|
}
|
|
218
218
|
/** docs_delete: mark a document deleted and remove its file (resurrection-poolable). */
|
|
@@ -28,8 +28,11 @@ export declare function listsInsertItem(anchor: string, at: "start" | "end" | {
|
|
|
28
28
|
} | {
|
|
29
29
|
after: string;
|
|
30
30
|
}, markdown: string): Op[];
|
|
31
|
+
/** One rewritten block of a retarget/repair (spec/surface §4, 3.0): the block's
|
|
32
|
+
* `id`, its document's `path` (the storage form here; the surface roots it),
|
|
33
|
+
* and the raw before/after. */
|
|
31
34
|
export interface RetargetHit {
|
|
32
|
-
|
|
35
|
+
id: string;
|
|
33
36
|
/** repo-relative path of the block's document */
|
|
34
37
|
path: string;
|
|
35
38
|
oldRaw: string;
|
|
@@ -230,7 +230,7 @@ export function linksRepair(store, repoId, repairs, opts = {}) {
|
|
|
230
230
|
c.tally.forEach((n, i) => { effective[i].hits += n; });
|
|
231
231
|
const hash = rawHashOfBlock(store, blockId);
|
|
232
232
|
ops.push({ op: "update", block: blockId, markdown: c.newRaw, ...(hash ? { expect: { content_hash: hash } } : {}) });
|
|
233
|
-
hits.push({
|
|
233
|
+
hits.push({ id: blockId, path: c.path, oldRaw: c.oldRaw, newRaw: c.newRaw });
|
|
234
234
|
}
|
|
235
235
|
return { ops, hits, pairs };
|
|
236
236
|
}
|
package/dist/src/mutate/ops.js
CHANGED
|
@@ -109,7 +109,7 @@ function checkContentHash(block, expect, opIndex) {
|
|
|
109
109
|
throw new MutationError("stale_expectation", "expect.content_hash required", {
|
|
110
110
|
op_index: opIndex,
|
|
111
111
|
block: block.id,
|
|
112
|
-
current: {
|
|
112
|
+
current: { hash: rawHashHex(block.raw), markdown: block.raw },
|
|
113
113
|
retriable: true,
|
|
114
114
|
});
|
|
115
115
|
}
|
|
@@ -119,7 +119,7 @@ function checkContentHash(block, expect, opIndex) {
|
|
|
119
119
|
op_index: opIndex,
|
|
120
120
|
block: block.id,
|
|
121
121
|
expected_content_hash: expect.content_hash,
|
|
122
|
-
current: {
|
|
122
|
+
current: { hash: current, markdown: block.raw },
|
|
123
123
|
retriable: true,
|
|
124
124
|
});
|
|
125
125
|
}
|
|
@@ -8,15 +8,18 @@ export type OpsetKind = "doc_update";
|
|
|
8
8
|
* reproduce the proposed bytes exactly.
|
|
9
9
|
*/
|
|
10
10
|
export type PlanDisposition = "same" | "edited" | "moved" | "edited_moved" | "inserted" | "deleted" | "split_from" | "merged_into" | "copied_from" | "resurrected" | "bulk_rewrite" | "retiled";
|
|
11
|
-
/** State the opset was planned against; applying against different state
|
|
11
|
+
/** State the opset was planned against; applying against different state
|
|
12
|
+
* fails. The document is named by its row attributes (spec/surface §1.2,
|
|
13
|
+
* 3.0): `id`, `path`, and `hash` — its current hash at plan time;
|
|
14
|
+
* `baseRevision` names a role and keeps its name. */
|
|
12
15
|
export interface OpsetPrecondition {
|
|
13
16
|
/** doc id the plan targets */
|
|
14
|
-
|
|
17
|
+
id: string;
|
|
15
18
|
path: string;
|
|
16
19
|
/** the document's current revision id at plan time (null for a doc with no committed revision yet) */
|
|
17
20
|
baseRevision: string | null;
|
|
18
|
-
/** sha256 hex of the document's current rendered bytes (docs.file_hash) at plan time */
|
|
19
|
-
|
|
21
|
+
/** sha256 hex of the document's current rendered bytes (docs.file_hash) at plan time — its `hash` */
|
|
22
|
+
hash: string;
|
|
20
23
|
}
|
|
21
24
|
/** One kernel op plus the identity consequence the planner attributes to it. */
|
|
22
25
|
export interface PlanOp {
|
|
@@ -51,7 +54,7 @@ export interface Opset {
|
|
|
51
54
|
version: 1;
|
|
52
55
|
kind: OpsetKind;
|
|
53
56
|
target: {
|
|
54
|
-
|
|
57
|
+
id: string;
|
|
55
58
|
path: string;
|
|
56
59
|
};
|
|
57
60
|
precondition: OpsetPrecondition;
|
|
@@ -84,8 +84,8 @@ export function planUpdate(store, repoId, rootPath, docRef, content, opts = {})
|
|
|
84
84
|
return {
|
|
85
85
|
version: 1,
|
|
86
86
|
kind: "doc_update",
|
|
87
|
-
target: {
|
|
88
|
-
precondition: {
|
|
87
|
+
target: { id: docId, path: path },
|
|
88
|
+
precondition: { id: docId, path: path, baseRevision: info.currentRev, hash: baseContentHash },
|
|
89
89
|
matcherV: config.matcherV,
|
|
90
90
|
ops,
|
|
91
91
|
...(fmChanged ? { frontmatter: { raw: targetFm } } : {}),
|
|
@@ -145,15 +145,16 @@ export function applyOpset(store, req) {
|
|
|
145
145
|
}
|
|
146
146
|
// Precondition: the document must still be at the revision/content the plan
|
|
147
147
|
// was computed against.
|
|
148
|
-
const
|
|
148
|
+
const docId = opset.precondition.id;
|
|
149
|
+
const row = store.db.prepare("SELECT current_rev, lower(hex(file_hash)) fh FROM docs WHERE doc_id = ? AND deleted_commit IS NULL").get(docId);
|
|
149
150
|
if (!row)
|
|
150
|
-
throw new MutationError("doc_missing", `doc ${
|
|
151
|
-
const stale = (opset.precondition.baseRevision !== null && row.current_rev !== opset.precondition.baseRevision) || (row.fh !== null && row.fh !== opset.precondition.
|
|
151
|
+
throw new MutationError("doc_missing", `doc ${docId} not found`, { doc: docId });
|
|
152
|
+
const stale = (opset.precondition.baseRevision !== null && row.current_rev !== opset.precondition.baseRevision) || (row.fh !== null && row.fh !== opset.precondition.hash);
|
|
152
153
|
if (stale) {
|
|
153
154
|
throw new MutationError("stale_plan", "document changed since the plan was computed; re-plan", {
|
|
154
|
-
doc:
|
|
155
|
+
doc: docId,
|
|
155
156
|
expected_revision: opset.precondition.baseRevision,
|
|
156
|
-
current: { revision: row.current_rev,
|
|
157
|
+
current: { revision: row.current_rev, hash: row.fh },
|
|
157
158
|
retriable: true,
|
|
158
159
|
});
|
|
159
160
|
}
|
|
@@ -166,7 +167,7 @@ export function applyOpset(store, req) {
|
|
|
166
167
|
...(req.dryRun !== undefined ? { dryRun: req.dryRun } : {}),
|
|
167
168
|
...(req.omgbaseDir !== undefined ? { omgbaseDir: req.omgbaseDir } : {}),
|
|
168
169
|
...(req.ts !== undefined ? { ts: req.ts } : {}),
|
|
169
|
-
...(opset.frontmatter ? { setFrontmatter: [{ doc:
|
|
170
|
+
...(opset.frontmatter ? { setFrontmatter: [{ doc: docId, raw: opset.frontmatter.raw }] } : {}),
|
|
170
171
|
});
|
|
171
172
|
}
|
|
172
173
|
/**
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import type { DataContext } from "@omgbase/oqx";
|
|
2
2
|
import type { Store } from "../core/store/store.js";
|
|
3
3
|
import type { SemanticVec } from "../search/cel/compile.js";
|
|
4
|
-
export type Target = "docs" | "blocks" | "nodes" | "
|
|
4
|
+
export type Target = "docs" | "blocks" | "nodes" | "links";
|
|
5
5
|
declare const TARGET: unique symbol;
|
|
6
|
+
/** The engine attributes per kind (spec/surface §1.2 table). Exported so the
|
|
7
|
+
* translator's tests pin the two against each other. */
|
|
8
|
+
export declare const ATTRIBUTES: Readonly<Record<Target, ReadonlySet<string>>>;
|
|
9
|
+
/** The source handles of a document (§1.2): `data` is the merged authored view
|
|
10
|
+
* (frontmatter + inline), the other two one source each. */
|
|
11
|
+
export declare const SOURCE_HANDLES: ReadonlySet<string>;
|
|
12
|
+
/** The value of a statically SINGLE relation that has no row — `dst` on an
|
|
13
|
+
* external or dangling link, `block` on a node without one (oqx 0.20, SEMANTICS
|
|
14
|
+
* §3): an object the engine treats as one row with no rows, so `dst { title }`
|
|
15
|
+
* is absent rather than `[]`, while as a VALUE it is absent (`materialize`),
|
|
16
|
+
* so `dst == null`, `has(dst)` and `dst.title` read as before. */
|
|
17
|
+
export declare const ABSENT_SINGLE: object;
|
|
6
18
|
export interface StoreContextOptions {
|
|
7
19
|
/** Pre-computed query vectors for `semantic("phrase")`, keyed by phrase (the
|
|
8
20
|
* async runner fills this; the sync path leaves it empty and a semantic() with
|
|
@@ -22,9 +34,10 @@ export declare function makeStoreContext(store: Store, repoId: string, opts?: St
|
|
|
22
34
|
export declare function tagRows(rows: Record<string, unknown>[], target: Target): unknown[];
|
|
23
35
|
/**
|
|
24
36
|
* A store row surfacing as a VALUE in a result (spec/surface §1.4, rows as
|
|
25
|
-
* values, 1.2) is rendered as `{ id, path }` — its id column and its
|
|
26
|
-
* path in the reference form (`/a.md`, §1 "Paths"), the same two keys
|
|
27
|
-
* carries — never the store
|
|
37
|
+
* values, 1.2) is rendered as `{ id, path }` (3.0) — its id column and its
|
|
38
|
+
* document's path in the reference form (`/a.md`, §1 "Paths"), the same two keys
|
|
39
|
+
* every hit carries, spelled as the attributes that read them — never the store
|
|
40
|
+
* row itself.
|
|
28
41
|
* Returns undefined for anything that is not a tagged row (run.ts leaves those
|
|
29
42
|
* alone).
|
|
30
43
|
*/
|