bashkit 0.1.0 → 0.1.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/AGENTS.md CHANGED
@@ -24,7 +24,7 @@ Runs commands directly on the local machine. Use for development/testing only.
24
24
  import { createAgentTools, LocalSandbox } from "bashkit";
25
25
 
26
26
  const sandbox = new LocalSandbox("/tmp/workspace");
27
- const tools = createAgentTools(sandbox);
27
+ const { tools } = createAgentTools(sandbox);
28
28
  ```
29
29
 
30
30
  ### VercelSandbox (Production)
@@ -38,7 +38,7 @@ const sandbox = new VercelSandbox({
38
38
  runtime: "node22",
39
39
  resources: { vcpus: 2 },
40
40
  });
41
- const tools = createAgentTools(sandbox);
41
+ const { tools } = createAgentTools(sandbox);
42
42
 
43
43
  // Don't forget to cleanup
44
44
  await sandbox.destroy();
@@ -46,7 +46,7 @@ await sandbox.destroy();
46
46
 
47
47
  ## Available Tools
48
48
 
49
- ### Sandbox-based Tools (from createAgentTools)
49
+ ### Default Tools (always included)
50
50
 
51
51
  | Tool | Purpose | Key Inputs |
52
52
  |------|---------|------------|
@@ -57,13 +57,23 @@ await sandbox.destroy();
57
57
  | `Glob` | Find files by pattern | `pattern`, `path?` |
58
58
  | `Grep` | Search file contents | `pattern`, `path?`, `output_mode?`, `-i?`, `-C?` |
59
59
 
60
+ ### Optional Tools (via config)
61
+
62
+ | Tool | Purpose | Config Key |
63
+ |------|---------|------------|
64
+ | `AskUser` | Ask user clarifying questions | `askUser: { onQuestion? }` |
65
+ | `EnterPlanMode` | Enter planning/exploration mode | `planMode: true` |
66
+ | `ExitPlanMode` | Exit planning mode with a plan | `planMode: true` |
67
+ | `Skill` | Execute skills | `skill: { skills }` |
68
+ | `WebSearch` | Search the web | `webSearch: { apiKey }` |
69
+ | `WebFetch` | Fetch URL and process with AI | `webFetch: { apiKey, model }` |
70
+
60
71
  ### Workflow Tools (created separately)
61
72
 
62
73
  | Tool | Purpose | Factory |
63
74
  |------|---------|---------|
64
75
  | `Task` | Spawn sub-agents | `createTaskTool({ model, tools, subagentTypes? })` |
65
76
  | `TodoWrite` | Track task progress | `createTodoWriteTool(state, config?, onUpdate?)` |
66
- | `ExitPlanMode` | Exit planning mode | `createExitPlanModeTool(config?, onPlanSubmit?)` |
67
77
 
68
78
  ### Web Tools (require `parallel-web` peer dependency)
69
79
 
@@ -84,7 +94,7 @@ import {
84
94
  } from "bashkit";
85
95
 
86
96
  const sandbox = new LocalSandbox("/tmp/workspace");
87
- const tools = createAgentTools(sandbox);
97
+ const { tools } = createAgentTools(sandbox);
88
98
 
89
99
  // Wrap model with prompt caching (recommended)
90
100
  const model = wrapLanguageModel({
@@ -273,7 +283,7 @@ import { anthropic } from "@ai-sdk/anthropic";
273
283
 
274
284
  const skills = await discoverSkills();
275
285
  const sandbox = new LocalSandbox("/tmp/workspace");
276
- const tools = createAgentTools(sandbox);
286
+ const { tools } = createAgentTools(sandbox);
277
287
 
278
288
  const result = await generateText({
279
289
  model: anthropic("claude-sonnet-4-20250514"),
@@ -363,7 +373,7 @@ const systemPrompt = `Save notes to: ${config.workspace.notes}
363
373
  ${skillsToXml(skills)}
364
374
  `;
365
375
 
366
- const tools = createAgentTools(sandbox);
376
+ const { tools } = createAgentTools(sandbox);
367
377
  ```
368
378
 
369
379
  ## Common Patterns
