@openacp/cli 2026.328.2 → 2026.330.3

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 (86) hide show
  1. package/dist/{adapter-HGJENQCN.js → adapter-AWSI4GML.js} +4 -4
  2. package/dist/api-server-5VNYFWJE.js +7 -0
  3. package/dist/{api-server-WFB5K6FP.js → api-server-JLBDKCU4.js} +2 -2
  4. package/dist/{chunk-5TCXYDLR.js → chunk-237WYH6H.js} +26 -3
  5. package/dist/chunk-237WYH6H.js.map +1 -0
  6. package/dist/{chunk-E2SLHZAC.js → chunk-2HEFALTZ.js} +6 -6
  7. package/dist/{chunk-I53NEV3S.js → chunk-5WGVYX3C.js} +13 -3
  8. package/dist/chunk-5WGVYX3C.js.map +1 -0
  9. package/dist/{chunk-IXMIC4GQ.js → chunk-BTJHGSLM.js} +2 -2
  10. package/dist/{chunk-43JVXFYP.js → chunk-GEOXPGCO.js} +2 -2
  11. package/dist/{chunk-JUFN4XMB.js → chunk-KDU3ZEWT.js} +2 -2
  12. package/dist/{chunk-QWP76EBW.js → chunk-MITTQMGZ.js} +16 -9
  13. package/dist/chunk-MITTQMGZ.js.map +1 -0
  14. package/dist/{chunk-QBEQJFGL.js → chunk-MPGEHTGE.js} +3 -3
  15. package/dist/{chunk-4B6PCWQP.js → chunk-PA6MNBG4.js} +6 -2
  16. package/dist/chunk-PA6MNBG4.js.map +1 -0
  17. package/dist/{chunk-VD3QSMVY.js → chunk-QWVHCTCA.js} +2 -2
  18. package/dist/{chunk-NT6FYV27.js → chunk-TMVTSWVH.js} +2 -2
  19. package/dist/{chunk-6VR4GWOO.js → chunk-UCIZM5SW.js} +247 -70
  20. package/dist/chunk-UCIZM5SW.js.map +1 -0
  21. package/dist/chunk-UWH7KIAA.js +701 -0
  22. package/dist/chunk-UWH7KIAA.js.map +1 -0
  23. package/dist/{chunk-JOMDPFQ2.js → chunk-W4LK6WJP.js} +29 -4
  24. package/dist/chunk-W4LK6WJP.js.map +1 -0
  25. package/dist/{chunk-RXMWJHWH.js → chunk-XBZIHNKV.js} +733 -221
  26. package/dist/chunk-XBZIHNKV.js.map +1 -0
  27. package/dist/cli.js +63 -68
  28. package/dist/cli.js.map +1 -1
  29. package/dist/config-KN6NKKPF.js +20 -0
  30. package/dist/{config-editor-OU6PUY66.js → config-editor-76RVZS4B.js} +3 -3
  31. package/dist/context-NXXW62NJ.js +9 -0
  32. package/dist/{core-plugins-R2EVZAJV.js → core-plugins-BPZY7SEB.js} +9 -9
  33. package/dist/{daemon-DTA6KYYY.js → daemon-XFEMMJSZ.js} +3 -3
  34. package/dist/doctor-AV6AUO22.js +9 -0
  35. package/dist/index.d.ts +110 -44
  36. package/dist/index.js +8 -8
  37. package/dist/{main-RRSX5SRL.js → main-VEJCG5PY.js} +38 -30
  38. package/dist/main-VEJCG5PY.js.map +1 -0
  39. package/dist/{plugin-installer-5XHORMLS.js → plugin-installer-VSTYZSXC.js} +2 -2
  40. package/dist/{setup-OI6A3OXW.js → setup-DISPNDEK.js} +4 -5
  41. package/dist/setup-DISPNDEK.js.map +1 -0
  42. package/dist/speech-SG62JYIF.js +9 -0
  43. package/dist/telegram-L3YM6SQJ.js +7 -0
  44. package/dist/tunnel-HWJ27WDH.js +7 -0
  45. package/dist/{tunnel-service-I2NFUX3V.js → tunnel-service-ZMO4THKE.js} +88 -8
  46. package/dist/tunnel-service-ZMO4THKE.js.map +1 -0
  47. package/package.json +1 -1
  48. package/dist/api-server-DSUW637I.js +0 -7
  49. package/dist/chunk-4B6PCWQP.js.map +0 -1
  50. package/dist/chunk-5TCXYDLR.js.map +0 -1
  51. package/dist/chunk-6VR4GWOO.js.map +0 -1
  52. package/dist/chunk-I53NEV3S.js.map +0 -1
  53. package/dist/chunk-JOMDPFQ2.js.map +0 -1
  54. package/dist/chunk-QWP76EBW.js.map +0 -1
  55. package/dist/chunk-RXMWJHWH.js.map +0 -1
  56. package/dist/chunk-ZHGPZBS4.js +0 -49
  57. package/dist/chunk-ZHGPZBS4.js.map +0 -1
  58. package/dist/config-UCAFCS5W.js +0 -14
  59. package/dist/context-7MPU7RL5.js +0 -9
  60. package/dist/doctor-D723IB2I.js +0 -9
  61. package/dist/main-RRSX5SRL.js.map +0 -1
  62. package/dist/setup-OI6A3OXW.js.map +0 -1
  63. package/dist/speech-GB7PHVQZ.js +0 -9
  64. package/dist/telegram-UVIAXADE.js +0 -7
  65. package/dist/tunnel-4WNFC7GO.js +0 -7
  66. package/dist/tunnel-service-I2NFUX3V.js.map +0 -1
  67. /package/dist/{adapter-HGJENQCN.js.map → adapter-AWSI4GML.js.map} +0 -0
  68. /package/dist/{api-server-DSUW637I.js.map → api-server-5VNYFWJE.js.map} +0 -0
  69. /package/dist/{api-server-WFB5K6FP.js.map → api-server-JLBDKCU4.js.map} +0 -0
  70. /package/dist/{chunk-E2SLHZAC.js.map → chunk-2HEFALTZ.js.map} +0 -0
  71. /package/dist/{chunk-IXMIC4GQ.js.map → chunk-BTJHGSLM.js.map} +0 -0
  72. /package/dist/{chunk-43JVXFYP.js.map → chunk-GEOXPGCO.js.map} +0 -0
  73. /package/dist/{chunk-JUFN4XMB.js.map → chunk-KDU3ZEWT.js.map} +0 -0
  74. /package/dist/{chunk-QBEQJFGL.js.map → chunk-MPGEHTGE.js.map} +0 -0
  75. /package/dist/{chunk-VD3QSMVY.js.map → chunk-QWVHCTCA.js.map} +0 -0
  76. /package/dist/{chunk-NT6FYV27.js.map → chunk-TMVTSWVH.js.map} +0 -0
  77. /package/dist/{config-UCAFCS5W.js.map → config-KN6NKKPF.js.map} +0 -0
  78. /package/dist/{config-editor-OU6PUY66.js.map → config-editor-76RVZS4B.js.map} +0 -0
  79. /package/dist/{context-7MPU7RL5.js.map → context-NXXW62NJ.js.map} +0 -0
  80. /package/dist/{core-plugins-R2EVZAJV.js.map → core-plugins-BPZY7SEB.js.map} +0 -0
  81. /package/dist/{daemon-DTA6KYYY.js.map → daemon-XFEMMJSZ.js.map} +0 -0
  82. /package/dist/{doctor-D723IB2I.js.map → doctor-AV6AUO22.js.map} +0 -0
  83. /package/dist/{plugin-installer-5XHORMLS.js.map → plugin-installer-VSTYZSXC.js.map} +0 -0
  84. /package/dist/{speech-GB7PHVQZ.js.map → speech-SG62JYIF.js.map} +0 -0
  85. /package/dist/{telegram-UVIAXADE.js.map → telegram-L3YM6SQJ.js.map} +0 -0
  86. /package/dist/{tunnel-4WNFC7GO.js.map → tunnel-HWJ27WDH.js.map} +0 -0
