octie-cli 1.0.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 (162) hide show
  1. package/README.md +523 -0
  2. package/dist/cli/commands/approve.d.ts +27 -0
  3. package/dist/cli/commands/approve.d.ts.map +1 -0
  4. package/dist/cli/commands/approve.js +119 -0
  5. package/dist/cli/commands/approve.js.map +1 -0
  6. package/dist/cli/commands/batch.d.ts +15 -0
  7. package/dist/cli/commands/batch.d.ts.map +1 -0
  8. package/dist/cli/commands/batch.js +521 -0
  9. package/dist/cli/commands/batch.js.map +1 -0
  10. package/dist/cli/commands/create.d.ts +9 -0
  11. package/dist/cli/commands/create.d.ts.map +1 -0
  12. package/dist/cli/commands/create.js +321 -0
  13. package/dist/cli/commands/create.js.map +1 -0
  14. package/dist/cli/commands/delete.d.ts +9 -0
  15. package/dist/cli/commands/delete.d.ts.map +1 -0
  16. package/dist/cli/commands/delete.js +143 -0
  17. package/dist/cli/commands/delete.js.map +1 -0
  18. package/dist/cli/commands/export.d.ts +9 -0
  19. package/dist/cli/commands/export.d.ts.map +1 -0
  20. package/dist/cli/commands/export.js +66 -0
  21. package/dist/cli/commands/export.js.map +1 -0
  22. package/dist/cli/commands/find.d.ts +16 -0
  23. package/dist/cli/commands/find.d.ts.map +1 -0
  24. package/dist/cli/commands/find.js +252 -0
  25. package/dist/cli/commands/find.js.map +1 -0
  26. package/dist/cli/commands/get.d.ts +9 -0
  27. package/dist/cli/commands/get.d.ts.map +1 -0
  28. package/dist/cli/commands/get.js +74 -0
  29. package/dist/cli/commands/get.js.map +1 -0
  30. package/dist/cli/commands/graph.d.ts +9 -0
  31. package/dist/cli/commands/graph.d.ts.map +1 -0
  32. package/dist/cli/commands/graph.js +200 -0
  33. package/dist/cli/commands/graph.js.map +1 -0
  34. package/dist/cli/commands/import.d.ts +9 -0
  35. package/dist/cli/commands/import.d.ts.map +1 -0
  36. package/dist/cli/commands/import.js +807 -0
  37. package/dist/cli/commands/import.js.map +1 -0
  38. package/dist/cli/commands/init.d.ts +9 -0
  39. package/dist/cli/commands/init.d.ts.map +1 -0
  40. package/dist/cli/commands/init.js +57 -0
  41. package/dist/cli/commands/init.js.map +1 -0
  42. package/dist/cli/commands/list.d.ts +9 -0
  43. package/dist/cli/commands/list.d.ts.map +1 -0
  44. package/dist/cli/commands/list.js +175 -0
  45. package/dist/cli/commands/list.js.map +1 -0
  46. package/dist/cli/commands/merge.d.ts +9 -0
  47. package/dist/cli/commands/merge.d.ts.map +1 -0
  48. package/dist/cli/commands/merge.js +113 -0
  49. package/dist/cli/commands/merge.js.map +1 -0
  50. package/dist/cli/commands/serve.d.ts +9 -0
  51. package/dist/cli/commands/serve.d.ts.map +1 -0
  52. package/dist/cli/commands/serve.js +94 -0
  53. package/dist/cli/commands/serve.js.map +1 -0
  54. package/dist/cli/commands/update.d.ts +9 -0
  55. package/dist/cli/commands/update.d.ts.map +1 -0
  56. package/dist/cli/commands/update.js +423 -0
  57. package/dist/cli/commands/update.js.map +1 -0
  58. package/dist/cli/commands/wire.d.ts +15 -0
  59. package/dist/cli/commands/wire.d.ts.map +1 -0
  60. package/dist/cli/commands/wire.js +164 -0
  61. package/dist/cli/commands/wire.js.map +1 -0
  62. package/dist/cli/index.d.ts +7 -0
  63. package/dist/cli/index.d.ts.map +1 -0
  64. package/dist/cli/index.js +100 -0
  65. package/dist/cli/index.js.map +1 -0
  66. package/dist/cli/output/json.d.ts +16 -0
  67. package/dist/cli/output/json.d.ts.map +1 -0
  68. package/dist/cli/output/json.js +29 -0
  69. package/dist/cli/output/json.js.map +1 -0
  70. package/dist/cli/output/markdown.d.ts +15 -0
  71. package/dist/cli/output/markdown.d.ts.map +1 -0
  72. package/dist/cli/output/markdown.js +206 -0
  73. package/dist/cli/output/markdown.js.map +1 -0
  74. package/dist/cli/output/table.d.ts +23 -0
  75. package/dist/cli/output/table.d.ts.map +1 -0
  76. package/dist/cli/output/table.js +150 -0
  77. package/dist/cli/output/table.js.map +1 -0
  78. package/dist/cli/utils/helpers.d.ts +126 -0
  79. package/dist/cli/utils/helpers.d.ts.map +1 -0
  80. package/dist/cli/utils/helpers.js +325 -0
  81. package/dist/cli/utils/helpers.js.map +1 -0
  82. package/dist/core/graph/algorithms.d.ts +11 -0
  83. package/dist/core/graph/algorithms.d.ts.map +1 -0
  84. package/dist/core/graph/algorithms.js +14 -0
  85. package/dist/core/graph/algorithms.js.map +1 -0
  86. package/dist/core/graph/cycle.d.ts +155 -0
  87. package/dist/core/graph/cycle.d.ts.map +1 -0
  88. package/dist/core/graph/cycle.js +297 -0
  89. package/dist/core/graph/cycle.js.map +1 -0
  90. package/dist/core/graph/index.d.ts +223 -0
  91. package/dist/core/graph/index.d.ts.map +1 -0
  92. package/dist/core/graph/index.js +475 -0
  93. package/dist/core/graph/index.js.map +1 -0
  94. package/dist/core/graph/operations.d.ts +240 -0
  95. package/dist/core/graph/operations.d.ts.map +1 -0
  96. package/dist/core/graph/operations.js +503 -0
  97. package/dist/core/graph/operations.js.map +1 -0
  98. package/dist/core/graph/sort.d.ts +76 -0
  99. package/dist/core/graph/sort.d.ts.map +1 -0
  100. package/dist/core/graph/sort.js +254 -0
  101. package/dist/core/graph/sort.js.map +1 -0
  102. package/dist/core/graph/traversal.d.ts +122 -0
  103. package/dist/core/graph/traversal.d.ts.map +1 -0
  104. package/dist/core/graph/traversal.js +336 -0
  105. package/dist/core/graph/traversal.js.map +1 -0
  106. package/dist/core/models/task-node.d.ts +328 -0
  107. package/dist/core/models/task-node.d.ts.map +1 -0
  108. package/dist/core/models/task-node.js +1090 -0
  109. package/dist/core/models/task-node.js.map +1 -0
  110. package/dist/core/registry/index.d.ts +102 -0
  111. package/dist/core/registry/index.d.ts.map +1 -0
  112. package/dist/core/registry/index.js +249 -0
  113. package/dist/core/registry/index.js.map +1 -0
  114. package/dist/core/registry/root-guard.d.ts +19 -0
  115. package/dist/core/registry/root-guard.d.ts.map +1 -0
  116. package/dist/core/registry/root-guard.js +28 -0
  117. package/dist/core/registry/root-guard.js.map +1 -0
  118. package/dist/core/storage/atomic-write.d.ts +181 -0
  119. package/dist/core/storage/atomic-write.d.ts.map +1 -0
  120. package/dist/core/storage/atomic-write.js +379 -0
  121. package/dist/core/storage/atomic-write.js.map +1 -0
  122. package/dist/core/storage/file-store.d.ts +148 -0
  123. package/dist/core/storage/file-store.d.ts.map +1 -0
  124. package/dist/core/storage/file-store.js +423 -0
  125. package/dist/core/storage/file-store.js.map +1 -0
  126. package/dist/core/storage/indexer.d.ts +138 -0
  127. package/dist/core/storage/indexer.d.ts.map +1 -0
  128. package/dist/core/storage/indexer.js +350 -0
  129. package/dist/core/storage/indexer.js.map +1 -0
  130. package/dist/core/utils/status-helpers.d.ts +59 -0
  131. package/dist/core/utils/status-helpers.d.ts.map +1 -0
  132. package/dist/core/utils/status-helpers.js +149 -0
  133. package/dist/core/utils/status-helpers.js.map +1 -0
  134. package/dist/index.d.ts +10 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +10 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/types/index.d.ts +504 -0
  139. package/dist/types/index.d.ts.map +1 -0
  140. package/dist/types/index.js +182 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/web/routes/graph.d.ts +17 -0
  143. package/dist/web/routes/graph.d.ts.map +1 -0
  144. package/dist/web/routes/graph.js +277 -0
  145. package/dist/web/routes/graph.js.map +1 -0
  146. package/dist/web/routes/projects.d.ts +14 -0
  147. package/dist/web/routes/projects.d.ts.map +1 -0
  148. package/dist/web/routes/projects.js +102 -0
  149. package/dist/web/routes/projects.js.map +1 -0
  150. package/dist/web/routes/tasks.d.ts +17 -0
  151. package/dist/web/routes/tasks.d.ts.map +1 -0
  152. package/dist/web/routes/tasks.js +538 -0
  153. package/dist/web/routes/tasks.js.map +1 -0
  154. package/dist/web/server.d.ts +121 -0
  155. package/dist/web/server.d.ts.map +1 -0
  156. package/dist/web/server.js +389 -0
  157. package/dist/web/server.js.map +1 -0
  158. package/dist/web-ui/assets/index-BB0qvF1y.css +1 -0
  159. package/dist/web-ui/assets/index-Vmm72oKY.js +34 -0
  160. package/dist/web-ui/index.html +14 -0
  161. package/dist/web-ui/vite.svg +1 -0
  162. package/package.json +94 -0
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Graph cycle detection algorithms
3
+ *
4
+ * Implements DFS-based cycle detection with three-color marking.
5
+ * Detects all cycles and returns cycle paths for debugging.
6
+ * Time complexity: O(V + E) where V = vertices, E = edges
7
+ *
8
+ * @module core/graph/cycle
9
+ */
10
+ import { CircularDependencyError } from '../../types/index.js';
11
+ /** Node visitation states for DFS cycle detection */
12
+ var VisitState;
13
+ (function (VisitState) {
14
+ /** Node has not been visited */
15
+ VisitState[VisitState["WHITE"] = 0] = "WHITE";
16
+ /** Node is currently being visited (in recursion stack) */
17
+ VisitState[VisitState["GRAY"] = 1] = "GRAY";
18
+ /** Node and all descendants have been completely visited */
19
+ VisitState[VisitState["BLACK"] = 2] = "BLACK";
20
+ })(VisitState || (VisitState = {}));
21
+ /**
22
+ * Detect cycles using DFS with three-color marking
23
+ *
24
+ * Algorithm:
25
+ * 1. Mark all nodes as WHITE (unvisited)
26
+ * 2. For each WHITE node, start DFS traversal
27
+ * 3. Mark node as GRAY when entering, BLACK when exiting
28
+ * 4. If we encounter a GRAY node during traversal, we found a cycle
29
+ * 5. Check for self-loops (task blocking itself) before DFS
30
+ * 6. Reconstruct cycle path using parent pointers
31
+ *
32
+ * Time Complexity: O(V + E)
33
+ * Space Complexity: O(V) for recursion stack and state tracking
34
+ *
35
+ * @param graph - Task graph store
36
+ * @returns Cycle detection result with all detected cycles
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const result = detectCycle(graph);
41
+ * if (result.hasCycle) {
42
+ * console.error('Found cycles:', result.cycles);
43
+ * for (const cycle of result.cycles) {
44
+ * console.error('Cycle:', cycle.join(' -> '));
45
+ * }
46
+ * }
47
+ * ```
48
+ */
49
+ export function detectCycle(graph) {
50
+ const cycles = [];
51
+ const color = new Map();
52
+ const parent = new Map();
53
+ // Initialize all nodes as WHITE
54
+ for (const taskId of graph.getAllTaskIds()) {
55
+ color.set(taskId, VisitState.WHITE);
56
+ parent.set(taskId, null);
57
+ }
58
+ /**
59
+ * DFS traversal to detect cycles
60
+ * @param nodeId - Current node being visited
61
+ * @returns true if a cycle was found (can continue to find more)
62
+ */
63
+ function dfs(nodeId) {
64
+ // Mark current node as being visited
65
+ color.set(nodeId, VisitState.GRAY);
66
+ // Check for self-loop (task blocks itself)
67
+ const task = graph.getNode(nodeId);
68
+ if (task && task.blockers.includes(nodeId)) {
69
+ cycles.push([nodeId, nodeId]); // Self-loop: A -> A
70
+ // Continue to find more cycles, don't return yet
71
+ }
72
+ // Visit all neighbors
73
+ const neighbors = graph.getOutgoingEdges(nodeId);
74
+ for (const neighbor of neighbors) {
75
+ const neighborState = color.get(neighbor) ?? VisitState.WHITE;
76
+ if (neighborState === VisitState.GRAY) {
77
+ // Found a cycle - reconstruct the path
78
+ const cycle = [neighbor];
79
+ // Backtrack from current node to the neighbor
80
+ let current = nodeId;
81
+ while (current && current !== neighbor) {
82
+ cycle.unshift(current);
83
+ current = parent.get(current) || null;
84
+ }
85
+ // Add neighbor at start to complete the cycle
86
+ cycle.unshift(neighbor);
87
+ cycles.push(cycle);
88
+ return true; // Continue to find more cycles
89
+ }
90
+ if (neighborState === VisitState.WHITE) {
91
+ // Set parent and continue DFS
92
+ parent.set(neighbor, nodeId);
93
+ if (dfs(neighbor)) {
94
+ return true; // Continue searching
95
+ }
96
+ }
97
+ // BLACK nodes are already processed, skip them
98
+ }
99
+ // Mark node as completely visited
100
+ color.set(nodeId, VisitState.BLACK);
101
+ return false;
102
+ }
103
+ // Start DFS from all unvisited nodes
104
+ for (const taskId of graph.getAllTaskIds()) {
105
+ if ((color.get(taskId) ?? VisitState.WHITE) === VisitState.WHITE) {
106
+ dfs(taskId);
107
+ }
108
+ }
109
+ return {
110
+ hasCycle: cycles.length > 0,
111
+ cycles,
112
+ };
113
+ }
114
+ /**
115
+ * Check if a graph contains any cycles
116
+ * Convenience function that returns a boolean
117
+ *
118
+ * @param graph - Task graph store
119
+ * @returns true if graph contains at least one cycle
120
+ */
121
+ export function hasCycle(graph) {
122
+ const result = detectCycle(graph);
123
+ return result.hasCycle;
124
+ }
125
+ /**
126
+ * Get all nodes involved in cycles
127
+ *
128
+ * @param graph - Task graph store
129
+ * @returns Set of task IDs that are part of at least one cycle
130
+ */
131
+ export function getCyclicNodes(graph) {
132
+ const result = detectCycle(graph);
133
+ const cyclicNodes = new Set();
134
+ for (const cycle of result.cycles) {
135
+ for (const nodeId of cycle) {
136
+ cyclicNodes.add(nodeId);
137
+ }
138
+ }
139
+ return cyclicNodes;
140
+ }
141
+ /**
142
+ * Find the shortest cycle in the graph
143
+ * Useful for identifying the most critical circular dependency
144
+ *
145
+ * @param graph - Task graph store
146
+ * @returns Shortest cycle array, or empty array if no cycles
147
+ */
148
+ export function findShortestCycle(graph) {
149
+ const result = detectCycle(graph);
150
+ if (result.cycles.length === 0) {
151
+ return [];
152
+ }
153
+ return result.cycles.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
154
+ }
155
+ /**
156
+ * Find all cycles involving a specific task
157
+ *
158
+ * @param graph - Task graph store
159
+ * @param taskId - Task ID to find cycles for
160
+ * @returns Array of cycles that include the specified task
161
+ */
162
+ export function findCyclesForTask(graph, taskId) {
163
+ const result = detectCycle(graph);
164
+ return result.cycles.filter(cycle => cycle.includes(taskId));
165
+ }
166
+ /**
167
+ * Validate that a graph is acyclic (DAG)
168
+ * Throws an error if cycles are detected
169
+ *
170
+ * @param graph - Task graph store
171
+ * @throws {CircularDependencyError} If graph contains cycles
172
+ */
173
+ export function validateAcyclic(graph) {
174
+ const result = detectCycle(graph);
175
+ if (result.hasCycle) {
176
+ // Use the first cycle found for the error
177
+ const firstCycle = result.cycles[0];
178
+ if (firstCycle) {
179
+ throw new CircularDependencyError(firstCycle);
180
+ }
181
+ }
182
+ }
183
+ /**
184
+ * Get cycle statistics
185
+ *
186
+ * @param graph - Task graph store
187
+ * @returns Object with cycle count and nodes in cycles
188
+ */
189
+ export function getCycleStatistics(graph) {
190
+ const result = detectCycle(graph);
191
+ const cyclicNodes = getCyclicNodes(graph);
192
+ const cyclesByLength = {};
193
+ for (const cycle of result.cycles) {
194
+ const len = cycle.length;
195
+ cyclesByLength[len] = (cyclesByLength[len] || 0) + 1;
196
+ }
197
+ return {
198
+ cycleCount: result.cycles.length,
199
+ nodesInCycles: cyclicNodes.size,
200
+ totalNodes: graph.size,
201
+ cyclesByLength,
202
+ };
203
+ }
204
+ /**
205
+ * Validate that all blocker references point to existing tasks
206
+ *
207
+ * Checks each task's blockers array to ensure all referenced tasks exist.
208
+ * This catches orphaned references that could occur from:
209
+ * - Manual JSON editing
210
+ * - Bugs in edge manipulation
211
+ * - Incomplete graph operations
212
+ *
213
+ * @param graph - Task graph store
214
+ * @returns Validation result with any invalid references found
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * const result = validateReferences(graph);
219
+ * if (result.hasInvalidReferences) {
220
+ * for (const ref of result.invalidReferences) {
221
+ * console.error(`Task ${ref.taskId} has missing blocker: ${ref.invalidBlockerId}`);
222
+ * }
223
+ * }
224
+ * ```
225
+ */
226
+ export function validateReferences(graph) {
227
+ const invalidReferences = [];
228
+ for (const taskId of graph.getAllTaskIds()) {
229
+ const task = graph.getNode(taskId);
230
+ if (task) {
231
+ for (const blockerId of task.blockers) {
232
+ if (!graph.hasNode(blockerId)) {
233
+ invalidReferences.push({ taskId, invalidBlockerId: blockerId });
234
+ }
235
+ }
236
+ }
237
+ }
238
+ return {
239
+ hasInvalidReferences: invalidReferences.length > 0,
240
+ invalidReferences,
241
+ };
242
+ }
243
+ /**
244
+ * Check if adding an edge would create a cycle
245
+ *
246
+ * When adding a blocker relationship (blockerId → taskId), this function
247
+ * checks if there's already a path from taskId to blockerId. If so,
248
+ * adding the edge would create a cycle.
249
+ *
250
+ * Also rejects self-blocking (taskId === blockerId).
251
+ *
252
+ * @param graph - Task graph store
253
+ * @param blockerId - The task that will block (source of edge)
254
+ * @param taskId - The task being blocked (target of edge)
255
+ * @returns true if adding this edge would create a cycle
256
+ *
257
+ * @example
258
+ * ```ts
259
+ * // Before adding blocker, check for cycle
260
+ * if (wouldCreateCycle(graph, blockerId, taskId)) {
261
+ * console.error('Cannot add blocker: would create a cycle');
262
+ * } else {
263
+ * task.addBlocker(blockerId);
264
+ * graph.addEdge(blockerId, taskId);
265
+ * }
266
+ * ```
267
+ */
268
+ export function wouldCreateCycle(graph, blockerId, taskId) {
269
+ // Self-blocking is always a cycle
270
+ if (blockerId === taskId) {
271
+ return true;
272
+ }
273
+ // Check if taskId can already reach blockerId through existing edges
274
+ // If so, adding blockerId → taskId would create a cycle
275
+ // We search 'forward' from taskId following outgoing edges
276
+ const visited = new Set();
277
+ const queue = [taskId];
278
+ while (queue.length > 0) {
279
+ const currentId = queue.shift();
280
+ if (currentId === blockerId) {
281
+ return true; // Found path from taskId to blockerId
282
+ }
283
+ if (visited.has(currentId)) {
284
+ continue;
285
+ }
286
+ visited.add(currentId);
287
+ // Follow outgoing edges (tasks that this task blocks)
288
+ const neighbors = graph.getOutgoingEdges(currentId);
289
+ for (const neighbor of neighbors) {
290
+ if (!visited.has(neighbor)) {
291
+ queue.push(neighbor);
292
+ }
293
+ }
294
+ }
295
+ return false;
296
+ }
297
+ //# sourceMappingURL=cycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cycle.js","sourceRoot":"","sources":["../../../src/core/graph/cycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Task Graph data structure
3
+ *
4
+ * Implements a directed graph using adjacency lists for O(1) node lookup
5
+ * and O(k) edge traversal where k is the number of edges.
6
+ *
7
+ * Graph Structure:
8
+ * - nodes: Map<taskId, TaskNode> for O(1) node lookup
9
+ * - outgoingEdges: Map<taskId, Set<targetTaskIds>> for forward traversal
10
+ * - incomingEdges: Map<taskId, Set<sourceTaskIds>> for reverse traversal
11
+ *
12
+ * @module core/graph
13
+ */
14
+ import type { TaskGraph, ProjectMetadata } from '../../types/index.js';
15
+ import { TaskNode } from '../models/task-node.js';
16
+ /**
17
+ * TaskGraphStore class
18
+ *
19
+ * Manages the task graph data structure with efficient lookup and traversal.
20
+ * Uses Map and Set for optimal performance:
21
+ * - O(1) node lookup by ID
22
+ * - O(k) edge traversal where k = edge count
23
+ * - O(1) edge existence checking
24
+ */
25
+ export declare class TaskGraphStore {
26
+ /** Primary node storage (hash map for O(1) lookup) */
27
+ private _nodes;
28
+ /** Outgoing edges: node -> nodes it points to */
29
+ private _outgoingEdges;
30
+ /** Incoming edges: node -> nodes pointing to it */
31
+ private _incomingEdges;
32
+ /** Graph metadata */
33
+ private _metadata;
34
+ /**
35
+ * Create a new TaskGraphStore
36
+ * @param metadata - Optional project metadata
37
+ */
38
+ constructor(metadata?: ProjectMetadata);
39
+ /**
40
+ * Get the number of tasks in the graph
41
+ */
42
+ get size(): number;
43
+ /**
44
+ * Get the graph metadata
45
+ */
46
+ get metadata(): ProjectMetadata;
47
+ /**
48
+ * Update graph metadata
49
+ * @param metadata - New metadata values (partial update)
50
+ */
51
+ setMetadata(metadata: Partial<ProjectMetadata>): void;
52
+ /**
53
+ * Get a task node by ID
54
+ * @param id - Task ID to look up
55
+ * @returns Task node or undefined if not found
56
+ * @complexity O(1)
57
+ */
58
+ getNode(id: string): TaskNode | undefined;
59
+ /**
60
+ * Get a task node by ID or throw error
61
+ * @param id - Task ID to look up
62
+ * @returns Task node
63
+ * @throws {TaskNotFoundError} If task not found
64
+ * @complexity O(1)
65
+ */
66
+ getNodeOrThrow(id: string): TaskNode;
67
+ /**
68
+ * Check if a task exists
69
+ * @param id - Task ID to check
70
+ * @returns True if task exists
71
+ * @complexity O(1)
72
+ */
73
+ hasNode(id: string): boolean;
74
+ /**
75
+ * Get a task node by short UUID prefix (first 7-8 characters)
76
+ * @param prefix - Short UUID prefix to look up
77
+ * @returns Task node or undefined if not found
78
+ * @throws {AmbiguousIdError} If multiple tasks match the prefix
79
+ * @complexity O(n) where n is the number of tasks
80
+ */
81
+ getNodeByPrefix(prefix: string): TaskNode | undefined;
82
+ /**
83
+ * Get a task node by ID or prefix
84
+ * @param id - Task ID or short UUID prefix to look up
85
+ * @returns Task node or undefined if not found
86
+ * @complexity O(1) for full ID, O(n) for prefix
87
+ */
88
+ getNodeByIdOrPrefix(id: string): TaskNode | undefined;
89
+ /**
90
+ * Generate a unique task ID with collision detection
91
+ * Ensures that the first 7 characters of the UUID are unique across all tasks
92
+ * @returns A unique task ID
93
+ * @throws {Error} If unable to generate unique ID after many attempts
94
+ */
95
+ generateUniqueId(): string;
96
+ /**
97
+ * Get all task IDs in the graph
98
+ * @returns Array of task IDs
99
+ */
100
+ getAllTaskIds(): string[];
101
+ /**
102
+ * Get all task nodes in the graph
103
+ * @returns Array of task nodes
104
+ */
105
+ getAllTasks(): TaskNode[];
106
+ /**
107
+ * Add a task node to the graph
108
+ * @param node - Task node to add
109
+ * @throws {ValidationError} If task ID already exists
110
+ * @complexity O(1)
111
+ */
112
+ addNode(node: TaskNode): void;
113
+ /**
114
+ * Remove a task node from the graph
115
+ * @param id - Task ID to remove
116
+ * @throws {TaskNotFoundError} If task not found
117
+ * @complexity O(k) where k is the number of edges
118
+ */
119
+ removeNode(id: string): void;
120
+ /**
121
+ * Update a task node in the graph
122
+ * @param node - Task node with updated values
123
+ * @throws {TaskNotFoundError} If task not found
124
+ * @complexity O(1)
125
+ */
126
+ updateNode(node: TaskNode): void;
127
+ /**
128
+ * Get outgoing edges for a node
129
+ * @param nodeId - Source task ID
130
+ * @returns Array of target task IDs
131
+ * @complexity O(k) where k is the number of outgoing edges
132
+ */
133
+ getOutgoingEdges(nodeId: string): string[];
134
+ /**
135
+ * Get incoming edges for a node
136
+ * @param nodeId - Target task ID
137
+ * @returns Array of source task IDs
138
+ * @complexity O(k) where k is the number of incoming edges
139
+ */
140
+ getIncomingEdges(nodeId: string): string[];
141
+ /**
142
+ * Add an edge between two nodes
143
+ * @param fromId - Source task ID
144
+ * @param toId - Target task ID
145
+ * @throws {TaskNotFoundError} If either task not found
146
+ * @throws {ValidationError} If edge already exists
147
+ * @complexity O(1)
148
+ */
149
+ addEdge(fromId: string, toId: string): void;
150
+ /**
151
+ * Remove an edge between two nodes
152
+ * @param fromId - Source task ID
153
+ * @param toId - Target task ID
154
+ * @throws {TaskNotFoundError} If either task not found
155
+ * @throws {ValidationError} If edge doesn't exist
156
+ * @complexity O(1)
157
+ */
158
+ removeEdge(fromId: string, toId: string): void;
159
+ /**
160
+ * Check if an edge exists
161
+ * @param fromId - Source task ID
162
+ * @param toId - Target task ID
163
+ * @returns True if edge exists
164
+ * @complexity O(1)
165
+ */
166
+ hasEdge(fromId: string, toId: string): boolean;
167
+ /**
168
+ * Get root tasks (tasks with no incoming edges)
169
+ * @returns Array of root task IDs
170
+ * @complexity O(n) where n is the number of tasks
171
+ */
172
+ getRootTasks(): string[];
173
+ /**
174
+ * Get orphan tasks (tasks with no edges at all)
175
+ * @returns Array of orphan task IDs
176
+ * @complexity O(n) where n is the number of tasks
177
+ */
178
+ getOrphanTasks(): string[];
179
+ /**
180
+ * Get leaf tasks (tasks with no outgoing edges)
181
+ * @returns Array of leaf task IDs
182
+ * @complexity O(n) where n is the number of tasks
183
+ */
184
+ getLeafTasks(): string[];
185
+ /**
186
+ * Clear all tasks and edges from the graph
187
+ * Keeps metadata but resets the graph structure
188
+ */
189
+ clear(): void;
190
+ /**
191
+ * Convert graph to TaskGraph interface
192
+ * @returns TaskGraph interface representation
193
+ */
194
+ toInterface(): TaskGraph;
195
+ /**
196
+ * Create TaskGraphStore from TaskGraph interface
197
+ * @param graph - TaskGraph interface
198
+ * @returns New TaskGraphStore instance
199
+ */
200
+ static fromInterface(graph: TaskGraph): TaskGraphStore;
201
+ /**
202
+ * Serialize graph to JSON-compatible object
203
+ * @returns JSON-serializable object
204
+ */
205
+ toJSON(): {
206
+ nodes: Record<string, TaskNode>;
207
+ outgoingEdges: Record<string, string[]>;
208
+ incomingEdges: Record<string, string[]>;
209
+ metadata: ProjectMetadata;
210
+ };
211
+ /**
212
+ * Deserialize graph from JSON object
213
+ * @param json - JSON object from toJSON()
214
+ * @returns New TaskGraphStore instance
215
+ */
216
+ static fromJSON(json: {
217
+ nodes: Record<string, TaskNode>;
218
+ outgoingEdges: Record<string, string[]>;
219
+ incomingEdges: Record<string, string[]>;
220
+ metadata: ProjectMetadata;
221
+ }): TaskGraphStore;
222
+ }
223
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/graph/index.ts"],"names":[],"mappings":"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"}