@bunny-agent/runner-cli 0.9.50-beta.4 → 0.9.50-beta.6

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 +200 -135
  2. package/package.json +5 -5
package/dist/bundle.mjs CHANGED
@@ -210,15 +210,39 @@ var BUNNY_AGENT_SYSTEM_PROMPT = [
210
210
  "If the answer is a number, give only the number. If it's a name, give the exact name as it appears in the source."
211
211
  ].join("\n");
212
212
 
213
+ // ../../packages/runner-harness/dist/prompt.js
214
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
215
+ import { dirname as dirname2, join as join2 } from "node:path";
216
+ var PROMPT_FILES = ["CLAUDE.md", "AGENTS.md"];
217
+ function loadSystemPrompt(cwd) {
218
+ let dir = cwd;
219
+ for (let i = 0; i < 5; i++) {
220
+ for (const name of PROMPT_FILES) {
221
+ const p = join2(dir, name);
222
+ if (existsSync2(p)) {
223
+ try {
224
+ return readFileSync2(p, "utf8").trim() || void 0;
225
+ } catch {
226
+ }
227
+ }
228
+ }
229
+ const parent = dirname2(dir);
230
+ if (parent === dir)
231
+ break;
232
+ dir = parent;
233
+ }
234
+ return void 0;
235
+ }
236
+
213
237
  // ../../packages/runner-claude/dist/ai-sdk-stream.js
