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.
- package/README.md +153 -3
- package/dist/bin/backpack-benchmark.d.ts +3 -0
- package/dist/bin/backpack-benchmark.d.ts.map +1 -0
- package/dist/bin/backpack-benchmark.js +213 -0
- package/dist/bin/backpack-benchmark.js.map +1 -0
- package/dist/bin/backpack.js +3 -3
- package/dist/bin/backpack.js.map +1 -1
- package/dist/bin/init.js +8 -11
- package/dist/bin/init.js.map +1 -1
- package/dist/core/backpack.d.ts +69 -2
- package/dist/core/backpack.d.ts.map +1 -1
- package/dist/core/backpack.js +205 -3
- package/dist/core/backpack.js.map +1 -1
- package/dist/core/draft.d.ts +42 -0
- package/dist/core/draft.d.ts.map +1 -0
- package/dist/core/draft.js +232 -0
- package/dist/core/draft.js.map +1 -0
- package/dist/core/events.d.ts +114 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +375 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/graph.d.ts +3 -1
- package/dist/core/graph.d.ts.map +1 -1
- package/dist/core/graph.js +50 -0
- package/dist/core/graph.js.map +1 -1
- package/dist/core/hooks.d.ts +11 -3
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/hooks.js +53 -47
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/normalize.d.ts +28 -0
- package/dist/core/normalize.d.ts.map +1 -0
- package/dist/core/normalize.js +133 -0
- package/dist/core/normalize.js.map +1 -0
- package/dist/core/remote-fetch.d.ts +50 -0
- package/dist/core/remote-fetch.d.ts.map +1 -0
- package/dist/core/remote-fetch.js +338 -0
- package/dist/core/remote-fetch.js.map +1 -0
- package/dist/core/remote-registry.d.ts +95 -0
- package/dist/core/remote-registry.d.ts.map +1 -0
- package/dist/core/remote-registry.js +296 -0
- package/dist/core/remote-registry.js.map +1 -0
- package/dist/core/remote-schema.d.ts +31 -0
- package/dist/core/remote-schema.d.ts.map +1 -0
- package/dist/core/remote-schema.js +252 -0
- package/dist/core/remote-schema.js.map +1 -0
- package/dist/core/role-audit.d.ts +20 -0
- package/dist/core/role-audit.d.ts.map +1 -0
- package/dist/core/role-audit.js +197 -0
- package/dist/core/role-audit.js.map +1 -0
- package/dist/core/telemetry.d.ts +2 -0
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js +16 -0
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/token-estimate.d.ts +16 -0
- package/dist/core/token-estimate.d.ts.map +1 -0
- package/dist/core/token-estimate.js +29 -0
- package/dist/core/token-estimate.js.map +1 -0
- package/dist/core/types.d.ts +30 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/bulk-tools.d.ts.map +1 -1
- package/dist/mcp/tools/bulk-tools.js +80 -12
- package/dist/mcp/tools/bulk-tools.js.map +1 -1
- package/dist/mcp/tools/edge-tools.d.ts.map +1 -1
- package/dist/mcp/tools/edge-tools.js +14 -18
- package/dist/mcp/tools/edge-tools.js.map +1 -1
- package/dist/mcp/tools/error-helpers.d.ts +16 -0
- package/dist/mcp/tools/error-helpers.d.ts.map +1 -0
- package/dist/mcp/tools/error-helpers.js +34 -0
- package/dist/mcp/tools/error-helpers.js.map +1 -0
- package/dist/mcp/tools/intelligence-tools.d.ts.map +1 -1
- package/dist/mcp/tools/intelligence-tools.js +28 -18
- package/dist/mcp/tools/intelligence-tools.js.map +1 -1
- package/dist/mcp/tools/node-tools.d.ts.map +1 -1
- package/dist/mcp/tools/node-tools.js +43 -40
- package/dist/mcp/tools/node-tools.js.map +1 -1
- package/dist/mcp/tools/ontology-tools.d.ts.map +1 -1
- package/dist/mcp/tools/ontology-tools.js +237 -12
- package/dist/mcp/tools/ontology-tools.js.map +1 -1
- package/dist/mcp/tools/remote-tools.d.ts +5 -0
- package/dist/mcp/tools/remote-tools.d.ts.map +1 -0
- package/dist/mcp/tools/remote-tools.js +295 -0
- package/dist/mcp/tools/remote-tools.js.map +1 -0
- package/dist/storage/backpack-app-backend.d.ts +1 -1
- package/dist/storage/backpack-app-backend.d.ts.map +1 -1
- package/dist/storage/backpack-app-backend.js +3 -1
- package/dist/storage/backpack-app-backend.js.map +1 -1
- package/dist/storage/event-sourced-backend.d.ts +174 -0
- package/dist/storage/event-sourced-backend.d.ts.map +1 -0
- package/dist/storage/event-sourced-backend.js +840 -0
- package/dist/storage/event-sourced-backend.js.map +1 -0
- package/dist/storage/json-file-backend.d.ts +1 -72
- package/dist/storage/json-file-backend.d.ts.map +1 -1
- package/dist/storage/json-file-backend.js +11 -549
- package/dist/storage/json-file-backend.js.map +1 -1
- package/package.json +3 -3
- package/hooks/auto-capture-prompt.md +0 -40
- package/hooks/hooks.json +0 -16
- package/hooks/suggest-viewer.sh +0 -4
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Node, Edge, LearningGraphData, LearningGraphMetadata } from "./types.js";
|
|
2
|
+
export declare const EVENT_SCHEMA_VERSION = 1;
|
|
3
|
+
export type EventOp = "node.add" | "node.update" | "node.retype" | "node.remove" | "edge.add" | "edge.remove" | "edge.retype" | "metadata.update" | "snapshot.label";
|
|
4
|
+
export interface BaseEvent {
|
|
5
|
+
/** Schema version for forward-compat checks. */
|
|
6
|
+
v: number;
|
|
7
|
+
/** ISO timestamp the event was created. */
|
|
8
|
+
ts: string;
|
|
9
|
+
/** Optional author identifier (e.g. machine ID, user email). */
|
|
10
|
+
author?: string;
|
|
11
|
+
/** Operation discriminator. */
|
|
12
|
+
op: EventOp;
|
|
13
|
+
}
|
|
14
|
+
export interface NodeAddEvent extends BaseEvent {
|
|
15
|
+
op: "node.add";
|
|
16
|
+
node: Node;
|
|
17
|
+
}
|
|
18
|
+
export interface NodeUpdateEvent extends BaseEvent {
|
|
19
|
+
op: "node.update";
|
|
20
|
+
id: string;
|
|
21
|
+
/** Properties to merge into the existing node. Pass `null` for a key to delete it. */
|
|
22
|
+
properties: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface NodeRetypeEvent extends BaseEvent {
|
|
25
|
+
op: "node.retype";
|
|
26
|
+
id: string;
|
|
27
|
+
/** New type for the node. The ID and properties are unchanged. */
|
|
28
|
+
type: string;
|
|
29
|
+
}
|
|
30
|
+
export interface NodeRemoveEvent extends BaseEvent {
|
|
31
|
+
op: "node.remove";
|
|
32
|
+
id: string;
|
|
33
|
+
}
|
|
34
|
+
export interface EdgeAddEvent extends BaseEvent {
|
|
35
|
+
op: "edge.add";
|
|
36
|
+
edge: Edge;
|
|
37
|
+
}
|
|
38
|
+
export interface EdgeRemoveEvent extends BaseEvent {
|
|
39
|
+
op: "edge.remove";
|
|
40
|
+
id: string;
|
|
41
|
+
}
|
|
42
|
+
export interface EdgeRetypeEvent extends BaseEvent {
|
|
43
|
+
op: "edge.retype";
|
|
44
|
+
id: string;
|
|
45
|
+
/** New type for the edge. The ID, endpoints, and properties are unchanged. */
|
|
46
|
+
type: string;
|
|
47
|
+
}
|
|
48
|
+
export interface MetadataUpdateEvent extends BaseEvent {
|
|
49
|
+
op: "metadata.update";
|
|
50
|
+
patch: Partial<Pick<LearningGraphMetadata, "name" | "description">>;
|
|
51
|
+
}
|
|
52
|
+
export interface SnapshotLabelEvent extends BaseEvent {
|
|
53
|
+
op: "snapshot.label";
|
|
54
|
+
/** Optional human-readable label. */
|
|
55
|
+
label?: string;
|
|
56
|
+
}
|
|
57
|
+
export type GraphEvent = NodeAddEvent | NodeUpdateEvent | NodeRetypeEvent | NodeRemoveEvent | EdgeAddEvent | EdgeRemoveEvent | EdgeRetypeEvent | MetadataUpdateEvent | SnapshotLabelEvent;
|
|
58
|
+
export declare class EventReplayError extends Error {
|
|
59
|
+
readonly eventIndex: number;
|
|
60
|
+
readonly event: GraphEvent | null;
|
|
61
|
+
constructor(message: string, eventIndex: number, event: GraphEvent | null);
|
|
62
|
+
}
|
|
63
|
+
export declare function makeNodeAddEvent(node: Node, author?: string): NodeAddEvent;
|
|
64
|
+
export declare function makeNodeUpdateEvent(id: string, properties: Record<string, unknown>, author?: string): NodeUpdateEvent;
|
|
65
|
+
export declare function makeNodeRetypeEvent(id: string, type: string, author?: string): NodeRetypeEvent;
|
|
66
|
+
export declare function makeNodeRemoveEvent(id: string, author?: string): NodeRemoveEvent;
|
|
67
|
+
export declare function makeEdgeAddEvent(edge: Edge, author?: string): EdgeAddEvent;
|
|
68
|
+
export declare function makeEdgeRemoveEvent(id: string, author?: string): EdgeRemoveEvent;
|
|
69
|
+
export declare function makeEdgeRetypeEvent(id: string, type: string, author?: string): EdgeRetypeEvent;
|
|
70
|
+
export declare function makeMetadataUpdateEvent(patch: Partial<Pick<LearningGraphMetadata, "name" | "description">>, author?: string): MetadataUpdateEvent;
|
|
71
|
+
export declare function makeSnapshotLabelEvent(label?: string, author?: string): SnapshotLabelEvent;
|
|
72
|
+
/**
|
|
73
|
+
* Apply a sequence of events on top of an existing state. Pure function:
|
|
74
|
+
* does not mutate inputs. Use this when you already have a materialized
|
|
75
|
+
* state and want to extend it with newly-appended events.
|
|
76
|
+
*/
|
|
77
|
+
export declare function applyEvents(state: LearningGraphData, events: GraphEvent[]): LearningGraphData;
|
|
78
|
+
/**
|
|
79
|
+
* Replay a sequence of events into a LearningGraphData state, starting
|
|
80
|
+
* from an empty state with the given metadata. Pure function: no IO, no
|
|
81
|
+
* mutation of inputs.
|
|
82
|
+
*
|
|
83
|
+
* Throws EventReplayError on the first invalid event. The error
|
|
84
|
+
* carries the event index so the caller can locate the problem in
|
|
85
|
+
* the source log.
|
|
86
|
+
*/
|
|
87
|
+
export declare function replay(events: GraphEvent[], initialMetadata: LearningGraphMetadata): LearningGraphData;
|
|
88
|
+
/**
|
|
89
|
+
* Compute the minimal sequence of events that would transform `before`
|
|
90
|
+
* into `after`. Used by the storage backend's `saveOntology` to support
|
|
91
|
+
* coarse-grained "save the whole graph" callers transparently.
|
|
92
|
+
*
|
|
93
|
+
* Detection rules:
|
|
94
|
+
* - Nodes present in `after` but not `before`: node.add
|
|
95
|
+
* - Nodes present in `before` but not `after`: node.remove (cascades to edges)
|
|
96
|
+
* - Nodes present in both with different properties: node.update
|
|
97
|
+
* - Edges present in `after` but not `before`: edge.add
|
|
98
|
+
* - Edges present in `before` but not `after`: edge.remove
|
|
99
|
+
* - Metadata name/description differences: metadata.update
|
|
100
|
+
*/
|
|
101
|
+
export declare function diffToEvents(before: LearningGraphData, after: LearningGraphData, author?: string): GraphEvent[];
|
|
102
|
+
/**
|
|
103
|
+
* Serialize an event to a single JSONL line (no trailing newline).
|
|
104
|
+
*/
|
|
105
|
+
export declare function serializeEvent(event: GraphEvent): string;
|
|
106
|
+
/**
|
|
107
|
+
* Parse a single JSONL line into an event. Throws on malformed input.
|
|
108
|
+
*/
|
|
109
|
+
export declare function parseEvent(line: string): GraphEvent;
|
|
110
|
+
/**
|
|
111
|
+
* Parse a full JSONL document into an array of events. Skips blank lines.
|
|
112
|
+
*/
|
|
113
|
+
export declare function parseEventLog(text: string): GraphEvent[];
|
|
114
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Event types and replay logic for event-sourced learning graphs.
|
|
3
|
+
//
|
|
4
|
+
// A graph branch is an append-only sequence of events. The current
|
|
5
|
+
// state of the branch is the result of replaying all events from the
|
|
6
|
+
// beginning. Snapshots are events with a `label` field. Rollback is
|
|
7
|
+
// truncating the event log at a snapshot's position.
|
|
8
|
+
//
|
|
9
|
+
// This module is pure: events in, state out, no IO. The storage
|
|
10
|
+
// backend handles persistence; this module handles semantics.
|
|
11
|
+
// ============================================================
|
|
12
|
+
// --- Event schema version ---
|
|
13
|
+
//
|
|
14
|
+
// Bumped when the event format changes incompatibly. The replay function
|
|
15
|
+
// rejects events with a version it doesn't know.
|
|
16
|
+
export const EVENT_SCHEMA_VERSION = 1;
|
|
17
|
+
// --- Errors ---
|
|
18
|
+
export class EventReplayError extends Error {
|
|
19
|
+
eventIndex;
|
|
20
|
+
event;
|
|
21
|
+
constructor(message, eventIndex, event) {
|
|
22
|
+
super(`event ${eventIndex}: ${message}`);
|
|
23
|
+
this.eventIndex = eventIndex;
|
|
24
|
+
this.event = event;
|
|
25
|
+
this.name = "EventReplayError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// --- Helpers ---
|
|
29
|
+
function nowISO() {
|
|
30
|
+
return new Date().toISOString();
|
|
31
|
+
}
|
|
32
|
+
export function makeNodeAddEvent(node, author) {
|
|
33
|
+
return { v: EVENT_SCHEMA_VERSION, ts: nowISO(), author, op: "node.add", node };
|
|
34
|
+
}
|
|
35
|
+
export function makeNodeUpdateEvent(id, properties, author) {
|
|
36
|
+
return {
|
|
37
|
+
v: EVENT_SCHEMA_VERSION,
|
|
38
|
+
ts: nowISO(),
|
|
39
|
+
author,
|
|
40
|
+
op: "node.update",
|
|
41
|
+
id,
|
|
42
|
+
properties,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function makeNodeRetypeEvent(id, type, author) {
|
|
46
|
+
return {
|
|
47
|
+
v: EVENT_SCHEMA_VERSION,
|
|
48
|
+
ts: nowISO(),
|
|
49
|
+
author,
|
|
50
|
+
op: "node.retype",
|
|
51
|
+
id,
|
|
52
|
+
type,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function makeNodeRemoveEvent(id, author) {
|
|
56
|
+
return { v: EVENT_SCHEMA_VERSION, ts: nowISO(), author, op: "node.remove", id };
|
|
57
|
+
}
|
|
58
|
+
export function makeEdgeAddEvent(edge, author) {
|
|
59
|
+
return { v: EVENT_SCHEMA_VERSION, ts: nowISO(), author, op: "edge.add", edge };
|
|
60
|
+
}
|
|
61
|
+
export function makeEdgeRemoveEvent(id, author) {
|
|
62
|
+
return { v: EVENT_SCHEMA_VERSION, ts: nowISO(), author, op: "edge.remove", id };
|
|
63
|
+
}
|
|
64
|
+
export function makeEdgeRetypeEvent(id, type, author) {
|
|
65
|
+
return {
|
|
66
|
+
v: EVENT_SCHEMA_VERSION,
|
|
67
|
+
ts: nowISO(),
|
|
68
|
+
author,
|
|
69
|
+
op: "edge.retype",
|
|
70
|
+
id,
|
|
71
|
+
type,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function makeMetadataUpdateEvent(patch, author) {
|
|
75
|
+
return {
|
|
76
|
+
v: EVENT_SCHEMA_VERSION,
|
|
77
|
+
ts: nowISO(),
|
|
78
|
+
author,
|
|
79
|
+
op: "metadata.update",
|
|
80
|
+
patch,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function makeSnapshotLabelEvent(label, author) {
|
|
84
|
+
return { v: EVENT_SCHEMA_VERSION, ts: nowISO(), author, op: "snapshot.label", label };
|
|
85
|
+
}
|
|
86
|
+
// --- Replay / apply ---
|
|
87
|
+
/**
|
|
88
|
+
* Apply a sequence of events on top of an existing state. Pure function:
|
|
89
|
+
* does not mutate inputs. Use this when you already have a materialized
|
|
90
|
+
* state and want to extend it with newly-appended events.
|
|
91
|
+
*/
|
|
92
|
+
export function applyEvents(state, events) {
|
|
93
|
+
return doReplay(events, state.metadata, state);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Replay a sequence of events into a LearningGraphData state, starting
|
|
97
|
+
* from an empty state with the given metadata. Pure function: no IO, no
|
|
98
|
+
* mutation of inputs.
|
|
99
|
+
*
|
|
100
|
+
* Throws EventReplayError on the first invalid event. The error
|
|
101
|
+
* carries the event index so the caller can locate the problem in
|
|
102
|
+
* the source log.
|
|
103
|
+
*/
|
|
104
|
+
export function replay(events, initialMetadata) {
|
|
105
|
+
return doReplay(events, initialMetadata, null);
|
|
106
|
+
}
|
|
107
|
+
function doReplay(events, initialMetadata, startingState) {
|
|
108
|
+
// Mutable accumulators (released as the immutable result on return)
|
|
109
|
+
const nodes = new Map();
|
|
110
|
+
const edges = new Map();
|
|
111
|
+
let metadata = { ...initialMetadata };
|
|
112
|
+
if (startingState) {
|
|
113
|
+
for (const node of startingState.nodes) {
|
|
114
|
+
nodes.set(node.id, { ...node });
|
|
115
|
+
}
|
|
116
|
+
for (const edge of startingState.edges) {
|
|
117
|
+
edges.set(edge.id, { ...edge });
|
|
118
|
+
}
|
|
119
|
+
metadata = { ...startingState.metadata };
|
|
120
|
+
}
|
|
121
|
+
for (let i = 0; i < events.length; i++) {
|
|
122
|
+
const event = events[i];
|
|
123
|
+
if (!event || typeof event !== "object") {
|
|
124
|
+
throw new EventReplayError("event is not an object", i, null);
|
|
125
|
+
}
|
|
126
|
+
if (event.v !== EVENT_SCHEMA_VERSION) {
|
|
127
|
+
throw new EventReplayError(`unknown event schema version ${event.v}`, i, event);
|
|
128
|
+
}
|
|
129
|
+
switch (event.op) {
|
|
130
|
+
case "node.add": {
|
|
131
|
+
if (nodes.has(event.node.id)) {
|
|
132
|
+
throw new EventReplayError(`node ${event.node.id} already exists`, i, event);
|
|
133
|
+
}
|
|
134
|
+
nodes.set(event.node.id, { ...event.node });
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case "node.update": {
|
|
138
|
+
const existing = nodes.get(event.id);
|
|
139
|
+
if (!existing) {
|
|
140
|
+
throw new EventReplayError(`node ${event.id} does not exist`, i, event);
|
|
141
|
+
}
|
|
142
|
+
const merged = { ...existing.properties };
|
|
143
|
+
for (const [key, value] of Object.entries(event.properties)) {
|
|
144
|
+
if (value === null) {
|
|
145
|
+
delete merged[key];
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
merged[key] = value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
nodes.set(event.id, {
|
|
152
|
+
...existing,
|
|
153
|
+
properties: merged,
|
|
154
|
+
updatedAt: event.ts,
|
|
155
|
+
});
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "node.retype": {
|
|
159
|
+
const existing = nodes.get(event.id);
|
|
160
|
+
if (!existing) {
|
|
161
|
+
throw new EventReplayError(`node ${event.id} does not exist`, i, event);
|
|
162
|
+
}
|
|
163
|
+
nodes.set(event.id, {
|
|
164
|
+
...existing,
|
|
165
|
+
type: event.type,
|
|
166
|
+
updatedAt: event.ts,
|
|
167
|
+
});
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "node.remove": {
|
|
171
|
+
if (!nodes.has(event.id)) {
|
|
172
|
+
throw new EventReplayError(`node ${event.id} does not exist`, i, event);
|
|
173
|
+
}
|
|
174
|
+
nodes.delete(event.id);
|
|
175
|
+
// Cascade delete edges that reference this node
|
|
176
|
+
for (const [edgeId, edge] of edges) {
|
|
177
|
+
if (edge.sourceId === event.id || edge.targetId === event.id) {
|
|
178
|
+
edges.delete(edgeId);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case "edge.add": {
|
|
184
|
+
if (edges.has(event.edge.id)) {
|
|
185
|
+
throw new EventReplayError(`edge ${event.edge.id} already exists`, i, event);
|
|
186
|
+
}
|
|
187
|
+
// Both endpoints must exist at the time of replay
|
|
188
|
+
if (!nodes.has(event.edge.sourceId)) {
|
|
189
|
+
throw new EventReplayError(`edge ${event.edge.id} sourceId ${event.edge.sourceId} not in graph`, i, event);
|
|
190
|
+
}
|
|
191
|
+
if (!nodes.has(event.edge.targetId)) {
|
|
192
|
+
throw new EventReplayError(`edge ${event.edge.id} targetId ${event.edge.targetId} not in graph`, i, event);
|
|
193
|
+
}
|
|
194
|
+
edges.set(event.edge.id, { ...event.edge });
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case "edge.remove": {
|
|
198
|
+
if (!edges.has(event.id)) {
|
|
199
|
+
throw new EventReplayError(`edge ${event.id} does not exist`, i, event);
|
|
200
|
+
}
|
|
201
|
+
edges.delete(event.id);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case "edge.retype": {
|
|
205
|
+
const existing = edges.get(event.id);
|
|
206
|
+
if (!existing) {
|
|
207
|
+
throw new EventReplayError(`edge ${event.id} does not exist`, i, event);
|
|
208
|
+
}
|
|
209
|
+
edges.set(event.id, {
|
|
210
|
+
...existing,
|
|
211
|
+
type: event.type,
|
|
212
|
+
updatedAt: event.ts,
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "metadata.update": {
|
|
217
|
+
metadata = {
|
|
218
|
+
...metadata,
|
|
219
|
+
...event.patch,
|
|
220
|
+
updatedAt: event.ts,
|
|
221
|
+
};
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case "snapshot.label": {
|
|
225
|
+
// Snapshots are markers in the log. They don't change state.
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
default: {
|
|
229
|
+
const exhaustive = event;
|
|
230
|
+
throw new EventReplayError(`unknown event op: ${exhaustive.op}`, i, exhaustive);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
metadata,
|
|
236
|
+
nodes: Array.from(nodes.values()),
|
|
237
|
+
edges: Array.from(edges.values()),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// --- Diff ---
|
|
241
|
+
/**
|
|
242
|
+
* Compute the minimal sequence of events that would transform `before`
|
|
243
|
+
* into `after`. Used by the storage backend's `saveOntology` to support
|
|
244
|
+
* coarse-grained "save the whole graph" callers transparently.
|
|
245
|
+
*
|
|
246
|
+
* Detection rules:
|
|
247
|
+
* - Nodes present in `after` but not `before`: node.add
|
|
248
|
+
* - Nodes present in `before` but not `after`: node.remove (cascades to edges)
|
|
249
|
+
* - Nodes present in both with different properties: node.update
|
|
250
|
+
* - Edges present in `after` but not `before`: edge.add
|
|
251
|
+
* - Edges present in `before` but not `after`: edge.remove
|
|
252
|
+
* - Metadata name/description differences: metadata.update
|
|
253
|
+
*/
|
|
254
|
+
export function diffToEvents(before, after, author) {
|
|
255
|
+
const events = [];
|
|
256
|
+
// Metadata
|
|
257
|
+
const metaPatch = {};
|
|
258
|
+
if (before.metadata.name !== after.metadata.name) {
|
|
259
|
+
metaPatch.name = after.metadata.name;
|
|
260
|
+
}
|
|
261
|
+
if (before.metadata.description !== after.metadata.description) {
|
|
262
|
+
metaPatch.description = after.metadata.description;
|
|
263
|
+
}
|
|
264
|
+
if (Object.keys(metaPatch).length > 0) {
|
|
265
|
+
events.push(makeMetadataUpdateEvent(metaPatch, author));
|
|
266
|
+
}
|
|
267
|
+
const beforeNodes = new Map(before.nodes.map((n) => [n.id, n]));
|
|
268
|
+
const afterNodes = new Map(after.nodes.map((n) => [n.id, n]));
|
|
269
|
+
const beforeEdges = new Map(before.edges.map((e) => [e.id, e]));
|
|
270
|
+
const afterEdges = new Map(after.edges.map((e) => [e.id, e]));
|
|
271
|
+
// Removed edges first (so cascade-delete from removed nodes doesn't double-emit)
|
|
272
|
+
// Removed nodes will cascade their own edges in replay; we only need explicit
|
|
273
|
+
// edge removes for edges whose endpoints are NOT being removed.
|
|
274
|
+
const removedNodeIds = new Set();
|
|
275
|
+
for (const id of beforeNodes.keys()) {
|
|
276
|
+
if (!afterNodes.has(id))
|
|
277
|
+
removedNodeIds.add(id);
|
|
278
|
+
}
|
|
279
|
+
for (const [id, edge] of beforeEdges) {
|
|
280
|
+
if (afterEdges.has(id))
|
|
281
|
+
continue;
|
|
282
|
+
// Skip edges whose endpoints are being removed — the node.remove cascade handles them
|
|
283
|
+
if (removedNodeIds.has(edge.sourceId) || removedNodeIds.has(edge.targetId)) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
events.push(makeEdgeRemoveEvent(id, author));
|
|
287
|
+
}
|
|
288
|
+
// Removed nodes
|
|
289
|
+
for (const id of removedNodeIds) {
|
|
290
|
+
events.push(makeNodeRemoveEvent(id, author));
|
|
291
|
+
}
|
|
292
|
+
// Added + updated nodes
|
|
293
|
+
for (const [id, node] of afterNodes) {
|
|
294
|
+
const prev = beforeNodes.get(id);
|
|
295
|
+
if (!prev) {
|
|
296
|
+
events.push(makeNodeAddEvent(node, author));
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
// Type change: emit retype (preserves ID + edges)
|
|
300
|
+
if (prev.type !== node.type) {
|
|
301
|
+
events.push(makeNodeRetypeEvent(id, node.type, author));
|
|
302
|
+
}
|
|
303
|
+
// Property change: emit update with the property delta
|
|
304
|
+
if (JSON.stringify(prev.properties) !== JSON.stringify(node.properties)) {
|
|
305
|
+
const patch = {};
|
|
306
|
+
for (const [k, v] of Object.entries(node.properties)) {
|
|
307
|
+
if (!Object.prototype.hasOwnProperty.call(prev.properties, k)) {
|
|
308
|
+
patch[k] = v;
|
|
309
|
+
}
|
|
310
|
+
else if (JSON.stringify(prev.properties[k]) !== JSON.stringify(v)) {
|
|
311
|
+
patch[k] = v;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
for (const k of Object.keys(prev.properties)) {
|
|
315
|
+
if (!Object.prototype.hasOwnProperty.call(node.properties, k)) {
|
|
316
|
+
patch[k] = null;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
events.push(makeNodeUpdateEvent(id, patch, author));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Added edges + edge type changes
|
|
323
|
+
for (const [id, edge] of afterEdges) {
|
|
324
|
+
const prev = beforeEdges.get(id);
|
|
325
|
+
if (!prev) {
|
|
326
|
+
events.push(makeEdgeAddEvent(edge, author));
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (prev.type !== edge.type) {
|
|
330
|
+
events.push(makeEdgeRetypeEvent(id, edge.type, author));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return events;
|
|
334
|
+
}
|
|
335
|
+
// --- Serialization ---
|
|
336
|
+
/**
|
|
337
|
+
* Serialize an event to a single JSONL line (no trailing newline).
|
|
338
|
+
*/
|
|
339
|
+
export function serializeEvent(event) {
|
|
340
|
+
return JSON.stringify(event);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Parse a single JSONL line into an event. Throws on malformed input.
|
|
344
|
+
*/
|
|
345
|
+
export function parseEvent(line) {
|
|
346
|
+
const trimmed = line.trim();
|
|
347
|
+
if (trimmed.length === 0) {
|
|
348
|
+
throw new Error("empty event line");
|
|
349
|
+
}
|
|
350
|
+
const parsed = JSON.parse(trimmed);
|
|
351
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
352
|
+
throw new Error("event must be an object");
|
|
353
|
+
}
|
|
354
|
+
return parsed;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Parse a full JSONL document into an array of events. Skips blank lines.
|
|
358
|
+
*/
|
|
359
|
+
export function parseEventLog(text) {
|
|
360
|
+
const events = [];
|
|
361
|
+
const lines = text.split("\n");
|
|
362
|
+
for (let i = 0; i < lines.length; i++) {
|
|
363
|
+
const line = lines[i];
|
|
364
|
+
if (line.trim().length === 0)
|
|
365
|
+
continue;
|
|
366
|
+
try {
|
|
367
|
+
events.push(parseEvent(line));
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
throw new Error(`parse error on line ${i + 1}: ${err.message}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return events;
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"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"}
|
package/dist/core/graph.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Node, Edge, LearningGraphData, NodeSummary, NodeTypeInfo, EdgeTypeInfo, ListNodesResult, GetNodeResult, NeighborResult, GraphStats, GraphAudit } from "./types.js";
|
|
1
|
+
import type { Node, Edge, LearningGraphData, NodeSummary, NodeTypeInfo, EdgeTypeInfo, ListNodesResult, GetNodeResult, NeighborResult, GraphStats, GraphAudit, GraphDegreeTable } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* In-memory graph operations on an LearningGraphData object.
|
|
4
4
|
* Pure logic — no I/O, no MCP, fully testable.
|
|
@@ -49,6 +49,8 @@ export declare class Graph {
|
|
|
49
49
|
getEdgeTypes(): EdgeTypeInfo[];
|
|
50
50
|
/** Compute graph statistics for diagnostics and improvement planning. */
|
|
51
51
|
getStats(): GraphStats;
|
|
52
|
+
/** Full node degree table grouped by type, sorted by connectivity ascending. */
|
|
53
|
+
getDegreeTable(): GraphDegreeTable;
|
|
52
54
|
/** Audit the graph and produce a structured improvement report. */
|
|
53
55
|
audit(): GraphAudit;
|
|
54
56
|
/** Bulk-import edges only (all nodes must already exist). Single atomic operation. */
|
package/dist/core/graph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/core/graph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,IAAI,EACJ,iBAAiB,EACjB,WAAW,EAEX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EAEb,cAAc,EACd,UAAU,EACV,UAAU,
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/core/graph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,IAAI,EACJ,iBAAiB,EACjB,WAAW,EAEX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EAEb,cAAc,EACd,UAAU,EACV,UAAU,EACV,gBAAgB,EAKjB,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AACH,qBAAa,KAAK;IACG,IAAI,EAAE,iBAAiB;gBAAvB,IAAI,EAAE,iBAAiB;IAI1C,OAAO,CAAC,GAAG;IAIX,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAOjB,wEAAwE;IACxE,OAAO,CAAC,aAAa;IAQrB,6CAA6C;IAC7C,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAchE;;;;OAIG;IACH,mBAAmB,CACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,EACnE,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,CAAC,GACD;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE;IA2C3C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIrC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAWjE,uFAAuF;IACvF,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAiB9B,6DAA6D;IAC7D,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,EAAE,MAAM,SAAI,GAAG,eAAe;IAgBjE,sEAAsE;IACtE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE;IA2BxD,qEAAqE;IACrE,YAAY,IAAI,YAAY,EAAE;IAU9B,qEAAqE;IACrE,YAAY,IAAI,YAAY,EAAE;IAU9B,yEAAyE;IACzE,QAAQ,IAAI,UAAU;IAkDtB,gFAAgF;IAChF,cAAc,IAAI,gBAAgB;IAwDlC,mEAAmE;IACnE,KAAK,IAAI,UAAU;IAyGnB,sFAAsF;IACtF,WAAW,CACT,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GACvG,MAAM,EAAE;IAiBX,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACvC,IAAI;IAoBP,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIrC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO5B,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa;IAW3C;;;OAGG;IACH,YAAY,CACV,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,GAAE,UAAU,GAAG,UAAU,GAAG,MAAe,EACpD,KAAK,SAAI,GACR,cAAc;CA8ClB"}
|
package/dist/core/graph.js
CHANGED
|
@@ -226,6 +226,56 @@ export class Graph {
|
|
|
226
226
|
.sort((a, b) => b.count - a.count),
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
|
+
/** Full node degree table grouped by type, sorted by connectivity ascending. */
|
|
230
|
+
getDegreeTable() {
|
|
231
|
+
const incoming = new Map();
|
|
232
|
+
const outgoing = new Map();
|
|
233
|
+
for (const edge of this.data.edges) {
|
|
234
|
+
outgoing.set(edge.sourceId, (outgoing.get(edge.sourceId) ?? 0) + 1);
|
|
235
|
+
incoming.set(edge.targetId, (incoming.get(edge.targetId) ?? 0) + 1);
|
|
236
|
+
}
|
|
237
|
+
const byType = new Map();
|
|
238
|
+
for (const node of this.data.nodes) {
|
|
239
|
+
const inc = incoming.get(node.id) ?? 0;
|
|
240
|
+
const out = outgoing.get(node.id) ?? 0;
|
|
241
|
+
const detail = {
|
|
242
|
+
id: node.id,
|
|
243
|
+
label: this.nodeLabel(node),
|
|
244
|
+
type: node.type,
|
|
245
|
+
incoming: inc,
|
|
246
|
+
outgoing: out,
|
|
247
|
+
total: inc + out,
|
|
248
|
+
propertyCount: Object.keys(node.properties).length,
|
|
249
|
+
};
|
|
250
|
+
const list = byType.get(node.type) ?? [];
|
|
251
|
+
list.push(detail);
|
|
252
|
+
byType.set(node.type, list);
|
|
253
|
+
}
|
|
254
|
+
const types = [];
|
|
255
|
+
for (const [type, nodes] of byType) {
|
|
256
|
+
nodes.sort((a, b) => a.total - b.total);
|
|
257
|
+
const totalConns = nodes.reduce((s, n) => s + n.total, 0);
|
|
258
|
+
const totalProps = nodes.reduce((s, n) => s + n.propertyCount, 0);
|
|
259
|
+
types.push({
|
|
260
|
+
type,
|
|
261
|
+
count: nodes.length,
|
|
262
|
+
avgConnections: Math.round((totalConns / nodes.length) * 10) / 10,
|
|
263
|
+
avgProperties: Math.round((totalProps / nodes.length) * 10) / 10,
|
|
264
|
+
nodes,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
types.sort((a, b) => a.avgConnections - b.avgConnections);
|
|
268
|
+
const totalPossible = this.data.nodes.length * (this.data.nodes.length - 1) / 2;
|
|
269
|
+
const totalConns = [...incoming.values()].reduce((a, b) => a + b, 0)
|
|
270
|
+
+ [...outgoing.values()].reduce((a, b) => a + b, 0);
|
|
271
|
+
return {
|
|
272
|
+
nodeCount: this.data.nodes.length,
|
|
273
|
+
edgeCount: this.data.edges.length,
|
|
274
|
+
density: totalPossible > 0 ? Math.round((this.data.edges.length / totalPossible) * 1000) / 1000 : 0,
|
|
275
|
+
avgConnections: this.data.nodes.length > 0 ? Math.round((totalConns / this.data.nodes.length) * 10) / 10 : 0,
|
|
276
|
+
types,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
229
279
|
/** Audit the graph and produce a structured improvement report. */
|
|
230
280
|
audit() {
|
|
231
281
|
const stats = this.getStats();
|