@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
@@ -0,0 +1,378 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { GoalError } from './errors.js';
3
+ const noopLogger = {
4
+ debug: () => { },
5
+ info: () => { },
6
+ warn: () => { },
7
+ error: () => { },
8
+ };
9
+ const DEFAULT_APPROVAL_EXPIRY_MS = 5 * 60 * 1000;
10
+ const DEFAULT_MAX_MESSAGE_LENGTH = 2000;
11
+ const MODIFICATION_ACTIONS = new Set([
12
+ 'create',
13
+ 'update',
14
+ 'delete',
15
+ 'pause',
16
+ 'resume',
17
+ 'complete',
18
+ 'abandon',
19
+ 'edit',
20
+ 'modify',
21
+ 'change',
22
+ 'set',
23
+ 'add',
24
+ 'remove',
25
+ ]);
26
+ export class GoalCommsError extends GoalError {
27
+ constructor(message, cause) {
28
+ super('COMMS_ERROR', message, cause ? { cause } : {});
29
+ }
30
+ }
31
+ export class ApprovalTimeoutError extends GoalError {
32
+ requestId;
33
+ taskId;
34
+ constructor(requestId, taskId) {
35
+ super('APPROVAL_TIMEOUT', `Approval request ${requestId} timed out`);
36
+ this.requestId = requestId;
37
+ this.taskId = taskId;
38
+ }
39
+ }
40
+ export class GoalCommsHandler extends EventEmitter {
41
+ logger;
42
+ sendFunction;
43
+ approvalExpiryMs;
44
+ includeDetails;
45
+ maxMessageLength;
46
+ pendingApprovals = new Map();
47
+ constructor(options = {}) {
48
+ super();
49
+ this.logger = options.logger ?? noopLogger;
50
+ this.sendFunction = options.sendFunction;
51
+ this.approvalExpiryMs = options.approvalExpiryMs ?? DEFAULT_APPROVAL_EXPIRY_MS;
52
+ this.includeDetails = options.includeDetails ?? true;
53
+ this.maxMessageLength = options.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH;
54
+ }
55
+ async sendNotification(subtype, goal, message, details) {
56
+ const notification = {
57
+ type: 'goal_notification',
58
+ subtype,
59
+ goalHash: goal.hash,
60
+ goalName: goal.name,
61
+ message: this.truncate(message, this.maxMessageLength),
62
+ details: this.includeDetails ? details : undefined,
63
+ timestamp: new Date(),
64
+ };
65
+ await this.send(notification);
66
+ this.emit('notification-sent', notification);
67
+ this.logger.debug('GOAL_COMMS', 'Notification sent', {
68
+ subtype,
69
+ goalHash: goal.hash,
70
+ });
71
+ }
72
+ async notifyTasksGenerated(goal, taskCount) {
73
+ await this.sendNotification('tasks_generated', goal, `${taskCount} new task${taskCount === 1 ? '' : 's'} generated for "${goal.name}"`, { taskCount });
74
+ }
75
+ async notifyMilestoneReached(goal, milestoneTitle, completedCount, totalCount) {
76
+ await this.sendNotification('milestone_reached', goal, `Milestone completed: "${milestoneTitle}" (${completedCount}/${totalCount})`, { milestoneTitle, completedCount, totalCount });
77
+ }
78
+ async notifyReviewDue(goal) {
79
+ await this.sendNotification('review_due', goal, `Review due for goal "${goal.name}"`);
80
+ }
81
+ async notifyGoalCompleted(goal) {
82
+ await this.sendNotification('goal_completed', goal, `Goal completed: "${goal.name}"`);
83
+ }
84
+ async notifyTaskCompleted(goal, task) {
85
+ await this.sendNotification('task_completed', goal, `Task completed: "${task.title}"`, { taskId: task.id, taskType: task.taskType });
86
+ }
87
+ async notifyTaskFailed(goal, task, error) {
88
+ await this.sendNotification('task_failed', goal, `Task failed: "${task.title}" - ${error}`, { taskId: task.id, taskType: task.taskType, error });
89
+ }
90
+ async notifyDailySummary(goals, completedTasks, pendingTasks) {
91
+ if (goals.length === 0)
92
+ return;
93
+ const message = [
94
+ `Daily Summary:`,
95
+ `Active goals: ${goals.filter((g) => g.status === 'active').length}`,
96
+ `Tasks completed today: ${completedTasks}`,
97
+ `Pending tasks: ${pendingTasks}`,
98
+ ].join('\n');
99
+ const notification = {
100
+ type: 'goal_notification',
101
+ subtype: 'daily_summary',
102
+ goalHash: 'system',
103
+ goalName: 'Daily Summary',
104
+ message: this.truncate(message, this.maxMessageLength),
105
+ details: this.includeDetails
106
+ ? { activeGoals: goals.length, completedTasks, pendingTasks }
107
+ : undefined,
108
+ timestamp: new Date(),
109
+ };
110
+ await this.send(notification);
111
+ this.emit('notification-sent', notification);
112
+ }
113
+ async requestApproval(goal, task, permissionRequired) {
114
+ const requestId = this.generateRequestId();
115
+ const expiresAt = new Date(Date.now() + this.approvalExpiryMs);
116
+ const request = {
117
+ type: 'goal_task_approval',
118
+ requestId,
119
+ goalHash: goal.hash,
120
+ goalName: goal.name,
121
+ taskId: task.id,
122
+ taskTitle: task.title,
123
+ taskDescription: task.description,
124
+ taskType: task.taskType,
125
+ permissionRequired,
126
+ options: ['approve', 'deny', 'skip', 'later'],
127
+ expiresAt,
128
+ timestamp: new Date(),
129
+ };
130
+ await this.send(request);
131
+ this.emit('approval-sent', request);
132
+ this.logger.debug('GOAL_COMMS', 'Approval request sent', {
133
+ requestId,
134
+ taskId: task.id,
135
+ });
136
+ return new Promise((resolve) => {
137
+ const timeoutId = setTimeout(() => {
138
+ this.pendingApprovals.delete(requestId);
139
+ resolve('timeout');
140
+ }, this.approvalExpiryMs);
141
+ this.pendingApprovals.set(requestId, {
142
+ request,
143
+ resolver: resolve,
144
+ timeoutId,
145
+ });
146
+ });
147
+ }
148
+ handleApprovalResponse(requestId, response, userId) {
149
+ const pending = this.pendingApprovals.get(requestId);
150
+ if (!pending) {
151
+ this.logger.warn('GOAL_COMMS', 'Unknown approval request', { requestId });
152
+ return;
153
+ }
154
+ clearTimeout(pending.timeoutId);
155
+ this.pendingApprovals.delete(requestId);
156
+ this.emit('approval-received', { requestId, response, userId });
157
+ pending.resolver(response);
158
+ this.logger.debug('GOAL_COMMS', 'Approval response received', {
159
+ requestId,
160
+ response,
161
+ userId,
162
+ });
163
+ }
164
+ cancelApprovalRequest(requestId) {
165
+ const pending = this.pendingApprovals.get(requestId);
166
+ if (!pending) {
167
+ return false;
168
+ }
169
+ clearTimeout(pending.timeoutId);
170
+ this.pendingApprovals.delete(requestId);
171
+ pending.resolver('timeout');
172
+ return true;
173
+ }
174
+ getPendingApprovals() {
175
+ return Array.from(this.pendingApprovals.values()).map((p) => p.request);
176
+ }
177
+ async handleViewRequest(request, dataProvider) {
178
+ this.emit('view-request', request);
179
+ try {
180
+ let data = null;
181
+ let message = '';
182
+ switch (request.action) {
183
+ case 'list': {
184
+ const goals = await dataProvider.listGoals(request.filters);
185
+ data = goals;
186
+ message = `Found ${goals.length} goal${goals.length === 1 ? '' : 's'}`;
187
+ break;
188
+ }
189
+ case 'show': {
190
+ if (!request.goalHash) {
191
+ return this.createViewResponse(request, null, false, 'Goal ID required');
192
+ }
193
+ const goal = await dataProvider.getGoal(request.goalHash);
194
+ if (!goal) {
195
+ return this.createViewResponse(request, null, false, 'Goal not found');
196
+ }
197
+ data = goal;
198
+ message = `Goal: ${goal.name}`;
199
+ break;
200
+ }
201
+ case 'tasks': {
202
+ if (!request.goalHash) {
203
+ return this.createViewResponse(request, null, false, 'Goal ID required');
204
+ }
205
+ const tasks = await dataProvider.listTasks(request.goalHash, request.filters?.taskStatus ? { status: request.filters.taskStatus } : undefined);
206
+ data = tasks;
207
+ message = `Found ${tasks.length} task${tasks.length === 1 ? '' : 's'}`;
208
+ break;
209
+ }
210
+ case 'progress':
211
+ case 'summary': {
212
+ if (!request.goalHash) {
213
+ return this.createViewResponse(request, null, false, 'Goal ID required');
214
+ }
215
+ const progress = await dataProvider.getProgress(request.goalHash);
216
+ if (!progress) {
217
+ return this.createViewResponse(request, null, false, 'Goal not found');
218
+ }
219
+ data = progress;
220
+ message = `Progress: ${progress.progress}% (${progress.tasks.completed}/${progress.tasks.total} tasks)`;
221
+ break;
222
+ }
223
+ default:
224
+ return this.createViewResponse(request, null, false, `Unknown action: ${request.action}`);
225
+ }
226
+ const response = this.createViewResponse(request, data, true, message);
227
+ this.emit('view-response-sent', response);
228
+ return response;
229
+ }
230
+ catch (error) {
231
+ const message = error instanceof Error ? error.message : String(error);
232
+ this.logger.error('GOAL_COMMS', 'View request failed', { error: message });
233
+ return this.createViewResponse(request, null, false, message);
234
+ }
235
+ }
236
+ createViewResponse(request, data, success, message, error) {
237
+ return {
238
+ type: 'goal_view_response',
239
+ requestId: request.requestId,
240
+ action: request.action,
241
+ data,
242
+ message: message ?? '',
243
+ success,
244
+ error,
245
+ timestamp: new Date(),
246
+ };
247
+ }
248
+ isModificationAction(action) {
249
+ const normalizedAction = action.toLowerCase().trim();
250
+ return MODIFICATION_ACTIONS.has(normalizedAction) ||
251
+ Array.from(MODIFICATION_ACTIONS).some((mod) => normalizedAction.includes(mod));
252
+ }
253
+ createModificationRedirect(requestedAction, goalHash) {
254
+ const cliCommand = this.getCliCommand(requestedAction, goalHash);
255
+ const redirect = {
256
+ type: 'goal_modification_redirect',
257
+ requestedAction,
258
+ cliCommand,
259
+ message: `Goal modifications require CLI or Native app.\nRun: ${cliCommand}`,
260
+ timestamp: new Date(),
261
+ };
262
+ this.emit('modification-redirected', redirect);
263
+ return redirect;
264
+ }
265
+ getCliCommand(action, goalHash) {
266
+ const normalizedAction = action.toLowerCase().trim();
267
+ const hashArg = goalHash ? ` ${goalHash}` : '';
268
+ if (normalizedAction.includes('create') || normalizedAction.includes('add')) {
269
+ return 'flowdot goals create "description"';
270
+ }
271
+ if (normalizedAction.includes('update') || normalizedAction.includes('edit') ||
272
+ normalizedAction.includes('modify') || normalizedAction.includes('change')) {
273
+ return `flowdot goals update${hashArg} "changes"`;
274
+ }
275
+ if (normalizedAction.includes('delete') || normalizedAction.includes('remove')) {
276
+ return `flowdot goals delete${hashArg}`;
277
+ }
278
+ if (normalizedAction.includes('pause')) {
279
+ return `flowdot goals pause${hashArg}`;
280
+ }
281
+ if (normalizedAction.includes('resume')) {
282
+ return `flowdot goals resume${hashArg}`;
283
+ }
284
+ if (normalizedAction.includes('complete')) {
285
+ return `flowdot goals complete${hashArg}`;
286
+ }
287
+ return `flowdot goals --help`;
288
+ }
289
+ formatGoalSummary(goal) {
290
+ const parts = [
291
+ `Goal: ${goal.name}`,
292
+ `Status: ${goal.status}`,
293
+ `Priority: ${goal.priority}`,
294
+ ];
295
+ if (goal.progress !== undefined) {
296
+ parts.push(`Progress: ${goal.progress}%`);
297
+ }
298
+ if (goal.deadline) {
299
+ const daysUntil = Math.ceil((goal.deadline.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
300
+ parts.push(`Deadline: ${daysUntil > 0 ? `${daysUntil} days` : 'Overdue'}`);
301
+ }
302
+ return parts.join('\n');
303
+ }
304
+ formatTaskSummary(task) {
305
+ return [
306
+ `Task: ${task.title}`,
307
+ `Type: ${task.taskType}`,
308
+ `Status: ${task.status}`,
309
+ task.description ? `Description: ${this.truncate(task.description, 100)}` : '',
310
+ ]
311
+ .filter(Boolean)
312
+ .join('\n');
313
+ }
314
+ formatProgressSummary(progress) {
315
+ const parts = [
316
+ `Goal: ${progress.goalName}`,
317
+ `Progress: ${progress.progress}%`,
318
+ `Status: ${progress.status}`,
319
+ `Milestones: ${progress.milestones.completed}/${progress.milestones.total}`,
320
+ `Tasks: ${progress.tasks.completed}/${progress.tasks.total}`,
321
+ ];
322
+ if (progress.tasks.pending > 0) {
323
+ parts.push(`Pending: ${progress.tasks.pending}`);
324
+ }
325
+ if (progress.tasks.failed > 0) {
326
+ parts.push(`Failed: ${progress.tasks.failed}`);
327
+ }
328
+ if (progress.daysUntilDeadline !== undefined) {
329
+ if (progress.daysUntilDeadline > 0) {
330
+ parts.push(`Deadline: ${progress.daysUntilDeadline} days`);
331
+ }
332
+ else if (progress.daysUntilDeadline === 0) {
333
+ parts.push(`Deadline: Today`);
334
+ }
335
+ else {
336
+ parts.push(`Deadline: Overdue by ${Math.abs(progress.daysUntilDeadline)} days`);
337
+ }
338
+ }
339
+ return parts.join('\n');
340
+ }
341
+ async send(payload) {
342
+ if (!this.sendFunction) {
343
+ this.logger.warn('GOAL_COMMS', 'No send function configured, message not sent');
344
+ return;
345
+ }
346
+ try {
347
+ await this.sendFunction(payload);
348
+ }
349
+ catch (error) {
350
+ const err = error instanceof Error ? error : new Error(String(error));
351
+ this.logger.error('GOAL_COMMS', 'Failed to send message', {
352
+ type: payload.type,
353
+ error: err.message,
354
+ });
355
+ this.emit('error', new GoalCommsError('Failed to send message', err));
356
+ }
357
+ }
358
+ generateRequestId() {
359
+ return `goal_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
360
+ }
361
+ truncate(text, maxLength) {
362
+ if (text.length <= maxLength) {
363
+ return text;
364
+ }
365
+ return text.substring(0, maxLength - 3) + '...';
366
+ }
367
+ dispose() {
368
+ for (const [, pending] of this.pendingApprovals) {
369
+ clearTimeout(pending.timeoutId);
370
+ pending.resolver('timeout');
371
+ }
372
+ this.pendingApprovals.clear();
373
+ this.removeAllListeners();
374
+ }
375
+ }
376
+ export function createGoalCommsHandler(options = {}) {
377
+ return new GoalCommsHandler(options);
378
+ }
@@ -0,0 +1,164 @@
1
+ import { EventEmitter } from 'events';
2
+ import type { Goal, GoalHash, Milestone, Task, GoalMemory, MetaGoal, Logger } from './types.js';
3
+ import type { GoalProgress, ProgressSnapshot } from './ProgressTracker.js';
4
+ import type { TaskFeedbackEntry } from './TaskFeedback.js';
5
+ export declare const EXPORT_FORMAT_VERSION = "1.0.0";
6
+ export type ExportType = 'full' | 'template' | 'backup' | 'archive';
7
+ export type ExportScope = 'single' | 'multiple' | 'all';
8
+ export interface ExportOptions {
9
+ readonly type?: ExportType;
10
+ readonly includeProgress?: boolean;
11
+ readonly includeSnapshots?: boolean;
12
+ readonly includeFeedback?: boolean;
13
+ readonly includeMetaGoals?: boolean;
14
+ readonly stripUserData?: boolean;
15
+ readonly compress?: boolean;
16
+ readonly prettyPrint?: boolean;
17
+ }
18
+ export interface ExportedGoal {
19
+ readonly hash: GoalHash;
20
+ readonly title: string;
21
+ readonly description?: string;
22
+ readonly status: string;
23
+ readonly priority: string;
24
+ readonly deadline?: string;
25
+ readonly approvalMode: string;
26
+ readonly parentHash?: GoalHash;
27
+ readonly dependencyHashes?: GoalHash[];
28
+ readonly tags?: string[];
29
+ readonly createdAt: string;
30
+ readonly updatedAt: string;
31
+ readonly milestones: ExportedMilestone[];
32
+ readonly tasks: ExportedTask[];
33
+ readonly memories: ExportedMemory[];
34
+ readonly progress?: GoalProgress;
35
+ readonly snapshots?: ProgressSnapshot[];
36
+ readonly feedback?: TaskFeedbackEntry[];
37
+ }
38
+ export interface ExportedMilestone {
39
+ readonly id: number;
40
+ readonly title: string;
41
+ readonly description?: string;
42
+ readonly status: string;
43
+ readonly order: number;
44
+ readonly deadline?: string;
45
+ readonly createdAt: string;
46
+ readonly updatedAt: string;
47
+ }
48
+ export interface ExportedTask {
49
+ readonly id: number;
50
+ readonly milestoneId?: number;
51
+ readonly title: string;
52
+ readonly description?: string;
53
+ readonly type: string;
54
+ readonly status: string;
55
+ readonly priority: number;
56
+ readonly params?: Record<string, unknown>;
57
+ readonly requiresApproval: boolean;
58
+ readonly deadline?: string;
59
+ readonly completedAt?: string;
60
+ readonly createdAt: string;
61
+ readonly updatedAt: string;
62
+ }
63
+ export interface ExportedMemory {
64
+ readonly id: number;
65
+ readonly category: string;
66
+ readonly content: string;
67
+ readonly source?: string;
68
+ readonly confidence?: number;
69
+ readonly expiresAt?: string;
70
+ readonly createdAt: string;
71
+ }
72
+ export interface ExportedMetaGoal {
73
+ readonly id: number;
74
+ readonly name: string;
75
+ readonly description?: string;
76
+ readonly scope: string;
77
+ readonly appliesTo?: string[];
78
+ readonly constraints: {
79
+ type: string;
80
+ value: string;
81
+ }[];
82
+ readonly priority: number;
83
+ readonly isActive: boolean;
84
+ readonly createdAt: string;
85
+ readonly updatedAt: string;
86
+ }
87
+ export interface ExportManifest {
88
+ readonly version: string;
89
+ readonly exportType: ExportType;
90
+ readonly exportedAt: string;
91
+ readonly exportedBy?: string;
92
+ readonly goalCount: number;
93
+ readonly metaGoalCount: number;
94
+ readonly totalMilestones: number;
95
+ readonly totalTasks: number;
96
+ readonly totalMemories: number;
97
+ readonly checksum?: string;
98
+ readonly options: ExportOptions;
99
+ }
100
+ export interface ExportPackage {
101
+ readonly manifest: ExportManifest;
102
+ readonly goals: ExportedGoal[];
103
+ readonly metaGoals?: ExportedMetaGoal[];
104
+ }
105
+ export interface ExportResult {
106
+ readonly success: boolean;
107
+ readonly package?: ExportPackage;
108
+ readonly serialized?: string;
109
+ readonly errors: string[];
110
+ readonly warnings: string[];
111
+ readonly statistics: {
112
+ goalsExported: number;
113
+ milestonesExported: number;
114
+ tasksExported: number;
115
+ memoriesExported: number;
116
+ metaGoalsExported: number;
117
+ exportSize: number;
118
+ };
119
+ }
120
+ export interface ExportDataProvider {
121
+ getGoals(hashes?: GoalHash[]): Promise<Goal[]>;
122
+ getMilestones(goalHash: GoalHash): Promise<Milestone[]>;
123
+ getTasks(goalHash: GoalHash): Promise<Task[]>;
124
+ getMemories(goalHash: GoalHash): Promise<GoalMemory[]>;
125
+ getMetaGoals?(): Promise<MetaGoal[]>;
126
+ getProgress?(goalHash: GoalHash): GoalProgress | undefined;
127
+ getSnapshots?(goalHash: GoalHash): ProgressSnapshot[];
128
+ getFeedback?(goalHash: GoalHash): TaskFeedbackEntry[];
129
+ }
130
+ export interface GoalExporterOptions {
131
+ readonly logger?: Logger;
132
+ readonly defaultOptions?: ExportOptions;
133
+ }
134
+ export interface GoalExporterEvents {
135
+ 'export:started': [goalCount: number];
136
+ 'export:progress': [current: number, total: number];
137
+ 'export:completed': [result: ExportResult];
138
+ 'export:error': [error: Error];
139
+ warning: [message: string];
140
+ }
141
+ export declare class GoalExporter extends EventEmitter<GoalExporterEvents> {
142
+ private readonly logger;
143
+ private readonly defaultOptions;
144
+ constructor(options?: GoalExporterOptions);
145
+ exportGoal(goalHash: GoalHash, dataProvider: ExportDataProvider, options?: ExportOptions): Promise<ExportResult>;
146
+ exportGoals(goalHashes: GoalHash[], dataProvider: ExportDataProvider, options?: ExportOptions): Promise<ExportResult>;
147
+ exportAll(dataProvider: ExportDataProvider, options?: ExportOptions): Promise<ExportResult>;
148
+ createTemplate(goalHash: GoalHash, dataProvider: ExportDataProvider, _templateName?: string): Promise<ExportResult>;
149
+ validateExport(data: string | ExportPackage): {
150
+ valid: boolean;
151
+ errors: string[];
152
+ warnings: string[];
153
+ };
154
+ private exportSingleGoal;
155
+ private exportMilestone;
156
+ private exportTask;
157
+ private exportMemory;
158
+ private exportMetaGoal;
159
+ private anonymizeHash;
160
+ private serialize;
161
+ private computeChecksum;
162
+ private emptyStatistics;
163
+ }
164
+ export declare function createGoalExporter(options?: GoalExporterOptions): GoalExporter;