@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,74 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { Goal, Milestone, CreateMilestoneInput, Logger } from './types.js';
3
+ import { GoalError } from './errors.js';
4
+ export type MilestoneLLMFunction = (prompt: string, options?: {
5
+ modelTier?: string;
6
+ maxTokens?: number;
7
+ temperature?: number;
8
+ }) => Promise<string>;
9
+ export interface MilestoneSuggestion {
10
+ readonly title: string;
11
+ readonly description: string;
12
+ readonly order: number;
13
+ readonly targetDate?: string;
14
+ readonly reasoning: string;
15
+ readonly effortPercent?: number;
16
+ readonly deliverables?: string[];
17
+ readonly dependsOn?: string[];
18
+ }
19
+ export interface MilestoneBreakdownResult {
20
+ readonly suggestions: MilestoneSuggestion[];
21
+ readonly strategySummary: string;
22
+ readonly warnings: string[];
23
+ readonly criticalPath?: string[];
24
+ readonly metadata: {
25
+ readonly generatedAt: string;
26
+ readonly modelTier: string;
27
+ readonly promptTokens?: number;
28
+ readonly responseTokens?: number;
29
+ };
30
+ }
31
+ export interface MilestoneBreakdownOptions {
32
+ readonly maxMilestones?: number;
33
+ readonly existingMilestones?: Milestone[];
34
+ readonly additionalContext?: string;
35
+ readonly modelTier?: string;
36
+ readonly includeReasoning?: boolean;
37
+ readonly hoursPerWeek?: number;
38
+ }
39
+ export interface MilestoneBreakerOptions {
40
+ readonly llmFunction: MilestoneLLMFunction;
41
+ readonly defaultModelTier?: string;
42
+ readonly defaultMaxMilestones?: number;
43
+ readonly logger?: Logger;
44
+ }
45
+ export interface MilestoneBreakerEvents {
46
+ breakdownStarted: [goalHash: string, options: MilestoneBreakdownOptions];
47
+ breakdownCompleted: [goalHash: string, result: MilestoneBreakdownResult];
48
+ breakdownFailed: [goalHash: string, error: Error];
49
+ milestoneSuggested: [goalHash: string, suggestion: MilestoneSuggestion];
50
+ }
51
+ export declare class MilestoneBreakdownError extends GoalError {
52
+ constructor(message: string, cause?: Error);
53
+ }
54
+ export declare class MilestoneBreaker extends EventEmitter<MilestoneBreakerEvents> {
55
+ private readonly llmFunction;
56
+ private readonly defaultModelTier;
57
+ private readonly defaultMaxMilestones;
58
+ private readonly logger;
59
+ constructor(options: MilestoneBreakerOptions);
60
+ breakdownGoal(goal: Goal, options?: MilestoneBreakdownOptions): Promise<MilestoneBreakdownResult>;
61
+ suggestAdditionalMilestones(goal: Goal, existingMilestones: Milestone[], count?: number): Promise<MilestoneSuggestion[]>;
62
+ analyzeOrder(goal: Goal, milestones: Milestone[]): Promise<{
63
+ suggestedOrder: number[];
64
+ reasoning: string;
65
+ dependencies: Map<number, number[]>;
66
+ }>;
67
+ suggestionToInput(suggestion: MilestoneSuggestion): CreateMilestoneInput;
68
+ private buildBreakdownPrompt;
69
+ private parseBreakdownResponse;
70
+ private validateSuggestion;
71
+ private cleanJsonResponse;
72
+ private parseRelativeDate;
73
+ }
74
+ export declare function createMilestoneBreaker(options: MilestoneBreakerOptions): MilestoneBreaker;
@@ -0,0 +1,348 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { GoalError } from './errors.js';
3
+ const DEFAULT_MAX_MILESTONES = 7;
4
+ const DEFAULT_MODEL_TIER = 'standard';
5
+ const noopLogger = {
6
+ debug: () => { },
7
+ info: () => { },
8
+ warn: () => { },
9
+ error: () => { },
10
+ };
11
+ export class MilestoneBreakdownError extends GoalError {
12
+ constructor(message, cause) {
13
+ super('MILESTONE_BREAKDOWN_ERROR', message, cause ? { cause } : {});
14
+ }
15
+ }
16
+ export class MilestoneBreaker extends EventEmitter {
17
+ llmFunction;
18
+ defaultModelTier;
19
+ defaultMaxMilestones;
20
+ logger;
21
+ constructor(options) {
22
+ super();
23
+ this.llmFunction = options.llmFunction;
24
+ this.defaultModelTier = options.defaultModelTier ?? DEFAULT_MODEL_TIER;
25
+ this.defaultMaxMilestones = options.defaultMaxMilestones ?? DEFAULT_MAX_MILESTONES;
26
+ this.logger = options.logger ?? noopLogger;
27
+ }
28
+ async breakdownGoal(goal, options = {}) {
29
+ const maxMilestones = options.maxMilestones ?? this.defaultMaxMilestones;
30
+ const modelTier = options.modelTier ?? this.defaultModelTier;
31
+ this.logger.info('MILESTONE_BREAKER', 'Breaking down goal', {
32
+ goalHash: goal.hash,
33
+ goalName: goal.name,
34
+ maxMilestones,
35
+ });
36
+ this.emit('breakdownStarted', goal.hash, options);
37
+ try {
38
+ const prompt = this.buildBreakdownPrompt(goal, options);
39
+ const response = await this.llmFunction(prompt, {
40
+ modelTier,
41
+ maxTokens: 3000,
42
+ temperature: 0.7,
43
+ });
44
+ const result = this.parseBreakdownResponse(response, goal, options);
45
+ for (const suggestion of result.suggestions) {
46
+ this.emit('milestoneSuggested', goal.hash, suggestion);
47
+ }
48
+ this.logger.info('MILESTONE_BREAKER', 'Breakdown completed', {
49
+ goalHash: goal.hash,
50
+ milestoneCount: result.suggestions.length,
51
+ });
52
+ this.emit('breakdownCompleted', goal.hash, result);
53
+ return result;
54
+ }
55
+ catch (err) {
56
+ const error = err instanceof Error ? err : new Error(String(err));
57
+ this.logger.error('MILESTONE_BREAKER', 'Breakdown failed', {
58
+ goalHash: goal.hash,
59
+ error: error.message,
60
+ });
61
+ this.emit('breakdownFailed', goal.hash, error);
62
+ throw new MilestoneBreakdownError(`Failed to break down goal: ${error.message}`, error);
63
+ }
64
+ }
65
+ async suggestAdditionalMilestones(goal, existingMilestones, count = 2) {
66
+ const result = await this.breakdownGoal(goal, {
67
+ existingMilestones,
68
+ maxMilestones: count,
69
+ additionalContext: `
70
+ The goal already has ${existingMilestones.length} milestones.
71
+ Only suggest ${count} additional milestones that would help achieve the goal.
72
+ Do not duplicate existing milestones.
73
+ Focus on gaps or missing steps.
74
+ `,
75
+ });
76
+ return result.suggestions;
77
+ }
78
+ async analyzeOrder(goal, milestones) {
79
+ const prompt = `Analyze the order of these milestones for the goal "${goal.name}".
80
+
81
+ Goal: ${goal.name}
82
+ Description: ${goal.description ?? 'No description'}
83
+
84
+ Current Milestones (in order):
85
+ ${milestones.map((m, i) => `${i + 1}. ${m.title}: ${m.description ?? ''}`).join('\n')}
86
+
87
+ Provide a JSON response with:
88
+ {
89
+ "suggestedOrder": [array of milestone indices in optimal order, 1-based],
90
+ "reasoning": "explanation of why this order is better",
91
+ "dependencies": {
92
+ "milestone_index": [indices this depends on]
93
+ }
94
+ }
95
+
96
+ Consider:
97
+ 1. Logical progression (prerequisites before dependent tasks)
98
+ 2. Risk reduction (validate risky assumptions early)
99
+ 3. Value delivery (get feedback on valuable parts early)
100
+
101
+ Respond ONLY with valid JSON.`;
102
+ const response = await this.llmFunction(prompt, {
103
+ modelTier: this.defaultModelTier,
104
+ maxTokens: 1000,
105
+ temperature: 0.5,
106
+ });
107
+ try {
108
+ const cleanResponse = this.cleanJsonResponse(response);
109
+ const parsed = JSON.parse(cleanResponse);
110
+ const dependencies = new Map();
111
+ if (parsed.dependencies && typeof parsed.dependencies === 'object') {
112
+ for (const [key, value] of Object.entries(parsed.dependencies)) {
113
+ const idx = parseInt(key, 10);
114
+ if (!isNaN(idx) && Array.isArray(value)) {
115
+ dependencies.set(idx, value.filter((v) => typeof v === 'number'));
116
+ }
117
+ }
118
+ }
119
+ return {
120
+ suggestedOrder: Array.isArray(parsed.suggestedOrder)
121
+ ? parsed.suggestedOrder.filter((n) => typeof n === 'number')
122
+ : milestones.map((_, i) => i + 1),
123
+ reasoning: typeof parsed.reasoning === 'string'
124
+ ? parsed.reasoning
125
+ : 'No reasoning provided',
126
+ dependencies,
127
+ };
128
+ }
129
+ catch {
130
+ return {
131
+ suggestedOrder: milestones.map((_, i) => i + 1),
132
+ reasoning: 'Could not analyze order',
133
+ dependencies: new Map(),
134
+ };
135
+ }
136
+ }
137
+ suggestionToInput(suggestion) {
138
+ return {
139
+ title: suggestion.title,
140
+ description: suggestion.description,
141
+ targetDate: suggestion.targetDate
142
+ ? this.parseRelativeDate(suggestion.targetDate)
143
+ : undefined,
144
+ };
145
+ }
146
+ buildBreakdownPrompt(goal, options) {
147
+ const maxMilestones = options.maxMilestones ?? this.defaultMaxMilestones;
148
+ let existingContext = '';
149
+ if (options.existingMilestones && options.existingMilestones.length > 0) {
150
+ existingContext = '\n## Existing Milestones\n';
151
+ for (const m of options.existingMilestones) {
152
+ const status = m.completedAt ? '✓ COMPLETED' : 'PENDING';
153
+ existingContext += `- [${status}] ${m.title}`;
154
+ if (m.description)
155
+ existingContext += `: ${m.description}`;
156
+ existingContext += '\n';
157
+ }
158
+ existingContext +=
159
+ '\nDo not duplicate existing milestones. Build on completed work.\n';
160
+ }
161
+ let timeContext = '';
162
+ if (options.hoursPerWeek) {
163
+ timeContext = `\nUser has approximately ${options.hoursPerWeek} hours per week available for this goal.\n`;
164
+ }
165
+ return `You are a project planning assistant. Break down the following goal into milestones.
166
+
167
+ # Goal
168
+ Name: ${goal.name}
169
+ Description: ${goal.description ?? 'No description provided'}
170
+ Priority: ${goal.priority}
171
+ Current Progress: ${goal.progress ?? 0}%
172
+ Target Date: ${goal.deadline ?? 'No target date set'}
173
+ ${existingContext}${timeContext}
174
+ ${options.additionalContext ?? ''}
175
+
176
+ # Instructions
177
+ Generate up to ${maxMilestones} milestones that will help achieve this goal.
178
+
179
+ ## Output Format
180
+ Respond with a JSON object containing:
181
+ {
182
+ "strategySummary": "Brief overview of the milestone strategy",
183
+ "suggestions": [
184
+ {
185
+ "title": "Clear, concise milestone title",
186
+ "description": "What needs to be accomplished in this milestone",
187
+ "order": 1,
188
+ "targetDate": "relative like '2 weeks' or ISO date",
189
+ "reasoning": "Why this milestone is important",
190
+ "effortPercent": 15,
191
+ "deliverables": ["key deliverable 1", "key deliverable 2"],
192
+ "dependsOn": ["title of milestone this depends on"]
193
+ }
194
+ ],
195
+ "warnings": ["Any concerns or notes"],
196
+ "criticalPath": ["milestone titles that are on critical path"]
197
+ }
198
+
199
+ Guidelines for milestones:
200
+ 1. Each milestone should be a significant checkpoint
201
+ 2. Milestones should be measurable (clear completion criteria)
202
+ 3. Order milestones logically (dependencies first)
203
+ 4. Space out target dates reasonably
204
+ 5. Consider the goal's priority and target date
205
+ 6. First milestone should be achievable quickly (build momentum)
206
+ 7. Include validation/testing milestones if appropriate
207
+
208
+ Respond ONLY with valid JSON, no markdown code blocks or other text.`;
209
+ }
210
+ parseBreakdownResponse(response, goal, options) {
211
+ try {
212
+ const cleanResponse = this.cleanJsonResponse(response);
213
+ const parsed = JSON.parse(cleanResponse);
214
+ const suggestions = [];
215
+ if (Array.isArray(parsed.suggestions)) {
216
+ for (let i = 0; i < parsed.suggestions.length; i++) {
217
+ const suggestion = this.validateSuggestion(parsed.suggestions[i], i);
218
+ if (suggestion) {
219
+ suggestions.push(suggestion);
220
+ }
221
+ }
222
+ }
223
+ return {
224
+ suggestions,
225
+ strategySummary: parsed.strategySummary ?? 'Milestone breakdown generated',
226
+ warnings: Array.isArray(parsed.warnings) ? parsed.warnings : [],
227
+ criticalPath: Array.isArray(parsed.criticalPath)
228
+ ? parsed.criticalPath.filter((t) => typeof t === 'string')
229
+ : undefined,
230
+ metadata: {
231
+ generatedAt: new Date().toISOString(),
232
+ modelTier: options.modelTier ?? this.defaultModelTier,
233
+ },
234
+ };
235
+ }
236
+ catch (err) {
237
+ this.logger.error('MILESTONE_BREAKER', 'Failed to parse response', {
238
+ response: response.substring(0, 500),
239
+ error: err instanceof Error ? err.message : String(err),
240
+ });
241
+ throw new MilestoneBreakdownError(`Failed to parse milestone breakdown response: ${err instanceof Error ? err.message : String(err)}`);
242
+ }
243
+ }
244
+ validateSuggestion(raw, index) {
245
+ if (!raw || typeof raw !== 'object') {
246
+ return null;
247
+ }
248
+ const s = raw;
249
+ const title = typeof s.title === 'string' ? s.title.trim() : '';
250
+ if (!title) {
251
+ this.logger.warn('MILESTONE_BREAKER', 'Invalid suggestion - no title', {
252
+ index,
253
+ });
254
+ return null;
255
+ }
256
+ const description = typeof s.description === 'string' ? s.description.trim() : '';
257
+ const order = typeof s.order === 'number' ? Math.max(1, Math.round(s.order)) : index + 1;
258
+ return {
259
+ title,
260
+ description,
261
+ order,
262
+ targetDate: typeof s.targetDate === 'string' ? s.targetDate : undefined,
263
+ reasoning: typeof s.reasoning === 'string' ? s.reasoning : '',
264
+ effortPercent: typeof s.effortPercent === 'number'
265
+ ? Math.max(0, Math.min(100, s.effortPercent))
266
+ : undefined,
267
+ deliverables: Array.isArray(s.deliverables)
268
+ ? s.deliverables.filter((d) => typeof d === 'string')
269
+ : undefined,
270
+ dependsOn: Array.isArray(s.dependsOn)
271
+ ? s.dependsOn.filter((d) => typeof d === 'string')
272
+ : undefined,
273
+ };
274
+ }
275
+ cleanJsonResponse(response) {
276
+ let clean = response.trim();
277
+ if (clean.startsWith('```json')) {
278
+ clean = clean.slice(7);
279
+ }
280
+ else if (clean.startsWith('```')) {
281
+ clean = clean.slice(3);
282
+ }
283
+ if (clean.endsWith('```')) {
284
+ clean = clean.slice(0, -3);
285
+ }
286
+ return clean.trim();
287
+ }
288
+ parseRelativeDate(dateStr) {
289
+ if (/^\d{4}-\d{2}-\d{2}/.test(dateStr)) {
290
+ return dateStr;
291
+ }
292
+ const now = new Date();
293
+ const lower = dateStr.toLowerCase().trim();
294
+ const patterns = [
295
+ {
296
+ regex: /^(\d+)\s*days?$/,
297
+ fn: (m) => {
298
+ const d = new Date(now);
299
+ d.setDate(d.getDate() + parseInt(m[1], 10));
300
+ return d;
301
+ },
302
+ },
303
+ {
304
+ regex: /^(\d+)\s*weeks?$/,
305
+ fn: (m) => {
306
+ const d = new Date(now);
307
+ d.setDate(d.getDate() + parseInt(m[1], 10) * 7);
308
+ return d;
309
+ },
310
+ },
311
+ {
312
+ regex: /^(\d+)\s*months?$/,
313
+ fn: (m) => {
314
+ const d = new Date(now);
315
+ d.setMonth(d.getMonth() + parseInt(m[1], 10));
316
+ return d;
317
+ },
318
+ },
319
+ {
320
+ regex: /^end\s*of\s*week$/,
321
+ fn: () => {
322
+ const d = new Date(now);
323
+ d.setDate(d.getDate() + (7 - d.getDay()));
324
+ return d;
325
+ },
326
+ },
327
+ {
328
+ regex: /^end\s*of\s*month$/,
329
+ fn: () => {
330
+ const d = new Date(now);
331
+ d.setMonth(d.getMonth() + 1, 0);
332
+ return d;
333
+ },
334
+ },
335
+ ];
336
+ for (const { regex, fn } of patterns) {
337
+ const match = lower.match(regex);
338
+ if (match) {
339
+ return fn(match).toISOString().split('T')[0];
340
+ }
341
+ }
342
+ this.logger.debug('MILESTONE_BREAKER', 'Could not parse date', { dateStr });
343
+ return undefined;
344
+ }
345
+ }
346
+ export function createMilestoneBreaker(options) {
347
+ return new MilestoneBreaker(options);
348
+ }
@@ -0,0 +1,109 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { GoalHash, ApprovalMode, Logger } from './types.js';
3
+ import { GoalError } from './errors.js';
4
+ import type { PermissionCategory, PermissionCheckResult, ExecutionContext } from './TaskExecutor.js';
5
+ export type PermissionDecision = 'allow' | 'deny' | 'ask';
6
+ export interface PermissionRule {
7
+ readonly category: PermissionCategory;
8
+ readonly decision: PermissionDecision;
9
+ readonly pattern?: string;
10
+ readonly scope: 'session' | 'permanent';
11
+ readonly expiresAt?: Date;
12
+ readonly createdAt: Date;
13
+ }
14
+ export interface StoredPermission {
15
+ readonly category: PermissionCategory;
16
+ readonly pattern: string | null;
17
+ readonly decision: PermissionDecision;
18
+ readonly scope: 'session' | 'permanent';
19
+ readonly createdAt: string;
20
+ readonly expiresAt: string | null;
21
+ }
22
+ export interface PermissionCheckOptions {
23
+ readonly path?: string;
24
+ readonly command?: string;
25
+ readonly domain?: string;
26
+ readonly useCache?: boolean;
27
+ }
28
+ export interface PermissionAuditEntry {
29
+ readonly timestamp: Date;
30
+ readonly goalHash: GoalHash;
31
+ readonly taskId: number;
32
+ readonly category: PermissionCategory;
33
+ readonly decision: PermissionDecision;
34
+ readonly approvalRequested: boolean;
35
+ readonly approvalGranted?: boolean;
36
+ readonly target?: string;
37
+ }
38
+ export interface PermissionBridgeOptions {
39
+ readonly logger?: Logger;
40
+ readonly defaultApprovalMode?: ApprovalMode;
41
+ readonly cacheTtlMs?: number;
42
+ readonly maxCacheEntries?: number;
43
+ readonly enableAudit?: boolean;
44
+ readonly maxAuditEntries?: number;
45
+ readonly permissionsProvider?: () => Promise<StoredPermission[]>;
46
+ }
47
+ export interface PermissionBridgeEvents {
48
+ 'permission-checked': [PermissionCheckResult, ExecutionContext];
49
+ 'permission-granted': [PermissionCheckResult, ExecutionContext];
50
+ 'permission-denied': [PermissionCheckResult, ExecutionContext];
51
+ 'approval-required': [ExecutionContext];
52
+ 'audit-logged': [PermissionAuditEntry];
53
+ 'cache-hit': [{
54
+ category: PermissionCategory;
55
+ decision: PermissionDecision;
56
+ }];
57
+ 'cache-miss': [{
58
+ category: PermissionCategory;
59
+ }];
60
+ 'error': [Error];
61
+ }
62
+ export declare class PermissionBridgeError extends GoalError {
63
+ constructor(message: string, cause?: Error);
64
+ }
65
+ export declare class PermissionBridge extends EventEmitter<PermissionBridgeEvents> {
66
+ private readonly logger;
67
+ private readonly defaultApprovalMode;
68
+ private readonly cacheTtlMs;
69
+ private readonly maxCacheEntries;
70
+ private readonly enableAudit;
71
+ private readonly maxAuditEntries;
72
+ private readonly permissionsProvider?;
73
+ private readonly cache;
74
+ private readonly auditLog;
75
+ private readonly sessionPermissions;
76
+ constructor(options?: PermissionBridgeOptions);
77
+ checkPermission(category: PermissionCategory, context: ExecutionContext, options?: PermissionCheckOptions): Promise<PermissionCheckResult>;
78
+ recordDecision(category: PermissionCategory, decision: PermissionDecision, options?: PermissionCheckOptions & {
79
+ scope?: 'session' | 'permanent';
80
+ }): void;
81
+ logAudit(context: ExecutionContext, category: PermissionCategory, decision: PermissionDecision, approvalRequested: boolean, approvalGranted?: boolean, target?: string): void;
82
+ private checkGoalRestrictions;
83
+ private isDangerous;
84
+ private applyApprovalMode;
85
+ private checkCache;
86
+ private cacheDecision;
87
+ private getCacheKey;
88
+ clearCache(): void;
89
+ private checkStoredPermissions;
90
+ private checkSessionPermissions;
91
+ private matchesPattern;
92
+ private createResult;
93
+ private createResultFromCached;
94
+ getAuditLog(filters?: {
95
+ goalHash?: GoalHash;
96
+ taskId?: number;
97
+ category?: PermissionCategory;
98
+ since?: Date;
99
+ limit?: number;
100
+ }): PermissionAuditEntry[];
101
+ clearAuditLog(): void;
102
+ clearSessionPermissions(): void;
103
+ getCacheStats(): {
104
+ cacheSize: number;
105
+ sessionPermissions: number;
106
+ auditEntries: number;
107
+ };
108
+ }
109
+ export declare function createPermissionBridge(options?: PermissionBridgeOptions): PermissionBridge;