@rengler33/prov 0.1.1
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 +314 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +381 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agent.d.ts +107 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +197 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/agent.test.d.ts +5 -0
- package/dist/commands/agent.test.d.ts.map +1 -0
- package/dist/commands/agent.test.js +199 -0
- package/dist/commands/agent.test.js.map +1 -0
- package/dist/commands/constraint.d.ts +100 -0
- package/dist/commands/constraint.d.ts.map +1 -0
- package/dist/commands/constraint.js +763 -0
- package/dist/commands/constraint.js.map +1 -0
- package/dist/commands/constraint.test.d.ts +9 -0
- package/dist/commands/constraint.test.d.ts.map +1 -0
- package/dist/commands/constraint.test.js +470 -0
- package/dist/commands/constraint.test.js.map +1 -0
- package/dist/commands/graph.d.ts +99 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +552 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/graph.test.d.ts +2 -0
- package/dist/commands/graph.test.d.ts.map +1 -0
- package/dist/commands/graph.test.js +258 -0
- package/dist/commands/graph.test.js.map +1 -0
- package/dist/commands/impact.d.ts +83 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +319 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/impact.test.d.ts +2 -0
- package/dist/commands/impact.test.d.ts.map +1 -0
- package/dist/commands/impact.test.js +234 -0
- package/dist/commands/impact.test.js.map +1 -0
- package/dist/commands/init.d.ts +45 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +94 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +7 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +174 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/integration.test.d.ts +10 -0
- package/dist/commands/integration.test.d.ts.map +1 -0
- package/dist/commands/integration.test.js +456 -0
- package/dist/commands/integration.test.js.map +1 -0
- package/dist/commands/mcp.d.ts +21 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +616 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/mcp.test.d.ts +7 -0
- package/dist/commands/mcp.test.d.ts.map +1 -0
- package/dist/commands/mcp.test.js +132 -0
- package/dist/commands/mcp.test.js.map +1 -0
- package/dist/commands/plan.d.ts +218 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +1307 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/plan.test.d.ts +9 -0
- package/dist/commands/plan.test.d.ts.map +1 -0
- package/dist/commands/plan.test.js +569 -0
- package/dist/commands/plan.test.js.map +1 -0
- package/dist/commands/spec.d.ts +94 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +635 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/spec.test.d.ts +9 -0
- package/dist/commands/spec.test.d.ts.map +1 -0
- package/dist/commands/spec.test.js +407 -0
- package/dist/commands/spec.test.js.map +1 -0
- package/dist/commands/trace.d.ts +157 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +847 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/trace.test.d.ts +9 -0
- package/dist/commands/trace.test.d.ts.map +1 -0
- package/dist/commands/trace.test.js +524 -0
- package/dist/commands/trace.test.js.map +1 -0
- package/dist/graph.d.ts +204 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +496 -0
- package/dist/graph.js.map +1 -0
- package/dist/graph.test.d.ts +2 -0
- package/dist/graph.test.d.ts.map +1 -0
- package/dist/graph.test.js +382 -0
- package/dist/graph.test.js.map +1 -0
- package/dist/hash.d.ts +72 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +137 -0
- package/dist/hash.js.map +1 -0
- package/dist/hash.test.d.ts +2 -0
- package/dist/hash.test.d.ts.map +1 -0
- package/dist/hash.test.js +227 -0
- package/dist/hash.test.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +11 -0
- package/dist/index.test.js.map +1 -0
- package/dist/output.d.ts +84 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +175 -0
- package/dist/output.js.map +1 -0
- package/dist/output.test.d.ts +7 -0
- package/dist/output.test.d.ts.map +1 -0
- package/dist/output.test.js +146 -0
- package/dist/output.test.js.map +1 -0
- package/dist/staleness.d.ts +162 -0
- package/dist/staleness.d.ts.map +1 -0
- package/dist/staleness.js +309 -0
- package/dist/staleness.js.map +1 -0
- package/dist/staleness.test.d.ts +2 -0
- package/dist/staleness.test.d.ts.map +1 -0
- package/dist/staleness.test.js +448 -0
- package/dist/staleness.test.js.map +1 -0
- package/dist/storage.d.ts +267 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +623 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.test.d.ts +5 -0
- package/dist/storage.test.d.ts.map +1 -0
- package/dist/storage.test.js +434 -0
- package/dist/storage.test.js.map +1 -0
- package/dist/types.d.ts +270 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/types.test.d.ts +2 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +232 -0
- package/dist/types.test.js.map +1 -0
- package/dist/watcher.d.ts +139 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +406 -0
- package/dist/watcher.js.map +1 -0
- package/dist/watcher.test.d.ts +5 -0
- package/dist/watcher.test.d.ts.map +1 -0
- package/dist/watcher.test.js +327 -0
- package/dist/watcher.test.js.map +1 -0
- package/package.json +53 -0
package/dist/graph.d.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent Graph implementation.
|
|
3
|
+
*
|
|
4
|
+
* The intent graph is a directed acyclic graph (DAG) that connects
|
|
5
|
+
* specifications to implementations via plans and traces.
|
|
6
|
+
*
|
|
7
|
+
* @see spec:intent-graph:v1
|
|
8
|
+
*/
|
|
9
|
+
import type { EntityId, NodeType, EdgeType, GraphNode, GraphEdge, Hash, Spec, Requirement, Constraint, Invariant, Plan, Decision, Step, Trace } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Entity data that can be stored in a graph node.
|
|
12
|
+
*/
|
|
13
|
+
export type EntityData = Spec | Requirement | Constraint | Invariant | Plan | Decision | Step | Trace;
|
|
14
|
+
/**
|
|
15
|
+
* Options for graph traversal.
|
|
16
|
+
*/
|
|
17
|
+
export interface TraversalOptions {
|
|
18
|
+
/** Maximum depth to traverse (default: unlimited) */
|
|
19
|
+
readonly maxDepth?: number;
|
|
20
|
+
/** Edge types to follow (default: all) */
|
|
21
|
+
readonly edgeTypes?: readonly EdgeType[];
|
|
22
|
+
/** Include the starting node in results */
|
|
23
|
+
readonly includeStart?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result of validation check.
|
|
27
|
+
*/
|
|
28
|
+
export interface ValidationResult {
|
|
29
|
+
readonly valid: boolean;
|
|
30
|
+
readonly errors: readonly string[];
|
|
31
|
+
readonly warnings: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Intent Graph - the central data structure for provenance tracking.
|
|
35
|
+
*
|
|
36
|
+
* @see req:graph:structure
|
|
37
|
+
*/
|
|
38
|
+
export declare class IntentGraph {
|
|
39
|
+
private readonly nodes;
|
|
40
|
+
private readonly edges;
|
|
41
|
+
private readonly outgoingEdges;
|
|
42
|
+
private readonly incomingEdges;
|
|
43
|
+
/**
|
|
44
|
+
* Create a new empty intent graph.
|
|
45
|
+
*/
|
|
46
|
+
constructor();
|
|
47
|
+
/**
|
|
48
|
+
* Get the number of nodes in the graph.
|
|
49
|
+
*/
|
|
50
|
+
get nodeCount(): number;
|
|
51
|
+
/**
|
|
52
|
+
* Get the number of edges in the graph.
|
|
53
|
+
*/
|
|
54
|
+
get edgeCount(): number;
|
|
55
|
+
/**
|
|
56
|
+
* Add a node to the graph.
|
|
57
|
+
*
|
|
58
|
+
* @param id - Entity ID
|
|
59
|
+
* @param type - Node type
|
|
60
|
+
* @param data - Entity data
|
|
61
|
+
* @param hash - Optional pre-computed hash
|
|
62
|
+
*/
|
|
63
|
+
addNode(id: EntityId, type: NodeType, data: EntityData, hash?: Hash): GraphNode;
|
|
64
|
+
/**
|
|
65
|
+
* Get a node by ID.
|
|
66
|
+
*/
|
|
67
|
+
getNode(id: EntityId): GraphNode | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Check if a node exists.
|
|
70
|
+
*/
|
|
71
|
+
hasNode(id: EntityId): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Remove a node and all its edges.
|
|
74
|
+
*/
|
|
75
|
+
removeNode(id: EntityId): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get all nodes of a specific type.
|
|
78
|
+
*/
|
|
79
|
+
getNodesByType(type: NodeType): GraphNode[];
|
|
80
|
+
/**
|
|
81
|
+
* Get all nodes as an array.
|
|
82
|
+
*/
|
|
83
|
+
getAllNodes(): GraphNode[];
|
|
84
|
+
/**
|
|
85
|
+
* Add an edge to the graph.
|
|
86
|
+
*
|
|
87
|
+
* @param from - Source node ID
|
|
88
|
+
* @param to - Target node ID
|
|
89
|
+
* @param type - Edge type
|
|
90
|
+
* @returns true if edge was added, false if it already exists
|
|
91
|
+
*/
|
|
92
|
+
addEdge(from: EntityId, to: EntityId, type: EdgeType): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Remove an edge from the graph.
|
|
95
|
+
*/
|
|
96
|
+
removeEdge(from: EntityId, to: EntityId, type: EdgeType): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Get edges going out from a node.
|
|
99
|
+
*/
|
|
100
|
+
getOutgoingEdges(id: EntityId, type?: EdgeType): GraphEdge[];
|
|
101
|
+
/**
|
|
102
|
+
* Get edges coming into a node.
|
|
103
|
+
*/
|
|
104
|
+
getIncomingEdges(id: EntityId, type?: EdgeType): GraphEdge[];
|
|
105
|
+
/**
|
|
106
|
+
* Get all edges.
|
|
107
|
+
*/
|
|
108
|
+
getAllEdges(): GraphEdge[];
|
|
109
|
+
/**
|
|
110
|
+
* Traverse forward from a node (follow outgoing edges).
|
|
111
|
+
*
|
|
112
|
+
* @see req:graph:traversal-forward
|
|
113
|
+
*/
|
|
114
|
+
traverseForward(startId: EntityId, options?: TraversalOptions): EntityId[];
|
|
115
|
+
/**
|
|
116
|
+
* Traverse backward from a node (follow incoming edges).
|
|
117
|
+
*
|
|
118
|
+
* @see req:graph:traversal-backward
|
|
119
|
+
*/
|
|
120
|
+
traverseBackward(startId: EntityId, options?: TraversalOptions): EntityId[];
|
|
121
|
+
/**
|
|
122
|
+
* Internal traversal implementation using BFS.
|
|
123
|
+
*/
|
|
124
|
+
private traverse;
|
|
125
|
+
/**
|
|
126
|
+
* Get all nodes reachable from a given node (forward).
|
|
127
|
+
*
|
|
128
|
+
* @see req:graph:subgraph-extraction
|
|
129
|
+
*/
|
|
130
|
+
getReachableFrom(id: EntityId): EntityId[];
|
|
131
|
+
/**
|
|
132
|
+
* Get all nodes that can reach a given node (backward).
|
|
133
|
+
*
|
|
134
|
+
* @see req:graph:subgraph-extraction
|
|
135
|
+
*/
|
|
136
|
+
getReachableTo(id: EntityId): EntityId[];
|
|
137
|
+
/**
|
|
138
|
+
* Get the neighborhood of a node (nodes it can reach + nodes that can reach it).
|
|
139
|
+
*
|
|
140
|
+
* @see req:graph:subgraph-extraction
|
|
141
|
+
*/
|
|
142
|
+
getNeighborhood(id: EntityId): EntityId[];
|
|
143
|
+
/**
|
|
144
|
+
* Find all nodes impacted by a change to the given node.
|
|
145
|
+
*
|
|
146
|
+
* @see req:graph:impact-analysis
|
|
147
|
+
*/
|
|
148
|
+
getImpact(id: EntityId): EntityId[];
|
|
149
|
+
/**
|
|
150
|
+
* Find orphan requirements (no step traces to them).
|
|
151
|
+
*
|
|
152
|
+
* @see req:graph:orphan-detection
|
|
153
|
+
*/
|
|
154
|
+
getOrphanRequirements(): EntityId[];
|
|
155
|
+
/**
|
|
156
|
+
* Find orphan artifacts (no step implements them).
|
|
157
|
+
*
|
|
158
|
+
* @see req:graph:orphan-detection
|
|
159
|
+
*/
|
|
160
|
+
getOrphanArtifacts(): EntityId[];
|
|
161
|
+
/**
|
|
162
|
+
* Check if the graph is a valid DAG (no cycles).
|
|
163
|
+
*
|
|
164
|
+
* @see req:graph:structure
|
|
165
|
+
*/
|
|
166
|
+
isDAG(): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Validate graph consistency.
|
|
169
|
+
*
|
|
170
|
+
* @see req:graph:consistency
|
|
171
|
+
*/
|
|
172
|
+
validate(): ValidationResult;
|
|
173
|
+
/**
|
|
174
|
+
* Export graph to a plain object for serialization.
|
|
175
|
+
*/
|
|
176
|
+
toJSON(): {
|
|
177
|
+
nodes: GraphNode[];
|
|
178
|
+
edges: GraphEdge[];
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Create a graph from a plain object.
|
|
182
|
+
*/
|
|
183
|
+
static fromJSON(data: {
|
|
184
|
+
nodes: GraphNode[];
|
|
185
|
+
edges: GraphEdge[];
|
|
186
|
+
}): IntentGraph;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Add a Spec and its Requirements to the graph.
|
|
190
|
+
*/
|
|
191
|
+
export declare function addSpecToGraph(graph: IntentGraph, spec: Spec): void;
|
|
192
|
+
/**
|
|
193
|
+
* Add a Constraint and its Invariants to the graph.
|
|
194
|
+
*/
|
|
195
|
+
export declare function addConstraintToGraph(graph: IntentGraph, constraint: Constraint): void;
|
|
196
|
+
/**
|
|
197
|
+
* Add a Plan and its Decisions/Steps to the graph.
|
|
198
|
+
*/
|
|
199
|
+
export declare function addPlanToGraph(graph: IntentGraph, plan: Plan): void;
|
|
200
|
+
/**
|
|
201
|
+
* Add a Trace to the graph (linking artifact to step).
|
|
202
|
+
*/
|
|
203
|
+
export declare function addTraceToGraph(graph: IntentGraph, trace: Trace): void;
|
|
204
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/graph.js
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent Graph implementation.
|
|
3
|
+
*
|
|
4
|
+
* The intent graph is a directed acyclic graph (DAG) that connects
|
|
5
|
+
* specifications to implementations via plans and traces.
|
|
6
|
+
*
|
|
7
|
+
* @see spec:intent-graph:v1
|
|
8
|
+
*/
|
|
9
|
+
import { computeHash } from './hash.js';
|
|
10
|
+
/**
|
|
11
|
+
* Intent Graph - the central data structure for provenance tracking.
|
|
12
|
+
*
|
|
13
|
+
* @see req:graph:structure
|
|
14
|
+
*/
|
|
15
|
+
export class IntentGraph {
|
|
16
|
+
nodes = new Map();
|
|
17
|
+
edges = [];
|
|
18
|
+
outgoingEdges = new Map();
|
|
19
|
+
incomingEdges = new Map();
|
|
20
|
+
/**
|
|
21
|
+
* Create a new empty intent graph.
|
|
22
|
+
*/
|
|
23
|
+
constructor() { }
|
|
24
|
+
/**
|
|
25
|
+
* Get the number of nodes in the graph.
|
|
26
|
+
*/
|
|
27
|
+
get nodeCount() {
|
|
28
|
+
return this.nodes.size;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the number of edges in the graph.
|
|
32
|
+
*/
|
|
33
|
+
get edgeCount() {
|
|
34
|
+
return this.edges.length;
|
|
35
|
+
}
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Node Operations
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Add a node to the graph.
|
|
41
|
+
*
|
|
42
|
+
* @param id - Entity ID
|
|
43
|
+
* @param type - Node type
|
|
44
|
+
* @param data - Entity data
|
|
45
|
+
* @param hash - Optional pre-computed hash
|
|
46
|
+
*/
|
|
47
|
+
addNode(id, type, data, hash) {
|
|
48
|
+
const node = {
|
|
49
|
+
id,
|
|
50
|
+
type,
|
|
51
|
+
data,
|
|
52
|
+
hash: hash ?? computeHash(data),
|
|
53
|
+
};
|
|
54
|
+
this.nodes.set(id, node);
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get a node by ID.
|
|
59
|
+
*/
|
|
60
|
+
getNode(id) {
|
|
61
|
+
return this.nodes.get(id);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a node exists.
|
|
65
|
+
*/
|
|
66
|
+
hasNode(id) {
|
|
67
|
+
return this.nodes.has(id);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Remove a node and all its edges.
|
|
71
|
+
*/
|
|
72
|
+
removeNode(id) {
|
|
73
|
+
if (!this.nodes.has(id)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Remove all edges connected to this node
|
|
77
|
+
const outgoing = this.outgoingEdges.get(id) ?? [];
|
|
78
|
+
const incoming = this.incomingEdges.get(id) ?? [];
|
|
79
|
+
for (const edge of [...outgoing, ...incoming]) {
|
|
80
|
+
this.removeEdge(edge.from, edge.to, edge.type);
|
|
81
|
+
}
|
|
82
|
+
this.nodes.delete(id);
|
|
83
|
+
this.outgoingEdges.delete(id);
|
|
84
|
+
this.incomingEdges.delete(id);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get all nodes of a specific type.
|
|
89
|
+
*/
|
|
90
|
+
getNodesByType(type) {
|
|
91
|
+
const result = [];
|
|
92
|
+
for (const node of this.nodes.values()) {
|
|
93
|
+
if (node.type === type) {
|
|
94
|
+
result.push(node);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get all nodes as an array.
|
|
101
|
+
*/
|
|
102
|
+
getAllNodes() {
|
|
103
|
+
return Array.from(this.nodes.values());
|
|
104
|
+
}
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Edge Operations
|
|
107
|
+
// ============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* Add an edge to the graph.
|
|
110
|
+
*
|
|
111
|
+
* @param from - Source node ID
|
|
112
|
+
* @param to - Target node ID
|
|
113
|
+
* @param type - Edge type
|
|
114
|
+
* @returns true if edge was added, false if it already exists
|
|
115
|
+
*/
|
|
116
|
+
addEdge(from, to, type) {
|
|
117
|
+
// Check for duplicate
|
|
118
|
+
const existing = this.edges.find((e) => e.from === from && e.to === to && e.type === type);
|
|
119
|
+
if (existing !== undefined) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const edge = { from, to, type };
|
|
123
|
+
this.edges.push(edge);
|
|
124
|
+
// Update adjacency lists
|
|
125
|
+
if (!this.outgoingEdges.has(from)) {
|
|
126
|
+
this.outgoingEdges.set(from, []);
|
|
127
|
+
}
|
|
128
|
+
this.outgoingEdges.get(from)?.push(edge);
|
|
129
|
+
if (!this.incomingEdges.has(to)) {
|
|
130
|
+
this.incomingEdges.set(to, []);
|
|
131
|
+
}
|
|
132
|
+
this.incomingEdges.get(to)?.push(edge);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Remove an edge from the graph.
|
|
137
|
+
*/
|
|
138
|
+
removeEdge(from, to, type) {
|
|
139
|
+
const index = this.edges.findIndex((e) => e.from === from && e.to === to && e.type === type);
|
|
140
|
+
if (index === -1) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
this.edges.splice(index, 1);
|
|
144
|
+
// Update adjacency lists
|
|
145
|
+
const outgoing = this.outgoingEdges.get(from);
|
|
146
|
+
if (outgoing !== undefined) {
|
|
147
|
+
const outIndex = outgoing.findIndex((e) => e.to === to && e.type === type);
|
|
148
|
+
if (outIndex !== -1) {
|
|
149
|
+
outgoing.splice(outIndex, 1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const incoming = this.incomingEdges.get(to);
|
|
153
|
+
if (incoming !== undefined) {
|
|
154
|
+
const inIndex = incoming.findIndex((e) => e.from === from && e.type === type);
|
|
155
|
+
if (inIndex !== -1) {
|
|
156
|
+
incoming.splice(inIndex, 1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get edges going out from a node.
|
|
163
|
+
*/
|
|
164
|
+
getOutgoingEdges(id, type) {
|
|
165
|
+
const edges = this.outgoingEdges.get(id) ?? [];
|
|
166
|
+
if (type === undefined) {
|
|
167
|
+
return [...edges];
|
|
168
|
+
}
|
|
169
|
+
return edges.filter((e) => e.type === type);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get edges coming into a node.
|
|
173
|
+
*/
|
|
174
|
+
getIncomingEdges(id, type) {
|
|
175
|
+
const edges = this.incomingEdges.get(id) ?? [];
|
|
176
|
+
if (type === undefined) {
|
|
177
|
+
return [...edges];
|
|
178
|
+
}
|
|
179
|
+
return edges.filter((e) => e.type === type);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get all edges.
|
|
183
|
+
*/
|
|
184
|
+
getAllEdges() {
|
|
185
|
+
return [...this.edges];
|
|
186
|
+
}
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// Traversal Operations
|
|
189
|
+
// ============================================================================
|
|
190
|
+
/**
|
|
191
|
+
* Traverse forward from a node (follow outgoing edges).
|
|
192
|
+
*
|
|
193
|
+
* @see req:graph:traversal-forward
|
|
194
|
+
*/
|
|
195
|
+
traverseForward(startId, options = {}) {
|
|
196
|
+
return this.traverse(startId, 'forward', options);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Traverse backward from a node (follow incoming edges).
|
|
200
|
+
*
|
|
201
|
+
* @see req:graph:traversal-backward
|
|
202
|
+
*/
|
|
203
|
+
traverseBackward(startId, options = {}) {
|
|
204
|
+
return this.traverse(startId, 'backward', options);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Internal traversal implementation using BFS.
|
|
208
|
+
*/
|
|
209
|
+
traverse(startId, direction, options) {
|
|
210
|
+
const { maxDepth, edgeTypes, includeStart = false } = options;
|
|
211
|
+
const visited = new Set();
|
|
212
|
+
const result = [];
|
|
213
|
+
const queue = [
|
|
214
|
+
{ id: startId, depth: 0 },
|
|
215
|
+
];
|
|
216
|
+
while (queue.length > 0) {
|
|
217
|
+
const current = queue.shift();
|
|
218
|
+
if (current === undefined)
|
|
219
|
+
break;
|
|
220
|
+
const { id, depth } = current;
|
|
221
|
+
if (visited.has(id))
|
|
222
|
+
continue;
|
|
223
|
+
visited.add(id);
|
|
224
|
+
// Add to result (skip start if not included)
|
|
225
|
+
if (id !== startId || includeStart) {
|
|
226
|
+
result.push(id);
|
|
227
|
+
}
|
|
228
|
+
// Check depth limit
|
|
229
|
+
if (maxDepth !== undefined && depth >= maxDepth)
|
|
230
|
+
continue;
|
|
231
|
+
// Get edges based on direction
|
|
232
|
+
const edges = direction === 'forward'
|
|
233
|
+
? this.getOutgoingEdges(id)
|
|
234
|
+
: this.getIncomingEdges(id);
|
|
235
|
+
// Follow edges
|
|
236
|
+
for (const edge of edges) {
|
|
237
|
+
// Filter by edge type if specified
|
|
238
|
+
if (edgeTypes !== undefined && !edgeTypes.includes(edge.type)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const nextId = direction === 'forward' ? edge.to : edge.from;
|
|
242
|
+
if (!visited.has(nextId)) {
|
|
243
|
+
queue.push({ id: nextId, depth: depth + 1 });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get all nodes reachable from a given node (forward).
|
|
251
|
+
*
|
|
252
|
+
* @see req:graph:subgraph-extraction
|
|
253
|
+
*/
|
|
254
|
+
getReachableFrom(id) {
|
|
255
|
+
return this.traverseForward(id, { includeStart: false });
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get all nodes that can reach a given node (backward).
|
|
259
|
+
*
|
|
260
|
+
* @see req:graph:subgraph-extraction
|
|
261
|
+
*/
|
|
262
|
+
getReachableTo(id) {
|
|
263
|
+
return this.traverseBackward(id, { includeStart: false });
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get the neighborhood of a node (nodes it can reach + nodes that can reach it).
|
|
267
|
+
*
|
|
268
|
+
* @see req:graph:subgraph-extraction
|
|
269
|
+
*/
|
|
270
|
+
getNeighborhood(id) {
|
|
271
|
+
const forward = new Set(this.getReachableFrom(id));
|
|
272
|
+
const backward = new Set(this.getReachableTo(id));
|
|
273
|
+
return [...new Set([...forward, ...backward])];
|
|
274
|
+
}
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// Impact Analysis
|
|
277
|
+
// ============================================================================
|
|
278
|
+
/**
|
|
279
|
+
* Find all nodes impacted by a change to the given node.
|
|
280
|
+
*
|
|
281
|
+
* @see req:graph:impact-analysis
|
|
282
|
+
*/
|
|
283
|
+
getImpact(id) {
|
|
284
|
+
return this.traverseForward(id, { includeStart: false });
|
|
285
|
+
}
|
|
286
|
+
// ============================================================================
|
|
287
|
+
// Orphan Detection
|
|
288
|
+
// ============================================================================
|
|
289
|
+
/**
|
|
290
|
+
* Find orphan requirements (no step traces to them).
|
|
291
|
+
*
|
|
292
|
+
* @see req:graph:orphan-detection
|
|
293
|
+
*/
|
|
294
|
+
getOrphanRequirements() {
|
|
295
|
+
const orphans = [];
|
|
296
|
+
for (const node of this.getNodesByType('requirement')) {
|
|
297
|
+
const incoming = this.getIncomingEdges(node.id, 'traces_to');
|
|
298
|
+
if (incoming.length === 0) {
|
|
299
|
+
orphans.push(node.id);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return orphans;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Find orphan artifacts (no step implements them).
|
|
306
|
+
*
|
|
307
|
+
* @see req:graph:orphan-detection
|
|
308
|
+
*/
|
|
309
|
+
getOrphanArtifacts() {
|
|
310
|
+
const orphans = [];
|
|
311
|
+
for (const node of this.getNodesByType('artifact')) {
|
|
312
|
+
const incoming = this.getIncomingEdges(node.id, 'implements');
|
|
313
|
+
if (incoming.length === 0) {
|
|
314
|
+
orphans.push(node.id);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return orphans;
|
|
318
|
+
}
|
|
319
|
+
// ============================================================================
|
|
320
|
+
// Validation
|
|
321
|
+
// ============================================================================
|
|
322
|
+
/**
|
|
323
|
+
* Check if the graph is a valid DAG (no cycles).
|
|
324
|
+
*
|
|
325
|
+
* @see req:graph:structure
|
|
326
|
+
*/
|
|
327
|
+
isDAG() {
|
|
328
|
+
const visited = new Set();
|
|
329
|
+
const recursionStack = new Set();
|
|
330
|
+
const hasCycle = (id) => {
|
|
331
|
+
visited.add(id);
|
|
332
|
+
recursionStack.add(id);
|
|
333
|
+
const edges = this.getOutgoingEdges(id);
|
|
334
|
+
for (const edge of edges) {
|
|
335
|
+
if (!visited.has(edge.to)) {
|
|
336
|
+
if (hasCycle(edge.to)) {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else if (recursionStack.has(edge.to)) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
recursionStack.delete(id);
|
|
345
|
+
return false;
|
|
346
|
+
};
|
|
347
|
+
for (const id of this.nodes.keys()) {
|
|
348
|
+
if (!visited.has(id)) {
|
|
349
|
+
if (hasCycle(id)) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Validate graph consistency.
|
|
358
|
+
*
|
|
359
|
+
* @see req:graph:consistency
|
|
360
|
+
*/
|
|
361
|
+
validate() {
|
|
362
|
+
const errors = [];
|
|
363
|
+
const warnings = [];
|
|
364
|
+
// Check for cycles
|
|
365
|
+
if (!this.isDAG()) {
|
|
366
|
+
errors.push('Graph contains cycles');
|
|
367
|
+
}
|
|
368
|
+
// Check that all edge endpoints exist
|
|
369
|
+
for (const edge of this.edges) {
|
|
370
|
+
if (!this.nodes.has(edge.from)) {
|
|
371
|
+
errors.push(`Edge references non-existent source node: ${edge.from}`);
|
|
372
|
+
}
|
|
373
|
+
if (!this.nodes.has(edge.to)) {
|
|
374
|
+
errors.push(`Edge references non-existent target node: ${edge.to}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Check for orphan requirements
|
|
378
|
+
const orphanReqs = this.getOrphanRequirements();
|
|
379
|
+
for (const id of orphanReqs) {
|
|
380
|
+
warnings.push(`Orphan requirement (no implementation): ${id}`);
|
|
381
|
+
}
|
|
382
|
+
// Check for orphan artifacts
|
|
383
|
+
const orphanArtifacts = this.getOrphanArtifacts();
|
|
384
|
+
for (const id of orphanArtifacts) {
|
|
385
|
+
warnings.push(`Orphan artifact (no implementing step): ${id}`);
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
valid: errors.length === 0,
|
|
389
|
+
errors,
|
|
390
|
+
warnings,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
// ============================================================================
|
|
394
|
+
// Serialization
|
|
395
|
+
// ============================================================================
|
|
396
|
+
/**
|
|
397
|
+
* Export graph to a plain object for serialization.
|
|
398
|
+
*/
|
|
399
|
+
toJSON() {
|
|
400
|
+
return {
|
|
401
|
+
nodes: this.getAllNodes(),
|
|
402
|
+
edges: this.getAllEdges(),
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Create a graph from a plain object.
|
|
407
|
+
*/
|
|
408
|
+
static fromJSON(data) {
|
|
409
|
+
const graph = new IntentGraph();
|
|
410
|
+
for (const node of data.nodes) {
|
|
411
|
+
graph.nodes.set(node.id, node);
|
|
412
|
+
}
|
|
413
|
+
for (const edge of data.edges) {
|
|
414
|
+
graph.addEdge(edge.from, edge.to, edge.type);
|
|
415
|
+
}
|
|
416
|
+
return graph;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// ============================================================================
|
|
420
|
+
// Graph Building Helpers
|
|
421
|
+
// ============================================================================
|
|
422
|
+
/**
|
|
423
|
+
* Add a Spec and its Requirements to the graph.
|
|
424
|
+
*/
|
|
425
|
+
export function addSpecToGraph(graph, spec) {
|
|
426
|
+
// Add spec node
|
|
427
|
+
graph.addNode(spec.id, 'spec', spec, spec.hash);
|
|
428
|
+
// Add requirement nodes and edges
|
|
429
|
+
for (const req of spec.requirements) {
|
|
430
|
+
graph.addNode(req.id, 'requirement', req);
|
|
431
|
+
graph.addEdge(spec.id, req.id, 'contains');
|
|
432
|
+
// Add dependency edges
|
|
433
|
+
if (req.dependencies !== undefined) {
|
|
434
|
+
for (const depId of req.dependencies) {
|
|
435
|
+
graph.addEdge(req.id, depId, 'depends_on');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Add a Constraint and its Invariants to the graph.
|
|
442
|
+
*/
|
|
443
|
+
export function addConstraintToGraph(graph, constraint) {
|
|
444
|
+
// Add constraint node
|
|
445
|
+
graph.addNode(constraint.id, 'constraint', constraint, constraint.hash);
|
|
446
|
+
// Add invariant nodes and edges
|
|
447
|
+
for (const inv of constraint.invariants) {
|
|
448
|
+
graph.addNode(inv.id, 'invariant', inv);
|
|
449
|
+
graph.addEdge(constraint.id, inv.id, 'contains');
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Add a Plan and its Decisions/Steps to the graph.
|
|
454
|
+
*/
|
|
455
|
+
export function addPlanToGraph(graph, plan) {
|
|
456
|
+
// Add plan node
|
|
457
|
+
graph.addNode(plan.id, 'plan', plan, plan.hash);
|
|
458
|
+
// Add derives_from edges to sources
|
|
459
|
+
for (const source of plan.sources) {
|
|
460
|
+
graph.addEdge(plan.id, source.id, 'derives_from');
|
|
461
|
+
}
|
|
462
|
+
// Add decision nodes and edges
|
|
463
|
+
for (const decision of plan.decisions) {
|
|
464
|
+
graph.addNode(decision.id, 'decision', decision);
|
|
465
|
+
graph.addEdge(plan.id, decision.id, 'contains');
|
|
466
|
+
// Add traces_to edges
|
|
467
|
+
for (const targetId of decision.tracesTo) {
|
|
468
|
+
graph.addEdge(decision.id, targetId, 'traces_to');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Add step nodes and edges
|
|
472
|
+
for (const step of plan.steps) {
|
|
473
|
+
graph.addNode(step.id, 'step', step);
|
|
474
|
+
graph.addEdge(plan.id, step.id, 'contains');
|
|
475
|
+
// Add traces_to edges
|
|
476
|
+
for (const targetId of step.tracesTo) {
|
|
477
|
+
graph.addEdge(step.id, targetId, 'traces_to');
|
|
478
|
+
}
|
|
479
|
+
// Add dependency edges
|
|
480
|
+
if (step.dependencies !== undefined) {
|
|
481
|
+
for (const depId of step.dependencies) {
|
|
482
|
+
graph.addEdge(step.id, depId, 'depends_on');
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Add a Trace to the graph (linking artifact to step).
|
|
489
|
+
*/
|
|
490
|
+
export function addTraceToGraph(graph, trace) {
|
|
491
|
+
// Add trace as artifact node
|
|
492
|
+
graph.addNode(trace.id, 'artifact', trace);
|
|
493
|
+
// Add implements edge from step to artifact
|
|
494
|
+
graph.addEdge(trace.step, trace.id, 'implements');
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=graph.js.map
|