backpack-ontology 0.2.25 → 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 (105) hide show
  1. package/README.md +153 -3
  2. package/dist/bin/backpack-benchmark.d.ts +3 -0
  3. package/dist/bin/backpack-benchmark.d.ts.map +1 -0
  4. package/dist/bin/backpack-benchmark.js +213 -0
  5. package/dist/bin/backpack-benchmark.js.map +1 -0
  6. package/dist/bin/backpack.js +3 -3
  7. package/dist/bin/backpack.js.map +1 -1
  8. package/dist/bin/init.js +8 -11
  9. package/dist/bin/init.js.map +1 -1
  10. package/dist/core/backpack.d.ts +69 -2
  11. package/dist/core/backpack.d.ts.map +1 -1
  12. package/dist/core/backpack.js +205 -3
  13. package/dist/core/backpack.js.map +1 -1
  14. package/dist/core/draft.d.ts +42 -0
  15. package/dist/core/draft.d.ts.map +1 -0
  16. package/dist/core/draft.js +232 -0
  17. package/dist/core/draft.js.map +1 -0
  18. package/dist/core/events.d.ts +114 -0
  19. package/dist/core/events.d.ts.map +1 -0
  20. package/dist/core/events.js +375 -0
  21. package/dist/core/events.js.map +1 -0
  22. package/dist/core/graph.d.ts +3 -1
  23. package/dist/core/graph.d.ts.map +1 -1
  24. package/dist/core/graph.js +50 -0
  25. package/dist/core/graph.js.map +1 -1
  26. package/dist/core/hooks.d.ts +11 -3
  27. package/dist/core/hooks.d.ts.map +1 -1
  28. package/dist/core/hooks.js +53 -47
  29. package/dist/core/hooks.js.map +1 -1
  30. package/dist/core/normalize.d.ts +28 -0
  31. package/dist/core/normalize.d.ts.map +1 -0
  32. package/dist/core/normalize.js +133 -0
  33. package/dist/core/normalize.js.map +1 -0
  34. package/dist/core/remote-fetch.d.ts +50 -0
  35. package/dist/core/remote-fetch.d.ts.map +1 -0
  36. package/dist/core/remote-fetch.js +338 -0
  37. package/dist/core/remote-fetch.js.map +1 -0
  38. package/dist/core/remote-registry.d.ts +95 -0
  39. package/dist/core/remote-registry.d.ts.map +1 -0
  40. package/dist/core/remote-registry.js +296 -0
  41. package/dist/core/remote-registry.js.map +1 -0
  42. package/dist/core/remote-schema.d.ts +31 -0
  43. package/dist/core/remote-schema.d.ts.map +1 -0
  44. package/dist/core/remote-schema.js +252 -0
  45. package/dist/core/remote-schema.js.map +1 -0
  46. package/dist/core/role-audit.d.ts +20 -0
  47. package/dist/core/role-audit.d.ts.map +1 -0
  48. package/dist/core/role-audit.js +197 -0
  49. package/dist/core/role-audit.js.map +1 -0
  50. package/dist/core/telemetry.d.ts +2 -0
  51. package/dist/core/telemetry.d.ts.map +1 -1
  52. package/dist/core/telemetry.js +16 -0
  53. package/dist/core/telemetry.js.map +1 -1
  54. package/dist/core/token-estimate.d.ts +16 -0
  55. package/dist/core/token-estimate.d.ts.map +1 -0
  56. package/dist/core/token-estimate.js +29 -0
  57. package/dist/core/token-estimate.js.map +1 -0
  58. package/dist/core/types.d.ts +30 -1
  59. package/dist/core/types.d.ts.map +1 -1
  60. package/dist/index.d.ts +9 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +8 -1
  63. package/dist/index.js.map +1 -1
  64. package/dist/mcp/server.d.ts.map +1 -1
  65. package/dist/mcp/server.js +9 -0
  66. package/dist/mcp/server.js.map +1 -1
  67. package/dist/mcp/tools/bulk-tools.d.ts.map +1 -1
  68. package/dist/mcp/tools/bulk-tools.js +80 -12
  69. package/dist/mcp/tools/bulk-tools.js.map +1 -1
  70. package/dist/mcp/tools/edge-tools.d.ts.map +1 -1
  71. package/dist/mcp/tools/edge-tools.js +14 -18
  72. package/dist/mcp/tools/edge-tools.js.map +1 -1
  73. package/dist/mcp/tools/error-helpers.d.ts +16 -0
  74. package/dist/mcp/tools/error-helpers.d.ts.map +1 -0
  75. package/dist/mcp/tools/error-helpers.js +34 -0
  76. package/dist/mcp/tools/error-helpers.js.map +1 -0
  77. package/dist/mcp/tools/intelligence-tools.d.ts.map +1 -1
  78. package/dist/mcp/tools/intelligence-tools.js +28 -18
  79. package/dist/mcp/tools/intelligence-tools.js.map +1 -1
  80. package/dist/mcp/tools/node-tools.d.ts.map +1 -1
  81. package/dist/mcp/tools/node-tools.js +43 -40
  82. package/dist/mcp/tools/node-tools.js.map +1 -1
  83. package/dist/mcp/tools/ontology-tools.d.ts.map +1 -1
  84. package/dist/mcp/tools/ontology-tools.js +237 -12
  85. package/dist/mcp/tools/ontology-tools.js.map +1 -1
  86. package/dist/mcp/tools/remote-tools.d.ts +5 -0
  87. package/dist/mcp/tools/remote-tools.d.ts.map +1 -0
  88. package/dist/mcp/tools/remote-tools.js +295 -0
  89. package/dist/mcp/tools/remote-tools.js.map +1 -0
  90. package/dist/storage/backpack-app-backend.d.ts +1 -1
  91. package/dist/storage/backpack-app-backend.d.ts.map +1 -1
  92. package/dist/storage/backpack-app-backend.js +3 -1
  93. package/dist/storage/backpack-app-backend.js.map +1 -1
  94. package/dist/storage/event-sourced-backend.d.ts +174 -0
  95. package/dist/storage/event-sourced-backend.d.ts.map +1 -0
  96. package/dist/storage/event-sourced-backend.js +840 -0
  97. package/dist/storage/event-sourced-backend.js.map +1 -0
  98. package/dist/storage/json-file-backend.d.ts +1 -72
  99. package/dist/storage/json-file-backend.d.ts.map +1 -1
  100. package/dist/storage/json-file-backend.js +11 -549
  101. package/dist/storage/json-file-backend.js.map +1 -1
  102. package/package.json +3 -3
  103. package/hooks/auto-capture-prompt.md +0 -40
  104. package/hooks/hooks.json +0 -16
  105. package/hooks/suggest-viewer.sh +0 -4
