@flowdot.ai/daemon 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 (85) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +51 -0
  3. package/dist/goals/DependencyResolver.d.ts +54 -0
  4. package/dist/goals/DependencyResolver.js +329 -0
  5. package/dist/goals/ErrorRecovery.d.ts +133 -0
  6. package/dist/goals/ErrorRecovery.js +489 -0
  7. package/dist/goals/GoalApiClient.d.ts +81 -0
  8. package/dist/goals/GoalApiClient.js +743 -0
  9. package/dist/goals/GoalCache.d.ts +65 -0
  10. package/dist/goals/GoalCache.js +243 -0
  11. package/dist/goals/GoalCommsHandler.d.ts +150 -0
  12. package/dist/goals/GoalCommsHandler.js +378 -0
  13. package/dist/goals/GoalExporter.d.ts +164 -0
  14. package/dist/goals/GoalExporter.js +318 -0
  15. package/dist/goals/GoalImporter.d.ts +107 -0
  16. package/dist/goals/GoalImporter.js +345 -0
  17. package/dist/goals/GoalManager.d.ts +110 -0
  18. package/dist/goals/GoalManager.js +535 -0
  19. package/dist/goals/GoalReporter.d.ts +105 -0
  20. package/dist/goals/GoalReporter.js +534 -0
  21. package/dist/goals/GoalScheduler.d.ts +102 -0
  22. package/dist/goals/GoalScheduler.js +209 -0
  23. package/dist/goals/GoalValidator.d.ts +72 -0
  24. package/dist/goals/GoalValidator.js +657 -0
  25. package/dist/goals/MetaGoalEnforcer.d.ts +111 -0
  26. package/dist/goals/MetaGoalEnforcer.js +536 -0
  27. package/dist/goals/MilestoneBreaker.d.ts +74 -0
  28. package/dist/goals/MilestoneBreaker.js +348 -0
  29. package/dist/goals/PermissionBridge.d.ts +109 -0
  30. package/dist/goals/PermissionBridge.js +326 -0
  31. package/dist/goals/ProgressTracker.d.ts +113 -0
  32. package/dist/goals/ProgressTracker.js +324 -0
  33. package/dist/goals/ReviewScheduler.d.ts +106 -0
  34. package/dist/goals/ReviewScheduler.js +360 -0
  35. package/dist/goals/TaskExecutor.d.ts +116 -0
  36. package/dist/goals/TaskExecutor.js +370 -0
  37. package/dist/goals/TaskFeedback.d.ts +126 -0
  38. package/dist/goals/TaskFeedback.js +402 -0
  39. package/dist/goals/TaskGenerator.d.ts +75 -0
  40. package/dist/goals/TaskGenerator.js +329 -0
  41. package/dist/goals/TaskQueue.d.ts +84 -0
  42. package/dist/goals/TaskQueue.js +331 -0
  43. package/dist/goals/TaskSanitizer.d.ts +61 -0
  44. package/dist/goals/TaskSanitizer.js +464 -0
  45. package/dist/goals/errors.d.ts +116 -0
  46. package/dist/goals/errors.js +299 -0
  47. package/dist/goals/index.d.ts +24 -0
  48. package/dist/goals/index.js +23 -0
  49. package/dist/goals/types.d.ts +395 -0
  50. package/dist/goals/types.js +230 -0
  51. package/dist/index.d.ts +4 -0
  52. package/dist/index.js +3 -0
  53. package/dist/loop/DaemonIPC.d.ts +67 -0
  54. package/dist/loop/DaemonIPC.js +358 -0
  55. package/dist/loop/IntervalParser.d.ts +39 -0
  56. package/dist/loop/IntervalParser.js +217 -0
  57. package/dist/loop/LoopDaemon.d.ts +123 -0
  58. package/dist/loop/LoopDaemon.js +1821 -0
  59. package/dist/loop/LoopExecutor.d.ts +93 -0
  60. package/dist/loop/LoopExecutor.js +326 -0
  61. package/dist/loop/LoopManager.d.ts +79 -0
  62. package/dist/loop/LoopManager.js +476 -0
  63. package/dist/loop/LoopScheduler.d.ts +69 -0
  64. package/dist/loop/LoopScheduler.js +329 -0
  65. package/dist/loop/LoopStore.d.ts +57 -0
  66. package/dist/loop/LoopStore.js +406 -0
  67. package/dist/loop/LoopValidator.d.ts +55 -0
  68. package/dist/loop/LoopValidator.js +603 -0
  69. package/dist/loop/errors.d.ts +115 -0
  70. package/dist/loop/errors.js +312 -0
  71. package/dist/loop/index.d.ts +11 -0
  72. package/dist/loop/index.js +10 -0
  73. package/dist/loop/notifications/Notifier.d.ts +28 -0
  74. package/dist/loop/notifications/Notifier.js +78 -0
  75. package/dist/loop/notifications/SlackNotifier.d.ts +28 -0
  76. package/dist/loop/notifications/SlackNotifier.js +203 -0
  77. package/dist/loop/notifications/TerminalNotifier.d.ts +18 -0
  78. package/dist/loop/notifications/TerminalNotifier.js +72 -0
  79. package/dist/loop/notifications/WebhookNotifier.d.ts +24 -0
  80. package/dist/loop/notifications/WebhookNotifier.js +123 -0
  81. package/dist/loop/notifications/index.d.ts +24 -0
  82. package/dist/loop/notifications/index.js +109 -0
  83. package/dist/loop/types.d.ts +280 -0
  84. package/dist/loop/types.js +222 -0
  85. package/package.json +92 -0
