bashkit 0.1.3 → 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.
package/dist/index.js CHANGED
@@ -18,10 +18,8 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/middleware/anthropic-cache.ts
21
- function ensureCacheMarker(message) {
22
- if (!message)
23
- return;
24
- if (!("content" in message))
21
+ function addCacheMarker(message) {
22
+ if (!message || !("content" in message))
25
23
  return;
26
24
  const content = message.content;
27
25
  if (!content || !Array.isArray(content))
@@ -36,21 +34,20 @@ function ensureCacheMarker(message) {
36
34
  }
37
35
  };
38
36
  }
37
+ function applyCacheMarkers(params) {
38
+ const messages = params.prompt;
39
+ if (!messages || messages.length === 0)
40
+ return params;
41
+ addCacheMarker(messages.at(-1));
42
+ addCacheMarker(messages.slice(0, -1).findLast((m) => m.role !== "assistant"));
43
+ return params;
44
+ }
45
+ var anthropicPromptCacheMiddlewareV2 = {
46
+ transformParams: async ({ params }) => applyCacheMarkers(params)
47
+ };
39
48
  var anthropicPromptCacheMiddleware = {
40
- transformParams: async ({
41
- params
42
- }) => {
43
- const messages = params.prompt;
44
- if (!messages || messages.length === 0) {
45
- return params;
46
- }
47
- ensureCacheMarker(messages.at(-1));
48
- ensureCacheMarker(messages.slice(0, -1).findLast((m) => m.role !== "assistant"));
49
- return {
50
- ...params,
51
- prompt: messages
52
- };
53
- }
49
+ specificationVersion: "v3",
50
+ transformParams: async ({ params }) => applyCacheMarkers(params)
54
51
  };
55
52
  // src/sandbox/e2b.ts
56
53
  import { Sandbox as E2BSandboxSDK } from "@e2b/code-interpreter";
@@ -349,6 +346,132 @@ function createVercelSandbox(config = {}) {
349
346
  }
350
347
  };
351
348
  }
349
+ // src/cache/lru.ts
350
+ class LRUCacheStore {
351
+ cache = new Map;
352
+ maxSize;
353
+ constructor(maxSize = 1000) {
354
+ this.maxSize = maxSize;
355
+ }
356
+ get(key) {
357
+ const entry = this.cache.get(key);
358
+ if (entry) {
359
+ this.cache.delete(key);
360
+ this.cache.set(key, entry);
361
+ }
362
+ return entry;
363
+ }
364
+ set(key, entry) {
365
+ if (this.cache.has(key)) {
366
+ this.cache.delete(key);
367
+ } else if (this.cache.size >= this.maxSize) {
368
+ const firstKey = this.cache.keys().next().value;
369
+ if (firstKey !== undefined) {
370
+ this.cache.delete(firstKey);
371
+ }
372
+ }
373
+ this.cache.set(key, entry);
374
+ }
375
+ delete(key) {
376
+ this.cache.delete(key);
377
+ }
378
+ clear() {
379
+ this.cache.clear();
380
+ }
381
+ size() {
382
+ return this.cache.size;
383
+ }
384
+ }
385
+ // src/cache/cached.ts
386
+ import { createHash } from "crypto";
387
+ function defaultKeyGenerator(toolName, params) {
388
+ const sortedKeys = params && typeof params === "object" ? Object.keys(params).sort() : undefined;
389
+ const serialized = JSON.stringify(params, sortedKeys);
390
+ const hash = createHash("sha256").update(serialized).digest("hex").slice(0, 16);
391
+ return `${toolName}:${hash}`;
392
+ }
393
+ function cached(tool, toolName, options = {}) {
394
+ const {
395
+ ttl = 5 * 60 * 1000,
396
+ store = new LRUCacheStore,
397
+ keyGenerator = defaultKeyGenerator,
398
+ debug = false,
399
+ onHit,
400
+ onMiss
401
+ } = options;
402
+ let hits = 0;
403
+ let misses = 0;
404
+ const log = debug ? console.log.bind(console) : () => {};
405
+ const cachedTool = {
406
+ ...tool,
407
+ execute: async (params, execOptions) => {
408
+ const key = keyGenerator(toolName, params);
409
+ const now = Date.now();
410
+ const entry = await store.get(key);
411
+ if (entry && now - entry.timestamp < ttl) {
412
+ hits++;
413
+ log(`[Cache] HIT ${toolName}:${key.slice(-8)}`);
414
+ onHit?.(toolName, key);
415
+ return entry.result;
416
+ }
417
+ misses++;
418
+ log(`[Cache] MISS ${toolName}:${key.slice(-8)}`);
419
+ onMiss?.(toolName, key);
420
+ if (!tool.execute) {
421
+ throw new Error(`Tool ${toolName} has no execute function`);
422
+ }
423
+ const result = await tool.execute(params, execOptions);
424
+ if (result && typeof result === "object" && !("error" in result)) {
425
+ await store.set(key, { result, timestamp: now });
426
+ log(`[Cache] STORED ${toolName}:${key.slice(-8)}`);
427
+ }
428
+ return result;
429
+ },
430
+ async getStats() {
431
+ const total = hits + misses;
432
+ const size = await store.size?.() ?? 0;
433
+ return {
434
+ hits,
435
+ misses,
436
+ hitRate: total > 0 ? hits / total : 0,
437
+ size
438
+ };
439
+ },
440
+ async clearCache(key) {
441
+ if (key) {
442
+ await store.delete(key);
443
+ } else {
444
+ await store.clear();
445
+ }
446
+ }
447
+ };
448
+ return cachedTool;
449
+ }
450
+ // src/cache/redis.ts
451
+ function createRedisCacheStore(client, options = {}) {
452
+ const { prefix = "bashkit:" } = options;
453
+ return {
454
+ async get(key) {
455
+ const data = await client.get(`${prefix}${key}`);
456
+ return data ? JSON.parse(data) : undefined;
457
+ },
458
+ async set(key, entry) {
459
+ await client.set(`${prefix}${key}`, JSON.stringify(entry));
460
+ },
461
+ async delete(key) {
462
+ await client.del(`${prefix}${key}`);
463
+ },
464
+ async clear() {
465
+ const keys = await client.keys(`${prefix}*`);
466
+ if (keys.length)
467
+ await client.del(keys);
468
+ },
469
+ async size() {
470
+ const keys = await client.keys(`${prefix}*`);
471
+ return keys.length;
472
+ }
473
+ };
474
+ }
352
475
  // src/types.ts
