@bunny-agent/runner-cli 0.9.62 → 0.9.63-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bundle.mjs +279 -249
  2. package/package.json +10 -10
package/dist/bundle.mjs CHANGED
@@ -23504,14 +23504,73 @@ function approvalFileName(toolCallId) {
23504
23504
  return `${stem}.json`;
23505
23505
  }
23506
23506
 
23507
+ // ../../packages/manager/dist/tool-output.js
23508
+ import { randomBytes } from "node:crypto";
23509
+ import { writeFile } from "node:fs/promises";
23510
+ import { tmpdir } from "node:os";
23511
+ import { join as join2 } from "node:path";
23512
+ var TOOL_OUTPUT_MAX_BYTES = 50 * 1024;
23513
+ var TOOL_OUTPUT_MAX_LINES = 2e3;
23514
+ function countLines(text) {
23515
+ let lines = 1;
23516
+ for (let index = 0; index < text.length; index++) {
23517
+ if (text[index] === "\n")
23518
+ lines++;
23519
+ }
23520
+ return lines;
23521
+ }
23522
+ function previewText(text, maxBytes, maxLines) {
23523
+ const buffer = Buffer.from(text.slice(0, maxBytes), "utf8");
23524
+ let end = Math.min(buffer.length, maxBytes);
23525
+ while (end > 0 && end < buffer.length && (buffer[end] & 192) === 128) {
23526
+ end--;
23527
+ }
23528
+ const prefix = buffer.subarray(0, end).toString("utf8");
23529
+ let lines = 1;
23530
+ for (let index = 0; index < prefix.length; index++) {
23531
+ if (prefix[index] === "\n" && ++lines > maxLines) {
23532
+ return prefix.slice(0, index);
23533
+ }
23534
+ }
23535
+ return prefix;
23536
+ }
23537
+ async function guardToolOutput(text) {
23538
+ const originalBytes = Buffer.byteLength(text, "utf8");
23539
+ const originalLines = countLines(text);
23540
+ if (originalBytes <= TOOL_OUTPUT_MAX_BYTES && originalLines <= TOOL_OUTPUT_MAX_LINES) {
23541
+ return { text };
23542
+ }
23543
+ let fullOutputPath;
23544
+ try {
23545
+ const path3 = join2(tmpdir(), `bunny-tool-output-${randomBytes(8).toString("hex")}.txt`);
23546
+ await writeFile(path3, text, { encoding: "utf8", mode: 384, flag: "wx" });
23547
+ fullOutputPath = path3;
23548
+ } catch {
23549
+ }
23550
+ const retrieval = fullOutputPath ? `Full output saved to: ${JSON.stringify(fullOutputPath)}. Use read with offset/limit or bash to extract a bounded fragment.` : "Full output could not be saved. Retry with a narrower query or fewer fields.";
23551
+ const notice = `
23552
+
23553
+ [Tool output truncated: original ${originalBytes} bytes / ${originalLines} lines; preview limit ${TOOL_OUTPUT_MAX_BYTES} bytes / ${TOOL_OUTPUT_MAX_LINES} lines. ${retrieval}]`;
23554
+ const preview = previewText(text, TOOL_OUTPUT_MAX_BYTES - Buffer.byteLength(notice, "utf8"), TOOL_OUTPUT_MAX_LINES - countLines(notice) + 1);
23555
+ return {
23556
+ text: `${preview}${notice}`,
23557
+ outputGuard: {
23558
+ truncated: true,
23559
+ originalBytes,
23560
+ originalLines,
23561
+ ...fullOutputPath ? { fullOutputPath } : {}
23562
+ }
23563
+ };
23564
+ }
23565
+
23507
23566
  // ../../packages/runner-claude/dist/ai-sdk-stream.js
23508
23567
  import { appendFileSync, existsSync as existsSync2, unlinkSync } from "node:fs";
