@agentdocumentformat/cli 0.7.8 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +1 -1
  2. package/dist/adf.mjs +59 -8
  3. package/dist/chunks/{APEv2Parser-2CNNHMXV.mjs → APEv2Parser-WIXRJLHB.mjs} +2 -2
  4. package/dist/chunks/{AiffParser-7BR4RL6G.mjs → AiffParser-ZC4QFOVJ.mjs} +5 -5
  5. package/dist/chunks/{App-7RIIOHJJ.mjs → App-4AZZJNN2.mjs} +917 -826
  6. package/dist/chunks/{DsdiffParser-CMD4AX7A.mjs → DsdiffParser-UAPAJHFX.mjs} +5 -5
  7. package/dist/chunks/{DsfParser-UOGZDS2M.mjs → DsfParser-NNYZK2QX.mjs} +6 -6
  8. package/dist/chunks/{FlacParser-HB3T3CD4.mjs → FlacParser-MW2W4LO3.mjs} +6 -6
  9. package/dist/chunks/{MP4Parser-66HBRUSX.mjs → MP4Parser-Z57SYOOQ.mjs} +4 -4
  10. package/dist/chunks/{MpegParser-YW6LIUEW.mjs → MpegParser-XIIPAZVM.mjs} +7 -7
  11. package/dist/chunks/{MusepackParser-PAUSXP7D.mjs → MusepackParser-QWNDEYHJ.mjs} +6 -6
  12. package/dist/chunks/{OggParser-NUBV3GWC.mjs → OggParser-WRX53F77.mjs} +9 -9
  13. package/dist/chunks/{WavPackParser-WQAGT7TC.mjs → WavPackParser-MJ7WCSJ5.mjs} +2 -2
  14. package/dist/chunks/{WaveParser-EWLQVDX4.mjs → WaveParser-RAVLHZ5S.mjs} +7 -7
  15. package/dist/chunks/{adf-schema-US4NFHMR.mjs → adf-schema-AIPBQTR2.mjs} +9 -3
  16. package/dist/chunks/auth-manager-AJ32FZWS.mjs +19 -0
  17. package/dist/chunks/auth-manager-C5OBEQK2.mjs +18 -0
  18. package/dist/chunks/auth-manager-TBNKCJ45.mjs +17 -0
  19. package/dist/chunks/{chatgpt-subscription-E4MXTIAT.mjs → chatgpt-subscription-MMGNW5KJ.mjs} +5 -2
  20. package/dist/chunks/chunk-2Z7X3UUR.mjs +678 -0
  21. package/dist/chunks/chunk-3UGZFWIF.mjs +26 -0
  22. package/dist/chunks/{chunk-XNPZBLYL.mjs → chunk-75DC5EWN.mjs} +13 -2
  23. package/dist/chunks/{chunk-5PO5PKRV.mjs → chunk-7JZXMDDF.mjs} +158 -67
  24. package/dist/chunks/chunk-AEAJDCVK.mjs +517 -0
  25. package/dist/chunks/{chunk-6VQEXLE2.mjs → chunk-BHY7QDCM.mjs} +41 -3
  26. package/dist/chunks/{chunk-CD3ATSXE.mjs → chunk-BR3AD5QZ.mjs} +8 -2
  27. package/dist/chunks/chunk-BS3USVEA.mjs +301 -0
  28. package/dist/chunks/chunk-C2S64Y6F.mjs +203 -0
  29. package/dist/chunks/chunk-D7A77SNL.mjs +976 -0
  30. package/dist/chunks/chunk-DDTTSKGG.mjs +2443 -0
  31. package/dist/chunks/{chunk-VAUOM3IN.mjs → chunk-DLWCKKIO.mjs} +1 -1
  32. package/dist/chunks/{chunk-G6PH7RPW.mjs → chunk-E7LC6SHP.mjs} +3 -3
  33. package/dist/chunks/{chunk-ZESQMP66.mjs → chunk-F3WSCAJD.mjs} +3 -3
  34. package/dist/chunks/{chunk-KXEF4F4E.mjs → chunk-GAZO6UMI.mjs} +1 -1
  35. package/dist/chunks/{chunk-XYTWGHFS.mjs → chunk-H3XLRWVE.mjs} +1 -1
  36. package/dist/chunks/{chunk-7T2YMTWL.mjs → chunk-H4C65MTP.mjs} +4 -4
  37. package/dist/chunks/chunk-HBOFZRUS.mjs +738 -0
  38. package/dist/chunks/{chunk-VN7UH7I5.mjs → chunk-IMVMSU3A.mjs} +251 -68
  39. package/dist/chunks/{chunk-XYV3VCIX.mjs → chunk-JZFONJSL.mjs} +79 -20
  40. package/dist/chunks/chunk-KCIRFUZH.mjs +12799 -0
  41. package/dist/chunks/chunk-KDDVQKCG.mjs +65 -0
  42. package/dist/chunks/chunk-KRPKWOMB.mjs +290 -0
  43. package/dist/chunks/chunk-LKFHERRV.mjs +145 -0
  44. package/dist/chunks/chunk-LTX74NU6.mjs +29 -0
  45. package/dist/chunks/{chunk-HSBV6YFU.mjs → chunk-LVF2DRBR.mjs} +634 -99
  46. package/dist/chunks/chunk-M2F7C2UJ.mjs +425 -0
  47. package/dist/chunks/{chunk-62NE4LG4.mjs → chunk-MQAMI5BF.mjs} +5 -5
  48. package/dist/chunks/chunk-MZRXFWPQ.mjs +278 -0
  49. package/dist/chunks/{chunk-PRMGZZM5.mjs → chunk-NZLEPJ5M.mjs} +2 -0
  50. package/dist/chunks/{chunk-I3UYSITV.mjs → chunk-O7XKQ6CH.mjs} +1 -1
  51. package/dist/chunks/chunk-P3RG5LQA.mjs +244 -0
  52. package/dist/chunks/chunk-PAK5JCO2.mjs +48 -0
  53. package/dist/chunks/chunk-PC63YFB7.mjs +34 -0
  54. package/dist/chunks/{daemon-control-HKFVSQTQ.mjs → chunk-RHBGCOS3.mjs} +67 -26
  55. package/dist/chunks/{chunk-J74STFKE.mjs → chunk-RJDOVMM4.mjs} +362 -58
  56. package/dist/chunks/{chunk-QPLEAE6V.mjs → chunk-SOSPQPEN.mjs} +167 -650
  57. package/dist/chunks/{chunk-LFMB4PAA.mjs → chunk-TKXIH27X.mjs} +974 -113
  58. package/dist/chunks/{chunk-5W7KES6P.mjs → chunk-UZPDETEU.mjs} +1 -1
  59. package/dist/chunks/chunk-V3MM6PCH.mjs +366 -0
  60. package/dist/chunks/chunk-VENQBMOA.mjs +62 -0
  61. package/dist/chunks/chunk-WJGPNHGX.mjs +67 -0
  62. package/dist/chunks/{chunk-Y5ZLKFLE.mjs → chunk-XNNJQCZP.mjs} +196 -165
  63. package/dist/chunks/{chunk-HDBPBORT.mjs → chunk-YRBFIDLB.mjs} +46 -10
  64. package/dist/chunks/{chunk-BNXUAOO4.mjs → chunk-ZGXUOAWZ.mjs} +3186 -959
  65. package/dist/chunks/chunk-ZPB3HYM7.mjs +45 -0
  66. package/dist/chunks/claude-subscription-EB4LAAVV.mjs +29 -0
  67. package/dist/chunks/{cli-NMFIAR7Z.mjs → cli-PCVFB6B4.mjs} +797 -56
  68. package/dist/chunks/{commands-KPJWFRUE.mjs → commands-KOMPXJZS.mjs} +4 -3
  69. package/dist/chunks/{daemon-YDIK3AAM.mjs → daemon-BVDB565V.mjs} +83142 -64424
  70. package/dist/chunks/daemon-control-MKN7G5M3.mjs +59 -0
  71. package/dist/chunks/{daemon-token-WRSULP7G.mjs → daemon-token-L5QKTHU5.mjs} +3 -1
  72. package/dist/chunks/{discord-DSP4HUWI.mjs → discord-IR62565M.mjs} +3 -52
  73. package/dist/chunks/{email-BRG7KUO2.mjs → email-KHHTJBDW.mjs} +4 -2
  74. package/dist/chunks/{grok-subscription-4PYX7TBF.mjs → grok-subscription-E74FS5EG.mjs} +5 -2
  75. package/dist/chunks/{layout-EPJQNFAI.mjs → layout-ECWGJF6M.mjs} +2 -2
  76. package/dist/chunks/{lib-N7FCZWKH.mjs → lib-L27L5PXM.mjs} +22 -22
  77. package/dist/chunks/{open-VAU7PXT6.mjs → open-3OR6WT4T.mjs} +6 -6
  78. package/dist/chunks/{parser-JVY2PWSM.mjs → parser-7GARNT5L.mjs} +1 -1
  79. package/dist/chunks/{pipeline-executor-O77NTGLP.mjs → pipeline-executor-DRYEEFDR.mjs} +6 -5
  80. package/dist/chunks/prompt-RRHZX4YT.mjs +13 -0
  81. package/dist/chunks/remote-access-cli-GLEEP7DI.mjs +268 -0
  82. package/dist/chunks/remote-hello-UFWUBDQI.mjs +37 -0
  83. package/dist/chunks/sdk-OJOAF4DP.mjs +30014 -0
  84. package/dist/chunks/{slack-OCNNF4DX.mjs → slack-IYC5RAB5.mjs} +3 -4
  85. package/dist/chunks/{store-HUVDJPYN.mjs → store-55CQSAOX.mjs} +7 -3
  86. package/dist/chunks/tailscale-WLJATFMB.mjs +25 -0
  87. package/dist/chunks/{theme-SFE3JMA2.mjs → theme-HLBDTF6F.mjs} +1 -1
  88. package/dist/chunks/{themes-YLXLOIJF.mjs → themes-BQ72P446.mjs} +2 -2
  89. package/dist/chunks/{token-6G3HCMNX.mjs → token-6D22WECM.mjs} +20 -16
  90. package/dist/chunks/{token-util-UXYSDQIW.mjs → token-util-YF3ZWBZ4.mjs} +1 -2
  91. package/dist/chunks/{tui-UQJLK7XI.mjs → tui-RAUVFOYY.mjs} +21 -18
  92. package/dist/chunks/{welcome-XHXFV7SH.mjs → welcome-J5JZZAM5.mjs} +1 -1
  93. package/dist/chunks/{whatsapp-AJMRQBT7.mjs → whatsapp-YJFFVN4Q.mjs} +9 -9
  94. package/package.json +1 -1
  95. package/dist/chunks/chunk-GKKCMXIZ.mjs +0 -94
  96. package/dist/chunks/chunk-IHDDCZBS.mjs +0 -112
  97. package/dist/chunks/chunk-KWFOS5WC.mjs +0 -41
  98. package/dist/chunks/chunk-UEZR2CNS.mjs +0 -65
  99. package/dist/chunks/chunk-VMHTYDH4.mjs +0 -172
  100. package/dist/chunks/chunk-Y2QA53AN.mjs +0 -259
  101. package/dist/chunks/{chunk-NBTUWMGP.mjs → chunk-2MTE22CR.mjs} +3 -3
  102. package/dist/chunks/{chunk-APRU6PHC.mjs → chunk-JZ7AQNPM.mjs} +3 -3
  103. package/dist/chunks/{telegram-2EFGKIVK.mjs → telegram-JYY2VDTI.mjs} +5 -5
