bashkit 0.1.2 → 0.2.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.
@@ -1,6 +1,25 @@
1
1
  import type { LanguageModelV2Middleware } from "@ai-sdk/provider";
2
+ import type { LanguageModelMiddleware } from "ai";
2
3
  /**
3
4
  * Middleware that enables Anthropic's prompt caching feature.
5
+ * For AI SDK v5 (LanguageModelV2).
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { wrapLanguageModel } from 'ai';
10
+ * import { anthropic } from '@ai-sdk/anthropic';
11
+ * import { anthropicPromptCacheMiddlewareV2 } from 'bashkit';
12
+ *
13
+ * const model = wrapLanguageModel({
14
+ * model: anthropic('claude-sonnet-4-20250514'),
15
+ * middleware: anthropicPromptCacheMiddlewareV2,
16
+ * });
17
+ * ```
18
+ */
19
+ export declare const anthropicPromptCacheMiddlewareV2: LanguageModelV2Middleware;
20
+ /**
21
+ * Middleware that enables Anthropic's prompt caching feature.
22
+ * For AI SDK v6+ (LanguageModelV3).
4
23
  *
5
24
  * @example
6
25
  * ```typescript
@@ -14,4 +33,4 @@ import type { LanguageModelV2Middleware } from "@ai-sdk/provider";
14
33
  * });
15
34
  * ```
16
35
  */
17
- export declare const anthropicPromptCacheMiddleware: LanguageModelV2Middleware;
36
+ export declare const anthropicPromptCacheMiddleware: LanguageModelMiddleware;
@@ -1 +1 @@
1
- export { anthropicPromptCacheMiddleware } from "./anthropic-cache";
1
+ export { anthropicPromptCacheMiddleware, anthropicPromptCacheMiddlewareV2, } from "./anthropic-cache";
@@ -2,5 +2,5 @@ export type { DiscoverSkillsOptions, SkillMetadata } from "./types";
2
2
  export type { SkillBundle } from "./fetch";
3
3
  export { discoverSkills } from "./discovery";
4
4
  export { fetchSkill, fetchSkills } from "./fetch";
5
- export { parseSkillMetadata } from "./loader";
5
+ export { parseSkillMetadata, loadSkillBundle, loadSkillBundles, } from "./loader";
6
6
  export { skillsToXml } from "./xml";
@@ -1,3 +1,4 @@
1
+ import type { SkillBundle } from "./fetch";
1
2
  import type { SkillMetadata } from "./types";
2
3
  /**
3
4
  * Parses YAML frontmatter from a SKILL.md file content.
@@ -9,3 +10,38 @@ import type { SkillMetadata } from "./types";
9
10
  * @throws Error if required fields (name, description) are missing
10
11
  */
11
12
  export declare function parseSkillMetadata(content: string, skillPath: string): SkillMetadata;