353
476
  var DEFAULT_CONFIG = {
354
477
  defaultTimeout: 120000,
@@ -500,6 +623,9 @@ function createBashTool(sandbox, config) {
500
623
  return tool2({
501
624
  description: BASH_DESCRIPTION,
502
625
  inputSchema: zodSchema2(bashInputSchema),
626
+ strict: config?.strict,
627
+ needsApproval: config?.needsApproval,
628
+ providerOptions: config?.providerOptions,
503
629
  execute: async ({
504
630
  command,
505
631
  timeout,
@@ -576,6 +702,9 @@ function createEditTool(sandbox, config) {
576
702
  return tool3({
577
703
  description: EDIT_DESCRIPTION,
578
704
  inputSchema: zodSchema3(editInputSchema),
705
+ strict: config?.strict,
706
+ needsApproval: config?.needsApproval,
707
+ providerOptions: config?.providerOptions,
579
708
  execute: async ({
580
709
  file_path,
581
710
  old_string,
@@ -750,7 +879,7 @@ Before using this tool, ensure your plan is clear and unambiguous. If there are
750
879
  1. "Search for and understand the implementation of X" - Do NOT use this tool (research task)
751
880
  2. "Help me implement feature Y" - Use this tool after planning the implementation steps
752
881
  3. "Add user authentication" - If unsure about approach (OAuth vs JWT), clarify first, then use this tool`;
753
- function createExitPlanModeTool(config, onPlanSubmit) {
882
+ function createExitPlanModeTool(onPlanSubmit) {
754
883
  return tool5({
755
884
  description: EXIT_PLAN_MODE_DESCRIPTION,
756
885
  inputSchema: zodSchema5(exitPlanModeInputSchema),
@@ -794,6 +923,9 @@ function createGlobTool(sandbox, config) {
794
923
  return tool6({
795
924
  description: GLOB_DESCRIPTION,
796
925
  inputSchema: zodSchema6(globInputSchema),
926
+ strict: config?.strict,
927
+ needsApproval: config?.needsApproval,
928
+ providerOptions: config?.providerOptions,
797
929
  execute: async ({
798
930
  pattern,
799
931
  path
@@ -871,6 +1003,9 @@ function createGrepTool(sandbox, config) {
871
1003
  return tool7({
872
1004
  description: GREP_DESCRIPTION,
873
1005
  inputSchema: zodSchema7(grepInputSchema),
1006
+ strict: config?.strict,
1007
+ needsApproval: config?.needsApproval,
1008
+ providerOptions: config?.providerOptions,
874
1009
  execute: async (input) => {
875
1010
  const {
876
1011
  pattern,
@@ -1080,6 +1215,9 @@ function createReadTool(sandbox, config) {
1080
1215
  return tool8({
1081
1216
  description: READ_DESCRIPTION,
1082
1217
  inputSchema: zodSchema8(readInputSchema),
1218
+ strict: config?.strict,
1219
+ needsApproval: config?.needsApproval,
1220
+ providerOptions: config?.providerOptions,
1083
1221
  execute: async ({
1084
1222
  file_path,
1085
1223
  offset,
@@ -1236,11 +1374,15 @@ function createSkillTool(config) {
1236
1374
  import { generateText, tool as tool10, zodSchema as zodSchema10 } from "ai";
1237
1375
  import Parallel from "parallel-web";
1238
1376
  import { z as z10 } from "zod";
1377
+
1378
+ // src/utils/http-constants.ts
1379
+ var RETRYABLE_STATUS_CODES = [408, 429, 500, 502, 503];
1380
+
1381
+ // src/tools/web-fetch.ts
1239
1382
  var webFetchInputSchema = z10.object({
1240
1383
  url: z10.string().describe("The URL to fetch content from"),
1241
1384
  prompt: z10.string().describe("The prompt to run on the fetched content")
1242
1385
  });
1243
- var RETRYABLE_CODES = [408, 429, 500, 502, 503];
1244
1386
  var WEB_FETCH_DESCRIPTION = `
1245
1387
  - Fetches content from a specified URL and processes it using an AI model
1246
1388
  - Takes a URL and a prompt as input
@@ -1258,10 +1400,13 @@ Usage notes:
1258
1400
  - When a URL redirects to a different host, the tool will inform you and provide the redirect URL. You should then make a new WebFetch request with the redirect URL to fetch the content.
1259
1401
  `;
1260
1402
  function createWebFetchTool(config) {
1261
- const { apiKey, model } = config;
1403
+ const { apiKey, model, strict, needsApproval, providerOptions } = config;
1262
1404
  return tool10({
1263
1405
  description: WEB_FETCH_DESCRIPTION,
1264
1406
  inputSchema: zodSchema10(webFetchInputSchema),
1407
+ strict,
1408
+ needsApproval,
1409
+ providerOptions,
1265
1410
  execute: async (input) => {
1266
1411
  const { url, prompt } = input;
1267
1412
  try {
@@ -1309,7 +1454,7 @@ ${content}`
1309
1454
  return {
1310
1455
  error: message,
1311
1456
  status_code: statusCode,
1312
- retryable: RETRYABLE_CODES.includes(statusCode)
1457
+ retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
1313
1458
  };
1314
1459
  }
1315
1460
  return {
@@ -1329,7 +1474,6 @@ var webSearchInputSchema = z11.object({
1329
1474
  allowed_domains: z11.array(z11.string()).optional().describe("Only include results from these domains"),
1330
1475
  blocked_domains: z11.array(z11.string()).optional().describe("Never include results from these domains")
1331
1476
  });
1332
- var RETRYABLE_CODES2 = [408, 429, 500, 502, 503];
1333
1477
  var WEB_SEARCH_DESCRIPTION = `Searches the web and returns results with links. Use this for accessing up-to-date information beyond your knowledge cutoff.
1334
1478
 
1335
1479
  **Capabilities:**
@@ -1351,10 +1495,13 @@ When searching for recent information, documentation, or current events, use the
1351
1495
  - allowed_domains: Only include results from these domains
1352
1496
  - blocked_domains: Never include results from these domains`;
1353
1497
  function createWebSearchTool(config) {
1354
- const { apiKey } = config;
1498
+ const { apiKey, strict, needsApproval, providerOptions } = config;
1355
1499
  return tool11({
1356
1500
  description: WEB_SEARCH_DESCRIPTION,
1357
1501
  inputSchema: zodSchema11(webSearchInputSchema),
1502
+ strict,
1503
+ needsApproval,
1504
+ providerOptions,
1358
1505
  execute: async (input) => {
1359
1506
  const { query, allowed_domains, blocked_domains } = input;
1360
1507
  try {
@@ -1388,7 +1535,7 @@ function createWebSearchTool(config) {
1388
1535
  return {
1389
1536
  error: message,
1390
1537
  status_code: statusCode,
1391
- retryable: RETRYABLE_CODES2.includes(statusCode)
1538
+ retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
1392
1539
  };
1393
1540
  }
1394
1541
  return {
@@ -1422,6 +1569,9 @@ function createWriteTool(sandbox, config) {
1422
1569
  return tool12({
1423
1570
  description: WRITE_DESCRIPTION,
1424
1571
  inputSchema: zodSchema12(writeInputSchema),
1572
+ strict: config?.strict,
1573
+ needsApproval: config?.needsApproval,
1574
+ providerOptions: config?.providerOptions,
1425
1575
  execute: async ({
1426
1576
  file_path,
1427
1577
  content
@@ -1465,13 +1615,17 @@ import { z as z13 } from "zod";
1465
1615
  var taskInputSchema = z13.object({
1466
1616
  description: z13.string().describe("A short (3-5 word) description of the task"),
1467
1617
  prompt: z13.string().describe("The task for the agent to perform"),
1468
- subagent_type: z13.string().describe("The type of specialized agent to use for this task")
1618
+ subagent_type: z13.string().describe("The type of specialized agent to use for this task"),
1619
+ system_prompt: z13.string().optional().describe("Optional custom system prompt for this agent. If provided, overrides the default system prompt for the subagent type. Use this to create dynamic, specialized agents on the fly."),
1620
+ tools: z13.array(z13.string()).optional().describe("Optional list of tool names this agent can use (e.g., ['Read', 'Grep', 'WebSearch']). If provided, overrides the default tools for the subagent type. Use this to restrict or expand the agent's capabilities.")
1469
1621
  });
1470
1622
  var TASK_DESCRIPTION = `Launch a new agent to handle complex, multi-step tasks autonomously.
1471
1623
 
1472
1624
  The Task tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
1473
1625
 
1474
- When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
1626
+ **Subagent types:**
1627
+ - Use predefined subagent_type values for common task patterns
1628
+ - For dynamic agents: provide custom system_prompt and/or tools to create a specialized agent on the fly
1475
1629
 
1476
1630
  **When NOT to use the Task tool:**
1477
1631
  - If you want to read a specific file path, use the Read or Glob tool instead, to find the match more quickly
@@ -1517,14 +1671,16 @@ function createTaskTool(config) {
1517
1671
  execute: async ({
1518
1672
  description,
1519
1673
  prompt,
1520
- subagent_type
1674
+ subagent_type,
1675
+ system_prompt,
1676
+ tools: customTools
1521
1677
  }) => {
1522
1678
  const startTime = performance.now();
1523
1679
  try {
1524
1680
  const typeConfig = subagentTypes[subagent_type] || {};
1525
1681
  const model = typeConfig.model || defaultModel;
1526
- const tools = filterTools(allTools, typeConfig.tools);
1527
- const systemPrompt = typeConfig.systemPrompt;
1682
+ const tools = filterTools(allTools, customTools ?? typeConfig.tools);
1683
+ const systemPrompt = system_prompt ?? typeConfig.systemPrompt;
1528
1684
  const commonOptions = {
1529
1685
  model,
1530
1686
  tools,
@@ -1677,7 +1833,7 @@ var TODO_WRITE_DESCRIPTION = `Use this tool to create and manage a structured ta
1677
1833
  - Keep exactly ONE task in_progress at any time
1678
1834
  - ONLY mark completed when FULLY accomplished
1679
1835
  - If blocked/errors, keep in_progress and create new task for the blocker`;
1680
- function createTodoWriteTool(state, config, onUpdate) {
1836
+ function createTodoWriteTool(state, onUpdate) {
1681
1837
  return tool14({
1682
1838
  description: TODO_WRITE_DESCRIPTION,
1683
1839
  inputSchema: zodSchema14(todoWriteInputSchema),
@@ -1709,6 +1865,58 @@ function createTodoWriteTool(state, config, onUpdate) {
1709
1865
  }
1710
1866
 
1711
1867
  // src/tools/index.ts
1868
+ var DEFAULT_CACHEABLE = [
1869
+ "Read",
1870
+ "Glob",
1871
+ "Grep",
1872
+ "WebFetch",
1873
+ "WebSearch"
1874
+ ];
1875
+ function resolveCache(config) {
1876
+ if (!config) {
1877
+ return { store: null, ttl: 0, debug: false, enabled: new Set };
1878
+ }
1879
+ if (config === true) {
1880
+ return {
1881
+ store: new LRUCacheStore,
1882
+ ttl: 5 * 60 * 1000,
1883
+ debug: false,
1884
+ enabled: new Set(DEFAULT_CACHEABLE)
1885
+ };
1886
+ }
1887
+ if (typeof config === "object" && typeof config.get === "function" && typeof config.set === "function" && typeof config.delete === "function" && typeof config.clear === "function") {
1888
+ return {
1889
+ store: config,
1890
+ ttl: 5 * 60 * 1000,
1891
+ debug: false,
1892
+ enabled: new Set(DEFAULT_CACHEABLE)
1893
+ };
1894
+ }
1895
+ const enabled = new Set;
1896
+ for (const tool15 of DEFAULT_CACHEABLE) {
1897
+ if (config[tool15] !== false) {
1898
+ enabled.add(tool15);
1899
+ }
1900
+ }
1901
+ for (const [key, value] of Object.entries(config)) {
1902
+ if (["store", "ttl", "debug", "onHit", "onMiss", "keyGenerator"].includes(key))
1903
+ continue;
1904
+ if (value === true)
1905
+ enabled.add(key);
1906
+ if (value === false)
1907
+ enabled.delete(key);
1908
+ }
1909
+ const cfg = config;
1910
+ return {
1911
+ store: cfg.store ?? new LRUCacheStore,
1912
+ ttl: cfg.ttl ?? 5 * 60 * 1000,
1913
+ debug: cfg.debug ?? false,
1914
+ onHit: cfg.onHit,
1915
+ onMiss: cfg.onMiss,
1916
+ keyGenerator: cfg.keyGenerator,
1917
+ enabled
1918
+ };
1919
+ }
1712
1920
  function createAgentTools(sandbox, config) {
1713
1921
  const toolsConfig = {
1714
1922
  ...DEFAULT_CONFIG.tools,
@@ -1744,6 +1952,21 @@ function createAgentTools(sandbox, config) {
1744
1952
  if (config?.webFetch) {
1745
1953
  tools.WebFetch = createWebFetchTool(config.webFetch);
1746
1954
  }
1955
+ const cacheConfig = resolveCache(config?.cache);
1956
+ if (cacheConfig.store) {
1957
+ for (const [name, tool15] of Object.entries(tools)) {
1958
+ if (cacheConfig.enabled.has(name)) {
1959
+ tools[name] = cached(tool15, name, {
1960
+ store: cacheConfig.store,
1961
+ ttl: cacheConfig.ttl,
1962
+ debug: cacheConfig.debug,
1963
+ onHit: cacheConfig.onHit,
1964
+ onMiss: cacheConfig.onMiss,
1965
+ keyGenerator: cacheConfig.keyGenerator
1966
+ });
1967
+ }
1968
+ }
1969
+ }
1747
1970
  return { tools, planModeState };
1748
1971
  }
1749
1972
  // src/utils/compact-conversation.ts
@@ -2097,11 +2320,13 @@ function contextNeedsCompaction(status) {
2097
2320
  return status.status === "critical";
2098
2321
  }
2099
2322
  // src/skills/discovery.ts
2100
- import { readdir, readFile, stat } from "node:fs/promises";
2323
+ import { readdir as readdir2, readFile as readFile2, stat } from "node:fs/promises";
2101
2324
  import { homedir } from "node:os";
2102
- import { join, resolve } from "node:path";
2325
+ import { join as join2, resolve } from "node:path";
2103
2326
 
2104
2327
  // src/skills/loader.ts
2328
+ import { readdir, readFile } from "node:fs/promises";
2329
+ import { basename, dirname, join } from "node:path";
2105
2330
  function parseSkillMetadata(content, skillPath) {
2106
2331
  const frontmatter = extractFrontmatter(content);
2107
2332
  if (!frontmatter) {
@@ -2190,6 +2415,32 @@ function parseYaml(yaml) {
2190
2415
  }
2191
2416
  return result;
2192
2417
  }
2418
+ async function loadSkillBundle(skillDir) {
2419
+ const files = {};
2420
+ const name = basename(skillDir);
2421
+ async function readDirRecursive(dir, prefix = "") {
2422
+ const entries = await readdir(dir, { withFileTypes: true });
2423
+ for (const entry of entries) {
2424
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
2425
+ const fullPath = join(dir, entry.name);
2426
+ if (entry.isDirectory()) {
2427
+ await readDirRecursive(fullPath, relativePath);
2428
+ } else {
2429
+ files[relativePath] = await readFile(fullPath, "utf-8");
2430
+ }
2431
+ }
2432
+ }
2433
+ await readDirRecursive(skillDir);
2434
+ return { name, files };
2435
+ }
2436
+ async function loadSkillBundles(skills) {
2437
+ const bundles = {};
2438
+ for (const skill of skills) {
2439
+ const skillDir = dirname(skill.path);
2440
+ bundles[skill.name] = await loadSkillBundle(skillDir);
2441
+ }
2442
+ return bundles;
2443
+ }
2193
2444
 
2194
2445
  // src/skills/discovery.ts
2195
2446
  var DEFAULT_SKILL_PATHS = [".skills", "~/.bashkit/skills"];
@@ -2212,7 +2463,7 @@ async function discoverSkills(options) {
2212
2463
  }
2213
2464
  function resolvePath(path, cwd) {
2214
2465
  if (path.startsWith("~/")) {
2215
- return join(homedir(), path.slice(2));
2466
+ return join2(homedir(), path.slice(2));
2216
2467
  }
2217
2468
  if (path.startsWith("/")) {
2218
2469
  return path;
@@ -2222,18 +2473,18 @@ function resolvePath(path, cwd) {
2222
2473
  async function scanDirectory(dirPath) {
2223
2474
  const skills = [];
2224
2475
  try {
2225
- const entries = await readdir(dirPath, { withFileTypes: true });
2476
+ const entries = await readdir2(dirPath, { withFileTypes: true });
2226
2477
  for (const entry of entries) {
2227
2478
  if (!entry.isDirectory()) {
2228
2479
  continue;
2229
2480
  }
2230
- const skillPath = join(dirPath, entry.name, "SKILL.md");
2481
+ const skillPath = join2(dirPath, entry.name, "SKILL.md");
2231
2482
  try {
2232
2483
  const skillStat = await stat(skillPath);
2233
2484
  if (!skillStat.isFile()) {
2234
2485
  continue;
2235
2486
  }
2236
- const content = await readFile(skillPath, "utf-8");
2487
+ const content = await readFile2(skillPath, "utf-8");
2237
2488
  const metadata = parseSkillMetadata(content, skillPath);
2238
2489
  if (metadata.name !== entry.name) {
2239
2490
  console.warn(`Skill name "${metadata.name}" does not match folder name "${entry.name}" in ${skillPath}`);
@@ -2406,6 +2657,8 @@ export {
2406
2657
  setupAgentEnvironment,
2407
2658
  pruneMessagesByTokens,
2408
2659
  parseSkillMetadata,
2660
+ loadSkillBundles,
2661
+ loadSkillBundle,
2409
2662
  getContextStatus,
2410
2663
  fetchSkills,
2411
2664
  fetchSkill,
@@ -2420,6 +2673,7 @@ export {
2420
2673
  createTodoWriteTool,
2421
2674
  createTaskTool,
2422
2675
  createSkillTool,
2676
+ createRedisCacheStore,
2423
2677
  createReadTool,
2424
2678
  createLocalSandbox,
2425
2679
  createGrepTool,
@@ -2435,7 +2689,10 @@ export {
2435
2689
  contextNeedsCompaction,
2436
2690
  contextNeedsAttention,
2437
2691
  compactConversation,
2692
+ cached,
2693
+ anthropicPromptCacheMiddlewareV2,
2438
2694
  anthropicPromptCacheMiddleware,
2439
2695
  MODEL_CONTEXT_LIMITS,
2696
+ LRUCacheStore,
2440
2697
  DEFAULT_CONFIG
2441
2698
  };
@@ -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,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>;
@@ -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 {};