@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.
- package/LICENSE +45 -0
- package/README.md +51 -0
- package/dist/goals/DependencyResolver.d.ts +54 -0
- package/dist/goals/DependencyResolver.js +329 -0
- package/dist/goals/ErrorRecovery.d.ts +133 -0
- package/dist/goals/ErrorRecovery.js +489 -0
- package/dist/goals/GoalApiClient.d.ts +81 -0
- package/dist/goals/GoalApiClient.js +743 -0
- package/dist/goals/GoalCache.d.ts +65 -0
- package/dist/goals/GoalCache.js +243 -0
- package/dist/goals/GoalCommsHandler.d.ts +150 -0
- package/dist/goals/GoalCommsHandler.js +378 -0
- package/dist/goals/GoalExporter.d.ts +164 -0
- package/dist/goals/GoalExporter.js +318 -0
- package/dist/goals/GoalImporter.d.ts +107 -0
- package/dist/goals/GoalImporter.js +345 -0
- package/dist/goals/GoalManager.d.ts +110 -0
- package/dist/goals/GoalManager.js +535 -0
- package/dist/goals/GoalReporter.d.ts +105 -0
- package/dist/goals/GoalReporter.js +534 -0
- package/dist/goals/GoalScheduler.d.ts +102 -0
- package/dist/goals/GoalScheduler.js +209 -0
- package/dist/goals/GoalValidator.d.ts +72 -0
- package/dist/goals/GoalValidator.js +657 -0
- package/dist/goals/MetaGoalEnforcer.d.ts +111 -0
- package/dist/goals/MetaGoalEnforcer.js +536 -0
- package/dist/goals/MilestoneBreaker.d.ts +74 -0
- package/dist/goals/MilestoneBreaker.js +348 -0
- package/dist/goals/PermissionBridge.d.ts +109 -0
- package/dist/goals/PermissionBridge.js +326 -0
- package/dist/goals/ProgressTracker.d.ts +113 -0
- package/dist/goals/ProgressTracker.js +324 -0
- package/dist/goals/ReviewScheduler.d.ts +106 -0
- package/dist/goals/ReviewScheduler.js +360 -0
- package/dist/goals/TaskExecutor.d.ts +116 -0
- package/dist/goals/TaskExecutor.js +370 -0
- package/dist/goals/TaskFeedback.d.ts +126 -0
- package/dist/goals/TaskFeedback.js +402 -0
- package/dist/goals/TaskGenerator.d.ts +75 -0
- package/dist/goals/TaskGenerator.js +329 -0
- package/dist/goals/TaskQueue.d.ts +84 -0
- package/dist/goals/TaskQueue.js +331 -0
- package/dist/goals/TaskSanitizer.d.ts +61 -0
- package/dist/goals/TaskSanitizer.js +464 -0
- package/dist/goals/errors.d.ts +116 -0
- package/dist/goals/errors.js +299 -0
- package/dist/goals/index.d.ts +24 -0
- package/dist/goals/index.js +23 -0
- package/dist/goals/types.d.ts +395 -0
- package/dist/goals/types.js +230 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/loop/DaemonIPC.d.ts +67 -0
- package/dist/loop/DaemonIPC.js +358 -0
- package/dist/loop/IntervalParser.d.ts +39 -0
- package/dist/loop/IntervalParser.js +217 -0
- package/dist/loop/LoopDaemon.d.ts +123 -0
- package/dist/loop/LoopDaemon.js +1821 -0
- package/dist/loop/LoopExecutor.d.ts +93 -0
- package/dist/loop/LoopExecutor.js +326 -0
- package/dist/loop/LoopManager.d.ts +79 -0
- package/dist/loop/LoopManager.js +476 -0
- package/dist/loop/LoopScheduler.d.ts +69 -0
- package/dist/loop/LoopScheduler.js +329 -0
- package/dist/loop/LoopStore.d.ts +57 -0
- package/dist/loop/LoopStore.js +406 -0
- package/dist/loop/LoopValidator.d.ts +55 -0
- package/dist/loop/LoopValidator.js +603 -0
- package/dist/loop/errors.d.ts +115 -0
- package/dist/loop/errors.js +312 -0
- package/dist/loop/index.d.ts +11 -0
- package/dist/loop/index.js +10 -0
- package/dist/loop/notifications/Notifier.d.ts +28 -0
- package/dist/loop/notifications/Notifier.js +78 -0
- package/dist/loop/notifications/SlackNotifier.d.ts +28 -0
- package/dist/loop/notifications/SlackNotifier.js +203 -0
- package/dist/loop/notifications/TerminalNotifier.d.ts +18 -0
- package/dist/loop/notifications/TerminalNotifier.js +72 -0
- package/dist/loop/notifications/WebhookNotifier.d.ts +24 -0
- package/dist/loop/notifications/WebhookNotifier.js +123 -0
- package/dist/loop/notifications/index.d.ts +24 -0
- package/dist/loop/notifications/index.js +109 -0
- package/dist/loop/types.d.ts +280 -0
- package/dist/loop/types.js +222 -0
- package/package.json +92 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { Goal, GoalHash, Milestone, Task, GoalMemory, MetaGoal, Logger } from './types.js';
|
|
3
|
+
export interface CacheStats {
|
|
4
|
+
readonly hits: number;
|
|
5
|
+
readonly misses: number;
|
|
6
|
+
readonly entries: number;
|
|
7
|
+
readonly hitRatio: number;
|
|
8
|
+
readonly evictions: number;
|
|
9
|
+
readonly expirations: number;
|
|
10
|
+
}
|
|
11
|
+
export interface GoalCacheOptions {
|
|
12
|
+
readonly ttlMs?: number;
|
|
13
|
+
readonly maxEntries?: number;
|
|
14
|
+
readonly logger?: Logger;
|
|
15
|
+
}
|
|
16
|
+
export interface GoalCacheEvents {
|
|
17
|
+
eviction: [type: CacheType, key: string];
|
|
18
|
+
expiration: [type: CacheType, key: string];
|
|
19
|
+
cleared: [type?: CacheType];
|
|
20
|
+
}
|
|
21
|
+
export type CacheType = 'goal' | 'milestone' | 'task' | 'memory' | 'metaGoal';
|
|
22
|
+
export declare class GoalCache extends EventEmitter<GoalCacheEvents> {
|
|
23
|
+
private readonly ttlMs;
|
|
24
|
+
private readonly maxEntries;
|
|
25
|
+
private readonly logger;
|
|
26
|
+
private readonly goals;
|
|
27
|
+
private readonly goalLists;
|
|
28
|
+
private readonly milestones;
|
|
29
|
+
private readonly tasks;
|
|
30
|
+
private readonly memories;
|
|
31
|
+
private readonly metaGoals;
|
|
32
|
+
private readonly pendingTasks;
|
|
33
|
+
private stats;
|
|
34
|
+
constructor(options?: GoalCacheOptions);
|
|
35
|
+
getGoal(hash: GoalHash): Goal | null;
|
|
36
|
+
getGoalOrThrow(hash: GoalHash): Goal;
|
|
37
|
+
setGoal(goal: Goal): void;
|
|
38
|
+
getGoalList(key?: string): Goal[] | null;
|
|
39
|
+
setGoalList(goals: Goal[], key?: string): void;
|
|
40
|
+
invalidateGoal(hash: GoalHash): void;
|
|
41
|
+
invalidateAllGoals(): void;
|
|
42
|
+
getMilestones(goalHash: GoalHash): Milestone[] | null;
|
|
43
|
+
setMilestones(goalHash: GoalHash, milestones: Milestone[]): void;
|
|
44
|
+
invalidateMilestones(goalHash: GoalHash): void;
|
|
45
|
+
getTasks(goalHash: GoalHash): Task[] | null;
|
|
46
|
+
setTasks(goalHash: GoalHash, tasks: Task[]): void;
|
|
47
|
+
invalidateTasks(goalHash: GoalHash): void;
|
|
48
|
+
invalidateAllTasks(): void;
|
|
49
|
+
getMemories(goalHash: GoalHash): GoalMemory[] | null;
|
|
50
|
+
setMemories(goalHash: GoalHash, memories: GoalMemory[]): void;
|
|
51
|
+
invalidateMemories(goalHash: GoalHash): void;
|
|
52
|
+
getMetaGoals(key?: string): MetaGoal[] | null;
|
|
53
|
+
setMetaGoals(metaGoals: MetaGoal[], key?: string): void;
|
|
54
|
+
invalidateMetaGoals(): void;
|
|
55
|
+
clearAll(): void;
|
|
56
|
+
getStats(): CacheStats;
|
|
57
|
+
resetStats(): void;
|
|
58
|
+
getTotalEntries(): number;
|
|
59
|
+
pruneExpired(): number;
|
|
60
|
+
private getFromCache;
|
|
61
|
+
private setInCache;
|
|
62
|
+
private evictLRU;
|
|
63
|
+
private pruneExpiredFromMap;
|
|
64
|
+
}
|
|
65
|
+
export declare function createGoalCache(options?: GoalCacheOptions): GoalCache;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { CacheMissError } from './errors.js';
|
|
3
|
+
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
4
|
+
const DEFAULT_MAX_ENTRIES = 1000;
|
|
5
|
+
const noopLogger = {
|
|
6
|
+
debug: () => { },
|
|
7
|
+
info: () => { },
|
|
8
|
+
warn: () => { },
|
|
9
|
+
error: () => { },
|
|
10
|
+
};
|
|
11
|
+
export class GoalCache extends EventEmitter {
|
|
12
|
+
ttlMs;
|
|
13
|
+
maxEntries;
|
|
14
|
+
logger;
|
|
15
|
+
goals;
|
|
16
|
+
goalLists;
|
|
17
|
+
milestones;
|
|
18
|
+
tasks;
|
|
19
|
+
memories;
|
|
20
|
+
metaGoals;
|
|
21
|
+
pendingTasks;
|
|
22
|
+
stats = {
|
|
23
|
+
hits: 0,
|
|
24
|
+
misses: 0,
|
|
25
|
+
evictions: 0,
|
|
26
|
+
expirations: 0,
|
|
27
|
+
};
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
super();
|
|
30
|
+
this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
31
|
+
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
32
|
+
this.logger = options.logger ?? noopLogger;
|
|
33
|
+
this.goals = new Map();
|
|
34
|
+
this.goalLists = new Map();
|
|
35
|
+
this.milestones = new Map();
|
|
36
|
+
this.tasks = new Map();
|
|
37
|
+
this.memories = new Map();
|
|
38
|
+
this.metaGoals = new Map();
|
|
39
|
+
this.pendingTasks = null;
|
|
40
|
+
this.logger.debug('GOAL_CACHE', 'Cache initialized', {
|
|
41
|
+
ttlMs: this.ttlMs,
|
|
42
|
+
maxEntries: this.maxEntries,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
getGoal(hash) {
|
|
46
|
+
return this.getFromCache(this.goals, hash, 'goal');
|
|
47
|
+
}
|
|
48
|
+
getGoalOrThrow(hash) {
|
|
49
|
+
const goal = this.getGoal(hash);
|
|
50
|
+
if (!goal) {
|
|
51
|
+
throw new CacheMissError(`goal:${hash}`);
|
|
52
|
+
}
|
|
53
|
+
return goal;
|
|
54
|
+
}
|
|
55
|
+
setGoal(goal) {
|
|
56
|
+
this.setInCache(this.goals, goal.hash, goal, 'goal');
|
|
57
|
+
this.logger.debug('GOAL_CACHE', 'Cached goal', { hash: goal.hash, name: goal.name });
|
|
58
|
+
}
|
|
59
|
+
getGoalList(key = 'default') {
|
|
60
|
+
return this.getFromCache(this.goalLists, key, 'goal');
|
|
61
|
+
}
|
|
62
|
+
setGoalList(goals, key = 'default') {
|
|
63
|
+
this.setInCache(this.goalLists, key, goals, 'goal');
|
|
64
|
+
for (const goal of goals) {
|
|
65
|
+
this.setGoal(goal);
|
|
66
|
+
}
|
|
67
|
+
this.logger.debug('GOAL_CACHE', 'Cached goal list', { key, count: goals.length });
|
|
68
|
+
}
|
|
69
|
+
invalidateGoal(hash) {
|
|
70
|
+
this.goals.delete(hash);
|
|
71
|
+
this.goalLists.clear();
|
|
72
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated goal', { hash });
|
|
73
|
+
}
|
|
74
|
+
invalidateAllGoals() {
|
|
75
|
+
this.goals.clear();
|
|
76
|
+
this.goalLists.clear();
|
|
77
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated all goals');
|
|
78
|
+
this.emit('cleared', 'goal');
|
|
79
|
+
}
|
|
80
|
+
getMilestones(goalHash) {
|
|
81
|
+
return this.getFromCache(this.milestones, goalHash, 'milestone');
|
|
82
|
+
}
|
|
83
|
+
setMilestones(goalHash, milestones) {
|
|
84
|
+
this.setInCache(this.milestones, goalHash, milestones, 'milestone');
|
|
85
|
+
this.logger.debug('GOAL_CACHE', 'Cached milestones', { goalHash, count: milestones.length });
|
|
86
|
+
}
|
|
87
|
+
invalidateMilestones(goalHash) {
|
|
88
|
+
this.milestones.delete(goalHash);
|
|
89
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated milestones', { goalHash });
|
|
90
|
+
}
|
|
91
|
+
getTasks(goalHash) {
|
|
92
|
+
return this.getFromCache(this.tasks, goalHash, 'task');
|
|
93
|
+
}
|
|
94
|
+
setTasks(goalHash, tasks) {
|
|
95
|
+
this.setInCache(this.tasks, goalHash, tasks, 'task');
|
|
96
|
+
this.logger.debug('GOAL_CACHE', 'Cached tasks', { goalHash, count: tasks.length });
|
|
97
|
+
}
|
|
98
|
+
invalidateTasks(goalHash) {
|
|
99
|
+
this.tasks.delete(goalHash);
|
|
100
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated tasks', { goalHash });
|
|
101
|
+
}
|
|
102
|
+
invalidateAllTasks() {
|
|
103
|
+
this.tasks.clear();
|
|
104
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated all tasks');
|
|
105
|
+
this.emit('cleared', 'task');
|
|
106
|
+
}
|
|
107
|
+
getMemories(goalHash) {
|
|
108
|
+
return this.getFromCache(this.memories, goalHash, 'memory');
|
|
109
|
+
}
|
|
110
|
+
setMemories(goalHash, memories) {
|
|
111
|
+
this.setInCache(this.memories, goalHash, memories, 'memory');
|
|
112
|
+
this.logger.debug('GOAL_CACHE', 'Cached memories', { goalHash, count: memories.length });
|
|
113
|
+
}
|
|
114
|
+
invalidateMemories(goalHash) {
|
|
115
|
+
this.memories.delete(goalHash);
|
|
116
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated memories', { goalHash });
|
|
117
|
+
}
|
|
118
|
+
getMetaGoals(key = 'all') {
|
|
119
|
+
return this.getFromCache(this.metaGoals, key, 'metaGoal');
|
|
120
|
+
}
|
|
121
|
+
setMetaGoals(metaGoals, key = 'all') {
|
|
122
|
+
this.setInCache(this.metaGoals, key, metaGoals, 'metaGoal');
|
|
123
|
+
this.logger.debug('GOAL_CACHE', 'Cached meta-goals', { key, count: metaGoals.length });
|
|
124
|
+
}
|
|
125
|
+
invalidateMetaGoals() {
|
|
126
|
+
this.metaGoals.clear();
|
|
127
|
+
this.logger.debug('GOAL_CACHE', 'Invalidated meta-goals');
|
|
128
|
+
this.emit('cleared', 'metaGoal');
|
|
129
|
+
}
|
|
130
|
+
clearAll() {
|
|
131
|
+
this.goals.clear();
|
|
132
|
+
this.goalLists.clear();
|
|
133
|
+
this.milestones.clear();
|
|
134
|
+
this.tasks.clear();
|
|
135
|
+
this.memories.clear();
|
|
136
|
+
this.metaGoals.clear();
|
|
137
|
+
this.logger.info('GOAL_CACHE', 'Cleared all caches');
|
|
138
|
+
this.emit('cleared');
|
|
139
|
+
}
|
|
140
|
+
getStats() {
|
|
141
|
+
const totalRequests = this.stats.hits + this.stats.misses;
|
|
142
|
+
return {
|
|
143
|
+
hits: this.stats.hits,
|
|
144
|
+
misses: this.stats.misses,
|
|
145
|
+
entries: this.getTotalEntries(),
|
|
146
|
+
hitRatio: totalRequests > 0 ? this.stats.hits / totalRequests : 0,
|
|
147
|
+
evictions: this.stats.evictions,
|
|
148
|
+
expirations: this.stats.expirations,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
resetStats() {
|
|
152
|
+
this.stats = {
|
|
153
|
+
hits: 0,
|
|
154
|
+
misses: 0,
|
|
155
|
+
evictions: 0,
|
|
156
|
+
expirations: 0,
|
|
157
|
+
};
|
|
158
|
+
this.logger.debug('GOAL_CACHE', 'Statistics reset');
|
|
159
|
+
}
|
|
160
|
+
getTotalEntries() {
|
|
161
|
+
return (this.goals.size +
|
|
162
|
+
this.goalLists.size +
|
|
163
|
+
this.milestones.size +
|
|
164
|
+
this.tasks.size +
|
|
165
|
+
this.memories.size +
|
|
166
|
+
this.metaGoals.size);
|
|
167
|
+
}
|
|
168
|
+
pruneExpired() {
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
let pruned = 0;
|
|
171
|
+
pruned += this.pruneExpiredFromMap(this.goals, 'goal', now);
|
|
172
|
+
pruned += this.pruneExpiredFromMap(this.goalLists, 'goal', now);
|
|
173
|
+
pruned += this.pruneExpiredFromMap(this.milestones, 'milestone', now);
|
|
174
|
+
pruned += this.pruneExpiredFromMap(this.tasks, 'task', now);
|
|
175
|
+
pruned += this.pruneExpiredFromMap(this.memories, 'memory', now);
|
|
176
|
+
pruned += this.pruneExpiredFromMap(this.metaGoals, 'metaGoal', now);
|
|
177
|
+
if (pruned > 0) {
|
|
178
|
+
this.logger.debug('GOAL_CACHE', 'Pruned expired entries', { count: pruned });
|
|
179
|
+
}
|
|
180
|
+
return pruned;
|
|
181
|
+
}
|
|
182
|
+
getFromCache(cache, key, type) {
|
|
183
|
+
const entry = cache.get(key);
|
|
184
|
+
if (!entry) {
|
|
185
|
+
this.stats.misses++;
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
if (entry.expiresAt < now) {
|
|
190
|
+
cache.delete(key);
|
|
191
|
+
this.stats.misses++;
|
|
192
|
+
this.stats.expirations++;
|
|
193
|
+
this.emit('expiration', type, key);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
entry.lastAccessedAt = now;
|
|
197
|
+
this.stats.hits++;
|
|
198
|
+
return entry.value;
|
|
199
|
+
}
|
|
200
|
+
setInCache(cache, key, value, type) {
|
|
201
|
+
if (cache.size >= this.maxEntries) {
|
|
202
|
+
this.evictLRU(cache, type);
|
|
203
|
+
}
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
cache.set(key, {
|
|
206
|
+
value,
|
|
207
|
+
expiresAt: now + this.ttlMs,
|
|
208
|
+
createdAt: now,
|
|
209
|
+
lastAccessedAt: now,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
evictLRU(cache, type) {
|
|
213
|
+
let oldestKey = null;
|
|
214
|
+
let oldestTime = Infinity;
|
|
215
|
+
for (const [key, entry] of cache) {
|
|
216
|
+
if (entry.lastAccessedAt < oldestTime) {
|
|
217
|
+
oldestTime = entry.lastAccessedAt;
|
|
218
|
+
oldestKey = key;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (oldestKey) {
|
|
222
|
+
cache.delete(oldestKey);
|
|
223
|
+
this.stats.evictions++;
|
|
224
|
+
this.emit('eviction', type, oldestKey);
|
|
225
|
+
this.logger.debug('GOAL_CACHE', 'Evicted LRU entry', { type, key: oldestKey });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
pruneExpiredFromMap(cache, type, now) {
|
|
229
|
+
let pruned = 0;
|
|
230
|
+
for (const [key, entry] of cache) {
|
|
231
|
+
if (entry.expiresAt < now) {
|
|
232
|
+
cache.delete(key);
|
|
233
|
+
this.stats.expirations++;
|
|
234
|
+
this.emit('expiration', type, key);
|
|
235
|
+
pruned++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return pruned;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export function createGoalCache(options = {}) {
|
|
242
|
+
return new GoalCache(options);
|
|
243
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { Goal, GoalHash, Task, TaskStatus, GoalStatus, Logger } from './types.js';
|
|
3
|
+
import { GoalError } from './errors.js';
|
|
4
|
+
export type GoalNotificationSubtype = 'tasks_generated' | 'milestone_reached' | 'review_due' | 'goal_completed' | 'goal_paused' | 'goal_resumed' | 'task_approved' | 'task_denied' | 'task_completed' | 'task_failed' | 'daily_summary';
|
|
5
|
+
export type ApprovalResponse = 'approve' | 'deny' | 'skip' | 'later' | 'timeout';
|
|
6
|
+
export type ViewAction = 'list' | 'show' | 'tasks' | 'progress' | 'summary';
|
|
7
|
+
export interface GoalNotification {
|
|
8
|
+
readonly type: 'goal_notification';
|
|
9
|
+
readonly subtype: GoalNotificationSubtype;
|
|
10
|
+
readonly goalHash: GoalHash;
|
|
11
|
+
readonly goalName: string;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
readonly details?: Record<string, unknown>;
|
|
14
|
+
readonly timestamp: Date;
|
|
15
|
+
}
|
|
16
|
+
export interface GoalApprovalRequest {
|
|
17
|
+
readonly type: 'goal_task_approval';
|
|
18
|
+
readonly requestId: string;
|
|
19
|
+
readonly goalHash: GoalHash;
|
|
20
|
+
readonly goalName: string;
|
|
21
|
+
readonly taskId: number;
|
|
22
|
+
readonly taskTitle: string;
|
|
23
|
+
readonly taskDescription: string | null;
|
|
24
|
+
readonly taskType: string;
|
|
25
|
+
readonly permissionRequired: string;
|
|
26
|
+
readonly options: ApprovalResponse[];
|
|
27
|
+
readonly expiresAt: Date;
|
|
28
|
+
readonly timestamp: Date;
|
|
29
|
+
}
|
|
30
|
+
export interface GoalViewRequest {
|
|
31
|
+
readonly type: 'goal_view';
|
|
32
|
+
readonly requestId: string;
|
|
33
|
+
readonly action: ViewAction;
|
|
34
|
+
readonly goalHash?: GoalHash;
|
|
35
|
+
readonly filters?: {
|
|
36
|
+
status?: GoalStatus;
|
|
37
|
+
taskStatus?: TaskStatus;
|
|
38
|
+
};
|
|
39
|
+
readonly userId: number;
|
|
40
|
+
readonly timestamp: Date;
|
|
41
|
+
}
|
|
42
|
+
export interface GoalViewResponse {
|
|
43
|
+
readonly type: 'goal_view_response';
|
|
44
|
+
readonly requestId: string;
|
|
45
|
+
readonly action: ViewAction;
|
|
46
|
+
readonly data: Goal | Goal[] | Task[] | ProgressSummary | null;
|
|
47
|
+
readonly message: string;
|
|
48
|
+
readonly success: boolean;
|
|
49
|
+
readonly error?: string;
|
|
50
|
+
readonly timestamp: Date;
|
|
51
|
+
}
|
|
52
|
+
export interface GoalModificationRedirect {
|
|
53
|
+
readonly type: 'goal_modification_redirect';
|
|
54
|
+
readonly requestedAction: string;
|
|
55
|
+
readonly cliCommand: string;
|
|
56
|
+
readonly message: string;
|
|
57
|
+
readonly timestamp: Date;
|
|
58
|
+
}
|
|
59
|
+
export interface ProgressSummary {
|
|
60
|
+
readonly goalHash: GoalHash;
|
|
61
|
+
readonly goalName: string;
|
|
62
|
+
readonly progress: number;
|
|
63
|
+
readonly status: GoalStatus;
|
|
64
|
+
readonly milestones: {
|
|
65
|
+
total: number;
|
|
66
|
+
completed: number;
|
|
67
|
+
};
|
|
68
|
+
readonly tasks: {
|
|
69
|
+
total: number;
|
|
70
|
+
completed: number;
|
|
71
|
+
pending: number;
|
|
72
|
+
failed: number;
|
|
73
|
+
};
|
|
74
|
+
readonly daysSinceActivity: number;
|
|
75
|
+
readonly deadline?: Date;
|
|
76
|
+
readonly daysUntilDeadline?: number;
|
|
77
|
+
}
|
|
78
|
+
export type CommsSendFunction = (payload: GoalNotification | GoalApprovalRequest | GoalViewResponse | GoalModificationRedirect) => Promise<void>;
|
|
79
|
+
export type ApprovalResponseHandler = (requestId: string, response: ApprovalResponse, userId: number) => Promise<void>;
|
|
80
|
+
export interface GoalCommsHandlerOptions {
|
|
81
|
+
readonly logger?: Logger;
|
|
82
|
+
readonly sendFunction?: CommsSendFunction;
|
|
83
|
+
readonly approvalExpiryMs?: number;
|
|
84
|
+
readonly includeDetails?: boolean;
|
|
85
|
+
readonly maxMessageLength?: number;
|
|
86
|
+
}
|
|
87
|
+
export interface GoalCommsHandlerEvents {
|
|
88
|
+
'notification-sent': [GoalNotification];
|
|
89
|
+
'approval-sent': [GoalApprovalRequest];
|
|
90
|
+
'approval-received': [{
|
|
91
|
+
requestId: string;
|
|
92
|
+
response: ApprovalResponse;
|
|
93
|
+
userId: number;
|
|
94
|
+
}];
|
|
95
|
+
'view-request': [GoalViewRequest];
|
|
96
|
+
'view-response-sent': [GoalViewResponse];
|
|
97
|
+
'modification-redirected': [GoalModificationRedirect];
|
|
98
|
+
'error': [Error];
|
|
99
|
+
}
|
|
100
|
+
export declare class GoalCommsError extends GoalError {
|
|
101
|
+
constructor(message: string, cause?: Error);
|
|
102
|
+
}
|
|
103
|
+
export declare class ApprovalTimeoutError extends GoalError {
|
|
104
|
+
readonly requestId: string;
|
|
105
|
+
readonly taskId: number;
|
|
106
|
+
constructor(requestId: string, taskId: number);
|
|
107
|
+
}
|
|
108
|
+
export declare class GoalCommsHandler extends EventEmitter<GoalCommsHandlerEvents> {
|
|
109
|
+
private readonly logger;
|
|
110
|
+
private readonly sendFunction?;
|
|
111
|
+
private readonly approvalExpiryMs;
|
|
112
|
+
private readonly includeDetails;
|
|
113
|
+
private readonly maxMessageLength;
|
|
114
|
+
private readonly pendingApprovals;
|
|
115
|
+
constructor(options?: GoalCommsHandlerOptions);
|
|
116
|
+
sendNotification(subtype: GoalNotificationSubtype, goal: Goal, message: string, details?: Record<string, unknown>): Promise<void>;
|
|
117
|
+
notifyTasksGenerated(goal: Goal, taskCount: number): Promise<void>;
|
|
118
|
+
notifyMilestoneReached(goal: Goal, milestoneTitle: string, completedCount: number, totalCount: number): Promise<void>;
|
|
119
|
+
notifyReviewDue(goal: Goal): Promise<void>;
|
|
120
|
+
notifyGoalCompleted(goal: Goal): Promise<void>;
|
|
121
|
+
notifyTaskCompleted(goal: Goal, task: Task): Promise<void>;
|
|
122
|
+
notifyTaskFailed(goal: Goal, task: Task, error: string): Promise<void>;
|
|
123
|
+
notifyDailySummary(goals: Goal[], completedTasks: number, pendingTasks: number): Promise<void>;
|
|
124
|
+
requestApproval(goal: Goal, task: Task, permissionRequired: string): Promise<ApprovalResponse>;
|
|
125
|
+
handleApprovalResponse(requestId: string, response: ApprovalResponse, userId: number): void;
|
|
126
|
+
cancelApprovalRequest(requestId: string): boolean;
|
|
127
|
+
getPendingApprovals(): GoalApprovalRequest[];
|
|
128
|
+
handleViewRequest(request: GoalViewRequest, dataProvider: {
|
|
129
|
+
getGoal: (hash: GoalHash) => Promise<Goal | null>;
|
|
130
|
+
listGoals: (filters?: {
|
|
131
|
+
status?: GoalStatus;
|
|
132
|
+
}) => Promise<Goal[]>;
|
|
133
|
+
listTasks: (goalHash: GoalHash, filters?: {
|
|
134
|
+
status?: TaskStatus;
|
|
135
|
+
}) => Promise<Task[]>;
|
|
136
|
+
getProgress: (hash: GoalHash) => Promise<ProgressSummary | null>;
|
|
137
|
+
}): Promise<GoalViewResponse>;
|
|
138
|
+
private createViewResponse;
|
|
139
|
+
isModificationAction(action: string): boolean;
|
|
140
|
+
createModificationRedirect(requestedAction: string, goalHash?: GoalHash): GoalModificationRedirect;
|
|
141
|
+
private getCliCommand;
|
|
142
|
+
formatGoalSummary(goal: Goal): string;
|
|
143
|
+
formatTaskSummary(task: Task): string;
|
|
144
|
+
formatProgressSummary(progress: ProgressSummary): string;
|
|
145
|
+
private send;
|
|
146
|
+
private generateRequestId;
|
|
147
|
+
private truncate;
|
|
148
|
+
dispose(): void;
|
|
149
|
+
}
|
|
150
|
+
export declare function createGoalCommsHandler(options?: GoalCommsHandlerOptions): GoalCommsHandler;
|