@@ -4,28 +4,38 @@ import { dirname as __adfDirname } from 'node:path';
4
4
  const require = __adfCreateRequire(import.meta.url);
5
5
  const __filename = __adfFileURLToPath(import.meta.url);
6
6
  const __dirname = __adfDirname(__filename);
7
+ import {
8
+ types_exports
9
+ } from "./chunk-75DC5EWN.mjs";
7
10
  import {
8
11
  require_jsx_runtime
9
12
  } from "./chunk-7CV2SA3H.mjs";
10
- import {
11
- DaemonError,
12
- MAIN_LOOP
13
- } from "./chunk-XNPZBLYL.mjs";
14
13
  import {
15
14
  cjs
16
15
  } from "./chunk-SGUTYISF.mjs";
17
16
  import {
18
- loop_parser_exports
19
- } from "./chunk-5PO5PKRV.mjs";
17
+ loop_parser_exports,
18
+ owner_command_row_exports
19
+ } from "./chunk-7JZXMDDF.mjs";
20
20
  import {
21
21
  require_react
22
22
  } from "./chunk-6GJ4QHRI.mjs";
23
+ import {
24
+ file_ref_exports
25
+ } from "./chunk-LKFHERRV.mjs";
26
+ import {
27
+ agent_commands_exports
28
+ } from "./chunk-VENQBMOA.mjs";
23
29
  import {
24
30
  __toESM
25
31
  } from "./chunk-M2RX3S2T.mjs";
26
32
 
27
33
  // src/main/tui/state/store.tsx
28
34
  var import_react = __toESM(require_react(), 1);
35
+ import { randomUUID } from "node:crypto";
36
+
37
+ // src/main/tui/api/types.ts
38
+ var shared = cjs(types_exports), MAIN_LOOP = shared.MAIN_LOOP, DaemonError = shared.DaemonError, isCredentialsLocked = shared.isCredentialsLocked, SUPPORTED_CLIENT_API_VERSION = shared.SUPPORTED_CLIENT_API_VERSION;
29
39
 
30
40
  // src/main/tui/state/tracked.ts
31
41
  var TRACKED_PREFIX = "file:";
@@ -130,7 +140,14 @@ function reconcileSelection(state, previousSummaries = {}, trackedFresh = !1) {
130
140
  }
131
141
 
132
142
  // src/main/tui/state/transcript.ts
133
- var MAX_TRANSCRIPT_ITEMS = 2e3, { parseLoopToDisplay } = cjs(loop_parser_exports), localCounter = 0;
143
+ var MAX_TRANSCRIPT_ITEMS = 2e3, { parseLoopToDisplay } = cjs(loop_parser_exports), { attachmentText } = cjs(file_ref_exports);
144
+ function withAttachments(text, attachments) {
145
+ if (!Array.isArray(attachments) || attachments.length === 0) return text;
146
+ let lines = attachments.map(attachmentText);
147
+ return [text, ...lines].filter(Boolean).join(`
148
+ `);
149
+ }
150
+ var localCounter = 0;
134
151
  function localId(prefix = "l") {
135
152
  return localCounter += 1, `${prefix}:${Date.now().toString(36)}:${localCounter}`;
136
153
  }
@@ -151,6 +168,19 @@ function isTaskRef(text) {
151
168
  return !1;
152
169
  }
153
170
  }
