@vortex-os/ontos 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.
Files changed (43) hide show
  1. package/README.md +50 -0
  2. package/dist/actions/index.d.ts +26 -0
  3. package/dist/actions/index.d.ts.map +1 -0
  4. package/dist/actions/index.js +34 -0
  5. package/dist/actions/index.js.map +1 -0
  6. package/dist/extract/deterministic.d.ts +9 -0
  7. package/dist/extract/deterministic.d.ts.map +1 -0
  8. package/dist/extract/deterministic.js +110 -0
  9. package/dist/extract/deterministic.js.map +1 -0
  10. package/dist/extract/index.d.ts +12 -0
  11. package/dist/extract/index.d.ts.map +1 -0
  12. package/dist/extract/index.js +12 -0
  13. package/dist/extract/index.js.map +1 -0
  14. package/dist/extract/types.d.ts +29 -0
  15. package/dist/extract/types.d.ts.map +1 -0
  16. package/dist/extract/types.js +2 -0
  17. package/dist/extract/types.js.map +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +4 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/internal/frontmatter.d.ts +6 -0
  23. package/dist/internal/frontmatter.d.ts.map +1 -0
  24. package/dist/internal/frontmatter.js +30 -0
  25. package/dist/internal/frontmatter.js.map +1 -0
  26. package/dist/sqlite/index.d.ts +4 -0
  27. package/dist/sqlite/index.d.ts.map +1 -0
  28. package/dist/sqlite/index.js +3 -0
  29. package/dist/sqlite/index.js.map +1 -0
  30. package/dist/sqlite/schema.d.ts +10 -0
  31. package/dist/sqlite/schema.d.ts.map +1 -0
  32. package/dist/sqlite/schema.js +40 -0
  33. package/dist/sqlite/schema.js.map +1 -0
  34. package/dist/sqlite/store.d.ts +51 -0
  35. package/dist/sqlite/store.d.ts.map +1 -0
  36. package/dist/sqlite/store.js +169 -0
  37. package/dist/sqlite/store.js.map +1 -0
  38. package/dist/types.d.ts +53 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +10 -0
  41. package/dist/types.js.map +1 -0
  42. package/package.json +62 -0
  43. package/scripts/rebuild-ontos.mjs +82 -0
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @vortex-os/ontos
2
+
3
+ A lightweight **ontology of your operational world** — objects, typed relations,
4
+ and multi-hop traversal — built from your VortEX records, layered on
5
+ `@vortex-os/base`. It is a distinct add-on from `@vortex-os/memory-extended`:
6
+ memory-extended *recalls* what was said; ontos *models* what is and how it
7
+ connects, and acts on recurring situations.
8
+
9
+ > Sibling add-ons, one line: **remember** (`memory-extended`) · **perceive**
10
+ > (`computer-use`) · **model** (`ontos`).
11
+
12
+ ## Status — Phase 1 (0.1.0)
13
+
14
+ Phase 1 is **text-first**: the ontology is built only from existing markdown
15
+ records (the failure ledger, decision-log, memories, `[[wikilinks]]`), with **no
16
+ screen perception and no background daemon** (those are Phase 2, only if Phase 1
17
+ proves its value). Storage is **sqlite** (better-sqlite3) with recursive-CTE
18
+ traversal — no graph DB (TypeDB/Neo4j) and no formal OWL/RDF reasoner.
19
+
20
+ Implemented and verified (typecheck/build/verify 15/15; confirmed on a real
21
+ instance — e.g. `literal-control-bytes` → 6 occurrences, guard fires):
22
+
23
+ - **`sqlite/OntosStore`** — schema; idempotent object/relation upsert
24
+ (relId = `sha256(source⏎relation⏎target)`); alias-based identity resolution;
25
+ hop-capped (≤ 3) cycle-guarded recursive-CTE traversal; recurrence count;
26
+ `clear()` + a transaction wrapper for a true rebuild.
27
+ - **`extract/`** — the deterministic extractor (Phase 1 §4): failure ledger →
28
+ recurring-failure subgraph (`recurs-as` occurrence→class, `covered-by` →rule);
29
+ decision-log → `decision:` objects (+ wikilink candidates); memory → `rule:`
30
+ objects. LLM enrichment is a documented `TODO`.
31
+ - **`actions/`** — `recurringFailureGuard` (the §5A fast-proof) and `why`
32
+ (§5B decision archaeology, evidence-first ≤ 3 hops).
33
+ - **`scripts/rebuild-ontos.mjs`** — read-only walk of `data/_failures`,
34
+ `data/decision-log`, `data/_memory` → extract → true-rebuild the index.
35
+
36
+ **Deferred** (Phase 1 follow-ups): frontmatter `ontos:` writeback, LLM
37
+ enrichment, confirmation UX, identity embedding-candidates (optional reuse of
38
+ `@vortex-os/memory-extended`'s embedder when present), and the `vortex ontos`
39
+ CLI / session-start trigger wiring.
40
+
41
+ Design: the concept and Phase 1 build spec live in the maintainer's VortEX
42
+ instance (Codex-reviewed, 2 rounds).
43
+
44
+ ## Develop
45
+
46
+ ```
47
+ npm run typecheck --workspace=@vortex-os/ontos
48
+ npm run build --workspace=@vortex-os/ontos
49
+ npm run verify --workspace=@vortex-os/ontos
50
+ ```
@@ -0,0 +1,26 @@
1
+ import type { OntosStore } from "../sqlite/index.js";
2
+ import type { WalkStep } from "../types.js";
3
+ /**
4
+ * §5B — decision archaeology. Walks the reasoning relations (supersedes /
5
+ * contradicts / causes) from an object, returning short, evidence-first chains
6
+ * capped at ≤ 3 hops (cycle-guarded by the store).
7
+ *
8
+ * TODO(phase1): shape the raw walk into chains with the backing evidence
9
+ * snippets (the store already carries `evidence` on each relation).
10
+ */
11
+ export declare function why(store: OntosStore, objectId: string, maxHops?: number): WalkStep[];
12
+ export interface GuardHit {
13
+ readonly failureId: string;
14
+ readonly recurrence: number;
15
+ }
16
+ /**
17
+ * §5A — recurring-failure guard. Given a situation already resolved to a failure
18
+ * object id (the §6 trigger surface does that resolution), report whether it
19
+ * recurs at/over the threshold, so the caller can surface the covering rule /
20
+ * guard.
21
+ *
22
+ * TODO(phase1): join `covered-by` (→Rule) and `resolved-by` (→Action/Guard) to
23
+ * return the remedy alongside the recurrence signal.
24
+ */
25
+ export declare function recurringFailureGuard(store: OntosStore, failureId: string, threshold?: number): GuardHit | null;
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,QAAQ,EAAE,CAKhF;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,SAAI,GACZ,QAAQ,GAAG,IAAI,CASjB"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * §5B — decision archaeology. Walks the reasoning relations (supersedes /
3
+ * contradicts / causes) from an object, returning short, evidence-first chains
4
+ * capped at ≤ 3 hops (cycle-guarded by the store).
5
+ *
6
+ * TODO(phase1): shape the raw walk into chains with the backing evidence
7
+ * snippets (the store already carries `evidence` on each relation).
8
+ */
9
+ export function why(store, objectId, maxHops = 3) {
10
+ return store.traverse(objectId, {
11
+ maxHops,
12
+ rels: ["supersedes", "contradicts", "causes"],
13
+ });
14
+ }
15
+ /**
16
+ * §5A — recurring-failure guard. Given a situation already resolved to a failure
17
+ * object id (the §6 trigger surface does that resolution), report whether it
18
+ * recurs at/over the threshold, so the caller can surface the covering rule /
19
+ * guard.
20
+ *
21
+ * TODO(phase1): join `covered-by` (→Rule) and `resolved-by` (→Action/Guard) to
22
+ * return the remedy alongside the recurrence signal.
23
+ */
24
+ export function recurringFailureGuard(store, failureId, threshold = 2) {
25
+ // Recurrence is counted on the canonical CLASS id. Resolve an occurrence to
26
+ // its class STRUCTURALLY — follow its recurs-as edge — rather than by string
27
+ // surgery on "@" (a recurrence_key could itself contain "@"). A class id has
28
+ // no outgoing recurs-as edge, so it resolves to itself.
29
+ const viaEdge = store.neighbors(failureId, ["recurs-as"]).find((r) => r.sourceId === failureId);
30
+ const classId = viaEdge ? viaEdge.targetId : failureId;
31
+ const recurrence = store.recurrenceCount(classId);
32
+ return recurrence >= threshold ? { failureId: classId, recurrence } : null;
33
+ }
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,UAAU,GAAG,CAAC,KAAiB,EAAE,QAAgB,EAAE,OAAO,GAAG,CAAC;IAClE,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE;QAC9B,OAAO;QACP,IAAI,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,CAAC;KAC9C,CAAC,CAAC;AACL,CAAC;AAOD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAiB,EACjB,SAAiB,EACjB,SAAS,GAAG,CAAC;IAEb,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,wDAAwD;IACxD,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAChG,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACvD,MAAM,UAAU,GAAG,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAClD,OAAO,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ExtractResult, RecordInput } from "./types.js";
2
+ /**
3
+ * Deterministic extraction (Phase 1 §4 step 2) — the fast-proof core, no LLM.
4
+ * Dispatches by record category. Confidently extracts the failure-recurrence +
5
+ * coverage subgraph and the object set; supersedes/causes chains arrive as
6
+ * wikilink candidates until an `ontos:` block or LLM enrichment types them.
7
+ */
8
+ export declare function extractDeterministic(record: RecordInput): ExtractResult;
9
+ //# sourceMappingURL=deterministic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic.d.ts","sourceRoot":"","sources":["../../src/extract/deterministic.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAiB,WAAW,EAAE,MAAM,YAAY,CAAC;AAkG5E;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAWvE"}
@@ -0,0 +1,110 @@
1
+ import { makeRelId } from "../sqlite/store.js";
2
+ const WIKILINK = /\[\[([^\]]+)\]\]/g;
3
+ function basenameSlug(path) {
4
+ const base = path.replace(/\\/g, "/").split("/").pop() ?? path;
5
+ return base.replace(/\.md$/i, "");
6
+ }
7
+ function str(v) {
8
+ return typeof v === "string" && v.length > 0 ? v : null;
9
+ }
10
+ function rel(sourceId, r, targetId, evidence) {
11
+ return {
12
+ relId: makeRelId(sourceId, r, targetId),
13
+ rel: r,
14
+ sourceId,
15
+ targetId,
16
+ provenance: "deterministic",
17
+ confidence: 1,
18
+ confirmed: null,
19
+ evidence,
20
+ };
21
+ }
22
+ function wikilinks(sourceId, body, evidence) {
23
+ const out = [];
24
+ for (const m of body.matchAll(WIKILINK)) {
25
+ const parts = (m[1] ?? "").split("|");
26
+ const targetRef = (parts[0] ?? "").trim();
27
+ if (targetRef)
28
+ out.push({ sourceId, targetRef, evidence });
29
+ }
30
+ return out;
31
+ }
32
+ function empty() {
33
+ return { objects: [], relations: [], links: [] };
34
+ }
35
+ /**
36
+ * Failure ledger -> the recurring-failure subgraph (powers the §5A guard,
37
+ * fully deterministic). One canonical `problem:failure:<key>` class object;
38
+ * each occurrence file becomes its own object with a `recurs-as` edge to the
39
+ * class (so the store's recurrence count = number of occurrences). The optional
40
+ * `rule` field becomes a `covered-by` edge to a `rule:<slug>` object.
41
+ */
42
+ function fromFailure(record) {
43
+ const key = str(record.frontmatter["recurrence_key"]);
44
+ if (!key)
45
+ return empty();
46
+ const classId = `problem:failure:${key}`;
47
+ // Occurrence id uses the file basename. The extracted categories (_failures,
48
+ // decision-log, _memory) are FLAT directories, so basenames are unique there;
49
+ // nested categories (worklog) are not extracted. If a category ever nests,
50
+ // switch this to a full-relative-path discriminator.
51
+ const occId = `${classId}@${basenameSlug(record.path)}`;
52
+ const objects = [
53
+ { id: classId, type: "problem", subtype: "failure", label: key, source: null },
54
+ { id: occId, type: "problem", subtype: "failure", label: key, source: record.path },
55
+ ];
56
+ const relations = [rel(occId, "recurs-as", classId, record.path)];
57
+ const ruleSlug = str(record.frontmatter["rule"]);
58
+ if (ruleSlug) {
59
+ objects.push({ id: `rule:${ruleSlug}`, type: "rule", label: ruleSlug, source: null });
60
+ relations.push(rel(classId, "covered-by", `rule:${ruleSlug}`, record.path));
61
+ }
62
+ return { objects, relations, links: [] };
63
+ }
64
+ /**
65
+ * Decision log -> a `decision:<slug>` object (label = the H1 title). Typed
66
+ * relations like `supersedes` are not structured in the records yet, so they
67
+ * surface as wikilink candidates for human typing (§4).
68
+ */
69
+ function fromDecision(record) {
70
+ const slug = basenameSlug(record.path);
71
+ const id = `decision:${slug}`;
72
+ const title = (record.body.match(/^#\s+(.+)$/m)?.[1] ?? slug).trim();
73
+ return {
74
+ objects: [{ id, type: "decision", label: title, source: record.path }],
75
+ relations: [],
76
+ links: wikilinks(id, record.body, record.path),
77
+ };
78
+ }
79
+ /** Memory -> a `rule:<slug>` object (label = frontmatter `name`); body wikilinks as candidates. */
80
+ function fromMemory(record) {
81
+ const slug = basenameSlug(record.path);
82
+ if (slug === "_INDEX" || slug === "MEMORY")
83
+ return empty();
84
+ const id = `rule:${slug}`;
85
+ const label = str(record.frontmatter["name"]) ?? slug;
86
+ return {
87
+ objects: [{ id, type: "rule", label, source: record.path }],
88
+ relations: [],
89
+ links: wikilinks(id, record.body, record.path),
90
+ };
91
+ }
92
+ /**
93
+ * Deterministic extraction (Phase 1 §4 step 2) — the fast-proof core, no LLM.
94
+ * Dispatches by record category. Confidently extracts the failure-recurrence +
95
+ * coverage subgraph and the object set; supersedes/causes chains arrive as
96
+ * wikilink candidates until an `ontos:` block or LLM enrichment types them.
97
+ */
98
+ export function extractDeterministic(record) {
99
+ switch (record.category) {
100
+ case "failure":
101
+ return fromFailure(record);
102
+ case "decision":
103
+ return fromDecision(record);
104
+ case "memory":
105
+ return fromMemory(record);
106
+ default:
107
+ return empty();
108
+ }
109
+ }
110
+ //# sourceMappingURL=deterministic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic.js","sourceRoot":"","sources":["../../src/extract/deterministic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AAErC,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;IAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC;AAED,SAAS,GAAG,CAAC,QAAgB,EAAE,CAAe,EAAE,QAAgB,EAAE,QAAgB;IAChF,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,CAAC;QACvC,GAAG,EAAE,CAAC;QACN,QAAQ;QACR,QAAQ;QACR,UAAU,EAAE,eAAe;QAC3B,UAAU,EAAE,CAAC;QACb,SAAS,EAAE,IAAI;QACf,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB,EAAE,IAAY,EAAE,QAAgB;IACjE,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,KAAK;IACZ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,MAAmB;IACtC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACtD,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,mBAAmB,GAAG,EAAE,CAAC;IACzC,6EAA6E;IAC7E,8EAA8E;IAC9E,2EAA2E;IAC3E,qDAAqD;IACrD,MAAM,KAAK,GAAG,GAAG,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IACxD,MAAM,OAAO,GAAgB;QAC3B,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QAC9E,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KACpF,CAAC;IACF,MAAM,SAAS,GAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACjD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACtF,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,QAAQ,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,MAAmB;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,YAAY,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QACtE,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,SAAS,UAAU,CAAC,MAAmB;IACrC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,EAAE,CAAC;IAC3D,MAAM,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC;IACtD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3D,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAmB;IACtD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,SAAS;YACZ,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,UAAU;YACb,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,KAAK,QAAQ;YACX,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B;YACE,OAAO,KAAK,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type { RecordCategory, RecordInput, LinkCandidate, ExtractResult } from "./types.js";
2
+ export { extractDeterministic } from "./deterministic.js";
3
+ import type { ExtractResult, RecordInput } from "./types.js";
4
+ /**
5
+ * LLM enrichment (Phase 1 §4 step 3) — runs ONLY on changed, weakly-structured
6
+ * files after deterministic extraction shows gaps, proposing typed relations
7
+ * with confidence + evidence (never auto-confirmed).
8
+ *
9
+ * TODO(phase1): implement against the host LLM. The skeleton is a pass-through.
10
+ */
11
+ export declare function enrichWithLlm(_record: RecordInput, deterministic: ExtractResult): ExtractResult;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,GAAG,aAAa,CAE/F"}
@@ -0,0 +1,12 @@
1
+ export { extractDeterministic } from "./deterministic.js";
2
+ /**
3
+ * LLM enrichment (Phase 1 §4 step 3) — runs ONLY on changed, weakly-structured
4
+ * files after deterministic extraction shows gaps, proposing typed relations
5
+ * with confidence + evidence (never auto-confirmed).
6
+ *
7
+ * TODO(phase1): implement against the host LLM. The skeleton is a pass-through.
8
+ */
9
+ export function enrichWithLlm(_record, deterministic) {
10
+ return deterministic;
11
+ }
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAI1D;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE,aAA4B;IAC9E,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { OntObject, OntRelation } from "../types.js";
2
+ /** Which record family a file came from (the rebuild walk knows this from the dir). */
3
+ export type RecordCategory = "failure" | "decision" | "memory" | "worklog" | "handoff" | "other";
4
+ /** A parsed VortEX markdown record, the input to extraction. */
5
+ export interface RecordInput {
6
+ readonly path: string;
7
+ readonly category: RecordCategory;
8
+ readonly frontmatter: Readonly<Record<string, unknown>>;
9
+ readonly body: string;
10
+ }
11
+ /**
12
+ * An untyped `[[wikilink]]` seed (§4). NOT stored as a typed relation — it is a
13
+ * candidate connection that still needs a human to *type* it (supersedes? causes?)
14
+ * and confirm. Kept separate from `relations` on purpose.
15
+ */
16
+ export interface LinkCandidate {
17
+ readonly sourceId: string;
18
+ /** The wikilink target text (a slug/title), `[[target|alias]]` reduced to `target`. */
19
+ readonly targetRef: string;
20
+ readonly evidence: string;
21
+ }
22
+ export interface ExtractResult {
23
+ readonly objects: OntObject[];
24
+ /** Explicit, deterministic typed relations (recurrence_key, the `rule` field, an `ontos:` block). */
25
+ readonly relations: OntRelation[];
26
+ /** Untyped wikilink seeds — for human typing + confirmation, never auto-stored. */
27
+ readonly links: LinkCandidate[];
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/extract/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjG,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;IAC9B,qGAAqG;IACrG,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC;IAClC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/extract/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export * as sqlite from "./sqlite/index.js";
2
+ export * as extract from "./extract/index.js";
3
+ export * as actions from "./actions/index.js";
4
+ export type * from "./types.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,mBAAmB,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * as sqlite from "./sqlite/index.js";
2
+ export * as extract from "./extract/index.js";
3
+ export * as actions from "./actions/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface FrontmatterDoc<T> {
2
+ readonly frontmatter: T;
3
+ readonly body: string;
4
+ }
5
+ export declare function parseFrontmatter<T = Record<string, unknown>>(source: string): FrontmatterDoc<T>;
6
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/internal/frontmatter.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAe/F"}
@@ -0,0 +1,30 @@
1
+ import { parse as parseYaml } from "yaml";
2
+ /**
3
+ * Inlined YAML-frontmatter parser — mirrors memory-extended's own inlined copy.
4
+ *
5
+ * ontos ships as a public add-on, so it cannot import the internal, unpublished
6
+ * `@vortex-os/core` `parseFrontmatter`. The single helper needed is inlined here
7
+ * (only `yaml` is an external dependency). BOM-safe; returns empty frontmatter +
8
+ * the source unchanged when no fence is present; tolerates a malformed fence by
9
+ * treating it as no frontmatter.
10
+ */
11
+ const FENCE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
12
+ const BOM = "";
13
+ export function parseFrontmatter(source) {
14
+ const cleaned = source.startsWith(BOM) ? source.slice(1) : source;
15
+ const match = cleaned.match(FENCE);
16
+ if (!match) {
17
+ return { frontmatter: {}, body: cleaned };
18
+ }
19
+ const yaml = match[1] ?? "";
20
+ const body = cleaned.slice(match[0].length);
21
+ let parsed;
22
+ try {
23
+ parsed = (parseYaml(yaml) ?? {});
24
+ }
25
+ catch {
26
+ parsed = {};
27
+ }
28
+ return { frontmatter: parsed, body };
29
+ }
30
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/internal/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,KAAK,GAAG,mCAAmC,CAAC;AAClD,MAAM,GAAG,GAAG,GAAG,CAAC;AAOhB,MAAM,UAAU,gBAAgB,CAA8B,MAAc;IAC1E,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAClE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAS,CAAC;IACd,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAM,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,EAAO,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { OntosStore, makeRelId } from "./store.js";
2
+ export type { TraverseOptions } from "./store.js";
3
+ export { SCHEMA } from "./schema.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { OntosStore, makeRelId } from "./store.js";
2
+ export { SCHEMA } from "./schema.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * SQLite schema for the ontos derived index.
3
+ *
4
+ * The markdown frontmatter `ontos:` block is the source of truth; this index is
5
+ * a regenerable derivative (delete the .sqlite file and re-run `rebuild-ontos`).
6
+ * Multi-hop traversal is a recursive CTE over `relations` — no graph DB
7
+ * (TypeDB/Neo4j) is needed at Phase 1 scale (see the build spec, storage section).
8
+ */
9
+ export declare const SCHEMA = "\nCREATE TABLE IF NOT EXISTS objects (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n subtype TEXT,\n label TEXT NOT NULL,\n source TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_objects_type ON objects(type);\n\nCREATE TABLE IF NOT EXISTS relations (\n rel_id TEXT PRIMARY KEY,\n rel TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n provenance TEXT NOT NULL,\n confidence REAL NOT NULL DEFAULT 1.0,\n confirmed TEXT,\n evidence TEXT,\n FOREIGN KEY (source_id) REFERENCES objects(id) ON DELETE CASCADE,\n FOREIGN KEY (target_id) REFERENCES objects(id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_id, rel);\nCREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id, rel);\n\nCREATE TABLE IF NOT EXISTS aliases (\n alias TEXT PRIMARY KEY,\n canonical_id TEXT NOT NULL,\n FOREIGN KEY (canonical_id) REFERENCES objects(id) ON DELETE CASCADE\n);\n";
10
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/sqlite/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,86BA8BlB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * SQLite schema for the ontos derived index.
3
+ *
4
+ * The markdown frontmatter `ontos:` block is the source of truth; this index is
5
+ * a regenerable derivative (delete the .sqlite file and re-run `rebuild-ontos`).
6
+ * Multi-hop traversal is a recursive CTE over `relations` — no graph DB
7
+ * (TypeDB/Neo4j) is needed at Phase 1 scale (see the build spec, storage section).
8
+ */
9
+ export const SCHEMA = `
10
+ CREATE TABLE IF NOT EXISTS objects (
11
+ id TEXT PRIMARY KEY,
12
+ type TEXT NOT NULL,
13
+ subtype TEXT,
14
+ label TEXT NOT NULL,
15
+ source TEXT
16
+ );
17
+ CREATE INDEX IF NOT EXISTS idx_objects_type ON objects(type);
18
+
19
+ CREATE TABLE IF NOT EXISTS relations (
20
+ rel_id TEXT PRIMARY KEY,
21
+ rel TEXT NOT NULL,
22
+ source_id TEXT NOT NULL,
23
+ target_id TEXT NOT NULL,
24
+ provenance TEXT NOT NULL,
25
+ confidence REAL NOT NULL DEFAULT 1.0,
26
+ confirmed TEXT,
27
+ evidence TEXT,
28
+ FOREIGN KEY (source_id) REFERENCES objects(id) ON DELETE CASCADE,
29
+ FOREIGN KEY (target_id) REFERENCES objects(id) ON DELETE CASCADE
30
+ );
31
+ CREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_id, rel);
32
+ CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id, rel);
33
+
34
+ CREATE TABLE IF NOT EXISTS aliases (
35
+ alias TEXT PRIMARY KEY,
36
+ canonical_id TEXT NOT NULL,
37
+ FOREIGN KEY (canonical_id) REFERENCES objects(id) ON DELETE CASCADE
38
+ );
39
+ `;
40
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/sqlite/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BrB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { OntObject, OntRelation, RelationType, WalkStep } from "../types.js";
2
+ /**
3
+ * §5-bis relation-id recipe. Stable over the (source, relation, target) triple,
4
+ * so re-accepting the same relation is idempotent (never duplicates).
5
+ */
6
+ export declare function makeRelId(sourceId: string, rel: RelationType, targetId: string): string;
7
+ export interface TraverseOptions {
8
+ /** Hop limit, capped at 3 (§5B). */
9
+ readonly maxHops?: number;
10
+ /** Restrict to these edge types (empty = all). */
11
+ readonly rels?: readonly RelationType[];
12
+ }
13
+ /**
14
+ * SQLite-backed ontos index. Markdown `ontos:` frontmatter is the source of
15
+ * truth; this is a regenerable derived index. Sync API (better-sqlite3); call
16
+ * `close()` to release the file lock (matters on Windows).
17
+ */
18
+ export declare class OntosStore {
19
+ readonly dbPath: string;
20
+ private db;
21
+ constructor(dbPath: string);
22
+ close(): void;
23
+ /** Run a function inside one transaction (bulk upserts during a rebuild). */
24
+ transaction(fn: () => void): void;
25
+ /**
26
+ * Empty all tables so a walk-and-upsert becomes a TRUE rebuild: stale objects
27
+ * and relations from deleted/renamed records, or from a changed recurrence_key
28
+ * / removed rule, do not linger (which would skew recurrenceCount). Call before
29
+ * re-populating from a full record walk.
30
+ */
31
+ clear(): void;
32
+ upsertObject(obj: OntObject): void;
33
+ /** Idempotent on relId (§5-bis): re-accepting the same relation updates, never duplicates. */
34
+ upsertRelation(rel: OntRelation): void;
35
+ addAlias(alias: string, canonicalId: string): void;
36
+ /** §3 identity: resolve a name to a canonical object id (a real object id wins, then an alias). */
37
+ resolveAlias(name: string): string | null;
38
+ getObject(id: string): OntObject | null;
39
+ /** Outgoing relations from an object, optionally filtered by relation type. */
40
+ neighbors(id: string, rels?: readonly RelationType[]): OntRelation[];
41
+ /**
42
+ * Multi-hop walk via recursive CTE — capped at maxHops (default 3, §5B) and
43
+ * cycle-guarded: a node never re-enters its own path. The path is delimited
44
+ * with ">" so the membership check is token-exact (not a loose substring).
45
+ * No graph DB is needed for this scale.
46
+ */
47
+ traverse(startId: string, opts?: TraverseOptions): WalkStep[];
48
+ /** §5A helper: how many failures recur as (share a pattern with) this one. */
49
+ recurrenceCount(problemId: string): number;
50
+ }
51
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sqlite/store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvF;AAED,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;CACzC;AA0BD;;;;GAIG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAS1B,KAAK,IAAI,IAAI;IAIb,6EAA6E;IAC7E,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAIjC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAIb,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI;IAkBlC,8FAA8F;IAC9F,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAqBtC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IASlD,mGAAmG;IACnG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAWzC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAgBvC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,WAAW,EAAE;IAapE;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,eAAoB,GAAG,QAAQ,EAAE;IAyBjE,8EAA8E;IAC9E,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;CAQ3C"}
@@ -0,0 +1,169 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import Database from "better-sqlite3";
5
+ import { SCHEMA } from "./schema.js";
6
+ /**
7
+ * §5-bis relation-id recipe. Stable over the (source, relation, target) triple,
8
+ * so re-accepting the same relation is idempotent (never duplicates).
9
+ */
10
+ export function makeRelId(sourceId, rel, targetId) {
11
+ // Newline separates the triple in the preimage: ids derive from filenames /
12
+ // frontmatter keys and never contain a newline, so distinct triples cannot
13
+ // collide on the preimage (a "|"-separated preimage could, since ids may hold "|").
14
+ return createHash("sha256").update(`${sourceId}\n${rel}\n${targetId}`).digest("hex").slice(0, 16);
15
+ }
16
+ function rowToRelation(r) {
17
+ return {
18
+ relId: r.rel_id,
19
+ rel: r.rel,
20
+ sourceId: r.source_id,
21
+ targetId: r.target_id,
22
+ provenance: r.provenance,
23
+ confidence: r.confidence,
24
+ confirmed: r.confirmed,
25
+ evidence: r.evidence,
26
+ };
27
+ }
28
+ /**
29
+ * SQLite-backed ontos index. Markdown `ontos:` frontmatter is the source of
30
+ * truth; this is a regenerable derived index. Sync API (better-sqlite3); call
31
+ * `close()` to release the file lock (matters on Windows).
32
+ */
33
+ export class OntosStore {
34
+ dbPath;
35
+ db;
36
+ constructor(dbPath) {
37
+ mkdirSync(dirname(dbPath), { recursive: true });
38
+ this.dbPath = dbPath;
39
+ this.db = new Database(dbPath);
40
+ this.db.pragma("journal_mode = WAL");
41
+ this.db.pragma("foreign_keys = ON");
42
+ this.db.exec(SCHEMA);
43
+ }
44
+ close() {
45
+ this.db.close();
46
+ }
47
+ /** Run a function inside one transaction (bulk upserts during a rebuild). */
48
+ transaction(fn) {
49
+ this.db.transaction(fn)();
50
+ }
51
+ /**
52
+ * Empty all tables so a walk-and-upsert becomes a TRUE rebuild: stale objects
53
+ * and relations from deleted/renamed records, or from a changed recurrence_key
54
+ * / removed rule, do not linger (which would skew recurrenceCount). Call before
55
+ * re-populating from a full record walk.
56
+ */
57
+ clear() {
58
+ this.db.exec("DELETE FROM relations; DELETE FROM aliases; DELETE FROM objects;");
59
+ }
60
+ upsertObject(obj) {
61
+ this.db
62
+ .prepare(`INSERT INTO objects (id, type, subtype, label, source)
63
+ VALUES (@id, @type, @subtype, @label, @source)
64
+ ON CONFLICT(id) DO UPDATE SET
65
+ type = excluded.type, subtype = excluded.subtype,
66
+ label = excluded.label, source = excluded.source`)
67
+ .run({
68
+ id: obj.id,
69
+ type: obj.type,
70
+ subtype: obj.subtype ?? null,
71
+ label: obj.label,
72
+ source: obj.source ?? null,
73
+ });
74
+ }
75
+ /** Idempotent on relId (§5-bis): re-accepting the same relation updates, never duplicates. */
76
+ upsertRelation(rel) {
77
+ this.db
78
+ .prepare(`INSERT INTO relations (rel_id, rel, source_id, target_id, provenance, confidence, confirmed, evidence)
79
+ VALUES (@relId, @rel, @sourceId, @targetId, @provenance, @confidence, @confirmed, @evidence)
80
+ ON CONFLICT(rel_id) DO UPDATE SET
81
+ provenance = excluded.provenance, confidence = excluded.confidence,
82
+ confirmed = excluded.confirmed, evidence = excluded.evidence`)
83
+ .run({
84
+ relId: rel.relId,
85
+ rel: rel.rel,
86
+ sourceId: rel.sourceId,
87
+ targetId: rel.targetId,
88
+ provenance: rel.provenance,
89
+ confidence: rel.confidence,
90
+ confirmed: rel.confirmed ?? null,
91
+ evidence: rel.evidence ?? null,
92
+ });
93
+ }
94
+ addAlias(alias, canonicalId) {
95
+ this.db
96
+ .prepare(`INSERT INTO aliases (alias, canonical_id) VALUES (?, ?)
97
+ ON CONFLICT(alias) DO UPDATE SET canonical_id = excluded.canonical_id`)
98
+ .run(alias, canonicalId);
99
+ }
100
+ /** §3 identity: resolve a name to a canonical object id (a real object id wins, then an alias). */
101
+ resolveAlias(name) {
102
+ const direct = this.db.prepare(`SELECT id FROM objects WHERE id = ?`).get(name);
103
+ if (direct)
104
+ return direct.id;
105
+ const row = this.db.prepare(`SELECT canonical_id FROM aliases WHERE alias = ?`).get(name);
106
+ return row ? row.canonical_id : null;
107
+ }
108
+ getObject(id) {
109
+ const row = this.db
110
+ .prepare(`SELECT id, type, subtype, label, source FROM objects WHERE id = ?`)
111
+ .get(id);
112
+ if (!row)
113
+ return null;
114
+ return {
115
+ id: row.id,
116
+ type: row.type,
117
+ subtype: row.subtype ?? null,
118
+ label: row.label,
119
+ source: row.source,
120
+ };
121
+ }
122
+ /** Outgoing relations from an object, optionally filtered by relation type. */
123
+ neighbors(id, rels) {
124
+ const rows = (rels && rels.length
125
+ ? this.db
126
+ .prepare(`SELECT * FROM relations WHERE source_id = ? AND rel IN (${rels.map(() => "?").join(",")})`)
127
+ .all(id, ...rels)
128
+ : this.db.prepare(`SELECT * FROM relations WHERE source_id = ?`).all(id));
129
+ return rows.map(rowToRelation);
130
+ }
131
+ /**
132
+ * Multi-hop walk via recursive CTE — capped at maxHops (default 3, §5B) and
133
+ * cycle-guarded: a node never re-enters its own path. The path is delimited
134
+ * with ">" so the membership check is token-exact (not a loose substring).
135
+ * No graph DB is needed for this scale.
136
+ */
137
+ traverse(startId, opts = {}) {
138
+ const maxHops = Math.min(opts.maxHops ?? 3, 3);
139
+ const rels = opts.rels ?? [];
140
+ const relFilter = rels.length ? `AND r.rel IN (${rels.map(() => "?").join(",")})` : "";
141
+ // Path tokens are newline-delimited: ids never contain a newline, so the
142
+ // membership check is exact (a ">"-delimiter could false-match an id that
143
+ // legitimately contains ">").
144
+ const sql = `
145
+ WITH RECURSIVE walk(node, depth, path) AS (
146
+ SELECT ?, 0, char(10) || ? || char(10)
147
+ UNION ALL
148
+ SELECT r.target_id, w.depth + 1, w.path || r.target_id || char(10)
149
+ FROM relations r JOIN walk w ON r.source_id = w.node
150
+ WHERE w.depth < ? AND instr(w.path, char(10) || r.target_id || char(10)) = 0 ${relFilter}
151
+ )
152
+ SELECT node, depth, path FROM walk WHERE depth > 0 ORDER BY depth`;
153
+ const params = [startId, startId, maxHops, ...rels];
154
+ const rows = this.db.prepare(sql).all(...params);
155
+ return rows.map((r) => ({
156
+ nodeId: r.node,
157
+ depth: r.depth,
158
+ path: r.path.split("\n").filter(Boolean),
159
+ }));
160
+ }
161
+ /** §5A helper: how many failures recur as (share a pattern with) this one. */
162
+ recurrenceCount(problemId) {
163
+ const row = this.db
164
+ .prepare(`SELECT COUNT(*) AS n FROM relations WHERE rel = 'recurs-as' AND (source_id = ? OR target_id = ?)`)
165
+ .get(problemId, problemId);
166
+ return row.n;
167
+ }
168
+ }
169
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sqlite/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @vortex-os/ontos — core types (Phase 1, text-first).
3
+ *
4
+ * Six object types, eight relation types. Object identity ("same-as") is handled
5
+ * by the alias layer (see the sqlite store), NOT as a graph relation — keeping
6
+ * dedup separate from `recurs-as` (pattern recurrence). See the maintainer's
7
+ * instance Phase 1 build spec for the full rationale.
8
+ */
9
+ export type ComponentKind = "host" | "service" | "module" | "repo";
10
+ export type ProblemKind = "incident" | "failure";
11
+ /** §1 — the six object types. `action` includes executable/checkable Guards. */
12
+ export type ObjectType = "component" | "problem" | "decision" | "rule" | "action" | "person";
13
+ export interface OntObject {
14
+ /** Canonical id, e.g. "component:vortex-os/base" or "problem:failure:dist-trap". */
15
+ readonly id: string;
16
+ readonly type: ObjectType;
17
+ /** Component/Problem subtype, when applicable. */
18
+ readonly subtype?: ComponentKind | ProblemKind | null;
19
+ /** Human-readable label. */
20
+ readonly label: string;
21
+ /** Record path this object was extracted from (provenance). */
22
+ readonly source?: string | null;
23
+ }
24
+ /** §2 — the eight relation types (standard-friendly names). */
25
+ export type RelationType = "causes" | "affects" | "depends-on" | "supersedes" | "contradicts" | "resolved-by" | "covered-by" | "recurs-as";
26
+ /** Where a relation came from (§4 / §5-bis provenance). */
27
+ export type RelationProvenance = "deterministic" | "llm" | "wikilink-promoted";
28
+ export interface OntRelation {
29
+ /** §5-bis: relId = hash(sourceId | rel | targetId) — the idempotent upsert key. */
30
+ readonly relId: string;
31
+ readonly rel: RelationType;
32
+ readonly sourceId: string;
33
+ readonly targetId: string;
34
+ readonly provenance: RelationProvenance;
35
+ /** 0..1; deterministic extraction = 1.0. */
36
+ readonly confidence: number;
37
+ /** ISO date a human confirmed it; null = proposed/unconfirmed. */
38
+ readonly confirmed?: string | null;
39
+ /** Record path / snippet pointer backing the relation. */
40
+ readonly evidence?: string | null;
41
+ }
42
+ /** §3 — alias → canonical object id (identity layer; replaces a `same-as` relation). */
43
+ export interface OntAlias {
44
+ readonly alias: string;
45
+ readonly canonicalId: string;
46
+ }
47
+ /** A single result of a multi-hop walk (§5B; capped at ≤ 3 hops, cycle-guarded). */
48
+ export interface WalkStep {
49
+ readonly nodeId: string;
50
+ readonly depth: number;
51
+ readonly path: readonly string[];
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjD,gFAAgF;AAChF,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7F,MAAM,WAAW,SAAS;IACxB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,WAAW,GAAG,IAAI,CAAC;IACtD,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,aAAa,GACb,YAAY,GACZ,WAAW,CAAC;AAEhB,2DAA2D;AAC3D,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG,KAAK,GAAG,mBAAmB,CAAC;AAE/E,MAAM,WAAW,WAAW;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,wFAAwF;AACxF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,oFAAoF;AACpF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @vortex-os/ontos — core types (Phase 1, text-first).
3
+ *
4
+ * Six object types, eight relation types. Object identity ("same-as") is handled
5
+ * by the alias layer (see the sqlite store), NOT as a graph relation — keeping
6
+ * dedup separate from `recurs-as` (pattern recurrence). See the maintainer's
7
+ * instance Phase 1 build spec for the full rationale.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@vortex-os/ontos",
3
+ "version": "0.1.0",
4
+ "description": "Add-on — a lightweight ontology of your operational world (objects, typed relations, multi-hop traversal) built from VortEX records, layered on @vortex-os/base. Phase 1 is text-first and sqlite-backed; no formal OWL/RDF reasoner.",
5
+ "license": "MIT",
6
+ "author": "vortex-os-project",
7
+ "homepage": "https://github.com/vortex-os-project/vortex#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vortex-os-project/vortex.git",
11
+ "directory": "modules/ontos"
12
+ },
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./sqlite": {
22
+ "types": "./dist/sqlite/index.d.ts",
23
+ "default": "./dist/sqlite/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "scripts/rebuild-ontos.mjs",
29
+ "README.md"
30
+ ],
31
+ "bin": {
32
+ "rebuild-ontos": "scripts/rebuild-ontos.mjs"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.json",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "verify": "node scripts/verify.mjs",
38
+ "prepublishOnly": "npm run build"
39
+ },
40
+ "dependencies": {
41
+ "yaml": "^2.6.0"
42
+ },
43
+ "peerDependencies": {
44
+ "@vortex-os/base": ">=0.3.0 <1.0.0",
45
+ "better-sqlite3": "^12.0.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@vortex-os/base": {
49
+ "optional": false
50
+ },
51
+ "better-sqlite3": {
52
+ "optional": false
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "@types/better-sqlite3": "^7.6.13",
57
+ "better-sqlite3": "^12.10.0"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ }
62
+ }
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ // Rebuild the ontos sqlite index from a VortEX instance's records (Phase 1,
3
+ // deterministic — no LLM, read-only on your files). Walks the record dirs,
4
+ // parses frontmatter, runs deterministic extraction, and upserts objects +
5
+ // typed relations. Untyped wikilink candidates are counted but not stored
6
+ // (they need human typing/confirmation — that lands with the confirm UX).
7
+ //
8
+ // Usage: rebuild-ontos [--data-dir <dir>] [--db <path>]
9
+ import { readFileSync, readdirSync } from "node:fs";
10
+ import { join, resolve } from "node:path";
11
+ import { OntosStore } from "../dist/sqlite/index.js";
12
+ import { extractDeterministic } from "../dist/extract/index.js";
13
+ import { parseFrontmatter } from "../dist/internal/frontmatter.js";
14
+
15
+ const args = process.argv.slice(2);
16
+ let dataDir = resolve(process.cwd(), "data");
17
+ let dbPath = null;
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (args[i] === "--data-dir" && args[i + 1]) dataDir = resolve(args[++i]);
20
+ else if (args[i] === "--db" && args[i + 1]) dbPath = resolve(args[++i]);
21
+ }
22
+ if (!dbPath) dbPath = join(dataDir, "_indexes", "ontos.sqlite");
23
+
24
+ const SOURCES = [
25
+ { dir: join(dataDir, "_failures"), category: "failure" },
26
+ { dir: join(dataDir, "decision-log"), category: "decision" },
27
+ { dir: join(dataDir, "_memory"), category: "memory" },
28
+ ];
29
+
30
+ // FLAT listing (non-recursive): the extracted categories (_failures, decision-log,
31
+ // _memory) are flat dirs, so file basenames are unique within each — which keeps
32
+ // occurrence ids unique AND portable across machines (a full-path id would differ
33
+ // by OS path separator). Subdirectories are intentionally not descended.
34
+ function listMd(dir) {
35
+ let entries;
36
+ try {
37
+ entries = readdirSync(dir, { withFileTypes: true });
38
+ } catch {
39
+ return []; // dir absent — skip
40
+ }
41
+ // isFile() is false for symlinks, so a symlinked *.md is not followed out of data/.
42
+ return entries
43
+ .filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_INDEX.md")
44
+ .map((e) => join(dir, e.name));
45
+ }
46
+
47
+ const store = new OntosStore(dbPath);
48
+ let files = 0;
49
+ let skipped = 0;
50
+ let objects = 0;
51
+ let relations = 0;
52
+ let links = 0;
53
+ try {
54
+ // One transaction = a TRUE rebuild: clear first (drop stale rows from deleted/
55
+ // renamed records), then repopulate from the full walk. Atomic + fast.
56
+ store.transaction(() => {
57
+ store.clear();
58
+ for (const { dir, category } of SOURCES) {
59
+ for (const path of listMd(dir)) {
60
+ files++;
61
+ const { frontmatter, body } = parseFrontmatter(readFileSync(path, "utf8"));
62
+ const res = extractDeterministic({ path, category, frontmatter, body });
63
+ if (res.objects.length === 0) skipped++; // no recognizable fields (e.g. malformed/empty frontmatter)
64
+ for (const o of res.objects) {
65
+ store.upsertObject(o);
66
+ objects++;
67
+ }
68
+ for (const r of res.relations) {
69
+ store.upsertRelation(r);
70
+ relations++;
71
+ }
72
+ links += res.links.length;
73
+ }
74
+ }
75
+ });
76
+ console.log(
77
+ `[rebuild-ontos] files=${files} skipped=${skipped} objects=${objects} relations=${relations} link-candidates=${links}`,
78
+ );
79
+ console.log(`[rebuild-ontos] db: ${store.dbPath}`);
80
+ } finally {
81
+ store.close();
82
+ }