@@ -0,0 +1,296 @@
1
+ // ============================================================
2
+ // Local registry of remote learning graphs.
3
+ //
4
+ // Stores user subscriptions to graphs hosted at HTTPS URLs.
5
+ // Persists to ~/.local/share/backpack/remotes.json.
6
+ // Caches fetched graph contents to ~/.local/share/backpack/remote-cache/<name>.json.
7
+ //
8
+ // This module owns the registry file and the cache directory. It does
9
+ // NOT fetch URLs (that's remote-fetch.ts) and does NOT validate graph
10
+ // content (that's remote-schema.ts). It glues those together and
11
+ // persists state.
12
+ // ============================================================
13
+ import * as fs from "node:fs/promises";
14
+ import * as path from "node:path";
15
+ import * as crypto from "node:crypto";
16
+ import { dataDir } from "./paths.js";
17
+ import { remoteFetch, RemoteFetchError } from "./remote-fetch.js";
18
+ import { validateRemoteGraph, RemoteSchemaError } from "./remote-schema.js";
19
+ const REGISTRY_VERSION = 1;
20
+ const NAME_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
21
+ // --- Errors ---
22
+ export class RemoteRegistryError extends Error {
23
+ code;
24
+ constructor(message, code) {
25
+ super(message);
26
+ this.code = code;
27
+ this.name = "RemoteRegistryError";
28
+ }
29
+ }
30
+ // --- Helpers ---
31
+ function emptyRegistry() {
32
+ return { version: REGISTRY_VERSION, remotes: [] };
33
+ }
34
+ function validateName(name) {
35
+ if (typeof name !== "string" || !NAME_RE.test(name)) {
36
+ throw new RemoteRegistryError(`invalid remote name '${name}': must match /^[a-z0-9][a-z0-9_-]{0,63}$/`, "INVALID_NAME");
37
+ }
38
+ }
39
+ function sha256Hex(s) {
40
+ return crypto.createHash("sha256").update(s).digest("hex");
41
+ }
42
+ // --- The registry class ---
43
+ export class RemoteRegistry {
44
+ baseDir;
45
+ constructor(baseDir) {
46
+ this.baseDir = baseDir ?? dataDir();
47
+ }
48
+ registryFile() {
49
+ return path.join(this.baseDir, "remotes.json");
50
+ }
51
+ cacheDir() {
52
+ return path.join(this.baseDir, "remote-cache");
53
+ }
54
+ cacheFile(name) {
55
+ validateName(name);
56
+ const resolved = path.resolve(this.cacheDir(), `${name}.json`);
57
+ const cacheRoot = path.resolve(this.cacheDir());
58
+ // Defense in depth: ensure the resolved path is inside the cache dir
59
+ if (!resolved.startsWith(cacheRoot + path.sep) && resolved !== cacheRoot) {
60
+ throw new RemoteRegistryError(`cache path escapes cache directory`, "PATH_TRAVERSAL");
61
+ }
62
+ return resolved;
63
+ }
64
+ /**
65
+ * Ensures the base directory and cache directory exist.
66
+ * Safe to call multiple times.
67
+ */
68
+ async initialize() {
69
+ await fs.mkdir(this.baseDir, { recursive: true });
70
+ await fs.mkdir(this.cacheDir(), { recursive: true });
71
+ }
72
+ /**
73
+ * Reads the registry file. Returns an empty registry if the file
74
+ * doesn't exist yet.
75
+ */
76
+ async load() {
77
+ try {
78
+ const text = await fs.readFile(this.registryFile(), "utf8");
79
+ const parsed = JSON.parse(text);
80
+ if (typeof parsed !== "object" ||
81
+ parsed === null ||
82
+ parsed.version !== REGISTRY_VERSION ||
83
+ !Array.isArray(parsed.remotes)) {
84
+ throw new RemoteRegistryError("registry file is malformed", "CORRUPT_REGISTRY");
85
+ }
86
+ return parsed;
87
+ }
88
+ catch (err) {
89
+ if (err.code === "ENOENT") {
90
+ return emptyRegistry();
91
+ }
92
+ throw err;
93
+ }
94
+ }
95
+ /**
96
+ * Atomically writes the registry file.
97
+ */
98
+ async save(reg) {
99
+ const tmp = `${this.registryFile()}.tmp`;
100
+ await fs.writeFile(tmp, JSON.stringify(reg, null, 2), "utf8");
101
+ await fs.rename(tmp, this.registryFile());
102
+ }
103
+ /**
104
+ * List all registered remotes.
105
+ */
106
+ async list() {
107
+ const reg = await this.load();
108
+ return reg.remotes;
109
+ }
110
+ /**
111
+ * Look up a single remote by name.
112
+ */
113
+ async get(name) {
114
+ validateName(name);
115
+ const reg = await this.load();
116
+ return reg.remotes.find((r) => r.name === name) ?? null;
117
+ }
118
+ /**
119
+ * Register a new remote: validate the name, fetch the URL, validate
120
+ * the graph schema, write to cache, and append to the registry.
121
+ *
122
+ * Throws if the name already exists, if the URL fails to fetch, or
123
+ * if the schema validation fails.
124
+ *
125
+ * The caller is responsible for ensuring the name does not collide
126
+ * with a local graph (this module doesn't know about local graphs).
127
+ */
128
+ async register(opts) {
129
+ validateName(opts.name);
130
+ await this.initialize();
131
+ const reg = await this.load();
132
+ if (reg.remotes.some((r) => r.name === opts.name)) {
133
+ throw new RemoteRegistryError(`remote '${opts.name}' is already registered`, "DUPLICATE_NAME");
134
+ }
135
+ // Fetch
136
+ let result;
137
+ try {
138
+ result = await remoteFetch(opts.url);
139
+ }
140
+ catch (err) {
141
+ if (err instanceof RemoteFetchError) {
142
+ throw new RemoteRegistryError(`fetch failed: ${err.message}`, err.code);
143
+ }
144
+ throw err;
145
+ }
146
+ // Parse + validate
147
+ let parsed;
148
+ try {
149
+ parsed = JSON.parse(result.body);
150
+ }
151
+ catch (err) {
152
+ throw new RemoteRegistryError(`response is not valid JSON: ${err.message}`, "INVALID_JSON");
153
+ }
154
+ let validated;
155
+ try {
156
+ validated = validateRemoteGraph(parsed);
157
+ }
158
+ catch (err) {
159
+ if (err instanceof RemoteSchemaError) {
160
+ throw new RemoteRegistryError(`schema validation failed: ${err.message}`, "SCHEMA_ERROR");
161
+ }
162
+ throw err;
163
+ }
164
+ // Write cache atomically
165
+ const cachePath = this.cacheFile(opts.name);
166
+ const cacheBody = JSON.stringify(validated.data);
167
+ const tmp = `${cachePath}.tmp`;
168
+ await fs.writeFile(tmp, cacheBody, "utf8");
169
+ await fs.rename(tmp, cachePath);
170
+ const now = new Date().toISOString();
171
+ const entry = {
172
+ name: opts.name,
173
+ url: opts.url,
174
+ source: opts.source,
175
+ addedAt: now,
176
+ lastFetched: now,
177
+ etag: result.etag,
178
+ sha256: sha256Hex(cacheBody),
179
+ pinned: !!opts.pin,
180
+ sizeBytes: cacheBody.length,
181
+ };
182
+ reg.remotes.push(entry);
183
+ await this.save(reg);
184
+ return entry;
185
+ }
186
+ /**
187
+ * Refetch a registered remote. Uses ETag for conditional GET.
188
+ *
189
+ * If pinned and the SHA256 changes, throws RemoteRegistryError with
190
+ * code "PIN_VIOLATION" without overwriting the cache.
191
+ */
192
+ async refresh(name) {
193
+ validateName(name);
194
+ const reg = await this.load();
195
+ const existing = reg.remotes.find((r) => r.name === name);
196
+ if (!existing) {
197
+ throw new RemoteRegistryError(`remote '${name}' is not registered`, "NOT_FOUND");
198
+ }
199
+ let result;
200
+ try {
201
+ result = await remoteFetch(existing.url, {
202
+ ifNoneMatch: existing.etag ?? undefined,
203
+ });
204
+ }
205
+ catch (err) {
206
+ if (err instanceof RemoteFetchError) {
207
+ throw new RemoteRegistryError(`fetch failed: ${err.message}`, err.code);
208
+ }
209
+ throw err;
210
+ }
211
+ if (result.notModified) {
212
+ existing.lastFetched = new Date().toISOString();
213
+ await this.save(reg);
214
+ return { entry: existing, changed: false, notModified: true };
215
+ }
216
+ let parsed;
217
+ try {
218
+ parsed = JSON.parse(result.body);
219
+ }
220
+ catch (err) {
221
+ throw new RemoteRegistryError(`response is not valid JSON: ${err.message}`, "INVALID_JSON");
222
+ }
223
+ let validated;
224
+ try {
225
+ validated = validateRemoteGraph(parsed);
226
+ }
227
+ catch (err) {
228
+ if (err instanceof RemoteSchemaError) {
229
+ throw new RemoteRegistryError(`schema validation failed: ${err.message}`, "SCHEMA_ERROR");
230
+ }
231
+ throw err;
232
+ }
233
+ const cacheBody = JSON.stringify(validated.data);
234
+ const newSha = sha256Hex(cacheBody);
235
+ const changed = newSha !== existing.sha256;
236
+ if (existing.pinned && changed) {
237
+ throw new RemoteRegistryError(`remote '${name}' is pinned and content has changed (was ${existing.sha256}, now ${newSha})`, "PIN_VIOLATION");
238
+ }
239
+ const cachePath = this.cacheFile(name);
240
+ const tmp = `${cachePath}.tmp`;
241
+ await fs.writeFile(tmp, cacheBody, "utf8");
242
+ await fs.rename(tmp, cachePath);
243
+ existing.lastFetched = new Date().toISOString();
244
+ existing.etag = result.etag;
245
+ existing.sha256 = newSha;
246
+ existing.sizeBytes = cacheBody.length;
247
+ await this.save(reg);
248
+ return { entry: existing, changed, notModified: false };
249
+ }
250
+ /**
251
+ * Remove a remote from the registry and delete its cache file.
252
+ */
253
+ async unregister(name) {
254
+ validateName(name);
255
+ const reg = await this.load();
256
+ const idx = reg.remotes.findIndex((r) => r.name === name);
257
+ if (idx === -1) {
258
+ throw new RemoteRegistryError(`remote '${name}' is not registered`, "NOT_FOUND");
259
+ }
260
+ reg.remotes.splice(idx, 1);
261
+ await this.save(reg);
262
+ // Best-effort cache deletion
263
+ try {
264
+ await fs.unlink(this.cacheFile(name));
265
+ }
266
+ catch (err) {
267
+ if (err.code !== "ENOENT") {
268
+ throw err;
269
+ }
270
+ }
271
+ }
272
+ /**
273
+ * Load the cached graph contents for a registered remote.
274
+ * Throws if the remote is not registered or the cache file is missing.
275
+ */
276
+ async loadCached(name) {
277
+ validateName(name);
278
+ const reg = await this.load();
279
+ const entry = reg.remotes.find((r) => r.name === name);
280
+ if (!entry) {
281
+ throw new RemoteRegistryError(`remote '${name}' is not registered`, "NOT_FOUND");
282
+ }
283
+ let text;
284
+ try {
285
+ text = await fs.readFile(this.cacheFile(name), "utf8");
286
+ }
287
+ catch (err) {
288
+ if (err.code === "ENOENT") {
289
+ throw new RemoteRegistryError(`cache file for '${name}' is missing — try refreshing`, "CACHE_MISSING");
290
+ }
291
+ throw err;
292
+ }
293
+ return JSON.parse(text);
294
+ }
295
+ }
296
+ //# sourceMappingURL=remote-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-registry.js","sourceRoot":"","sources":["../../src/core/remote-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { LearningGraphData } from "./types.js";
2
+ export declare const REMOTE_GRAPH_LIMITS: {
3
+ readonly maxNodes: 50000;
4
+ readonly maxEdges: 200000;
5
+ readonly maxPropertyKeys: 64;
6
+ readonly maxPropertyKeyLength: 128;
7
+ readonly maxPropertyStringLength: 16384;
8
+ readonly maxArrayLength: 256;
9
+ readonly maxIdLength: 256;
10
+ readonly maxTypeLength: 128;
11
+ readonly maxNameLength: 256;
12
+ readonly maxDescriptionLength: 4096;
13
+ };
14
+ export declare class RemoteSchemaError extends Error {
15
+ readonly path: string;
16
+ constructor(message: string, path: string);
17
+ }
18
+ /**
19
+ * Validates a parsed JSON value against the remote graph schema.
20
+ * Throws RemoteSchemaError on any violation.
21
+ *
22
+ * The returned object is a fresh, type-safe LearningGraphData. Edges
23
+ * that reference node IDs not in the graph are dropped (not an error —
24
+ * remote graphs may legitimately have hanging references after partial
25
+ * exports). Use the `droppedEdges` count from the result if you care.
26
+ */
27
+ export declare function validateRemoteGraph(raw: unknown): {
28
+ data: LearningGraphData;
29
+ droppedEdges: number;
30
+ };
31
+ //# sourceMappingURL=remote-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-schema.d.ts","sourceRoot":"","sources":["../../src/core/remote-schema.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAc,MAAM,YAAY,CAAC;AAIhE,eAAO,MAAM,mBAAmB;;;;;;;;;;;CAWtB,CAAC;AAIX,qBAAa,iBAAkB,SAAQ,KAAK;aAGxB,IAAI,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAK/B;AAwND;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG;IACjD,IAAI,EAAE,iBAAiB,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAmGA"}
@@ -0,0 +1,252 @@
1
+ // ============================================================
2
+ // Strict validation for remote learning graphs.
3
+ //
4
+ // Anything fetched from a third-party URL must pass through this
5
+ // validator before any other code touches it. The goal is to:
6
+ // 1. Reject malformed input that could crash the parser
7
+ // 2. Reject oversized graphs that could exhaust memory
8
+ // 3. Reject unknown structures that could carry future exploits
9
+ // 4. Coerce property values to a safe primitive subset
10
+ //
11
+ // This is intentionally STRICTER than the schema used for local
12
+ // graphs. Local graphs are trusted (the user wrote them); remote
13
+ // graphs are not.
14
+ // ============================================================
15
+ // --- Limits ---
16
+ export const REMOTE_GRAPH_LIMITS = {
17
+ maxNodes: 50_000,
18
+ maxEdges: 200_000,
19
+ maxPropertyKeys: 64,
20
+ maxPropertyKeyLength: 128,
21
+ maxPropertyStringLength: 16_384,
22
+ maxArrayLength: 256,
23
+ maxIdLength: 256,
24
+ maxTypeLength: 128,
25
+ maxNameLength: 256,
26
+ maxDescriptionLength: 4_096,
27
+ };
28
+ // --- Errors ---
29
+ export class RemoteSchemaError extends Error {
30
+ path;
31
+ constructor(message, path) {
32
+ super(`${path}: ${message}`);
33
+ this.path = path;
34
+ this.name = "RemoteSchemaError";
35
+ }
36
+ }
37
+ // --- Validators ---
38
+ function isPlainObject(value) {
39
+ return (typeof value === "object" &&
40
+ value !== null &&
41
+ !Array.isArray(value) &&
42
+ Object.getPrototypeOf(value) === Object.prototype);
43
+ }
44
+ function validateString(value, path, maxLength, required = true) {
45
+ if (value === undefined || value === null) {
46
+ if (required) {
47
+ throw new RemoteSchemaError("missing required string", path);
48
+ }
49
+ return "";
50
+ }
51
+ if (typeof value !== "string") {
52
+ throw new RemoteSchemaError(`expected string, got ${typeof value}`, path);
53
+ }
54
+ if (value.length > maxLength) {
55
+ throw new RemoteSchemaError(`string exceeds max length ${maxLength} (got ${value.length})`, path);
56
+ }
57
+ return value;
58
+ }
59
+ /**
60
+ * Validates a property value. Allowed: string, number (finite), boolean,
61
+ * or array of those primitives. Rejects nested objects, functions, symbols,
62
+ * bigints, and any non-finite numbers.
63
+ */
64
+ function validatePropertyValue(value, path) {
65
+ if (value === null || value === undefined) {
66
+ return value;
67
+ }
68
+ if (typeof value === "string") {
69
+ if (value.length > REMOTE_GRAPH_LIMITS.maxPropertyStringLength) {
70
+ throw new RemoteSchemaError(`property string exceeds max length ${REMOTE_GRAPH_LIMITS.maxPropertyStringLength}`, path);
71
+ }
72
+ return value;
73
+ }
74
+ if (typeof value === "number") {
75
+ if (!Number.isFinite(value)) {
76
+ throw new RemoteSchemaError("number must be finite", path);
77
+ }
78
+ return value;
79
+ }
80
+ if (typeof value === "boolean") {
81
+ return value;
82
+ }
83
+ if (Array.isArray(value)) {
84
+ if (value.length > REMOTE_GRAPH_LIMITS.maxArrayLength) {
85
+ throw new RemoteSchemaError(`array exceeds max length ${REMOTE_GRAPH_LIMITS.maxArrayLength}`, path);
86
+ }
87
+ return value.map((item, i) => {
88
+ if (item === null || item === undefined)
89
+ return item;
90
+ if (typeof item === "string") {
91
+ if (item.length > REMOTE_GRAPH_LIMITS.maxPropertyStringLength) {
92
+ throw new RemoteSchemaError(`array item string exceeds max length`, `${path}[${i}]`);
93
+ }
94
+ return item;
95
+ }
96
+ if (typeof item === "number") {
97
+ if (!Number.isFinite(item)) {
98
+ throw new RemoteSchemaError("number must be finite", `${path}[${i}]`);
99
+ }
100
+ return item;
101
+ }
102
+ if (typeof item === "boolean")
103
+ return item;
104
+ throw new RemoteSchemaError(`array items must be string, number, or boolean (got ${typeof item})`, `${path}[${i}]`);
105
+ });
106
+ }
107
+ throw new RemoteSchemaError(`properties must be string, number, boolean, null, or array of those (got ${typeof value})`, path);
108
+ }
109
+ function validateProperties(value, path) {
110
+ if (value === undefined || value === null) {
111
+ return {};
112
+ }
113
+ if (!isPlainObject(value)) {
114
+ throw new RemoteSchemaError("properties must be a plain object", path);
115
+ }
116
+ const keys = Object.keys(value);
117
+ if (keys.length > REMOTE_GRAPH_LIMITS.maxPropertyKeys) {
118
+ throw new RemoteSchemaError(`too many property keys (max ${REMOTE_GRAPH_LIMITS.maxPropertyKeys})`, path);
119
+ }
120
+ const out = {};
121
+ for (const key of keys) {
122
+ if (key.length > REMOTE_GRAPH_LIMITS.maxPropertyKeyLength) {
123
+ throw new RemoteSchemaError(`property key exceeds max length`, `${path}.${key.slice(0, 32)}...`);
124
+ }
125
+ // Reject prototype-pollution attempts
126
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
127
+ throw new RemoteSchemaError(`property key '${key}' is not allowed`, path);
128
+ }
129
+ out[key] = validatePropertyValue(value[key], `${path}.${key}`);
130
+ }
131
+ return out;
132
+ }
133
+ function validateNode(raw, index) {
134
+ const path = `nodes[${index}]`;
135
+ if (!isPlainObject(raw)) {
136
+ throw new RemoteSchemaError("node must be a plain object", path);
137
+ }
138
+ const id = validateString(raw.id, `${path}.id`, REMOTE_GRAPH_LIMITS.maxIdLength);
139
+ const type = validateString(raw.type, `${path}.type`, REMOTE_GRAPH_LIMITS.maxTypeLength);
140
+ const properties = validateProperties(raw.properties, `${path}.properties`);
141
+ const createdAt = validateString(raw.createdAt, `${path}.createdAt`, 64, false);
142
+ const updatedAt = validateString(raw.updatedAt, `${path}.updatedAt`, 64, false);
143
+ return {
144
+ id,
145
+ type,
146
+ properties,
147
+ createdAt: createdAt || new Date().toISOString(),
148
+ updatedAt: updatedAt || new Date().toISOString(),
149
+ };
150
+ }
151
+ function validateEdge(raw, index) {
152
+ const path = `edges[${index}]`;
153
+ if (!isPlainObject(raw)) {
154
+ throw new RemoteSchemaError("edge must be a plain object", path);
155
+ }
156
+ const id = validateString(raw.id, `${path}.id`, REMOTE_GRAPH_LIMITS.maxIdLength);
157
+ const type = validateString(raw.type, `${path}.type`, REMOTE_GRAPH_LIMITS.maxTypeLength);
158
+ const sourceId = validateString(raw.sourceId, `${path}.sourceId`, REMOTE_GRAPH_LIMITS.maxIdLength);
159
+ const targetId = validateString(raw.targetId, `${path}.targetId`, REMOTE_GRAPH_LIMITS.maxIdLength);
160
+ const properties = validateProperties(raw.properties, `${path}.properties`);
161
+ const createdAt = validateString(raw.createdAt, `${path}.createdAt`, 64, false);
162
+ const updatedAt = validateString(raw.updatedAt, `${path}.updatedAt`, 64, false);
163
+ return {
164
+ id,
165
+ type,
166
+ sourceId,
167
+ targetId,
168
+ properties,
169
+ createdAt: createdAt || new Date().toISOString(),
170
+ updatedAt: updatedAt || new Date().toISOString(),
171
+ };
172
+ }
173
+ /**
174
+ * Validates a parsed JSON value against the remote graph schema.
175
+ * Throws RemoteSchemaError on any violation.
176
+ *
177
+ * The returned object is a fresh, type-safe LearningGraphData. Edges
178
+ * that reference node IDs not in the graph are dropped (not an error —
179
+ * remote graphs may legitimately have hanging references after partial
180
+ * exports). Use the `droppedEdges` count from the result if you care.
181
+ */
182
+ export function validateRemoteGraph(raw) {
183
+ if (!isPlainObject(raw)) {
184
+ throw new RemoteSchemaError("root must be a plain object", "$");
185
+ }
186
+ // Allowed top-level keys only
187
+ const allowedKeys = new Set(["metadata", "nodes", "edges"]);
188
+ for (const key of Object.keys(raw)) {
189
+ if (!allowedKeys.has(key)) {
190
+ throw new RemoteSchemaError(`unknown top-level key '${key}'`, "$");
191
+ }
192
+ }
193
+ // metadata
194
+ if (!isPlainObject(raw.metadata)) {
195
+ throw new RemoteSchemaError("metadata must be a plain object", "metadata");
196
+ }
197
+ const metaName = validateString(raw.metadata.name, "metadata.name", REMOTE_GRAPH_LIMITS.maxNameLength);
198
+ const metaDescription = validateString(raw.metadata.description, "metadata.description", REMOTE_GRAPH_LIMITS.maxDescriptionLength, false);
199
+ const metaCreatedAt = validateString(raw.metadata.createdAt, "metadata.createdAt", 64, false);
200
+ const metaUpdatedAt = validateString(raw.metadata.updatedAt, "metadata.updatedAt", 64, false);
201
+ // nodes
202
+ if (!Array.isArray(raw.nodes)) {
203
+ throw new RemoteSchemaError("nodes must be an array", "nodes");
204
+ }
205
+ if (raw.nodes.length > REMOTE_GRAPH_LIMITS.maxNodes) {
206
+ throw new RemoteSchemaError(`node count ${raw.nodes.length} exceeds max ${REMOTE_GRAPH_LIMITS.maxNodes}`, "nodes");
207
+ }
208
+ const nodes = [];
209
+ const nodeIds = new Set();
210
+ for (let i = 0; i < raw.nodes.length; i++) {
211
+ const node = validateNode(raw.nodes[i], i);
212
+ if (nodeIds.has(node.id)) {
213
+ throw new RemoteSchemaError(`duplicate node id '${node.id}'`, `nodes[${i}]`);
214
+ }
215
+ nodeIds.add(node.id);
216
+ nodes.push(node);
217
+ }
218
+ // edges
219
+ if (!Array.isArray(raw.edges)) {
220
+ throw new RemoteSchemaError("edges must be an array", "edges");
221
+ }
222
+ if (raw.edges.length > REMOTE_GRAPH_LIMITS.maxEdges) {
223
+ throw new RemoteSchemaError(`edge count ${raw.edges.length} exceeds max ${REMOTE_GRAPH_LIMITS.maxEdges}`, "edges");
224
+ }
225
+ const edges = [];
226
+ let droppedEdges = 0;
227
+ for (let i = 0; i < raw.edges.length; i++) {
228
+ const edge = validateEdge(raw.edges[i], i);
229
+ // Drop edges that reference nodes outside this graph — these are
230
+ // legitimate orphans, not malicious, but they break traversal
231
+ if (!nodeIds.has(edge.sourceId) || !nodeIds.has(edge.targetId)) {
232
+ droppedEdges++;
233
+ continue;
234
+ }
235
+ edges.push(edge);
236
+ }
237
+ const now = new Date().toISOString();
238
+ return {
239
+ data: {
240
+ metadata: {
241
+ name: metaName,
242
+ description: metaDescription,
243
+ createdAt: metaCreatedAt || now,
244
+ updatedAt: metaUpdatedAt || now,
245
+ },
246
+ nodes,
247
+ edges,
248
+ },
249
+ droppedEdges,
250
+ };
251
+ }
252
+ //# sourceMappingURL=remote-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-schema.js","sourceRoot":"","sources":["../../src/core/remote-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Node } from "./types.js";
2
+ export interface RoleAuditCandidate {
3
+ nodeId: string;
4
+ type: string;
5
+ label: string;
6
+ reason: string;
7
+ suggestion: string;
8
+ }
9
+ export interface RoleAuditResult {
10
+ proceduralCandidates: RoleAuditCandidate[];
11
+ briefingCandidates: RoleAuditCandidate[];
12
+ summary: {
13
+ nodesScanned: number;
14
+ proceduralCount: number;
15
+ briefingCount: number;
16
+ cleanCount: number;
17
+ };
18
+ }
19
+ export declare function auditRoles(nodes: Node[]): RoleAuditResult;
20
+ //# sourceMappingURL=role-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-audit.d.ts","sourceRoot":"","sources":["../../src/core/role-audit.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,oBAAoB,EAAE,kBAAkB,EAAE,CAAC;IAC3C,kBAAkB,EAAE,kBAAkB,EAAE,CAAC;IACzC,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AA6KD,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,eAAe,CAwCzD"}