13
+ /**
14
+ * Loads all files from a local skill directory as a SkillBundle.
15
+ * Recursively reads all files, preserving directory structure.
16
+ *
17
+ * @param skillDir - Absolute path to skill directory (containing SKILL.md)
18
+ * @returns SkillBundle with all files
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const bundle = await loadSkillBundle('/path/to/.skills/pdf-processing');
23
+ * // bundle.files = {
24
+ * // 'SKILL.md': '---\nname: pdf-processing\n...',
25
+ * // 'templates/report.md': '# Report Template...',
26
+ * // 'scripts/extract.sh': '#!/bin/bash...',
27
+ * // }
28
+ * ```
29
+ */
30
+ export declare function loadSkillBundle(skillDir: string): Promise<SkillBundle>;
31
+ /**
32
+ * Loads multiple discovered skills as bundles.
33
+ * Takes the output of discoverSkills() and loads all files for each skill.
34
+ *
35
+ * @param skills - Array of skill metadata from discoverSkills()
36
+ * @returns Record mapping skill names to their bundles
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const discovered = await discoverSkills();
41
+ * const bundles = await loadSkillBundles(discovered);
42
+ *
43
+ * // Use with setupAgentEnvironment
44
+ * await setupAgentEnvironment(sandbox, { skills: bundles });
45
+ * ```
46
+ */
47
+ export declare function loadSkillBundles(skills: SkillMetadata[]): Promise<Record<string, SkillBundle>>;
@@ -1,23 +1,53 @@
1
- export interface AskUserOutput {
1
+ export interface QuestionOption {
2
+ label: string;
3
+ description?: string;
4
+ }
5
+ export interface StructuredQuestion {
6
+ header?: string;
7
+ question: string;
8
+ options?: QuestionOption[];
9
+ multiSelect?: boolean;
10
+ }
11
+ export interface AskUserSimpleOutput {
2
12
  question: string;
3
13
  awaiting_response: true;
4
14
  }
15
+ export interface AskUserStructuredOutput {
16
+ questions: StructuredQuestion[];
17
+ awaiting_response: true;
18
+ }
19
+ export type AskUserOutput = AskUserSimpleOutput | AskUserStructuredOutput;
5
20
  export interface AskUserError {
6
21
  error: string;
7
22
  }
23
+ export interface AskUserAnswerOutput {
24
+ answer: string;
25
+ answers?: Record<string, string | string[]>;
26
+ }
8
27
  export type AskUserResponseHandler = (question: string) => Promise<string> | string;
28
+ export type AskUserStructuredHandler = (questions: StructuredQuestion[]) => Promise<Record<string, string | string[]>> | Record<string, string | string[]>;
29
+ export interface AskUserToolConfig {
30
+ /** Handler for simple string questions */
31
+ onQuestion?: AskUserResponseHandler;
32
+ /** Handler for structured questions with options */
33
+ onStructuredQuestions?: AskUserStructuredHandler;
34
+ }
9
35
  /**
10
36
  * Creates a tool for asking the user clarifying questions.
11
37
  *
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
38
+ * Supports both simple string questions and structured multi-choice questions.
16
39
  *
17
- * @param onQuestion - Optional callback to handle the question and return an answer
40
+ * @param config - Configuration with optional handlers for questions
18
41
  */
19
- export declare function createAskUserTool(onQuestion?: AskUserResponseHandler): import("ai").Tool<{
20
- question: string;
21
- }, AskUserOutput | AskUserError | {
22
- answer: string;
23
- }>;
42
+ export declare function createAskUserTool(config?: AskUserToolConfig | AskUserResponseHandler): import("ai").Tool<{
43
+ question?: string | undefined;
44
+ questions?: {
45
+ question: string;
46
+ header?: string | undefined;
47
+ options?: {
48
+ label: string;
49
+ description?: string | undefined;
50
+ }[] | undefined;
51
+ multiSelect?: boolean | undefined;
52
+ }[] | undefined;
53
+ }, AskUserOutput | AskUserError | AskUserAnswerOutput>;
@@ -1,4 +1,3 @@
1
- import type { ToolConfig } from "../types";
2
1
  export interface ExitPlanModeOutput {
3
2
  message: string;
4
3
  approved?: boolean;
@@ -6,6 +5,6 @@ export interface ExitPlanModeOutput {
6
5
  export interface ExitPlanModeError {
7
6
  error: string;
8
7
  }
9
- export declare function createExitPlanModeTool(config?: ToolConfig, onPlanSubmit?: (plan: string) => Promise<boolean> | boolean): import("ai").Tool<{
8
+ export declare function createExitPlanModeTool(onPlanSubmit?: (plan: string) => Promise<boolean> | boolean): import("ai").Tool<{
10
9
  plan: string;
11
10
  }, ExitPlanModeOutput | ExitPlanModeError>;
@@ -1,5 +1,5 @@
1
1
  import type { Sandbox } from "../sandbox/interface";
2
- import type { ToolConfig } from "../types";
2
+ import type { GrepToolConfig } from "../types";
3
3
  export interface GrepMatch {
4
4
  file: string;
5
5
  line_number?: number;
@@ -26,7 +26,7 @@ export interface GrepError {
26
26
  error: string;
27
27
  }
28
28
  export type GrepOutput = GrepContentOutput | GrepFilesOutput | GrepCountOutput | GrepError;
29
- export declare function createGrepTool(sandbox: Sandbox, config?: ToolConfig): import("ai").Tool<{
29
+ export declare function createGrepTool(sandbox: Sandbox, config?: GrepToolConfig): import("ai").Tool<{
30
30
  pattern: string;
31
31
  path?: string | undefined;
32
32
  glob?: string | undefined;
@@ -38,5 +38,6 @@ export declare function createGrepTool(sandbox: Sandbox, config?: ToolConfig): i
38
38
  "-A"?: number | undefined;
39
39
  "-C"?: number | undefined;
40
40
  head_limit?: number | undefined;
41
+ offset?: number | undefined;
41
42
  multiline?: boolean | undefined;
42
43
  }, GrepOutput>;
@@ -69,9 +69,9 @@ export type { SubagentEventData, SubagentStepEvent, SubagentTypeConfig, TaskErro
69
69
  export { createTaskTool } from "./task";
70
70
  export type { TodoItem, TodoState, TodoWriteError, TodoWriteOutput, } from "./todo-write";
71
71
  export { createTodoWriteTool } from "./todo-write";
72
- export type { WebFetchError, WebFetchOutput, WebFetchToolConfig, } from "./web-fetch";
72
+ export type { WebFetchError, WebFetchOutput } from "./web-fetch";
73
73
  export { createWebFetchTool } from "./web-fetch";
74
- export type { WebSearchError, WebSearchOutput, WebSearchResult, WebSearchToolConfig, } from "./web-search";
74
+ export type { WebSearchError, WebSearchOutput, WebSearchResult, } from "./web-search";
75
75
  export { createWebSearchTool } from "./web-search";
76
76
  export type { WriteError, WriteOutput } from "./write";
77
77
  export { createWriteTool } from "./write";
@@ -1,4 +1,5 @@
1
1
  import { type ModelMessage, type LanguageModel, type PrepareStepFunction, type StepResult, type StopCondition, type UIMessageStreamWriter, type Tool, type ToolSet } from "ai";
2
+ import { z } from "zod";
2
3
  export interface TaskOutput {
3
4
  result: string;
4
5
  usage?: {
@@ -12,6 +13,14 @@ export interface TaskOutput {
12
13
  export interface TaskError {
13
14
  error: string;
14
15
  }
16
+ declare const taskInputSchema: z.ZodObject<{
17
+ description: z.ZodString;
18
+ prompt: z.ZodString;
19
+ subagent_type: z.ZodString;
20
+ system_prompt: z.ZodOptional<z.ZodString>;
21
+ tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ }, z.core.$strip>;
23
+ type TaskInput = z.infer<typeof taskInputSchema>;
15
24
  /** Event emitted for each step a subagent takes */
16
25
  export interface SubagentStepEvent {
17
26
  subagentType: string;
@@ -55,4 +64,5 @@ export interface TaskToolConfig {
55
64
  /** Optional stream writer for real-time subagent activity (uses streamText instead of generateText) */
56
65
  streamWriter?: UIMessageStreamWriter;
57
66
  }
58
- export declare function createTaskTool(config: TaskToolConfig): Tool;
67
+ export declare function createTaskTool(config: TaskToolConfig): Tool<TaskInput, TaskOutput | TaskError>;
68
+ export {};
@@ -1,4 +1,3 @@
1
- import type { ToolConfig } from "../types";
2
1
  export interface TodoItem {
3
2
  content: string;
4
3
  status: "pending" | "in_progress" | "completed";
@@ -19,7 +18,7 @@ export interface TodoWriteError {
19
18
  export interface TodoState {
20
19
  todos: TodoItem[];
21
20
  }
22
- export declare function createTodoWriteTool(state: TodoState, config?: ToolConfig, onUpdate?: (todos: TodoItem[]) => void): import("ai").Tool<{
21
+ export declare function createTodoWriteTool(state: TodoState, onUpdate?: (todos: TodoItem[]) => void): import("ai").Tool<{
23
22
  todos: {
24
23
  content: string;
25
24
  status: "pending" | "in_progress" | "completed";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * HTTP status codes that indicate a retryable error.
3
+ * Shared between web-search and web-fetch tools.
4
+ */
5
+ export declare const RETRYABLE_STATUS_CODES: number[];
@@ -1,4 +1,4 @@
1
- import type { LanguageModel } from "ai";
1
+ import type { WebFetchConfig } from "../types";
2
2
  export interface WebFetchOutput {
3
3
  response: string;
4
4
  url: string;
@@ -10,11 +10,7 @@ export interface WebFetchError {
10
10
  status_code?: number;
11
11
  retryable?: boolean;
12
12
  }
13
- export interface WebFetchToolConfig {
14
- apiKey: string;
15
- model: LanguageModel;
16
- }
17
- export declare function createWebFetchTool(config: WebFetchToolConfig): import("ai").Tool<{
13
+ export declare function createWebFetchTool(config: WebFetchConfig): import("ai").Tool<{
18
14
  url: string;
19
15
  prompt: string;
20
16
  }, WebFetchOutput | WebFetchError>;
@@ -1,3 +1,4 @@
1
+ import type { WebSearchConfig } from "../types";
1
2
  export interface WebSearchResult {
2
3
  title: string;
3
4
  url: string;
@@ -14,10 +15,7 @@ export interface WebSearchError {
14
15
  status_code?: number;
15
16
  retryable?: boolean;
16
17
  }
17
- export interface WebSearchToolConfig {
18
- apiKey: string;
19
- }
20
- export declare function createWebSearchTool(config: WebSearchToolConfig): import("ai").Tool<{
18
+ export declare function createWebSearchTool(config: WebSearchConfig): import("ai").Tool<{
21
19
  query: string;
22
20
  allowed_domains?: string[] | undefined;
23
21
  blocked_domains?: string[] | undefined;
package/dist/types.d.ts CHANGED
@@ -1,19 +1,37 @@
1
- import type { LanguageModel } from "ai";
1
+ import type { LanguageModel, Tool } from "ai";
2
+ import type { CacheStore } from "./cache/types";
2
3
  import type { SkillMetadata } from "./skills/types";
4
+ /**
5
+ * SDK tool options picked from the Tool type.
6
+ * This automatically adapts to the user's installed AI SDK version.
7
+ * - v5 users get v5 options (if any)
8
+ * - v6 users get v6 options (needsApproval, strict, etc.)
9
+ *
10
+ * Uses `any` for input/output to allow typed needsApproval functions.
11
+ */
12
+ export type SDKToolOptions = Partial<Pick<Tool<any, any>, "strict" | "needsApproval" | "providerOptions">>;
13
+ /**
14
+ * Configuration for sandbox-based tools.
15
+ * Extends AI SDK tool options for version-appropriate type safety.
16
+ */
3
17
  export type ToolConfig = {
4
18
  timeout?: number;
5
19
  maxFileSize?: number;
6
20
  maxOutputLength?: number;
7
21
  allowedPaths?: string[];
8
22
  blockedCommands?: string[];
23
+ } & SDKToolOptions;
24
+ export type GrepToolConfig = ToolConfig & {
25
+ /** Use ripgrep (rg) instead of grep. Requires ripgrep to be installed. Default: false */
26
+ useRipgrep?: boolean;
9
27
  };
10
28
  export type WebSearchConfig = {
11
29
  apiKey: string;
12
- };
30
+ } & SDKToolOptions;
13
31
  export type WebFetchConfig = {
14
32
  apiKey: string;
15
33
  model: LanguageModel;
16
- };
34
+ } & SDKToolOptions;
17
35
  export type AskUserConfig = {
18
36
  /** Callback to handle questions and return answers */
19
37
  onQuestion?: (question: string) => Promise<string> | string;
@@ -24,6 +42,40 @@ export type SkillConfig = {
24
42
  /** Callback when a skill is activated */
25
43
  onActivate?: (skill: SkillMetadata, instructions: string) => void | Promise<void>;
26
44
  };
45
+ /**
46
+ * Cache configuration for tool result caching.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * // Enable with defaults (LRU cache, 5min TTL, safe tools only)
51
+ * cache: true
52
+ *
53
+ * // Custom cache store
54
+ * cache: myRedisStore
55
+ *
56
+ * // Per-tool control
57
+ * cache: { Read: true, Glob: true, Bash: false }
58
+ *
59
+ * // Full options
60
+ * cache: { store: myStore, ttl: 600000, debug: true, Read: true }
61
+ * ```
62
+ */
63
+ export type CacheConfig = boolean | CacheStore | {
64
+ /** Custom cache store (default: LRUCacheStore) */
65
+ store?: CacheStore;
66
+ /** TTL in milliseconds (default: 5 minutes) */
67
+ ttl?: number;
68
+ /** Enable debug logging for cache hits/misses */
69
+ debug?: boolean;
70
+ /** Callback when cache hit occurs */
71
+ onHit?: (toolName: string, key: string) => void;
72
+ /** Callback when cache miss occurs */
73
+ onMiss?: (toolName: string, key: string) => void;
74
+ /** Custom key generator for cache keys */
75
+ keyGenerator?: (toolName: string, params: unknown) => string;
76
+ /** Per-tool overrides - any tool name can be enabled/disabled */
77
+ [toolName: string]: boolean | CacheStore | number | ((toolName: string, key: string) => void) | ((toolName: string, params: unknown) => string) | undefined;
78
+ };
27
79
  export type AgentConfig = {
28
80
  tools?: {
29
81
  Bash?: ToolConfig;
@@ -31,7 +83,7 @@ export type AgentConfig = {
31
83
  Write?: ToolConfig;
32
84
  Edit?: ToolConfig;
33
85
  Glob?: ToolConfig;
34
- Grep?: ToolConfig;
86
+ Grep?: GrepToolConfig;
35
87
  };
36
88
  /** Include AskUser tool for user clarification */
37
89
  askUser?: AskUserConfig;
@@ -43,6 +95,8 @@ export type AgentConfig = {
43
95
  webSearch?: WebSearchConfig;
44
96
  /** Include WebFetch tool with this config */
45
97
  webFetch?: WebFetchConfig;
98
+ /** Enable tool result caching */
99
+ cache?: CacheConfig;
46
100
  defaultTimeout?: number;
47
101
  workingDirectory?: string;
48
102
  };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * HTTP status codes that indicate a retryable error.
3
+ * Shared between web-search and web-fetch tools.
4
+ */
5
+ export declare const RETRYABLE_STATUS_CODES: number[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bashkit",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Agentic coding tools for the Vercel AI SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,17 +54,18 @@
54
54
  "@clack/prompts": "^0.7.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@ai-sdk/anthropic": "^2.0.50",
57
+ "@ai-sdk/anthropic": "^3.0.1",
58
58
  "@biomejs/biome": "^2.3.9",
59
59
  "@e2b/code-interpreter": "^1.5.1",
60
60
  "@types/bun": "latest",
61
61
  "@types/node": "^24.10.0",
62
62
  "@vercel/sandbox": "^1.0.4",
63
+ "ai": "^6.0.0",
63
64
  "parallel-web": "^0.2.4",
64
65
  "typescript": "^5.9.3"
65
66
  },
66
67
  "peerDependencies": {
67
- "ai": "^5.0.0",
68
+ "ai": ">=5.0.0",
68
69
  "zod": "^4.1.8",
69
70
  "@vercel/sandbox": "^1.0.0",
70
71
  "@e2b/code-interpreter": "^1.0.0",