@compilr-dev/agents 0.0.1 → 0.2.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 (44) hide show
  1. package/dist/agent.d.ts +188 -1
  2. package/dist/agent.js +284 -14
  3. package/dist/context/file-tracker.d.ts +156 -0
  4. package/dist/context/file-tracker.js +358 -0
  5. package/dist/context/file-tracking-hook.d.ts +29 -0
  6. package/dist/context/file-tracking-hook.js +103 -0
  7. package/dist/context/index.d.ts +5 -1
  8. package/dist/context/index.js +3 -0
  9. package/dist/context/manager.d.ts +69 -1
  10. package/dist/context/manager.js +304 -0
  11. package/dist/context/types.d.ts +95 -0
  12. package/dist/index.d.ts +13 -5
  13. package/dist/index.js +11 -3
  14. package/dist/messages/index.d.ts +13 -0
  15. package/dist/messages/index.js +51 -0
  16. package/dist/permissions/manager.js +6 -1
  17. package/dist/providers/gemini.d.ts +91 -0
  18. package/dist/providers/gemini.js +138 -0
  19. package/dist/providers/index.d.ts +8 -0
  20. package/dist/providers/index.js +7 -3
  21. package/dist/providers/mock.js +8 -0
  22. package/dist/providers/ollama.d.ts +87 -0
  23. package/dist/providers/ollama.js +133 -0
  24. package/dist/providers/openai-compatible.d.ts +182 -0
  25. package/dist/providers/openai-compatible.js +357 -0
  26. package/dist/providers/openai.d.ts +93 -0
  27. package/dist/providers/openai.js +133 -0
  28. package/dist/skills/index.js +691 -0
  29. package/dist/tools/builtin/glob.d.ts +11 -0
  30. package/dist/tools/builtin/glob.js +44 -2
  31. package/dist/tools/builtin/grep.d.ts +11 -1
  32. package/dist/tools/builtin/grep.js +38 -2
  33. package/dist/tools/builtin/index.d.ts +6 -1
  34. package/dist/tools/builtin/index.js +7 -0
  35. package/dist/tools/builtin/suggest.d.ts +57 -0
  36. package/dist/tools/builtin/suggest.js +99 -0
  37. package/dist/tools/builtin/task.js +13 -8
  38. package/dist/tools/builtin/tool-names.d.ts +44 -0
  39. package/dist/tools/builtin/tool-names.js +51 -0
  40. package/dist/tools/index.d.ts +2 -2
  41. package/dist/tools/index.js +5 -1
  42. package/dist/tools/registry.d.ts +4 -0
  43. package/dist/tools/registry.js +9 -0
  44. package/package.json +2 -2
@@ -5,6 +5,29 @@ import { readdir } from 'node:fs/promises';
5
5
  import { join } from 'node:path';
6
6
  import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
7
7
  import { isNodeError } from './utils.js';
8
+ /**
9
+ * Default directories to exclude from glob searches.
10
+ * These are typically large, generated, or not relevant for code search.
11
+ */
12
+ const DEFAULT_EXCLUDE_DIRS = [
13
+ 'node_modules',
14
+ '.git',
15
+ 'dist',
16
+ 'build',
17
+ '.next',
18
+ '.nuxt',
19
+ '.output',
20
+ 'coverage',
21
+ '.nyc_output',
22
+ '__pycache__',
23
+ '.pytest_cache',
24
+ 'venv',
25
+ '.venv',
26
+ 'target', // Rust/Java
27
+ 'vendor', // Go/PHP
28
+ '.cargo',
29
+ '.cache',
30
+ ];
8
31
  /**
9
32
  * Glob tool definition
10
33
  */
@@ -48,6 +71,11 @@ export const globTool = defineTool({
48
71
  type: 'boolean',
49
72
  description: 'Return absolute paths instead of relative',
50
73
  },
74
+ excludeDirs: {
75
+ type: 'array',
76
+ items: { type: 'string' },
77
+ description: 'Directory names to exclude (default: node_modules, .git, dist, build, etc.)',
78
+ },
51
79
  },
52
80
  required: ['pattern'],
53
81
  },
