@hraness/oh 0.2.6 → 0.3.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 (55) hide show
  1. package/README.md +116 -12
  2. package/dist/canonical.d.ts.map +1 -1
  3. package/dist/cli.d.ts +1 -1
  4. package/dist/cli.js +91 -19
  5. package/dist/cloudflare-embedding.d.ts +104 -0
  6. package/dist/cloudflare-embedding.d.ts.map +1 -0
  7. package/dist/graph.d.ts.map +1 -1
  8. package/dist/index.js +90 -18
  9. package/dist/libsql-semantic.d.ts +111 -0
  10. package/dist/libsql-semantic.d.ts.map +1 -0
  11. package/dist/libsql.js +105 -18
  12. package/dist/memory-page.d.ts +2 -0
  13. package/dist/memory-page.d.ts.map +1 -0
  14. package/dist/memory-page.js +725 -0
  15. package/dist/memory-pages.d.ts +76 -0
  16. package/dist/memory-pages.d.ts.map +1 -0
  17. package/dist/memory.d.ts +1 -0
  18. package/dist/memory.d.ts.map +1 -1
  19. package/dist/memory.js +478 -18
  20. package/dist/projection-public.js +105 -18
  21. package/dist/projection-suss.js +105 -18
  22. package/dist/sdk.js +90 -18
  23. package/dist/semantic-cloud.d.ts +3 -0
  24. package/dist/semantic-cloud.d.ts.map +1 -0
  25. package/dist/semantic-cloud.js +1843 -0
  26. package/dist/semantic.d.ts.map +1 -1
  27. package/dist/semantic.js +104 -21
  28. package/dist/sqlite/index.js +90 -18
  29. package/dist/store.js +105 -18
  30. package/dist/sync.js +90 -18
  31. package/package.json +10 -2
  32. package/skills/oh/SKILL.md +28 -2
  33. package/spec/README.md +11 -3
  34. package/spec/manifest.json +9 -1
  35. package/spec/v1/cloudflare-embedding-profile.json +13 -0
  36. package/spec/v1/cloudflare-embedding-renderer.json +8 -0
  37. package/spec/v1/memory-page.md +153 -0
  38. package/spec/v1/memory-page.schema.json +154 -0
  39. package/spec/v1/memory.md +18 -0
  40. package/spec/v1/migration.md +13 -0
  41. package/spec/v1/semantic-cloud.md +87 -0
  42. package/src/canonical.ts +28 -13
  43. package/src/cli.ts +1 -1
  44. package/src/cloudflare-embedding.test.ts +306 -0
  45. package/src/cloudflare-embedding.ts +385 -0
  46. package/src/contracts.test.ts +20 -0
  47. package/src/graph.ts +63 -6
  48. package/src/libsql-semantic.test.ts +478 -0
  49. package/src/libsql-semantic.ts +1117 -0
  50. package/src/memory-page.ts +1 -0
  51. package/src/memory-pages.test.ts +277 -0
  52. package/src/memory-pages.ts +440 -0
  53. package/src/memory.ts +2 -0
  54. package/src/semantic-cloud.ts +2 -0
  55. package/src/semantic.ts +14 -3
