@compilr-dev/agents 0.0.1
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/README.md +1277 -0
- package/dist/agent.d.ts +1272 -0
- package/dist/agent.js +1912 -0
- package/dist/anchors/builtin.d.ts +24 -0
- package/dist/anchors/builtin.js +61 -0
- package/dist/anchors/index.d.ts +6 -0
- package/dist/anchors/index.js +5 -0
- package/dist/anchors/manager.d.ts +115 -0
- package/dist/anchors/manager.js +412 -0
- package/dist/anchors/types.d.ts +168 -0
- package/dist/anchors/types.js +10 -0
- package/dist/context/index.d.ts +12 -0
- package/dist/context/index.js +10 -0
- package/dist/context/manager.d.ts +224 -0
- package/dist/context/manager.js +770 -0
- package/dist/context/types.d.ts +377 -0
- package/dist/context/types.js +7 -0
- package/dist/costs/index.d.ts +8 -0
- package/dist/costs/index.js +7 -0
- package/dist/costs/tracker.d.ts +121 -0
- package/dist/costs/tracker.js +295 -0
- package/dist/costs/types.d.ts +157 -0
- package/dist/costs/types.js +8 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +249 -0
- package/dist/guardrails/builtin.d.ts +27 -0
- package/dist/guardrails/builtin.js +223 -0
- package/dist/guardrails/index.d.ts +6 -0
- package/dist/guardrails/index.js +5 -0
- package/dist/guardrails/manager.d.ts +117 -0
- package/dist/guardrails/manager.js +288 -0
- package/dist/guardrails/types.d.ts +159 -0
- package/dist/guardrails/types.js +7 -0
- package/dist/hooks/index.d.ts +31 -0
- package/dist/hooks/index.js +29 -0
- package/dist/hooks/manager.d.ts +147 -0
- package/dist/hooks/manager.js +600 -0
- package/dist/hooks/types.d.ts +368 -0
- package/dist/hooks/types.js +12 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +73 -0
- package/dist/mcp/client.d.ts +93 -0
- package/dist/mcp/client.js +287 -0
- package/dist/mcp/errors.d.ts +60 -0
- package/dist/mcp/errors.js +78 -0
- package/dist/mcp/index.d.ts +43 -0
- package/dist/mcp/index.js +45 -0
- package/dist/mcp/manager.d.ts +120 -0
- package/dist/mcp/manager.js +276 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.js +99 -0
- package/dist/mcp/types.d.ts +150 -0
- package/dist/mcp/types.js +40 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/loader.d.ts +114 -0
- package/dist/memory/loader.js +463 -0
- package/dist/memory/types.d.ts +182 -0
- package/dist/memory/types.js +8 -0
- package/dist/messages/index.d.ts +82 -0
- package/dist/messages/index.js +155 -0
- package/dist/permissions/index.d.ts +5 -0
- package/dist/permissions/index.js +4 -0
- package/dist/permissions/manager.d.ts +125 -0
- package/dist/permissions/manager.js +379 -0
- package/dist/permissions/types.d.ts +162 -0
- package/dist/permissions/types.js +7 -0
- package/dist/providers/claude.d.ts +90 -0
- package/dist/providers/claude.js +348 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/mock.d.ts +133 -0
- package/dist/providers/mock.js +204 -0
- package/dist/providers/types.d.ts +168 -0
- package/dist/providers/types.js +4 -0
- package/dist/rate-limit/index.d.ts +45 -0
- package/dist/rate-limit/index.js +47 -0
- package/dist/rate-limit/limiter.d.ts +104 -0
- package/dist/rate-limit/limiter.js +326 -0
- package/dist/rate-limit/provider-wrapper.d.ts +112 -0
- package/dist/rate-limit/provider-wrapper.js +201 -0
- package/dist/rate-limit/retry.d.ts +108 -0
- package/dist/rate-limit/retry.js +287 -0
- package/dist/rate-limit/types.d.ts +181 -0
- package/dist/rate-limit/types.js +22 -0
- package/dist/rehearsal/file-analyzer.d.ts +22 -0
- package/dist/rehearsal/file-analyzer.js +351 -0
- package/dist/rehearsal/git-analyzer.d.ts +22 -0
- package/dist/rehearsal/git-analyzer.js +472 -0
- package/dist/rehearsal/index.d.ts +35 -0
- package/dist/rehearsal/index.js +36 -0
- package/dist/rehearsal/manager.d.ts +100 -0
- package/dist/rehearsal/manager.js +290 -0
- package/dist/rehearsal/types.d.ts +235 -0
- package/dist/rehearsal/types.js +8 -0
- package/dist/skills/index.d.ts +160 -0
- package/dist/skills/index.js +282 -0
- package/dist/state/agent-state.d.ts +41 -0
- package/dist/state/agent-state.js +88 -0
- package/dist/state/checkpointer.d.ts +110 -0
- package/dist/state/checkpointer.js +362 -0
- package/dist/state/errors.d.ts +66 -0
- package/dist/state/errors.js +88 -0
- package/dist/state/index.d.ts +35 -0
- package/dist/state/index.js +37 -0
- package/dist/state/serializer.d.ts +55 -0
- package/dist/state/serializer.js +172 -0
- package/dist/state/types.d.ts +312 -0
- package/dist/state/types.js +14 -0
- package/dist/tools/builtin/bash-output.d.ts +61 -0
- package/dist/tools/builtin/bash-output.js +90 -0
- package/dist/tools/builtin/bash.d.ts +150 -0
- package/dist/tools/builtin/bash.js +354 -0
- package/dist/tools/builtin/edit.d.ts +50 -0
- package/dist/tools/builtin/edit.js +215 -0
- package/dist/tools/builtin/glob.d.ts +62 -0
- package/dist/tools/builtin/glob.js +244 -0
- package/dist/tools/builtin/grep.d.ts +74 -0
- package/dist/tools/builtin/grep.js +363 -0
- package/dist/tools/builtin/index.d.ts +44 -0
- package/dist/tools/builtin/index.js +69 -0
- package/dist/tools/builtin/kill-shell.d.ts +44 -0
- package/dist/tools/builtin/kill-shell.js +80 -0
- package/dist/tools/builtin/read-file.d.ts +57 -0
- package/dist/tools/builtin/read-file.js +184 -0
- package/dist/tools/builtin/shell-manager.d.ts +176 -0
- package/dist/tools/builtin/shell-manager.js +337 -0
- package/dist/tools/builtin/task.d.ts +202 -0
- package/dist/tools/builtin/task.js +350 -0
- package/dist/tools/builtin/todo.d.ts +207 -0
- package/dist/tools/builtin/todo.js +453 -0
- package/dist/tools/builtin/utils.d.ts +27 -0
- package/dist/tools/builtin/utils.js +70 -0
- package/dist/tools/builtin/web-fetch.d.ts +96 -0
- package/dist/tools/builtin/web-fetch.js +290 -0
- package/dist/tools/builtin/write-file.d.ts +54 -0
- package/dist/tools/builtin/write-file.js +147 -0
- package/dist/tools/define.d.ts +60 -0
- package/dist/tools/define.js +65 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/registry.d.ts +79 -0
- package/dist/tools/registry.js +151 -0
- package/dist/tools/types.d.ts +59 -0
- package/dist/tools/types.js +4 -0
- package/dist/tracing/hooks.d.ts +58 -0
- package/dist/tracing/hooks.js +377 -0
- package/dist/tracing/index.d.ts +51 -0
- package/dist/tracing/index.js +55 -0
- package/dist/tracing/logging.d.ts +78 -0
- package/dist/tracing/logging.js +310 -0
- package/dist/tracing/manager.d.ts +160 -0
- package/dist/tracing/manager.js +468 -0
- package/dist/tracing/otel.d.ts +102 -0
- package/dist/tracing/otel.js +246 -0
- package/dist/tracing/types.d.ts +346 -0
- package/dist/tracing/types.js +38 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.js +44 -0
- package/package.json +79 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for @compilr-dev/agents
|
|
3
|
+
*
|
|
4
|
+
* Error hierarchy:
|
|
5
|
+
* - AgentError (base)
|
|
6
|
+
* - ProviderError (LLM API errors)
|
|
7
|
+
* - ToolError (tool execution errors)
|
|
8
|
+
* - ValidationError (input validation errors)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Base error class for all agent-related errors.
|
|
12
|
+
*/
|
|
13
|
+
export class AgentError extends Error {
|
|
14
|
+
cause;
|
|
15
|
+
constructor(message, cause) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
this.name = 'AgentError';
|
|
19
|
+
// Maintains proper stack trace in V8 environments
|
|
20
|
+
if (typeof Error.captureStackTrace === 'function') {
|
|
21
|
+
Error.captureStackTrace(this, this.constructor);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when an LLM provider API call fails.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* throw new ProviderError(
|
|
31
|
+
* 'Rate limit exceeded. Retry after 60s',
|
|
32
|
+
* 'claude',
|
|
33
|
+
* 429
|
|
34
|
+
* );
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class ProviderError extends AgentError {
|
|
38
|
+
provider;
|
|
39
|
+
statusCode;
|
|
40
|
+
constructor(message, provider, statusCode, cause) {
|
|
41
|
+
super(message, cause);
|
|
42
|
+
this.provider = provider;
|
|
43
|
+
this.statusCode = statusCode;
|
|
44
|
+
this.name = 'ProviderError';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if this is a rate limit error (HTTP 429)
|
|
48
|
+
*/
|
|
49
|
+
isRateLimitError() {
|
|
50
|
+
return this.statusCode === 429;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if this is an authentication error (HTTP 401/403)
|
|
54
|
+
*/
|
|
55
|
+
isAuthError() {
|
|
56
|
+
return this.statusCode === 401 || this.statusCode === 403;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if this is a server error (HTTP 5xx)
|
|
60
|
+
*/
|
|
61
|
+
isServerError() {
|
|
62
|
+
return this.statusCode !== undefined && this.statusCode >= 500 && this.statusCode < 600;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if this error is retryable
|
|
66
|
+
*/
|
|
67
|
+
isRetryable() {
|
|
68
|
+
return this.isRateLimitError() || this.isServerError();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Error thrown when a tool execution fails.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* throw new ToolError(
|
|
77
|
+
* 'File not found: /path/to/file.txt',
|
|
78
|
+
* 'read_file',
|
|
79
|
+
* originalError
|
|
80
|
+
* );
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export class ToolError extends AgentError {
|
|
84
|
+
toolName;
|
|
85
|
+
constructor(message, toolName, cause) {
|
|
86
|
+
super(message, cause);
|
|
87
|
+
this.toolName = toolName;
|
|
88
|
+
this.name = 'ToolError';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Error thrown when a tool execution times out.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* throw new ToolTimeoutError('read_file', 30000);
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export class ToolTimeoutError extends ToolError {
|
|
100
|
+
toolName;
|
|
101
|
+
timeoutMs;
|
|
102
|
+
constructor(toolName, timeoutMs) {
|
|
103
|
+
super(`Tool '${toolName}' timed out after ${String(timeoutMs)}ms`, toolName);
|
|
104
|
+
this.toolName = toolName;
|
|
105
|
+
this.timeoutMs = timeoutMs;
|
|
106
|
+
this.name = 'ToolTimeoutError';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Error thrown when input validation fails.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* throw new ValidationError(
|
|
115
|
+
* 'maxTokens must be a positive number',
|
|
116
|
+
* 'maxTokens'
|
|
117
|
+
* );
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export class ValidationError extends AgentError {
|
|
121
|
+
field;
|
|
122
|
+
constructor(message, field) {
|
|
123
|
+
super(message);
|
|
124
|
+
this.field = field;
|
|
125
|
+
this.name = 'ValidationError';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Error thrown when the agentic loop exceeds max iterations.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* throw new MaxIterationsError(10);
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export class MaxIterationsError extends AgentError {
|
|
137
|
+
maxIterations;
|
|
138
|
+
constructor(maxIterations) {
|
|
139
|
+
super(`Agent exceeded maximum iterations (${String(maxIterations)})`);
|
|
140
|
+
this.maxIterations = maxIterations;
|
|
141
|
+
this.name = 'MaxIterationsError';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Error thrown when the agent is stuck in a tool call loop.
|
|
146
|
+
*
|
|
147
|
+
* This occurs when the same tool is called with identical input
|
|
148
|
+
* multiple times consecutively, indicating the agent is not
|
|
149
|
+
* processing the tool results properly.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* throw new ToolLoopError('read_file', 3);
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export class ToolLoopError extends AgentError {
|
|
157
|
+
toolName;
|
|
158
|
+
consecutiveCalls;
|
|
159
|
+
input;
|
|
160
|
+
constructor(toolName, consecutiveCalls, input) {
|
|
161
|
+
super(`Agent stuck in tool loop: '${toolName}' called ${String(consecutiveCalls)} times ` +
|
|
162
|
+
`with identical input. The agent may not be processing tool results correctly.`);
|
|
163
|
+
this.toolName = toolName;
|
|
164
|
+
this.consecutiveCalls = consecutiveCalls;
|
|
165
|
+
this.input = input;
|
|
166
|
+
this.name = 'ToolLoopError';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Error thrown when a request is aborted via AbortSignal.
|
|
171
|
+
*/
|
|
172
|
+
export class AbortError extends AgentError {
|
|
173
|
+
constructor(message = 'Request was aborted') {
|
|
174
|
+
super(message);
|
|
175
|
+
this.name = 'AbortError';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Error thrown when context window cannot be reduced sufficiently.
|
|
180
|
+
*
|
|
181
|
+
* This occurs when:
|
|
182
|
+
* - Multiple summarization rounds fail to reduce context below target
|
|
183
|
+
* - Content is too large even after aggressive filtering
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* throw new ContextOverflowError(
|
|
188
|
+
* 'Unable to reduce context below 90% after 3 summarization rounds',
|
|
189
|
+
* 0.95, // current utilization
|
|
190
|
+
* 3 // rounds attempted
|
|
191
|
+
* );
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export class ContextOverflowError extends AgentError {
|
|
195
|
+
utilization;
|
|
196
|
+
roundsAttempted;
|
|
197
|
+
constructor(message, utilization, roundsAttempted) {
|
|
198
|
+
super(message);
|
|
199
|
+
this.utilization = utilization;
|
|
200
|
+
this.roundsAttempted = roundsAttempted;
|
|
201
|
+
this.name = 'ContextOverflowError';
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Type guard to check if an error is a ContextOverflowError
|
|
206
|
+
*/
|
|
207
|
+
export function isContextOverflowError(error) {
|
|
208
|
+
return error instanceof ContextOverflowError;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Type guard to check if an error is an AgentError
|
|
212
|
+
*/
|
|
213
|
+
export function isAgentError(error) {
|
|
214
|
+
return error instanceof AgentError;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Type guard to check if an error is a ProviderError
|
|
218
|
+
*/
|
|
219
|
+
export function isProviderError(error) {
|
|
220
|
+
return error instanceof ProviderError;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Type guard to check if an error is a ToolError
|
|
224
|
+
*/
|
|
225
|
+
export function isToolError(error) {
|
|
226
|
+
return error instanceof ToolError;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Type guard to check if an error is a ToolLoopError
|
|
230
|
+
*/
|
|
231
|
+
export function isToolLoopError(error) {
|
|
232
|
+
return error instanceof ToolLoopError;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Type guard to check if an error is a ToolTimeoutError
|
|
236
|
+
*/
|
|
237
|
+
export function isToolTimeoutError(error) {
|
|
238
|
+
return error instanceof ToolTimeoutError;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Wrap an unknown error into an AgentError
|
|
242
|
+
*/
|
|
243
|
+
export function wrapError(error, message) {
|
|
244
|
+
if (error instanceof AgentError) {
|
|
245
|
+
return error;
|
|
246
|
+
}
|
|
247
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
248
|
+
return new AgentError(message ?? cause.message, cause);
|
|
249
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in guardrails for common dangerous operations
|
|
3
|
+
*
|
|
4
|
+
* These guardrails provide sensible safety defaults that can be disabled
|
|
5
|
+
* by setting includeDefaults: false in GuardrailManagerOptions.
|
|
6
|
+
*/
|
|
7
|
+
import type { Guardrail } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Built-in guardrails for dangerous operations
|
|
10
|
+
*/
|
|
11
|
+
export declare const BUILTIN_GUARDRAILS: Guardrail[];
|
|
12
|
+
/**
|
|
13
|
+
* Get a copy of the built-in guardrails
|
|
14
|
+
*/
|
|
15
|
+
export declare function getBuiltinGuardrails(): Guardrail[];
|
|
16
|
+
/**
|
|
17
|
+
* Check if a guardrail is a built-in default
|
|
18
|
+
*/
|
|
19
|
+
export declare function isBuiltinGuardrail(guardrail: Guardrail): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Get built-in guardrail IDs
|
|
22
|
+
*/
|
|
23
|
+
export declare function getBuiltinGuardrailIds(): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Get guardrails by tag
|
|
26
|
+
*/
|
|
27
|
+
export declare function getGuardrailsByTag(tag: string): Guardrail[];
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in guardrails for common dangerous operations
|
|
3
|
+
*
|
|
4
|
+
* These guardrails provide sensible safety defaults that can be disabled
|
|
5
|
+
* by setting includeDefaults: false in GuardrailManagerOptions.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Built-in guardrails for dangerous operations
|
|
9
|
+
*/
|
|
10
|
+
export const BUILTIN_GUARDRAILS = [
|
|
11
|
+
// ==========================================================================
|
|
12
|
+
// Git Destructive Operations
|
|
13
|
+
// ==========================================================================
|
|
14
|
+
{
|
|
15
|
+
id: 'git-reset-hard',
|
|
16
|
+
name: 'Git Hard Reset',
|
|
17
|
+
description: 'Detects git reset --hard which discards uncommitted changes',
|
|
18
|
+
patterns: [/git\s+reset\s+--hard/i],
|
|
19
|
+
action: 'confirm',
|
|
20
|
+
message: 'git reset --hard will discard all uncommitted changes. Are you sure?',
|
|
21
|
+
scope: ['bash'],
|
|
22
|
+
tags: ['builtin', 'git', 'destructive'],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'git-clean',
|
|
26
|
+
name: 'Git Clean',
|
|
27
|
+
description: 'Detects git clean which deletes untracked files',
|
|
28
|
+
patterns: [/git\s+clean\s+-[fd]/i],
|
|
29
|
+
action: 'confirm',
|
|
30
|
+
message: 'git clean will permanently delete untracked files.',
|
|
31
|
+
scope: ['bash'],
|
|
32
|
+
tags: ['builtin', 'git', 'destructive'],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'git-force-push',
|
|
36
|
+
name: 'Git Force Push',
|
|
37
|
+
description: 'Detects force push which can overwrite remote history',
|
|
38
|
+
patterns: [/git\s+push\s+.*--force/i, /git\s+push\s+-f\b/i],
|
|
39
|
+
action: 'warn',
|
|
40
|
+
message: 'Force push can overwrite remote history. Verify this is intentional.',
|
|
41
|
+
scope: ['bash'],
|
|
42
|
+
tags: ['builtin', 'git', 'destructive'],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'git-checkout-discard',
|
|
46
|
+
name: 'Git Checkout Discard',
|
|
47
|
+
description: 'Detects git checkout -- which discards local changes',
|
|
48
|
+
patterns: [/git\s+checkout\s+--\s+/i],
|
|
49
|
+
action: 'warn',
|
|
50
|
+
message: 'git checkout -- will discard local changes to the specified files.',
|
|
51
|
+
scope: ['bash'],
|
|
52
|
+
tags: ['builtin', 'git', 'destructive'],
|
|
53
|
+
},
|
|
54
|
+
// ==========================================================================
|
|
55
|
+
// File System Dangers
|
|
56
|
+
// ==========================================================================
|
|
57
|
+
{
|
|
58
|
+
id: 'rm-rf',
|
|
59
|
+
name: 'Recursive Delete',
|
|
60
|
+
description: 'Detects rm -rf which recursively deletes without confirmation',
|
|
61
|
+
patterns: [/rm\s+-rf\s/i, /rm\s+.*-r.*-f/i, /rm\s+-fr\s/i],
|
|
62
|
+
action: 'confirm',
|
|
63
|
+
message: 'Recursive delete detected. Verify the path is correct.',
|
|
64
|
+
scope: ['bash'],
|
|
65
|
+
tags: ['builtin', 'filesystem', 'destructive'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'rm-root',
|
|
69
|
+
name: 'Root Delete Protection',
|
|
70
|
+
description: 'Prevents deletion of root or home directories',
|
|
71
|
+
patterns: [/rm\s+.*\s+\/($|\s)/, /rm\s+.*\s+~\/($|\s)/, /rm\s+.*\s+\$HOME($|\s|\/)/],
|
|
72
|
+
action: 'block',
|
|
73
|
+
message: 'Deletion of root or home directory is blocked.',
|
|
74
|
+
scope: ['bash'],
|
|
75
|
+
tags: ['builtin', 'filesystem', 'critical'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'chmod-777',
|
|
79
|
+
name: 'Insecure Permissions',
|
|
80
|
+
description: 'Detects chmod 777 which gives full access to everyone',
|
|
81
|
+
patterns: [/chmod\s+777/i, /chmod\s+a\+rwx/i],
|
|
82
|
+
action: 'warn',
|
|
83
|
+
message: 'chmod 777 gives full access to everyone. Consider more restrictive permissions.',
|
|
84
|
+
scope: ['bash'],
|
|
85
|
+
tags: ['builtin', 'filesystem', 'security'],
|
|
86
|
+
},
|
|
87
|
+
// ==========================================================================
|
|
88
|
+
// Database Dangers
|
|
89
|
+
// ==========================================================================
|
|
90
|
+
{
|
|
91
|
+
id: 'drop-table',
|
|
92
|
+
name: 'SQL Drop Table',
|
|
93
|
+
description: 'Detects DROP TABLE statements',
|
|
94
|
+
patterns: [/DROP\s+TABLE/i],
|
|
95
|
+
action: 'confirm',
|
|
96
|
+
message: 'DROP TABLE will permanently delete the table and all its data.',
|
|
97
|
+
scope: ['bash'],
|
|
98
|
+
tags: ['builtin', 'database', 'destructive'],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'truncate-table',
|
|
102
|
+
name: 'SQL Truncate',
|
|
103
|
+
description: 'Detects TRUNCATE statements',
|
|
104
|
+
patterns: [/TRUNCATE\s+TABLE/i, /TRUNCATE\s+\w+/i],
|
|
105
|
+
action: 'confirm',
|
|
106
|
+
message: 'TRUNCATE will delete all data from the table.',
|
|
107
|
+
scope: ['bash'],
|
|
108
|
+
tags: ['builtin', 'database', 'destructive'],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'delete-all',
|
|
112
|
+
name: 'SQL Delete Without WHERE',
|
|
113
|
+
description: 'Detects DELETE statements without WHERE clause',
|
|
114
|
+
patterns: [/DELETE\s+FROM\s+\w+\s*;/i, /DELETE\s+FROM\s+\w+\s*$/im],
|
|
115
|
+
action: 'warn',
|
|
116
|
+
message: 'DELETE without WHERE clause will delete all rows. Verify this is intentional.',
|
|
117
|
+
scope: ['bash'],
|
|
118
|
+
tags: ['builtin', 'database', 'destructive'],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'drop-database',
|
|
122
|
+
name: 'SQL Drop Database',
|
|
123
|
+
description: 'Detects DROP DATABASE statements',
|
|
124
|
+
patterns: [/DROP\s+DATABASE/i],
|
|
125
|
+
action: 'block',
|
|
126
|
+
message: 'DROP DATABASE is blocked. This would delete the entire database.',
|
|
127
|
+
scope: ['bash'],
|
|
128
|
+
tags: ['builtin', 'database', 'critical'],
|
|
129
|
+
},
|
|
130
|
+
// ==========================================================================
|
|
131
|
+
// Secrets and Credentials
|
|
132
|
+
// ==========================================================================
|
|
133
|
+
{
|
|
134
|
+
id: 'env-exposure',
|
|
135
|
+
name: 'Environment Variable Exposure',
|
|
136
|
+
description: 'Detects commands that might expose secrets',
|
|
137
|
+
patterns: [
|
|
138
|
+
/echo\s+\$[A-Z_]*KEY/i,
|
|
139
|
+
/echo\s+\$[A-Z_]*SECRET/i,
|
|
140
|
+
/echo\s+\$[A-Z_]*PASSWORD/i,
|
|
141
|
+
/echo\s+\$[A-Z_]*TOKEN/i,
|
|
142
|
+
/printenv\s+[A-Z_]*KEY/i,
|
|
143
|
+
/printenv\s+[A-Z_]*SECRET/i,
|
|
144
|
+
/printenv\s+[A-Z_]*PASSWORD/i,
|
|
145
|
+
],
|
|
146
|
+
action: 'warn',
|
|
147
|
+
message: 'This command may expose sensitive environment variables.',
|
|
148
|
+
scope: ['bash'],
|
|
149
|
+
tags: ['builtin', 'security', 'secrets'],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: 'hardcoded-secrets',
|
|
153
|
+
name: 'Hardcoded Secrets Detection',
|
|
154
|
+
description: 'Detects potential hardcoded secrets in commands',
|
|
155
|
+
patterns: [
|
|
156
|
+
/password\s*=\s*['"][^'"]+['"]/i,
|
|
157
|
+
/api_key\s*=\s*['"][^'"]+['"]/i,
|
|
158
|
+
/secret\s*=\s*['"][^'"]+['"]/i,
|
|
159
|
+
/token\s*=\s*['"][^'"]+['"]/i,
|
|
160
|
+
],
|
|
161
|
+
action: 'warn',
|
|
162
|
+
message: 'Potential hardcoded secret detected. Consider using environment variables.',
|
|
163
|
+
scope: ['bash'],
|
|
164
|
+
tags: ['builtin', 'security', 'secrets'],
|
|
165
|
+
},
|
|
166
|
+
// ==========================================================================
|
|
167
|
+
// Network and System
|
|
168
|
+
// ==========================================================================
|
|
169
|
+
{
|
|
170
|
+
id: 'curl-pipe-bash',
|
|
171
|
+
name: 'Curl Pipe to Bash',
|
|
172
|
+
description: 'Detects piping curl output directly to bash',
|
|
173
|
+
patterns: [
|
|
174
|
+
/curl\s+.*\|\s*bash/i,
|
|
175
|
+
/curl\s+.*\|\s*sh\b/i,
|
|
176
|
+
/wget\s+.*\|\s*bash/i,
|
|
177
|
+
/wget\s+.*\|\s*sh\b/i,
|
|
178
|
+
],
|
|
179
|
+
action: 'warn',
|
|
180
|
+
message: 'Piping remote content directly to shell is risky. Consider downloading and reviewing first.',
|
|
181
|
+
scope: ['bash'],
|
|
182
|
+
tags: ['builtin', 'security', 'network'],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'sudo-dangerous',
|
|
186
|
+
name: 'Dangerous Sudo Operations',
|
|
187
|
+
description: 'Detects potentially dangerous sudo commands',
|
|
188
|
+
patterns: [/sudo\s+rm\s+-rf\s+\//i, /sudo\s+dd\s+/i, /sudo\s+mkfs/i],
|
|
189
|
+
action: 'confirm',
|
|
190
|
+
message: 'This sudo command could cause system damage. Verify before proceeding.',
|
|
191
|
+
scope: ['bash'],
|
|
192
|
+
tags: ['builtin', 'system', 'critical'],
|
|
193
|
+
},
|
|
194
|
+
];
|
|
195
|
+
/**
|
|
196
|
+
* Get a copy of the built-in guardrails
|
|
197
|
+
*/
|
|
198
|
+
export function getBuiltinGuardrails() {
|
|
199
|
+
return BUILTIN_GUARDRAILS.map((g) => ({
|
|
200
|
+
...g,
|
|
201
|
+
patterns: g.patterns.map((p) => new RegExp(p.source, p.flags)),
|
|
202
|
+
scope: g.scope ? [...g.scope] : undefined,
|
|
203
|
+
tags: g.tags ? [...g.tags] : undefined,
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if a guardrail is a built-in default
|
|
208
|
+
*/
|
|
209
|
+
export function isBuiltinGuardrail(guardrail) {
|
|
210
|
+
return guardrail.tags?.includes('builtin') ?? false;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get built-in guardrail IDs
|
|
214
|
+
*/
|
|
215
|
+
export function getBuiltinGuardrailIds() {
|
|
216
|
+
return BUILTIN_GUARDRAILS.map((g) => g.id);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get guardrails by tag
|
|
220
|
+
*/
|
|
221
|
+
export function getGuardrailsByTag(tag) {
|
|
222
|
+
return getBuiltinGuardrails().filter((g) => g.tags?.includes(tag));
|
|
223
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guardrails module - Pattern-based safety checks for tool execution
|
|
3
|
+
*/
|
|
4
|
+
export { GuardrailManager } from './manager.js';
|
|
5
|
+
export { getBuiltinGuardrails, isBuiltinGuardrail, getBuiltinGuardrailIds, getGuardrailsByTag, BUILTIN_GUARDRAILS, } from './builtin.js';
|
|
6
|
+
export type { Guardrail, GuardrailInput, GuardrailAction, GuardrailResult, GuardrailContext, GuardrailManagerOptions, GuardrailTriggeredHandler, GuardrailEventType, GuardrailEvent, GuardrailEventHandler, } from './types.js';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardrailManager - Pattern-based safety checks for tool execution
|
|
3
|
+
*/
|
|
4
|
+
import type { Guardrail, GuardrailInput, GuardrailResult, GuardrailManagerOptions, GuardrailEventHandler } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* GuardrailManager - Manages pattern-based safety checks for tool execution
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const manager = new GuardrailManager({
|
|
11
|
+
* enabled: true,
|
|
12
|
+
* includeDefaults: true,
|
|
13
|
+
* custom: [
|
|
14
|
+
* {
|
|
15
|
+
* id: 'no-prod-db',
|
|
16
|
+
* name: 'Production Database Protection',
|
|
17
|
+
* description: 'Prevent operations on production database',
|
|
18
|
+
* patterns: [/prod.*db/i, /production.*database/i],
|
|
19
|
+
* action: 'block',
|
|
20
|
+
* message: 'Operations on production database are blocked',
|
|
21
|
+
* }
|
|
22
|
+
* ],
|
|
23
|
+
* onTriggered: async (result, context) => {
|
|
24
|
+
* if (result.action === 'confirm') {
|
|
25
|
+
* return await askUserConfirmation(result.guardrail.message);
|
|
26
|
+
* }
|
|
27
|
+
* return result.action !== 'block';
|
|
28
|
+
* }
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Check before tool execution
|
|
32
|
+
* const result = manager.check('bash', { command: 'rm -rf /' });
|
|
33
|
+
* if (result.triggered && result.action === 'block') {
|
|
34
|
+
* throw new Error(result.guardrail.message);
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class GuardrailManager {
|
|
39
|
+
private readonly guardrails;
|
|
40
|
+
private readonly options;
|
|
41
|
+
private eventHandler?;
|
|
42
|
+
constructor(options?: GuardrailManagerOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Set the event handler for guardrail events
|
|
45
|
+
*/
|
|
46
|
+
onEvent(handler: GuardrailEventHandler): void;
|
|
47
|
+
/**
|
|
48
|
+
* Add a custom guardrail
|
|
49
|
+
*/
|
|
50
|
+
add(input: GuardrailInput): Guardrail;
|
|
51
|
+
/**
|
|
52
|
+
* Get a guardrail by ID
|
|
53
|
+
*/
|
|
54
|
+
get(id: string): Guardrail | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Get all guardrails
|
|
57
|
+
*/
|
|
58
|
+
getAll(): Guardrail[];
|
|
59
|
+
/**
|
|
60
|
+
* Get guardrails that apply to a specific tool
|
|
61
|
+
*/
|
|
62
|
+
getForTool(toolName: string): Guardrail[];
|
|
63
|
+
/**
|
|
64
|
+
* Check if a guardrail exists
|
|
65
|
+
*/
|
|
66
|
+
has(id: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Remove a guardrail by ID
|
|
69
|
+
*/
|
|
70
|
+
remove(id: string): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Enable a guardrail
|
|
73
|
+
*/
|
|
74
|
+
enable(id: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Disable a guardrail
|
|
77
|
+
*/
|
|
78
|
+
disable(id: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Get the number of guardrails
|
|
81
|
+
*/
|
|
82
|
+
get size(): number;
|
|
83
|
+
/**
|
|
84
|
+
* Check if guardrails are enabled
|
|
85
|
+
*/
|
|
86
|
+
get enabled(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Enable or disable all guardrails
|
|
89
|
+
*/
|
|
90
|
+
setEnabled(enabled: boolean): void;
|
|
91
|
+
/**
|
|
92
|
+
* Check tool input against all applicable guardrails
|
|
93
|
+
*
|
|
94
|
+
* @param toolName - Name of the tool being called
|
|
95
|
+
* @param input - Tool input to check
|
|
96
|
+
* @returns GuardrailResult indicating if any guardrail was triggered
|
|
97
|
+
*/
|
|
98
|
+
check(toolName: string, input: unknown): GuardrailResult;
|
|
99
|
+
/**
|
|
100
|
+
* Check and handle guardrail triggering
|
|
101
|
+
*
|
|
102
|
+
* This method checks the input and calls the onTriggered handler if configured.
|
|
103
|
+
* Returns true if execution should proceed, false if blocked.
|
|
104
|
+
*
|
|
105
|
+
* @param toolName - Name of the tool being called
|
|
106
|
+
* @param input - Tool input to check
|
|
107
|
+
* @returns Promise<{ proceed: boolean; result: GuardrailResult }>
|
|
108
|
+
*/
|
|
109
|
+
checkAndHandle(toolName: string, input: unknown): Promise<{
|
|
110
|
+
proceed: boolean;
|
|
111
|
+
result: GuardrailResult;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* Stringify input for pattern matching
|
|
115
|
+
*/
|
|
116
|
+
private stringifyInput;
|
|
117
|
+
}
|