@omgbase/core 0.21.0 → 0.24.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/dist/src/core/ids.d.ts +1 -1
- package/dist/src/core/read/document.d.ts +4 -1
- package/dist/src/core/read/document.js +18 -6
- package/dist/src/core/store/archive.d.ts +196 -0
- package/dist/src/core/store/archive.js +606 -0
- package/dist/src/core/store/gc.d.ts +25 -4
- package/dist/src/core/store/gc.js +43 -28
- package/dist/src/core/store/rebuild.d.ts +2 -0
- package/dist/src/core/store/rebuild.js +8 -2
- package/dist/src/core/store/retention.d.ts +138 -0
- package/dist/src/core/store/retention.js +409 -0
- package/dist/src/core/store/schema.d.ts +3 -2
- package/dist/src/core/store/schema.js +30 -4
- package/dist/src/core/store/size.d.ts +21 -2
- package/dist/src/core/store/size.js +24 -3
- package/dist/src/core/store/store.d.ts +1 -0
- package/dist/src/core/store/store.js +53 -1
- package/dist/src/graph/history.d.ts +2 -0
- package/dist/src/graph/history.js +8 -4
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -0
- package/dist/src/mcp/errors.d.ts +1 -1
- package/dist/src/mcp/errors.js +4 -0
- package/dist/src/mcp/reference.d.ts +1 -1
- package/dist/src/mcp/reference.js +49 -11
- package/dist/src/mcp/server.js +2 -2
- package/dist/src/mutate/select.js +5 -1
- package/dist/src/oqx-js/context.js +39 -8
- package/dist/src/oqx-js/dates.d.ts +105 -0
- package/dist/src/oqx-js/dates.js +427 -0
- package/dist/src/oqx-js/names.js +14 -3
- package/dist/src/oqx-js/planner.js +21 -2
- package/dist/src/oqx-js/run.d.ts +1 -0
- package/dist/src/oqx-js/run.js +82 -2
- package/dist/src/oqx-js/sql/translate.js +12 -5
- package/dist/src/oqx-js/store-index.js +1 -1
- package/dist/src/spec-versions.d.ts +4 -4
- package/dist/src/spec-versions.js +3 -3
- package/package.json +2 -2
package/dist/src/oqx-js/names.js
CHANGED
|
@@ -165,6 +165,14 @@ function kindOfPath(on, path) {
|
|
|
165
165
|
cur = seg;
|
|
166
166
|
continue;
|
|
167
167
|
}
|
|
168
|
+
// At a group scope `rows` yields the grouped rows (their kind); a key is a
|
|
169
|
+
// value the language built, not a row of any kind.
|
|
170
|
+
if (typeof cur === "object") {
|
|
171
|
+
if (seg !== "rows" || i !== 0)
|
|
172
|
+
return null;
|
|
173
|
+
cur = cur.group;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
168
176
|
if (seg === "$it" && i === 0)
|
|
169
177
|
continue;
|
|
170
178
|
const next = HANDLES[cur][seg] ?? RELATIONS[cur][seg];
|
|
@@ -172,7 +180,7 @@ function kindOfPath(on, path) {
|
|
|
172
180
|
return null;
|
|
173
181
|
cur = next;
|
|
174
182
|
}
|
|
175
|
-
return cur === "root" ? null : cur;
|
|
183
|
+
return cur === "root" || typeof cur === "object" ? null : cur;
|
|
176
184
|
}
|
|
177
185
|
/** The kind of the frontier rows of a walk: the seeds' kind when every destination yields rows of that same kind, else unknown. */
|
|
178
186
|
function kindOfFrontier(seed, f, readDepth, byDepth) {
|
|
@@ -194,13 +202,16 @@ export function kindOfScope(steps) {
|
|
|
194
202
|
for (const step of steps) {
|
|
195
203
|
const e = step.expr;
|
|
196
204
|
if (e.kind === "follow")
|
|
197
|
-
cur = kindOfFrontier(cur === "root" ? null : cur, e, readDepth, byDepth);
|
|
205
|
+
cur = kindOfFrontier(cur === "root" || typeof cur === "object" ? null : cur, e, readDepth, byDepth);
|
|
206
|
+
// A `group by` step (oqx 0.24): the rows at this depth become groups of them.
|
|
207
|
+
else if (e.kind === "groupBy")
|
|
208
|
+
cur = { group: cur === "root" || typeof cur === "object" ? null : cur };
|
|
198
209
|
else
|
|
199
210
|
cur = kindOfExpr(e, cur, readDepth, byDepth);
|
|
200
211
|
byDepth.set(step.depth, cur);
|
|
201
212
|
readDepth = step.depth;
|
|
202
213
|
}
|
|
203
|
-
return cur === "root" ? null : cur;
|
|
214
|
+
return cur === "root" || typeof cur === "object" ? null : cur;
|
|
204
215
|
}
|
|
205
216
|
/** Judge a dotted name read on rows of `target`; null = known. */
|
|
206
217
|
function judge(store, repoId, target, path) {
|
|
@@ -91,6 +91,15 @@ function subMayRaise(s, target) {
|
|
|
91
91
|
return true;
|
|
92
92
|
if (s.follow && followMayRaise(s.follow, target))
|
|
93
93
|
return true;
|
|
94
|
+
// A grouped block (oqx 0.24) evaluates its keys, `having` and its aggregates
|
|
95
|
+
// (`sum` over a string raises) per group.
|
|
96
|
+
if (s.groupBy?.keys.some((k) => exprMayRaise(k.expr, target, false)))
|
|
97
|
+
return true;
|
|
98
|
+
if (s.having && whereMayRaise(s.having, target, false))
|
|
99
|
+
return true;
|
|
100
|
+
// A flattened block (oqx 0.25) evaluates each `flatten` expression per row.
|
|
101
|
+
if (s.flatten.some((f) => exprMayRaise(f.expr, target, false)))
|
|
102
|
+
return true;
|
|
94
103
|
if (s.limit && exprMayRaise(s.limit, target, false))
|
|
95
104
|
return true;
|
|
96
105
|
if (s.offset && exprMayRaise(s.offset, target, false))
|
|
@@ -133,6 +142,9 @@ function exprMayRaise(e, target, root) {
|
|
|
133
142
|
// a record is an eval error only the data decides, so with any interpolation
|
|
134
143
|
// it may raise.
|
|
135
144
|
case "template": return e.parts.some((p) => typeof p !== "string");
|
|
145
|
+
// An aggregate (oqx 0.24) raises on a non-number under `sum`/`avg`, which
|
|
146
|
+
// only the data decides; a grouped query is never planned anyway (below).
|
|
147
|
+
case "aggregate": return true;
|
|
136
148
|
case "lit":
|
|
137
149
|
case "binding": return false;
|
|
138
150
|
}
|
|
@@ -148,8 +160,15 @@ export class SQLiteQueryPlanner {
|
|
|
148
160
|
this.ctxOpts = ctxOpts;
|
|
149
161
|
}
|
|
150
162
|
plan(query, params) {
|
|
151
|
-
// Only simple top-level scans: no follow, no `from E` re-projection
|
|
152
|
-
|
|
163
|
+
// Only simple top-level scans: no follow, no `from E` re-projection, no
|
|
164
|
+
// `group by` (oqx 0.24), no `flatten` (oqx 0.25). A grouped or flattened
|
|
165
|
+
// query is declined whole: its `where` conjuncts could be pushed (the fan-out
|
|
166
|
+
// and the grouping happen after them, so the residual would flatten and
|
|
167
|
+
// group the produced rows correctly), but a pushed conjunct that empties the
|
|
168
|
+
// scan would hide an eval error a `flatten` expression, an aggregate or
|
|
169
|
+
// `having` raises in memory (`x!`, `sum` over a string) — decline (c)
|
|
170
|
+
// extended to the post-where clauses. SQL pushdown of either is a later round.
|
|
171
|
+
if (query.follow || query.from.length > 0 || query.groupBy || query.flatten.length > 0)
|
|
153
172
|
return null;
|
|
154
173
|
const target = rootTarget(query.source);
|
|
155
174
|
if (!target)
|
package/dist/src/oqx-js/run.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ export interface OqxOptions {
|
|
|
72
72
|
}
|
|
73
73
|
export declare function rootPathLiterals(e: Expr): Expr;
|
|
74
74
|
export declare function checkRootSpellings(q: Query): void;
|
|
75
|
+
export declare function foldDates(e: Expr): Expr;
|
|
75
76
|
export declare function collectSemanticPhrases(source: string): string[];
|
|
76
77
|
export declare function reservedAlias(items: readonly SelectItem[]): FilterInvalid | null;
|
|
77
78
|
export declare const BARE_NEEDS_SELECT_MESSAGE = "`bare` needs a `select` \u2014 without a projection a hit is only its envelope";
|
package/dist/src/oqx-js/run.js
CHANGED
|
@@ -9,6 +9,7 @@ import { makeStoreContext, rowRef } from "./context.js";
|
|
|
9
9
|
import { SQLiteQueryPlanner } from "./planner.js";
|
|
10
10
|
import { REPO_REMOVED_MESSAGE, ROOTS, bareTargetMessage, pastRootMessage, unknownTargetMessage } from "./root-row.js";
|
|
11
11
|
import { checkNames } from "./names.js";
|
|
12
|
+
import { DATE_FUNCTIONS, DATE_METHODS, dateFunction, dateMethod } from "./dates.js";
|
|
12
13
|
import { FilterInvalid } from "../search/cel/parser.js";
|
|
13
14
|
import { float32ToBlob } from "../core/vec.js";
|
|
14
15
|
import { encodeCursor as encodeKeyset, decodePathCursor } from "../core/cursor.js";
|
|
@@ -91,8 +92,32 @@ export function checkRootSpellings(q) {
|
|
|
91
92
|
},
|
|
92
93
|
});
|
|
93
94
|
}
|
|
95
|
+
// Dates over literals fold to literals (spec/surface §1.3 "Dates and
|
|
96
|
+
// durations", 4.8): `date("today")`, `dur("30 days")`, and a date method whose
|
|
97
|
+
// receiver and arguments are literals (`date("today").minus(dur("30 days"))`,
|
|
98
|
+
// folded inside-out since `transform` maps children first) become the string /
|
|
99
|
+
// number / null they evaluate to — by the SAME functions the context runs, so
|
|
100
|
+
// nothing changes in meaning — before the planner sees the tree. So `where
|
|
101
|
+
// updated_at < date("today")` is a text-vs-text comparison the translator
|
|
102
|
+
// pushes down (a call is otherwise an unconditional decline), and a named point
|
|
103
|
+
// is resolved ONCE per query. A call with the wrong arity is left in place: it
|
|
104
|
+
// raises when evaluated, and an empty source never evaluates it (spec/oqx §11).
|
|
105
|
+
const isLit = (e) => e.kind === "lit";
|
|
106
|
+
export function foldDates(e) {
|
|
107
|
+
if (e.kind !== "call" || !e.args.every(isLit))
|
|
108
|
+
return e;
|
|
109
|
+
const args = e.args.map((a) => a.value);
|
|
110
|
+
if (e.recv === null) {
|
|
111
|
+
if (!Object.hasOwn(DATE_FUNCTIONS, e.name) || DATE_FUNCTIONS[e.name] !== args.length)
|
|
112
|
+
return e;
|
|
113
|
+
return build.lit(dateFunction(e.name, args).value);
|
|
114
|
+
}
|
|
115
|
+
if (!isLit(e.recv) || !Object.hasOwn(DATE_METHODS, e.name) || DATE_METHODS[e.name] !== args.length)
|
|
116
|
+
return e;
|
|
117
|
+
return build.lit(dateMethod(e.name, e.recv.value, args).value);
|
|
118
|
+
}
|
|
94
119
|
function rewriteQuery(q) {
|
|
95
|
-
return transform(q, (e) => (e.kind === "call" && e.recv === null && ROW_FNS.has(e.name) ? { ...e, recv: build.ident("$self") } : rootPathLiterals(e)));
|
|
120
|
+
return transform(q, (e) => (e.kind === "call" && e.recv === null && ROW_FNS.has(e.name) ? { ...e, recv: build.ident("$self") } : foldDates(rootPathLiterals(e))));
|
|
96
121
|
}
|
|
97
122
|
// A top-level `limit`/`offset` on the collect path is applied by the runner (see
|
|
98
123
|
// oqxRunInner), so it must be a plain number literal here — there is no row to
|
|
@@ -347,6 +372,33 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
347
372
|
const res = engine.run(parsed, []);
|
|
348
373
|
return { hits: [], truncated: false, cursor: null, consumer: "none", none: res.consumer === "none" ? res.none : true };
|
|
349
374
|
}
|
|
375
|
+
// A grouped query (oqx 0.24, SEMANTICS §24) yields GROUPS, not store rows:
|
|
376
|
+
// the envelope does not apply — there is no `id`/`path` to inject and no
|
|
377
|
+
// keyset to page by — so a hit is the group's projection as the query wrote
|
|
378
|
+
// it (`{ layer, n }`), exactly what `bare` yields for a row query; `bare` is
|
|
379
|
+
// accepted and changes nothing. Rows that surface as values (`rows collect {
|
|
380
|
+
// }` with an empty projection, `collect(doc)`) render as `{ id, path }` refs
|
|
381
|
+
// like every row-as-value. Paging is by position: the query's own
|
|
382
|
+
// `limit`/`offset` define the set, the tool's `limit` takes the first page,
|
|
383
|
+
// `truncated` says whether more groups follow, the cursor is always null (as
|
|
384
|
+
// under a custom `order by`). `distinct` cannot occur (a parse error).
|
|
385
|
+
if (parsed.groupBy)
|
|
386
|
+
return runGrouped(engine, parsed, consumer, opts);
|
|
387
|
+
// A flattened query (oqx 0.25, SEMANTICS §25) yields the parent rows, one per
|
|
388
|
+
// element: a hit is still a store row, so the envelope is injected as usual
|
|
389
|
+
// and repeats per element (Dataview's `TABLE … FLATTEN`). What changes is
|
|
390
|
+
// uniqueness — `(path, id)` no longer names one hit — so the keyset cursor
|
|
391
|
+
// cannot land inside a document's elements: a flattened query pages
|
|
392
|
+
// positionally with a null cursor, as a grouped query and a custom `order by`
|
|
393
|
+
// do (a keyset extended with the flatten ordinal is a later round). A bound
|
|
394
|
+
// name of `id` or `path` would shadow the envelope's own reads (the name
|
|
395
|
+
// shadows a same-named row property on the flattened row): refused, like a
|
|
396
|
+
// projection that collides with the envelope.
|
|
397
|
+
const flattened = parsed.flatten.length > 0;
|
|
398
|
+
for (const f of parsed.flatten) {
|
|
399
|
+
if (ENVELOPE_KEYS.has(f.name))
|
|
400
|
+
throw new FilterInvalid(`flatten \`as ${f.name}\` collides with the hit envelope — a flattened row is still the row, whose \`${f.name}\` the envelope reads; bind another name`, "OQX");
|
|
401
|
+
}
|
|
350
402
|
// collect / first / single: inject id + path so every hit carries them. A
|
|
351
403
|
// top-level `select distinct` is applied HERE, not in the engine: the injected
|
|
352
404
|
// id/path are unique per row and would defeat the engine's projection dedup, so
|
|
@@ -400,7 +452,7 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
400
452
|
const limit = constBound(topLimit, "limit");
|
|
401
453
|
if (offset || limit != null)
|
|
402
454
|
rows = rows.slice(offset, limit == null ? undefined : offset + limit);
|
|
403
|
-
const custom = !!parsed.orderBy && parsed.orderBy.length > 0;
|
|
455
|
+
const custom = (!!parsed.orderBy && parsed.orderBy.length > 0) || flattened;
|
|
404
456
|
const cap = opts.limit ?? 50;
|
|
405
457
|
let page = rows;
|
|
406
458
|
if (!custom && opts.cursor) {
|
|
@@ -417,6 +469,34 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
417
469
|
return { hits: [], truncated, cursor, consumer: "collect", values: page.map((s) => s.proj[VALUE_KEY]) };
|
|
418
470
|
return { hits: page.map(render), truncated, cursor, consumer: "collect" };
|
|
419
471
|
}
|
|
472
|
+
// The collect/first/single path of a grouped query (see `runResolved`).
|
|
473
|
+
function runGrouped(engine, parsed, consumer, opts) {
|
|
474
|
+
const topValues = parsed.values;
|
|
475
|
+
// A `values` projection rides as a record under VALUE_KEY and is peeled off
|
|
476
|
+
// the page, as on the row path.
|
|
477
|
+
const select = topValues ? [{ ...parsed.select[0], name: VALUE_KEY }] : parsed.select;
|
|
478
|
+
const { limit: topLimit, offset: topOffset } = parsed;
|
|
479
|
+
const base = consumer === "collect" ? { ...parsed, limit: null, offset: null } : parsed;
|
|
480
|
+
const res = engine.run({ ...base, values: false, select }, []);
|
|
481
|
+
const project = (row) => renderValue(row);
|
|
482
|
+
if (consumer === "first" || consumer === "single") {
|
|
483
|
+
const row = res.consumer === "first" || res.consumer === "single" ? res.row : null;
|
|
484
|
+
if (topValues)
|
|
485
|
+
return { hits: [], truncated: false, cursor: null, consumer, values: row == null ? [] : [project(row)[VALUE_KEY]] };
|
|
486
|
+
return { hits: row == null ? [] : [project(row)], truncated: false, cursor: null, consumer };
|
|
487
|
+
}
|
|
488
|
+
let groups = (res.consumer === "collect" ? res.rows : []).map(project);
|
|
489
|
+
const offset = constBound(topOffset, "offset") ?? 0;
|
|
490
|
+
const limit = constBound(topLimit, "limit");
|
|
491
|
+
if (offset || limit != null)
|
|
492
|
+
groups = groups.slice(offset, limit == null ? undefined : offset + limit);
|
|
493
|
+
const cap = opts.limit ?? 50;
|
|
494
|
+
const truncated = groups.length > cap;
|
|
495
|
+
const page = groups.slice(0, cap);
|
|
496
|
+
if (topValues)
|
|
497
|
+
return { hits: [], truncated, cursor: null, consumer: "collect", values: page.map((g) => g[VALUE_KEY]) };
|
|
498
|
+
return { hits: page, truncated, cursor: null, consumer: "collect" };
|
|
499
|
+
}
|
|
420
500
|
export async function oqxRunAsync(store, repoId, source, opts = {}, embedQuery) {
|
|
421
501
|
const phrases = collectSemanticPhrases(source);
|
|
422
502
|
if (phrases.length === 0)
|
|
@@ -60,14 +60,16 @@ export const NON_PROPERTY_NAMES = {
|
|
|
60
60
|
};
|
|
61
61
|
// ---- engine attributes ------------------------------------------------------
|
|
62
62
|
// The engine attributes (spec/surface §1.2, 3.0: bare, snake_case, winning on
|
|
63
|
-
// collision — `id`, `path`, `raw`, `hash`, `updated_at` on docs
|
|
64
|
-
// `title`/`tags` on docs, `id`/`path` on nodes and edges) → a param-free SQL
|
|
63
|
+
// collision — `id`, `path`, `raw`, `hash`, `updated_at`, `created_at` on docs
|
|
64
|
+
// and blocks, `title`/`tags` on docs, `id`/`path` on nodes and edges) → a param-free SQL
|
|
65
65
|
// scalar, per target, with its kind. The structural columns and foreign keys are
|
|
66
66
|
// translated in `translateOperand`. Anything not mapped (`raw`, reconstructed or
|
|
67
67
|
// a blob; `title`, computed; `tags`, the union of the authored list and the
|
|
68
68
|
// computed hashtags) returns null → residual, and the caller must NOT fall
|
|
69
69
|
// through to a property read of the same name (the attribute wins in memory).
|
|
70
|
-
// `updated_at`
|
|
70
|
+
// `updated_at` and `created_at` (4.10) are correlated subqueries over the
|
|
71
|
+
// document's revisions (`current_rev` / `seq = 1`); a block's are residual, as
|
|
72
|
+
// before. `path` (and the edge field `dst_path`)
|
|
71
73
|
// is the REFERENCE form on the surface (spec/surface §1 "Paths", 2.0) — `'/' ||
|
|
72
74
|
// <storage column>` in SQL — so every comparison, `startsWith`, `contains`,
|
|
73
75
|
// `lower()`… sees exactly the string the in-memory attribute yields;
|
|
@@ -79,8 +81,8 @@ export function pathColumn(col) {
|
|
|
79
81
|
/** The identity/bytes/time attributes per kind — the names `attributeSql` owns
|
|
80
82
|
* (the structural columns are handled per target in `translateOperand`). */
|
|
81
83
|
export const ROW_ATTRIBUTES = {
|
|
82
|
-
docs: new Set(["id", "path", "raw", "hash", "updated_at", "title", "tags"]),
|
|
83
|
-
blocks: new Set(["id", "path", "raw", "hash", "updated_at"]),
|
|
84
|
+
docs: new Set(["id", "path", "raw", "hash", "updated_at", "created_at", "title", "tags"]),
|
|
85
|
+
blocks: new Set(["id", "path", "raw", "hash", "updated_at", "created_at"]),
|
|
84
86
|
nodes: new Set(["id", "path"]),
|
|
85
87
|
links: new Set(["id", "path"]),
|
|
86
88
|
};
|
|
@@ -93,6 +95,7 @@ function attributeSql(name, ctx) {
|
|
|
93
95
|
case "path": return pathColumn(`${doc}.path`);
|
|
94
96
|
case "hash": return text(`lower(hex(${self}.file_hash))`);
|
|
95
97
|
case "updated_at": return text(`(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = ${self}.current_rev)`);
|
|
98
|
+
case "created_at": return text(`(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.doc_id = ${self}.doc_id AND r.seq = 1)`);
|
|
96
99
|
}
|
|
97
100
|
else if (target === "blocks")
|
|
98
101
|
switch (name) {
|
|
@@ -300,6 +303,8 @@ export function translateOperand(e, ctx) {
|
|
|
300
303
|
return text(`lower(hex(${doc}.file_hash))`);
|
|
301
304
|
if (k === "updated_at")
|
|
302
305
|
return text(`(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = ${doc}.current_rev)`);
|
|
306
|
+
if (k === "created_at")
|
|
307
|
+
return text(`(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.doc_id = ${doc}.doc_id AND r.seq = 1)`);
|
|
303
308
|
if (k === "format")
|
|
304
309
|
return text(`${doc}.format`);
|
|
305
310
|
if (k.startsWith("$"))
|
|
@@ -334,6 +339,8 @@ export function translateOperand(e, ctx) {
|
|
|
334
339
|
return probe("lower(hex(dd.file_hash))");
|
|
335
340
|
if (k === "updated_at")
|
|
336
341
|
return probe("(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = dd.current_rev)");
|
|
342
|
+
if (k === "created_at")
|
|
343
|
+
return probe("(SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.doc_id = dd.doc_id AND r.seq = 1)");
|
|
337
344
|
if (k === "format")
|
|
338
345
|
return probe("dd.format");
|
|
339
346
|
if (k.startsWith("$"))
|
|
@@ -79,7 +79,7 @@ function probeFor(target, path) {
|
|
|
79
79
|
// relation / handle (`out_links`, `data`, `frontmatter`, …), not the `format` column
|
|
80
80
|
// (not indexed), not an OQX `$` name, and of the engine attributes only
|
|
81
81
|
// `title` (the computed `$title` row, a scalar property the author's `title:`
|
|
82
|
-
// never reaches — `data.title` does): `raw`, `hash`, `updated_at` and `tags`
|
|
82
|
+
// never reaches — `data.title` does): `raw`, `hash`, `updated_at`, `created_at` and `tags`
|
|
83
83
|
// (authored ∪ hashtags) have no index and are never property probes.
|
|
84
84
|
if (key === "title")
|
|
85
85
|
return { kind: "property", key: "$title", source: "computed" };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export declare const SPEC_VERSIONS: {
|
|
2
|
-
readonly oqx: "0.
|
|
2
|
+
readonly oqx: "0.25";
|
|
3
3
|
readonly format: "0.2";
|
|
4
4
|
readonly reconcile: "2.3";
|
|
5
|
-
readonly store: "
|
|
5
|
+
readonly store: "15.0";
|
|
6
6
|
readonly properties: "1.1";
|
|
7
7
|
readonly graph: "1.1";
|
|
8
8
|
readonly search: "2.0";
|
|
9
9
|
readonly mutate: "3.5";
|
|
10
10
|
readonly sync: "2.2";
|
|
11
|
-
readonly surface: "4.
|
|
12
|
-
readonly cli: "4.
|
|
11
|
+
readonly surface: "4.10";
|
|
12
|
+
readonly cli: "4.6";
|
|
13
13
|
};
|
|
14
14
|
export type SpecName = keyof typeof SPEC_VERSIONS;
|
|
@@ -13,13 +13,13 @@ export const SPEC_VERSIONS = {
|
|
|
13
13
|
oqx: LANGUAGE_VERSION,
|
|
14
14
|
format: "0.2",
|
|
15
15
|
reconcile: "2.3",
|
|
16
|
-
store: "
|
|
16
|
+
store: "15.0",
|
|
17
17
|
properties: "1.1",
|
|
18
18
|
graph: "1.1",
|
|
19
19
|
search: "2.0",
|
|
20
20
|
mutate: "3.5",
|
|
21
21
|
sync: "2.2",
|
|
22
|
-
surface: "4.
|
|
23
|
-
cli: "4.
|
|
22
|
+
surface: "4.10",
|
|
23
|
+
cli: "4.6",
|
|
24
24
|
};
|
|
25
25
|
//# sourceMappingURL=spec-versions.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omgbase/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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.25.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",
|