@@ -142,8 +142,8 @@ var TypedEmitter = class {
142
142
  // src/core/agents/agent-instance.ts
143
143
  import { spawn as spawn2, execFileSync } from "child_process";
144
144
  import { Transform } from "stream";
145
- import fs from "fs";
146
- import path from "path";
145
+ import fs2 from "fs";
146
+ import path2 from "path";
147
147
  import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
148
148
  import { PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
149
149
 
@@ -297,15 +297,48 @@ var McpManager = class {
297
297
  }
298
298
  };
299
299
 
300
+ // src/core/utils/debug-tracer.ts
301
+ import fs from "fs";
302
+ import path from "path";
303
+ var DEBUG_ENABLED = process.env.OPENACP_DEBUG === "true" || process.env.OPENACP_DEBUG === "1";
304
+ var DebugTracer = class {
305
+ constructor(sessionId, workingDirectory) {
306
+ this.sessionId = sessionId;
307
+ this.workingDirectory = workingDirectory;
308
+ this.logDir = path.join(workingDirectory, ".log");
309
+ }
310
+ dirCreated = false;
311
+ logDir;
312
+ log(layer, data) {
313
+ try {
314
+ if (!this.dirCreated) {
315
+ fs.mkdirSync(this.logDir, { recursive: true });
316
+ this.dirCreated = true;
317
+ }
318
+ const filePath = path.join(this.logDir, `${this.sessionId}_${layer}.jsonl`);
319
+ const line = JSON.stringify({ ts: Date.now(), ...data }) + "\n";
320
+ fs.appendFileSync(filePath, line);
321
+ } catch {
322
+ }
323
+ }
324
+ /** No-op cleanup — establishes the pattern for future async implementations */
325
+ destroy() {
326
+ }
327
+ };
328
+ function createDebugTracer(sessionId, workingDirectory) {
329
+ if (!DEBUG_ENABLED) return null;
330
+ return new DebugTracer(sessionId, workingDirectory);
331
+ }
332
+
300
333
  // src/core/agents/agent-instance.ts
301
334
  var log = createChildLogger({ module: "agent-instance" });
302
335
  function findPackageRoot(startDir) {
303
336
  let dir = startDir;
304
- while (dir !== path.dirname(dir)) {
305
- if (fs.existsSync(path.join(dir, "package.json"))) {
337
+ while (dir !== path2.dirname(dir)) {
338
+ if (fs2.existsSync(path2.join(dir, "package.json"))) {
306
339
  return dir;
307
340
  }
308
- dir = path.dirname(dir);
341
+ dir = path2.dirname(dir);
309
342
  }
310
343
  return startDir;
311
344
  }
@@ -317,26 +350,26 @@ function resolveAgentCommand(cmd) {
317
350
  }
318
351
  for (const root of searchRoots) {
319
352
  const packageDirs = [
320
- path.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
321
- path.resolve(root, "node_modules", cmd, "dist", "index.js")
353
+ path2.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
354
+ path2.resolve(root, "node_modules", cmd, "dist", "index.js")
322
355
  ];
323
356
  for (const jsPath of packageDirs) {
324
- if (fs.existsSync(jsPath)) {
357
+ if (fs2.existsSync(jsPath)) {
325
358
  return { command: process.execPath, args: [jsPath] };
326
359
  }
327
360
  }
328
361
  }
329
362
  for (const root of searchRoots) {
330
- const localBin = path.resolve(root, "node_modules", ".bin", cmd);
331
- if (fs.existsSync(localBin)) {
332
- const content = fs.readFileSync(localBin, "utf-8");
363
+ const localBin = path2.resolve(root, "node_modules", ".bin", cmd);
364
+ if (fs2.existsSync(localBin)) {
365
+ const content = fs2.readFileSync(localBin, "utf-8");
333
366
  if (content.startsWith("#!/usr/bin/env node")) {
334
367
  return { command: process.execPath, args: [localBin] };
335
368
  }
336
369
  const match = content.match(/"([^"]+\.js)"/);
337
370
  if (match) {
338
- const target = path.resolve(path.dirname(localBin), match[1]);
339
- if (fs.existsSync(target)) {
371
+ const target = path2.resolve(path2.dirname(localBin), match[1]);
372
+ if (fs2.existsSync(target)) {
340
373
  return { command: process.execPath, args: [target] };
341
374
  }
342
375
  }
@@ -345,7 +378,7 @@ function resolveAgentCommand(cmd) {
345
378
  try {
346
379
  const fullPath = execFileSync("which", [cmd], { encoding: "utf-8" }).trim();
347
380
  if (fullPath) {
348
- const content = fs.readFileSync(fullPath, "utf-8");
381
+ const content = fs2.readFileSync(fullPath, "utf-8");
349
382
  if (content.startsWith("#!/usr/bin/env node")) {
350
383
  return { command: process.execPath, args: [fullPath] };
351
384
  }
@@ -365,6 +398,7 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
365
398
  agentName;
366
399
  promptCapabilities;
367
400
  middlewareChain;
401
+ debugTracer = null;
368
402
  // Callback — set by core when wiring events
369
403
  onPermissionRequest = async () => "";
370
404
  constructor(agentName) {
@@ -407,20 +441,28 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
407
441
  });
408
442
  const stdinLogger = new Transform({
409
443
  transform(chunk, _enc, cb) {
410
- log.debug(
411
- { direction: "send", raw: chunk.toString().trimEnd() },
412
- "ACP raw"
413
- );
444
+ if (instance.debugTracer) {
445
+ const raw = chunk.toString().trimEnd();
446
+ try {
447
+ instance.debugTracer.log("acp", { dir: "send", data: JSON.parse(raw) });
448
+ } catch {
449
+ instance.debugTracer.log("acp", { dir: "send", data: raw });
450
+ }
451
+ }
414
452
  cb(null, chunk);
415
453
  }
416
454
  });
417
455
  stdinLogger.pipe(instance.child.stdin);
418
456
  const stdoutLogger = new Transform({
419
457
  transform(chunk, _enc, cb) {
420
- log.debug(
421
- { direction: "recv", raw: chunk.toString().trimEnd() },
422
- "ACP raw"
423
- );
458
+ if (instance.debugTracer) {
459
+ const raw = chunk.toString().trimEnd();
460
+ try {
461
+ instance.debugTracer.log("acp", { dir: "recv", data: JSON.parse(raw) });
462
+ } catch {
463
+ instance.debugTracer.log("acp", { dir: "recv", data: raw });
464
+ }
465
+ }
424
466
  cb(null, chunk);
425
467
  }
426
468
  });
@@ -489,6 +531,7 @@ ${stderr}`
489
531
  mcpServers: resolvedMcp
490
532
  });
491
533
  instance.sessionId = response.sessionId;
534
+ instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
492
535
  instance.setupCrashDetection();
493
536
  log.info(
494
537
  { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
@@ -509,6 +552,7 @@ ${stderr}`
509
552
  cwd: workingDirectory
510
553
  });
511
554
  instance.sessionId = response.sessionId;
555
+ instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
512
556
  log.info(
513
557
  { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
514
558
  "Agent resume complete"
@@ -524,6 +568,7 @@ ${stderr}`
524
568
  mcpServers: resolvedMcp
525
569
  });
526
570
  instance.sessionId = response.sessionId;
571
+ instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
527
572
  log.info(
528
573
  { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
529
574
  "Agent fallback spawn complete"
@@ -712,8 +757,8 @@ ${stderr}`
712
757
  writePath = result.path;
713
758
  writeContent = result.content;
714
759
  }
715
- await fs.promises.mkdir(path.dirname(writePath), { recursive: true });
716
- await fs.promises.writeFile(writePath, writeContent, "utf-8");
760
+ await fs2.promises.mkdir(path2.dirname(writePath), { recursive: true });
761
+ await fs2.promises.writeFile(writePath, writeContent, "utf-8");
717
762
  return {};
718
763
  },
719
764
  // ── Terminal operations (delegated to TerminalManager) ─────────────
@@ -797,10 +842,10 @@ ${stderr}`
797
842
  for (const att of attachments ?? []) {
798
843
  const tooLarge = att.size > 10 * 1024 * 1024;
799
844
  if (att.type === "image" && this.promptCapabilities?.image && !tooLarge && SUPPORTED_IMAGE_MIMES.has(att.mimeType)) {
800
- const data = await fs.promises.readFile(att.filePath);
845
+ const data = await fs2.promises.readFile(att.filePath);
801
846
  contentBlocks.push({ type: "image", data: data.toString("base64"), mimeType: att.mimeType });
802
847
  } else if (att.type === "audio" && this.promptCapabilities?.audio && !tooLarge) {
803
- const data = await fs.promises.readFile(att.filePath);
848
+ const data = await fs2.promises.readFile(att.filePath);
804
849
  contentBlocks.push({ type: "audio", data: data.toString("base64"), mimeType: att.mimeType });
805
850
  } else {
806
851
  if ((att.type === "image" || att.type === "audio") && !tooLarge) {
@@ -1003,7 +1048,7 @@ var PermissionGate = class {
1003
1048
 
1004
1049
  // src/core/sessions/session.ts
1005
1050
  import { nanoid } from "nanoid";
1006
- import * as fs2 from "fs";
1051
+ import * as fs3 from "fs";
1007
1052
  var moduleLog = createChildLogger({ module: "session" });
1008
1053
  var TTS_PROMPT_INSTRUCTION = `
1009
1054
 
@@ -1220,7 +1265,7 @@ ${text}`;
1220
1265
  try {
1221
1266
  const audioPath = att.originalFilePath || att.filePath;
1222
1267
  const audioMime = att.originalFilePath ? "audio/ogg" : att.mimeType;
1223
- const audioBuffer = await fs2.promises.readFile(audioPath);
1268
+ const audioBuffer = await fs3.promises.readFile(audioPath);
1224
1269
  const result = await this.speechService.transcribe(audioBuffer, audioMime);
1225
1270
  this.log.info({ provider: "stt", duration: result.duration }, "Voice transcribed");
1226
1271
  this.emit("agent_event", {
@@ -1564,17 +1609,23 @@ var SessionBridge = class {
1564
1609
  sessionEventHandler;
1565
1610
  statusChangeHandler;
1566
1611
  namedHandler;
1612
+ get tracer() {
1613
+ return this.session.agentInstance.debugTracer ?? null;
1614
+ }
1567
1615
  /** Send message to adapter, optionally running through message:outgoing middleware */
1568
1616
  async sendMessage(sessionId, message) {
1569
1617
  try {
1570
1618
  const mw = this.deps.middlewareChain;
1571
1619
  if (mw) {
1572
1620
  const result = await mw.execute("message:outgoing", { sessionId, message }, async (m) => m);
1621
+ this.tracer?.log("core", { step: "middleware:outgoing", sessionId, hook: "message:outgoing", blocked: !result });
1573
1622
  if (!result) return;
1623
+ this.tracer?.log("core", { step: "dispatch", sessionId, message: result.message });
1574
1624
  this.adapter.sendMessage(sessionId, result.message).catch((err) => {
1575
1625
  log2.error({ err, sessionId }, "Failed to send message to adapter");
1576
1626
  });
1577
1627
  } else {
1628
+ this.tracer?.log("core", { step: "dispatch", sessionId, message });
1578
1629
  this.adapter.sendMessage(sessionId, message).catch((err) => {
1579
1630
  log2.error({ err, sessionId }, "Failed to send message to adapter");
1580
1631
  });
@@ -1616,9 +1667,11 @@ var SessionBridge = class {
1616
1667
  }
1617
1668
  wireSessionToAdapter() {
1618
1669
  this.sessionEventHandler = (event) => {
1670
+ this.tracer?.log("core", { step: "agent_event", sessionId: this.session.id, event });
1619
1671
  const mw = this.deps.middlewareChain;
1620
1672
  if (mw) {
1621
1673
  mw.execute("agent:beforeEvent", { sessionId: this.session.id, event }, async (e) => e).then((result) => {
1674
+ this.tracer?.log("core", { step: "middleware:before", sessionId: this.session.id, hook: "agent:beforeEvent", blocked: !result });
1622
1675
  if (!result) return;
1623
1676
  try {
1624
1677
  const transformedEvent = result.event;
@@ -1668,6 +1721,7 @@ var SessionBridge = class {
1668
1721
  case "plan":
1669
1722
  case "usage":
1670
1723
  outgoing = this.deps.messageTransformer.transform(event, ctx);
1724
+ this.tracer?.log("core", { step: "transform", sessionId: this.session.id, input: event, output: outgoing });
1671
1725
  this.sendMessage(this.session.id, outgoing);
1672
1726
  break;
1673
1727
  case "session_end":
@@ -1697,12 +1751,12 @@ var SessionBridge = class {
1697
1751
  break;
1698
1752
  case "image_content": {
1699
1753
  if (this.deps.fileService) {
1700
- const fs5 = this.deps.fileService;
1754
+ const fs6 = this.deps.fileService;
1701
1755
  const sid = this.session.id;
1702
1756
  const { data, mimeType } = event;
1703
1757
  const buffer = Buffer.from(data, "base64");
1704
- const ext = fs5.extensionFromMime(mimeType);
1705
- fs5.saveFile(sid, `agent-image${ext}`, buffer, mimeType).then((att) => {
1758
+ const ext = fs6.extensionFromMime(mimeType);
1759
+ fs6.saveFile(sid, `agent-image${ext}`, buffer, mimeType).then((att) => {
1706
1760
  this.sendMessage(sid, {
1707
1761
  type: "attachment",
1708
1762
  text: "",
@@ -1714,12 +1768,12 @@ var SessionBridge = class {
1714
1768
  }
1715
1769
  case "audio_content": {
1716
1770
  if (this.deps.fileService) {
1717
- const fs5 = this.deps.fileService;
1771
+ const fs6 = this.deps.fileService;
1718
1772
  const sid = this.session.id;
1719
1773
  const { data, mimeType } = event;
1720
1774
  const buffer = Buffer.from(data, "base64");
1721
- const ext = fs5.extensionFromMime(mimeType);
1722
- fs5.saveFile(sid, `agent-audio${ext}`, buffer, mimeType).then((att) => {
1775
+ const ext = fs6.extensionFromMime(mimeType);
1776
+ fs6.saveFile(sid, `agent-audio${ext}`, buffer, mimeType).then((att) => {
1723
1777
  this.sendMessage(sid, {
1724
1778
  type: "attachment",
1725
1779
  text: "",
@@ -1896,14 +1950,22 @@ function extractFileInfo(name, kind, content, rawInput, meta) {
1896
1950
  let info = null;
1897
1951
  if (meta) {
1898
1952
  const m = meta;
1899
- const claudeCode = m?.claudeCode;
1900
- const tr = claudeCode?.toolResponse;
1901
- const file = tr?.file;
1902
- if (typeof file?.filePath === "string" && typeof file?.content === "string") {
1903
- info = { filePath: file.filePath, content: file.content };
1904
- }
1905
- if (!info && typeof tr?.filePath === "string" && typeof tr?.content === "string") {
1906
- info = { filePath: tr.filePath, content: tr.content };
1953
+ const toolResponse = resolveToolResponse(m);
1954
+ if (toolResponse) {
1955
+ const file = toolResponse.file;
1956
+ if (typeof file?.filePath === "string" && typeof file?.content === "string") {
1957
+ info = { filePath: file.filePath, content: file.content };
1958
+ }
1959
+ if (!info && typeof toolResponse.filePath === "string" && typeof toolResponse.originalFile === "string") {
1960
+ const originalFile = toolResponse.originalFile;
1961
+ const oldString = typeof toolResponse.oldString === "string" ? toolResponse.oldString : void 0;
1962
+ const newString = typeof toolResponse.newString === "string" ? toolResponse.newString : void 0;
1963
+ const newContent = oldString && newString ? originalFile.replace(oldString, newString) : originalFile;
1964
+ info = { filePath: toolResponse.filePath, content: newContent, oldContent: originalFile };
1965
+ }
1966
+ if (!info && typeof toolResponse.filePath === "string" && typeof toolResponse.content === "string") {
1967
+ info = { filePath: toolResponse.filePath, content: toolResponse.content };
1968
+ }
1907
1969
  }
1908
1970
  }
1909
1971
  if (!info && rawInput && typeof rawInput === "object") {
@@ -1912,7 +1974,19 @@ function extractFileInfo(name, kind, content, rawInput, meta) {
1912
1974
  if (typeof filePath === "string") {
1913
1975
  const parsed = content ? parseContent(content) : null;
1914
1976
  const riContent = typeof ri?.content === "string" ? ri.content : void 0;
1915
- info = { filePath, content: parsed?.content || riContent, oldContent: parsed?.oldContent };
1977
+ if (kind === "edit") {
1978
+ const oldStr = typeof ri.old_string === "string" ? ri.old_string : typeof ri.oldText === "string" ? ri.oldText : void 0;
1979
+ const newStr = typeof ri.new_string === "string" ? ri.new_string : typeof ri.newText === "string" ? ri.newText : void 0;
1980
+ if (newStr) {
1981
+ info = { filePath, content: newStr, oldContent: oldStr };
1982
+ } else {
1983
+ info = { filePath, content: riContent || parsed?.content, oldContent: parsed?.oldContent };
1984
+ }
1985
+ } else if (kind === "write") {
1986
+ info = { filePath, content: riContent || parsed?.content, oldContent: parsed?.oldContent };
1987
+ } else {
1988
+ info = { filePath, content: parsed?.content || riContent, oldContent: parsed?.oldContent };
1989
+ }
1916
1990
  }
1917
1991
  }
1918
1992
  if (!info && content) {
@@ -1926,6 +2000,16 @@ function extractFileInfo(name, kind, content, rawInput, meta) {
1926
2000
  if (!info.filePath || !info.content) return null;
1927
2001
  return info;
1928
2002
  }
2003
+ function resolveToolResponse(meta) {
2004
+ const claudeCode = meta.claudeCode;
2005
+ if (claudeCode?.toolResponse && typeof claudeCode.toolResponse === "object") {
2006
+ return claudeCode.toolResponse;
2007
+ }
2008
+ if (meta.toolResponse && typeof meta.toolResponse === "object") {
2009
+ return meta.toolResponse;
2010
+ }
2011
+ return void 0;
2012
+ }
1929
2013
  function parseContent(content) {
1930
2014
  if (typeof content === "string") {
1931
2015
  return { content };
@@ -1984,7 +2068,30 @@ function parseContent(content) {
1984
2068
 
1985
2069
  // src/core/message-transformer.ts
1986
2070
  var log3 = createChildLogger({ module: "message-transformer" });
2071
+ function computeLineDiff(oldStr, newStr) {
2072
+ const oldLines = oldStr ? oldStr.split("\n") : [];
2073
+ const newLines = newStr ? newStr.split("\n") : [];
2074
+ let prefixLen = 0;
2075
+ const minLen = Math.min(oldLines.length, newLines.length);
2076
+ while (prefixLen < minLen && oldLines[prefixLen] === newLines[prefixLen]) {
2077
+ prefixLen++;
2078
+ }
2079
+ let suffixLen = 0;
2080
+ const maxSuffix = minLen - prefixLen;
2081
+ while (suffixLen < maxSuffix && oldLines[oldLines.length - 1 - suffixLen] === newLines[newLines.length - 1 - suffixLen]) {
2082
+ suffixLen++;
2083
+ }
2084
+ return {
2085
+ added: Math.max(0, newLines.length - prefixLen - suffixLen),
2086
+ removed: Math.max(0, oldLines.length - prefixLen - suffixLen)
2087
+ };
2088
+ }
1987
2089
  var MessageTransformer = class {
2090
+ tunnelService;
2091
+ /** Cache rawInput from tool_call so it's available in tool_update (which often lacks it) */
2092
+ toolRawInputCache = /* @__PURE__ */ new Map();
2093
+ /** Cache viewer links generated from intermediate updates so completion events carry them */
2094
+ toolViewerCache = /* @__PURE__ */ new Map();
1988
2095
  constructor(tunnelService) {
1989
2096
  this.tunnelService = tunnelService;
1990
2097
  }
@@ -1995,6 +2102,9 @@ var MessageTransformer = class {
1995
2102
  case "thought":
1996
2103
  return { type: "thought", text: event.content };
1997
2104
  case "tool_call": {
2105
+ if (event.id && this.isNonEmptyInput(event.rawInput)) {
2106
+ this.toolRawInputCache.set(event.id, event.rawInput);
2107
+ }
1998
2108
  const meta = event.meta;
1999
2109
  const metadata = {
2000
2110
  id: event.id,
@@ -2012,6 +2122,14 @@ var MessageTransformer = class {
2012
2122
  return { type: "tool_call", text: event.name, metadata };
2013
2123
  }
2014
2124
  case "tool_update": {
2125
+ if (event.id && this.isNonEmptyInput(event.rawInput)) {
2126
+ this.toolRawInputCache.set(event.id, event.rawInput);
2127
+ }
2128
+ const cachedRawInput = event.id ? this.toolRawInputCache.get(event.id) : void 0;
2129
+ const effectiveRawInput = this.isNonEmptyInput(event.rawInput) ? event.rawInput : cachedRawInput;
2130
+ if (event.id && (event.status === "completed" || event.status === "done" || event.status === "failed" || event.status === "error")) {
2131
+ this.toolRawInputCache.delete(event.id);
2132
+ }
2015
2133
  const meta = event.meta;
2016
2134
  const metadata = {
2017
2135
  id: event.id,
@@ -2019,12 +2137,28 @@ var MessageTransformer = class {
2019
2137
  kind: event.kind,
2020
2138
  status: event.status,
2021
2139
  content: event.content,
2022
- rawInput: event.rawInput,
2140
+ rawInput: effectiveRawInput,
2023
2141
  displaySummary: meta?.displaySummary,
2024
2142
  displayTitle: meta?.displayTitle,
2025
2143
  displayKind: meta?.displayKind
2026
2144
  };
2027
- this.enrichWithViewerLinks(event, metadata, sessionContext);
2145
+ const enrichEvent = { ...event, rawInput: effectiveRawInput };
2146
+ this.enrichWithViewerLinks(enrichEvent, metadata, sessionContext);
2147
+ if (event.id) {
2148
+ const cached = this.toolViewerCache.get(event.id);
2149
+ if (cached) {
2150
+ metadata.viewerLinks = cached.viewerLinks;
2151
+ metadata.viewerFilePath = cached.viewerFilePath;
2152
+ } else if (metadata.viewerLinks) {
2153
+ this.toolViewerCache.set(event.id, {
2154
+ viewerLinks: metadata.viewerLinks,
2155
+ viewerFilePath: metadata.viewerFilePath
2156
+ });
2157
+ }
2158
+ if (event.status === "completed" || event.status === "done" || event.status === "failed" || event.status === "error") {
2159
+ this.toolViewerCache.delete(event.id);
2160
+ }
2161
+ }
2028
2162
  return { type: "tool_update", text: "", metadata };
2029
2163
  }
2030
2164
  case "plan":
@@ -2094,12 +2228,38 @@ var MessageTransformer = class {
2094
2228
  return { type: "text", text: "" };
2095
2229
  }
2096
2230
  }
2231
+ /** Check if rawInput is a non-empty object (not null, not {}) */
2232
+ isNonEmptyInput(input) {
2233
+ return input !== null && input !== void 0 && typeof input === "object" && !Array.isArray(input) && Object.keys(input).length > 0;
2234
+ }
2097
2235
  enrichWithViewerLinks(event, metadata, sessionContext) {
2098
- if (!this.tunnelService || !sessionContext) return;
2099
- const name = "name" in event ? event.name || "" : "";
2100
2236
  const kind = "kind" in event ? event.kind : void 0;
2237
+ if (!metadata.diffStats && (kind === "edit" || kind === "write")) {
2238
+ const ri = event.rawInput;
2239
+ if (ri) {
2240
+ const oldStr = typeof ri.old_string === "string" ? ri.old_string : typeof ri.oldText === "string" ? ri.oldText : null;
2241
+ const newStr = typeof ri.new_string === "string" ? ri.new_string : typeof ri.newText === "string" ? ri.newText : typeof ri.content === "string" ? ri.content : null;
2242
+ if (oldStr !== null && newStr !== null) {
2243
+ const stats = computeLineDiff(oldStr, newStr);
2244
+ if (stats.added > 0 || stats.removed > 0) {
2245
+ metadata.diffStats = stats;
2246
+ }
2247
+ } else if (oldStr === null && newStr !== null && kind === "write") {
2248
+ const added = newStr.split("\n").length;
2249
+ if (added > 0) metadata.diffStats = { added, removed: 0 };
2250
+ }
2251
+ }
2252
+ }
2253
+ if (!this.tunnelService || !sessionContext) {
2254
+ log3.debug(
2255
+ { hasTunnel: !!this.tunnelService, hasCtx: !!sessionContext, kind },
2256
+ "enrichWithViewerLinks: skipping (no tunnel or session context)"
2257
+ );
2258
+ return;
2259
+ }
2260
+ const name = "name" in event ? event.name || "" : "";
2101
2261
  log3.debug(
2102
- { name, kind, status: event.status, hasContent: !!event.content },
2262
+ { name, kind, status: event.status, hasContent: !!event.content, hasRawInput: !!event.rawInput },
2103
2263
  "enrichWithViewerLinks: inspecting event"
2104
2264
  );
2105
2265
  const fileInfo = extractFileInfo(
@@ -2109,7 +2269,18 @@ var MessageTransformer = class {
2109
2269
  event.rawInput,
2110
2270
  event.meta
2111
2271
  );
2112
- if (!fileInfo) return;
2272
+ if (!fileInfo) {
2273
+ log3.debug(
2274
+ { name, kind, hasContent: !!event.content, hasRawInput: !!event.rawInput, hasMeta: !!event.meta },
2275
+ "enrichWithViewerLinks: extractFileInfo returned null"
2276
+ );
2277
+ return;
2278
+ }
2279
+ const publicUrl = this.tunnelService.getPublicUrl();
2280
+ if (publicUrl.startsWith("http://localhost") || publicUrl.startsWith("http://127.0.0.1")) {
2281
+ log3.debug({ kind, filePath: fileInfo.filePath }, "enrichWithViewerLinks: skipping (no public tunnel URL)");
2282
+ return;
2283
+ }
2113
2284
  log3.info(
2114
2285
  {
2115
2286
  name,
@@ -2130,6 +2301,12 @@ var MessageTransformer = class {
2130
2301
  sessionContext.workingDirectory
2131
2302
  );
2132
2303
  if (id2) viewerLinks.diff = this.tunnelService.diffUrl(id2);
2304
+ if (!metadata.diffStats) {
2305
+ const stats = computeLineDiff(fileInfo.oldContent, fileInfo.content);
2306
+ if (stats.added > 0 || stats.removed > 0) {
2307
+ metadata.diffStats = stats;
2308
+ }
2309
+ }
2133
2310
  }
2134
2311
  const id = store.storeFile(
2135
2312
  sessionContext.id,
@@ -2245,12 +2422,12 @@ var EventBus = class extends TypedEmitter {
2245
2422
  };
2246
2423
 
2247
2424
  // src/core/core.ts
2248
- import path4 from "path";
2425
+ import path5 from "path";
2249
2426
  import os from "os";
2250
2427
 
2251
2428
  // src/core/sessions/session-store.ts
2252
- import fs3 from "fs";
2253
- import path2 from "path";
2429
+ import fs4 from "fs";
2430
+ import path3 from "path";
2254
2431
  var log5 = createChildLogger({ module: "session-store" });
2255
2432
  var DEBOUNCE_MS = 2e3;
2256
2433
  var JsonFileSessionStore = class {
@@ -2312,9 +2489,9 @@ var JsonFileSessionStore = class {
2312
2489
  version: 1,
2313
2490
  sessions: Object.fromEntries(this.records)
2314
2491
  };
2315
- const dir = path2.dirname(this.filePath);
2316
- if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
2317
- fs3.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
2492
+ const dir = path3.dirname(this.filePath);
2493
+ if (!fs4.existsSync(dir)) fs4.mkdirSync(dir, { recursive: true });
2494
+ fs4.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
2318
2495
  }
2319
2496
  destroy() {
2320
2497
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
@@ -2327,10 +2504,10 @@ var JsonFileSessionStore = class {
2327
2504
  }
2328
2505
  }
2329
2506
  load() {
2330
- if (!fs3.existsSync(this.filePath)) return;
2507
+ if (!fs4.existsSync(this.filePath)) return;
2331
2508
  try {
2332
2509
  const raw = JSON.parse(
2333
- fs3.readFileSync(this.filePath, "utf-8")
2510
+ fs4.readFileSync(this.filePath, "utf-8")
2334
2511
  );
2335
2512
  if (raw.version !== 1) {
2336
2513
  log5.warn(
@@ -2346,7 +2523,7 @@ var JsonFileSessionStore = class {
2346
2523
  } catch (err) {
2347
2524
  log5.error({ err }, "Failed to load session store, backing up corrupt file");
2348
2525
  try {
2349
- fs3.renameSync(this.filePath, `${this.filePath}.bak`);
2526
+ fs4.renameSync(this.filePath, `${this.filePath}.bak`);
2350
2527
  } catch {
2351
2528
  }
2352
2529
  }
@@ -2620,27 +2797,27 @@ var ErrorTracker = class {
2620
2797
  };
2621
2798
 
2622
2799
  // src/core/plugin/plugin-storage.ts
2623
- import fs4 from "fs";
2624
- import path3 from "path";
2800
+ import fs5 from "fs";
2801
+ import path4 from "path";
2625
2802
  var PluginStorageImpl = class {
2626
2803
  kvPath;
2627
2804
  dataDir;
2628
2805
  writeChain = Promise.resolve();
2629
2806
  constructor(baseDir) {
2630
- this.dataDir = path3.join(baseDir, "data");
2631
- this.kvPath = path3.join(baseDir, "kv.json");
2632
- fs4.mkdirSync(baseDir, { recursive: true });
2807
+ this.dataDir = path4.join(baseDir, "data");
2808
+ this.kvPath = path4.join(baseDir, "kv.json");
2809
+ fs5.mkdirSync(baseDir, { recursive: true });
2633
2810
  }
2634
2811
  readKv() {
2635
2812
  try {
2636
- const raw = fs4.readFileSync(this.kvPath, "utf-8");
2813
+ const raw = fs5.readFileSync(this.kvPath, "utf-8");
2637
2814
  return JSON.parse(raw);
2638
2815
  } catch {
2639
2816
  return {};
2640
2817
  }
2641
2818
  }
2642
2819
  writeKv(data) {
2643
- fs4.writeFileSync(this.kvPath, JSON.stringify(data), "utf-8");
2820
+ fs5.writeFileSync(this.kvPath, JSON.stringify(data), "utf-8");
2644
2821
  }
2645
2822
  async get(key) {
2646
2823
  const data = this.readKv();
@@ -2666,7 +2843,7 @@ var PluginStorageImpl = class {
2666
2843
  return Object.keys(this.readKv());
2667
2844
  }
2668
2845
  getDataDir() {
2669
- fs4.mkdirSync(this.dataDir, { recursive: true });
2846
+ fs5.mkdirSync(this.dataDir, { recursive: true });
2670
2847
  return this.dataDir;
2671
2848
  }
2672
2849
  };
@@ -3113,7 +3290,7 @@ var OpenACPCore = class {
3113
3290
  this.agentCatalog = new AgentCatalog();
3114
3291
  this.agentCatalog.load();
3115
3292
  this.agentManager = new AgentManager(this.agentCatalog);
3116
- const storePath = path4.join(os.homedir(), ".openacp", "sessions.json");
3293
+ const storePath = path5.join(os.homedir(), ".openacp", "sessions.json");
3117
3294
  this.sessionStore = new JsonFileSessionStore(
3118
3295
  storePath,
3119
3296
  config.sessionStore.ttlDays
@@ -3136,7 +3313,7 @@ var OpenACPCore = class {
3136
3313
  sessions: this.sessionManager,
3137
3314
  config: this.configManager,
3138
3315
  core: this,
3139
- storagePath: path4.join(os.homedir(), ".openacp", "plugins", "data"),
3316
+ storagePath: path5.join(os.homedir(), ".openacp", "plugins", "data"),
3140
3317
  log: createChildLogger({ module: "plugin" })
3141
3318
  });
3142
3319
  this.sessionFactory.middlewareChain = this.lifecycleManager.middlewareChain;
@@ -3169,7 +3346,7 @@ var OpenACPCore = class {
3169
3346
  }
3170
3347
  set tunnelService(service) {
3171
3348
  this._tunnelService = service;
3172
- this.messageTransformer = new MessageTransformer(service);
3349
+ this.messageTransformer.tunnelService = service;
3173
3350
  }
3174
3351
  registerAdapter(name, adapter) {
3175
3352
  this.adapters.set(name, adapter);
@@ -3737,4 +3914,4 @@ export {
3737
3914
  OpenACPCore,
3738
3915
  CommandRegistry
3739
3916
  };
3740
- //# sourceMappingURL=chunk-6VR4GWOO.js.map
3917
+ //# sourceMappingURL=chunk-UCIZM5SW.js.map