@compilr-dev/agents 0.2.1 → 0.3.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.
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Backlog Tools - File-based project backlog management
3
+ *
4
+ * Provides backlog_read and backlog_write tools for managing project backlogs.
5
+ * Uses a JSON file stored in .compilr/backlog.json (or backlog.json in project root).
6
+ *
7
+ * Features:
8
+ * - Read with filters (status, type, search, limit)
9
+ * - Write/update individual items or full backlog
10
+ * - Support for common item types (feature, bug, chore, spike)
11
+ * - Priority levels (critical, high, medium, low)
12
+ */
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+ import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
16
+ // =============================================================================
17
+ // File Operations
18
+ // =============================================================================
19
+ const BACKLOG_PATHS = ['.compilr/backlog.json', 'backlog.json', '.claude/backlog.json'];
20
+ function findBacklogFile(cwd = process.cwd()) {
21
+ for (const relPath of BACKLOG_PATHS) {
22
+ const fullPath = path.join(cwd, relPath);
23
+ if (fs.existsSync(fullPath)) {
24
+ return fullPath;
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+ function getDefaultBacklogPath(cwd = process.cwd()) {
30
+ // Prefer .compilr directory if it exists
31
+ const compilrDir = path.join(cwd, '.compilr');
32
+ if (fs.existsSync(compilrDir)) {
33
+ return path.join(compilrDir, 'backlog.json');
34
+ }
35
+ // Otherwise use project root
36
+ return path.join(cwd, 'backlog.json');
37
+ }
38
+ function loadBacklog(filePath) {
39
+ try {
40
+ const content = fs.readFileSync(filePath, 'utf-8');
41
+ const data = JSON.parse(content);
42
+ return {
43
+ version: data.version || '1.0',
44
+ items: Array.isArray(data.items) ? data.items : [],
45
+ };
46
+ }
47
+ catch {
48
+ return { version: '1.0', items: [] };
49
+ }
50
+ }
51
+ function saveBacklog(filePath, backlog) {
52
+ // Ensure directory exists
53
+ const dir = path.dirname(filePath);
54
+ if (!fs.existsSync(dir)) {
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ }
57
+ // Update timestamps
58
+ const now = new Date().toISOString();
59
+ backlog.items = backlog.items.map((item) => ({
60
+ ...item,
61
+ updatedAt: now,
62
+ createdAt: item.createdAt || now,
63
+ }));
64
+ fs.writeFileSync(filePath, JSON.stringify(backlog, null, 2), 'utf-8');
65
+ }
66
+ function generateItemId(type, items) {
67
+ const prefix = {
68
+ feature: 'FEAT',
69
+ bug: 'BUG',
70
+ chore: 'CHORE',
71
+ spike: 'SPIKE',
72
+ }[type];
73
+ // Find highest number for this type
74
+ const existingIds = items
75
+ .filter((i) => i.id.startsWith(prefix))
76
+ .map((i) => parseInt(i.id.split('-')[1], 10))
77
+ .filter((n) => !isNaN(n));
78
+ const nextNum = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 1;
79
+ return `${prefix}-${String(nextNum).padStart(3, '0')}`;
80
+ }
81
+ // =============================================================================
82
+ // Backlog Read Tool
83
+ // =============================================================================
84
+ /**
85
+ * Read backlog items with optional filters
86
+ */
87
+ export const backlogReadTool = defineTool({
88
+ name: 'backlog_read',
89
+ description: 'Read backlog items from the project. ' +
90
+ 'Use filters to narrow results. Use id parameter to get a specific item. ' +
91
+ 'Returns items sorted by priority (critical first) then by creation date.',
92
+ inputSchema: {
93
+ type: 'object',
94
+ properties: {
95
+ id: {
96
+ type: 'string',
97
+ description: 'Get a specific item by ID (e.g., "FEAT-001")',
98
+ },
99
+ status: {
100
+ type: 'string',
101
+ enum: ['backlog', 'in-progress', 'done', 'blocked'],
102
+ description: 'Filter by status',
103
+ },
104
+ type: {
105
+ type: 'string',
106
+ enum: ['feature', 'bug', 'chore', 'spike'],
107
+ description: 'Filter by item type',
108
+ },
109
+ search: {
110
+ type: 'string',
111
+ description: 'Search in title and description',
112
+ },
113
+ priority: {
114
+ type: 'string',
115
+ enum: ['critical', 'high', 'medium', 'low'],
116
+ description: 'Filter by priority',
117
+ },
118
+ limit: {
119
+ type: 'number',
120
+ description: 'Maximum items to return (default: 20)',
121
+ },
122
+ },
123
+ },
124
+ // eslint-disable-next-line @typescript-eslint/require-await
125
+ execute: async (input) => {
126
+ try {
127
+ const filePath = findBacklogFile();
128
+ if (!filePath) {
129
+ return createSuccessResult({
130
+ items: [],
131
+ total: 0,
132
+ filtered: 0,
133
+ message: 'No backlog file found. Use backlog_write to create one.',
134
+ });
135
+ }
136
+ const backlog = loadBacklog(filePath);
137
+ let items = [...backlog.items];
138
+ const total = items.length;
139
+ // Filter by ID (exact match)
140
+ if (input.id) {
141
+ items = items.filter((i) => i.id === input.id);
142
+ }
143
+ // Filter by status
144
+ if (input.status) {
145
+ items = items.filter((i) => i.status === input.status);
146
+ }
147
+ // Filter by type
148
+ if (input.type) {
149
+ items = items.filter((i) => i.type === input.type);
150
+ }
151
+ // Filter by priority
152
+ if (input.priority) {
153
+ items = items.filter((i) => i.priority === input.priority);
154
+ }
155
+ // Search in title and description
156
+ if (input.search) {
157
+ const query = input.search.toLowerCase();
158
+ items = items.filter((i) => i.title.toLowerCase().includes(query) || i.description?.toLowerCase().includes(query));
159
+ }
160
+ // Sort by priority then by creation date
161
+ const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
162
+ items.sort((a, b) => {
163
+ const pa = priorityOrder[a.priority || 'medium'];
164
+ const pb = priorityOrder[b.priority || 'medium'];
165
+ if (pa !== pb)
166
+ return pa - pb;
167
+ return (a.createdAt || '').localeCompare(b.createdAt || '');
168
+ });
169
+ // Apply limit
170
+ const limit = input.limit ?? 20;
171
+ const filtered = items.length;
172
+ items = items.slice(0, limit);
173
+ return createSuccessResult({
174
+ items,
175
+ total,
176
+ filtered,
177
+ });
178
+ }
179
+ catch (error) {
180
+ return createErrorResult(error instanceof Error ? error.message : String(error));
181
+ }
182
+ },
183
+ });
184
+ // =============================================================================
185
+ // Backlog Write Tool
186
+ // =============================================================================
187
+ /**
188
+ * Write/update backlog items
189
+ */
190
+ export const backlogWriteTool = defineTool({
191
+ name: 'backlog_write',
192
+ description: 'Create, update, or delete backlog items. ' +
193
+ 'Actions: add (new item), update (modify existing), delete (remove), replace (full list). ' +
194
+ 'IDs are auto-generated for new items based on type (e.g., FEAT-001, BUG-002).',
195
+ inputSchema: {
196
+ type: 'object',
197
+ properties: {
198
+ action: {
199
+ type: 'string',
200
+ enum: ['add', 'update', 'delete', 'replace'],
201
+ description: 'Action to perform',
202
+ },
203
+ item: {
204
+ type: 'object',
205
+ description: 'Item to add or update (for add/update actions)',
206
+ properties: {
207
+ id: { type: 'string', description: 'Item ID (required for update)' },
208
+ type: {
209
+ type: 'string',
210
+ enum: ['feature', 'bug', 'chore', 'spike'],
211
+ description: 'Item type (required for add)',
212
+ },
213
+ title: { type: 'string', description: 'Item title' },
214
+ description: { type: 'string', description: 'Detailed description' },
215
+ status: {
216
+ type: 'string',
217
+ enum: ['backlog', 'in-progress', 'done', 'blocked'],
218
+ description: 'Item status',
219
+ },
220
+ priority: {
221
+ type: 'string',
222
+ enum: ['critical', 'high', 'medium', 'low'],
223
+ description: 'Priority level',
224
+ },
225
+ acceptanceCriteria: {
226
+ type: 'array',
227
+ items: { type: 'string' },
228
+ description: 'Acceptance criteria list',
229
+ },
230
+ dependencies: {
231
+ type: 'array',
232
+ items: { type: 'string' },
233
+ description: 'IDs of items this depends on',
234
+ },
235
+ labels: {
236
+ type: 'array',
237
+ items: { type: 'string' },
238
+ description: 'Labels/tags',
239
+ },
240
+ },
241
+ },
242
+ deleteId: {
243
+ type: 'string',
244
+ description: 'Item ID to delete (for delete action)',
245
+ },
246
+ items: {
247
+ type: 'array',
248
+ description: 'Full list of items (for replace action)',
249
+ items: {
250
+ type: 'object',
251
+ },
252
+ },
253
+ },
254
+ required: ['action'],
255
+ },
256
+ // eslint-disable-next-line @typescript-eslint/require-await
257
+ execute: async (input) => {
258
+ try {
259
+ const existingPath = findBacklogFile();
260
+ const filePath = existingPath || getDefaultBacklogPath();
261
+ const backlog = existingPath ? loadBacklog(existingPath) : { version: '1.0', items: [] };
262
+ switch (input.action) {
263
+ case 'add': {
264
+ if (!input.item) {
265
+ return createErrorResult('Item is required for add action');
266
+ }
267
+ const itemType = input.item.type;
268
+ const itemTitle = input.item.title;
269
+ if (!itemType) {
270
+ return createErrorResult('Item type is required for add action');
271
+ }
272
+ if (!itemTitle) {
273
+ return createErrorResult('Item title is required for add action');
274
+ }
275
+ const newItem = {
276
+ id: generateItemId(itemType, backlog.items),
277
+ type: itemType,
278
+ title: itemTitle,
279
+ description: input.item.description,
280
+ status: input.item.status ?? 'backlog',
281
+ priority: input.item.priority,
282
+ acceptanceCriteria: input.item.acceptanceCriteria,
283
+ dependencies: input.item.dependencies,
284
+ labels: input.item.labels,
285
+ };
286
+ backlog.items.push(newItem);
287
+ saveBacklog(filePath, backlog);
288
+ return createSuccessResult({
289
+ success: true,
290
+ action: 'add',
291
+ itemId: newItem.id,
292
+ itemCount: backlog.items.length,
293
+ });
294
+ }
295
+ case 'update': {
296
+ const updateItem = input.item;
297
+ const updateId = updateItem?.id;
298
+ if (!updateItem || !updateId) {
299
+ return createErrorResult('Item ID is required for update action');
300
+ }
301
+ const idx = backlog.items.findIndex((i) => i.id === updateId);
302
+ if (idx === -1) {
303
+ return createErrorResult(`Item not found: ${updateId}`);
304
+ }
305
+ // Merge updates
306
+ backlog.items[idx] = {
307
+ ...backlog.items[idx],
308
+ ...updateItem,
309
+ id: backlog.items[idx].id, // Preserve original ID
310
+ };
311
+ saveBacklog(filePath, backlog);
312
+ return createSuccessResult({
313
+ success: true,
314
+ action: 'update',
315
+ itemId: updateId,
316
+ itemCount: backlog.items.length,
317
+ });
318
+ }
319
+ case 'delete': {
320
+ const deleteId = input.deleteId || input.item?.id;
321
+ if (!deleteId) {
322
+ return createErrorResult('deleteId or item.id is required for delete action');
323
+ }
324
+ const initialCount = backlog.items.length;
325
+ backlog.items = backlog.items.filter((i) => i.id !== deleteId);
326
+ if (backlog.items.length === initialCount) {
327
+ return createErrorResult(`Item not found: ${deleteId}`);
328
+ }
329
+ saveBacklog(filePath, backlog);
330
+ return createSuccessResult({
331
+ success: true,
332
+ action: 'delete',
333
+ itemId: deleteId,
334
+ itemCount: backlog.items.length,
335
+ });
336
+ }
337
+ case 'replace': {
338
+ if (!input.items) {
339
+ return createErrorResult('Items array is required for replace action');
340
+ }
341
+ backlog.items = input.items;
342
+ saveBacklog(filePath, backlog);
343
+ return createSuccessResult({
344
+ success: true,
345
+ action: 'replace',
346
+ itemCount: backlog.items.length,
347
+ });
348
+ }
349
+ default:
350
+ return createErrorResult(`Unknown action: ${input.action}`);
351
+ }
352
+ }
353
+ catch (error) {
354
+ return createErrorResult(error instanceof Error ? error.message : String(error));
355
+ }
356
+ },
357
+ });
358
+ /**
359
+ * Create backlog tools with custom options
360
+ */
361
+ export function createBacklogTools(_options = {}) {
362
+ // For now, just return the default tools
363
+ // Future: could customize file paths, storage backend, etc.
364
+ return {
365
+ backlogRead: backlogReadTool,
366
+ backlogWrite: backlogWriteTool,
367
+ };
368
+ }
@@ -116,7 +116,7 @@ export const bashTool = defineTool({
116
116
  /**
117
117
  * Execute the bash tool
118
118
  */
119
- async function executeBash(input) {
119
+ async function executeBash(input, context) {
120
120
  const { command, cwd, timeout = DEFAULT_TIMEOUT, env, run_in_background } = input;
121
121
  // Detect FIFO usage and add warning
122
122
  const fifoCheck = detectFifoUsage(command);
@@ -124,6 +124,17 @@ async function executeBash(input) {
124
124
  if (run_in_background) {
125
125
  return executeInBackground(command, { cwd, env });
126
126
  }
127
+ // Use streaming execution if context.onOutput is provided
128
+ if (context?.onOutput) {
129
+ return executeWithStreaming(command, {
130
+ cwd,
131
+ timeout,
132
+ env,
133
+ onOutput: context.onOutput,
134
+ fifoCheck,
135
+ });
136
+ }
137
+ // Non-streaming execution (original behavior)
127
138
  try {
128
139
  const result = await execAsync(command, {
129
140
  cwd,
@@ -164,6 +175,154 @@ async function executeBash(input) {
164
175
  return createErrorResult(error instanceof Error ? error.message : String(error));
165
176
  }
166
177
  }
178
+ /**
179
+ * Execute command with streaming output to onOutput callback
180
+ */
181
+ async function executeWithStreaming(command, options) {
182
+ const { cwd, timeout = DEFAULT_TIMEOUT, env, onOutput, fifoCheck } = options;
183
+ return new Promise((resolve) => {
184
+ const child = spawn(command, [], {
185
+ cwd,
186
+ shell: '/bin/bash',
187
+ env: env ? { ...process.env, ...env } : undefined,
188
+ });
189
+ let stdoutBuffer = '';
190
+ let stderrBuffer = '';
191
+ let timedOut = false;
192
+ // Set up timeout
193
+ const timeoutId = timeout > 0
194
+ ? setTimeout(() => {
195
+ timedOut = true;
196
+ child.kill('SIGTERM');
197
+ // Force kill after 5 seconds if not dead
198
+ setTimeout(() => child.kill('SIGKILL'), 5000);
199
+ }, timeout)
200
+ : undefined;
201
+ // Stream stdout
202
+ child.stdout.on('data', (data) => {
203
+ const text = data.toString();
204
+ stdoutBuffer += text;
205
+ // Emit each line separately for better UI updates
206
+ const lines = text.split('\n');
207
+ for (const line of lines) {
208
+ if (line.length > 0) {
209
+ onOutput(line, 'stdout');
210
+ }
211
+ }
212
+ });
213
+ // Stream stderr
214
+ child.stderr.on('data', (data) => {
215
+ const text = data.toString();
216
+ stderrBuffer += text;
217
+ // Emit each line separately
218
+ const lines = text.split('\n');
219
+ for (const line of lines) {
220
+ if (line.length > 0) {
221
+ onOutput(line, 'stderr');
222
+ }
223
+ }
224
+ });
225
+ // Handle completion
226
+ child.on('close', (code) => {
227
+ if (timeoutId)
228
+ clearTimeout(timeoutId);
229
+ if (timedOut) {
230
+ resolve(createErrorResult(`Command timed out after ${String(timeout)}ms`));
231
+ return;
232
+ }
233
+ // Truncate for final result
234
+ const stdout = truncateOutput(stdoutBuffer, DEFAULT_MAX_OUTPUT_SIZE);
235
+ const stderr = truncateOutput(stderrBuffer, DEFAULT_MAX_OUTPUT_SIZE);
236
+ resolve(createSuccessResult({
237
+ stdout: stdout.content,
238
+ stderr: stderr.content,
239
+ exitCode: code ?? 0,
240
+ truncated: stdout.truncated || stderr.truncated,
241
+ ...(fifoCheck.detected && { fifoWarning: fifoCheck.warning }),
242
+ }));
243
+ });
244
+ // Handle spawn errors
245
+ child.on('error', (error) => {
246
+ if (timeoutId)
247
+ clearTimeout(timeoutId);
248
+ resolve(createErrorResult(error.message));
249
+ });
250
+ });
251
+ }
252
+ /**
253
+ * Execute command with streaming output (custom options version for createBashTool)
254
+ */
255
+ async function executeWithStreamingCustom(command, options) {
256
+ const { cwd, timeout = DEFAULT_TIMEOUT, env, onOutput, fifoCheck, maxOutputSize, shell, } = options;
257
+ return new Promise((resolve) => {
258
+ const child = spawn(command, [], {
259
+ cwd,
260
+ shell,
261
+ env: env ? { ...process.env, ...env } : undefined,
262
+ });
263
+ let stdoutBuffer = '';
264
+ let stderrBuffer = '';
265
+ let timedOut = false;
266
+ // Set up timeout
267
+ const timeoutId = timeout > 0
268
+ ? setTimeout(() => {
269
+ timedOut = true;
270
+ child.kill('SIGTERM');
271
+ // Force kill after 5 seconds if not dead
272
+ setTimeout(() => child.kill('SIGKILL'), 5000);
273
+ }, timeout)
274
+ : undefined;
275
+ // Stream stdout
276
+ child.stdout.on('data', (data) => {
277
+ const text = data.toString();
278
+ stdoutBuffer += text;
279
+ // Emit each line separately for better UI updates
280
+ const lines = text.split('\n');
281
+ for (const line of lines) {
282
+ if (line.length > 0) {
283
+ onOutput(line, 'stdout');
284
+ }
285
+ }
286
+ });
287
+ // Stream stderr
288
+ child.stderr.on('data', (data) => {
289
+ const text = data.toString();
290
+ stderrBuffer += text;
291
+ // Emit each line separately
292
+ const lines = text.split('\n');
293
+ for (const line of lines) {
294
+ if (line.length > 0) {
295
+ onOutput(line, 'stderr');
296
+ }
297
+ }
298
+ });
299
+ // Handle completion
300
+ child.on('close', (code) => {
301
+ if (timeoutId)
302
+ clearTimeout(timeoutId);
303
+ if (timedOut) {
304
+ resolve(createErrorResult(`Command timed out after ${String(timeout)}ms`));
305
+ return;
306
+ }
307
+ // Truncate for final result
308
+ const stdout = truncateOutput(stdoutBuffer, maxOutputSize);
309
+ const stderr = truncateOutput(stderrBuffer, maxOutputSize);
310
+ resolve(createSuccessResult({
311
+ stdout: stdout.content,
312
+ stderr: stderr.content,
313
+ exitCode: code ?? 0,
314
+ truncated: stdout.truncated || stderr.truncated,
315
+ ...(fifoCheck.detected && { fifoWarning: fifoCheck.warning }),
316
+ }));
317
+ });
318
+ // Handle spawn errors
319
+ child.on('error', (error) => {
320
+ if (timeoutId)
321
+ clearTimeout(timeoutId);
322
+ resolve(createErrorResult(error.message));
323
+ });
324
+ });
325
+ }
167
326
  /**
168
327
  * Execute command in background and return shell ID
169
328
  */
@@ -234,7 +393,7 @@ export function createBashTool(options) {
234
393
  },
235
394
  required: ['command'],
236
395
  },
237
- execute: async (input) => {
396
+ execute: async (input, context) => {
238
397
  const { cwd: defaultCwd, timeout: defaultTimeout = DEFAULT_TIMEOUT, maxOutputSize = DEFAULT_MAX_OUTPUT_SIZE, blockedCommands = [], restrictToAllowed = false, allowedCommands = [], shell = '/bin/bash', shellManager, fifoMode = 'warn', } = options ?? {};
239
398
  const command = input.command.trim();
240
399
  // Detect FIFO usage
@@ -274,19 +433,27 @@ export function createBashTool(options) {
274
433
  return createErrorResult(error instanceof Error ? error.message : String(error));
275
434
  }
276
435
  }
277
- // Execute with merged options
278
- const mergedInput = {
279
- ...input,
280
- cwd: input.cwd ?? defaultCwd,
281
- timeout: input.timeout ?? defaultTimeout,
282
- };
436
+ const timeout = input.timeout ?? defaultTimeout;
437
+ // Use streaming execution if context.onOutput is provided
438
+ if (context?.onOutput) {
439
+ return executeWithStreamingCustom(command, {
440
+ cwd: input.cwd ?? defaultCwd,
441
+ timeout,
442
+ env: input.env,
443
+ onOutput: context.onOutput,
444
+ fifoCheck,
445
+ maxOutputSize,
446
+ shell,
447
+ });
448
+ }
449
+ // Execute with merged options (non-streaming)
283
450
  try {
284
- const result = await execAsync(mergedInput.command, {
285
- cwd: mergedInput.cwd,
286
- timeout: mergedInput.timeout,
451
+ const result = await execAsync(command, {
452
+ cwd: input.cwd ?? defaultCwd,
453
+ timeout,
287
454
  maxBuffer: MAX_BUFFER_SIZE,
288
455
  shell,
289
- env: mergedInput.env ? { ...process.env, ...mergedInput.env } : undefined,
456
+ env: input.env ? { ...process.env, ...input.env } : undefined,
290
457
  });
291
458
  // Truncate output to prevent memory bloat
292
459
  const stdout = truncateOutput(result.stdout, maxOutputSize);
@@ -302,7 +469,7 @@ export function createBashTool(options) {
302
469
  catch (error) {
303
470
  if (isExecError(error)) {
304
471
  if (error.killed) {
305
- return createErrorResult(`Command timed out after ${String(mergedInput.timeout ?? defaultTimeout)}ms`);
472
+ return createErrorResult(`Command timed out after ${String(timeout)}ms`);
306
473
  }
307
474
  // Truncate output even on error
308
475
  const stdout = truncateOutput(error.stdout ?? '', maxOutputSize);
@@ -29,6 +29,12 @@ export { webFetchTool, createWebFetchTool } from './web-fetch.js';
29
29
  export type { WebFetchInput, WebFetchResult, WebFetchOptions } from './web-fetch.js';
30
30
  export { suggestTool, createSuggestTool } from './suggest.js';
31
31
  export type { SuggestInput, SuggestToolOptions } from './suggest.js';
32
+ export { askUserTool, createAskUserTool } from './ask-user.js';
33
+ export type { AskUserInput, AskUserResult, AskUserQuestion, AskUserOption, AskUserToolOptions, } from './ask-user.js';
34
+ export { askUserSimpleTool, createAskUserSimpleTool } from './ask-user-simple.js';
35
+ export type { AskUserSimpleInput, AskUserSimpleResult, AskUserSimpleToolOptions, } from './ask-user-simple.js';
36
+ export { backlogReadTool, backlogWriteTool, createBacklogTools } from './backlog.js';
37
+ export type { BacklogItem, BacklogStatus, BacklogItemType, BacklogPriority, BacklogReadInput, BacklogReadResult, BacklogWriteInput, BacklogWriteResult, BacklogToolOptions, } from './backlog.js';
32
38
  export declare const builtinTools: {
33
39
  readonly readFile: import("../types.js").Tool<import("./read-file.js").ReadFileInput>;
34
40
  readonly writeFile: import("../types.js").Tool<import("./write-file.js").WriteFileInput>;
@@ -42,8 +48,12 @@ export declare const builtinTools: {
42
48
  readonly todoRead: import("../types.js").Tool<import("./todo.js").TodoReadInput>;
43
49
  readonly webFetch: import("../types.js").Tool<import("./web-fetch.js").WebFetchInput>;
44
50
  readonly suggest: import("../types.js").Tool<import("./suggest.js").SuggestInput>;
51
+ readonly askUser: import("../types.js").Tool<import("./ask-user.js").AskUserInput>;
52
+ readonly askUserSimple: import("../types.js").Tool<import("./ask-user-simple.js").AskUserSimpleInput>;
53
+ readonly backlogRead: import("../types.js").Tool<import("./backlog.js").BacklogReadInput>;
54
+ readonly backlogWrite: import("../types.js").Tool<import("./backlog.js").BacklogWriteInput>;
45
55
  };
46
56
  /**
47
57
  * Array of all built-in tools
48
58
  */
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>];
59
+ 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>, import("../types.js").Tool<import("./ask-user.js").AskUserInput>, import("../types.js").Tool<import("./ask-user-simple.js").AskUserSimpleInput>, import("../types.js").Tool<import("./backlog.js").BacklogReadInput>, import("../types.js").Tool<import("./backlog.js").BacklogWriteInput>];
@@ -29,6 +29,11 @@ export { createTaskTool, defaultAgentTypes } from './task.js';
29
29
  export { webFetchTool, createWebFetchTool } from './web-fetch.js';
30
30
  // Suggest tool (next action suggestions)
31
31
  export { suggestTool, createSuggestTool } from './suggest.js';
32
+ // Ask user tools (user interaction)
33
+ export { askUserTool, createAskUserTool } from './ask-user.js';
34
+ export { askUserSimpleTool, createAskUserSimpleTool } from './ask-user-simple.js';
35
+ // Backlog tools (file-based project backlog)
36
+ export { backlogReadTool, backlogWriteTool, createBacklogTools } from './backlog.js';
32
37
  /**
33
38
  * Collection of all built-in tools for easy registration
34
39
  */
@@ -43,6 +48,9 @@ import { editTool } from './edit.js';
43
48
  import { todoWriteTool, todoReadTool } from './todo.js';
44
49
  import { webFetchTool } from './web-fetch.js';
45
50
  import { suggestTool } from './suggest.js';
51
+ import { askUserTool } from './ask-user.js';
52
+ import { askUserSimpleTool } from './ask-user-simple.js';
53
+ import { backlogReadTool, backlogWriteTool } from './backlog.js';
46
54
  export const builtinTools = {
47
55
  readFile: readFileTool,
48
56
  writeFile: writeFileTool,
@@ -56,6 +64,10 @@ export const builtinTools = {
56
64
  todoRead: todoReadTool,
57
65
  webFetch: webFetchTool,
58
66
  suggest: suggestTool,
67
+ askUser: askUserTool,
68
+ askUserSimple: askUserSimpleTool,
69
+ backlogRead: backlogReadTool,
70
+ backlogWrite: backlogWriteTool,
59
71
  };
60
72
  /**
61
73
  * Array of all built-in tools
@@ -73,4 +85,8 @@ export const allBuiltinTools = [
73
85
  todoReadTool,
74
86
  webFetchTool,
75
87
  suggestTool,
88
+ askUserTool,
89
+ askUserSimpleTool,
90
+ backlogReadTool,
91
+ backlogWriteTool,
76
92
  ];