@@ -0,0 +1 @@
1
+ export * from "./memory-pages";
@@ -0,0 +1,277 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { type Sha256Hex } from "./canonical";
4
+ import { createKnowledgeGraphRecordV1 } from "./graph";
5
+ import {
6
+ createOhMemoryPageRecordV1,
7
+ createOhMemoryPageValueV1,
8
+ OH_MEMORY_PAGE_FORMAT_V1,
9
+ OH_MEMORY_PAGE_LIMITS_V1,
10
+ OH_MEMORY_PAGE_RECORD_CODEC_V1,
11
+ parseOhMemoryPageMarkdownV1,
12
+ parseOhMemoryPageRecordV1,
13
+ parseOhMemoryPageValueV1,
14
+ renderOhMemoryPageMarkdownV1,
15
+ type OhMemoryPageSourceV1,
16
+ type OhMemoryPageValueV1,
17
+ } from "./memory-pages";
18
+
19
+ const digestA = "a".repeat(64) as Sha256Hex;
20
+ const digestB = "b".repeat(64) as Sha256Hex;
21
+
22
+ function source(url = "https://example.com/a", overrides: Partial<OhMemoryPageSourceV1> = {}): OhMemoryPageSourceV1 {
23
+ return {
24
+ contentSha256: digestA,
25
+ observedAt: "2026-08-30T10:00:00.000Z",
26
+ title: "Primary source",
27
+ url,
28
+ v: 1,
29
+ ...overrides,
30
+ };
31
+ }
32
+
33
+ function page(overrides: Partial<OhMemoryPageValueV1> = {}): OhMemoryPageValueV1 {
34
+ return {
35
+ body: "A durable note with **Markdown**.",
36
+ createdAt: "2026-08-30T10:30:00.000Z",
37
+ format: OH_MEMORY_PAGE_FORMAT_V1,
38
+ language: "en",
39
+ provenance: {
40
+ actorId: "host.memory",
41
+ attestationSha256: digestB,
42
+ attestedAt: "2026-08-30T12:00:00.000Z",
43
+ kind: "host-attested",
44
+ v: 1,
45
+ },
46
+ sources: [source()],
47
+ summary: "The compact statement used for inspection and recall.",
48
+ title: "Memory page",
49
+ updatedAt: "2026-08-30T11:00:00.000Z",
50
+ v: 1,
51
+ ...overrides,
52
+ };
53
+ }
54
+
55
+ function pageRecord(value = page(), dependencies: readonly string[] = ["activity:page-attestation"])
56
+ : ReturnType<typeof createOhMemoryPageRecordV1> {
57
+ return createOhMemoryPageRecordV1({ dependencies, key: "edition:memory-page", value });
58
+ }
59
+
60
+ describe("Oh memory page value and edition codec", () => {
61
+ test("creates and parses a model-neutral edition record", () => {
62
+ const value = createOhMemoryPageValueV1(page());
63
+ expect(parseOhMemoryPageValueV1(value)).toEqual(value);
64
+ expect(OH_MEMORY_PAGE_RECORD_CODEC_V1.parse(value)).toEqual(value);
65
+
66
+ const record = createOhMemoryPageRecordV1({
67
+ dependencies: ["activity:page-attestation"],
68
+ key: "edition:memory-page",
69
+ value,
70
+ });
71
+ expect(record.kind).toBe("edition");
72
+ expect(parseOhMemoryPageRecordV1(record)).toEqual(record);
73
+ expect(parseOhMemoryPageRecordV1({ ...record, recordSha256: digestA })).toBeNull();
74
+ expect(parseOhMemoryPageRecordV1(createKnowledgeGraphRecordV1({
75
+ dependencies: [], key: "entity:not-a-page", kind: "entity", v: 1, value: { name: "not a page" },
76
+ }))).toBeNull();
77
+ });
78
+
79
+ test("rejects hostile record envelopes without invoking accessors", () => {
80
+ const record = pageRecord();
81
+ const hidden = { ...record } as Record<PropertyKey, unknown>;
82
+ Object.defineProperty(hidden, "hidden", { value: true });
83
+ const symbolic = { ...record } as Record<PropertyKey, unknown>;
84
+ symbolic[Symbol("hidden")] = true;
85
+ let accessorReads = 0;
86
+ const accessor = { ...record } as Record<PropertyKey, unknown>;
87
+ Object.defineProperty(accessor, "recordSha256", {
88
+ enumerable: true,
89
+ get() { accessorReads += 1; throw new Error("must not execute"); },
90
+ });
91
+ const dependencyAccessor = { ...record, dependencies: [...record.dependencies] };
92
+ Object.defineProperty(dependencyAccessor.dependencies, "0", {
93
+ enumerable: true,
94
+ get() { accessorReads += 1; return record.dependencies[0]; },
95
+ });
96
+ const sourceAccessor = {
97
+ ...record,
98
+ value: { ...record.value, sources: [...record.value.sources] },
99
+ };
100
+ Object.defineProperty(sourceAccessor.value.sources, "0", {
101
+ enumerable: true,
102
+ get() { accessorReads += 1; return record.value.sources[0]; },
103
+ });
104
+
105
+ expect(parseOhMemoryPageRecordV1(hidden)).toBeNull();
106
+ expect(parseOhMemoryPageRecordV1(symbolic)).toBeNull();
107
+ expect(parseOhMemoryPageRecordV1(accessor)).toBeNull();
108
+ expect(parseOhMemoryPageRecordV1(dependencyAccessor)).toBeNull();
109
+ expect(parseOhMemoryPageRecordV1(sourceAccessor)).toBeNull();
110
+ expect(accessorReads).toBe(0);
111
+ });
112
+
113
+ test("requires exact fields, host provenance, canonical chronology, and no provider metadata", () => {
114
+ const valid = page();
115
+ const second = source("https://example.com/b", { contentSha256: digestB });
116
+ const hidden = { ...valid } as Record<PropertyKey, unknown>;
117
+ Object.defineProperty(hidden, "hidden", { value: true });
118
+ const symbolic = { ...valid } as Record<PropertyKey, unknown>;
119
+ symbolic[Symbol("hidden")] = true;
120
+ let accessorReads = 0;
121
+ const accessor = { ...valid } as Record<PropertyKey, unknown>;
122
+ Object.defineProperty(accessor, "title", {
123
+ enumerable: true,
124
+ get() { accessorReads += 1; return "must not execute"; },
125
+ });
126
+ const sourceAccessor = { ...source() } as Record<PropertyKey, unknown>;
127
+ Object.defineProperty(sourceAccessor, "title", {
128
+ enumerable: true,
129
+ get() { accessorReads += 1; return "must not execute"; },
130
+ });
131
+ const sourcesWithHiddenProperty = [source()] as unknown[] & Record<string, unknown>;
132
+ Object.defineProperty(sourcesWithHiddenProperty, "hidden", { value: true });
133
+ const invalid: unknown[] = [
134
+ hidden,
135
+ symbolic,
136
+ accessor,
137
+ { ...valid, provider: "hosted-embedding-provider" },
138
+ { ...valid, vector: [0, 1] },
139
+ { ...valid, title: "Cafe\u0301" },
140
+ { ...valid, title: "line one\nline two" },
141
+ { ...valid, title: "line one\u2028line two" },
142
+ { ...valid, title: "line one\u2029line two" },
143
+ { ...valid, summary: "" },
144
+ { ...valid, body: "" },
145
+ { ...valid, language: "EN-us" },
146
+ { ...valid, language: "en_US" },
147
+ { ...valid, createdAt: "2026-08-30T10:30:00Z" },
148
+ { ...valid, createdAt: "2026-08-30T11:30:00.000Z" },
149
+ { ...valid, provenance: { ...valid.provenance, attestedAt: "2026-08-30T10:59:59.999Z" } },
150
+ { ...valid, provenance: { ...valid.provenance, actorId: "model selected actor" } },
151
+ { ...valid, provenance: { ...valid.provenance, receipt: digestA } },
152
+ { ...valid, sources: [second, source()] },
153
+ { ...valid, sources: [source(), source()] },
154
+ { ...valid, sources: [source("https://user:secret@example.com/a")] },
155
+ { ...valid, sources: [source("https://example.com")] },
156
+ { ...valid, sources: [source("https://example.com/%")] },
157
+ { ...valid, sources: [source("https://example.com/%zz")] },
158
+ { ...valid, sources: [source("https://example.com/%7E")] },
159
+ { ...valid, sources: [source("https://example.com/%7e")] },
160
+ { ...valid, sources: [source("https://example.com/a", { title: "line\u2028break" })] },
161
+ { ...valid, sources: [source("https://example.com/a", { observedAt: "2026-08-30T11:00:00.001Z" })] },
162
+ { ...valid, sources: [{ ...source(), extra: true }] },
163
+ { ...valid, sources: [sourceAccessor] },
164
+ { ...valid, sources: sourcesWithHiddenProperty },
165
+ ];
166
+ invalid.forEach((candidate) => expect(parseOhMemoryPageValueV1(candidate)).toBeNull());
167
+ expect(accessorReads).toBe(0);
168
+ expect(parseOhMemoryPageValueV1({ ...valid, sources: [source(), second] })).not.toBeNull();
169
+ expect(parseOhMemoryPageValueV1({ ...valid, language: null })).not.toBeNull();
170
+ });
171
+
172
+ test("measures NFC text limits in UTF-8 bytes", () => {
173
+ const twoByte = "é";
174
+ expect(parseOhMemoryPageValueV1(page({
175
+ title: twoByte.repeat(OH_MEMORY_PAGE_LIMITS_V1.titleBytes / 2),
176
+ }))).not.toBeNull();
177
+ expect(parseOhMemoryPageValueV1(page({
178
+ title: twoByte.repeat(OH_MEMORY_PAGE_LIMITS_V1.titleBytes / 2 + 1),
179
+ }))).toBeNull();
180
+ expect(parseOhMemoryPageValueV1(page({
181
+ body: twoByte.repeat(OH_MEMORY_PAGE_LIMITS_V1.bodyBytes / 2),
182
+ }))).not.toBeNull();
183
+ expect(parseOhMemoryPageValueV1(page({
184
+ body: twoByte.repeat(OH_MEMORY_PAGE_LIMITS_V1.bodyBytes / 2 + 1),
185
+ }))).toBeNull();
186
+ const maximumLanguage = `en-${"aaaaaaaa-".repeat(27)}aaaaaaaa`;
187
+ expect(Buffer.byteLength(maximumLanguage)).toBeLessThanOrEqual(
188
+ OH_MEMORY_PAGE_LIMITS_V1.languageBytes,
189
+ );
190
+ expect(parseOhMemoryPageValueV1(page({ language: maximumLanguage }))).not.toBeNull();
191
+ expect(parseOhMemoryPageValueV1(page({ language: `${maximumLanguage}-aaaaaaaa` }))).toBeNull();
192
+ });
193
+
194
+ test("rejects oversized or noncanonical source collections before record creation", () => {
195
+ const sources = Array.from({ length: OH_MEMORY_PAGE_LIMITS_V1.sources + 1 }, (_, index) =>
196
+ source(`https://example.com/${index.toString().padStart(3, "0")}`));
197
+ expect(parseOhMemoryPageValueV1(page({ sources }))).toBeNull();
198
+ expect(() => createOhMemoryPageValueV1(page({ sources }))).toThrow("Invalid Oh memory page value");
199
+ expect(() => createOhMemoryPageRecordV1({
200
+ dependencies: [], key: "edition:bad", value: page({ sources }),
201
+ })).toThrow("Invalid Oh memory page value");
202
+ });
203
+ });
204
+
205
+ describe("canonical .oh.md interchange", () => {
206
+ test("round-trips Unicode, JSON scalar escapes, sources, and Markdown delimiters", () => {
207
+ const value = page({
208
+ body: "First paragraph.\n\n---\n\n# A heading with 🧽\n",
209
+ language: null,
210
+ sources: [
211
+ source("https://example.com/a?x=1#part"),
212
+ source("https://example.com/b", { contentSha256: digestB, title: 'A "quoted" source' }),
213
+ ],
214
+ summary: "Line one\nLine two\u2028Line three",
215
+ title: "Café memory",
216
+ });
217
+ const record = pageRecord(value, ["activity:page-attestation", "entity:source-owner"]);
218
+ const rendered = renderOhMemoryPageMarkdownV1(record);
219
+ expect(rendered.startsWith('---\nformat: "oh.memory-page.v1"\nrecord-v: 1\nrecord-kind: "edition"\n'))
220
+ .toBe(true);
221
+ expect(rendered).toContain('dependency-count: 2\ndependency-0000-key: "activity:page-attestation"');
222
+ expect(rendered).toContain('summary: "Line one\\nLine two\\u2028Line three"');
223
+ expect(rendered).toContain("source-001-content-sha256:");
224
+ expect(rendered.endsWith(value.body)).toBe(true);
225
+ expect(parseOhMemoryPageMarkdownV1(rendered)).toEqual(record);
226
+ expect(renderOhMemoryPageMarkdownV1(parseOhMemoryPageMarkdownV1(rendered) as typeof record)).toBe(rendered);
227
+ });
228
+
229
+ test("rejects YAML features and alternate spellings outside the exact scalar subset", () => {
230
+ const record = pageRecord(page(), ["activity:page-attestation", "entity:source-owner"]);
231
+ const rendered = renderOhMemoryPageMarkdownV1(record);
232
+ const hostile = [
233
+ rendered.replaceAll("\n", "\r\n"),
234
+ rendered.replace("record-v: 1", "record-v: 01"),
235
+ rendered.replace('title: "Memory page"', "title: Memory page"),
236
+ rendered.replace('title: "Memory page"', 'title: &title "Memory page"'),
237
+ rendered.replace('title: "Memory page"', 'title: "\\u004demory page"'),
238
+ rendered.replace('title: "Memory page"', 'title: "Memory page" # comment'),
239
+ rendered.replace("summary:", 'title: "duplicate"\nsummary:'),
240
+ rendered.replace("summary:", 'provider: "external"\nsummary:'),
241
+ rendered.replace("source-count: 1", "source-count: 0"),
242
+ rendered.replace("source-count: 1", `source-count: ${OH_MEMORY_PAGE_LIMITS_V1.sources + 1}`),
243
+ rendered.replace("dependency-count: 2", "dependency-count: 1"),
244
+ rendered.replace('dependency-0000-key: "activity:page-attestation"',
245
+ 'dependency-0000-key: "entity:source-owner"'),
246
+ rendered.replace('record-key: "edition:memory-page"', 'record-key: "edition:other-page"'),
247
+ rendered.replace(`record-sha256: "${record.recordSha256}"`, `record-sha256: "${digestA}"`),
248
+ rendered.replace("A durable note", "Tampered note"),
249
+ rendered.replace('title: "Memory page"\nsummary:', "summary:").replace(
250
+ 'summary: "The compact statement used for inspection and recall."',
251
+ 'summary: "The compact statement used for inspection and recall."\ntitle: "Memory page"'),
252
+ rendered.slice(4),
253
+ rendered.replace("\n---\nA durable", "\n...\nA durable"),
254
+ ];
255
+ hostile.forEach((candidate) => expect(parseOhMemoryPageMarkdownV1(candidate)).toBeNull());
256
+ });
257
+
258
+ test("rejects hostile scalar types, truncated metadata, and bounded-file attacks", () => {
259
+ const rendered = renderOhMemoryPageMarkdownV1(pageRecord());
260
+ expect(parseOhMemoryPageMarkdownV1(rendered.replace('language: "en"', "language: [en]"))).toBeNull();
261
+ expect(parseOhMemoryPageMarkdownV1(rendered.replace('language: "en"', "language: true"))).toBeNull();
262
+ expect(parseOhMemoryPageMarkdownV1(rendered.replace("source-count: 1", "source-count: 1.5"))).toBeNull();
263
+ expect(parseOhMemoryPageMarkdownV1(rendered.replace("source-000-title:", "source-001-title:"))).toBeNull();
264
+ expect(parseOhMemoryPageMarkdownV1(`---\nformat: "${OH_MEMORY_PAGE_FORMAT_V1}"\n---\nbody`)).toBeNull();
265
+ const tooManyLines = `---\n${"x: 0\n".repeat(
266
+ OH_MEMORY_PAGE_LIMITS_V1.frontmatterLines + 1,
267
+ )}---\nbody`;
268
+ expect(parseOhMemoryPageMarkdownV1(tooManyLines)).toBeNull();
269
+ expect(parseOhMemoryPageMarkdownV1("x".repeat(OH_MEMORY_PAGE_LIMITS_V1.fileBytes + 1))).toBeNull();
270
+ });
271
+ });
272
+
273
+ test("the public schema mirror is byte-identical", async () => {
274
+ const root = new URL("../spec/v1/memory-page.schema.json", import.meta.url);
275
+ const mirror = new URL("../site/public/spec/v1/memory-page.schema.json", import.meta.url);
276
+ expect(await Bun.file(root).text()).toBe(await Bun.file(mirror).text());
277
+ });