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,503 @@
1
+ /**
2
+ * Graph manipulation operations
3
+ *
4
+ * Implements complex graph operations for task management:
5
+ * - Cut nodes from graph while reconnecting edges
6
+ * - Insert nodes between existing nodes
7
+ * - Move subtrees to new parents
8
+ * - Merge tasks together
9
+ *
10
+ * @module core/graph/operations
11
+ */
12
+ import { TaskNode } from '../models/task-node.js';
13
+ import { TaskNotFoundError, ValidationError } from '../../types/index.js';
14
+ /**
15
+ * Cut a node from the graph, reconnecting its incoming edges to its outgoing edges
16
+ *
17
+ * Before: A -> B -> C
18
+ * After: A -> C (B removed)
19
+ *
20
+ * Algorithm:
21
+ * 1. Get all incoming edges to the node
22
+ * 2. Get all outgoing edges from the node
23
+ * 3. For each incoming source, connect it to all outgoing targets
24
+ * 4. Update target blockers to reference new sources instead of deleted node
25
+ * 5. Remove the node from the graph
26
+ *
27
+ * Time Complexity: O(k * m) where k = incoming edges, m = outgoing edges
28
+ *
29
+ * @param graph - Task graph store
30
+ * @param nodeId - Task ID to cut
31
+ * @throws {TaskNotFoundError} If task not found
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * // Graph: A -> B -> C
36
+ * cutNode(graph, 'B');
37
+ * // Result: A -> C (B removed, A now points directly to C)
38
+ * // Also: C.blockers updated from [B] to [A]
39
+ * ```
40
+ */
41
+ export function cutNode(graph, nodeId) {
42
+ if (!graph.hasNode(nodeId)) {
43
+ throw new TaskNotFoundError(nodeId);
44
+ }
45
+ // Get all incoming and outgoing edges before removing the node
46
+ const incomingSources = graph.getIncomingEdges(nodeId);
47
+ const outgoingTargets = graph.getOutgoingEdges(nodeId);
48
+ // Reconnect: for each incoming source, connect to all outgoing targets
49
+ for (const sourceId of incomingSources) {
50
+ for (const targetId of outgoingTargets) {
51
+ // Only add edge if it doesn't already exist
52
+ if (!graph.hasEdge(sourceId, targetId)) {
53
+ graph.addEdge(sourceId, targetId);
54
+ // Update target's blockers array to include the new source
55
+ const targetNode = graph.getNode(targetId);
56
+ if (targetNode && !targetNode.blockers.includes(sourceId)) {
57
+ targetNode.addBlocker(sourceId);
58
+ }
59
+ }
60
+ }
61
+ }
62
+ // Remove deleted nodeId from all targets' blockers arrays
63
+ for (const targetId of outgoingTargets) {
64
+ const targetNode = graph.getNode(targetId);
65
+ if (targetNode && targetNode.blockers.includes(nodeId)) {
66
+ targetNode.removeBlocker(nodeId);
67
+ }
68
+ }
69
+ // Remove the node (this also removes all its edges)
70
+ graph.removeNode(nodeId);
71
+ }
72
+ /**
73
+ * Insert a node between two existing nodes
74
+ *
75
+ * Before: A -> C
76
+ * After: A -> B -> C
77
+ *
78
+ * Algorithm:
79
+ * 1. Verify both nodes exist
80
+ * 2. Verify edge exists from afterId to beforeId
81
+ * 3. Remove the existing edge
82
+ * 4. Add the new node to the graph
83
+ * 5. Create edges: afterId -> newNodeId -> beforeId
84
+ *
85
+ * Time Complexity: O(1) for edge operations
86
+ *
87
+ * @param graph - Task graph store
88
+ * @param newNode - Task node to insert
89
+ * @param afterId - Source node ID (edge comes from here)
90
+ * @param beforeId - Target node ID (edge goes to here)
91
+ * @throws {TaskNotFoundError} If afterId or beforeId not found
92
+ * @throws {ValidationError} If edge doesn't exist or would create duplicate
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * // Graph: A -> C
97
+ * const newNode = createTaskNode({ title: 'B', ... });
98
+ * insertNodeBetween(graph, newNode, 'A', 'C');
99
+ * // Result: A -> B -> C
100
+ * ```
101
+ */
102
+ export function insertNodeBetween(graph, newNode, afterId, beforeId) {
103
+ // Verify source and target nodes exist
104
+ if (!graph.hasNode(afterId)) {
105
+ throw new TaskNotFoundError(afterId);
106
+ }
107
+ if (!graph.hasNode(beforeId)) {
108
+ throw new TaskNotFoundError(beforeId);
109
+ }
110
+ // Verify edge exists
111
+ if (!graph.hasEdge(afterId, beforeId)) {
112
+ throw new ValidationError(`Edge from '${afterId}' to '${beforeId}' does not exist`, 'edges');
113
+ }
114
+ // Add the new node to the graph first
115
+ graph.addNode(newNode);
116
+ // Remove the existing edge
117
+ graph.removeEdge(afterId, beforeId);
118
+ // Add new edges: afterId -> newNodeId -> beforeId
119
+ graph.addEdge(afterId, newNode.id);
120
+ graph.addEdge(newNode.id, beforeId);
121
+ }
122
+ /**
123
+ * Move a subtree to a new parent
124
+ *
125
+ * Moves a task (and all its descendants) to be under a new parent.
126
+ * This is useful for reorganizing task hierarchies.
127
+ *
128
+ * Before:
129
+ * A -> X
130
+ * B -> Y
131
+ * After moveSubtree(graph, 'Y', 'A'):
132
+ * A -> X -> Y
133
+ * B
134
+ *
135
+ * Algorithm:
136
+ * 1. Get all current parents of the subtree root
137
+ * 2. Remove edges from all current parents
138
+ * 3. Add edge from new parent to subtree root
139
+ *
140
+ * Time Complexity: O(k) where k = number of current parents
141
+ *
142
+ * @param graph - Task graph store
143
+ * @param subtreeRootId - Root of the subtree to move
144
+ * @param newParentId - New parent task ID
145
+ * @throws {TaskNotFoundError} If subtreeRootId or newParentId not found
146
+ * @throws {ValidationError} If edge already exists or would create self-loop
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * // Graph: A -> X, B -> Y
151
+ * moveSubtree(graph, 'Y', 'X');
152
+ * // Result: A -> X -> Y, B
153
+ * ```
154
+ */
155
+ export function moveSubtree(graph, subtreeRootId, newParentId) {
156
+ // Verify both nodes exist
157
+ if (!graph.hasNode(subtreeRootId)) {
158
+ throw new TaskNotFoundError(subtreeRootId);
159
+ }
160
+ if (!graph.hasNode(newParentId)) {
161
+ throw new TaskNotFoundError(newParentId);
162
+ }
163
+ // Prevent self-loops
164
+ if (subtreeRootId === newParentId) {
165
+ throw new ValidationError('Cannot move subtree to be its own parent', 'subtreeRootId');
166
+ }
167
+ // Check if edge already exists
168
+ if (graph.hasEdge(newParentId, subtreeRootId)) {
169
+ throw new ValidationError(`Edge from '${newParentId}' to '${subtreeRootId}' already exists`, 'edges');
170
+ }
171
+ // Get all current parents (nodes that point to subtreeRootId)
172
+ const currentParents = graph.getIncomingEdges(subtreeRootId);
173
+ // Remove from all current parents
174
+ for (const parentId of currentParents) {
175
+ graph.removeEdge(parentId, subtreeRootId);
176
+ }
177
+ // Add to new parent
178
+ graph.addEdge(newParentId, subtreeRootId);
179
+ }
180
+ /**
181
+ * Merge two tasks into one
182
+ *
183
+ * Combines the source task into the target task by:
184
+ * 1. Merging all properties (description, success_criteria, deliverables, etc.)
185
+ * 2. Reconnecting all edges from source to point to target
186
+ * 3. Removing the source task
187
+ *
188
+ * Before:
189
+ * A -> source -> C
190
+ * B -> target -> D
191
+ * After mergeTasks(graph, 'source', 'target'):
192
+ * A -> target -> C, D
193
+ * B -> target -> C, D
194
+ * (source is removed)
195
+ *
196
+ * Algorithm:
197
+ * 1. Get source and target tasks
198
+ * 2. Merge target properties with source properties
199
+ * 3. Get all incoming edges to source (except target)
200
+ * 4. Get all outgoing edges from source (except target)
201
+ * 5. Reconnect edges: incoming -> target, target -> outgoing
202
+ * 6. Remove source node
203
+ * 7. Return merge result
204
+ *
205
+ * Time Complexity: O(k + m) where k = incoming edges, m = outgoing edges
206
+ *
207
+ * @param graph - Task graph store
208
+ * @param sourceId - Source task ID (will be removed)
209
+ * @param targetId - Target task ID (will be kept and merged into)
210
+ * @returns Merge result with merged task and affected task IDs
211
+ * @throws {TaskNotFoundError} If source or target not found
212
+ * @throws {ValidationError} If source and target are the same
213
+ *
214
+ * @example
215
+ * ```ts
216
+ * const result = mergeTasks(graph, 'task-001', 'task-002');
217
+ * console.log('Merged task:', result.task.id);
218
+ * console.log('Removed tasks:', result.removedTasks);
219
+ * ```
220
+ */
221
+ export function mergeTasks(graph, sourceId, targetId) {
222
+ // Verify both tasks exist
223
+ const source = graph.getNode(sourceId);
224
+ const target = graph.getNode(targetId);
225
+ if (!source) {
226
+ throw new TaskNotFoundError(sourceId);
227
+ }
228
+ if (!target) {
229
+ throw new TaskNotFoundError(targetId);
230
+ }
231
+ // Cannot merge a task with itself
232
+ if (sourceId === targetId) {
233
+ throw new ValidationError('Cannot merge a task with itself', 'sourceId');
234
+ }
235
+ // Merge properties into target task
236
+ // Merge descriptions with separator
237
+ const newDescription = target.description
238
+ ? `${target.description}\n\n--- Merged from "${source.title}" ---\n${source.description}`
239
+ : source.description;
240
+ target.setDescription(newDescription);
241
+ // Merge success criteria (avoiding duplicates by ID)
242
+ for (const sc of source.success_criteria) {
243
+ if (!target.success_criteria.some(tsc => tsc.id === sc.id)) {
244
+ target.addSuccessCriterion(sc);
245
+ }
246
+ }
247
+ // Merge deliverables (avoiding duplicates by ID)
248
+ for (const d of source.deliverables) {
249
+ if (!target.deliverables.some(td => td.id === d.id)) {
250
+ target.addDeliverable(d);
251
+ }
252
+ }
253
+ // Merge related files (avoiding duplicates)
254
+ for (const file of source.related_files) {
255
+ target.addRelatedFile(file);
256
+ }
257
+ // Merge notes with separator
258
+ const newNotes = target.notes
259
+ ? `${target.notes}\n\nMerged notes from "${source.title}":\n${source.notes}`
260
+ : source.notes;
261
+ target.appendNotes(newNotes);
262
+ // Merge C7 verifications
263
+ for (const cv of source.c7_verified) {
264
+ target.addC7Verification(cv);
265
+ }
266
+ // Remove source from target's blockers (source is being merged/removed)
267
+ if (target.blockers.includes(sourceId)) {
268
+ target.removeBlocker(sourceId);
269
+ }
270
+ // Merge blockers (avoiding duplicates and self-references)
271
+ for (const blockerId of source.blockers) {
272
+ if (blockerId !== targetId && !target.blockers.includes(blockerId)) {
273
+ target.addBlocker(blockerId);
274
+ }
275
+ }
276
+ // Merge dependencies explanation text (combine both)
277
+ if (source.dependencies) {
278
+ if (target.dependencies) {
279
+ target.setDependencies(`${target.dependencies}\n${source.dependencies}`);
280
+ }
281
+ else {
282
+ target.setDependencies(source.dependencies);
283
+ }
284
+ }
285
+ // Track which tasks were affected by reconnection
286
+ const reconnectSources = [];
287
+ const reconnectTargets = [];
288
+ // Get source's incoming edges (tasks pointing to source)
289
+ const sourceIncoming = graph.getIncomingEdges(sourceId);
290
+ // Get source's outgoing edges (tasks source points to)
291
+ const sourceOutgoing = graph.getOutgoingEdges(sourceId);
292
+ // Reconnect incoming edges (except target and self-loops)
293
+ for (const fromId of sourceIncoming) {
294
+ if (fromId !== targetId && !graph.hasEdge(fromId, targetId)) {
295
+ graph.addEdge(fromId, targetId);
296
+ reconnectSources.push(fromId);
297
+ }
298
+ }
299
+ // Reconnect outgoing edges (except target and self-loops)
300
+ for (const toId of sourceOutgoing) {
301
+ if (toId !== targetId && !graph.hasEdge(targetId, toId)) {
302
+ graph.addEdge(targetId, toId);
303
+ reconnectTargets.push(toId);
304
+ }
305
+ }
306
+ // Update the target task in the graph with merged data
307
+ graph.updateNode(target);
308
+ // Remove the source task
309
+ graph.removeNode(sourceId);
310
+ // Collect all affected task IDs
311
+ const allAffected = new Set([
312
+ ...reconnectSources,
313
+ ...reconnectTargets,
314
+ targetId
315
+ ]);
316
+ return {
317
+ task: target,
318
+ removedTasks: [sourceId],
319
+ updatedTasks: Array.from(allAffected)
320
+ };
321
+ }
322
+ /**
323
+ * Get all descendants of a node (transitive closure via outgoing edges)
324
+ *
325
+ * Returns all tasks reachable from the given node.
326
+ *
327
+ * @param graph - Task graph store
328
+ * @param nodeId - Starting task ID
329
+ * @returns Set of descendant task IDs (including the starting node)
330
+ * @throws {TaskNotFoundError} If node not found
331
+ *
332
+ * @example
333
+ * ```ts
334
+ * // Graph: A -> B -> C, A -> D
335
+ * const descendants = getDescendants(graph, 'A');
336
+ * // Returns: ['A', 'B', 'C', 'D']
337
+ * ```
338
+ */
339
+ export function getDescendants(graph, nodeId) {
340
+ if (!graph.hasNode(nodeId)) {
341
+ throw new TaskNotFoundError(nodeId);
342
+ }
343
+ const descendants = new Set();
344
+ const stack = [nodeId];
345
+ while (stack.length > 0) {
346
+ const current = stack.pop();
347
+ if (descendants.has(current)) {
348
+ continue;
349
+ }
350
+ descendants.add(current);
351
+ // Add all children to the stack
352
+ const children = graph.getOutgoingEdges(current);
353
+ for (const child of children) {
354
+ if (!descendants.has(child)) {
355
+ stack.push(child);
356
+ }
357
+ }
358
+ }
359
+ return descendants;
360
+ }
361
+ /**
362
+ * Get all ancestors of a node (transitive closure via incoming edges)
363
+ *
364
+ * Returns all tasks that can reach the given node.
365
+ *
366
+ * @param graph - Task graph store
367
+ * @param nodeId - Starting task ID
368
+ * @returns Set of ancestor task IDs (including the starting node)
369
+ * @throws {TaskNotFoundError} If node not found
370
+ *
371
+ * @example
372
+ * ```ts
373
+ * // Graph: A -> B -> C
374
+ * const ancestors = getAncestors(graph, 'C');
375
+ * // Returns: ['C', 'B', 'A']
376
+ * ```
377
+ */
378
+ export function getAncestors(graph, nodeId) {
379
+ if (!graph.hasNode(nodeId)) {
380
+ throw new TaskNotFoundError(nodeId);
381
+ }
382
+ const ancestors = new Set();
383
+ const stack = [nodeId];
384
+ while (stack.length > 0) {
385
+ const current = stack.pop();
386
+ if (ancestors.has(current)) {
387
+ continue;
388
+ }
389
+ ancestors.add(current);
390
+ // Add all parents to the stack
391
+ const parents = graph.getIncomingEdges(current);
392
+ for (const parent of parents) {
393
+ if (!ancestors.has(parent)) {
394
+ stack.push(parent);
395
+ }
396
+ }
397
+ }
398
+ return ancestors;
399
+ }
400
+ /**
401
+ * Validate that moving a subtree won't create a cycle
402
+ *
403
+ * Checks if adding an edge from newParentId to subtreeRootId would create a cycle.
404
+ * This is important for moveSubtree operations.
405
+ *
406
+ * @param graph - Task graph store
407
+ * @param subtreeRootId - Root of the subtree to move
408
+ * @param newParentId - Potential new parent task ID
409
+ * @returns true if move is safe (won't create cycle), false otherwise
410
+ * @throws {TaskNotFoundError} If either task not found
411
+ *
412
+ * @example
413
+ * ```ts
414
+ * // Graph: A -> B -> C
415
+ * if (isValidSubtreeMove(graph, 'C', 'A')) {
416
+ * // This would create a cycle (A -> B -> C -> A)
417
+ * // Don't allow the move
418
+ * }
419
+ * ```
420
+ */
421
+ export function isValidSubtreeMove(graph, subtreeRootId, newParentId) {
422
+ if (!graph.hasNode(subtreeRootId)) {
423
+ throw new TaskNotFoundError(subtreeRootId);
424
+ }
425
+ if (!graph.hasNode(newParentId)) {
426
+ throw new TaskNotFoundError(newParentId);
427
+ }
428
+ // Check if newParentId is in the descendants of subtreeRootId
429
+ // If so, adding edge subtreeRootId -> newParentId would create a cycle
430
+ const descendants = getDescendants(graph, subtreeRootId);
431
+ return !descendants.has(newParentId);
432
+ }
433
+ /**
434
+ * Cascade delete a node and all its dependent tasks
435
+ *
436
+ * Deletes the specified node and all tasks that depend on it (directly or transitively).
437
+ * Tasks are deleted in reverse order (leaves first) to maintain graph integrity.
438
+ *
439
+ * Before:
440
+ * A -> B -> C -> D
441
+ * After cascadeDelete(graph, 'B'):
442
+ * A (B, C, D removed)
443
+ *
444
+ * Algorithm:
445
+ * 1. Get all descendants of the node (tasks that depend on it transitively)
446
+ * 2. Iteratively find and delete leaf nodes (no outgoing edges) first
447
+ * 3. Continue until all descendants are deleted
448
+ *
449
+ * Time Complexity: O(k * m) where k = descendants, m = average edges
450
+ *
451
+ * @param graph - Task graph store
452
+ * @param nodeId - Task ID to cascade delete
453
+ * @returns Array of deleted task IDs (in order of deletion)
454
+ * @throws {TaskNotFoundError} If node not found
455
+ *
456
+ * @example
457
+ * ```ts
458
+ * // Graph: A -> B -> C -> D
459
+ * const deleted = cascadeDelete(graph, 'B');
460
+ * // Returns: ['D', 'C', 'B'] (deleted in this order)
461
+ * // Result: Only A remains
462
+ * ```
463
+ */
464
+ export function cascadeDelete(graph, nodeId) {
465
+ if (!graph.hasNode(nodeId)) {
466
+ throw new TaskNotFoundError(nodeId);
467
+ }
468
+ const deletedIds = [];
469
+ // Get all tasks that depend on this node (directly or transitively)
470
+ const descendants = getDescendants(graph, nodeId);
471
+ // Remove the original node from descendants set for processing
472
+ // We'll delete it last (or as part of the iterative process)
473
+ const toDelete = new Set(descendants);
474
+ // Iteratively delete leaf nodes (nodes with no outgoing edges in remaining set)
475
+ while (toDelete.size > 0) {
476
+ let deletedThisRound = false;
477
+ for (const id of toDelete) {
478
+ // Check if this node is a leaf (no outgoing edges to other nodes in toDelete)
479
+ const outgoing = graph.getOutgoingEdges(id);
480
+ const hasDependentsInSet = outgoing.some(depId => toDelete.has(depId));
481
+ if (!hasDependentsInSet) {
482
+ // This is a leaf in our deletion set, safe to delete
483
+ graph.removeNode(id);
484
+ deletedIds.push(id);
485
+ toDelete.delete(id);
486
+ deletedThisRound = true;
487
+ break; // Restart loop after each deletion
488
+ }
489
+ }
490
+ // Safety check to prevent infinite loop
491
+ if (!deletedThisRound && toDelete.size > 0) {
492
+ // This shouldn't happen in a valid DAG, but handle gracefully
493
+ // Force delete remaining nodes
494
+ for (const id of toDelete) {
495
+ graph.removeNode(id);
496
+ deletedIds.push(id);
497
+ }
498
+ break;
499
+ }
500
+ }
501
+ return deletedIds;
502
+ }
503
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../../src/core/graph/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Graph topological sort algorithms
3
+ *
4
+ * Implements Kahn's algorithm for topological sorting with cycle detection.
5
+ * Time complexity: O(V + E) where V = vertices, E = edges
6
+ *
7
+ * @module core/graph/sort
8
+ */
9
+ import type { TaskGraphStore } from './index.js';
10
+ import type { TopologicalSortResult } from '../../types/index.js';
11
+ /**
12
+ * Clear the topological sort cache
13
+ * Call this after modifying the graph structure
14
+ */
15
+ export declare function clearSortCache(): void;
16
+ /**
17
+ * Perform topological sort using Kahn's algorithm
18
+ *
19
+ * Algorithm steps:
20
+ * 1. Calculate in-degree for all nodes
21
+ * 2. Initialize queue with nodes having zero in-degree
22
+ * 3. Process queue: remove node, add to result, reduce neighbors' in-degree
23
+ * 4. Add any neighbors with zero in-degree to queue
24
+ * 5. Detect cycle if result doesn't contain all nodes
25
+ *
26
+ * Time Complexity: O(V + E)
27
+ * Space Complexity: O(V)
28
+ *
29
+ * @param graph - Task graph store
30
+ * @param useCache - Whether to use memoization cache (default: true)
31
+ * @returns Topological sort result with sorted order and cycle detection
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const result = topologicalSort(graph);
36
+ * if (result.hasCycle) {
37
+ * console.error('Cycle detected:', result.cycleNodes);
38
+ * } else {
39
+ * console.log('Execution order:', result.sorted);
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function topologicalSort(graph: TaskGraphStore, useCache?: boolean): TopologicalSortResult;
44
+ /**
45
+ * Find the critical path (longest path) in the DAG
46
+ * Uses topological sort and dynamic programming
47
+ *
48
+ * Time Complexity: O(V + E)
49
+ *
50
+ * @param graph - Task graph store
51
+ * @param taskDuration - Duration for each task (default: 1)
52
+ * @returns Object with path array and total duration
53
+ * @throws {CircularDependencyError} If graph contains cycles
54
+ */
55
+ export declare function findCriticalPath(graph: TaskGraphStore, taskDuration?: number | Map<string, number>): {
56
+ path: string[];
57
+ duration: number;
58
+ };
59
+ /**
60
+ * Validate that a graph is a valid DAG
61
+ * Convenience wrapper around topologicalSort
62
+ *
63
+ * @param graph - Task graph store
64
+ * @returns true if graph is a valid DAG, false otherwise
65
+ */
66
+ export declare function isValidDAG(graph: TaskGraphStore): boolean;
67
+ /**
68
+ * Get task execution levels (parallelizable stages)
69
+ * Tasks at the same level have no dependencies between them
70
+ *
71
+ * @param graph - Task graph store
72
+ * @returns Array of task ID arrays (each level is a parallelizable stage)
73
+ * @throws {CircularDependencyError} If graph contains cycles
74
+ */
75
+ export declare function getExecutionLevels(graph: TaskGraphStore): string[][];
76
+ //# sourceMappingURL=sort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../../src/core/graph/sort.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAmBlE;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,UAAO,GAAG,qBAAqB,CAmB7F;AAiED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,YAAY,GAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAK,GAC7C;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiEtC;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,EAAE,CA8CpE"}