171
+ function taskRefId(text) {
172
+ if (isTaskRef(text))
173
+ return JSON.parse(text).task_id;
174
+ }
175
+ function unresolvedTasks(items) {
176
+ let out = [];
177
+ for (let item of items) {
178
+ if (item.kind !== "tool" || item.status !== "running" || !item.toolUseId) continue;
179
+ let taskId = taskRefId(item.taskRef);
180
+ taskId && out.push({ toolUseId: item.toolUseId, taskId });
181
+ }
182
+ return out;
183
+ }
154
184
  function askQuestion(input) {
155
185
  let q = input && typeof input == "object" ? input.question : void 0;
156
186
  return typeof q == "string" ? q : "";
@@ -161,13 +191,19 @@ function historyToItems(entries) {
161
191
  let meta = entry.metadata ?? {}, base = { id: `h:${entry.id}`, at: entry.timestamp, seq: typeof meta.seq == "number" ? meta.seq : void 0 };
162
192
  switch (entry.type) {
163
193
  case "user":
164
- items.push({ ...base, kind: "user", text: entry.content, origin: "owner" });
194
+ items.push({ ...base, kind: "user", text: withAttachments(entry.content, meta.attachments), origin: "owner" });
165
195
  break;
166
196
  case "trigger":
167
197
  items.push({ ...base, kind: "user", text: entry.content, origin: "runtime" });
168
198
  break;
169
199
  case "context":
170
- meta.category === "loop" && typeof meta.fromLoop == "string" ? items.push({ ...base, kind: "user", text: entry.content, origin: "loop", from: meta.fromLoop }) : items.push({ ...base, kind: "context", category: String(meta.category ?? "context"), text: entry.content });
200
+ meta.category === "loop" && typeof meta.fromLoop == "string" ? items.push({ ...base, kind: "user", text: entry.content, origin: "loop", from: meta.fromLoop }) : meta.category === "runtime" ? items.push({ ...base, kind: "user", text: entry.content, origin: "runtime" }) : items.push({
201
+ ...base,
202
+ kind: "context",
203
+ category: String(meta.category ?? "context"),
204
+ text: entry.content,
205
+ ...meta.category === "owner_command" ? { ownerCommand: meta.ownerCommand } : {}
206
+ });
171
207
  break;
172
208
  case "compaction":
173
209
  items.push({ ...base, kind: "context", category: "compaction", text: entry.content });
@@ -176,7 +212,7 @@ function historyToItems(entries) {
176
212
  items.push({ ...base, kind: "error", text: entry.content });
177
213
  break;
178
214
  case "text":
179
- items.push({ ...base, kind: "assistant", text: entry.content, streaming: !1, model: typeof meta.model == "string" ? meta.model : void 0 });
215
+ items.push({ ...base, kind: "assistant", text: entry.content, streaming: !1, model: typeof meta.model == "string" ? meta.model : void 0, ...meta.interrupted === !0 ? { interrupted: !0 } : {} });
180
216
  break;
181
217
  case "thinking":
182
218
  items.push({ ...base, kind: "thinking", text: entry.content, streaming: !1 });
@@ -196,7 +232,14 @@ function historyToItems(entries) {
196
232
  }
197
233
  case "tool_result": {
198
234
  let useId = typeof meta.tool_use_id == "string" ? meta.tool_use_id : void 0, call = useId ? toolsById.get(useId) : void 0, status = meta.isError ? "error" : "ok";
199
- call ? (call.status = status, call.result = entry.content, call.completedAt = entry.timestamp, !meta.isError && isTaskRef(entry.content) && (call.async = !0, call.taskRef = entry.content)) : items.push({ ...base, kind: "tool", toolUseId: useId, name: typeof meta.name == "string" ? meta.name : "tool", input: void 0, status, result: entry.content, completedAt: entry.timestamp });
235
+ if (call) {
236
+ if (!meta.isError && isTaskRef(entry.content)) {
237
+ call.async = !0, call.taskRef = entry.content;
238
+ break;
239
+ }
240
+ call.status = status, call.result = withAttachments(entry.content, meta.attachments), call.completedAt = entry.timestamp;
241
+ } else
242
+ items.push({ ...base, kind: "tool", toolUseId: useId, name: typeof meta.name == "string" ? meta.name : "tool", input: void 0, status, result: entry.content, completedAt: entry.timestamp });
200
243
  break;
201
244
  }
202
245
  }
@@ -210,8 +253,8 @@ function mergeHistory(existing, incoming) {
210
253
  let history = incoming.map((item) => {
211
254
  if (item.kind !== "tool" || item.taskRef === void 0 || !item.toolUseId) return item;
212
255
  let live = finished.get(item.toolUseId);
213
- return !live || live.result === item.taskRef ? item : { ...item, status: live.status, result: live.result, completedAt: live.completedAt };
214
- }), historyTools = /* @__PURE__ */ new Set(), historyTexts = /* @__PURE__ */ new Map(), countText = (key) => historyTexts.set(key, (historyTexts.get(key) ?? 0) + 1);
256
+ return live ? { ...item, status: live.status, result: live.result, completedAt: live.completedAt } : item;
257
+ }), historyTools = /* @__PURE__ */ new Set(), historyCommands = new Set(history.flatMap((item) => item.kind === "context" && item.ownerCommand ? [item.ownerCommand.id] : [])), historyTexts = /* @__PURE__ */ new Map(), countText = (key) => historyTexts.set(key, (historyTexts.get(key) ?? 0) + 1);
215
258
  for (let item of history)
216
259
  item.kind === "tool" && item.toolUseId && historyTools.add(item.toolUseId), (item.kind === "user" || item.kind === "assistant" || item.kind === "thinking") && countText(`${item.kind}:${item.text.trim()}`), item.kind === "tool" && item.name === "ask" && countText(`ask:${askQuestion(item.input).trim()}`);
217
260
  let consume = (key) => {
@@ -227,7 +270,7 @@ function mergeHistory(existing, incoming) {
227
270
  case "thinking":
228
271
  return !consume(`${item.kind}:${item.text.trim()}`);
229
272
  case "context":
230
- return !1;
273
+ return !!item.ownerCommand && !historyCommands.has(item.ownerCommand.id);
231
274
  case "ask":
232
275
  return !consume(`ask:${item.question.trim()}`);
233
276
  default:
@@ -240,7 +283,9 @@ function prependHistory(existing, older) {
240
283
  let ids = new Set(existing.map((item) => item.id)), orphans = /* @__PURE__ */ new Map();
241
284
  for (let item of existing)
242
285
  item.kind === "tool" && !item.local && item.toolUseId && item.status !== "running" && orphans.set(item.toolUseId, item);
243
- let merged = /* @__PURE__ */ new Set();
286
+ let merged = /* @__PURE__ */ new Set(), commands = new Set(older.flatMap((item) => item.kind === "context" && item.ownerCommand ? [item.ownerCommand.id] : []));
287
+ for (let item of existing)
288
+ item.local && item.kind === "context" && item.ownerCommand && commands.has(item.ownerCommand.id) && (merged.add(item), ids.delete(item.id));
244
289
  return [...older.filter((item) => !ids.has(item.id)).map((item) => {
245
290
  if (item.kind !== "tool" || item.status !== "running" || !item.toolUseId) return item;
246
291
  let result = orphans.get(item.toolUseId);
@@ -254,6 +299,9 @@ function finalizeStreaming(items) {
254
299
  let changed = !1, next = items.map((item) => (item.kind === "assistant" || item.kind === "thinking") && item.streaming ? (changed = !0, { ...item, streaming: !1 }) : item);
255
300
  return changed ? next : items;
256
301
  }
302
+ function markInterrupted(items) {
303
+ return items.map((item) => item.kind === "assistant" && item.streaming ? { ...item, interrupted: !0 } : item);
304
+ }
257
305
  function cap(items) {
258
306
  return items.length > MAX_TRANSCRIPT_ITEMS ? items.slice(items.length - MAX_TRANSCRIPT_ITEMS) : items;
259
307
  }
@@ -332,7 +380,7 @@ function applyEventToItems(items, event) {
332
380
  return next[index] = { ...next[index], ...patch }, next;
333
381
  }
334
382
  case "turn.completed": {
335
- let closed = finalizeStreaming(items), content = str(p.content)?.trim();
383
+ let closed = finalizeStreaming(p.interrupted === !0 && p.partial === !0 ? markInterrupted(items) : items), content = str(p.content)?.trim();
336
384
  if (!content) return closed;
337
385
  let lastUser = -1;
338
386
  for (let i = closed.length - 1; i >= 0; i--) if (closed[i].kind === "user") {
@@ -346,7 +394,7 @@ function applyEventToItems(items, event) {
346
394
  return !taskId || items.some((item) => item.kind === "hil" && item.taskId === taskId) ? items : cap([...finalizeStreaming(items), { id: localId(), at, local: !0, kind: "hil", taskId, tool: str(p.tool) ?? "tool", input: p.input, reason: str(p.reason), status: "pending" }]);
347
395
  }
348
396
  case "hil.resolved": {
349
- let taskId = str(p.task_id) ?? str(p.request_id), index = items.findIndex((item) => item.kind === "hil" && item.taskId === taskId), status = p.approved === !0 ? "approved" : "denied";
397
+ let taskId = str(p.task_id) ?? str(p.request_id), index = items.findIndex((item) => item.kind === "hil" && item.taskId === taskId), status = p.settled === !0 ? "completed" : p.approved === !0 ? "approved" : "denied";
350
398
  if (index < 0)
351
399
  return cap([...items, { id: localId(), at, local: !0, kind: "notice", level: "info", event: event.event_type, text: `Approval ${taskId ?? ""} ${status}${p.timed_out ? " (timed out)" : ""}` }]);
352
400
  let next = items.slice();
@@ -640,6 +688,13 @@ function tuiReducer(state, action) {
640
688
  return patchTranscript(state, action.key, (t) => ({ ...t, loading: !1, error: action.error }));
641
689
  case "transcript/append":
642
690
  return patchTranscript(state, action.key, (t) => ({ ...t, items: [...t.items, action.item] }));
691
+ case "transcript/owner-command":
692
+ return patchTranscript(state, action.key, (t) => {
693
+ let matches = (item) => item.kind === "context" && item.ownerCommand?.id === action.item.ownerCommand?.id, existing = t.items.find(matches);
694
+ return existing?.seq !== void 0 && (action.item.seq === void 0 || existing.seq === action.item.seq) ? t : { ...t, items: [...t.items.filter((item) => !matches(item)), action.item] };
695
+ });
696
+ case "transcript/remove":
697
+ return patchTranscript(state, action.key, (t) => ({ ...t, items: t.items.filter((item) => item.id !== action.id || item.seq !== void 0) }));
643
698
  case "transcript/update":
644
699
  return patchTranscript(state, action.key, (t) => {
645
700
  let index = t.items.findIndex((item) => item.id === action.id);
@@ -651,10 +706,31 @@ function tuiReducer(state, action) {
651
706
  return patchTranscript(state, action.key, () => ({ ...emptyTranscript(), loaded: !0 }));
652
707
  case "transcript/idle":
653
708
  return patchTranscript(state, action.key, endLive);
709
+ case "tool/result":
710
+ return patchTranscript(state, action.key, (t) => {
711
+ let index = t.items.findIndex((item2) => item2.kind === "tool" && item2.toolUseId === action.toolUseId), item = t.items[index];
712
+ if (!item || item.kind !== "tool" || item.result === action.result) return t;
713
+ let items = t.items.slice();
714
+ return !action.isError && isTaskRef(action.result) ? (items[index] = { ...item, async: !0, taskRef: action.result }, { ...t, items }) : (items[index] = { ...item, result: action.result, status: action.isError ? "error" : "ok", completedAt: item.completedAt ?? Date.now() }, { ...t, items });
715
+ });
716
+ case "tool/task":
717
+ return patchTranscript(state, action.key, (t) => {
718
+ let index = t.items.findIndex((item2) => item2.kind === "tool" && item2.toolUseId === action.toolUseId), item = t.items[index];
719
+ if (!item || item.kind !== "tool" || item.status !== "running") return t;
720
+ let task = action.task, patch;
721
+ if (!task) patch = { status: "ok", result: item.taskRef };
722
+ else if (task.status === "completed") patch = { status: "ok", result: task.result ?? "" };
723
+ else if (task.status === "failed" || task.status === "denied" || task.status === "cancelled") patch = { status: "error", result: task.error ?? task.result ?? task.status };
724
+ else return t;
725
+ let items = t.items.slice();
726
+ return items[index] = { ...item, ...patch, completedAt: task?.completed_at ?? item.at }, { ...t, items };
727
+ });
654
728
  case "event":
655
- return applyEvent(state, action.frame.event);
729
+ return applyEvent(state, action.frame.event, !isSynthetic(action.frame));
656
730
  case "events":
657
- return action.frames.reduce((next, frame) => applyEvent(next, frame.event), state);
731
+ return action.frames.reduce((next, frame) => applyEvent(next, frame.event, !isSynthetic(frame)), state);
732
+ case "activity/note":
733
+ return { ...state, activity: pushBounded(state.activity, { id: localId("a"), at: Date.now(), agentId: null, loop: MAIN_LOOP, type: action.kind, summary: action.text }, MAX_ACTIVITY) };
658
734
  case "viewState/set":
659
735
  return { ...state, viewState: { ...state.viewState, [action.view]: action.value } };
660
736
  default:
@@ -690,8 +766,11 @@ var TRANSCRIPT_EVENTS = /* @__PURE__ */ new Set([
690
766
  "chat.delivered",
691
767
  "chat.discarded"
692
768
  ]);
693
- function applyEvent(state, event) {
694
- let agentId = event.agent_id ?? null, loop = eventLoop(event), next = {
769
+ function isSynthetic(frame) {
770
+ return frame.synthetic === !0;
771
+ }
772
+ function applyEvent(state, event, log = !0) {
773
+ let agentId = event.agent_id ?? null, loop = eventLoop(event), next = log ? {
695
774
  ...state,
696
775
  activity: pushBounded(state.activity, {
697
776
  id: localId("a"),
@@ -702,7 +781,7 @@ function applyEvent(state, event) {
702
781
  summary: summarizeEvent(event)
703
782
  }, MAX_ACTIVITY),
704
783
  lastEvents: pushBounded(state.lastEvents, event, MAX_LAST_EVENTS)
705
- };
784
+ } : state;
706
785
  if (!agentId || !next.agents[agentId]) return next;
707
786
  let p = event.payload ?? {};
708
787
  switch (event.event_type) {
@@ -808,6 +887,63 @@ function num(value) {
808
887
  return typeof value == "number" && Number.isFinite(value) ? value : 0;
809
888
  }
810
889
 
890
+ // src/main/tui/state/client-stream.ts
891
+ var { parseOwnerCommandRow } = cjs(owner_command_row_exports), TUI_CLIENT_NAME = "tui", MAIN = "main", NONE = { frames: [] };
892
+ function clientFrameEffects(frame) {
893
+ if (frame.kind === "umbilical") return { frames: [{ cursor: frame.cursor, event: frame.event }] };
894
+ if (frame.kind === "push" && frame.topic === "daemon_orphan_hold") {
895
+ let payload2 = frame.payload;
896
+ return { frames: [], notice: payload2.holding ? { text: `The daemon stays up because this app is connected: ${payload2.reason}`, level: "warn" } : { text: "The daemon is no longer waiting for this app to close", level: "info" } };
897
+ }
898
+ if (frame.kind !== "executor") return NONE;
899
+ let { event, agentId } = frame, loop = frame.loop ?? event.loop ?? MAIN, payload = event.payload ?? {};
900
+ switch (event.type) {
901
+ case "context_injected": {
902
+ if (payload.category !== "owner_command") return NONE;
903
+ let record = typeof payload.content == "string" ? parseOwnerCommandRow(payload.content) : null;
904
+ return !record || typeof payload.seq != "number" ? { frames: [], reload: { agentId, loop } } : { frames: [], ownerCommand: { agentId, loop, item: {
905
+ id: `command:${record.header.id}`,
906
+ at: event.timestamp,
907
+ local: !0,
908
+ seq: payload.seq,
909
+ kind: "context",
910
+ category: "owner_command",
911
+ ownerCommand: record.header,
912
+ text: record.body
913
+ } } };
914
+ }
915
+ case "text_delta":
916
+ case "text_delta_batch":
917
+ case "thinking_delta":
918
+ case "thinking_delta_batch": {
919
+ let text = deltaText(payload);
920
+ if (!text) return NONE;
921
+ let kind = event.type.startsWith("thinking") ? "thinking" : "text", delta = {
922
+ seq: frame.cursor,
923
+ event_type: "turn.delta",
924
+ timestamp: event.timestamp,
925
+ source: `agent:${agentId}`,
926
+ agent_id: agentId,
927
+ ...loop !== MAIN ? { loop } : {},
928
+ payload: { kind, text }
929
+ };
930
+ return { frames: [{ cursor: frame.cursor, event: delta, synthetic: !0 }] };
931
+ }
932
+ case "tool_call_result": {
933
+ if (frame.stripped) return NONE;
934
+ let id = typeof payload.id == "string" ? payload.id : void 0, result = payload.result;
935
+ return !id || typeof result?.content != "string" ? NONE : { frames: [], toolResult: { agentId, loop, toolUseId: id, result: result.content, isError: result.isError === !0 } };
936
+ }
937
+ case "chat_updated":
938
+ return { frames: [], reload: { agentId, loop } };
939
+ default:
940
+ return NONE;
941
+ }
942
+ }
943
+ function deltaText(payload) {
944
+ return Array.isArray(payload.deltas) ? payload.deltas.filter((d) => typeof d == "string").join("") : typeof payload.delta == "string" ? payload.delta : typeof payload.text == "string" ? payload.text : "";
945
+ }
946
+
811
947
  // src/main/tui/web/model.ts
812
948
  var isRecord = (v) => typeof v == "object" && v !== null && !Array.isArray(v);
813
949
  function parseServer(raw) {
@@ -892,13 +1028,14 @@ function serverText(server) {
892
1028
  }
893
1029
 
894
1030
  // src/main/tui/state/store.tsx
895
- var import_jsx_runtime = __toESM(require_jsx_runtime(), 1), REFRESH_DEBOUNCE_MS = 120, WEB_EVENT_DEBOUNCE_MS = 900, RESUME_VERDICT_MS = 1500, WEB_POLL_MS = 2e4, TRACKED_POLL_MS = 15e3, FOLDER_OVERLAY = "fleet.track", PROMPT_PREFILL_KEY = "shell.prompt.prefill", CHAT_VIEW_ID = "chat";
1031
+ var import_jsx_runtime = __toESM(require_jsx_runtime(), 1), { parseAuthorizeToken } = cjs(agent_commands_exports), TUI_MIN_CLIENT_API_VERSION = 1, REFRESH_DEBOUNCE_MS = 120, WEB_EVENT_DEBOUNCE_MS = 900, RESUME_VERDICT_MS = 1500, WEB_POLL_MS = 2e4, TRACKED_POLL_MS = 15e3, FOLDER_OVERLAY = "fleet.track", PROMPT_PREFILL_KEY = "shell.prompt.prefill", CHAT_VIEW_ID = "chat";
896
1032
  function createTuiStore(options) {
897
- let client = options.client, pageSize = options.pageSize ?? 100, state = initialState(client.baseUrl, options.initialView), listeners = /* @__PURE__ */ new Set(), confirmResolvers = /* @__PURE__ */ new Map(), toastTimers = /* @__PURE__ */ new Map(), debounced = /* @__PURE__ */ new Map(), stream = null, webTick = null, trackedTick = null, stopped = !1, needsResync = !1, resumeFallback = null, getState = () => state, dispatch = (action) => {
1033
+ let client = options.client, plain = options.client, current = new WeakSet([client]), pageSize = options.pageSize ?? 100, state = initialState(client.baseUrl, options.initialView), selectionRevision = 0, listeners = /* @__PURE__ */ new Set(), confirmResolvers = /* @__PURE__ */ new Map(), toastTimers = /* @__PURE__ */ new Map(), debounced = /* @__PURE__ */ new Map(), stream = null, sessionId = null, fallbackNoticed = !1, sessionRetry = !1, reopening = !1, focusSent, focusInFlight = !1, focusRetryAt = 0, lastResyncAt = 0, webTick = null, trackedTick = null, stopped = !1, needsResync = !1, resumeFallback = null, getState = () => state, dispatch = (action) => {
898
1034
  let next = tuiReducer(state, action);
899
1035
  if (next !== state) {
900
- state = next;
1036
+ action.type === "select/agent" && selectionRevision++, state = next;
901
1037
  for (let listener of listeners) listener();
1038
+ sessionId && desiredFocus() !== focusSent && syncFocus();
902
1039
  }
903
1040
  }, subscribe = (listener) => (listeners.add(listener), () => {
904
1041
  listeners.delete(listener);
@@ -919,9 +1056,21 @@ function createTuiStore(options) {
919
1056
  err instanceof DaemonError && err.unreachable && dispatch({ type: "daemon/reachable", reachable: !1 }), toast(`${label}: ${describe(err)}`, "error");
920
1057
  return;
921
1058
  }
922
- }, selectedLoopOf = (agentId) => state.selectedLoop[agentId] ?? MAIN_LOOP, stale = (c) => c !== client, actions = {
1059
+ }, selectedLoopOf = (agentId) => state.selectedLoop[agentId] ?? MAIN_LOOP, stale = (c) => !current.has(c), settleBackgroundTasks = (c, agentId, key) => {
1060
+ for (let { toolUseId, taskId } of unresolvedTasks(state.transcripts[key]?.items ?? []))
1061
+ c.task(agentId, taskId).then(
1062
+ (result) => {
1063
+ stale(c) || dispatch({ type: "tool/task", key, toolUseId, task: result.task });
1064
+ },
1065
+ (err) => {
1066
+ !stale(c) && err instanceof DaemonError && err.status === 404 && dispatch({ type: "tool/task", key, toolUseId, task: null });
1067
+ }
1068
+ );
1069
+ }, useSession = (id) => {
1070
+ client = id ? plain.withClientSession(id) : plain, current.add(client);
1071
+ }, actions = {
923
1072
  async setDaemonUrl(url, token) {
924
- let next = client.withBaseUrl(url, token);
1073
+ let next = plain.withBaseUrl(url, token);
925
1074
  if (next.baseUrl === client.baseUrl && token === void 0)
926
1075
  return toast(`Already connected to ${next.baseUrl}`, "info"), !0;
927
1076
  client.hasToken && !next.hasToken && toast(`Not sending this daemon's token to ${next.baseUrl}; use /url <url> --token <token> if it needs one`, "warn", 6e3), toast(`Checking ${next.baseUrl}\u2026`, "info", 2e3);
@@ -931,9 +1080,9 @@ function createTuiStore(options) {
931
1080
  return toast(`Not switching: ${next.baseUrl} is not answering (${describe(err)}). Still on ${client.baseUrl}.`, "error"), !1;
932
1081
  }
933
1082
  let previous = client.baseUrl;
934
- stream?.close(), stream = null;
1083
+ stream?.close(), stream = null, endSession(client);
935
1084
  for (let timer of debounced.values()) clearTimeout(timer);
936
- return debounced.clear(), client = next, dispatch({ type: "daemon/switch", url: next.baseUrl }), toast(`Switched from ${previous} to ${next.baseUrl} \u2014 agents on the old daemon keep running`, "success", 6e3), await start(), !0;
1085
+ return debounced.clear(), client = next, plain = next, current = new WeakSet([next]), dispatch({ type: "daemon/switch", url: next.baseUrl }), toast(`Switched from ${previous} to ${next.baseUrl} \u2014 agents on the old daemon keep running`, "success", 6e3), await start(), !0;
937
1086
  },
938
1087
  async refreshAgents() {
939
1088
  let c = client;
@@ -1051,7 +1200,7 @@ function createTuiStore(options) {
1051
1200
  return toast(`${agent.name}: its identity is password-protected. Load it with /load ${filePath} and unlock it`, "warn", 8e3), null;
1052
1201
  let review = () => (toast(`${agent.name} has not been reviewed on this daemon: review it first`, "warn", 5e3), actions.pushOverlay({ kind: FOLDER_OVERLAY, props: { folder, review: filePath } }), null);
1053
1202
  if (agent.status === "needs_review") return review();
1054
- let start2 = options2.start ?? !0, c = client;
1203
+ let start2 = options2.start ?? !0, selectionAtStart = selectionRevision, c = client;
1055
1204
  dispatch({ type: "tracked/busy", filePath, busy: "loading" }), dispatch({ type: "tracked/file-error", filePath, error: void 0 });
1056
1205
  let ref;
1057
1206
  try {
@@ -1073,8 +1222,10 @@ function createTuiStore(options) {
1073
1222
  if (dispatch({ type: "tracked/busy", filePath, busy: void 0 }), stale(c)) return null;
1074
1223
  let text = `Loaded ${name}${started}`;
1075
1224
  toast(text, level, 5e3);
1076
- let wasSelected = state.selectedAgentId === key || state.selectedAgentId === entry.key;
1077
- return await actions.refreshAgents(), actions.refreshTracked(), (wasSelected || !state.selectedAgentId || isTrackedKey(state.selectedAgentId)) && state.agents[ref.id] && actions.selectAgent(ref.id), actions.notice(ref.id, MAIN_LOOP, text, level === "success" ? "info" : "warn"), ref.id;
1225
+ let selectedBefore = state.selectedAgentId, wasSelected = selectedBefore === key || selectedBefore === entry.key;
1226
+ await actions.refreshAgents(), actions.refreshTracked();
1227
+ let current2 = state.selectedAgentId, untouched = current2 === selectedBefore || current2 === ref.id;
1228
+ return selectionRevision === selectionAtStart && untouched && (wasSelected || !selectedBefore || isTrackedKey(selectedBefore)) && state.agents[ref.id] && actions.selectAgent(ref.id), actions.notice(ref.id, MAIN_LOOP, text, level === "success" ? "info" : "warn"), ref.id;
1078
1229
  },
1079
1230
  selectAgent(agentId) {
1080
1231
  dispatch({ type: "select/agent", agentId }), !isTrackedKey(agentId) && agentId && (actions.ensureTranscript(agentId, selectedLoopOf(agentId)), state.agents[agentId]?.config || actions.loadConfig(agentId));
@@ -1126,7 +1277,8 @@ function createTuiStore(options) {
1126
1277
  dispatch({ type: "transcript/loading", key });
1127
1278
  try {
1128
1279
  let page = await c.loopHistory(agentId, { loop, limit: pageSize });
1129
- stale(c) || dispatch({ type: "transcript/history", key, entries: page.entries, total: page.total, offset: page.offset, mode: "replace" });
1280
+ if (stale(c)) return;
1281
+ dispatch({ type: "transcript/history", key, entries: page.entries, total: page.total, offset: page.offset, mode: "replace" }), settleBackgroundTasks(c, agentId, key);
1130
1282
  } catch (err) {
1131
1283
  stale(c) || dispatch({ type: "transcript/error", key, error: describe(err) });
1132
1284
  }
@@ -1138,7 +1290,8 @@ function createTuiStore(options) {
1138
1290
  dispatch({ type: "transcript/loading", key });
1139
1291
  try {
1140
1292
  let page = await c.loopHistory(agentId, { loop, limit, offset });
1141
- stale(c) || dispatch({ type: "transcript/history", key, entries: page.entries, total: page.total, offset: page.offset, mode: "prepend" });
1293
+ if (stale(c)) return;
1294
+ dispatch({ type: "transcript/history", key, entries: page.entries, total: page.total, offset: page.offset, mode: "prepend" }), settleBackgroundTasks(c, agentId, key);
1142
1295
  } catch (err) {
1143
1296
  stale(c) || dispatch({ type: "transcript/error", key, error: describe(err) });
1144
1297
  }
@@ -1163,6 +1316,45 @@ function createTuiStore(options) {
1163
1316
  return dispatch({ type: "transcript/update", key, id: item.id, patch: { pending: !1 } }), dispatch({ type: "transcript/append", key, item: { id: localId(), at: Date.now(), local: !0, kind: "error", text: `Not sent: ${describe(err)}` } }), !1;
1164
1317
  }
1165
1318
  },
1319
+ async runAgentCommand(agentId, loop, name, rawArgs) {
1320
+ let c = client;
1321
+ if (isTrackedKey(agentId)) {
1322
+ toast(`Agent is off. Start it, then run /${name} again.`, "warn");
1323
+ return;
1324
+ }
1325
+ if (rawArgs.includes(`
1326
+ `) || rawArgs.includes("\r") || rawArgs.length > 4096) {
1327
+ toast(`/${name}: arguments must be one line of at most 4096 characters.`, "warn");
1328
+ return;
1329
+ }
1330
+ let { args, authorize } = parseAuthorizeToken(rawArgs), requestId = randomUUID(), key = transcriptKey(agentId, loop), registered = state.agents[agentId]?.config?.commands, lambda = Array.isArray(registered) ? registered.find((command) => command?.name === name)?.lambda : void 0, item = {
1331
+ id: `command:${requestId}`,
1332
+ at: Date.now(),
1333
+ local: !0,
1334
+ kind: "context",
1335
+ category: "owner_command",
1336
+ text: "",
1337
+ ownerCommand: { v: 1, id: requestId, command: `/${name}${args ? ` ${args}` : ""}`, lambda: typeof lambda == "string" ? lambda : "", authorized: authorize, status: "running", duration_ms: 0 }
1338
+ };
1339
+ dispatch({ type: "transcript/owner-command", key, item });
1340
+ try {
1341
+ let result = await c.runCommand(agentId, name, { args, authorize, loop, requestId });
1342
+ if (stale(c) || stopped) return;
1343
+ dispatch({ type: "transcript/owner-command", key, item: {
1344
+ ...item,
1345
+ seq: result.seq,
1346
+ text: result.result,
1347
+ deferred: result.deferred,
1348
+ unrecorded: !result.deferred && result.seq === void 0,
1349
+ ownerCommand: { ...item.ownerCommand, authorized: result.authorized, status: result.status, duration_ms: result.durationMs }
1350
+ } });
1351
+ let label = `${agentLabel(agentId)} /${name} (${loop})`;
1352
+ toast(`${label}: ${result.status === "denied" ? "permission denied; add !authorize for one authorized run" : result.status}${result.deferred ? " \u2014 recording after the current step" : ""}`, result.status === "ok" ? "success" : result.status === "denied" ? "warn" : "error");
1353
+ } catch (err) {
1354
+ if (stale(c) || stopped) return;
1355
+ dispatch({ type: "transcript/remove", key, id: item.id }), err instanceof DaemonError && err.unreachable && dispatch({ type: "daemon/reachable", reachable: !1 }), toast(`/${name}: ${describe(err)}`, "error");
1356
+ }
1357
+ },
1166
1358
  async clearLoopHistory(agentId, loop) {
1167
1359
  await run("Clear", (c) => c.clearChat(agentId, loop)) && (dispatch({ type: "transcript/reset", key: transcriptKey(agentId, loop) }), toast(`Cleared ${loop} history`, "success"), await actions.refreshLoops(agentId));
1168
1360
  },
@@ -1223,7 +1415,7 @@ function createTuiStore(options) {
1223
1415
  }
1224
1416
  },
1225
1417
  async logoutSubscription(provider) {
1226
- let label = provider === "chatgpt" ? "ChatGPT" : "Grok", result = await run(`Sign out of ${label}`, (c) => c.logoutSubscription(provider));
1418
+ let label = { chatgpt: "ChatGPT", grok: "Grok", claude: "Claude" }[provider], result = await run(`Sign out of ${label}`, (c) => c.logoutSubscription(provider));
1227
1419
  return result && toast(`Signed the daemon out of ${label}`, "success"), await actions.refreshAuth(), !!result;
1228
1420
  },
1229
1421
  async refreshWeb() {
@@ -1332,6 +1524,11 @@ function createTuiStore(options) {
1332
1524
  }, WEB_EVENT_DEBOUNCE_MS), !agentId || !state.agents[agentId]) return;
1333
1525
  let loop = eventLoop(event), key = transcriptKey(agentId, loop);
1334
1526
  switch (event.event_type) {
1527
+ case "context.injected":
1528
+ event.payload?.category === "owner_command" && debounce(`t:${key}`, () => {
1529
+ actions.loadTranscript(agentId, loop);
1530
+ });
1531
+ break;
1335
1532
  case "turn.completed":
1336
1533
  case "loop.cleared":
1337
1534
  case "loop.compacted":
@@ -1386,40 +1583,137 @@ function createTuiStore(options) {
1386
1583
  } catch {
1387
1584
  dispatch({ type: "daemon/reachable", reachable: !1 });
1388
1585
  }
1389
- options.live !== !1 && (stream = client.events({
1390
- onEvent: onFrame,
1391
- onState: (info) => {
1392
- dispatch({ type: "connection", info }), info.state === "reconnecting" && (needsResync = !0, info.error && dispatch({ type: "daemon/reachable", reachable: !1 })), info.state === "open" && info.resumed ? (needsResync = !1, resumeFallback && clearTimeout(resumeFallback), resumeFallback = setTimeout(() => {
1393
- resumeFallback = null, toast("Reconnected to daemon \u2014 resyncing", "info", 2500), resync();
1394
- }, RESUME_VERDICT_MS)) : info.state === "open" && needsResync && (needsResync = !1, toast("Connected to daemon", "info", 2500), resync());
1395
- },
1396
- onResume: (info) => {
1397
- if (resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), info.exact) {
1398
- toast("Reconnected to daemon \u2014 no events missed", "info", 2500), Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]);
1399
- return;
1400
- }
1401
- toast(info.reason === "epoch_changed" ? "The daemon restarted \u2014 reloading" : "Events were missed while disconnected \u2014 reloading", "warn", 4e3), resync();
1402
- }
1403
- }).start(), webTick && clearInterval(webTick), webTick = setInterval(() => {
1586
+ let opening = Promise.resolve();
1587
+ options.live !== !1 && (opening = openStream(), webTick && clearInterval(webTick), webTick = setInterval(() => {
1404
1588
  stopped || actions.refreshWeb();
1405
1589
  }, WEB_POLL_MS), trackedTick && clearInterval(trackedTick), trackedTick = setInterval(() => {
1406
1590
  !stopped && state.daemonReachable !== !1 && actions.refreshTracked();
1407
- }, TRACKED_POLL_MS)), await Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]), await actions.refreshTracked();
1591
+ }, TRACKED_POLL_MS)), await Promise.all([opening, actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]), await actions.refreshTracked();
1592
+ }
1593
+ function onStreamState(info) {
1594
+ if (dispatch({ type: "connection", info }), info.state === "reconnecting" && (needsResync = !0, info.error && dispatch({ type: "daemon/reachable", reachable: !1 }), sessionId && info.error?.startsWith("HTTP 404") && reopenSession()), info.state === "open" && sessionRetry && !sessionId) {
1595
+ sessionRetry = !1, reopenSession();
1596
+ return;
1597
+ }
1598
+ info.state === "open" && info.resumed ? (needsResync = !1, resumeFallback && clearTimeout(resumeFallback), resumeFallback = setTimeout(() => {
1599
+ resumeFallback = null, toast("Reconnected to daemon \u2014 resyncing", "info", 2500), resync();
1600
+ }, RESUME_VERDICT_MS)) : info.state === "open" && needsResync && (needsResync = !1, toast("Connected to daemon", "info", 2500), resync());
1601
+ }
1602
+ function onStreamResume(info) {
1603
+ if (resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), info.exact) {
1604
+ toast("Reconnected to daemon \u2014 no events missed", "info", 2500), Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]);
1605
+ return;
1606
+ }
1607
+ toast(info.reason === "epoch_changed" ? "The daemon restarted \u2014 reloading" : "Events were missed while disconnected \u2014 reloading", "warn", 4e3), resync();
1608
+ }
1609
+ function onStreamGap(gap) {
1610
+ Date.now() - lastResyncAt < RESUME_VERDICT_MS || (toast(`${gap.dropped ? `${gap.dropped} live event${gap.dropped === 1 ? " was" : "s were"}` : "Live events were"} dropped \u2014 reloading`, "warn", 4e3), resync());
1611
+ }
1612
+ function onClientFrame(frame) {
1613
+ let effects = clientFrameEffects(frame);
1614
+ for (let envelope of effects.frames) onFrame(envelope);
1615
+ if (effects.ownerCommand) {
1616
+ flushFrames();
1617
+ let { agentId, loop, item } = effects.ownerCommand;
1618
+ dispatch({ type: "transcript/owner-command", key: transcriptKey(agentId, loop), item });
1619
+ }
1620
+ if (effects.toolResult) {
1621
+ flushFrames();
1622
+ let { agentId, loop, toolUseId, result, isError } = effects.toolResult;
1623
+ dispatch({ type: "tool/result", key: transcriptKey(agentId, loop), toolUseId, result, isError });
1624
+ }
1625
+ if (effects.notice && toast(effects.notice.text, effects.notice.level, effects.notice.level === "warn" ? 1e4 : 4e3), effects.reload) {
1626
+ let { agentId, loop } = effects.reload, key = transcriptKey(agentId, loop);
1627
+ state.transcripts[key]?.loaded && debounce(`t:${key}`, () => {
1628
+ actions.loadTranscript(agentId, loop);
1629
+ });
1630
+ }
1631
+ }
1632
+ function noticeFallback(reason) {
1633
+ fallbackNoticed || (fallbackNoticed = !0, dispatch({ type: "activity/note", kind: "client.fallback", text: `Live events over /events: ${reason}. Token streaming follows each agent's umbilical.stream_deltas.` }));
1634
+ }
1635
+ async function openSession(c) {
1636
+ try {
1637
+ let version = (await c.version()).clientApiVersion;
1638
+ if (typeof version != "number" || version < TUI_MIN_CLIENT_API_VERSION || version > SUPPORTED_CLIENT_API_VERSION)
1639
+ return noticeFallback(`the daemon speaks client API ${version}, this app ${TUI_MIN_CLIENT_API_VERSION}-${SUPPORTED_CLIENT_API_VERSION}`), null;
1640
+ } catch (err) {
1641
+ return err instanceof DaemonError && err.unreachable ? (sessionRetry = !0, null) : (noticeFallback(err instanceof DaemonError && err.status === 404 ? "the daemon has no client sessions (an older version)" : `GET /version failed (${describe(err)})`), null);
1642
+ }
1643
+ try {
1644
+ return (await c.createClientSession({ client: TUI_CLIENT_NAME, version: options.clientVersion ?? process.env.ADF_VERSION ?? "dev", umbilical: !0 })).sessionId;
1645
+ } catch (err) {
1646
+ return err instanceof DaemonError && err.unreachable ? (sessionRetry = !0, null) : (noticeFallback(err instanceof DaemonError && err.status === 404 ? "the daemon has no client sessions (an older version)" : `opening a client session failed (${describe(err)})`), null);
1647
+ }
1648
+ }
1649
+ async function openStream() {
1650
+ let c = plain, id = options.clientSessions === !1 ? null : await openSession(c);
1651
+ if (stale(c) || stopped) {
1652
+ id && c.endClientSession(id).catch(() => {
1653
+ });
1654
+ return;
1655
+ }
1656
+ sessionId = id, useSession(id), focusSent = void 0, id ? (stream = c.clientSessionEvents(id, { onEvent: onClientFrame, onState: onStreamState, onResume: onStreamResume, onGap: onStreamGap }).start(), syncFocus()) : stream = c.events({ onEvent: onFrame, onState: onStreamState, onResume: onStreamResume }).start();
1657
+ }
1658
+ async function reopenSession() {
1659
+ if (!(reopening || stopped)) {
1660
+ reopening = !0;
1661
+ try {
1662
+ let hadSession = sessionId !== null;
1663
+ if (stream?.close(), stream = null, sessionId = null, useSession(null), await openStream(), stopped) return;
1664
+ hadSession && toast("The daemon no longer had this app's client session \u2014 reopened, reloading", "warn", 4e3), await resync();
1665
+ } finally {
1666
+ reopening = !1;
1667
+ }
1668
+ }
1669
+ }
1670
+ function desiredFocus() {
1671
+ let id = state.selectedAgentId;
1672
+ return state.activeView === CHAT_VIEW_ID && id && !isTrackedKey(id) ? id : null;
1673
+ }
1674
+ async function syncFocus() {
1675
+ if (!sessionId || focusInFlight || Date.now() < focusRetryAt) return;
1676
+ let want = desiredFocus();
1677
+ if (want === focusSent) return;
1678
+ let id = sessionId, c = client;
1679
+ focusInFlight = !0;
1680
+ try {
1681
+ await c.setClientSessionFocus(id, want), sessionId === id && (focusSent = want);
1682
+ } catch {
1683
+ focusRetryAt = Date.now() + 2e3;
1684
+ } finally {
1685
+ focusInFlight = !1;
1686
+ }
1687
+ sessionId === id && desiredFocus() !== focusSent && syncFocus();
1688
+ }
1689
+ function endSession(c) {
1690
+ let id = sessionId;
1691
+ return sessionId = null, c === client && useSession(null), focusSent = void 0, id ? c.endClientSession(id).then(() => {
1692
+ }, () => {
1693
+ }) : Promise.resolve();
1408
1694
  }
1409
1695
  async function resync() {
1410
- await Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]), actions.refreshTracked();
1696
+ lastResyncAt = Date.now(), await Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]), actions.refreshTracked();
1411
1697
  for (let key of Object.keys(state.transcripts)) {
1412
1698
  let at = key.indexOf("\0"), agentId = key.slice(0, at);
1413
1699
  state.agents[agentId] && state.transcripts[key].loaded && actions.loadTranscript(agentId, key.slice(at + 1));
1414
1700
  }
1415
1701
  }
1416
1702
  function stop() {
1417
- stopped = !0, stream?.close(), stream = null, resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), webTick && (clearInterval(webTick), webTick = null), trackedTick && (clearInterval(trackedTick), trackedTick = null), pendingFrames = [];
1703
+ stopped = !0, stream?.close(), stream = null;
1704
+ let ended = endSession(client);
1705
+ resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), webTick && (clearInterval(webTick), webTick = null), trackedTick && (clearInterval(trackedTick), trackedTick = null), pendingFrames = [];
1418
1706
  for (let timer of toastTimers.values()) clearTimeout(timer);
1419
1707
  for (let timer of debounced.values()) clearTimeout(timer);
1420
1708
  toastTimers.clear(), debounced.clear();
1421
1709
  for (let resolve of confirmResolvers.values()) resolve(!1);
1422
- confirmResolvers.clear();
1710
+ return confirmResolvers.clear(), ended;
1711
+ }
1712
+ async function close() {
1713
+ let ended = stop(), timer;
1714
+ await Promise.race([ended, new Promise((resolve) => {
1715
+ timer = setTimeout(resolve, 1e3);
1716
+ })]), timer && clearTimeout(timer);
1423
1717
  }
1424
1718
  function resolveConfirm(id, confirmed) {
1425
1719
  let resolve = confirmResolvers.get(id);
@@ -1434,7 +1728,13 @@ function createTuiStore(options) {
1434
1728
  dispatch,
1435
1729
  subscribe,
1436
1730
  start,
1437
- stop,
1731
+ stop: () => {
1732
+ stop();
1733
+ },
1734
+ close,
1735
+ get liveMode() {
1736
+ return sessionId ? "session" : stream ? "events" : "none";
1737
+ },
1438
1738
  resolveConfirm
1439
1739
  };
1440
1740
  }
@@ -1477,14 +1777,17 @@ function shallowEqual(a, b) {
1477
1777
  }
1478
1778
 
1479
1779
  export {
1480
- emptyTranscript,
1481
- isAsyncInput,
1482
- askQuestion,
1780
+ MAIN_LOOP,
1781
+ DaemonError,
1782
+ isCredentialsLocked,
1483
1783
  isTrackedKey,
1484
1784
  folderName,
1485
1785
  stoppedLabel,
1486
1786
  stoppedError,
1487
1787
  findTracked,
1788
+ emptyTranscript,
1789
+ isAsyncInput,
1790
+ askQuestion,
1488
1791
  transcriptKey,
1489
1792
  isBusyState,
1490
1793
  parseServer,
@@ -1495,6 +1798,7 @@ export {
1495
1798
  SERVER_STOPPED_TEXT,
1496
1799
  serverBadge,
1497
1800
  serverText,
1801
+ TUI_MIN_CLIENT_API_VERSION,
1498
1802
  PROMPT_PREFILL_KEY,
1499
1803
  createTuiStore,
1500
1804
  StoreProvider,