214
- import { appendFileSync, existsSync as existsSync2, unlinkSync } from "node:fs";
215
- import { join as join2 } from "node:path";
238
+ import { appendFileSync, existsSync as existsSync3, unlinkSync } from "node:fs";
239
+ import { join as join3 } from "node:path";
216
240
  function trace(data, reset = false) {
217
241
  if (process.env.DEBUG !== "true")
218
242
  return;
219
243
  try {
220
- const file = join2(process.cwd(), "claude-message-stream-debug.json");
221
- if (reset && existsSync2(file))
244
+ const file = join3(process.cwd(), "claude-message-stream-debug.json");
245
+ if (reset && existsSync3(file))
222
246
  unlinkSync(file);
223
247
  const entry = {
224
248
  _t: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1276,107 +1300,14 @@ function createOpenCodeRunner(options = {}) {
1276
1300
  };
1277
1301
  }
1278
1302
 
1279
- // ../../packages/runner-pi/dist/fork.js
1280
- import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
1281
-
1282
- // ../../packages/runner-pi/dist/session-utils.js
1283
- import { closeSync, fstatSync, openSync, readdirSync as readdirSync2, readSync, statSync as statSync2 } from "node:fs";
1284
- import { join as join4 } from "node:path";
1285
- import { SessionManager } from "@earendil-works/pi-coding-agent";
1286
- var MAX_SESSION_FILE_BYTES = Number(process.env.SANDAGENT_MAX_SESSION_BYTES) || 10 * 1024 * 1024;
1287
- function resolveSessionPathById(cwd, sessionIdOrPath) {
1288
- if (sessionIdOrPath.includes("/"))
1289
- return sessionIdOrPath;
1290
- const tempMgr = SessionManager.create(cwd);
1291
- const sessionsDir = tempMgr.getSessionDir();
1292
- try {
1293
- const suffix = `_${sessionIdOrPath}.jsonl`;
1294
- const match = readdirSync2(sessionsDir).find((f) => f.endsWith(suffix));
1295
- return match ? join4(sessionsDir, match) : void 0;
1296
- } catch {
1297
- return void 0;
1298
- }
1299
- }
1300
- function isSessionFileTooLarge(sessionPath2) {
1301
- try {
1302
- return statSync2(sessionPath2).size > MAX_SESSION_FILE_BYTES;
1303
- } catch {
1304
- return false;
1305
- }
1306
- }
1307
- function readTailEntries(sessionPath2, tailBytes = 1024 * 1024) {
1308
- let fd;
1309
- try {
1310
- fd = openSync(sessionPath2, "r");
1311
- } catch {
1312
- return [];
1313
- }
1314
- try {
1315
- const fileSize = fstatSync(fd).size;
1316
- const readStart = Math.max(0, fileSize - tailBytes);
1317
- const readLen = fileSize - readStart;
1318
- const buf = Buffer.alloc(readLen);
1319
- readSync(fd, buf, 0, readLen, readStart);
1320
- const tail = buf.toString("utf8");
1321
- const entries = [];
1322
- for (const line of tail.split("\n")) {
1323
- const trimmed = line.trim();
1324
- if (!trimmed)
1325
- continue;
1326
- try {
1327
- entries.push(JSON.parse(trimmed));
1328
- } catch {
1329
- }
1330
- }
1331
- return entries;
1332
- } finally {
1333
- closeSync(fd);
1334
- }
1335
- }
1336
- function extractSessionContext(sessionPath2) {
1337
- const entries = readTailEntries(sessionPath2);
1338
- if (entries.length === 0)
1339
- return void 0;
1340
- for (let i = entries.length - 1; i >= 0; i--) {
1341
- const e = entries[i];
1342
- if (e.type === "compaction" && typeof e.summary === "string") {
1343
- return e.summary;
1344
- }
1345
- }
1346
- const recentMessages = [];
1347
- const MAX_MESSAGES = 6;
1348
- for (let i = entries.length - 1; i >= 0 && recentMessages.length < MAX_MESSAGES; i--) {
1349
- const e = entries[i];
1350
- if (e.type !== "message")
1351
- continue;
1352
- const msg = e.message;
1353
- if (!msg)
1354
- continue;
1355
- if (msg.role !== "user" && msg.role !== "assistant")
1356
- continue;
1357
- let text = "";
1358
- if (typeof msg.content === "string") {
1359
- text = msg.content;
1360
- } else if (Array.isArray(msg.content)) {
1361
- text = msg.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
1362
- }
1363
- if (text) {
1364
- recentMessages.unshift(`[${msg.role}]: ${text}`);
1365
- }
1366
- }
1367
- if (recentMessages.length === 0)
1368
- return void 0;
1369
- return "## Previous Session Context (auto-extracted)\n\nThe following is the tail of the previous conversation:\n\n" + recentMessages.join("\n\n");
1370
- }
1371
-
1372
1303
  // ../../packages/runner-pi/dist/pi-runner.js
1373
- import { appendFileSync as appendFileSync2, existsSync as existsSync4, unlinkSync as unlinkSync3 } from "node:fs";
1374
- import { join as join7 } from "node:path";
1304
+ import { appendFileSync as appendFileSync2, existsSync as existsSync5, unlinkSync as unlinkSync3 } from "node:fs";
1305
+ import { join as join8 } from "node:path";
1375
1306
  import { getModel } from "@earendil-works/pi-ai";
1376
- import { AuthStorage, createAgentSession, ModelRegistry, SessionManager as SessionManager3 } from "@earendil-works/pi-coding-agent";
1307
+ import { AuthStorage, createAgentSession, ModelRegistry, SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
1377
1308
 
1378
1309
  // ../../packages/runner-pi/dist/bunny-agent-resource-loader.js
1379
- import { existsSync as existsSync3 } from "node:fs";
1310
+ import { existsSync as existsSync4 } from "node:fs";
1380
1311
  import { homedir } from "node:os";
1381
1312
  import { isAbsolute, join as join5, resolve as resolve2 } from "node:path";
1382
1313
  import { DefaultResourceLoader, loadSkills } from "@earendil-works/pi-coding-agent";
@@ -1390,7 +1321,7 @@ function logSkillLoad(cwd, agentDir, skillPaths, result) {
1390
1321
  ];
1391
1322
  for (const raw of skillPaths) {
1392
1323
  const abs = isAbsolute(raw) ? raw : resolve2(cwd, raw);
1393
- lines.push(` ${raw} -> ${abs} (exists: ${existsSync3(abs) ? "yes" : "no"})`);
1324
+ lines.push(` ${raw} -> ${abs} (exists: ${existsSync4(abs) ? "yes" : "no"})`);
1394
1325
  }
1395
1326
  lines.push(` loaded skills: ${result.skills.length}`);
1396
1327
  if (result.skills.length > 0) {
@@ -1466,7 +1397,7 @@ var BunnyAgentResourceLoader = class {
1466
1397
 
1467
1398
  // ../../packages/runner-pi/dist/image-tools.js
1468
1399
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
1469
- import { dirname as dirname2, extname, join as join6 } from "node:path";
1400
+ import { dirname as dirname3, extname, join as join6 } from "node:path";
1470
1401
  var generateImageSchema = {
1471
1402
  type: "object",
1472
1403
  properties: {
@@ -1699,7 +1630,7 @@ async function saveImageItem(item, filePath, apiKey) {
1699
1630
  const b64 = await resolveB64(item, apiKey);
1700
1631
  if (!b64)
1701
1632
  return void 0;
1702
- mkdirSync2(dirname2(filePath), { recursive: true });
1633
+ mkdirSync2(dirname3(filePath), { recursive: true });
1703
1634
  writeFileSync3(filePath, Buffer.from(b64, "base64"));
1704
1635
  return filePath;
1705
1636
  }
@@ -1997,6 +1928,96 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
1997
1928
  };
1998
1929
  }
1999
1930
 
1931
+ // ../../packages/runner-pi/dist/session-utils.js
1932
+ import { closeSync, fstatSync, openSync, readdirSync as readdirSync2, readSync, statSync as statSync2 } from "node:fs";
1933
+ import { join as join7 } from "node:path";
1934
+ import { SessionManager } from "@earendil-works/pi-coding-agent";
1935
+ var MAX_SESSION_FILE_BYTES = Number(process.env.SANDAGENT_MAX_SESSION_BYTES) || 10 * 1024 * 1024;
1936
+ function resolveSessionPathById(cwd, sessionIdOrPath) {
1937
+ if (sessionIdOrPath.includes("/"))
1938
+ return sessionIdOrPath;
1939
+ const tempMgr = SessionManager.create(cwd);
1940
+ const sessionsDir = tempMgr.getSessionDir();
1941
+ try {
1942
+ const suffix = `_${sessionIdOrPath}.jsonl`;
1943
+ const match = readdirSync2(sessionsDir).find((f) => f.endsWith(suffix));
1944
+ return match ? join7(sessionsDir, match) : void 0;
1945
+ } catch {
1946
+ return void 0;
1947
+ }
1948
+ }
1949
+ function isSessionFileTooLarge(sessionPath2) {
1950
+ try {
1951
+ return statSync2(sessionPath2).size > MAX_SESSION_FILE_BYTES;
1952
+ } catch {
1953
+ return false;
1954
+ }
1955
+ }
1956
+ function readTailEntries(sessionPath2, tailBytes = 1024 * 1024) {
1957
+ let fd;
1958
+ try {
1959
+ fd = openSync(sessionPath2, "r");
1960
+ } catch {
1961
+ return [];
1962
+ }
1963
+ try {
1964
+ const fileSize = fstatSync(fd).size;
1965
+ const readStart = Math.max(0, fileSize - tailBytes);
1966
+ const readLen = fileSize - readStart;
1967
+ const buf = Buffer.alloc(readLen);
1968
+ readSync(fd, buf, 0, readLen, readStart);
1969
+ const tail = buf.toString("utf8");
1970
+ const entries = [];
1971
+ for (const line of tail.split("\n")) {
1972
+ const trimmed = line.trim();
1973
+ if (!trimmed)
1974
+ continue;
1975
+ try {
1976
+ entries.push(JSON.parse(trimmed));
1977
+ } catch {
1978
+ }
1979
+ }
1980
+ return entries;
1981
+ } finally {
1982
+ closeSync(fd);
1983
+ }
1984
+ }
1985
+ function extractSessionContext(sessionPath2) {
1986
+ const entries = readTailEntries(sessionPath2);
1987
+ if (entries.length === 0)
1988
+ return void 0;
1989
+ for (let i = entries.length - 1; i >= 0; i--) {
1990
+ const e = entries[i];
1991
+ if (e.type === "compaction" && typeof e.summary === "string") {
1992
+ return e.summary;
1993
+ }
1994
+ }
1995
+ const recentMessages = [];
1996
+ const MAX_MESSAGES = 6;
1997
+ for (let i = entries.length - 1; i >= 0 && recentMessages.length < MAX_MESSAGES; i--) {
1998
+ const e = entries[i];
1999
+ if (e.type !== "message")
2000
+ continue;
2001
+ const msg = e.message;
2002
+ if (!msg)
2003
+ continue;
2004
+ if (msg.role !== "user" && msg.role !== "assistant")
2005
+ continue;
2006
+ let text = "";
2007
+ if (typeof msg.content === "string") {
2008
+ text = msg.content;
2009
+ } else if (Array.isArray(msg.content)) {
2010
+ text = msg.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
2011
+ }
2012
+ if (text) {
2013
+ recentMessages.unshift(`[${msg.role}]: ${text}`);
2014
+ }
2015
+ }
2016
+ if (recentMessages.length === 0)
2017
+ return void 0;
2018
+ return "## Previous Session Context (auto-extracted)\n\nThe following is the tail of the previous conversation:\n\n" + recentMessages.join("\n\n");
2019
+ }
2020
+
2000
2021
  // ../../packages/runner-pi/dist/usage-metadata.js
2001
2022
  function usageToMessageMetadata(usage) {
2002
2023
  return {
@@ -5328,12 +5349,79 @@ function serializeResult(result) {
5328
5349
 
5329
5350
  // ../../packages/runner-pi/dist/pi-runner.js
5330
5351
  var LOG_PREFIX2 = "[bunny-agent:pi]";
5352
+ var LLM_THOUGHT_SIGNATURE_SEPARATOR = "__thought__";
5331
5353
  function applyAllowedTools(tools, allowedTools) {
5332
5354
  if (!allowedTools)
5333
5355
  return tools;
5334
5356
  const allowed = new Set(allowedTools);
5335
5357
  return tools.filter((tool) => allowed.has(tool.name));
5336
5358
  }
5359
+ function shouldStripLLMThoughtSignaturesForModel(model) {
5360
+ const id = (model.id ?? "").toLowerCase();
5361
+ return !id.includes("gemini");
5362
+ }
5363
+ function stripLLMThoughtSignatureFromId(id) {
5364
+ const separatorIndex = id.indexOf(LLM_THOUGHT_SIGNATURE_SEPARATOR);
5365
+ if (separatorIndex === -1)
5366
+ return id;
5367
+ return id.slice(0, separatorIndex);
5368
+ }
5369
+ function stripLLMThoughtSignaturesFromSessionManager(sessionManager, model) {
5370
+ if (!shouldStripLLMThoughtSignaturesForModel(model))
5371
+ return;
5372
+ const manager = sessionManager;
5373
+ const entries = manager.getEntries?.();
5374
+ if (Array.isArray(entries)) {
5375
+ for (const entry of entries) {
5376
+ if (entry == null || typeof entry !== "object")
5377
+ continue;
5378
+ const message = entry.message;
5379
+ if (entry.type === "message") {
5380
+ stripLLMThoughtSignaturesFromMessage(message);
5381
+ }
5382
+ }
5383
+ return;
5384
+ }
5385
+ const context = sessionManager.buildSessionContext?.();
5386
+ const messages = context?.messages;
5387
+ if (!Array.isArray(messages))
5388
+ return;
5389
+ for (const message of messages) {
5390
+ stripLLMThoughtSignaturesFromMessage(message);
5391
+ }
5392
+ }
5393
+ function stripLLMThoughtSignaturesFromMessage(message) {
5394
+ if (message == null || typeof message !== "object")
5395
+ return;
5396
+ const msg = message;
5397
+ if (typeof msg.toolCallId === "string") {
5398
+ msg.toolCallId = stripLLMThoughtSignatureFromId(msg.toolCallId);
5399
+ }
5400
+ if (typeof msg.tool_call_id === "string") {
5401
+ msg.tool_call_id = stripLLMThoughtSignatureFromId(msg.tool_call_id);
5402
+ }
5403
+ if (!Array.isArray(msg.content))
5404
+ return;
5405
+ for (const block of msg.content) {
5406
+ if (block == null || typeof block !== "object")
5407
+ continue;
5408
+ const contentBlock = block;
5409
+ if (contentBlock.type !== "toolCall")
5410
+ continue;
5411
+ if (typeof contentBlock.id === "string") {
5412
+ contentBlock.id = stripLLMThoughtSignatureFromId(contentBlock.id);
5413
+ }
5414
+ if (typeof contentBlock.toolCallId === "string") {
5415
+ contentBlock.toolCallId = stripLLMThoughtSignatureFromId(contentBlock.toolCallId);
5416
+ }
5417
+ if (typeof contentBlock.tool_call_id === "string") {
5418
+ contentBlock.tool_call_id = stripLLMThoughtSignatureFromId(contentBlock.tool_call_id);
5419
+ }
5420
+ if (typeof contentBlock.call_id === "string") {
5421
+ contentBlock.call_id = stripLLMThoughtSignatureFromId(contentBlock.call_id);
5422
+ }
5423
+ }
5424
+ }
5337
5425
  function parseModelSpec(model) {
5338
5426
  const trimmed = model.trim();
5339
5427
  const separator = trimmed.indexOf(":");
@@ -5388,8 +5476,8 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
5388
5476
  if (!enabled)
5389
5477
  return;
5390
5478
  try {
5391
- const file = join7(debugCwd, "pi-message-stream-debug.json");
5392
- if (reset && existsSync4(file))
5479
+ const file = join8(debugCwd, "pi-message-stream-debug.json");
5480
+ if (reset && existsSync5(file))
5393
5481
  unlinkSync3(file);
5394
5482
  const type = data !== null && typeof data === "object" ? data.type : void 0;
5395
5483
  let payload = data;
@@ -5461,7 +5549,7 @@ function createPiRunner(options = {}) {
5461
5549
  if (!sourcePath) {
5462
5550
  throw new Error(`Pi runner: forkFrom source session not found: ${forkFrom}`);
5463
5551
  }
5464
- return SessionManager3.forkFrom(sourcePath, cwd);
5552
+ return SessionManager2.forkFrom(sourcePath, cwd);
5465
5553
  }
5466
5554
  if (resume) {
5467
5555
  const sessionPath2 = resolveSessionPathById(cwd, resume);
@@ -5470,19 +5558,20 @@ function createPiRunner(options = {}) {
5470
5558
  if (isSessionFileTooLarge(sessionPath2)) {
5471
5559
  const context = extractSessionContext(sessionPath2);
5472
5560
  console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
5473
- const newMgr = SessionManager3.create(cwd);
5561
+ const newMgr = SessionManager2.create(cwd);
5474
5562
  if (context) {
5475
5563
  const firstId = newMgr.getEntries()[0]?.id ?? "";
5476
5564
  newMgr.appendCompaction(context, firstId, 0);
5477
5565
  }
5478
5566
  return newMgr;
5479
5567
  }
5480
- return SessionManager3.open(sessionPath2);
5568
+ return SessionManager2.open(sessionPath2);
5481
5569
  }
5482
- return SessionManager3.create(cwd);
5570
+ return SessionManager2.create(cwd);
5483
5571
  }
5484
- return SessionManager3.create(cwd);
5572
+ return SessionManager2.create(cwd);
5485
5573
  })();
5574
+ stripLLMThoughtSignaturesFromSessionManager(sessionManager, model);
5486
5575
  const resourceLoader = options.skillPaths ? new BunnyAgentResourceLoader({
5487
5576
  cwd,
5488
5577
  skillPaths: options.skillPaths,
@@ -5610,30 +5699,6 @@ function createPiRunner(options = {}) {
5610
5699
  };
5611
5700
  }
5612
5701
 
5613
- // ../../packages/runner-harness/dist/prompt.js
5614
- import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
5615
- import { dirname as dirname3, join as join8 } from "node:path";
5616
- var PROMPT_FILES = ["CLAUDE.md", "AGENTS.md"];
5617
- function loadSystemPrompt(cwd) {
5618
- let dir = cwd;
5619
- for (let i = 0; i < 5; i++) {
5620
- for (const name of PROMPT_FILES) {
5621
- const p = join8(dir, name);
5622
- if (existsSync5(p)) {
5623
- try {
5624
- return readFileSync2(p, "utf8").trim() || void 0;
5625
- } catch {
5626
- }
5627
- }
5628
- }
5629
- const parent = dirname3(dir);
5630
- if (parent === dir)
5631
- break;
5632
- dir = parent;
5633
- }
5634
- return void 0;
5635
- }
5636
-
5637
5702
  // ../../packages/runner-harness/dist/session.js
5638
5703
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
5639
5704
  import { join as join9 } from "node:path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunny-agent/runner-cli",
3
- "version": "0.9.50-beta.4",
3
+ "version": "0.9.50-beta.6",
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": {
@@ -54,11 +54,11 @@
54
54
  "typescript": "^5.3.0",
55
55
  "vitest": "^1.6.1",
56
56
  "@bunny-agent/runner-claude": "0.6.2",
57
- "@bunny-agent/runner-harness": "0.1.1-beta.0",
58
- "@bunny-agent/runner-gemini": "0.6.2",
59
- "@bunny-agent/runner-opencode": "0.6.2",
60
57
  "@bunny-agent/runner-codex": "0.6.2",
61
- "@bunny-agent/runner-pi": "0.6.4-beta.0"
58
+ "@bunny-agent/runner-opencode": "0.6.2",
59
+ "@bunny-agent/runner-pi": "0.6.4-beta.0",
60
+ "@bunny-agent/runner-gemini": "0.6.2",
61
+ "@bunny-agent/runner-harness": "0.1.1-beta.0"
62
62
  },
63
63
  "scripts": {
64
64
  "build": "tsc && pnpm bundle",