@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,464 @@
|
|
|
1
|
+
import { GoalError } from './errors.js';
|
|
2
|
+
const MAX_TITLE_LENGTH = 200;
|
|
3
|
+
const MAX_DESCRIPTION_LENGTH = 2000;
|
|
4
|
+
const noopLogger = {
|
|
5
|
+
debug: () => { },
|
|
6
|
+
info: () => { },
|
|
7
|
+
warn: () => { },
|
|
8
|
+
error: () => { },
|
|
9
|
+
};
|
|
10
|
+
const PROMPT_INJECTION_PATTERNS = [
|
|
11
|
+
{
|
|
12
|
+
pattern: /ignore\s+(previous|all|prior)\s+instructions?/i,
|
|
13
|
+
severity: 'critical',
|
|
14
|
+
description: 'Attempt to ignore previous instructions',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: /disregard\s+(all|any|the)\s+(rules?|instructions?|guidelines?)/i,
|
|
18
|
+
severity: 'critical',
|
|
19
|
+
description: 'Attempt to disregard rules',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
pattern: /execute\s+without\s+(permission|approval|asking)/i,
|
|
23
|
+
severity: 'critical',
|
|
24
|
+
description: 'Attempt to bypass permission system',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
pattern: /bypass\s+(security|permission|approval|authentication)/i,
|
|
28
|
+
severity: 'critical',
|
|
29
|
+
description: 'Attempt to bypass security',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: /you\s+are\s+now\s+(a|an|the)/i,
|
|
33
|
+
severity: 'high',
|
|
34
|
+
description: 'Role manipulation attempt',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
pattern: /pretend\s+(to\s+be|you\s+are)/i,
|
|
38
|
+
severity: 'high',
|
|
39
|
+
description: 'Identity manipulation attempt',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
pattern: /forget\s+(everything|all|what)/i,
|
|
43
|
+
severity: 'high',
|
|
44
|
+
description: 'Memory manipulation attempt',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
pattern: /system\s*:\s*|<system>|<\/system>/i,
|
|
48
|
+
severity: 'high',
|
|
49
|
+
description: 'System prompt injection attempt',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
pattern: /\[INST\]|\[\/INST\]|<<SYS>>|<</i,
|
|
53
|
+
severity: 'high',
|
|
54
|
+
description: 'LLM control sequence injection',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
pattern: /act\s+as\s+(if|though)\s+you/i,
|
|
58
|
+
severity: 'medium',
|
|
59
|
+
description: 'Behavioral manipulation attempt',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
pattern: /override\s+(your|the|all)\s+(instructions?|rules?|limits?)/i,
|
|
63
|
+
severity: 'critical',
|
|
64
|
+
description: 'Instruction override attempt',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
pattern: /do\s+not\s+follow\s+(the|any|your)\s+(rules?|guidelines?)/i,
|
|
68
|
+
severity: 'critical',
|
|
69
|
+
description: 'Rule bypass attempt',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
const DANGEROUS_COMMAND_PATTERNS = [
|
|
73
|
+
{
|
|
74
|
+
pattern: /rm\s+-rf\s+[/~]/,
|
|
75
|
+
severity: 'critical',
|
|
76
|
+
description: 'Recursive delete of root or home directory',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
pattern: /rm\s+-rf\s+\*/,
|
|
80
|
+
severity: 'critical',
|
|
81
|
+
description: 'Recursive delete with wildcard',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
pattern: /:\s*\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;/,
|
|
85
|
+
severity: 'critical',
|
|
86
|
+
description: 'Fork bomb detected',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
pattern: />\s*\/dev\/sd[a-z]/,
|
|
90
|
+
severity: 'critical',
|
|
91
|
+
description: 'Direct disk write attempt',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
pattern: /mkfs\./,
|
|
95
|
+
severity: 'critical',
|
|
96
|
+
description: 'Filesystem format attempt',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
pattern: /dd\s+if=.*of=\/dev\//,
|
|
100
|
+
severity: 'critical',
|
|
101
|
+
description: 'Direct disk manipulation',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
pattern: /chmod\s+(-R\s+)?777\s+\//,
|
|
105
|
+
severity: 'high',
|
|
106
|
+
description: 'Recursive permission change on root',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pattern: /chown\s+-R\s+.*\s+\//,
|
|
110
|
+
severity: 'high',
|
|
111
|
+
description: 'Recursive ownership change on root',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
pattern: /curl.*\|\s*(ba)?sh/,
|
|
115
|
+
severity: 'high',
|
|
116
|
+
description: 'Remote script execution',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
pattern: /wget.*\|\s*(ba)?sh/,
|
|
120
|
+
severity: 'high',
|
|
121
|
+
description: 'Remote script execution',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
pattern: /eval\s*\(/,
|
|
125
|
+
severity: 'medium',
|
|
126
|
+
description: 'Dynamic code evaluation',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
pattern: /base64\s+-d.*\|\s*(ba)?sh/,
|
|
130
|
+
severity: 'high',
|
|
131
|
+
description: 'Encoded command execution',
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
const PATH_TRAVERSAL_PATTERNS = [
|
|
135
|
+
{
|
|
136
|
+
pattern: /\.\.\//,
|
|
137
|
+
severity: 'medium',
|
|
138
|
+
description: 'Parent directory traversal',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
pattern: /\.\.\\/,
|
|
142
|
+
severity: 'medium',
|
|
143
|
+
description: 'Parent directory traversal (Windows)',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
pattern: /%2e%2e%2f/i,
|
|
147
|
+
severity: 'high',
|
|
148
|
+
description: 'URL-encoded path traversal',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
pattern: /%252e%252e%252f/i,
|
|
152
|
+
severity: 'high',
|
|
153
|
+
description: 'Double URL-encoded path traversal',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
pattern: /\.\.%c0%af/i,
|
|
157
|
+
severity: 'high',
|
|
158
|
+
description: 'Unicode path traversal',
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
const SENSITIVE_PATHS = [
|
|
162
|
+
/^\/etc\/passwd/,
|
|
163
|
+
/^\/etc\/shadow/,
|
|
164
|
+
/^\/etc\/sudoers/,
|
|
165
|
+
/^~?\/?\.ssh\//,
|
|
166
|
+
/^~?\/?\.gnupg\//,
|
|
167
|
+
/^~?\/?\.aws\//,
|
|
168
|
+
/^~?\/?\.config\/gcloud/,
|
|
169
|
+
/\.env($|\.)/,
|
|
170
|
+
/\.pem$/,
|
|
171
|
+
/\.key$/,
|
|
172
|
+
/id_rsa/,
|
|
173
|
+
/id_ed25519/,
|
|
174
|
+
/credentials\.json/,
|
|
175
|
+
/secrets?\.(json|ya?ml|toml)/i,
|
|
176
|
+
/\.git\/config/,
|
|
177
|
+
/\.netrc/,
|
|
178
|
+
/\.npmrc/,
|
|
179
|
+
/\.pypirc/,
|
|
180
|
+
];
|
|
181
|
+
const CONTROL_CHAR_PATTERN = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
182
|
+
export class TaskSanitizationError extends GoalError {
|
|
183
|
+
issues;
|
|
184
|
+
constructor(message, issues) {
|
|
185
|
+
super('TASK_SANITIZATION_FAILED', message);
|
|
186
|
+
this.issues = issues;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export class TaskSanitizer {
|
|
190
|
+
allowedPaths;
|
|
191
|
+
deniedPaths;
|
|
192
|
+
allowedCommands;
|
|
193
|
+
deniedCommands;
|
|
194
|
+
maxTitleLength;
|
|
195
|
+
maxDescriptionLength;
|
|
196
|
+
strictMode;
|
|
197
|
+
customBlockedPatterns;
|
|
198
|
+
logger;
|
|
199
|
+
constructor(options = {}) {
|
|
200
|
+
this.allowedPaths = options.allowedPaths ?? [];
|
|
201
|
+
this.deniedPaths = options.deniedPaths ?? [];
|
|
202
|
+
this.allowedCommands = options.allowedCommands ?? [];
|
|
203
|
+
this.deniedCommands = options.deniedCommands ?? [];
|
|
204
|
+
this.maxTitleLength = options.maxTitleLength ?? MAX_TITLE_LENGTH;
|
|
205
|
+
this.maxDescriptionLength = options.maxDescriptionLength ?? MAX_DESCRIPTION_LENGTH;
|
|
206
|
+
this.strictMode = options.strictMode ?? false;
|
|
207
|
+
this.customBlockedPatterns = options.customBlockedPatterns ?? [];
|
|
208
|
+
this.logger = options.logger ?? noopLogger;
|
|
209
|
+
}
|
|
210
|
+
sanitize(input) {
|
|
211
|
+
const issues = [];
|
|
212
|
+
const warnings = [];
|
|
213
|
+
const modifications = [];
|
|
214
|
+
const sanitized = { ...input };
|
|
215
|
+
const titleInjections = this.checkPromptInjection(input.title, 'title');
|
|
216
|
+
issues.push(...titleInjections);
|
|
217
|
+
if (input.description) {
|
|
218
|
+
const descInjections = this.checkPromptInjection(input.description, 'description');
|
|
219
|
+
issues.push(...descInjections);
|
|
220
|
+
}
|
|
221
|
+
const sanitizedTitle = this.sanitizeText(input.title);
|
|
222
|
+
if (sanitizedTitle !== input.title) {
|
|
223
|
+
modifications.push('Title sanitized (control characters removed)');
|
|
224
|
+
sanitized.title = sanitizedTitle;
|
|
225
|
+
}
|
|
226
|
+
if (sanitizedTitle.length > this.maxTitleLength) {
|
|
227
|
+
issues.push({
|
|
228
|
+
type: 'excessive_length',
|
|
229
|
+
severity: 'low',
|
|
230
|
+
description: `Title exceeds maximum length (${sanitizedTitle.length} > ${this.maxTitleLength})`,
|
|
231
|
+
location: 'title',
|
|
232
|
+
});
|
|
233
|
+
sanitized.title = sanitizedTitle.substring(0, this.maxTitleLength);
|
|
234
|
+
modifications.push('Title truncated to maximum length');
|
|
235
|
+
}
|
|
236
|
+
if (input.description) {
|
|
237
|
+
const sanitizedDesc = this.sanitizeText(input.description);
|
|
238
|
+
if (sanitizedDesc !== input.description) {
|
|
239
|
+
modifications.push('Description sanitized (control characters removed)');
|
|
240
|
+
sanitized.description = sanitizedDesc;
|
|
241
|
+
}
|
|
242
|
+
if (sanitizedDesc.length > this.maxDescriptionLength) {
|
|
243
|
+
issues.push({
|
|
244
|
+
type: 'excessive_length',
|
|
245
|
+
severity: 'low',
|
|
246
|
+
description: `Description exceeds maximum length (${sanitizedDesc.length} > ${this.maxDescriptionLength})`,
|
|
247
|
+
location: 'description',
|
|
248
|
+
});
|
|
249
|
+
sanitized.description =
|
|
250
|
+
sanitizedDesc.substring(0, this.maxDescriptionLength);
|
|
251
|
+
modifications.push('Description truncated to maximum length');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (input.taskType && input.description) {
|
|
255
|
+
const cmdIssues = this.checkDangerousCommands(input.description, 'description');
|
|
256
|
+
issues.push(...cmdIssues);
|
|
257
|
+
}
|
|
258
|
+
const customIssues = this.checkCustomPatterns(input);
|
|
259
|
+
issues.push(...customIssues);
|
|
260
|
+
const criticalIssues = issues.filter((i) => i.severity === 'critical');
|
|
261
|
+
const highIssues = issues.filter((i) => i.severity === 'high');
|
|
262
|
+
const blocked = criticalIssues.length > 0 ||
|
|
263
|
+
(this.strictMode && highIssues.length > 0);
|
|
264
|
+
for (const issue of issues) {
|
|
265
|
+
if (issue.severity !== 'critical') {
|
|
266
|
+
warnings.push(`[${issue.severity.toUpperCase()}] ${issue.description}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const blockReason = blocked
|
|
270
|
+
? criticalIssues[0]?.description ?? highIssues[0]?.description
|
|
271
|
+
: undefined;
|
|
272
|
+
if (blocked) {
|
|
273
|
+
this.logger.warn('TASK_SANITIZER', 'Task blocked', {
|
|
274
|
+
reason: blockReason,
|
|
275
|
+
issueCount: issues.length,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
else if (issues.length > 0) {
|
|
279
|
+
this.logger.debug('TASK_SANITIZER', 'Task sanitized with warnings', {
|
|
280
|
+
warningCount: warnings.length,
|
|
281
|
+
modifications: modifications.length,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
isValid: !blocked,
|
|
286
|
+
sanitizedInput: blocked ? null : sanitized,
|
|
287
|
+
warnings,
|
|
288
|
+
blocked,
|
|
289
|
+
blockReason,
|
|
290
|
+
securityIssues: issues,
|
|
291
|
+
modifications,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
validatePath(path) {
|
|
295
|
+
const issues = [];
|
|
296
|
+
for (const { pattern, severity, description } of PATH_TRAVERSAL_PATTERNS) {
|
|
297
|
+
if (pattern.test(path)) {
|
|
298
|
+
issues.push({
|
|
299
|
+
type: 'path_traversal',
|
|
300
|
+
severity,
|
|
301
|
+
description,
|
|
302
|
+
location: 'path',
|
|
303
|
+
matchedPattern: pattern.toString(),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const pattern of SENSITIVE_PATHS) {
|
|
308
|
+
if (pattern.test(path)) {
|
|
309
|
+
issues.push({
|
|
310
|
+
type: 'sensitive_path',
|
|
311
|
+
severity: 'high',
|
|
312
|
+
description: `Access to sensitive path: ${path}`,
|
|
313
|
+
location: 'path',
|
|
314
|
+
matchedPattern: pattern.toString(),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const normalizedPath = path
|
|
319
|
+
.replace(/\\/g, '/')
|
|
320
|
+
.replace(/\/+/g, '/')
|
|
321
|
+
.replace(/\/$/, '');
|
|
322
|
+
for (const deniedPattern of this.deniedPaths) {
|
|
323
|
+
if (this.matchesGlob(normalizedPath, deniedPattern)) {
|
|
324
|
+
issues.push({
|
|
325
|
+
type: 'sensitive_path',
|
|
326
|
+
severity: 'high',
|
|
327
|
+
description: `Path matches denied pattern: ${deniedPattern}`,
|
|
328
|
+
location: 'path',
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (this.allowedPaths.length > 0) {
|
|
333
|
+
const isAllowed = this.allowedPaths.some((pattern) => this.matchesGlob(normalizedPath, pattern));
|
|
334
|
+
if (!isAllowed) {
|
|
335
|
+
issues.push({
|
|
336
|
+
type: 'sensitive_path',
|
|
337
|
+
severity: 'medium',
|
|
338
|
+
description: `Path not in allowed paths list`,
|
|
339
|
+
location: 'path',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
isValid: issues.filter((i) => i.severity === 'critical' || i.severity === 'high').length === 0,
|
|
345
|
+
normalizedPath,
|
|
346
|
+
issues,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
validateCommand(command) {
|
|
350
|
+
const issues = [];
|
|
351
|
+
const cmdIssues = this.checkDangerousCommands(command, 'command');
|
|
352
|
+
issues.push(...cmdIssues);
|
|
353
|
+
for (const denied of this.deniedCommands) {
|
|
354
|
+
if (command === denied ||
|
|
355
|
+
command.startsWith(denied + ' ') ||
|
|
356
|
+
command.includes(` ${denied} `) ||
|
|
357
|
+
command.includes(` ${denied}`)) {
|
|
358
|
+
issues.push({
|
|
359
|
+
type: 'dangerous_command',
|
|
360
|
+
severity: 'high',
|
|
361
|
+
description: `Command matches denied pattern: ${denied}`,
|
|
362
|
+
location: 'command',
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (this.allowedCommands.length > 0) {
|
|
367
|
+
const isAllowed = this.allowedCommands.some((allowed) => command === allowed ||
|
|
368
|
+
command.startsWith(allowed + ' '));
|
|
369
|
+
if (!isAllowed) {
|
|
370
|
+
issues.push({
|
|
371
|
+
type: 'dangerous_command',
|
|
372
|
+
severity: 'medium',
|
|
373
|
+
description: 'Command not in allowed commands list',
|
|
374
|
+
location: 'command',
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return issues;
|
|
379
|
+
}
|
|
380
|
+
checkPromptInjection(text, location) {
|
|
381
|
+
const issues = [];
|
|
382
|
+
for (const { pattern, severity, description } of PROMPT_INJECTION_PATTERNS) {
|
|
383
|
+
const match = text.match(pattern);
|
|
384
|
+
if (match) {
|
|
385
|
+
issues.push({
|
|
386
|
+
type: 'prompt_injection',
|
|
387
|
+
severity,
|
|
388
|
+
description,
|
|
389
|
+
location,
|
|
390
|
+
matchedPattern: match[0],
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return issues;
|
|
395
|
+
}
|
|
396
|
+
checkDangerousCommands(text, location) {
|
|
397
|
+
const issues = [];
|
|
398
|
+
for (const { pattern, severity, description } of DANGEROUS_COMMAND_PATTERNS) {
|
|
399
|
+
const match = text.match(pattern);
|
|
400
|
+
if (match) {
|
|
401
|
+
issues.push({
|
|
402
|
+
type: 'dangerous_command',
|
|
403
|
+
severity,
|
|
404
|
+
description,
|
|
405
|
+
location,
|
|
406
|
+
matchedPattern: match[0],
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return issues;
|
|
411
|
+
}
|
|
412
|
+
checkCustomPatterns(input) {
|
|
413
|
+
const issues = [];
|
|
414
|
+
const textToCheck = `${input.title} ${input.description ?? ''}`;
|
|
415
|
+
for (const pattern of this.customBlockedPatterns) {
|
|
416
|
+
const match = textToCheck.match(pattern);
|
|
417
|
+
if (match) {
|
|
418
|
+
issues.push({
|
|
419
|
+
type: 'suspicious_pattern',
|
|
420
|
+
severity: 'high',
|
|
421
|
+
description: `Matches custom blocked pattern`,
|
|
422
|
+
matchedPattern: match[0],
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return issues;
|
|
427
|
+
}
|
|
428
|
+
sanitizeText(text) {
|
|
429
|
+
return text.replace(CONTROL_CHAR_PATTERN, '').trim();
|
|
430
|
+
}
|
|
431
|
+
matchesGlob(path, pattern) {
|
|
432
|
+
const regexPattern = pattern
|
|
433
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
434
|
+
.replace(/\*/g, '.*')
|
|
435
|
+
.replace(/\?/g, '.');
|
|
436
|
+
const regex = new RegExp(`^${regexPattern}$`, 'i');
|
|
437
|
+
return regex.test(path);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
export function createTaskSanitizer(options = {}) {
|
|
441
|
+
return new TaskSanitizer(options);
|
|
442
|
+
}
|
|
443
|
+
export function createSecureTaskSanitizer(logger) {
|
|
444
|
+
return new TaskSanitizer({
|
|
445
|
+
deniedPaths: [
|
|
446
|
+
'./.git',
|
|
447
|
+
'./.env*',
|
|
448
|
+
'./secrets',
|
|
449
|
+
'./**/credentials*',
|
|
450
|
+
'./**/*.pem',
|
|
451
|
+
'./**/*.key',
|
|
452
|
+
],
|
|
453
|
+
deniedCommands: [
|
|
454
|
+
'rm -rf',
|
|
455
|
+
'rm -r /',
|
|
456
|
+
'git push --force',
|
|
457
|
+
'git push -f',
|
|
458
|
+
'npm publish',
|
|
459
|
+
'yarn publish',
|
|
460
|
+
],
|
|
461
|
+
strictMode: false,
|
|
462
|
+
logger,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { GoalHash, GoalStatus, TaskStatus } from './types.js';
|
|
2
|
+
export type GoalErrorCode = 'GOAL_NOT_FOUND' | 'GOAL_ALREADY_EXISTS' | 'GOAL_INVALID_STATUS' | 'GOAL_BLOCKED' | 'GOAL_DEPENDENCY_NOT_FOUND' | 'GOAL_CIRCULAR_DEPENDENCY' | 'MILESTONE_NOT_FOUND' | 'MILESTONE_ALREADY_COMPLETE' | 'TASK_NOT_FOUND' | 'TASK_INVALID_STATUS' | 'TASK_EXECUTION_ERROR' | 'TASK_EXECUTION_TIMEOUT' | 'TASK_APPROVAL_REQUIRED' | 'TASK_SANITIZATION_FAILED' | 'MEMORY_NOT_FOUND' | 'MEMORY_CONTENT_TOO_LONG' | 'META_GOAL_NOT_FOUND' | 'META_GOAL_CONSTRAINT_VIOLATED' | 'API_REQUEST_FAILED' | 'API_AUTHENTICATION_FAILED' | 'API_RATE_LIMITED' | 'API_RESPONSE_INVALID' | 'API_NETWORK_ERROR' | 'API_TIMEOUT' | 'VALIDATION_ERROR' | 'INVALID_INPUT' | 'INVALID_GOAL_NAME' | 'INVALID_TASK_TYPE' | 'CACHE_ERROR' | 'CACHE_MISS' | 'CACHE_STALE' | 'MANAGER_NOT_INITIALIZED' | 'MANAGER_ERROR' | 'DEPENDENCY_RESOLUTION_ERROR' | 'CHECKPOINT_NOT_FOUND' | 'RECOVERY_ERROR' | 'COMMS_ERROR' | 'APPROVAL_TIMEOUT' | 'ENFORCEMENT_ERROR' | 'MILESTONE_BREAKDOWN_ERROR' | 'PERMISSION_ERROR' | 'PERMISSION_DENIED' | 'TASK_GENERATION_ERROR' | 'TASK_QUOTA_EXCEEDED';
|
|
3
|
+
export declare class GoalError extends Error {
|
|
4
|
+
readonly code: GoalErrorCode;
|
|
5
|
+
readonly context: Record<string, unknown>;
|
|
6
|
+
readonly timestamp: Date;
|
|
7
|
+
constructor(code: GoalErrorCode, message: string, context?: Record<string, unknown>);
|
|
8
|
+
toJSON(): Record<string, unknown>;
|
|
9
|
+
toLogString(): string;
|
|
10
|
+
}
|
|
11
|
+
export declare class GoalNotFoundError extends GoalError {
|
|
12
|
+
constructor(identifier: string, identifierType?: 'hash' | 'id');
|
|
13
|
+
}
|
|
14
|
+
export declare class GoalAlreadyExistsError extends GoalError {
|
|
15
|
+
constructor(name: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class GoalInvalidStatusError extends GoalError {
|
|
18
|
+
constructor(goalHash: GoalHash, currentStatus: GoalStatus, operation: string, allowedStatuses: GoalStatus[]);
|
|
19
|
+
}
|
|
20
|
+
export declare class GoalBlockedError extends GoalError {
|
|
21
|
+
constructor(goalHash: GoalHash, blockedBy: GoalHash[]);
|
|
22
|
+
}
|
|
23
|
+
export declare class GoalDependencyNotFoundError extends GoalError {
|
|
24
|
+
constructor(goalHash: GoalHash, dependencyHash: GoalHash);
|
|
25
|
+
}
|
|
26
|
+
export declare class GoalCircularDependencyError extends GoalError {
|
|
27
|
+
constructor(goalHash: GoalHash, cycle: GoalHash[]);
|
|
28
|
+
}
|
|
29
|
+
export declare class MilestoneNotFoundError extends GoalError {
|
|
30
|
+
constructor(goalHash: GoalHash, milestoneId: number);
|
|
31
|
+
}
|
|
32
|
+
export declare class MilestoneAlreadyCompleteError extends GoalError {
|
|
33
|
+
constructor(goalHash: GoalHash, milestoneId: number);
|
|
34
|
+
}
|
|
35
|
+
export declare class TaskNotFoundError extends GoalError {
|
|
36
|
+
constructor(goalHash: GoalHash, taskId: number);
|
|
37
|
+
}
|
|
38
|
+
export declare class TaskInvalidStatusError extends GoalError {
|
|
39
|
+
constructor(taskId: number, currentStatus: TaskStatus, operation: string, allowedStatuses: TaskStatus[]);
|
|
40
|
+
}
|
|
41
|
+
export declare class TaskExecutionError extends GoalError {
|
|
42
|
+
constructor(taskId: number, cause: string, originalError?: Error);
|
|
43
|
+
}
|
|
44
|
+
export declare class TaskExecutionTimeoutError extends GoalError {
|
|
45
|
+
constructor(taskId: number, timeoutMs: number);
|
|
46
|
+
}
|
|
47
|
+
export declare class TaskApprovalRequiredError extends GoalError {
|
|
48
|
+
constructor(taskId: number, permissionCategory: string | null);
|
|
49
|
+
}
|
|
50
|
+
export declare class TaskSanitizationFailedError extends GoalError {
|
|
51
|
+
constructor(taskId: number, reason: string);
|
|
52
|
+
}
|
|
53
|
+
export declare class MemoryNotFoundError extends GoalError {
|
|
54
|
+
constructor(goalHash: GoalHash, memoryId: number);
|
|
55
|
+
}
|
|
56
|
+
export declare class MemoryContentTooLongError extends GoalError {
|
|
57
|
+
constructor(contentLength: number, maxLength: number);
|
|
58
|
+
}
|
|
59
|
+
export declare class MetaGoalNotFoundError extends GoalError {
|
|
60
|
+
constructor(metaGoalId: number);
|
|
61
|
+
}
|
|
62
|
+
export declare class MetaGoalConstraintViolatedError extends GoalError {
|
|
63
|
+
constructor(metaGoalId: number, description: string, violation: string);
|
|
64
|
+
}
|
|
65
|
+
export declare class ApiRequestFailedError extends GoalError {
|
|
66
|
+
constructor(endpoint: string, method: string, statusCode: number | null, reason: string);
|
|
67
|
+
}
|
|
68
|
+
export declare class ApiAuthenticationFailedError extends GoalError {
|
|
69
|
+
constructor(reason: string);
|
|
70
|
+
}
|
|
71
|
+
export declare class ApiRateLimitedError extends GoalError {
|
|
72
|
+
constructor(retryAfter: number | null);
|
|
73
|
+
}
|
|
74
|
+
export declare class ApiResponseInvalidError extends GoalError {
|
|
75
|
+
constructor(endpoint: string, reason: string);
|
|
76
|
+
}
|
|
77
|
+
export declare class ApiNetworkError extends GoalError {
|
|
78
|
+
constructor(endpoint: string, reason: string, originalError?: Error);
|
|
79
|
+
}
|
|
80
|
+
export declare class ApiTimeoutError extends GoalError {
|
|
81
|
+
constructor(endpoint: string, timeoutMs: number);
|
|
82
|
+
}
|
|
83
|
+
export declare class ValidationError extends GoalError {
|
|
84
|
+
readonly errors?: Record<string, string[]>;
|
|
85
|
+
constructor(message: string, errors: Record<string, string[]>);
|
|
86
|
+
constructor(field: string, value: unknown, reason: string);
|
|
87
|
+
}
|
|
88
|
+
export declare class InvalidInputError extends GoalError {
|
|
89
|
+
constructor(input: string, reason: string);
|
|
90
|
+
}
|
|
91
|
+
export declare class InvalidGoalNameError extends GoalError {
|
|
92
|
+
constructor(name: string, reason: string);
|
|
93
|
+
}
|
|
94
|
+
export declare class InvalidTaskTypeError extends GoalError {
|
|
95
|
+
constructor(taskType: string);
|
|
96
|
+
}
|
|
97
|
+
export declare class CacheError extends GoalError {
|
|
98
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
99
|
+
}
|
|
100
|
+
export declare class CacheMissError extends GoalError {
|
|
101
|
+
constructor(key: string);
|
|
102
|
+
}
|
|
103
|
+
export declare class CacheStaleError extends GoalError {
|
|
104
|
+
constructor(key: string, age: number, maxAge: number);
|
|
105
|
+
}
|
|
106
|
+
export declare class ManagerNotInitializedError extends GoalError {
|
|
107
|
+
constructor();
|
|
108
|
+
}
|
|
109
|
+
export declare class ManagerError extends GoalError {
|
|
110
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
111
|
+
}
|
|
112
|
+
export declare function isGoalError(error: unknown): error is GoalError;
|
|
113
|
+
export declare function hasErrorCode(error: unknown, code: GoalErrorCode): error is GoalError;
|
|
114
|
+
export declare function wrapError(error: unknown, code: GoalErrorCode, message: string): GoalError;
|
|
115
|
+
export declare function isNotFoundError(error: unknown): boolean;
|
|
116
|
+
export declare function isApiError(error: unknown): boolean;
|