23509
- import { join as join2 } from "node:path";
23568
+ import { join as join3 } from "node:path";
23510
23569
  function trace(data, reset = false) {
23511
23570
  if (process.env.DEBUG !== "true")
23512
23571
  return;
23513
23572
  try {
23514
- const file3 = join2(process.cwd(), "claude-message-stream-debug.json");
23573
+ const file3 = join3(process.cwd(), "claude-message-stream-debug.json");
23515
23574
  if (reset && existsSync2(file3))
23516
23575
  unlinkSync(file3);
23517
23576
  const entry = {
@@ -23861,22 +23920,22 @@ function streamSDKMessagesToAISDKUI(messageIterator) {
23861
23920
 
23862
23921
  // ../../packages/runner-claude/dist/skill-plugin.js
23863
23922
  import { cpSync, mkdirSync, mkdtempSync, symlinkSync, writeFileSync } from "node:fs";
23864
- import { tmpdir } from "node:os";
23865
- import { basename, join as join3 } from "node:path";
23923
+ import { tmpdir as tmpdir2 } from "node:os";
23924
+ import { basename, join as join4 } from "node:path";
23866
23925
  var PLUGIN_NAME = "bunny-agent-skills";
23867
23926
  function createSkillPlugin(skillPaths) {
23868
23927
  if (skillPaths.length === 0)
23869
23928
  return void 0;
23870
23929
  try {
23871
- const pluginDir = mkdtempSync(join3(tmpdir(), "bunny-claude-skills-"));
23872
- const manifestDir = join3(pluginDir, ".claude-plugin");
23930
+ const pluginDir = mkdtempSync(join4(tmpdir2(), "bunny-claude-skills-"));
23931
+ const manifestDir = join4(pluginDir, ".claude-plugin");
23873
23932
  mkdirSync(manifestDir, { recursive: true });
23874
- writeFileSync(join3(manifestDir, "plugin.json"), JSON.stringify({
23933
+ writeFileSync(join4(manifestDir, "plugin.json"), JSON.stringify({
23875
23934
  name: PLUGIN_NAME,
23876
23935
  version: "0.0.0",
23877
23936
  description: "Bunny Agent skills exposed to the Claude runner"
23878
23937
  }, null, 2));
23879
- const skillsDir = join3(pluginDir, "skills");
23938
+ const skillsDir = join4(pluginDir, "skills");
23880
23939
  mkdirSync(skillsDir, { recursive: true });
23881
23940
  const usedNames = /* @__PURE__ */ new Set();
23882
23941
  for (const skillPath of skillPaths) {
@@ -23886,7 +23945,7 @@ function createSkillPlugin(skillPaths) {
23886
23945
  name = `${basename(skillPath)}-${suffix++}`;
23887
23946
  }
23888
23947
  usedNames.add(name);
23889
- const target = join3(skillsDir, name);
23948
+ const target = join4(skillsDir, name);
23890
23949
  try {
23891
23950
  symlinkSync(skillPath, target, "dir");
23892
23951
  } catch {
@@ -37687,13 +37746,15 @@ function buildOne(ref) {
37687
37746
  response = await executeToolRef(ref, args, void 0);
37688
37747
  } catch (error109) {
37689
37748
  const message = error109 instanceof Error ? error109.message : String(error109);
37690
- return errorResult(`Tool "${ref.name}" transport error: ${message}`);
37749
+ const output3 = await guardToolOutput(`Tool "${ref.name}" transport error: ${message}`);
37750
+ return errorResult(output3.text);
37691
37751
  }
37752
+ const output2 = await guardToolOutput(response.body);
37692
37753
  if (response.status < 200 || response.status >= 300) {
37693
- const body = response.body.trim();
37754
+ const body = output2.text.trim();
37694
37755
  return errorResult(body.length > 0 ? body : `Tool execution failed with status ${response.status}`);
37695
37756
  }
37696
- return { content: [{ type: "text", text: response.body }] };
37757
+ return { content: [{ type: "text", text: output2.text }] };
37697
37758
  }
37698
37759
  };
37699
37760
  }
@@ -38447,7 +38508,7 @@ ${inputToCodex}`;
38447
38508
 
38448
38509
  // ../../packages/runner-copilot/dist/copilot-runner.js
38449
38510
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
38450
- import { join as join5 } from "node:path";
38511
+ import { join as join6 } from "node:path";
38451
38512
  import { approveAll, CopilotClient } from "@github/copilot-sdk";
38452
38513
  var AsyncEventQueue = class {
38453
38514
  values = [];
@@ -38539,8 +38600,8 @@ function createFilePermissionHandler(cwd) {
38539
38600
  return async (request) => {
38540
38601
  const rawId = request.toolCallId ?? `copilot-${Date.now()}`;
38541
38602
  const approvalId = rawId.replace(/[^a-zA-Z0-9_.-]/g, "_");
38542
- const approvalDir = join5(cwd, ".bunny-agent", "approvals");
38543
- const approvalFile = join5(approvalDir, `${approvalId}.json`);
38603
+ const approvalDir = join6(cwd, ".bunny-agent", "approvals");
38604
+ const approvalFile = join6(approvalDir, `${approvalId}.json`);
38544
38605
  mkdirSync2(approvalDir, { recursive: true });
38545
38606
  if (!existsSync3(approvalFile)) {
38546
38607
  writeFileSync3(approvalFile, JSON.stringify({
@@ -38818,7 +38879,7 @@ function createCopilotRunner(options) {
38818
38879
  // ../../packages/runner-acp/dist/process-runner.js
38819
38880
  import { spawn } from "node:child_process";
38820
38881
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "node:fs";
38821
- import { join as join6 } from "node:path";
38882
+ import { join as join7 } from "node:path";
38822
38883
  import { Readable, Writable } from "node:stream";
38823
38884
  var AsyncQueue2 = class {
38824
38885
  values = [];
@@ -38902,8 +38963,8 @@ function usageMetadata(usage) {
38902
38963
  async function waitForFileApproval(cwd, request) {
38903
38964
  const rawId = request.toolCall.toolCallId ?? `acp-${Date.now()}`;
38904
38965
  const approvalId = rawId.replace(/[^a-zA-Z0-9_.-]/g, "_");
38905
- const approvalDir = join6(cwd, ".bunny-agent", "approvals");
38906
- const approvalFile = join6(approvalDir, `${approvalId}.json`);
38966
+ const approvalDir = join7(cwd, ".bunny-agent", "approvals");
38967
+ const approvalFile = join7(approvalDir, `${approvalId}.json`);
38907
38968
  mkdirSync3(approvalDir, { recursive: true });
38908
38969
  if (!existsSync4(approvalFile)) {
38909
38970
  writeFileSync4(approvalFile, JSON.stringify({
@@ -39206,7 +39267,7 @@ var mcpAdapterModule;
39206
39267
  function getMcpAdapterModule() {
39207
39268
  if (!mcpAdapterModule) {
39208
39269
  const jiti = createJiti(import.meta.url, {
39209
- fsCache: false,
39270
+ fsCache: true,
39210
39271
  moduleCache: true
39211
39272
  });
39212
39273
  mcpAdapterModule = jiti("pi-mcp-adapter");
@@ -39490,15 +39551,15 @@ function createMcpExtension(config4) {
39490
39551
  }
39491
39552
 
39492
39553
  // ../../packages/runner-pi/dist/pi-runner.js
39493
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, unlinkSync as unlinkSync7 } from "node:fs";
39494
- import { join as join12 } from "node:path";
39554
+ import { appendFileSync as appendFileSync2, existsSync as existsSync8, unlinkSync as unlinkSync7 } from "node:fs";
39555
+ import { isAbsolute, join as join12, resolve as resolve2 } from "node:path";
39495
39556
  import { getBuiltinModel } from "@earendil-works/pi-ai/providers/all";
39496
- import { createAgentSession, createCodingTools, ModelRuntime, SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
39557
+ import { CONFIG_DIR_NAME, createAgentSession, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager as SessionManager2, SettingsManager } from "@earendil-works/pi-coding-agent";
39497
39558
 
39498
39559
  // ../../packages/runner-pi/dist/apply-patch-shim.js
39499
39560
  import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync4, renameSync, writeFileSync as writeFileSync5 } from "node:fs";
39500
- import { tmpdir as tmpdir3 } from "node:os";
39501
- import { join as join7 } from "node:path";
39561
+ import { tmpdir as tmpdir4 } from "node:os";
39562
+ import { join as join8 } from "node:path";
39502
39563
  import { fileURLToPath } from "node:url";
39503
39564
  var SHIM_FILE = "apply_patch";
39504
39565
  function resolveApplyPatchBin() {
@@ -39514,15 +39575,15 @@ function ensureApplyPatchShim(binPath = resolveApplyPatchBin()) {
39514
39575
  }
39515
39576
  try {
39516
39577
  const uid = process.getuid?.() ?? 0;
39517
- const shimDir = join7(tmpdir3(), `bunny-agent-apply-patch-${uid}`);
39578
+ const shimDir = join8(tmpdir4(), `bunny-agent-apply-patch-${uid}`);
39518
39579
  mkdirSync4(shimDir, { recursive: true });
39519
39580
  const script = `#!/bin/sh
39520
39581
  exec "${process.execPath}" "${binPath}" "$@"
39521
39582
  `;
39522
- const staging = join7(shimDir, `.${SHIM_FILE}.${process.pid}.tmp`);
39583
+ const staging = join8(shimDir, `.${SHIM_FILE}.${process.pid}.tmp`);
39523
39584
  writeFileSync5(staging, script);
39524
39585
  chmodSync(staging, 493);
39525
- renameSync(staging, join7(shimDir, SHIM_FILE));
39586
+ renameSync(staging, join8(shimDir, SHIM_FILE));
39526
39587
  return shimDir;
39527
39588
  } catch {
39528
39589
  return void 0;
@@ -39787,102 +39848,6 @@ function buildApplyPatchTool(cwd) {
39787
39848
  };
39788
39849
  }
39789
39850
 
39790
- // ../../packages/runner-pi/dist/bunny-agent-resource-loader.js
39791
- import { existsSync as existsSync7 } from "node:fs";
39792
- import { homedir } from "node:os";
39793
- import { isAbsolute, join as join8, resolve as resolve2 } from "node:path";
39794
- import { DefaultResourceLoader, loadSkills } from "@earendil-works/pi-coding-agent";
39795
- var LOG_PREFIX = "[bunny-agent:pi]";
39796
- function logSkillLoad(cwd, agentDir, skillPaths, result) {
39797
- const lines = [
39798
- `${LOG_PREFIX} loadSkills`,
39799
- ` cwd: ${cwd}`,
39800
- ` agentDir: ${agentDir}`,
39801
- ` extra skillPaths (${skillPaths.length}):`
39802
- ];
39803
- for (const raw of skillPaths) {
39804
- const abs = isAbsolute(raw) ? raw : resolve2(cwd, raw);
39805
- lines.push(` ${raw} -> ${abs} (exists: ${existsSync7(abs) ? "yes" : "no"})`);
39806
- }
39807
- lines.push(` loaded skills: ${result.skills.length}`);
39808
- if (result.skills.length > 0) {
39809
- lines.push(` skill names: ${result.skills.map((s) => s.name).join(", ")}`);
39810
- }
39811
- if (result.diagnostics.length > 0) {
39812
- lines.push(` diagnostics (${result.diagnostics.length}):`);
39813
- for (const d of result.diagnostics) {
39814
- const pathPart = d.path !== void 0 ? ` path=${d.path}` : "";
39815
- lines.push(` [${d.type}] ${d.message}${pathPart}`);
39816
- }
39817
- }
39818
- console.error(lines.join("\n"));
39819
- }
39820
- var BunnyAgentResourceLoader = class {
39821
- constructor(options = {}) {
39822
- this.cwd = options.cwd ?? process.cwd();
39823
- this.agentDir = options.agentDir ?? join8(homedir(), ".bunny", "agent");
39824
- this.skillPaths = options.skillPaths ?? [];
39825
- this.extraAppendPrompt = options.appendSystemPrompt;
39826
- this.delegate = new DefaultResourceLoader({
39827
- cwd: this.cwd,
39828
- agentDir: this.agentDir,
39829
- settingsManager: options.settingsManager,
39830
- extensionFactories: options.extensionFactories
39831
- });
39832
- }
39833
- async reload() {
39834
- await this.delegate.reload();
39835
- this.cachedSkills = void 0;
39836
- }
39837
- getSkills() {
39838
- if (!this.cachedSkills) {
39839
- this.cachedSkills = loadSkills({
39840
- cwd: this.cwd,
39841
- agentDir: this.agentDir,
39842
- skillPaths: this.skillPaths,
39843
- includeDefaults: true
39844
- });
39845
- if (this.skillPaths.length > 0) {
39846
- logSkillLoad(this.cwd, this.agentDir, this.skillPaths, this.cachedSkills);
39847
- }
39848
- }
39849
- return this.cachedSkills;
39850
- }
39851
- // Delegate all other methods
39852
- getExtensions() {
39853
- return this.delegate.getExtensions();
39854
- }
39855
- getPrompts() {
39856
- return this.delegate.getPrompts();
39857
- }
39858
- getThemes() {
39859
- return this.delegate.getThemes();
39860
- }
39861
- getAgentsFiles() {
39862
- return this.delegate.getAgentsFiles();
39863
- }
39864
- getSystemPrompt() {
39865
- return this.delegate.getSystemPrompt();
39866
- }
39867
- getSystemPromptSource() {
39868
- return this.delegate.getSystemPromptSource();
39869
- }
39870
- getAppendSystemPromptSources() {
39871
- return this.delegate.getAppendSystemPromptSources();
39872
- }
39873
- getAppendSystemPrompt() {
39874
- const base = this.delegate.getAppendSystemPrompt();
39875
- if (this.extraAppendPrompt) {
39876
- console.error(`${LOG_PREFIX} getAppendSystemPrompt: appending extra prompt (${this.extraAppendPrompt.length} chars)`);
39877
- return [...base, this.extraAppendPrompt];
39878
- }
39879
- return base;
39880
- }
39881
- extendResources(paths) {
39882
- this.delegate.extendResources(paths);
39883
- }
39884
- };
39885
-
39886
39851
  // ../../packages/runner-pi/dist/image-tools.js
39887
39852
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "node:fs";
39888
39853
  import { dirname as dirname3, extname, join as join9 } from "node:path";
@@ -40294,7 +40259,7 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
40294
40259
  // biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
40295
40260
  parameters: editImageSchema,
40296
40261
  async execute(_toolCallId, params, signal, _onUpdate) {
40297
- const { readFileSync: readFileSync8, existsSync: existsSync13 } = await import("node:fs");
40262
+ const { readFileSync: readFileSync8, existsSync: existsSync12 } = await import("node:fs");
40298
40263
  const { resolve: resolve5, basename: basename3 } = await import("node:path");
40299
40264
  const p = params;
40300
40265
  const imagePath = p.image;
@@ -40307,7 +40272,7 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
40307
40272
  const rawFilename = p.filename;
40308
40273
  const safePrompt = buildPolicySafeEditPrompt(prompt);
40309
40274
  const resolvedImage = resolve5(cwd, imagePath);
40310
- if (!existsSync13(resolvedImage)) {
40275
+ if (!existsSync12(resolvedImage)) {
40311
40276
  return {
40312
40277
  content: [
40313
40278
  {
@@ -40351,7 +40316,7 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
40351
40316
  ];
40352
40317
  if (maskPath) {
40353
40318
  const resolvedMask = resolve5(cwd, maskPath);
40354
- if (existsSync13(resolvedMask)) {
40319
+ if (existsSync12(resolvedMask)) {
40355
40320
  files.push({
40356
40321
  name: "mask",
40357
40322
  filename: basename3(resolvedMask),
@@ -43568,37 +43533,37 @@ function buildAskUserQuestionTool(options) {
43568
43533
  }
43569
43534
  };
43570
43535
  }
43571
- function wrapToolWithApproval(tool, options) {
43536
+ function createToolApprovalExtension(options) {
43572
43537
  return {
43573
- name: tool.name,
43574
- label: tool.label ?? tool.name,
43575
- description: tool.description,
43576
- parameters: tool.parameters,
43577
- async execute(toolCallId, params, signal, onUpdate, ctx) {
43578
- const decision = await waitForApproval({
43579
- cwd: options.cwd,
43580
- toolCallId,
43581
- toolName: tool.name,
43582
- input: params,
43583
- signal: signal ?? options.fallbackSignal,
43584
- pollIntervalMs: options.pollIntervalMs,
43585
- timeoutMs: options.timeoutMs
43538
+ name: "bunny-agent-tool-approval",
43539
+ factory: (pi) => {
43540
+ pi.on("tool_call", async (event, ctx) => {
43541
+ if (isAskUserQuestionToolName(event.toolName) || event.parentToolCallId !== void 0) {
43542
+ return void 0;
43543
+ }
43544
+ const decision = await waitForApproval({
43545
+ cwd: options.cwd,
43546
+ toolCallId: event.toolCallId,
43547
+ toolName: event.toolName,
43548
+ input: event.input,
43549
+ signal: ctx.signal ?? options.fallbackSignal,
43550
+ pollIntervalMs: options.pollIntervalMs,
43551
+ timeoutMs: options.timeoutMs
43552
+ });
43553
+ if (decision.behavior === "deny") {
43554
+ return {
43555
+ block: true,
43556
+ reason: `Tool "${event.toolName}" was not approved: ${decision.message}`
43557
+ };
43558
+ }
43559
+ return void 0;
43586
43560
  });
43587
- if (decision.behavior === "deny") {
43588
- throw new Error(`Tool "${tool.name}" was not approved: ${decision.message}`);
43589
- }
43590
- return tool.execute(toolCallId, params, signal, onUpdate, ctx);
43591
43561
  }
43592
43562
  };
43593
43563
  }
43594
- function gateToolsForApproval(tools, bypass, options) {
43595
- if (bypass)
43596
- return tools;
43597
- return tools.map((tool) => wrapToolWithApproval(tool, options));
43598
- }
43599
43564
 
43600
43565
  // ../../packages/runner-pi/dist/tool-overrides.js
43601
- import { createBashTool, createReadTool } from "@earendil-works/pi-coding-agent";
43566
+ import { createBashToolDefinition } from "@earendil-works/pi-coding-agent";
43602
43567
 
43603
43568
  // ../../packages/runner-pi/dist/web-tools.js
43604
43569
  var braveProvider = {
@@ -44020,11 +43985,11 @@ function buildWebFetchTool() {
44020
43985
 
44021
43986
  // ../../packages/runner-pi/dist/tool-overrides.js
44022
43987
  function redactSecrets(text, secrets) {
44023
- if (Object.keys(secrets).length === 0)
43988
+ const values = secretValues(secrets).filter((v) => text.includes(v));
43989
+ if (values.length === 0)
44024
43990
  return text;
44025
43991
  let result = text;
44026
43992
  const escapeRegex3 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
44027
- const values = Object.values(secrets).filter((v) => v.length >= 8).filter((v) => !/^\//.test(v) && !/^[A-Za-z]:[/\\]/.test(v)).sort((a, b) => b.length - a.length);
44028
43993
  for (const v of values) {
44029
43994
  const ev = escapeRegex3(v);
44030
43995
  result = result.replace(new RegExp(`^\\S+=.*${ev}.*$\\n?`, "gm"), "");
@@ -44034,19 +43999,61 @@ function redactSecrets(text, secrets) {
44034
43999
  result = result.replace(/\n{3,}/g, "\n\n");
44035
44000
  return result.trim();
44036
44001
  }
44037
- function redactResultContent(result, secrets) {
44038
- if (result?.content && Array.isArray(result.content)) {
44039
- result.content = result.content.map((c) => c.type === "text" && typeof c.text === "string" ? { ...c, text: redactSecrets(c.text, secrets) } : c);
44002
+ function secretValues(secrets) {
44003
+ return Object.values(secrets).filter((v) => v.length >= 8).filter((v) => !/^\//.test(v) && !/^[A-Za-z]:[/\\]/.test(v)).sort((a, b) => b.length - a.length);
44004
+ }
44005
+ function maskSecrets(value, values) {
44006
+ if (typeof value === "string") {
44007
+ let masked = value;
44008
+ for (const v of values)
44009
+ masked = masked.split(v).join("***");
44010
+ return masked;
44011
+ }
44012
+ if (Array.isArray(value)) {
44013
+ const next = value.map((item) => maskSecrets(item, values));
44014
+ return next.some((item, i) => item !== value[i]) ? next : value;
44015
+ }
44016
+ if (value !== null && typeof value === "object") {
44017
+ let changed = false;
44018
+ const next = {};
44019
+ for (const [key, item] of Object.entries(value)) {
44020
+ next[key] = maskSecrets(item, values);
44021
+ if (next[key] !== item)
44022
+ changed = true;
44023
+ }
44024
+ return changed ? next : value;
44040
44025
  }
44026
+ return value;
44041
44027
  }
44028
+ var ENV_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
44029
+ "-u",
44030
+ "--unset",
44031
+ "-C",
44032
+ "--chdir",
44033
+ "-S",
44034
+ "--split-string"
44035
+ ]);
44042
44036
  function isEnvDumpCommand(command) {
44043
44037
  const cmd = command.replace(/\s+/g, " ").trim();
44044
- return /(?:^|[|;&])\s*(?:env|printenv|export\s+-p|declare\s+-x)\b/.test(cmd);
44038
+ if (/(?:^|[|;&])\s*(?:printenv|export\s+-p|declare\s+-x)\b/.test(cmd)) {
44039
+ return true;
44040
+ }
44041
+ for (const match of cmd.matchAll(/(?:^|[|;&])\s*env(?=$|[\s|;&>])([^|;&>]*)/g)) {
44042
+ const words = match[1].trim().split(" ").filter(Boolean);
44043
+ let i = 0;
44044
+ while (i < words.length && (words[i].startsWith("-") || /^[A-Za-z_]\w*=/.test(words[i]))) {
44045
+ i += ENV_OPTIONS_WITH_VALUE.has(words[i]) ? 2 : 1;
44046
+ }
44047
+ if (i >= words.length || isEnvDumpCommand(words.slice(i).join(" "))) {
44048
+ return true;
44049
+ }
44050
+ }
44051
+ return false;
44045
44052
  }
44046
- function buildEnvInjectedBashTool(cwd, extraEnv, opts = {}) {
44053
+ function buildEnvInjectedBashTool(cwd, opts = {}) {
44047
44054
  const safeEnv = opts.systemEnv ?? {};
44048
44055
  const pathPrepend = opts.pathPrepend;
44049
- const bashAgentTool = createBashTool(cwd, {
44056
+ return createBashToolDefinition(cwd, {
44050
44057
  spawnHook: (ctx) => {
44051
44058
  const env = {
44052
44059
  ...ctx.env,
@@ -44059,50 +44066,45 @@ function buildEnvInjectedBashTool(cwd, extraEnv, opts = {}) {
44059
44066
  return { ...ctx, env };
44060
44067
  }
44061
44068
  });
44062
- return {
44063
- name: bashAgentTool.name,
44064
- label: bashAgentTool.label ?? "bash",
44065
- description: bashAgentTool.description,
44066
- // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema from pi internals
44067
- parameters: bashAgentTool.parameters,
44068
- async execute(toolCallId, params, signal, onUpdate) {
44069
- const command = params.command ?? "";
44070
- if (isEnvDumpCommand(command)) {
44071
- return {
44072
- content: [
44073
- {
44074
- type: "text",
44075
- text: "Command blocked: printing or redirecting environment variables is not allowed."
44076
- }
44077
- ],
44078
- details: void 0
44079
- };
44080
- }
44081
- const result = await bashAgentTool.execute(toolCallId, params, signal, onUpdate);
44082
- redactResultContent(result, extraEnv);
44083
- return result;
44084
- }
44085
- };
44086
44069
  }
44087
- function buildSecretRedactingReadTool(cwd, secrets) {
44088
- const readAgentTool = createReadTool(cwd);
44070
+ var ENV_DUMP_BLOCKED_MESSAGE = "Command blocked: printing or redirecting environment variables is not allowed.";
44071
+ function createSecretGuardExtension(secrets) {
44089
44072
  return {
44090
- name: readAgentTool.name,
44091
- label: readAgentTool.label ?? "read",
44092
- description: readAgentTool.description,
44093
- // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema from pi internals
44094
- parameters: readAgentTool.parameters,
44095
- async execute(toolCallId, params, signal, onUpdate) {
44096
- const result = await readAgentTool.execute(toolCallId, params, signal, onUpdate);
44097
- redactResultContent(result, secrets);
44098
- return result;
44073
+ name: "bunny-agent-secret-guard",
44074
+ factory: (pi) => {
44075
+ pi.on("tool_call", (event) => {
44076
+ if (event.toolName === "bash" && typeof event.input.command === "string" && isEnvDumpCommand(event.input.command)) {
44077
+ return { block: true, reason: ENV_DUMP_BLOCKED_MESSAGE };
44078
+ }
44079
+ return void 0;
44080
+ });
44081
+ const values = secretValues(secrets);
44082
+ pi.on("tool_result", (event) => {
44083
+ if (values.length === 0)
44084
+ return void 0;
44085
+ let contentChanged = false;
44086
+ const content = event.content.map((part) => {
44087
+ if (part.type !== "text")
44088
+ return part;
44089
+ const text = redactSecrets(part.text, secrets);
44090
+ if (text === part.text)
44091
+ return part;
44092
+ contentChanged = true;
44093
+ return { ...part, text };
44094
+ });
44095
+ const details = maskSecrets(event.details, values);
44096
+ const structuredContent = maskSecrets(event.structuredContent, values);
44097
+ if (!contentChanged && details === event.details && structuredContent === event.structuredContent) {
44098
+ return void 0;
44099
+ }
44100
+ return { content, details, structuredContent };
44101
+ });
44099
44102
  }
44100
44103
  };
44101
44104
  }
44102
44105
  function buildSecretAwareTools(cwd, secrets, opts = {}) {
44103
44106
  const tools = [
44104
- buildEnvInjectedBashTool(cwd, secrets, opts),
44105
- buildSecretRedactingReadTool(cwd, secrets),
44107
+ buildEnvInjectedBashTool(cwd, opts),
44106
44108
  buildWebFetchTool()
44107
44109
  ];
44108
44110
  if (resolveSearchProvider(secrets)) {
@@ -44136,17 +44138,21 @@ function buildOne2(spec) {
44136
44138
  try {
44137
44139
  response = await executeToolRef2(spec, params, signal);
44138
44140
  } catch (error109) {
44139
- const message = formatTransportError(error109);
44140
- throw new PiToolRefError(`Tool "${spec.name}" transport error: ${message}`, { toolName: spec.name });
44141
+ const { text: message } = await guardToolOutput(`Tool "${spec.name}" transport error: ${formatTransportError(error109)}`);
44142
+ throw new PiToolRefError(message, { toolName: spec.name });
44141
44143
  }
44144
+ const output2 = await guardToolOutput(response.body);
44142
44145
  if (response.status < 200 || response.status >= 300) {
44143
- throw new PiToolRefError(formatToolRuntimeErrorMessage(response), {
44146
+ throw new PiToolRefError(formatToolRuntimeErrorMessage({ ...response, body: output2.text }), {
44144
44147
  toolName: spec.name,
44145
44148
  status: response.status,
44146
- body: response.body
44149
+ body: output2.text
44147
44150
  });
44148
44151
  }
44149
- return okResult(response.body);
44152
+ return {
44153
+ content: [{ type: "text", text: output2.text }],
44154
+ details: output2.outputGuard ? { outputGuard: output2.outputGuard } : void 0
44155
+ };
44150
44156
  }
44151
44157
  };
44152
44158
  }
@@ -44203,12 +44209,6 @@ async function executeModuleTool2(runtime, params, signal) {
44203
44209
  const result = await fn(params, { signal });
44204
44210
  return { status: 200, body: serializeResult2(result) };
44205
44211
  }
44206
- function okResult(text) {
44207
- return {
44208
- content: [{ type: "text", text }],
44209
- details: void 0
44210
- };
44211
- }
44212
44212
  function serializeResult2(result) {
44213
44213
  if (typeof result === "string")
44214
44214
  return result;
@@ -44216,7 +44216,7 @@ function serializeResult2(result) {
44216
44216
  }
44217
44217
 
44218
44218
  // ../../packages/runner-pi/dist/pi-runner.js
44219
- var LOG_PREFIX2 = "[bunny-agent:pi]";
44219
+ var LOG_PREFIX = "[bunny-agent:pi]";
44220
44220
  var DEFAULT_DYNAMIC_MODEL_PROFILE = {
44221
44221
  contextWindow: 128e3,
44222
44222
  maxTokens: 16384,
@@ -44345,7 +44345,7 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
44345
44345
  return;
44346
44346
  try {
44347
44347
  const file3 = join12(debugCwd, "pi-message-stream-debug.json");
44348
- if (reset && existsSync9(file3))
44348
+ if (reset && existsSync8(file3))
44349
44349
  unlinkSync7(file3);
44350
44350
  const type = data !== null && typeof data === "object" ? data.type : void 0;
44351
44351
  let payload = data;
@@ -44359,6 +44359,39 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
44359
44359
  } catch {
44360
44360
  }
44361
44361
  }
44362
+ async function createPiResourceLoader(options) {
44363
+ const { systemPrompt } = options;
44364
+ const defaultSkillDirs = [
44365
+ join12(options.agentDir, "skills"),
44366
+ join12(options.cwd, CONFIG_DIR_NAME, "skills")
44367
+ ].filter((dir) => existsSync8(dir));
44368
+ const loader = new DefaultResourceLoader({
44369
+ cwd: options.cwd,
44370
+ agentDir: options.agentDir,
44371
+ settingsManager: options.settingsManager,
44372
+ noSkills: true,
44373
+ additionalSkillPaths: [...defaultSkillDirs, ...options.skillPaths ?? []],
44374
+ appendSystemPromptOverride: systemPrompt ? (base) => [...base, systemPrompt] : void 0,
44375
+ extensionFactories: options.extensionFactories
44376
+ });
44377
+ await loader.reload();
44378
+ if (options.skillPaths && options.skillPaths.length > 0) {
44379
+ logSkillLoad(options.cwd, options.skillPaths, loader.getSkills());
44380
+ }
44381
+ return loader;
44382
+ }
44383
+ function logSkillLoad(cwd, skillPaths, result) {
44384
+ const lines = [`${LOG_PREFIX} loadSkills cwd=${cwd}`];
44385
+ for (const raw of skillPaths) {
44386
+ const abs = isAbsolute(raw) ? raw : resolve2(cwd, raw);
44387
+ lines.push(` ${raw} -> ${abs} (exists: ${existsSync8(abs) ? "yes" : "no"})`);
44388
+ }
44389
+ lines.push(` loaded skills (${result.skills.length}): ${result.skills.map((s) => s.name).join(", ")}`);
44390
+ for (const d of result.diagnostics) {
44391
+ lines.push(` [${d.type}] ${d.message}${d.path !== void 0 ? ` path=${d.path}` : ""}`);
44392
+ }
44393
+ console.error(lines.join("\n"));
44394
+ }
44362
44395
  function createPiRunner(options = {}) {
44363
44396
  const modelSpec = options.model;
44364
44397
  if (modelSpec == null || modelSpec.trim() === "") {
@@ -44372,6 +44405,8 @@ function createPiRunner(options = {}) {
44372
44405
  const mcpExtension = shouldEnableMcp(options.mcpConfig, options.allowedTools) ? createMcpExtension(options.mcpConfig) : void 0;
44373
44406
  return {
44374
44407
  async *run(userInput) {
44408
+ const agentDir = getAgentDir();
44409
+ const settingsManager = SettingsManager.create(cwd, agentDir);
44375
44410
  const modelRuntime = await ModelRuntime.create({
44376
44411
  modelsPath: null,
44377
44412
  allowModelNetwork: false
@@ -44418,7 +44453,7 @@ function createPiRunner(options = {}) {
44418
44453
  const sessionManager = await (async () => {
44419
44454
  if (forkFrom) {
44420
44455
  const sourcePath = resolveSessionPathById(cwd, forkFrom);
44421
- console.error(`${LOG_PREFIX2} fork: sourceId=${forkFrom} sourcePath=${sourcePath ?? "(not found)"}`);
44456
+ console.error(`${LOG_PREFIX} fork: sourceId=${forkFrom} sourcePath=${sourcePath ?? "(not found)"}`);
44422
44457
  if (!sourcePath) {
44423
44458
  throw new Error(`Pi runner: forkFrom source session not found: ${forkFrom}`);
44424
44459
  }
@@ -44426,11 +44461,11 @@ function createPiRunner(options = {}) {
44426
44461
  }
44427
44462
  if (resume) {
44428
44463
  const sessionPath2 = resolveSessionPathById(cwd, resume);
44429
- console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
44464
+ console.error(`${LOG_PREFIX} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
44430
44465
  if (sessionPath2) {
44431
44466
  if (isSessionFileTooLarge(sessionPath2)) {
44432
44467
  const context = extractSessionContext(sessionPath2);
44433
- console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
44468
+ console.error(`${LOG_PREFIX} session file too large, starting fresh${context ? " (with context)" : ""}`);
44434
44469
  const newMgr = SessionManager2.create(cwd);
44435
44470
  if (context) {
44436
44471
  const firstId = newMgr.getEntries()[0]?.id ?? "";
@@ -44444,24 +44479,14 @@ function createPiRunner(options = {}) {
44444
44479
  }
44445
44480
  return SessionManager2.create(cwd);
44446
44481
  })();
44447
- const resourceLoader = options.skillPaths || options.systemPrompt || mcpExtension ? new BunnyAgentResourceLoader({
44448
- cwd,
44449
- skillPaths: options.skillPaths,
44450
- appendSystemPrompt: options.systemPrompt,
44451
- extensionFactories: mcpExtension ? [mcpExtension] : void 0
44452
- }) : void 0;
44453
- if (options.skillPaths && options.skillPaths.length > 0) {
44454
- console.error(`${LOG_PREFIX2} runner: cwd=${cwd} skillPaths=${JSON.stringify(options.skillPaths)}`);
44455
- }
44456
- if (resourceLoader) {
44457
- await resourceLoader.reload();
44458
- }
44459
44482
  const applyPatchShimDir = ensureApplyPatchShim();
44460
44483
  const customTools = options.env && Object.keys(options.env).length > 0 ? buildSecretAwareTools(cwd, options.env, {
44461
44484
  systemEnv: options.systemEnv,
44462
44485
  pathPrepend: applyPatchShimDir
44463
44486
  }) : applyPatchShimDir ? [
44464
- buildEnvInjectedBashTool(cwd, {}, { pathPrepend: applyPatchShimDir })
44487
+ buildEnvInjectedBashTool(cwd, {
44488
+ pathPrepend: applyPatchShimDir
44489
+ })
44465
44490
  ] : [];
44466
44491
  if (provider === "openai") {
44467
44492
  customTools.push(buildApplyPatchTool(cwd));
@@ -44482,29 +44507,34 @@ function createPiRunner(options = {}) {
44482
44507
  cwd,
44483
44508
  fallbackSignal: options.abortController?.signal
44484
44509
  };
44485
- let regularTools = [
44486
- ...applyAllowedTools(customTools, allowedTools),
44487
- ...toolRefDefinitions
44488
- ];
44489
- if (!bypassApproval) {
44490
- const overriddenNames = new Set(regularTools.map((tool) => tool.name));
44491
- const builtinTools = applyAllowedTools(createCodingTools(cwd), allowedTools).filter((tool) => !overriddenNames.has(tool.name));
44492
- regularTools = [...regularTools, ...builtinTools];
44493
- }
44494
- const gatedTools = gateToolsForApproval(regularTools, bypassApproval, approvalGate);
44495
44510
  const askUserQuestionEnabled = allowedTools === void 0 || allowedTools.includes(ASK_USER_QUESTION_TOOL_NAME);
44496
44511
  const previousModel = sessionManager.buildSessionContext?.().model;
44497
44512
  const thinkingLevel = resolveInitialThinkingLevel(options.effort, previousModel, model);
44513
+ const resourceLoader = await createPiResourceLoader({
44514
+ cwd,
44515
+ agentDir,
44516
+ settingsManager,
44517
+ skillPaths: options.skillPaths,
44518
+ systemPrompt: options.systemPrompt,
44519
+ extensionFactories: [
44520
+ createSecretGuardExtension(options.env ?? {}),
44521
+ ...bypassApproval ? [] : [createToolApprovalExtension(approvalGate)],
44522
+ ...mcpExtension ? [mcpExtension] : []
44523
+ ]
44524
+ });
44498
44525
  const { session } = await createAgentSession({
44499
44526
  cwd,
44527
+ agentDir,
44500
44528
  model,
44501
44529
  sessionManager,
44530
+ settingsManager,
44502
44531
  modelRuntime,
44503
44532
  resourceLoader,
44504
44533
  thinkingLevel,
44505
44534
  tools: allowedTools,
44506
44535
  customTools: [
44507
- ...gatedTools,
44536
+ ...applyAllowedTools(customTools, allowedTools),
44537
+ ...toolRefDefinitions,
44508
44538
  ...askUserQuestionEnabled ? [
44509
44539
  buildAskUserQuestionTool({
44510
44540
  ...approvalGate,
@@ -44637,7 +44667,7 @@ function createPiRunner(options = {}) {
44637
44667
  }
44638
44668
 
44639
44669
  // ../../packages/runner-harness/dist/session.js
44640
- import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync9 } from "node:fs";
44670
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync9 } from "node:fs";
44641
44671
  import { join as join13 } from "node:path";
44642
44672
  var DIR = ".bunny-agent";
44643
44673
  var FILE = "session-id";
@@ -44647,7 +44677,7 @@ function sessionPath(cwd) {
44647
44677
  function readSessionId(cwd) {
44648
44678
  try {
44649
44679
  const p = sessionPath(cwd);
44650
- if (!existsSync10(p))
44680
+ if (!existsSync9(p))
44651
44681
  return void 0;
44652
44682
  return readFileSync6(p, "utf8").trim() || void 0;
44653
44683
  } catch {
@@ -44663,21 +44693,21 @@ function writeSessionId(cwd, id) {
44663
44693
  }
44664
44694
 
44665
44695
  // ../../packages/runner-harness/dist/skills.js
44666
- import { existsSync as existsSync11, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
44667
- import { homedir as homedir2 } from "node:os";
44696
+ import { existsSync as existsSync10, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
44697
+ import { homedir } from "node:os";
44668
44698
  import { join as join14 } from "node:path";
44669
44699
  function discoverSkillPaths(cwd) {
44670
44700
  const paths = [];
44671
44701
  for (const base of [
44672
44702
  join14(cwd, "skills"),
44673
- join14(homedir2(), ".bunny-agent", "skills")
44703
+ join14(homedir(), ".bunny-agent", "skills")
44674
44704
  ]) {
44675
- if (!existsSync11(base))
44705
+ if (!existsSync10(base))
44676
44706
  continue;
44677
44707
  try {
44678
44708
  for (const entry of readdirSync2(base)) {
44679
44709
  const full = join14(base, entry);
44680
- if (statSync2(full).isDirectory() && existsSync11(join14(full, "SKILL.md"))) {
44710
+ if (statSync2(full).isDirectory() && existsSync10(join14(full, "SKILL.md"))) {
44681
44711
  paths.push(full);
44682
44712
  }
44683
44713
  }
@@ -45211,7 +45241,7 @@ async function runAcpAgent(options) {
45211
45241
  import { execSync } from "node:child_process";
45212
45242
  import {
45213
45243
  copyFileSync,
45214
- existsSync as existsSync12,
45244
+ existsSync as existsSync11,
45215
45245
  mkdirSync as mkdirSync9,
45216
45246
  readdirSync as readdirSync3,
45217
45247
  readFileSync as readFileSync7,
@@ -45239,7 +45269,7 @@ function getShippedDockerfile() {
45239
45269
  resolve3(process.cwd(), "docker", "bunny-agent-claude", "Dockerfile")
45240
45270
  ];
45241
45271
  for (const p of candidates) {
45242
- if (existsSync12(p)) return p;
45272
+ if (existsSync11(p)) return p;
45243
45273
  }
45244
45274
  console.error(
45245
45275
  `\u274C Dockerfile not found. Searched:
@@ -45260,7 +45290,7 @@ function ensureDocker() {
45260
45290
  }
45261
45291
  function resolveTemplatePath(template) {
45262
45292
  const abs = resolve3(process.cwd(), template);
45263
- if (!existsSync12(abs)) {
45293
+ if (!existsSync11(abs)) {
45264
45294
  console.error(`\u274C Template directory not found: ${abs}`);
45265
45295
  process.exit(1);
45266
45296
  }
@@ -45297,16 +45327,16 @@ async function buildImage(opts) {
45297
45327
  const destDir = join15(buildContext, "templates", templateName);
45298
45328
  mkdirSync9(destDir, { recursive: true });
45299
45329
  const claudeMd = join15(templatePath, "CLAUDE.md");
45300
- if (existsSync12(claudeMd))
45330
+ if (existsSync11(claudeMd))
45301
45331
  copyFileSync(claudeMd, join15(destDir, "CLAUDE.md"));
45302
45332
  const claudeDir = join15(templatePath, ".claude");
45303
- if (existsSync12(claudeDir)) copyDirSync(claudeDir, join15(destDir, ".claude"));
45333
+ if (existsSync11(claudeDir)) copyDirSync(claudeDir, join15(destDir, ".claude"));
45304
45334
  let copyLines = "\n# Template files\nRUN mkdir -p /opt/bunny-agent/templates";
45305
- if (existsSync12(join15(destDir, "CLAUDE.md"))) {
45335
+ if (existsSync11(join15(destDir, "CLAUDE.md"))) {
45306
45336
  copyLines += `
45307
45337
  COPY templates/${templateName}/CLAUDE.md /opt/bunny-agent/templates/CLAUDE.md`;
45308
45338
  }
45309
- if (existsSync12(join15(destDir, ".claude"))) {
45339
+ if (existsSync11(join15(destDir, ".claude"))) {
45310
45340
  copyLines += `
45311
45341
  COPY templates/${templateName}/.claude /opt/bunny-agent/templates/.claude`;
45312
45342
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunny-agent/runner-cli",
3
- "version": "0.9.62",
3
+ "version": "0.9.63-beta.2",
4
4
  "description": "BunnyAgent Runner CLI - Like gemini-cli or claude-code, runs in your local terminal with AI SDK UI streaming",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,15 +42,15 @@
42
42
  "dependencies": {
43
43
  "@anthropic-ai/claude-agent-sdk": "0.3.215",
44
44
  "@anthropic-ai/sdk": "0.112.3",
45
- "@earendil-works/pi-agent-core": "1.2.0",
46
- "@earendil-works/pi-ai": "1.2.0",
47
- "@earendil-works/pi-coding-agent": "1.2.0",
48
- "@earendil-works/pi-tui": "1.2.0",
45
+ "@earendil-works/pi-agent-core": "1.3.0",
46
+ "@earendil-works/pi-ai": "1.3.0",
47
+ "@earendil-works/pi-coding-agent": "1.3.0",
48
+ "@earendil-works/pi-tui": "1.3.0",
49
49
  "@github/copilot-sdk": "1.0.7",
50
50
  "@openai/codex-sdk": "^0.144.6",
51
51
  "dotenv": "^17.3.1",
52
52
  "jiti": "2.7.0",
53
- "pi-mcp-adapter": "5.3.0",
53
+ "pi-mcp-adapter": "5.3.1",
54
54
  "typebox": "1.1.38",
55
55
  "zod": "^4.0.0"
56
56
  },
@@ -60,15 +60,15 @@
60
60
  "typescript": "^5.3.0",
61
61
  "vitest": "^1.6.1",
62
62
  "@bunny-agent/apply-patch": "0.1.0",
63
- "@bunny-agent/runner-claude": "0.6.2",
64
- "@bunny-agent/manager": "0.9.62",
65
63
  "@bunny-agent/runner-codex": "0.6.2",
64
+ "@bunny-agent/runner-claude": "0.6.2",
66
65
  "@bunny-agent/runner-gemini": "0.6.2",
67
66
  "@bunny-agent/runner-harness": "0.1.1-beta.0",
68
67
  "@bunny-agent/runner-copilot": "0.1.0",
69
- "@bunny-agent/server-acp": "0.1.0",
68
+ "@bunny-agent/runner-opencode": "0.6.2",
70
69
  "@bunny-agent/runner-pi": "0.6.4-beta.0",
71
- "@bunny-agent/runner-opencode": "0.6.2"
70
+ "@bunny-agent/manager": "0.9.63-beta.2",
71
+ "@bunny-agent/server-acp": "0.1.0"
72
72
  },
73
73
  "scripts": {
74
74
  "build": "tsc && pnpm bundle",