codebot-ai 1.6.0 → 1.8.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/dist/agent.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { Message, AgentEvent, LLMProvider } from './types';
2
+ import { AuditLogger } from './audit';
3
+ import { PolicyEnforcer } from './policy';
4
+ import { TokenTracker } from './telemetry';
2
5
  export declare class Agent {
3
6
  private provider;
4
7
  private tools;
@@ -10,11 +13,15 @@ export declare class Agent {
10
13
  private cache;
11
14
  private rateLimiter;
12
15
  private auditLogger;
16
+ private policyEnforcer;
17
+ private tokenTracker;
18
+ private branchCreated;
13
19
  private askPermission;
14
20
  private onMessage?;
15
21
  constructor(opts: {
16
22
  provider: LLMProvider;
17
23
  model: string;
24
+ providerName?: string;
18
25
  maxIterations?: number;
19
26
  autoApprove?: boolean;
20
27
  askPermission?: (tool: string, args: Record<string, unknown>) => Promise<boolean>;
@@ -31,6 +38,12 @@ export declare class Agent {
31
38
  after: number;
32
39
  };
33
40
  getMessages(): Message[];
41
+ /** Get the token tracker for session summary / CLI display */
42
+ getTokenTracker(): TokenTracker;
43
+ /** Get the policy enforcer for inspection */
44
+ getPolicyEnforcer(): PolicyEnforcer;
45
+ /** Get the audit logger for verification */
46
+ getAuditLogger(): AuditLogger;
34
47
  /**
35
48
  * Validate and repair message history to prevent OpenAI 400 errors.
36
49
  * Handles three types of corruption:
@@ -42,6 +55,15 @@ export declare class Agent {
42
55
  * or session resume corruption.
43
56
  */
44
57
  private repairToolCallMessages;
58
+ /**
59
+ * Auto-create a feature branch when always_branch is enabled and on main/master.
60
+ * Called before the first write/edit operation. Fail-open: if branching fails, continue.
61
+ */
62
+ private ensureBranch;
63
+ /** Sanitize user message into a branch-safe slug. */
64
+ private sanitizeSlug;
65
+ /** Check capability-based restrictions before tool execution. Returns reason string or null. */
66
+ private checkToolCapabilities;
45
67
  private buildSystemPrompt;
46
68
  }
47
69
  //# sourceMappingURL=agent.d.ts.map
package/dist/agent.js CHANGED
@@ -46,6 +46,8 @@ const plugins_1 = require("./plugins");
46
46
  const cache_1 = require("./cache");
47
47
  const rate_limiter_1 = require("./rate-limiter");
48
48
  const audit_1 = require("./audit");
49
+ const policy_1 = require("./policy");
50
+ const telemetry_1 = require("./telemetry");
49
51
  /** Lightweight schema validation — returns error string or null if valid */
50
52
  function validateToolArgs(args, schema) {
51
53
  const props = schema.properties;
@@ -100,20 +102,31 @@ class Agent {
100
102
  cache;
101
103
  rateLimiter;
102
104
  auditLogger;
105
+ policyEnforcer;
106
+ tokenTracker;
107
+ branchCreated = false;
103
108
  askPermission;
104
109
  onMessage;
105
110
  constructor(opts) {
106
111
  this.provider = opts.provider;
107
112
  this.model = opts.model;
108
- this.tools = new tools_1.ToolRegistry(process.cwd());
113
+ // Load policy FIRST — tools need it for filesystem/git enforcement
114
+ this.policyEnforcer = new policy_1.PolicyEnforcer((0, policy_1.loadPolicy)(process.cwd()), process.cwd());
115
+ this.tools = new tools_1.ToolRegistry(process.cwd(), this.policyEnforcer);
109
116
  this.context = new manager_1.ContextManager(opts.model, opts.provider);
110
- this.maxIterations = opts.maxIterations || 25;
117
+ // Use policy-defined max iterations as default, CLI overrides
118
+ this.maxIterations = opts.maxIterations || this.policyEnforcer.getMaxIterations();
111
119
  this.autoApprove = opts.autoApprove || false;
112
120
  this.askPermission = opts.askPermission || defaultAskPermission;
113
121
  this.onMessage = opts.onMessage;
114
122
  this.cache = new cache_1.ToolCache();
115
123
  this.rateLimiter = new rate_limiter_1.RateLimiter();
116
124
  this.auditLogger = new audit_1.AuditLogger();
125
+ // Token & cost tracking
126
+ this.tokenTracker = new telemetry_1.TokenTracker(opts.model, opts.providerName || 'unknown');
127
+ const costLimit = this.policyEnforcer.getCostLimitUsd();
128
+ if (costLimit > 0)
129
+ this.tokenTracker.setCostLimit(costLimit);
117
130
  // Load plugins
118
131
  try {
119
132
  const plugins = (0, plugins_1.loadPlugins)(process.cwd());
@@ -180,6 +193,10 @@ class Agent {
180
193
  }
181
194
  break;
182
195
  case 'usage':
196
+ // Track tokens and cost
197
+ if (event.usage) {
198
+ this.tokenTracker.recordUsage(event.usage.inputTokens || 0, event.usage.outputTokens || 0);
199
+ }
183
200
  yield { type: 'usage', usage: event.usage };
184
201
  break;
185
202
  case 'error':
@@ -231,6 +248,11 @@ class Agent {
231
248
  yield { type: 'done' };
232
249
  return;
233
250
  }
251
+ // Cost budget check: stop if over limit
252
+ if (this.tokenTracker.isOverBudget()) {
253
+ yield { type: 'error', error: `Cost limit exceeded ($${this.tokenTracker.getTotalCost().toFixed(4)} / $${this.policyEnforcer.getCostLimitUsd().toFixed(2)}). Stopping.` };
254
+ return;
255
+ }
234
256
  const prepared = [];
235
257
  for (const tc of toolCalls) {
236
258
  const toolName = tc.function.name;
@@ -239,6 +261,13 @@ class Agent {
239
261
  prepared.push({ tc, tool: null, args: {}, denied: false, error: `Error: Unknown tool "${toolName}"` });
240
262
  continue;
241
263
  }
264
+ // Policy check: is this tool allowed?
265
+ const policyCheck = this.policyEnforcer.isToolAllowed(toolName);
266
+ if (!policyCheck.allowed) {
267
+ this.auditLogger.log({ tool: toolName, action: 'policy_block', args: {}, reason: policyCheck.reason });
268
+ prepared.push({ tc, tool, args: {}, denied: false, error: `Error: ${policyCheck.reason}` });
269
+ continue;
270
+ }
242
271
  let args;
243
272
  try {
244
273
  args = JSON.parse(tc.function.arguments);
@@ -254,9 +283,11 @@ class Agent {
254
283
  continue;
255
284
  }
256
285
  yield { type: 'tool_call', toolCall: { name: toolName, args } };
257
- // Permission check (sequential needs user interaction)
258
- const needsPermission = tool.permission === 'always-ask' ||
259
- (tool.permission === 'prompt' && !this.autoApprove);
286
+ // Permission check: policy override > tool default
287
+ const policyPermission = this.policyEnforcer.getToolPermission(toolName);
288
+ const effectivePermission = policyPermission || tool.permission;
289
+ const needsPermission = effectivePermission === 'always-ask' ||
290
+ (effectivePermission === 'prompt' && !this.autoApprove);
260
291
  let denied = false;
261
292
  if (needsPermission) {
262
293
  const approved = await this.askPermission(toolName, args);
@@ -296,6 +327,19 @@ class Agent {
296
327
  // Helper to execute a single tool with cache + rate limiting
297
328
  const executeTool = async (prep) => {
298
329
  const toolName = prep.tc.function.name;
330
+ // Auto-branch on first write/edit when always_branch is enabled (v1.8.0)
331
+ if (toolName === 'write_file' || toolName === 'edit_file' || toolName === 'batch_edit') {
332
+ const branchName = await this.ensureBranch();
333
+ if (branchName) {
334
+ this.auditLogger.log({ tool: 'git', action: 'execute', args: { branch: branchName }, result: 'auto-branch' });
335
+ }
336
+ }
337
+ // Capability check: fine-grained resource restrictions (v1.8.0)
338
+ const capBlock = this.checkToolCapabilities(toolName, prep.args);
339
+ if (capBlock) {
340
+ this.auditLogger.log({ tool: toolName, action: 'capability_block', args: prep.args, reason: capBlock });
341
+ return { content: `Error: ${capBlock}`, is_error: true };
342
+ }
299
343
  // Check cache first
300
344
  if (prep.tool.cacheable) {
301
345
  const cacheKey = cache_1.ToolCache.key(toolName, prep.args);
@@ -310,6 +354,11 @@ class Agent {
310
354
  const output = await prep.tool.execute(prep.args);
311
355
  // Audit log: successful execution
312
356
  this.auditLogger.log({ tool: toolName, action: 'execute', args: prep.args, result: 'success' });
357
+ // Telemetry: track tool calls and file modifications
358
+ this.tokenTracker.recordToolCall();
359
+ if ((toolName === 'write_file' || toolName === 'edit_file' || toolName === 'batch_edit') && prep.args.path) {
360
+ this.tokenTracker.recordFileModified(prep.args.path);
361
+ }
313
362
  // Store in cache for cacheable tools
314
363
  if (prep.tool.cacheable) {
315
364
  const ttl = cache_1.ToolCache.TTL[toolName] || 30_000;
@@ -387,6 +436,18 @@ class Agent {
387
436
  getMessages() {
388
437
  return [...this.messages];
389
438
  }
439
+ /** Get the token tracker for session summary / CLI display */
440
+ getTokenTracker() {
441
+ return this.tokenTracker;
442
+ }
443
+ /** Get the policy enforcer for inspection */
444
+ getPolicyEnforcer() {
445
+ return this.policyEnforcer;
446
+ }
447
+ /** Get the audit logger for verification */
448
+ getAuditLogger() {
449
+ return this.auditLogger;
450
+ }
390
451
  /**
391
452
  * Validate and repair message history to prevent OpenAI 400 errors.
392
453
  * Handles three types of corruption:
@@ -454,6 +515,78 @@ class Agent {
454
515
  }
455
516
  }
456
517
  }
518
+ /**
519
+ * Auto-create a feature branch when always_branch is enabled and on main/master.
520
+ * Called before the first write/edit operation. Fail-open: if branching fails, continue.
521
+ */
522
+ async ensureBranch() {
523
+ if (this.branchCreated)
524
+ return null;
525
+ if (!this.policyEnforcer.shouldAlwaysBranch())
526
+ return null;
527
+ try {
528
+ const { execSync } = require('child_process');
529
+ const cwd = process.cwd();
530
+ const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
531
+ cwd, encoding: 'utf-8', timeout: 5000,
532
+ }).trim();
533
+ if (currentBranch !== 'main' && currentBranch !== 'master') {
534
+ this.branchCreated = true;
535
+ return null; // Already on a feature branch
536
+ }
537
+ // Generate branch name from first user message
538
+ const firstUserMsg = this.messages.find(m => m.role === 'user');
539
+ const prefix = this.policyEnforcer.getBranchPrefix();
540
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);
541
+ const slug = this.sanitizeSlug(firstUserMsg?.content || 'task');
542
+ const branchName = `${prefix}${timestamp}-${slug}`;
543
+ execSync(`git checkout -b "${branchName}"`, {
544
+ cwd, encoding: 'utf-8', timeout: 10000,
545
+ });
546
+ this.branchCreated = true;
547
+ return branchName;
548
+ }
549
+ catch {
550
+ // Don't block the operation if branching fails (not in a git repo, etc.)
551
+ this.branchCreated = true; // Don't retry
552
+ return null;
553
+ }
554
+ }
555
+ /** Sanitize user message into a branch-safe slug. */
556
+ sanitizeSlug(message) {
557
+ return message
558
+ .toLowerCase()
559
+ .replace(/[^a-z0-9\s-]/g, '')
560
+ .replace(/\s+/g, '-')
561
+ .substring(0, 30)
562
+ .replace(/-+$/, '') || 'task';
563
+ }
564
+ /** Check capability-based restrictions before tool execution. Returns reason string or null. */
565
+ checkToolCapabilities(toolName, args) {
566
+ // fs_write check for write/edit tools
567
+ if ((toolName === 'write_file' || toolName === 'edit_file' || toolName === 'batch_edit') && args.path) {
568
+ const check = this.policyEnforcer.checkCapability(toolName, 'fs_write', args.path);
569
+ if (!check.allowed)
570
+ return check.reason || 'Capability blocked';
571
+ }
572
+ // shell_commands check for execute tool
573
+ if (toolName === 'execute' && args.command) {
574
+ const check = this.policyEnforcer.checkCapability(toolName, 'shell_commands', args.command);
575
+ if (!check.allowed)
576
+ return check.reason || 'Capability blocked';
577
+ }
578
+ // net_access check for web tools
579
+ if ((toolName === 'web_fetch' || toolName === 'http_client') && args.url) {
580
+ try {
581
+ const domain = new URL(args.url).hostname;
582
+ const check = this.policyEnforcer.checkCapability(toolName, 'net_access', domain);
583
+ if (!check.allowed)
584
+ return check.reason || 'Capability blocked';
585
+ }
586
+ catch { /* invalid URL handled by the tool itself */ }
587
+ }
588
+ return null;
589
+ }
457
590
  buildSystemPrompt(supportsTools) {
458
591
  let repoMap = '';
459
592
  try {
package/dist/audit.d.ts CHANGED
@@ -1,39 +1,61 @@
1
1
  /**
2
- * Audit logger for CodeBot.
2
+ * Audit logger for CodeBot v1.7.0
3
3
  *
4
4
  * Provides append-only JSONL logging of all security-relevant actions.
5
5
  * Logs are stored at ~/.codebot/audit/audit-YYYY-MM-DD.jsonl
6
- * Masks secrets in args before writing.
6
+ *
7
+ * v1.7.0: Hash-chained entries for tamper detection.
8
+ * Each entry includes a SHA-256 hash of (prevHash + entry content).
9
+ * Verification walks the chain and detects any modifications.
10
+ *
7
11
  * NEVER throws — audit failures must not crash the agent.
8
12
  */
9
13
  export interface AuditEntry {
10
14
  timestamp: string;
11
15
  sessionId: string;
16
+ sequence: number;
12
17
  tool: string;
13
- action: 'execute' | 'deny' | 'error' | 'security_block';
18
+ action: 'execute' | 'deny' | 'error' | 'security_block' | 'policy_block' | 'capability_block';
14
19
  args: Record<string, unknown>;
15
20
  result?: string;
16
21
  reason?: string;
22
+ prevHash: string;
23
+ hash: string;
24
+ }
25
+ /** Result of verifying an audit chain */
26
+ export interface VerifyResult {
27
+ valid: boolean;
28
+ entriesChecked: number;
29
+ firstInvalidAt?: number;
30
+ reason?: string;
17
31
  }
18
32
  export declare class AuditLogger {
19
33
  private logDir;
20
34
  private sessionId;
35
+ private sequence;
36
+ private prevHash;
21
37
  constructor(logDir?: string);
22
- /** Get the current session ID */
23
38
  getSessionId(): string;
24
- /** Append an audit entry to the log file */
25
- log(entry: Omit<AuditEntry, 'timestamp' | 'sessionId'>): void;
39
+ /** Append a hash-chained audit entry to the log file */
40
+ log(entry: Omit<AuditEntry, 'timestamp' | 'sessionId' | 'sequence' | 'prevHash' | 'hash'>): void;
26
41
  /** Read log entries, optionally filtered */
27
42
  query(filter?: {
28
43
  tool?: string;
29
44
  action?: string;
30
45
  since?: string;
46
+ sessionId?: string;
31
47
  }): AuditEntry[];
32
- /** Get the path to today's log file */
48
+ /**
49
+ * Verify the hash chain integrity of audit entries.
50
+ * Walks through entries for a given session and checks each hash.
51
+ */
52
+ static verify(entries: AuditEntry[]): VerifyResult;
53
+ /**
54
+ * Verify all entries for a given session.
55
+ */
56
+ verifySession(sessionId?: string): VerifyResult;
33
57
  private getLogFilePath;
34
- /** Rotate log file if it exceeds MAX_LOG_SIZE */
35
58
  private rotateIfNeeded;
36
- /** Sanitize args for logging: mask secrets and truncate long values */
37
59
  private sanitizeArgs;
38
60
  }
39
61
  //# sourceMappingURL=audit.d.ts.map
package/dist/audit.js CHANGED
@@ -37,12 +37,16 @@ exports.AuditLogger = void 0;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const os = __importStar(require("os"));
40
+ const crypto = __importStar(require("crypto"));
40
41
  const secrets_1 = require("./secrets");
41
42
  const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB before rotation
42
- const MAX_ARG_LENGTH = 500; // Truncate long arg values for logging
43
+ const MAX_ARG_LENGTH = 500;
44
+ const GENESIS_HASH = 'genesis';
43
45
  class AuditLogger {
44
46
  logDir;
45
47
  sessionId;
48
+ sequence = 0;
49
+ prevHash = GENESIS_HASH;
46
50
  constructor(logDir) {
47
51
  this.logDir = logDir || path.join(os.homedir(), '.codebot', 'audit');
48
52
  this.sessionId = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
@@ -53,22 +57,32 @@ class AuditLogger {
53
57
  // Can't create dir — logging will be disabled
54
58
  }
55
59
  }
56
- /** Get the current session ID */
57
60
  getSessionId() {
58
61
  return this.sessionId;
59
62
  }
60
- /** Append an audit entry to the log file */
63
+ /** Append a hash-chained audit entry to the log file */
61
64
  log(entry) {
62
65
  try {
63
- const fullEntry = {
66
+ this.sequence++;
67
+ // Build entry without hash first (hash is computed over the other fields)
68
+ const partial = {
64
69
  timestamp: new Date().toISOString(),
65
70
  sessionId: this.sessionId,
66
- ...entry,
71
+ sequence: this.sequence,
72
+ tool: entry.tool,
73
+ action: entry.action,
67
74
  args: this.sanitizeArgs(entry.args),
75
+ result: entry.result,
76
+ reason: entry.reason,
77
+ prevHash: this.prevHash,
68
78
  };
79
+ // Compute hash: SHA-256 of (prevHash + JSON of partial entry)
80
+ const hashInput = this.prevHash + JSON.stringify(partial);
81
+ const hash = crypto.createHash('sha256').update(hashInput).digest('hex');
82
+ const fullEntry = { ...partial, hash };
83
+ this.prevHash = hash;
69
84
  const logFile = this.getLogFilePath();
70
85
  const line = JSON.stringify(fullEntry) + '\n';
71
- // Check if rotation is needed
72
86
  this.rotateIfNeeded(logFile);
73
87
  fs.appendFileSync(logFile, line, 'utf-8');
74
88
  }
@@ -96,6 +110,8 @@ class AuditLogger {
96
110
  continue;
97
111
  if (filter?.since && entry.timestamp < filter.since)
98
112
  continue;
113
+ if (filter?.sessionId && entry.sessionId !== filter.sessionId)
114
+ continue;
99
115
  entries.push(entry);
100
116
  }
101
117
  catch { /* skip malformed */ }
@@ -107,12 +123,72 @@ class AuditLogger {
107
123
  }
108
124
  return entries;
109
125
  }
110
- /** Get the path to today's log file */
126
+ /**
127
+ * Verify the hash chain integrity of audit entries.
128
+ * Walks through entries for a given session and checks each hash.
129
+ */
130
+ static verify(entries) {
131
+ if (entries.length === 0) {
132
+ return { valid: true, entriesChecked: 0 };
133
+ }
134
+ // Sort by sequence
135
+ const sorted = [...entries].sort((a, b) => a.sequence - b.sequence);
136
+ for (let i = 0; i < sorted.length; i++) {
137
+ const entry = sorted[i];
138
+ // Check sequence continuity
139
+ if (i === 0 && entry.prevHash !== GENESIS_HASH) {
140
+ // First entry should reference genesis (unless it's a continuation)
141
+ // Allow non-genesis for continuation of previous sessions
142
+ }
143
+ // Recompute hash
144
+ const partial = {
145
+ timestamp: entry.timestamp,
146
+ sessionId: entry.sessionId,
147
+ sequence: entry.sequence,
148
+ tool: entry.tool,
149
+ action: entry.action,
150
+ args: entry.args,
151
+ result: entry.result,
152
+ reason: entry.reason,
153
+ prevHash: entry.prevHash,
154
+ };
155
+ const hashInput = entry.prevHash + JSON.stringify(partial);
156
+ const expectedHash = crypto.createHash('sha256').update(hashInput).digest('hex');
157
+ if (entry.hash !== expectedHash) {
158
+ return {
159
+ valid: false,
160
+ entriesChecked: i + 1,
161
+ firstInvalidAt: entry.sequence,
162
+ reason: `Hash mismatch at sequence ${entry.sequence}: expected ${expectedHash.substring(0, 16)}..., got ${entry.hash.substring(0, 16)}...`,
163
+ };
164
+ }
165
+ // Check chain continuity (sequence i+1 should reference sequence i's hash)
166
+ if (i < sorted.length - 1) {
167
+ const next = sorted[i + 1];
168
+ if (next.prevHash !== entry.hash) {
169
+ return {
170
+ valid: false,
171
+ entriesChecked: i + 2,
172
+ firstInvalidAt: next.sequence,
173
+ reason: `Chain break at sequence ${next.sequence}: prevHash doesn't match previous entry's hash`,
174
+ };
175
+ }
176
+ }
177
+ }
178
+ return { valid: true, entriesChecked: sorted.length };
179
+ }
180
+ /**
181
+ * Verify all entries for a given session.
182
+ */
183
+ verifySession(sessionId) {
184
+ const sid = sessionId || this.sessionId;
185
+ const entries = this.query({ sessionId: sid });
186
+ return AuditLogger.verify(entries);
187
+ }
111
188
  getLogFilePath() {
112
- const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
189
+ const date = new Date().toISOString().split('T')[0];
113
190
  return path.join(this.logDir, `audit-${date}.jsonl`);
114
191
  }
115
- /** Rotate log file if it exceeds MAX_LOG_SIZE */
116
192
  rotateIfNeeded(logFile) {
117
193
  try {
118
194
  if (!fs.existsSync(logFile))
@@ -127,7 +203,6 @@ class AuditLogger {
127
203
  // Rotation failure is non-fatal
128
204
  }
129
205
  }
130
- /** Sanitize args for logging: mask secrets and truncate long values */
131
206
  sanitizeArgs(args) {
132
207
  const sanitized = {};
133
208
  for (const [key, value] of Object.entries(args)) {
@@ -139,7 +214,6 @@ class AuditLogger {
139
214
  sanitized[key] = masked;
140
215
  }
141
216
  else if (typeof value === 'object' && value !== null) {
142
- // For objects/arrays, stringify and mask
143
217
  const str = JSON.stringify(value);
144
218
  const masked = (0, secrets_1.maskSecretsInString)(str);
145
219
  sanitized[key] = masked.length > MAX_ARG_LENGTH
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Capability-Based Tool Permissions for CodeBot v1.8.0
3
+ *
4
+ * Fine-grained, per-tool resource restrictions.
5
+ * Configured via .codebot/policy.json → tools.capabilities.
6
+ *
7
+ * Example:
8
+ * {
9
+ * "execute": {
10
+ * "shell_commands": ["npm", "node", "git", "tsc"],
11
+ * "max_output_kb": 500
12
+ * },
13
+ * "write_file": {
14
+ * "fs_write": ["./src/**", "./tests/**"]
15
+ * }
16
+ * }
17
+ */
18
+ export interface ToolCapabilities {
19
+ fs_read?: string[];
20
+ fs_write?: string[];
21
+ net_access?: string[];
22
+ shell_commands?: string[];
23
+ max_output_kb?: number;
24
+ }
25
+ export type CapabilityConfig = Record<string, ToolCapabilities>;
26
+ export declare class CapabilityChecker {
27
+ private capabilities;
28
+ private projectRoot;
29
+ constructor(capabilities: CapabilityConfig, projectRoot: string);
30
+ /** Get capabilities for a tool. undefined = no restrictions. */
31
+ getToolCapabilities(toolName: string): ToolCapabilities | undefined;
32
+ /** Check if a specific capability is allowed. */
33
+ checkCapability(toolName: string, capabilityType: keyof ToolCapabilities, value: string | number): {
34
+ allowed: boolean;
35
+ reason?: string;
36
+ };
37
+ /** Check if a path matches any of the allowed glob patterns. */
38
+ private checkGlobs;
39
+ /** Check if a domain is in the allowed list. */
40
+ private checkDomain;
41
+ /** Check if a command starts with an allowed prefix. */
42
+ private checkCommandPrefix;
43
+ /** Check if output size is within the cap. */
44
+ private checkOutputSize;
45
+ /** Simple glob matching (** = any depth, * = one segment). */
46
+ private matchGlob;
47
+ }
48
+ //# sourceMappingURL=capabilities.d.ts.map