package/LICENSE ADDED
@@ -0,0 +1,45 @@
1
+ FlowDot Proprietary Software License
2
+
3
+ Copyright (c) 2026 FlowDot LLC. All Rights Reserved.
4
+
5
+ TERMS AND CONDITIONS
6
+
7
+ 1. GRANT OF LICENSE
8
+ FlowDot LLC grants you a limited, non-exclusive, non-transferable license
9
+ to install and use this software for personal or commercial purposes,
10
+ subject to the terms of this agreement.
11
+
12
+ 2. RESTRICTIONS
13
+ You may NOT:
14
+ - Modify, alter, adapt, or create derivative works of this software
15
+ - Reverse engineer, decompile, disassemble, or attempt to derive the
16
+ source code of this software
17
+ - Redistribute, sublicense, lease, rent, or sell copies of this software
18
+ - Remove, alter, or obscure any proprietary notices, labels, or marks
19
+ - Use this software to create a competing product or service
20
+
21
+ 3. OWNERSHIP
22
+ This software is licensed, not sold. FlowDot LLC retains all right, title,
23
+ and interest in and to the software, including all intellectual property
24
+ rights therein.
25
+
26
+ 4. TERMINATION
27
+ This license is effective until terminated. Your rights under this license
28
+ will terminate automatically without notice if you fail to comply with any
29
+ of its terms.
30
+
31
+ 5. DISCLAIMER OF WARRANTIES
32
+ THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
35
+
36
+ 6. LIMITATION OF LIABILITY
37
+ IN NO EVENT SHALL FLOWDOT LLC BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
38
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
39
+ CONNECTION WITH THIS SOFTWARE.
40
+
41
+ 7. GOVERNING LAW
42
+ This agreement shall be governed by the laws of the State of Delaware,
43
+ United States, without regard to its conflict of law provisions.
44
+
45
+ For licensing inquiries, contact: hello@flowdot.ai
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @flowdot.ai/daemon
2
+
3
+ Shared daemon and loop/goal management for the [FlowDot](https://flowdot.ai) platform.
4
+
5
+ Used by the FlowDot CLI and the FlowDot native desktop app to run background loops, track autonomous goals, and coordinate IPC between local clients and the FlowDot Hub.
6
+
7
+ ## Features
8
+
9
+ - **Loop scheduling** — background execution of scheduled FlowDot workflows
10
+ - **Goal tracking** — autonomous task execution with dependency resolution, progress tracking, and error recovery
11
+ - **IPC** — daemon-to-client communication over local sockets
12
+ - **Notifications** — terminal, webhook, and Slack delivery
13
+ - **State management** — persistent daemon state with crash recovery
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @flowdot.ai/daemon
19
+ ```
20
+
21
+ `@flowdot.ai/api` is an optional peer dependency — install it if you want to use the api-backed features.
22
+
23
+ ```bash
24
+ npm install @flowdot.ai/daemon @flowdot.ai/api
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```typescript
30
+ import {
31
+ LoopDaemon,
32
+ LoopManager,
33
+ IPCClient,
34
+ createNotifier,
35
+ GoalManager,
36
+ TaskGenerator,
37
+ TaskExecutor,
38
+ } from '@flowdot.ai/daemon';
39
+ ```
40
+
41
+ See the [FlowDot CLI source](https://github.com/ElliotTheGreek/flowdot-cli) for end-to-end integration examples.
42
+
43
+ ## Requirements
44
+
45
+ - Node.js ≥ 20.0.0
46
+
47
+ ## License
48
+
49
+ Proprietary — see [LICENSE](./LICENSE).
50
+
51
+ Copyright © 2026 FlowDot LLC. All rights reserved.
@@ -0,0 +1,54 @@
1
+ import type { Goal, Task, GoalHash, Logger } from './types.js';
2
+ import { GoalError } from './errors.js';
3
+ export interface DependencyNode {
4
+ readonly id: string;
5
+ readonly dependsOn: string[];
6
+ readonly dependents: string[];
7
+ readonly status: 'pending' | 'ready' | 'blocked' | 'completed';
8
+ readonly blockReason?: string;
9
+ }
10
+ export interface GoalResolutionResult {
11
+ readonly orderedGoals: GoalHash[];
12
+ readonly blockedGoals: Map<GoalHash, string>;
13
+ readonly circularGoals: GoalHash[];
14
+ readonly graph: Map<GoalHash, DependencyNode>;
15
+ readonly success: boolean;
16
+ readonly errors: string[];
17
+ }
18
+ export interface TaskDependencyNode {
19
+ readonly taskId: number;
20
+ readonly goalHash: GoalHash;
21
+ readonly title: string;
22
+ readonly dependsOn: number[];
23
+ readonly isReady: boolean;
24
+ readonly blockReason?: string;
25
+ }
26
+ export interface DependencyResolverOptions {
27
+ readonly logger?: Logger;
28
+ }
29
+ export declare class DependencyResolutionError extends GoalError {
30
+ constructor(message: string, cause?: Error);
31
+ }
32
+ export declare class DependencyResolver {
33
+ private readonly logger;
34
+ constructor(options?: DependencyResolverOptions);
35
+ resolveGoals(goals: Goal[]): GoalResolutionResult;
36
+ canStartGoal(goal: Goal, allGoals: Goal[]): {
37
+ canStart: boolean;
38
+ reason?: string;
39
+ waitingOn?: GoalHash[];
40
+ };
41
+ getBlockedBy(goalHash: GoalHash, allGoals: Goal[]): GoalHash[];
42
+ wouldCreateCycle(fromGoal: GoalHash, toGoal: GoalHash, allGoals: Goal[]): boolean;
43
+ resolveTasks(tasks: Task[], _goalHash: GoalHash): {
44
+ orderedTasks: Task[];
45
+ blocked: Map<number, string>;
46
+ };
47
+ getTaskExecutionOrder(tasks: Task[], milestoneOrder: number[]): Task[];
48
+ private detectCircularDependencies;
49
+ private topologicalSort;
50
+ }
51
+ export declare function getTransitiveDependencies(goalHash: GoalHash, allGoals: Goal[]): GoalHash[];
52
+ export declare function getTransitiveDependents(goalHash: GoalHash, allGoals: Goal[]): GoalHash[];
53
+ export declare function calculateCriticalPath(goals: Goal[]): GoalHash[];
54
+ export declare function createDependencyResolver(options?: DependencyResolverOptions): DependencyResolver;
@@ -0,0 +1,329 @@
1
+ function getPriorityWeight(priority) {
2
+ switch (priority) {
3
+ case 'high': return 3;
4
+ case 'medium': return 2;
5
+ case 'low': return 1;
6
+ default: return 0;
7
+ }
8
+ }
9
+ import { GoalError } from './errors.js';
10
+ const noopLogger = {
11
+ debug: () => { },
12
+ info: () => { },
13
+ warn: () => { },
14
+ error: () => { },
15
+ };
16
+ export class DependencyResolutionError extends GoalError {
17
+ constructor(message, cause) {
18
+ super('DEPENDENCY_RESOLUTION_ERROR', message, cause ? { cause } : {});
19
+ }
20
+ }
21
+ export class DependencyResolver {
22
+ logger;
23
+ constructor(options = {}) {
24
+ this.logger = options.logger ?? noopLogger;
25
+ }
26
+ resolveGoals(goals) {
27
+ const graph = new Map();
28
+ const errors = [];
29
+ for (const goal of goals) {
30
+ const dependsOn = goal.dependsOn ?? [];
31
+ graph.set(goal.hash, {
32
+ id: goal.hash,
33
+ dependsOn,
34
+ dependents: [],
35
+ status: goal.status === 'completed' ? 'completed' : 'pending',
36
+ });
37
+ }
38
+ for (const node of graph.values()) {
39
+ for (const depId of node.dependsOn) {
40
+ const depNode = graph.get(depId);
41
+ if (depNode) {
42
+ depNode.dependents.push(node.id);
43
+ }
44
+ }
45
+ }
46
+ const circularGoals = this.detectCircularDependencies(graph);
47
+ if (circularGoals.length > 0) {
48
+ errors.push(`Circular dependencies detected: ${circularGoals.join(' -> ')}`);
49
+ }
50
+ const blockedGoals = new Map();
51
+ for (const [hash, node] of graph) {
52
+ if (circularGoals.includes(hash)) {
53
+ blockedGoals.set(hash, 'Circular dependency detected');
54
+ node.status = 'blocked';
55
+ node.blockReason =
56
+ 'Circular dependency detected';
57
+ continue;
58
+ }
59
+ const incompleteDeps = [];
60
+ for (const depId of node.dependsOn) {
61
+ const depNode = graph.get(depId);
62
+ if (depNode && depNode.status !== 'completed') {
63
+ incompleteDeps.push(depId);
64
+ }
65
+ else if (!depNode) {
66
+ incompleteDeps.push(`${depId} (not found)`);
67
+ }
68
+ }
69
+ if (incompleteDeps.length > 0) {
70
+ blockedGoals.set(hash, `Waiting on: ${incompleteDeps.join(', ')}`);
71
+ node.status = 'blocked';
72
+ node.blockReason =
73
+ `Waiting on: ${incompleteDeps.join(', ')}`;
74
+ }
75
+ else if (node.status !== 'completed') {
76
+ node.status = 'ready';
77
+ }
78
+ }
79
+ const orderedGoals = this.topologicalSort(graph, circularGoals);
80
+ this.logger.debug('DEPENDENCY_RESOLVER', 'Goals resolved', {
81
+ total: goals.length,
82
+ ready: orderedGoals.length,
83
+ blocked: blockedGoals.size,
84
+ circular: circularGoals.length,
85
+ });
86
+ return {
87
+ orderedGoals,
88
+ blockedGoals,
89
+ circularGoals,
90
+ graph,
91
+ success: errors.length === 0,
92
+ errors,
93
+ };
94
+ }
95
+ canStartGoal(goal, allGoals) {
96
+ if (!goal.dependsOn || goal.dependsOn.length === 0) {
97
+ return { canStart: true };
98
+ }
99
+ const waitingOn = [];
100
+ for (const depHash of goal.dependsOn) {
101
+ const depGoal = allGoals.find((g) => g.hash === depHash);
102
+ if (!depGoal) {
103
+ waitingOn.push(depHash);
104
+ }
105
+ else if (depGoal.status !== 'completed') {
106
+ waitingOn.push(depHash);
107
+ }
108
+ }
109
+ if (waitingOn.length > 0) {
110
+ return {
111
+ canStart: false,
112
+ reason: `Waiting on ${waitingOn.length} dependent goal(s)`,
113
+ waitingOn,
114
+ };
115
+ }
116
+ return { canStart: true };
117
+ }
118
+ getBlockedBy(goalHash, allGoals) {
119
+ const blocked = [];
120
+ for (const goal of allGoals) {
121
+ if (goal.dependsOn?.includes(goalHash)) {
122
+ blocked.push(goal.hash);
123
+ }
124
+ }
125
+ return blocked;
126
+ }
127
+ wouldCreateCycle(fromGoal, toGoal, allGoals) {
128
+ const visited = new Set();
129
+ const stack = [toGoal];
130
+ while (stack.length > 0) {
131
+ const current = stack.pop();
132
+ if (visited.has(current)) {
133
+ continue;
134
+ }
135
+ visited.add(current);
136
+ if (current === fromGoal) {
137
+ return true;
138
+ }
139
+ const goal = allGoals.find((g) => g.hash === current);
140
+ if (goal?.dependsOn) {
141
+ for (const dep of goal.dependsOn) {
142
+ stack.push(dep);
143
+ }
144
+ }
145
+ }
146
+ return false;
147
+ }
148
+ resolveTasks(tasks, _goalHash) {
149
+ const blocked = new Map();
150
+ const completed = new Set();
151
+ const pending = [];
152
+ for (const task of tasks) {
153
+ if (task.status === 'completed') {
154
+ completed.add(task.id);
155
+ }
156
+ else if (task.status === 'pending' || task.status === 'awaiting_approval') {
157
+ pending.push(task);
158
+ }
159
+ }
160
+ const ready = [];
161
+ for (const task of pending) {
162
+ ready.push(task);
163
+ }
164
+ ready.sort((a, b) => getPriorityWeight(b.priority) - getPriorityWeight(a.priority));
165
+ return {
166
+ orderedTasks: ready,
167
+ blocked,
168
+ };
169
+ }
170
+ getTaskExecutionOrder(tasks, milestoneOrder) {
171
+ const byMilestone = new Map();
172
+ for (const task of tasks) {
173
+ const key = task.milestoneId ?? null;
174
+ if (!byMilestone.has(key)) {
175
+ byMilestone.set(key, []);
176
+ }
177
+ byMilestone.get(key).push(task);
178
+ }
179
+ const ordered = [];
180
+ const general = byMilestone.get(null) ?? [];
181
+ general.sort((a, b) => getPriorityWeight(b.priority) - getPriorityWeight(a.priority));
182
+ ordered.push(...general);
183
+ for (const milestoneId of milestoneOrder) {
184
+ const milestoneTasks = byMilestone.get(milestoneId) ?? [];
185
+ milestoneTasks.sort((a, b) => getPriorityWeight(b.priority) - getPriorityWeight(a.priority));
186
+ ordered.push(...milestoneTasks);
187
+ }
188
+ return ordered;
189
+ }
190
+ detectCircularDependencies(graph) {
191
+ const circularGoals = [];
192
+ const visited = new Set();
193
+ const recursionStack = new Set();
194
+ const dfs = (nodeId, path) => {
195
+ if (recursionStack.has(nodeId)) {
196
+ const cycleStart = path.indexOf(nodeId);
197
+ const cycle = path.slice(cycleStart);
198
+ cycle.forEach((id) => {
199
+ if (!circularGoals.includes(id)) {
200
+ circularGoals.push(id);
201
+ }
202
+ });
203
+ return true;
204
+ }
205
+ if (visited.has(nodeId)) {
206
+ return false;
207
+ }
208
+ visited.add(nodeId);
209
+ recursionStack.add(nodeId);
210
+ path.push(nodeId);
211
+ const node = graph.get(nodeId);
212
+ if (node) {
213
+ for (const depId of node.dependsOn) {
214
+ if (dfs(depId, [...path])) {
215
+ }
216
+ }
217
+ }
218
+ recursionStack.delete(nodeId);
219
+ return false;
220
+ };
221
+ for (const nodeId of graph.keys()) {
222
+ if (!visited.has(nodeId)) {
223
+ dfs(nodeId, []);
224
+ }
225
+ }
226
+ return circularGoals;
227
+ }
228
+ topologicalSort(graph, exclude) {
229
+ const result = [];
230
+ const visited = new Set();
231
+ const temp = new Set();
232
+ const visit = (nodeId) => {
233
+ if (visited.has(nodeId) || exclude.includes(nodeId)) {
234
+ return;
235
+ }
236
+ if (temp.has(nodeId)) {
237
+ return;
238
+ }
239
+ temp.add(nodeId);
240
+ const node = graph.get(nodeId);
241
+ if (node) {
242
+ for (const depId of node.dependsOn) {
243
+ visit(depId);
244
+ }
245
+ }
246
+ temp.delete(nodeId);
247
+ visited.add(nodeId);
248
+ if (node && node.status === 'ready') {
249
+ result.push(nodeId);
250
+ }
251
+ };
252
+ for (const nodeId of graph.keys()) {
253
+ visit(nodeId);
254
+ }
255
+ return result;
256
+ }
257
+ }
258
+ export function getTransitiveDependencies(goalHash, allGoals) {
259
+ const result = new Set();
260
+ const stack = [goalHash];
261
+ while (stack.length > 0) {
262
+ const current = stack.pop();
263
+ const goal = allGoals.find((g) => g.hash === current);
264
+ if (goal?.dependsOn) {
265
+ for (const dep of goal.dependsOn) {
266
+ if (!result.has(dep)) {
267
+ result.add(dep);
268
+ stack.push(dep);
269
+ }
270
+ }
271
+ }
272
+ }
273
+ return Array.from(result);
274
+ }
275
+ export function getTransitiveDependents(goalHash, allGoals) {
276
+ const result = new Set();
277
+ const stack = [goalHash];
278
+ while (stack.length > 0) {
279
+ const current = stack.pop();
280
+ for (const goal of allGoals) {
281
+ if (goal.dependsOn?.includes(current) && !result.has(goal.hash)) {
282
+ result.add(goal.hash);
283
+ stack.push(goal.hash);
284
+ }
285
+ }
286
+ }
287
+ return Array.from(result);
288
+ }
289
+ export function calculateCriticalPath(goals) {
290
+ const endNodes = goals.filter((g) => {
291
+ const hasDependents = goals.some((other) => other.dependsOn?.includes(g.hash));
292
+ return !hasDependents && g.status !== 'completed';
293
+ });
294
+ if (endNodes.length === 0) {
295
+ return [];
296
+ }
297
+ let longestPath = [];
298
+ for (const endNode of endNodes) {
299
+ const path = findLongestPath(endNode.hash, goals, new Set());
300
+ if (path.length > longestPath.length) {
301
+ longestPath = path;
302
+ }
303
+ }
304
+ return longestPath.reverse();
305
+ }
306
+ function findLongestPath(goalHash, allGoals, visited) {
307
+ if (visited.has(goalHash)) {
308
+ return [];
309
+ }
310
+ visited.add(goalHash);
311
+ const goal = allGoals.find((g) => g.hash === goalHash);
312
+ if (!goal) {
313
+ return [goalHash];
314
+ }
315
+ if (!goal.dependsOn || goal.dependsOn.length === 0) {
316
+ return [goalHash];
317
+ }
318
+ let longestDepPath = [];
319
+ for (const depHash of goal.dependsOn) {
320
+ const depPath = findLongestPath(depHash, allGoals, new Set(visited));
321
+ if (depPath.length > longestDepPath.length) {
322
+ longestDepPath = depPath;
323
+ }
324
+ }
325
+ return [goalHash, ...longestDepPath];
326
+ }
327
+ export function createDependencyResolver(options = {}) {
328
+ return new DependencyResolver(options);
329
+ }
@@ -0,0 +1,133 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { Goal, GoalHash, Task, TaskStatus, Logger } from './types.js';
3
+ import { GoalError } from './errors.js';
4
+ import type { ExecutionResult } from './TaskExecutor.js';
5
+ export type RecoveryStrategy = 'retry' | 'skip' | 'rollback' | 'escalate' | 'abort';
6
+ export type ErrorCategory = 'transient' | 'permission' | 'validation' | 'resource' | 'timeout' | 'network' | 'system' | 'unknown';
7
+ export interface Checkpoint {
8
+ readonly id: string;
9
+ readonly goalHash: GoalHash;
10
+ readonly taskId: number;
11
+ readonly taskStatus: TaskStatus;
12
+ readonly timestamp: Date;
13
+ readonly stateData: CheckpointState;
14
+ readonly description?: string;
15
+ }
16
+ export interface CheckpointState {
17
+ readonly completedTasks: number[];
18
+ readonly pendingTasks: number[];
19
+ readonly customData?: Record<string, unknown>;
20
+ }
21
+ export interface ErrorAnalysis {
22
+ readonly category: ErrorCategory;
23
+ readonly rootCause: string;
24
+ readonly isRecoverable: boolean;
25
+ readonly recommendedStrategy: RecoveryStrategy;
26
+ readonly confidence: number;
27
+ readonly suggestions: string[];
28
+ readonly relatedErrors?: string[];
29
+ }
30
+ export interface RecoveryAction {
31
+ readonly type: RecoveryStrategy;
32
+ readonly taskId: number;
33
+ readonly goalHash: GoalHash;
34
+ readonly attempt: number;
35
+ readonly maxAttempts: number;
36
+ readonly delayMs: number;
37
+ readonly checkpointId?: string;
38
+ readonly timestamp: Date;
39
+ }
40
+ export interface RecoveryResult {
41
+ readonly success: boolean;
42
+ readonly strategy: RecoveryStrategy;
43
+ readonly details: string;
44
+ readonly newStatus?: TaskStatus;
45
+ readonly shouldContinue: boolean;
46
+ }
47
+ export interface RetryConfig {
48
+ readonly maxAttempts: number;
49
+ readonly baseDelayMs: number;
50
+ readonly multiplier: number;
51
+ readonly maxDelayMs: number;
52
+ readonly jitter: number;
53
+ }
54
+ export interface ErrorRecoveryOptions {
55
+ readonly logger?: Logger;
56
+ readonly retryConfig?: Partial<RetryConfig>;
57
+ readonly maxCheckpointsPerGoal?: number;
58
+ readonly autoRetryTransient?: boolean;
59
+ readonly escalateThreshold?: number;
60
+ }
61
+ export interface ErrorRecoveryEvents {
62
+ 'checkpoint-created': [Checkpoint];
63
+ 'checkpoint-restored': [Checkpoint];
64
+ 'error-analyzed': [ErrorAnalysis, ExecutionResult];
65
+ 'recovery-started': [RecoveryAction];
66
+ 'recovery-completed': [RecoveryResult, RecoveryAction];
67
+ 'recovery-failed': [RecoveryResult, RecoveryAction];
68
+ 'escalation-triggered': [{
69
+ goalHash: GoalHash;
70
+ taskId: number;
71
+ reason: string;
72
+ }];
73
+ 'error': [Error];
74
+ }
75
+ export declare class ErrorRecoveryError extends GoalError {
76
+ constructor(message: string, cause?: Error);
77
+ }
78
+ export declare class CheckpointNotFoundError extends GoalError {
79
+ readonly checkpointId: string;
80
+ constructor(checkpointId: string);
81
+ }
82
+ export declare class ErrorRecovery extends EventEmitter<ErrorRecoveryEvents> {
83
+ private readonly logger;
84
+ private readonly retryConfig;
85
+ private readonly maxCheckpointsPerGoal;
86
+ private readonly autoRetryTransient;
87
+ private readonly escalateThreshold;
88
+ private readonly checkpoints;
89
+ private readonly failureCounts;
90
+ private readonly retryState;
91
+ constructor(options?: ErrorRecoveryOptions);
92
+ createCheckpoint(goal: Goal, task: Task, state: CheckpointState, description?: string): Checkpoint;
93
+ getCheckpoints(goalHash: GoalHash): Checkpoint[];
94
+ getCheckpoint(checkpointId: string): Checkpoint | null;
95
+ restoreCheckpoint(checkpointId: string, restoreFunction: (state: CheckpointState) => Promise<void>): Promise<void>;
96
+ clearCheckpoints(goalHash: GoalHash): void;
97
+ analyzeError(result: ExecutionResult): ErrorAnalysis;
98
+ private categorizeError;
99
+ private isRecoverable;
100
+ private recommendStrategy;
101
+ private generateSuggestions;
102
+ private extractRootCause;
103
+ private calculateConfidence;
104
+ executeRecovery(action: RecoveryAction, handlers: {
105
+ retry: (taskId: number) => Promise<ExecutionResult>;
106
+ skip: (taskId: number) => Promise<void>;
107
+ rollback: (checkpointId: string) => Promise<void>;
108
+ escalate: (taskId: number, goalHash: GoalHash) => Promise<void>;
109
+ abort: (goalHash: GoalHash) => Promise<void>;
110
+ }): Promise<RecoveryResult>;
111
+ createRecoveryAction(strategy: RecoveryStrategy, taskId: number, goalHash: GoalHash, options?: {
112
+ checkpointId?: string;
113
+ customDelay?: number;
114
+ }): RecoveryAction;
115
+ private calculateRetryDelay;
116
+ private updateRetryState;
117
+ canRetry(taskId: number): boolean;
118
+ getRemainingRetries(taskId: number): number;
119
+ resetRetryState(taskId: number): void;
120
+ recordFailure(taskId: number): number;
121
+ getFailureCount(taskId: number): number;
122
+ shouldEscalate(taskId: number): boolean;
123
+ private generateCheckpointId;
124
+ private delay;
125
+ clearAll(): void;
126
+ getStats(): {
127
+ totalCheckpoints: number;
128
+ goalCheckpoints: Map<GoalHash, number>;
129
+ failedTasks: number;
130
+ pendingRetries: number;
131
+ };
132
+ }
133
+ export declare function createErrorRecovery(options?: ErrorRecoveryOptions): ErrorRecovery;