@@ -57,7 +85,7 @@ export const globTool = defineTool({
57
85
  * Execute the glob tool
58
86
  */
59
87
  async function executeGlob(input) {
60
- const { pattern, path: basePath = '.', includeHidden = false, onlyDirectories = false, onlyFiles = !onlyDirectories, maxDepth, maxResults = 1000, absolute = false, } = input;
88
+ const { pattern, path: basePath = '.', includeHidden = false, onlyDirectories = false, onlyFiles = !onlyDirectories, maxDepth, maxResults = 1000, absolute = false, excludeDirs = DEFAULT_EXCLUDE_DIRS, } = input;
61
89
  // Check if base path exists
62
90
  try {
63
91
  await readdir(basePath);
@@ -91,6 +119,7 @@ async function executeGlob(input) {
91
119
  maxResults,
92
120
  matches,
93
121
  basePath,
122
+ excludeDirs,
94
123
  });
95
124
  // Format output
96
125
  const results = absolute ? matches.map((m) => join(basePath, m)) : matches;
@@ -117,6 +146,7 @@ async function searchDirectory(basePath, relativePath, depth, options) {
117
146
  return;
118
147
  }
119
148
  const currentPath = relativePath ? join(basePath, relativePath) : basePath;
149
+ const excludeSet = new Set(options.excludeDirs);
120
150
  let entries;
121
151
  try {
122
152
  entries = await readdir(currentPath, { withFileTypes: true });
@@ -133,8 +163,12 @@ async function searchDirectory(basePath, relativePath, depth, options) {
133
163
  if (!options.includeHidden && entry.name.startsWith('.')) {
134
164
  continue;
135
165
  }
136
- const entryRelativePath = relativePath ? join(relativePath, entry.name) : entry.name;
137
166
  const isDir = entry.isDirectory();
167
+ // Skip excluded directories
168
+ if (isDir && excludeSet.has(entry.name)) {
169
+ continue;
170
+ }
171
+ const entryRelativePath = relativePath ? join(relativePath, entry.name) : entry.name;
138
172
  const isFile = entry.isFile();
139
173
  // Check if this entry matches the pattern
140
174
  if (options.pattern.test(entryRelativePath)) {
@@ -226,6 +260,11 @@ export function createGlobTool(options) {
226
260
  type: 'boolean',
227
261
  description: 'Return absolute paths instead of relative',
228
262
  },
263
+ excludeDirs: {
264
+ type: 'array',
265
+ items: { type: 'string' },
266
+ description: 'Directory names to exclude (default: node_modules, .git, dist, build, etc.)',
267
+ },
229
268
  },
230
269
  required: ['pattern'],
231
270
  },
@@ -235,9 +274,12 @@ export function createGlobTool(options) {
235
274
  if (options?.baseDir && !searchPath.startsWith('/')) {
236
275
  searchPath = join(options.baseDir, searchPath);
237
276
  }
277
+ // Apply custom excludeDirs from factory options if specified and input doesn't override
278
+ const excludeDirs = input.excludeDirs ?? options?.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
238
279
  return executeGlob({
239
280
  ...input,
240
281
  path: searchPath,
282
+ excludeDirs,
241
283
  });
242
284
  },
243
285
  });
@@ -50,6 +50,12 @@ export interface GrepInput {
50
50
  * Search recursively in directories (default: true)
51
51
  */
52
52
  recursive?: boolean;
53
+ /**
54
+ * Directory names to exclude from search.
55
+ * Default excludes: node_modules, .git, dist, build, etc.
56
+ * Set to empty array [] to include all directories.
57
+ */
58
+ excludeDirs?: string[];
53
59
  }
54
60
  /**
55
61
  * Grep tool definition
@@ -60,7 +66,6 @@ export declare const grepTool: Tool<GrepInput>;
60
66
  *
61
67
  * TODO: Future enhancements could include:
62
68
  * - maxFileSize: Skip files larger than specified size
63
- * - excludeDirs: Exclude directories by name (e.g., node_modules, .git)
64
69
  */
65
70
  export declare function createGrepTool(options?: {
66
71
  /**
@@ -71,4 +76,9 @@ export declare function createGrepTool(options?: {
71
76
  * Default file extensions to search
72
77
  */
73
78
  defaultExtensions?: string[];
79
+ /**
80
+ * Override default excluded directories.
81
+ * Defaults to: node_modules, .git, dist, build, etc.
82
+ */
83
+ excludeDirs?: string[];
74
84
  }): Tool<GrepInput>;
@@ -6,6 +6,29 @@ import { readdir, stat } from 'node:fs/promises';
6
6
  import { join, relative } from 'node:path';
7
7
  import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
8
8
  import { isNodeError, isExtensionAllowed } from './utils.js';
9
+ /**
10
+ * Default directories to exclude from grep searches.
11
+ * These are typically large, generated, or not relevant for code search.
12
+ */
13
+ const DEFAULT_EXCLUDE_DIRS = [
14
+ 'node_modules',
15
+ '.git',
16
+ 'dist',
17
+ 'build',
18
+ '.next',
19
+ '.nuxt',
20
+ '.output',
21
+ 'coverage',
22
+ '.nyc_output',
23
+ '__pycache__',
24
+ '.pytest_cache',
25
+ 'venv',
26
+ '.venv',
27
+ 'target', // Rust/Java
28
+ 'vendor', // Go/PHP
29
+ '.cargo',
30
+ '.cache',
31
+ ];
9
32
  /**
10
33
  * Grep tool definition
11
34
  */
@@ -103,7 +126,7 @@ function safeRegexTest(regex, text) {
103
126
  */
104
127
  async function executeGrep(input) {
105
128
  try {
106
- const { pattern, path, ignoreCase = false, lineNumbers = true, before = 0, after = 0, filesOnly = false, includeHidden = false, extensions, maxMatches = 100, recursive = true, } = input;
129
+ const { pattern, path, ignoreCase = false, lineNumbers = true, before = 0, after = 0, filesOnly = false, includeHidden = false, extensions, maxMatches = 100, recursive = true, excludeDirs = DEFAULT_EXCLUDE_DIRS, } = input;
107
130
  // Check for potentially dangerous regex patterns
108
131
  if (isPotentiallyDangerousRegex(pattern)) {
109
132
  return createErrorResult(`Potentially dangerous regex pattern detected (ReDoS risk). ` +
@@ -128,6 +151,7 @@ async function executeGrep(input) {
128
151
  recursive,
129
152
  includeHidden,
130
153
  extensions,
154
+ excludeDirs,
131
155
  });
132
156
  }
133
157
  else {
@@ -189,6 +213,7 @@ async function executeGrep(input) {
189
213
  */
190
214
  async function collectFiles(dir, files, options) {
191
215
  const entries = await readdir(dir, { withFileTypes: true });
216
+ const excludeSet = new Set(options.excludeDirs ?? []);
192
217
  for (const entry of entries) {
193
218
  // Skip hidden files unless included
194
219
  if (!options.includeHidden && entry.name.startsWith('.')) {
@@ -205,6 +230,10 @@ async function collectFiles(dir, files, options) {
205
230
  files.push(fullPath);
206
231
  }
207
232
  else if (entry.isDirectory() && options.recursive) {
233
+ // Skip excluded directories
234
+ if (excludeSet.has(entry.name)) {
235
+ continue;
236
+ }
208
237
  await collectFiles(fullPath, files, options);
209
238
  }
210
239
  }
@@ -286,7 +315,6 @@ function formatMatches(matches, options) {
286
315
  *
287
316
  * TODO: Future enhancements could include:
288
317
  * - maxFileSize: Skip files larger than specified size
289
- * - excludeDirs: Exclude directories by name (e.g., node_modules, .git)
290
318
  */
291
319
  export function createGrepTool(options) {
292
320
  return defineTool({
@@ -342,6 +370,11 @@ export function createGrepTool(options) {
342
370
  type: 'boolean',
343
371
  description: 'Search recursively in directories (default: true)',
344
372
  },
373
+ excludeDirs: {
374
+ type: 'array',
375
+ items: { type: 'string' },
376
+ description: 'Directory names to exclude (default: node_modules, .git, dist, build, etc.)',
377
+ },
345
378
  },
346
379
  required: ['pattern', 'path'],
347
380
  },
@@ -353,10 +386,13 @@ export function createGrepTool(options) {
353
386
  }
354
387
  // Apply default extensions if none specified
355
388
  const extensions = input.extensions ?? options?.defaultExtensions;
389
+ // Apply custom excludeDirs from factory options if specified and input doesn't override
390
+ const excludeDirs = input.excludeDirs ?? options?.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
356
391
  return executeGrep({
357
392
  ...input,
358
393
  path: searchPath,
359
394
  extensions,
395
+ excludeDirs,
360
396
  });
361
397
  },
362
398
  });
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Built-in tools for common operations
3
3
  */
4
+ export { TOOL_NAMES, TOOL_SETS } from './tool-names.js';
5
+ export type { ToolName } from './tool-names.js';
4
6
  export { readFileTool, createReadFileTool } from './read-file.js';
5
7
  export type { ReadFileInput } from './read-file.js';
6
8
  export { writeFileTool, createWriteFileTool } from './write-file.js';
@@ -25,6 +27,8 @@ export { createTaskTool, defaultAgentTypes } from './task.js';
25
27
  export type { TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, } from './task.js';
26
28
  export { webFetchTool, createWebFetchTool } from './web-fetch.js';
27
29
  export type { WebFetchInput, WebFetchResult, WebFetchOptions } from './web-fetch.js';
30
+ export { suggestTool, createSuggestTool } from './suggest.js';
31
+ export type { SuggestInput, SuggestToolOptions } from './suggest.js';
28
32
  export declare const builtinTools: {
29
33
  readonly readFile: import("../types.js").Tool<import("./read-file.js").ReadFileInput>;
30
34
  readonly writeFile: import("../types.js").Tool<import("./write-file.js").WriteFileInput>;
@@ -37,8 +41,9 @@ export declare const builtinTools: {
37
41
  readonly todoWrite: import("../types.js").Tool<import("./todo.js").TodoWriteInput>;
38
42
  readonly todoRead: import("../types.js").Tool<import("./todo.js").TodoReadInput>;
39
43
  readonly webFetch: import("../types.js").Tool<import("./web-fetch.js").WebFetchInput>;
44
+ readonly suggest: import("../types.js").Tool<import("./suggest.js").SuggestInput>;
40
45
  };
41
46
  /**
42
47
  * Array of all built-in tools
43
48
  */
44
- export declare const allBuiltinTools: readonly [import("../types.js").Tool<import("./read-file.js").ReadFileInput>, import("../types.js").Tool<import("./write-file.js").WriteFileInput>, import("../types.js").Tool<import("./bash.js").BashInput>, import("../types.js").Tool<import("./bash-output.js").BashOutputInput>, import("../types.js").Tool<import("./kill-shell.js").KillShellInput>, import("../types.js").Tool<import("./grep.js").GrepInput>, import("../types.js").Tool<import("./glob.js").GlobInput>, import("../types.js").Tool<import("./edit.js").EditInput>, import("../types.js").Tool<import("./todo.js").TodoWriteInput>, import("../types.js").Tool<import("./todo.js").TodoReadInput>, import("../types.js").Tool<import("./web-fetch.js").WebFetchInput>];
49
+ export declare const allBuiltinTools: readonly [import("../types.js").Tool<import("./read-file.js").ReadFileInput>, import("../types.js").Tool<import("./write-file.js").WriteFileInput>, import("../types.js").Tool<import("./bash.js").BashInput>, import("../types.js").Tool<import("./bash-output.js").BashOutputInput>, import("../types.js").Tool<import("./kill-shell.js").KillShellInput>, import("../types.js").Tool<import("./grep.js").GrepInput>, import("../types.js").Tool<import("./glob.js").GlobInput>, import("../types.js").Tool<import("./edit.js").EditInput>, import("../types.js").Tool<import("./todo.js").TodoWriteInput>, import("../types.js").Tool<import("./todo.js").TodoReadInput>, import("../types.js").Tool<import("./web-fetch.js").WebFetchInput>, import("../types.js").Tool<import("./suggest.js").SuggestInput>];
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Built-in tools for common operations
3
3
  */
4
+ // Tool names - single source of truth
5
+ export { TOOL_NAMES, TOOL_SETS } from './tool-names.js';
4
6
  // Read file tool
5
7
  export { readFileTool, createReadFileTool } from './read-file.js';
6
8
  // Write file tool
@@ -25,6 +27,8 @@ export { todoWriteTool, todoReadTool, createTodoTools, TodoStore, resetDefaultTo
25
27
  export { createTaskTool, defaultAgentTypes } from './task.js';
26
28
  // WebFetch tool
27
29
  export { webFetchTool, createWebFetchTool } from './web-fetch.js';
30
+ // Suggest tool (next action suggestions)
31
+ export { suggestTool, createSuggestTool } from './suggest.js';
28
32
  /**
29
33
  * Collection of all built-in tools for easy registration
30
34
  */
@@ -38,6 +42,7 @@ import { globTool } from './glob.js';
38
42
  import { editTool } from './edit.js';
39
43
  import { todoWriteTool, todoReadTool } from './todo.js';
40
44
  import { webFetchTool } from './web-fetch.js';
45
+ import { suggestTool } from './suggest.js';
41
46
  export const builtinTools = {
42
47
  readFile: readFileTool,
43
48
  writeFile: writeFileTool,
@@ -50,6 +55,7 @@ export const builtinTools = {
50
55
  todoWrite: todoWriteTool,
51
56
  todoRead: todoReadTool,
52
57
  webFetch: webFetchTool,
58
+ suggest: suggestTool,
53
59
  };
54
60
  /**
55
61
  * Array of all built-in tools
@@ -66,4 +72,5 @@ export const allBuiltinTools = [
66
72
  todoWriteTool,
67
73
  todoReadTool,
68
74
  webFetchTool,
75
+ suggestTool,
69
76
  ];
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Suggest Tool - Suggest next action to the user
3
+ *
4
+ * This tool allows the agent to suggest a logical next action for the user.
5
+ * The suggestion appears as "ghost text" in the CLI input prompt.
6
+ *
7
+ * Features:
8
+ * - Silent tool (produces no visible output in conversation)
9
+ * - Emits 'suggest' event for CLI to handle
10
+ * - Only the last suggestion per response is kept
11
+ */
12
+ import type { Tool } from '../types.js';
13
+ import type { AgentEvent } from '../../agent.js';
14
+ /**
15
+ * Input parameters for suggest tool
16
+ */
17
+ export interface SuggestInput {
18
+ /**
19
+ * The suggested action or command for the user to take next
20
+ */
21
+ action: string;
22
+ /**
23
+ * Brief explanation of why this action is suggested (optional)
24
+ */
25
+ reason?: string;
26
+ }
27
+ /**
28
+ * Options for creating the suggest tool
29
+ */
30
+ export interface SuggestToolOptions {
31
+ /**
32
+ * Callback to emit suggest event
33
+ * The CLI captures this to display the suggestion
34
+ */
35
+ onSuggest?: (event: Extract<AgentEvent, {
36
+ type: 'suggest';
37
+ }>) => void;
38
+ }
39
+ /**
40
+ * Default suggest tool (no-op, for testing or when suggestions are disabled)
41
+ */
42
+ export declare const suggestTool: Tool<SuggestInput>;
43
+ /**
44
+ * Create a suggest tool with event emission
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const suggestTool = createSuggestTool({
49
+ * onSuggest: (event) => {
50
+ * // Handle the suggestion (e.g., pass to CLI input prompt)
51
+ * console.log('Suggested action:', event.action);
52
+ * }
53
+ * });
54
+ * agent.registerTool(suggestTool);
55
+ * ```
56
+ */
57
+ export declare function createSuggestTool(options?: SuggestToolOptions): Tool<SuggestInput>;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Suggest Tool - Suggest next action to the user
3
+ *
4
+ * This tool allows the agent to suggest a logical next action for the user.
5
+ * The suggestion appears as "ghost text" in the CLI input prompt.
6
+ *
7
+ * Features:
8
+ * - Silent tool (produces no visible output in conversation)
9
+ * - Emits 'suggest' event for CLI to handle
10
+ * - Only the last suggestion per response is kept
11
+ */
12
+ import { defineTool, createSuccessResult } from '../define.js';
13
+ /**
14
+ * Default suggest tool (no-op, for testing or when suggestions are disabled)
15
+ */
16
+ export const suggestTool = defineTool({
17
+ name: 'suggest',
18
+ description: 'Suggest a next action for the user. The suggestion appears as ghost text in the input prompt. ' +
19
+ 'Use this after completing a task to guide the user toward a logical next step. ' +
20
+ 'Good suggestions are actionable, specific, and follow naturally from what you just did. ' +
21
+ 'Examples: "run npm test to verify the fix", "review the changes in src/index.ts", ' +
22
+ '"commit the changes with git commit". Only suggest when there is a clear, helpful next step.',
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ action: {
27
+ type: 'string',
28
+ description: 'The suggested action or command for the user to take next',
29
+ },
30
+ reason: {
31
+ type: 'string',
32
+ description: 'Brief explanation of why this action is suggested (optional)',
33
+ },
34
+ },
35
+ required: ['action'],
36
+ },
37
+ execute: (_input) => {
38
+ // Default implementation - silent, no-op
39
+ // Real implementation uses createSuggestTool with onSuggest callback
40
+ return Promise.resolve(createSuccessResult({
41
+ suggested: true,
42
+ message: 'Suggestion noted (no handler configured)',
43
+ }));
44
+ },
45
+ });
46
+ /**
47
+ * Create a suggest tool with event emission
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const suggestTool = createSuggestTool({
52
+ * onSuggest: (event) => {
53
+ * // Handle the suggestion (e.g., pass to CLI input prompt)
54
+ * console.log('Suggested action:', event.action);
55
+ * }
56
+ * });
57
+ * agent.registerTool(suggestTool);
58
+ * ```
59
+ */
60
+ export function createSuggestTool(options = {}) {
61
+ const { onSuggest } = options;
62
+ return defineTool({
63
+ name: 'suggest',
64
+ description: 'Suggest a next action for the user. The suggestion appears as ghost text in the input prompt. ' +
65
+ 'Use this after completing a task to guide the user toward a logical next step. ' +
66
+ 'Good suggestions are actionable, specific, and follow naturally from what you just did. ' +
67
+ 'Examples: "run npm test to verify the fix", "review the changes in src/index.ts", ' +
68
+ '"commit the changes with git commit". Only suggest when there is a clear, helpful next step.',
69
+ inputSchema: {
70
+ type: 'object',
71
+ properties: {
72
+ action: {
73
+ type: 'string',
74
+ description: 'The suggested action or command for the user to take next',
75
+ },
76
+ reason: {
77
+ type: 'string',
78
+ description: 'Brief explanation of why this action is suggested (optional)',
79
+ },
80
+ },
81
+ required: ['action'],
82
+ },
83
+ execute: (input) => {
84
+ // Emit the suggest event if handler is configured
85
+ if (onSuggest) {
86
+ onSuggest({
87
+ type: 'suggest',
88
+ action: input.action,
89
+ reason: input.reason,
90
+ });
91
+ }
92
+ // Silent result - no visible output in conversation
93
+ return Promise.resolve(createSuccessResult({
94
+ suggested: true,
95
+ action: input.action,
96
+ }));
97
+ },
98
+ });
99
+ }
@@ -13,6 +13,7 @@
13
13
  * - Extended built-in agent types
14
14
  */
15
15
  import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
16
+ import { TOOL_NAMES, TOOL_SETS } from './tool-names.js';
16
17
  /**
17
18
  * Map our context mode to agent's context mode
18
19
  */
@@ -123,6 +124,7 @@ export function createTaskTool(options) {
123
124
  const agentConfig = agentTypes[subagent_type];
124
125
  // Check concurrent limit
125
126
  if (activeCount >= maxConcurrent) {
127
+ console.error(`[task-tool] BLOCKED: activeCount=${String(activeCount)}, maxConcurrent=${String(maxConcurrent)}`);
126
128
  return createErrorResult(`Maximum concurrent sub-agents (${String(maxConcurrent)}) reached. ` +
127
129
  `Wait for existing tasks to complete.`);
128
130
  }
@@ -131,6 +133,7 @@ export function createTaskTool(options) {
131
133
  onSpawn(subagent_type, description);
132
134
  }
133
135
  activeCount++;
136
+ console.error(`[task-tool] SPAWN: ${subagent_type}, activeCount=${String(activeCount)}`);
134
137
  try {
135
138
  // Note: Sub-agents currently use the parent's provider
136
139
  // Future enhancement: support model switching via providerFactory
@@ -198,10 +201,12 @@ export function createTaskTool(options) {
198
201
  return createSuccessResult(taskResult);
199
202
  }
200
203
  catch (error) {
204
+ console.error(`[task-tool] ERROR: ${subagent_type}, error=${error instanceof Error ? error.message : String(error)}`);
201
205
  return createErrorResult(`Sub-agent failed: ${error instanceof Error ? error.message : String(error)}`);
202
206
  }
203
207
  finally {
204
208
  activeCount--;
209
+ console.error(`[task-tool] DONE: ${subagent_type}, activeCount=${String(activeCount)}`);
205
210
  }
206
211
  },
207
212
  });
@@ -222,7 +227,7 @@ export const defaultAgentTypes = {
222
227
  contextMode: 'inherit-summary',
223
228
  supportsThoroughness: true,
224
229
  toolInheritance: 'filter',
225
- allowedTools: ['glob', 'grep', 'read'],
230
+ allowedTools: [...TOOL_SETS.READ_ONLY],
226
231
  },
227
232
  'code-review': {
228
233
  description: 'Agent specialized for reviewing code changes. Use after writing ' +
@@ -238,7 +243,7 @@ export const defaultAgentTypes = {
238
243
  contextMode: 'inherit-summary',
239
244
  supportsThoroughness: false,
240
245
  toolInheritance: 'filter',
241
- allowedTools: ['glob', 'grep', 'read'],
246
+ allowedTools: [...TOOL_SETS.READ_ONLY],
242
247
  },
243
248
  general: {
244
249
  description: 'General-purpose agent for complex multi-step tasks. Use when ' +
@@ -262,7 +267,7 @@ export const defaultAgentTypes = {
262
267
  contextMode: 'inherit-summary',
263
268
  supportsThoroughness: false,
264
269
  toolInheritance: 'filter',
265
- allowedTools: ['glob', 'grep', 'read'],
270
+ allowedTools: [...TOOL_SETS.READ_ONLY],
266
271
  },
267
272
  'test-runner': {
268
273
  description: 'Agent for running and analyzing tests. Use to run test suites, ' +
@@ -278,7 +283,7 @@ export const defaultAgentTypes = {
278
283
  contextMode: 'inherit-summary',
279
284
  supportsThoroughness: true,
280
285
  toolInheritance: 'filter',
281
- allowedTools: ['bash', 'glob', 'grep', 'read'],
286
+ allowedTools: [...TOOL_SETS.READ_ONLY_WITH_BASH],
282
287
  },
283
288
  'doc-lookup': {
284
289
  description: 'Agent for searching documentation and APIs. Use to find ' +
@@ -294,7 +299,7 @@ export const defaultAgentTypes = {
294
299
  contextMode: 'isolated',
295
300
  supportsThoroughness: true,
296
301
  toolInheritance: 'filter',
297
- allowedTools: ['webFetch', 'glob', 'grep', 'read'],
302
+ allowedTools: [...TOOL_SETS.READ_ONLY_WITH_WEB],
298
303
  },
299
304
  refactor: {
300
305
  description: 'Agent for refactoring code safely. Use for renaming, extracting, ' +
@@ -310,8 +315,8 @@ export const defaultAgentTypes = {
310
315
  contextMode: 'inherit-summary',
311
316
  supportsThoroughness: false,
312
317
  toolInheritance: 'filter',
313
- allowedTools: ['glob', 'grep', 'read', 'edit', 'write'],
314
- deniedTools: ['bash'],
318
+ allowedTools: [...TOOL_SETS.REFACTOR],
319
+ deniedTools: [TOOL_NAMES.BASH],
315
320
  },
316
321
  'security-audit': {
317
322
  description: 'Agent for security auditing code. Use to scan for vulnerabilities, ' +
@@ -329,7 +334,7 @@ export const defaultAgentTypes = {
329
334
  contextMode: 'isolated',
330
335
  supportsThoroughness: true,
331
336
  toolInheritance: 'filter',
332
- allowedTools: ['glob', 'grep', 'read', 'bash'],
337
+ allowedTools: [...TOOL_SETS.SECURITY_AUDIT],
333
338
  },
334
339
  debug: {
335
340
  description: 'Agent for debugging issues. Use to investigate bugs, analyze ' +
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Tool Names - Single Source of Truth
3
+ *
4
+ * All tool names are defined here to avoid hardcoding them in multiple places.
5
+ * Import these constants wherever you need to reference tool names.
6
+ */
7
+ /**
8
+ * Built-in tool names as constants
9
+ */
10
+ export declare const TOOL_NAMES: {
11
+ readonly READ_FILE: "read_file";
12
+ readonly WRITE_FILE: "write_file";
13
+ readonly BASH: "bash";
14
+ readonly BASH_OUTPUT: "bash_output";
15
+ readonly KILL_SHELL: "kill_shell";
16
+ readonly GREP: "grep";
17
+ readonly GLOB: "glob";
18
+ readonly EDIT: "edit";
19
+ readonly TODO_WRITE: "todo_write";
20
+ readonly TODO_READ: "todo_read";
21
+ readonly WEB_FETCH: "web_fetch";
22
+ readonly TASK: "task";
23
+ readonly SUGGEST: "suggest";
24
+ };
25
+ /**
26
+ * Type for tool name values
27
+ */
28
+ export type ToolName = (typeof TOOL_NAMES)[keyof typeof TOOL_NAMES];
29
+ /**
30
+ * Common tool sets for agent types
31
+ * Use these instead of hardcoding tool arrays
32
+ */
33
+ export declare const TOOL_SETS: {
34
+ /** Read-only tools for exploration and code review */
35
+ readonly READ_ONLY: readonly ["glob", "grep", "read_file"];
36
+ /** Read-only tools plus bash for running commands */
37
+ readonly READ_ONLY_WITH_BASH: readonly ["bash", "glob", "grep", "read_file"];
38
+ /** Read-only tools plus web fetch for documentation lookup */
39
+ readonly READ_ONLY_WITH_WEB: readonly ["web_fetch", "glob", "grep", "read_file"];
40
+ /** Tools for refactoring (read + edit + write, no bash) */
41
+ readonly REFACTOR: readonly ["glob", "grep", "read_file", "edit", "write_file"];
42
+ /** Tools for security auditing (read + bash for dependency checks) */
43
+ readonly SECURITY_AUDIT: readonly ["glob", "grep", "read_file", "bash"];
44
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Tool Names - Single Source of Truth
3
+ *
4
+ * All tool names are defined here to avoid hardcoding them in multiple places.
5
+ * Import these constants wherever you need to reference tool names.
6
+ */
7
+ /**
8
+ * Built-in tool names as constants
9
+ */
10
+ export const TOOL_NAMES = {
11
+ READ_FILE: 'read_file',
12
+ WRITE_FILE: 'write_file',
13
+ BASH: 'bash',
14
+ BASH_OUTPUT: 'bash_output',
15
+ KILL_SHELL: 'kill_shell',
16
+ GREP: 'grep',
17
+ GLOB: 'glob',
18
+ EDIT: 'edit',
19
+ TODO_WRITE: 'todo_write',
20
+ TODO_READ: 'todo_read',
21
+ WEB_FETCH: 'web_fetch',
22
+ TASK: 'task',
23
+ SUGGEST: 'suggest',
24
+ };
25
+ /**
26
+ * Common tool sets for agent types
27
+ * Use these instead of hardcoding tool arrays
28
+ */
29
+ export const TOOL_SETS = {
30
+ /** Read-only tools for exploration and code review */
31
+ READ_ONLY: [TOOL_NAMES.GLOB, TOOL_NAMES.GREP, TOOL_NAMES.READ_FILE],
32
+ /** Read-only tools plus bash for running commands */
33
+ READ_ONLY_WITH_BASH: [TOOL_NAMES.BASH, TOOL_NAMES.GLOB, TOOL_NAMES.GREP, TOOL_NAMES.READ_FILE],
34
+ /** Read-only tools plus web fetch for documentation lookup */
35
+ READ_ONLY_WITH_WEB: [
36
+ TOOL_NAMES.WEB_FETCH,
37
+ TOOL_NAMES.GLOB,
38
+ TOOL_NAMES.GREP,
39
+ TOOL_NAMES.READ_FILE,
40
+ ],
41
+ /** Tools for refactoring (read + edit + write, no bash) */
42
+ REFACTOR: [
43
+ TOOL_NAMES.GLOB,
44
+ TOOL_NAMES.GREP,
45
+ TOOL_NAMES.READ_FILE,
46
+ TOOL_NAMES.EDIT,
47
+ TOOL_NAMES.WRITE_FILE,
48
+ ],
49
+ /** Tools for security auditing (read + bash for dependency checks) */
50
+ SECURITY_AUDIT: [TOOL_NAMES.GLOB, TOOL_NAMES.GREP, TOOL_NAMES.READ_FILE, TOOL_NAMES.BASH],
51
+ };
@@ -6,5 +6,5 @@ export { defineTool, createSuccessResult, createErrorResult, wrapToolExecute } f
6
6
  export type { DefineToolOptions } from './define.js';
7
7
  export { DefaultToolRegistry, createToolRegistry } from './registry.js';
8
8
  export type { ToolRegistryOptions } from './registry.js';
9
- export { readFileTool, createReadFileTool, writeFileTool, createWriteFileTool, bashTool, createBashTool, execStream, detectFifoUsage, bashOutputTool, createBashOutputTool, killShellTool, createKillShellTool, ShellManager, getDefaultShellManager, setDefaultShellManager, grepTool, createGrepTool, globTool, createGlobTool, editTool, createEditTool, todoWriteTool, todoReadTool, createTodoTools, TodoStore, resetDefaultTodoStore, getDefaultTodoStore, createIsolatedTodoStore, cleanupTodoContextMessages, getTodoContextStats, webFetchTool, createWebFetchTool, createTaskTool, defaultAgentTypes, builtinTools, allBuiltinTools, } from './builtin/index.js';
10
- export type { ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, BashOutputInput, BashOutputResult, KillShellInput, KillShellResult, ShellStatus, BackgroundShell, ShellOutput, ShellManagerOptions, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, WebFetchInput, WebFetchResult, WebFetchOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, } from './builtin/index.js';
9
+ export { readFileTool, createReadFileTool, writeFileTool, createWriteFileTool, bashTool, createBashTool, execStream, detectFifoUsage, bashOutputTool, createBashOutputTool, killShellTool, createKillShellTool, ShellManager, getDefaultShellManager, setDefaultShellManager, grepTool, createGrepTool, globTool, createGlobTool, editTool, createEditTool, todoWriteTool, todoReadTool, createTodoTools, TodoStore, resetDefaultTodoStore, getDefaultTodoStore, createIsolatedTodoStore, cleanupTodoContextMessages, getTodoContextStats, webFetchTool, createWebFetchTool, createTaskTool, defaultAgentTypes, suggestTool, createSuggestTool, builtinTools, allBuiltinTools, TOOL_NAMES, TOOL_SETS, } from './builtin/index.js';
10
+ export type { ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, BashOutputInput, BashOutputResult, KillShellInput, KillShellResult, ShellStatus, BackgroundShell, ShellOutput, ShellManagerOptions, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, WebFetchInput, WebFetchResult, WebFetchOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, SuggestInput, SuggestToolOptions, } from './builtin/index.js';