@@ -386,7 +396,7 @@ import {
386
396
  const sandbox = new LocalSandbox("/tmp/workspace");
387
397
 
388
398
  // 2. Create sandbox tools
389
- const sandboxTools = createAgentTools(sandbox);
399
+ const { tools: sandboxTools } = createAgentTools(sandbox);
390
400
 
391
401
  // 3. Create model with caching
392
402
  const model = wrapLanguageModel({
@@ -424,7 +434,7 @@ await sandbox.destroy();
424
434
  Restrict tools with configuration:
425
435
 
426
436
  ```typescript
427
- const tools = createAgentTools(sandbox, {
437
+ const { tools } = createAgentTools(sandbox, {
428
438
  tools: {
429
439
  Bash: {
430
440
  enabled: true,
package/README.md CHANGED
@@ -43,7 +43,7 @@ import { generateText, stepCountIs } from 'ai';
43
43
  const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
44
44
 
45
45
  // Create tools bound to the sandbox
46
- const tools = createAgentTools(sandbox);
46
+ const { tools } = createAgentTools(sandbox);
47
47
 
48
48
  // Use with Vercel AI SDK
49
49
  const result = await generateText({
@@ -74,7 +74,7 @@ const sandbox = createVercelSandbox({
74
74
  resources: { vcpus: 2 },
75
75
  });
76
76
 
77
- const tools = createAgentTools(sandbox);
77
+ const { tools } = createAgentTools(sandbox);
78
78
 
79
79
  const result = streamText({
80
80
  model: anthropic('claude-sonnet-4-5'),
@@ -89,7 +89,7 @@ await sandbox.destroy();
89
89
 
90
90
  ## Available Tools
91
91
 
92
- ### Sandbox-based Tools (from `createAgentTools`)
92
+ ### Default Tools (always included)
93
93
 
94
94
  | Tool | Purpose | Key Inputs |
95
95
  |------|---------|------------|
@@ -100,13 +100,23 @@ await sandbox.destroy();
100
100
  | `Glob` | Find files by pattern | `pattern`, `path?` |
101
101
  | `Grep` | Search file contents | `pattern`, `path?`, `output_mode?`, `-i?`, `-C?` |
102
102
 
103
+ ### Optional Tools (via config)
104
+
105
+ | Tool | Purpose | Config Key |
106
+ |------|---------|------------|
107
+ | `AskUser` | Ask user clarifying questions | `askUser: { onQuestion? }` |
108
+ | `EnterPlanMode` | Enter planning/exploration mode | `planMode: true` |
109
+ | `ExitPlanMode` | Exit planning mode with a plan | `planMode: true` |
110
+ | `Skill` | Execute skills | `skill: { skills }` |
111
+ | `WebSearch` | Search the web | `webSearch: { apiKey }` |
112
+ | `WebFetch` | Fetch URL and process with AI | `webFetch: { apiKey, model }` |
113
+
103
114
  ### Workflow Tools (created separately)
104
115
 
105
116
  | Tool | Purpose | Factory |
106
117
  |------|---------|---------|
107
118
  | `Task` | Spawn sub-agents | `createTaskTool({ model, tools, subagentTypes? })` |
108
119
  | `TodoWrite` | Track task progress | `createTodoWriteTool(state, config?, onUpdate?)` |
109
- | `ExitPlanMode` | Exit planning mode | `createExitPlanModeTool(config?, onPlanSubmit?)` |
110
120
 
111
121
  ### Web Tools (require `parallel-web` peer dependency)
112
122
 
@@ -154,10 +164,30 @@ const sandbox = createE2BSandbox({
154
164
 
155
165
  ## Configuration
156
166
 
157
- You can configure tools with security restrictions and limits:
167
+ You can configure tools with security restrictions and limits, and enable optional tools:
158
168
 
159
169
  ```typescript
160
- const tools = createAgentTools(sandbox, {
170
+ const { tools, planModeState } = createAgentTools(sandbox, {
171
+ // Enable optional tools
172
+ askUser: {
173
+ onQuestion: async (question) => {
174
+ // Return user's answer, or undefined to return awaiting_response
175
+ return await promptUser(question);
176
+ },
177
+ },
178
+ planMode: true, // Enables EnterPlanMode and ExitPlanMode
179
+ skill: {
180
+ skills: discoveredSkills, // From discoverSkills()
181
+ },
182
+ webSearch: {
183
+ apiKey: process.env.PARALLEL_API_KEY,
184
+ },
185
+ webFetch: {
186
+ apiKey: process.env.PARALLEL_API_KEY,
187
+ model: anthropic('claude-haiku-4'),
188
+ },
189
+
190
+ // Tool-specific config
161
191
  tools: {
162
192
  Bash: {
163
193
  timeout: 30000,
@@ -171,13 +201,6 @@ const tools = createAgentTools(sandbox, {
171
201
  maxFileSize: 1_000_000, // 1MB limit
172
202
  },
173
203
  },
174
- webSearch: {
175
- apiKey: process.env.PARALLEL_API_KEY,
176
- },
177
- webFetch: {
178
- apiKey: process.env.PARALLEL_API_KEY,
179
- model: anthropic('claude-haiku-4'),
180
- },
181
204
  });
182
205
  ```
183
206
 
@@ -335,7 +358,7 @@ import { discoverSkills, skillsToXml, createAgentTools, createLocalSandbox } fro
335
358
 
336
359
  const skills = await discoverSkills();
337
360
  const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
338
- const tools = createAgentTools(sandbox);
361
+ const { tools } = createAgentTools(sandbox);
339
362
 
340
363
  const result = await generateText({
341
364
  model: anthropic('claude-sonnet-4-5'),
@@ -504,7 +527,7 @@ ${skillsToXml(skills)}
504
527
  `;
505
528
 
506
529
  // Create tools and run
507
- const tools = createAgentTools(sandbox);
530
+ const { tools } = createAgentTools(sandbox);
508
531
 
509
532
  const result = await generateText({
510
533
  model: anthropic('claude-sonnet-4-5'),
@@ -571,7 +594,7 @@ class DockerSandbox implements Sandbox {
571
594
  }
572
595
 
573
596
  const sandbox = new DockerSandbox();
574
- const tools = createAgentTools(sandbox);
597
+ const { tools } = createAgentTools(sandbox);
575
598
  ```
576
599
 
577
600
  ## Architecture
@@ -641,7 +664,13 @@ Creates a set of agent tools bound to a sandbox instance.
641
664
 
642
665
  - `createTaskTool(config)` - Spawn sub-agents for complex tasks
643
666
  - `createTodoWriteTool(state, config?, onUpdate?)` - Track task progress
644
- - `createExitPlanModeTool(config?, onPlanSubmit?)` - Exit planning mode
667
+
668
+ ### Optional Tools (also available via config)
669
+
670
+ - `createAskUserTool(onQuestion?)` - Ask user for clarification
671
+ - `createEnterPlanModeTool(state)` - Enter planning/exploration mode
672
+ - `createExitPlanModeTool(state, onPlanSubmit?)` - Exit planning mode with a plan
673
+ - `createSkillTool(skills)` - Execute loaded skills
645
674
 
646
675
  ### Utilities
647
676
 
package/dist/cli/init.js CHANGED
@@ -54,7 +54,7 @@ export const config: AgentConfig = {${webTools ? `
54
54
  ` : ""}};
55
55
 
56
56
  // Create tools
57
- export const tools = createAgentTools(sandbox${webTools ? ", config" : ""});
57
+ export const { tools } = createAgentTools(sandbox${webTools ? ", config" : ""});
58
58
  `;
59
59
  const configPath = join(process.cwd(), "bashkit.config.ts");
60
60
  if (existsSync(configPath)) {
@@ -141,7 +141,7 @@ async function init() {
141
141
  stdio: "inherit"
142
142
  });
143
143
  s.stop("Dependencies installed ✓");
144
- } catch (error) {
144
+ } catch {
145
145
  s.stop("Installation failed ✗");
146
146
  console.error(`
147
147
  ❌ Failed to install dependencies`);
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@ export { anthropicPromptCacheMiddleware } from "./middleware";
2
2
  export type { E2BSandboxConfig, LocalSandboxConfig, VercelSandboxConfig, } from "./sandbox";
3
3
  export { createE2BSandbox, createLocalSandbox, createVercelSandbox, } from "./sandbox";
4
4
  export type { ExecOptions, ExecResult, Sandbox } from "./sandbox/interface";
5
- export type { BashError, BashOutput, EditError, EditOutput, ExitPlanModeError, ExitPlanModeOutput, GlobError, GlobOutput, GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, GrepMatch, GrepOutput, ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, TodoItem, TodoState, TodoWriteError, TodoWriteOutput, WebFetchError, WebFetchOutput, WebFetchToolConfig, WebSearchError, WebSearchOutput, WebSearchResult, WebSearchToolConfig, WriteError, WriteOutput, } from "./tools";
6
- export { createAgentTools, createBashTool, createEditTool, createExitPlanModeTool, createGlobTool, createGrepTool, createReadTool, createTaskTool, createTodoWriteTool, createWebFetchTool, createWebSearchTool, createWriteTool, } from "./tools";
7
- export type { AgentConfig, ToolConfig, WebFetchConfig, WebSearchConfig, } from "./types";
5
+ export type { AgentToolsResult, AskUserError, AskUserOutput, AskUserResponseHandler, BashError, BashOutput, EditError, EditOutput, EnterPlanModeError, EnterPlanModeOutput, ExitPlanModeError, ExitPlanModeOutput, PlanModeState, GlobError, GlobOutput, GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, GrepMatch, GrepOutput, ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, SkillError, SkillOutput, SkillToolConfig, SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, TodoItem, TodoState, TodoWriteError, TodoWriteOutput, WebFetchError, WebFetchOutput, WebFetchToolConfig, WebSearchError, WebSearchOutput, WebSearchResult, WebSearchToolConfig, WriteError, WriteOutput, } from "./tools";
6
+ export { createAgentTools, createAskUserTool, createBashTool, createEditTool, createEnterPlanModeTool, createExitPlanModeTool, createGlobTool, createGrepTool, createReadTool, createSkillTool, createTaskTool, createTodoWriteTool, createWebFetchTool, createWebSearchTool, createWriteTool, } from "./tools";
7
+ export type { AgentConfig, AskUserConfig, SkillConfig, ToolConfig, WebFetchConfig, WebSearchConfig, } from "./types";
8
8
  export { DEFAULT_CONFIG } from "./types";
9
9
  export type { CompactConversationConfig, CompactConversationResult, CompactConversationState, ContextMetrics, ContextStatus, ContextStatusConfig, ContextStatusLevel, ModelContextLimit, PruneMessagesConfig, } from "./utils";
10
10
  export { compactConversation, contextNeedsAttention, contextNeedsCompaction, createCompactConfig, estimateMessagesTokens, estimateMessageTokens, estimateTokens, getContextStatus, MODEL_CONTEXT_LIMITS, pruneMessagesByTokens, } from "./utils";
package/dist/index.js CHANGED
@@ -358,14 +358,59 @@ var DEFAULT_CONFIG = {
358
358
  }
359
359
  };
360
360
 
361
- // src/tools/bash.ts
361
+ // src/tools/ask-user.ts
362
362
  import { tool, zodSchema } from "ai";
363
363
  import { z } from "zod";
364
- var bashInputSchema = z.object({
365
- command: z.string().describe("The command to execute"),
366
- timeout: z.number().optional().describe("Optional timeout in milliseconds (max 600000)"),
367
- description: z.string().optional().describe("Clear, concise description of what this command does in 5-10 words"),
368
- run_in_background: z.boolean().optional().describe("Set to true to run this command in the background")
364
+ var askUserInputSchema = z.object({
365
+ question: z.string().describe("The question to ask the user. Be specific and concise.")
366
+ });
367
+ var ASK_USER_DESCRIPTION = `Ask the user a clarifying question when you need more information to proceed.
368
+
369
+ **When to use:**
370
+ - You need clarification on ambiguous requirements
371
+ - Multiple valid approaches exist and user preference matters
372
+ - You're about to make a decision with significant consequences
373
+ - Required information is missing from the context
374
+
375
+ **When NOT to use:**
376
+ - You can make a reasonable assumption
377
+ - The question is trivial or can be inferred
378
+ - You're just being overly cautious
379
+
380
+ Keep questions specific and actionable. Avoid yes/no questions when you need details.`;
381
+ function createAskUserTool(onQuestion) {
382
+ return tool({
383
+ description: ASK_USER_DESCRIPTION,
384
+ inputSchema: zodSchema(askUserInputSchema),
385
+ execute: async ({
386
+ question
387
+ }) => {
388
+ try {
389
+ if (onQuestion) {
390
+ const answer = await onQuestion(question);
391
+ return { answer };
392
+ }
393
+ return {
394
+ question,
395
+ awaiting_response: true
396
+ };
397
+ } catch (error) {
398
+ return {
399
+ error: error instanceof Error ? error.message : "Unknown error"
400
+ };
401
+ }
402
+ }
403
+ });
404
+ }
405
+
406
+ // src/tools/bash.ts
407
+ import { tool as tool2, zodSchema as zodSchema2 } from "ai";
408
+ import { z as z2 } from "zod";
409
+ var bashInputSchema = z2.object({
410
+ command: z2.string().describe("The command to execute"),
411
+ timeout: z2.number().optional().describe("Optional timeout in milliseconds (max 600000)"),
412
+ description: z2.string().optional().describe("Clear, concise description of what this command does in 5-10 words"),
413
+ run_in_background: z2.boolean().optional().describe("Set to true to run this command in the background")
369
414
  });
370
415
  var BASH_DESCRIPTION = `Executes bash commands in a persistent shell session with optional timeout and background execution.
371
416
 
@@ -379,9 +424,9 @@ var BASH_DESCRIPTION = `Executes bash commands in a persistent shell session wit
379
424
  function createBashTool(sandbox, config) {
380
425
  const maxOutputLength = config?.maxOutputLength ?? 30000;
381
426
  const defaultTimeout = config?.timeout ?? 120000;
382
- return tool({
427
+ return tool2({
383
428
  description: BASH_DESCRIPTION,
384
- inputSchema: zodSchema(bashInputSchema),
429
+ inputSchema: zodSchema2(bashInputSchema),
385
430
  execute: async ({
386
431
  command,
387
432
  timeout,
@@ -429,18 +474,18 @@ function createBashTool(sandbox, config) {
429
474
  }
430
475
 
431
476
  // src/tools/edit.ts
432
- import { tool as tool2, zodSchema as zodSchema2 } from "ai";
433
- import { z as z2 } from "zod";
434
- var editInputSchema = z2.object({
435
- file_path: z2.string().describe("The absolute path to the file to modify"),
436
- old_string: z2.string().describe("The text to replace"),
437
- new_string: z2.string().describe("The text to replace it with (must be different from old_string)"),
438
- replace_all: z2.boolean().optional().describe("Replace all occurrences of old_string (default false)")
477
+ import { tool as tool3, zodSchema as zodSchema3 } from "ai";
478
+ import { z as z3 } from "zod";
479
+ var editInputSchema = z3.object({
480
+ file_path: z3.string().describe("The absolute path to the file to modify"),
481
+ old_string: z3.string().describe("The text to replace"),
482
+ new_string: z3.string().describe("The text to replace it with (must be different from old_string)"),
483
+ replace_all: z3.boolean().optional().describe("Replace all occurrences of old_string (default false)")
439
484
  });
440
485
  function createEditTool(sandbox, config) {
441
- return tool2({
486
+ return tool3({
442
487
  description: "Performs exact string replacements in files.",
443
- inputSchema: zodSchema2(editInputSchema),
488
+ inputSchema: zodSchema3(editInputSchema),
444
489
  execute: async ({
445
490
  file_path,
446
491
  old_string,
@@ -495,17 +540,104 @@ function createEditTool(sandbox, config) {
495
540
  });
496
541
  }
497
542
 
543
+ // src/tools/enter-plan-mode.ts
544
+ import { tool as tool4, zodSchema as zodSchema4 } from "ai";
545
+ import { z as z4 } from "zod";
546
+ var enterPlanModeInputSchema = z4.object({
547
+ reason: z4.string().describe("Brief explanation of why you're entering planning mode (e.g., 'Need to explore codebase architecture before implementing feature')")
548
+ });
549
+ var ENTER_PLAN_MODE_DESCRIPTION = `Enter planning mode to explore and design implementation approaches before making changes.
550
+
551
+ **When to use:**
552
+ - Complex tasks requiring research or exploration
553
+ - Need to understand codebase structure before implementing
554
+ - Multiple approaches possible and you need to evaluate trade-offs
555
+ - User explicitly asks you to plan before executing
556
+
557
+ **In planning mode:**
558
+ - Focus on reading, searching, and understanding
559
+ - Avoid making file changes (use Read, Grep, Glob instead of Write, Edit)
560
+ - Document your findings and proposed approach
561
+ - Use ExitPlanMode when ready with a plan for user approval
562
+
563
+ **When NOT to use:**
564
+ - Simple, well-defined tasks
565
+ - You already understand the codebase and approach
566
+ - User wants immediate execution`;
567
+ function createEnterPlanModeTool(state, onEnter) {
568
+ return tool4({
569
+ description: ENTER_PLAN_MODE_DESCRIPTION,
570
+ inputSchema: zodSchema4(enterPlanModeInputSchema),
571
+ execute: async ({
572
+ reason
573
+ }) => {
574
+ try {
575
+ if (state.isActive) {
576
+ return {
577
+ error: "Already in planning mode. Use ExitPlanMode to exit."
578
+ };
579
+ }
580
+ state.isActive = true;
581
+ state.enteredAt = new Date;
582
+ state.reason = reason;
583
+ if (onEnter) {
584
+ await onEnter(reason);
585
+ }
586
+ return {
587
+ message: `Entered planning mode: ${reason}. Use Read, Grep, and Glob to explore. Call ExitPlanMode when ready with a plan.`,
588
+ mode: "planning"
589
+ };
590
+ } catch (error) {
591
+ return {
592
+ error: error instanceof Error ? error.message : "Unknown error"
593
+ };
594
+ }
595
+ }
596
+ });
597
+ }
598
+
599
+ // src/tools/exit-plan-mode.ts
600
+ import { tool as tool5, zodSchema as zodSchema5 } from "ai";
601
+ import { z as z5 } from "zod";
602
+ var exitPlanModeInputSchema = z5.object({
603
+ plan: z5.string().describe("The plan to present to the user for approval")
604
+ });
605
+ function createExitPlanModeTool(config, onPlanSubmit) {
606
+ return tool5({
607
+ description: "Exits planning mode and prompts the user to approve the plan. Use this when you have finished planning and want user confirmation before proceeding.",
608
+ inputSchema: zodSchema5(exitPlanModeInputSchema),
609
+ execute: async ({
610
+ plan
611
+ }) => {
612
+ try {
613
+ let approved;
614
+ if (onPlanSubmit) {
615
+ approved = await onPlanSubmit(plan);
616
+ }
617
+ return {
618
+ message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
619
+ approved
620
+ };
621
+ } catch (error) {
622
+ return {
623
+ error: error instanceof Error ? error.message : "Unknown error"
624
+ };
625
+ }
626
+ }
627
+ });
628
+ }
629
+
498
630
  // src/tools/glob.ts
499
- import { tool as tool3, zodSchema as zodSchema3 } from "ai";
500
- import { z as z3 } from "zod";
501
- var globInputSchema = z3.object({
502
- pattern: z3.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js", "*.md")'),
503
- path: z3.string().optional().describe("Directory to search in (defaults to working directory)")
631
+ import { tool as tool6, zodSchema as zodSchema6 } from "ai";
632
+ import { z as z6 } from "zod";
633
+ var globInputSchema = z6.object({
634
+ pattern: z6.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js", "*.md")'),
635
+ path: z6.string().optional().describe("Directory to search in (defaults to working directory)")
504
636
  });
505
637
  function createGlobTool(sandbox, config) {
506
- return tool3({
638
+ return tool6({
507
639
  description: "Search for files matching a glob pattern. Returns file paths sorted by modification time. Use this instead of `find` command.",
508
- inputSchema: zodSchema3(globInputSchema),
640
+ inputSchema: zodSchema6(globInputSchema),
509
641
  execute: async ({
510
642
  pattern,
511
643
  path
@@ -539,26 +671,26 @@ function createGlobTool(sandbox, config) {
539
671
  }
540
672
 
541
673
  // src/tools/grep.ts
542
- import { tool as tool4, zodSchema as zodSchema4 } from "ai";
543
- import { z as z4 } from "zod";
544
- var grepInputSchema = z4.object({
545
- pattern: z4.string().describe("The regular expression pattern to search for"),
546
- path: z4.string().optional().describe("File or directory to search in (defaults to cwd)"),
547
- glob: z4.string().optional().describe('Glob pattern to filter files (e.g. "*.js")'),
548
- type: z4.string().optional().describe('File type to search (e.g. "js", "py", "rust")'),
549
- output_mode: z4.enum(["content", "files_with_matches", "count"]).optional().describe('Output mode: "content", "files_with_matches", or "count"'),
550
- "-i": z4.boolean().optional().describe("Case insensitive search"),
551
- "-n": z4.boolean().optional().describe("Show line numbers (for content mode)"),
552
- "-B": z4.number().optional().describe("Lines to show before each match"),
553
- "-A": z4.number().optional().describe("Lines to show after each match"),
554
- "-C": z4.number().optional().describe("Lines to show before and after each match"),
555
- head_limit: z4.number().optional().describe("Limit output to first N lines/entries"),
556
- multiline: z4.boolean().optional().describe("Enable multiline mode")
674
+ import { tool as tool7, zodSchema as zodSchema7 } from "ai";
675
+ import { z as z7 } from "zod";
676
+ var grepInputSchema = z7.object({
677
+ pattern: z7.string().describe("The regular expression pattern to search for"),
678
+ path: z7.string().optional().describe("File or directory to search in (defaults to cwd)"),
679
+ glob: z7.string().optional().describe('Glob pattern to filter files (e.g. "*.js")'),
680
+ type: z7.string().optional().describe('File type to search (e.g. "js", "py", "rust")'),
681
+ output_mode: z7.enum(["content", "files_with_matches", "count"]).optional().describe('Output mode: "content", "files_with_matches", or "count"'),
682
+ "-i": z7.boolean().optional().describe("Case insensitive search"),
683
+ "-n": z7.boolean().optional().describe("Show line numbers (for content mode)"),
684
+ "-B": z7.number().optional().describe("Lines to show before each match"),
685
+ "-A": z7.number().optional().describe("Lines to show after each match"),
686
+ "-C": z7.number().optional().describe("Lines to show before and after each match"),
687
+ head_limit: z7.number().optional().describe("Limit output to first N lines/entries"),
688
+ multiline: z7.boolean().optional().describe("Enable multiline mode")
557
689
  });
558
690
  function createGrepTool(sandbox, config) {
559
- return tool4({
691
+ return tool7({
560
692
  description: "Powerful search tool built on ripgrep with regex support. Use this instead of the grep command.",
561
- inputSchema: zodSchema4(grepInputSchema),
693
+ inputSchema: zodSchema7(grepInputSchema),
562
694
  execute: async (input) => {
563
695
  const {
564
696
  pattern,
@@ -668,17 +800,17 @@ function createGrepTool(sandbox, config) {
668
800
  }
669
801
 
670
802
  // src/tools/read.ts
671
- import { tool as tool5, zodSchema as zodSchema5 } from "ai";
672
- import { z as z5 } from "zod";
673
- var readInputSchema = z5.object({
674
- file_path: z5.string().describe("Absolute path to file or directory"),
675
- offset: z5.number().optional().describe("Line number to start reading from (1-indexed)"),
676
- limit: z5.number().optional().describe("Maximum number of lines to read")
803
+ import { tool as tool8, zodSchema as zodSchema8 } from "ai";
804
+ import { z as z8 } from "zod";
805
+ var readInputSchema = z8.object({
806
+ file_path: z8.string().describe("Absolute path to file or directory"),
807
+ offset: z8.number().optional().describe("Line number to start reading from (1-indexed)"),
808
+ limit: z8.number().optional().describe("Maximum number of lines to read")
677
809
  });
678
810
  function createReadTool(sandbox, config) {
679
- return tool5({
811
+ return tool8({
680
812
  description: "Read the contents of a file or list directory entries. For text files, returns numbered lines with total line count. For directories, returns file/folder names. Use this instead of `cat`, `head`, or `tail` commands.",
681
- inputSchema: zodSchema5(readInputSchema),
813
+ inputSchema: zodSchema8(readInputSchema),
682
814
  execute: async ({
683
815
  file_path,
684
816
  offset,
@@ -760,20 +892,91 @@ function createReadTool(sandbox, config) {
760
892
  });
761
893
  }
762
894
 
895
+ // src/tools/skill.ts
896
+ import { tool as tool9, zodSchema as zodSchema9 } from "ai";
897
+ import { z as z9 } from "zod";
898
+ var skillInputSchema = z9.object({
899
+ name: z9.string().describe("The name of the skill to activate (from available skills list)")
900
+ });
901
+ var SKILL_DESCRIPTION = `Activate a skill to get specialized instructions for a task.
902
+
903
+ **How skills work:**
904
+ 1. Skills are pre-loaded at startup (only metadata: name, description, path)
905
+ 2. Calling this tool loads the full skill instructions from SKILL.md
906
+ 3. Follow the returned instructions to complete the task
907
+ 4. Some skills restrict which tools you can use (allowed_tools)
908
+
909
+ **When to use:**
910
+ - A task matches a skill's description
911
+ - You need specialized knowledge for a domain (e.g., PDF processing, web research)
912
+ - The skill provides step-by-step guidance you should follow
913
+
914
+ **Available skills are listed in the system prompt.**`;
915
+ function createSkillTool(config) {
916
+ const { skills, sandbox, onActivate } = config;
917
+ return tool9({
918
+ description: SKILL_DESCRIPTION,
919
+ inputSchema: zodSchema9(skillInputSchema),
920
+ execute: async ({
921
+ name
922
+ }) => {
923
+ try {
924
+ const skill = skills[name];
925
+ if (!skill) {
926
+ const available = Object.keys(skills);
927
+ if (available.length === 0) {
928
+ return { error: "No skills are available." };
929
+ }
930
+ return {
931
+ error: `Skill '${name}' not found. Available skills: ${available.join(", ")}`
932
+ };
933
+ }
934
+ let instructions;
935
+ if (!sandbox) {
936
+ return {
937
+ error: `Cannot load skill '${name}': no sandbox provided to read ${skill.path}`
938
+ };
939
+ }
940
+ const content = await sandbox.readFile(skill.path);
941
+ const frontmatterEnd = content.indexOf(`
942
+ ---`, 4);
943
+ if (frontmatterEnd !== -1) {
944
+ instructions = content.slice(frontmatterEnd + 4).trim();
945
+ } else {
946
+ instructions = content;
947
+ }
948
+ if (onActivate) {
949
+ await onActivate(skill, instructions);
950
+ }
951
+ return {
952
+ name: skill.name,
953
+ instructions,
954
+ allowed_tools: skill.allowedTools,
955
+ message: skill.allowedTools ? `Skill '${name}' activated. Restricted to tools: ${skill.allowedTools.join(", ")}` : `Skill '${name}' activated. Follow the instructions below.`
956
+ };
957
+ } catch (error) {
958
+ return {
959
+ error: error instanceof Error ? error.message : "Unknown error"
960
+ };
961
+ }
962
+ }
963
+ });
964
+ }
965
+
763
966
  // src/tools/web-fetch.ts
764
- import { generateText, tool as tool6, zodSchema as zodSchema6 } from "ai";
967
+ import { generateText, tool as tool10, zodSchema as zodSchema10 } from "ai";
765
968
  import Parallel from "parallel-web";
766
- import { z as z6 } from "zod";
767
- var webFetchInputSchema = z6.object({
768
- url: z6.string().describe("The URL to fetch content from"),
769
- prompt: z6.string().describe("The prompt to run on the fetched content")
969
+ import { z as z10 } from "zod";
970
+ var webFetchInputSchema = z10.object({
971
+ url: z10.string().describe("The URL to fetch content from"),
972
+ prompt: z10.string().describe("The prompt to run on the fetched content")
770
973
  });
771
974
  var RETRYABLE_CODES = [408, 429, 500, 502, 503];
772
975
  function createWebFetchTool(config) {
773
976
  const { apiKey, model } = config;
774
- return tool6({
977
+ return tool10({
775
978
  description: "Fetches content from a URL and processes it with an AI model. Use this to analyze web pages, extract information, or summarize content.",
776
- inputSchema: zodSchema6(webFetchInputSchema),
979
+ inputSchema: zodSchema10(webFetchInputSchema),
777
980
  execute: async (input) => {
778
981
  const { url, prompt } = input;
779
982
  try {
@@ -833,20 +1036,20 @@ ${content}`
833
1036
  }
834
1037
 
835
1038
  // src/tools/web-search.ts
836
- import { tool as tool7, zodSchema as zodSchema7 } from "ai";
1039
+ import { tool as tool11, zodSchema as zodSchema11 } from "ai";
837
1040
  import Parallel2 from "parallel-web";
838
- import { z as z7 } from "zod";
839
- var webSearchInputSchema = z7.object({
840
- query: z7.string().describe("The search query to use"),
841
- allowed_domains: z7.array(z7.string()).optional().describe("Only include results from these domains"),
842
- blocked_domains: z7.array(z7.string()).optional().describe("Never include results from these domains")
1041
+ import { z as z11 } from "zod";
1042
+ var webSearchInputSchema = z11.object({
1043
+ query: z11.string().describe("The search query to use"),
1044
+ allowed_domains: z11.array(z11.string()).optional().describe("Only include results from these domains"),
1045
+ blocked_domains: z11.array(z11.string()).optional().describe("Never include results from these domains")
843
1046
  });
844
1047
  var RETRYABLE_CODES2 = [408, 429, 500, 502, 503];
845
1048
  function createWebSearchTool(config) {
846
1049
  const { apiKey } = config;
847
- return tool7({
1050
+ return tool11({
848
1051
  description: "Searches the web and returns formatted results. Use this to find current information, documentation, articles, and more.",
849
- inputSchema: zodSchema7(webSearchInputSchema),
1052
+ inputSchema: zodSchema11(webSearchInputSchema),
850
1053
  execute: async (input) => {
851
1054
  const { query, allowed_domains, blocked_domains } = input;
852
1055
  try {
@@ -892,16 +1095,16 @@ function createWebSearchTool(config) {
892
1095
  }
893
1096
 
894
1097
  // src/tools/write.ts
895
- import { tool as tool8, zodSchema as zodSchema8 } from "ai";
896
- import { z as z8 } from "zod";
897
- var writeInputSchema = z8.object({
898
- file_path: z8.string().describe("Path to the file to write"),
899
- content: z8.string().describe("Content to write to the file")
1098
+ import { tool as tool12, zodSchema as zodSchema12 } from "ai";
1099
+ import { z as z12 } from "zod";
1100
+ var writeInputSchema = z12.object({
1101
+ file_path: z12.string().describe("Path to the file to write"),
1102
+ content: z12.string().describe("Content to write to the file")
900
1103
  });
901
1104
  function createWriteTool(sandbox, config) {
902
- return tool8({
1105
+ return tool12({
903
1106
  description: "Write content to a file. Creates the file if it does not exist, overwrites if it does.",
904
- inputSchema: zodSchema8(writeInputSchema),
1107
+ inputSchema: zodSchema12(writeInputSchema),
905
1108
  execute: async ({
906
1109
  file_path,
907
1110
  content
@@ -933,48 +1136,18 @@ function createWriteTool(sandbox, config) {
933
1136
  }
934
1137
  });
935
1138
  }
936
- // src/tools/exit-plan-mode.ts
937
- import { tool as tool9, zodSchema as zodSchema9 } from "ai";
938
- import { z as z9 } from "zod";
939
- var exitPlanModeInputSchema = z9.object({
940
- plan: z9.string().describe("The plan to present to the user for approval")
941
- });
942
- function createExitPlanModeTool(config, onPlanSubmit) {
943
- return tool9({
944
- description: "Exits planning mode and prompts the user to approve the plan. Use this when you have finished planning and want user confirmation before proceeding.",
945
- inputSchema: zodSchema9(exitPlanModeInputSchema),
946
- execute: async ({
947
- plan
948
- }) => {
949
- try {
950
- let approved;
951
- if (onPlanSubmit) {
952
- approved = await onPlanSubmit(plan);
953
- }
954
- return {
955
- message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
956
- approved
957
- };
958
- } catch (error) {
959
- return {
960
- error: error instanceof Error ? error.message : "Unknown error"
961
- };
962
- }
963
- }
964
- });
965
- }
966
1139
  // src/tools/task.ts
967
1140
  import {
968
1141
  generateText as generateText2,
969
1142
  stepCountIs,
970
- tool as tool10,
971
- zodSchema as zodSchema10
1143
+ tool as tool13,
1144
+ zodSchema as zodSchema13
972
1145
  } from "ai";
973
- import { z as z10 } from "zod";
974
- var taskInputSchema = z10.object({
975
- description: z10.string().describe("A short (3-5 word) description of the task"),
976
- prompt: z10.string().describe("The task for the agent to perform"),
977
- subagent_type: z10.string().describe("The type of specialized agent to use for this task")
1146
+ import { z as z13 } from "zod";
1147
+ var taskInputSchema = z13.object({
1148
+ description: z13.string().describe("A short (3-5 word) description of the task"),
1149
+ prompt: z13.string().describe("The task for the agent to perform"),
1150
+ subagent_type: z13.string().describe("The type of specialized agent to use for this task")
978
1151
  });
979
1152
  function filterTools(allTools, allowedTools) {
980
1153
  if (!allowedTools)
@@ -997,9 +1170,9 @@ function createTaskTool(config) {
997
1170
  defaultStopWhen,
998
1171
  defaultOnStepFinish
999
1172
  } = config;
1000
- return tool10({
1173
+ return tool13({
1001
1174
  description: "Launches a new agent to handle complex, multi-step tasks autonomously. Use this for tasks that require multiple steps, research, or specialized expertise.",
1002
- inputSchema: zodSchema10(taskInputSchema),
1175
+ inputSchema: zodSchema13(taskInputSchema),
1003
1176
  execute: async ({
1004
1177
  description,
1005
1178
  prompt,
@@ -1051,19 +1224,19 @@ function createTaskTool(config) {
1051
1224
  });
1052
1225
  }
1053
1226
  // src/tools/todo-write.ts
1054
- import { tool as tool11, zodSchema as zodSchema11 } from "ai";
1055
- import { z as z11 } from "zod";
1056
- var todoWriteInputSchema = z11.object({
1057
- todos: z11.array(z11.object({
1058
- content: z11.string().describe("The task description"),
1059
- status: z11.enum(["pending", "in_progress", "completed"]).describe("The task status"),
1060
- activeForm: z11.string().describe("Active form of the task description")
1227
+ import { tool as tool14, zodSchema as zodSchema14 } from "ai";
1228
+ import { z as z14 } from "zod";
1229
+ var todoWriteInputSchema = z14.object({
1230
+ todos: z14.array(z14.object({
1231
+ content: z14.string().describe("The task description"),
1232
+ status: z14.enum(["pending", "in_progress", "completed"]).describe("The task status"),
1233
+ activeForm: z14.string().describe("Active form of the task description")
1061
1234
  })).describe("The updated todo list")
1062
1235
  });
1063
1236
  function createTodoWriteTool(state, config, onUpdate) {
1064
- return tool11({
1237
+ return tool14({
1065
1238
  description: "Creates and manages a structured task list for tracking progress. Use this to plan complex tasks and track completion.",
1066
- inputSchema: zodSchema11(todoWriteInputSchema),
1239
+ inputSchema: zodSchema14(todoWriteInputSchema),
1067
1240
  execute: async ({
1068
1241
  todos
1069
1242
  }) => {
@@ -1105,13 +1278,29 @@ function createAgentTools(sandbox, config) {
1105
1278
  Glob: createGlobTool(sandbox, toolsConfig.Glob),
1106
1279
  Grep: createGrepTool(sandbox, toolsConfig.Grep)
1107
1280
  };
1281
+ let planModeState;
1282
+ if (config?.askUser) {
1283
+ tools.AskUser = createAskUserTool(config.askUser.onQuestion);
1284
+ }
1285
+ if (config?.planMode) {
1286
+ planModeState = { isActive: false };
1287
+ tools.EnterPlanMode = createEnterPlanModeTool(planModeState);
1288
+ tools.ExitPlanMode = createExitPlanModeTool();
1289
+ }
1290
+ if (config?.skill) {
1291
+ tools.Skill = createSkillTool({
1292
+ skills: config.skill.skills,
1293
+ sandbox,
1294
+ onActivate: config.skill.onActivate
1295
+ });
1296
+ }
1108
1297
  if (config?.webSearch) {
1109
1298
  tools.WebSearch = createWebSearchTool(config.webSearch);
1110
1299
  }
1111
1300
  if (config?.webFetch) {
1112
1301
  tools.WebFetch = createWebFetchTool(config.webFetch);
1113
1302
  }
1114
- return tools;
1303
+ return { tools, planModeState };
1115
1304
  }
1116
1305
  // src/utils/compact-conversation.ts
1117
1306
  import { generateText as generateText3 } from "ai";
@@ -1786,15 +1975,18 @@ export {
1786
1975
  createVercelSandbox,
1787
1976
  createTodoWriteTool,
1788
1977
  createTaskTool,
1978
+ createSkillTool,
1789
1979
  createReadTool,
1790
1980
  createLocalSandbox,
1791
1981
  createGrepTool,
1792
1982
  createGlobTool,
1793
1983
  createExitPlanModeTool,
1984
+ createEnterPlanModeTool,
1794
1985
  createEditTool,
1795
1986
  createE2BSandbox,
1796
1987
  createCompactConfig,
1797
1988
  createBashTool,
1989
+ createAskUserTool,
1798
1990
  createAgentTools,
1799
1991
  contextNeedsCompaction,
1800
1992
  contextNeedsAttention,
@@ -0,0 +1,23 @@
1
+ export interface AskUserOutput {
2
+ question: string;
3
+ awaiting_response: true;
4
+ }
5
+ export interface AskUserError {
6
+ error: string;
7
+ }
8
+ export type AskUserResponseHandler = (question: string) => Promise<string> | string;
9
+ /**
10
+ * Creates a tool for asking the user clarifying questions.
11
+ *
12
+ * The response handler can be:
13
+ * - Synchronous: returns the answer immediately
14
+ * - Async: waits for user input (e.g., from a UI)
15
+ * - Undefined: tool returns awaiting_response flag for external handling
16
+ *
17
+ * @param onQuestion - Optional callback to handle the question and return an answer
18
+ */
19
+ export declare function createAskUserTool(onQuestion?: AskUserResponseHandler): import("ai").Tool<{
20
+ question: string;
21
+ }, AskUserOutput | AskUserError | {
22
+ answer: string;
23
+ }>;
@@ -0,0 +1,22 @@
1
+ export interface PlanModeState {
2
+ isActive: boolean;
3
+ enteredAt?: Date;
4
+ reason?: string;
5
+ }
6
+ export interface EnterPlanModeOutput {
7
+ message: string;
8
+ mode: "planning";
9
+ }
10
+ export interface EnterPlanModeError {
11
+ error: string;
12
+ }
13
+ /**
14
+ * Creates a tool for entering planning mode.
15
+ * Works in conjunction with ExitPlanMode for plan-then-execute workflows.
16
+ *
17
+ * @param state - Shared state object to track planning mode
18
+ * @param onEnter - Optional callback when entering planning mode
19
+ */
20
+ export declare function createEnterPlanModeTool(state: PlanModeState, onEnter?: (reason: string) => void | Promise<void>): import("ai").Tool<{
21
+ reason: string;
22
+ }, EnterPlanModeOutput | EnterPlanModeError>;
@@ -1,30 +1,60 @@
1
1
  import type { ToolSet } from "ai";
2
2
  import type { Sandbox } from "../sandbox/interface";
3
3
  import type { AgentConfig } from "../types";
4
+ import { type PlanModeState } from "./enter-plan-mode";
4
5
  /**
5
- * Creates all sandbox-based agent tools for AI SDK's generateText/streamText.
6
- * Returns an object with Bash, Read, Write, Edit, Glob, Grep tools.
7
- * Optionally includes WebSearch and WebFetch if configured.
6
+ * Result from createAgentTools including tools and optional shared state.
7
+ */
8
+ export interface AgentToolsResult {
9
+ /** All configured tools for use with generateText/streamText */
10
+ tools: ToolSet;
11
+ /** Shared plan mode state (only present when planMode is enabled) */
12
+ planModeState?: PlanModeState;
13
+ }
14
+ /**
15
+ * Creates agent tools for AI SDK's generateText/streamText.
16
+ *
17
+ * **Default tools (always included):**
18
+ * - Bash, Read, Write, Edit, Glob, Grep (sandbox operations)
19
+ *
20
+ * **Optional tools (via config):**
21
+ * - `askUser` — AskUser tool for clarifying questions
22
+ * - `planMode` — EnterPlanMode, ExitPlanMode for interactive planning
23
+ * - `skill` — Skill tool for skill execution
24
+ * - `webSearch` — WebSearch tool
25
+ * - `webFetch` — WebFetch tool
8
26
  *
9
27
  * @param sandbox - The sandbox to execute commands in
10
- * @param config - Optional configuration for individual tools and web tools
28
+ * @param config - Optional configuration for tools
29
+ * @returns Object with tools and optional planModeState
11
30
  *
12
31
  * @example
13
- * // Basic sandbox tools only
14
- * const tools = createAgentTools(sandbox);
32
+ * // Basic usage (lean default for background agents)
33
+ * const { tools } = createAgentTools(sandbox);
34
+ *
35
+ * @example
36
+ * // Interactive agent with plan mode
37
+ * const { tools, planModeState } = createAgentTools(sandbox, {
38
+ * planMode: true,
39
+ * askUser: { onQuestion: async (q) => await promptUser(q) },
40
+ * });
15
41
  *
16
42
  * @example
17
- * // With web tools included
18
- * const tools = createAgentTools(sandbox, {
43
+ * // With web and skill tools
44
+ * const { tools } = createAgentTools(sandbox, {
19
45
  * webSearch: { apiKey: process.env.PARALLEL_API_KEY },
20
- * webFetch: { apiKey: process.env.PARALLEL_API_KEY, model: haiku },
46
+ * skill: { skills: discoveredSkills },
21
47
  * });
22
48
  */
23
- export declare function createAgentTools(sandbox: Sandbox, config?: AgentConfig): ToolSet;
49
+ export declare function createAgentTools(sandbox: Sandbox, config?: AgentConfig): AgentToolsResult;
50
+ export type { AskUserError, AskUserOutput, AskUserResponseHandler, } from "./ask-user";
51
+ export { createAskUserTool } from "./ask-user";
24
52
  export type { BashError, BashOutput } from "./bash";
25
53
  export { createBashTool } from "./bash";
26
54
  export type { EditError, EditOutput } from "./edit";
27
55
  export { createEditTool } from "./edit";
56
+ export type { EnterPlanModeError, EnterPlanModeOutput, PlanModeState, } from "./enter-plan-mode";
57
+ export { createEnterPlanModeTool } from "./enter-plan-mode";
28
58
  export type { ExitPlanModeError, ExitPlanModeOutput } from "./exit-plan-mode";
29
59
  export { createExitPlanModeTool } from "./exit-plan-mode";
30
60
  export type { GlobError, GlobOutput } from "./glob";
@@ -33,6 +63,8 @@ export type { GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, Gr
33
63
  export { createGrepTool } from "./grep";
34
64
  export type { ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, } from "./read";
35
65
  export { createReadTool } from "./read";
66
+ export type { SkillError, SkillOutput, SkillToolConfig } from "./skill";
67
+ export { createSkillTool } from "./skill";
36
68
  export type { SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, } from "./task";
37
69
  export { createTaskTool } from "./task";
38
70
  export type { TodoItem, TodoState, TodoWriteError, TodoWriteOutput, } from "./todo-write";
@@ -0,0 +1,94 @@
1
+ /**
2
+ * A diagnostic (error/warning) from the language server.
3
+ */
4
+ export interface LspDiagnostic {
5
+ file: string;
6
+ line: number;
7
+ column: number;
8
+ endLine?: number;
9
+ endColumn?: number;
10
+ severity: "error" | "warning" | "info" | "hint";
11
+ message: string;
12
+ source?: string;
13
+ code?: string | number;
14
+ }
15
+ /**
16
+ * A location in the codebase (for go-to-definition, references, etc.)
17
+ */
18
+ export interface LspLocation {
19
+ file: string;
20
+ line: number;
21
+ column: number;
22
+ endLine?: number;
23
+ endColumn?: number;
24
+ preview?: string;
25
+ }
26
+ /**
27
+ * Hover information for a symbol.
28
+ */
29
+ export interface LspHoverInfo {
30
+ contents: string;
31
+ range?: {
32
+ startLine: number;
33
+ startColumn: number;
34
+ endLine: number;
35
+ endColumn: number;
36
+ };
37
+ }
38
+ /**
39
+ * Interface that LSP providers must implement.
40
+ * This abstracts over different LSP implementations (vscode, standalone servers, etc.)
41
+ */
42
+ export interface LspProvider {
43
+ /** Get diagnostics for a file or the entire workspace */
44
+ getDiagnostics(file?: string): Promise<LspDiagnostic[]>;
45
+ /** Go to definition of symbol at position */
46
+ getDefinition(file: string, line: number, column: number): Promise<LspLocation[]>;
47
+ /** Find all references to symbol at position */
48
+ getReferences(file: string, line: number, column: number): Promise<LspLocation[]>;
49
+ /** Get hover information for symbol at position */
50
+ getHover(file: string, line: number, column: number): Promise<LspHoverInfo | null>;
51
+ /** Get available actions at position (optional) */
52
+ getCodeActions?(file: string, line: number, column: number): Promise<Array<{
53
+ title: string;
54
+ kind?: string;
55
+ }>>;
56
+ }
57
+ export interface LspDiagnosticsOutput {
58
+ type: "diagnostics";
59
+ diagnostics: LspDiagnostic[];
60
+ counts: {
61
+ errors: number;
62
+ warnings: number;
63
+ info: number;
64
+ hints: number;
65
+ };
66
+ }
67
+ export interface LspDefinitionOutput {
68
+ type: "definition";
69
+ locations: LspLocation[];
70
+ }
71
+ export interface LspReferencesOutput {
72
+ type: "references";
73
+ locations: LspLocation[];
74
+ count: number;
75
+ }
76
+ export interface LspHoverOutput {
77
+ type: "hover";
78
+ info: LspHoverInfo | null;
79
+ }
80
+ export interface LspError {
81
+ error: string;
82
+ }
83
+ export type LspOutput = LspDiagnosticsOutput | LspDefinitionOutput | LspReferencesOutput | LspHoverOutput | LspError;
84
+ /**
85
+ * Creates an LSP tool for code intelligence operations.
86
+ *
87
+ * @param provider - An implementation of LspProvider that interfaces with language servers
88
+ */
89
+ export declare function createLspTool(provider: LspProvider): import("ai").Tool<{
90
+ action: "diagnostics" | "definition" | "references" | "hover";
91
+ file?: string | undefined;
92
+ line?: number | undefined;
93
+ column?: number | undefined;
94
+ }, LspOutput>;
@@ -0,0 +1,27 @@
1
+ import type { Sandbox } from "../sandbox/interface";
2
+ import type { SkillMetadata } from "../skills/types";
3
+ export interface SkillOutput {
4
+ name: string;
5
+ instructions: string;
6
+ allowed_tools?: string[];
7
+ message: string;
8
+ }
9
+ export interface SkillError {
10
+ error: string;
11
+ }
12
+ export interface SkillToolConfig {
13
+ /** Map of skill name to metadata (from discoverSkills or setupAgentEnvironment) */
14
+ skills: Record<string, SkillMetadata>;
15
+ /** Sandbox for reading skill files (optional if skills have embedded content) */
16
+ sandbox?: Sandbox;
17
+ /** Callback when a skill is activated */
18
+ onActivate?: (skill: SkillMetadata, instructions: string) => void | Promise<void>;
19
+ }
20
+ /**
21
+ * Creates a tool for activating and loading skills.
22
+ *
23
+ * @param config - Configuration with available skills and optional sandbox
24
+ */
25
+ export declare function createSkillTool(config: SkillToolConfig): import("ai").Tool<{
26
+ name: string;
27
+ }, SkillOutput | SkillError>;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { LanguageModel } from "ai";
2
+ import type { SkillMetadata } from "./skills/types";
2
3
  export type ToolConfig = {
3
4
  timeout?: number;
4
5
  maxFileSize?: number;
@@ -13,6 +14,16 @@ export type WebFetchConfig = {
13
14
  apiKey: string;
14
15
  model: LanguageModel;
15
16
  };
17
+ export type AskUserConfig = {
18
+ /** Callback to handle questions and return answers */
19
+ onQuestion?: (question: string) => Promise<string> | string;
20
+ };
21
+ export type SkillConfig = {
22
+ /** Map of skill name to metadata */
23
+ skills: Record<string, SkillMetadata>;
24
+ /** Callback when a skill is activated */
25
+ onActivate?: (skill: SkillMetadata, instructions: string) => void | Promise<void>;
26
+ };
16
27
  export type AgentConfig = {
17
28
  tools?: {
18
29
  Bash?: ToolConfig;
@@ -22,6 +33,12 @@ export type AgentConfig = {
22
33
  Glob?: ToolConfig;
23
34
  Grep?: ToolConfig;
24
35
  };
36
+ /** Include AskUser tool for user clarification */
37
+ askUser?: AskUserConfig;
38
+ /** Include EnterPlanMode and ExitPlanMode tools for interactive planning */
39
+ planMode?: boolean;
40
+ /** Include Skill tool with this config */
41
+ skill?: SkillConfig;
25
42
  /** Include WebSearch tool with this config */
26
43
  webSearch?: WebSearchConfig;
27
44
  /** Include WebFetch tool with this config */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bashkit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Agentic coding tools for the Vercel AI SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",