@agentdocumentformat/cli 0.8.2 → 0.8.4

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 (129) hide show
  1. package/README.md +55 -4
  2. package/dist/adf.mjs +16 -13
  3. package/dist/chunks/{App-4AZZJNN2.mjs → App-XOPHZTGN.mjs} +515 -349
  4. package/dist/chunks/{auth-manager-TBNKCJ45.mjs → auth-manager-2YHTYI3C.mjs} +2 -1
  5. package/dist/chunks/{build-QF5W473T.mjs → build-BFOCXM5S.mjs} +1 -1
  6. package/dist/chunks/{chunk-RHBGCOS3.mjs → chunk-22ZGZFOV.mjs} +5 -16
  7. package/dist/chunks/chunk-26RK7T5L.mjs +20 -0
  8. package/dist/chunks/{chunk-KCIRFUZH.mjs → chunk-2WIFHJV2.mjs} +2 -2
  9. package/dist/chunks/{chunk-D7A77SNL.mjs → chunk-3FWPIWYM.mjs} +1 -1
  10. package/dist/chunks/chunk-4T745GJA.mjs +431 -0
  11. package/dist/chunks/{chunk-7JZXMDDF.mjs → chunk-7ADDKFT5.mjs} +105 -31
  12. package/dist/chunks/chunk-A53XYNJL.mjs +26 -0
  13. package/dist/chunks/{chunk-MZRXFWPQ.mjs → chunk-AN6USKYQ.mjs} +40 -8
  14. package/dist/chunks/{chunk-2Z7X3UUR.mjs → chunk-DHO5Z6HP.mjs} +14 -12
  15. package/dist/chunks/{chunk-F5ELW46V.mjs → chunk-GJYMGPH4.mjs} +1 -0
  16. package/dist/chunks/chunk-HONGRUAE.mjs +175 -0
  17. package/dist/chunks/{chunk-AEAJDCVK.mjs → chunk-IM5JKLXO.mjs} +1 -1
  18. package/dist/chunks/chunk-J2N63ZUD.mjs +12 -0
  19. package/dist/chunks/{chunk-IMVMSU3A.mjs → chunk-JK6K2BMV.mjs} +12 -38
  20. package/dist/chunks/{chunk-75DC5EWN.mjs → chunk-KBXC5EHK.mjs} +1 -0
  21. package/dist/chunks/chunk-NRTRTR7C.mjs +43 -0
  22. package/dist/chunks/{chunk-BS3USVEA.mjs → chunk-P4G5ZEBI.mjs} +1 -1
  23. package/dist/chunks/{chunk-E7LC6SHP.mjs → chunk-RIAB37IS.mjs} +4 -2
  24. package/dist/chunks/{chunk-LVF2DRBR.mjs → chunk-TBMQOM7Y.mjs} +247 -610
  25. package/dist/chunks/{chunk-SOSPQPEN.mjs → chunk-TDRQG5UO.mjs} +1 -162
  26. package/dist/chunks/{chunk-RJDOVMM4.mjs → chunk-TPA2ITKV.mjs} +49 -33
  27. package/dist/chunks/{chunk-BHY7QDCM.mjs → chunk-UBWWGUMU.mjs} +1 -0
  28. package/dist/chunks/{chunk-3AT7IIP7.mjs → chunk-WZ6S3SQP.mjs} +1 -1
  29. package/dist/chunks/chunk-X6R32YVE.mjs +43 -0
  30. package/dist/chunks/chunk-XJWGENZ5.mjs +5903 -0
  31. package/dist/chunks/{chunk-F3WSCAJD.mjs → chunk-XP4U4A2W.mjs} +1 -1
  32. package/dist/chunks/chunk-XS46KYYY.mjs +31 -0
  33. package/dist/chunks/{chunk-HBOFZRUS.mjs → chunk-XZQVDY3U.mjs} +9 -1
  34. package/dist/chunks/chunk-ZECGH3LT.mjs +88 -0
  35. package/dist/chunks/{claude-subscription-EB4LAAVV.mjs → claude-subscription-42L4YM5L.mjs} +4 -3
  36. package/dist/chunks/{cli-PCVFB6B4.mjs → cli-JPRYEY4J.mjs} +53 -13
  37. package/dist/chunks/{commands-KOMPXJZS.mjs → commands-TZW2FSXG.mjs} +5 -2
  38. package/dist/chunks/context-AZOIJOUG.mjs +5933 -0
  39. package/dist/chunks/{daemon-HEQ3FUYH.mjs → daemon-DK3KUDZJ.mjs} +3571 -6806
  40. package/dist/chunks/{daemon-control-MKN7G5M3.mjs → daemon-control-U4OGCAAJ.mjs} +4 -4
  41. package/dist/chunks/{devtools-H7CI2ZVG.mjs → devtools-AUZWFIPL.mjs} +1 -1
  42. package/dist/chunks/firewall-service-7RGJN4LD.mjs +163 -0
  43. package/dist/chunks/{open-3OR6WT4T.mjs → open-T3VGLWGF.mjs} +6 -5
  44. package/dist/chunks/{pipeline-executor-DRYEEFDR.mjs → pipeline-executor-MHRI7ODL.mjs} +6 -3
  45. package/dist/chunks/{remote-access-cli-GLEEP7DI.mjs → remote-access-cli-EFVCXFOY.mjs} +22 -6
  46. package/dist/chunks/{store-55CQSAOX.mjs → store-37YHXFJ6.mjs} +4 -3
  47. package/dist/chunks/{tui-RAUVFOYY.mjs → tui-NJKGFAKU.mjs} +12 -11
  48. package/dist/chunks/web-F4XHDGUX.mjs +149 -0
  49. package/dist/chunks/{whatsapp-YJFFVN4Q.mjs → whatsapp-J7PX7TKT.mjs} +1 -1
  50. package/package.json +4 -3
  51. package/web/assets/EditorPanel-5ZGWvexa.js +161 -0
  52. package/web/assets/MeshGraphView-BZV40eAE.css +1 -0
  53. package/web/assets/MeshGraphView-Vp2R5TLK.js +23 -0
  54. package/web/assets/SettingsPage-_uHkBERV.js +6 -0
  55. package/web/assets/agent-window-B8X7FV4_.js +3 -0
  56. package/web/assets/agent.store-BHweGGTh.js +1 -0
  57. package/web/assets/app.store-j_-OuVPe.js +1 -0
  58. package/web/assets/core-DVezgdzc.js +12 -0
  59. package/web/assets/css-Z72CF80r.js +1 -0
  60. package/web/assets/diff-D97Zzqfu.js +1 -0
  61. package/web/assets/document.store-CMD3_OM0.js +1 -0
  62. package/web/assets/edit-recovery-Ce8tPQZl.js +3 -0
  63. package/web/assets/engine-javascript-CuxHA8oH.js +141 -0
  64. package/web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  65. package/web/assets/github-light-DAi9KRSo.js +1 -0
  66. package/web/assets/go-C27-OAKa.js +1 -0
  67. package/web/assets/html-BlS82ilI.js +1 -0
  68. package/web/assets/index-B5Eot_tL.js +1 -0
  69. package/web/assets/index-B5FYMbFc.js +3 -0
  70. package/web/assets/index-BQIEMvvt.js +2 -0
  71. package/web/assets/index-C_gf4L3q.js +1 -0
  72. package/web/assets/index-Ca6bEWGu.js +1 -0
  73. package/web/assets/index-CuTaWSEs.css +1 -0
  74. package/web/assets/index-DBFkrLao.js +1 -0
  75. package/web/assets/index-DF1leTEa.js +11 -0
  76. package/web/assets/index-DS9H-PJI.js +1 -0
  77. package/web/assets/index-DkhbLs9K.js +6 -0
  78. package/web/assets/index-KNnHrO8-.js +13 -0
  79. package/web/assets/index-nM_Q5x7Q.js +1 -0
  80. package/web/assets/inter-tight-cyrillic-ext-wght-italic-BJqtfpQe.woff2 +0 -0
  81. package/web/assets/inter-tight-cyrillic-ext-wght-normal-okcGN4Nq.woff2 +0 -0
  82. package/web/assets/inter-tight-cyrillic-wght-italic-HmhN1gQv.woff2 +0 -0
  83. package/web/assets/inter-tight-cyrillic-wght-normal-BS41q_Tv.woff2 +0 -0
  84. package/web/assets/inter-tight-greek-ext-wght-italic-B_3RbJza.woff2 +0 -0
  85. package/web/assets/inter-tight-greek-ext-wght-normal-DQgQPNk4.woff2 +0 -0
  86. package/web/assets/inter-tight-greek-wght-italic-Bb1BGCmL.woff2 +0 -0
  87. package/web/assets/inter-tight-greek-wght-normal-sS1B39LI.woff2 +0 -0
  88. package/web/assets/inter-tight-latin-ext-wght-italic-DYqsmiDd.woff2 +0 -0
  89. package/web/assets/inter-tight-latin-ext-wght-normal-B4u9PlvR.woff2 +0 -0
  90. package/web/assets/inter-tight-latin-wght-italic-DiXukCDG.woff2 +0 -0
  91. package/web/assets/inter-tight-latin-wght-normal-DX-nOvPD.woff2 +0 -0
  92. package/web/assets/inter-tight-vietnamese-wght-italic-CiVF0Juh.woff2 +0 -0
  93. package/web/assets/inter-tight-vietnamese-wght-normal-TKKdAiBA.woff2 +0 -0
  94. package/web/assets/javascript-wDzz0qaB.js +1 -0
  95. package/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  96. package/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  97. package/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  98. package/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  99. package/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  100. package/web/assets/json-Cp-IABpG.js +1 -0
  101. package/web/assets/jsx-g9-lgVsj.js +1 -0
  102. package/web/assets/main-Zf3qnQYd.css +1 -0
  103. package/web/assets/main-o2ocfqUC.js +319 -0
  104. package/web/assets/markdown-Cvjx9yec.js +1 -0
  105. package/web/assets/message-queue.store-ke_rFZAb.js +2 -0
  106. package/web/assets/module-RjUF93sV.js +716 -0
  107. package/web/assets/native-48B9X9Wg.js +1 -0
  108. package/web/assets/orbital-render.worker-BovOTauk.js +1 -0
  109. package/web/assets/python-B6aJPvgy.js +1 -0
  110. package/web/assets/react-D-F9gHrJ.js +1 -0
  111. package/web/assets/rust-DPvrY3IQ.js +1 -0
  112. package/web/assets/shellscript-Yzrsuije.js +1 -0
  113. package/web/assets/sql-DkvoVjww.js +1 -0
  114. package/web/assets/stix-two-text-cyrillic-wght-italic-BzL1BdzR.woff2 +0 -0
  115. package/web/assets/stix-two-text-cyrillic-wght-normal-CcrOj1MU.woff2 +0 -0
  116. package/web/assets/stix-two-text-greek-wght-italic-glgrbyRu.woff2 +0 -0
  117. package/web/assets/stix-two-text-greek-wght-normal-DAdwyhkq.woff2 +0 -0
  118. package/web/assets/stix-two-text-latin-ext-wght-italic--XhV508b.woff2 +0 -0
  119. package/web/assets/stix-two-text-latin-ext-wght-normal-BUpo8gM0.woff2 +0 -0
  120. package/web/assets/stix-two-text-latin-wght-italic-BDl6bBME.woff2 +0 -0
  121. package/web/assets/stix-two-text-latin-wght-normal-BTZaHlTl.woff2 +0 -0
  122. package/web/assets/stix-two-text-vietnamese-wght-italic-B1jFRJrJ.woff2 +0 -0
  123. package/web/assets/stix-two-text-vietnamese-wght-normal-CfS0RdBA.woff2 +0 -0
  124. package/web/assets/tsx-COt5Ahok.js +1 -0
  125. package/web/assets/typescript-BPQ3VLAy.js +1 -0
  126. package/web/assets/window-kind-mxlpdE1l.js +1 -0
  127. package/web/assets/with-selector-Ot-ZoUn0.js +1 -0
  128. package/web/assets/yaml-Buea-lGh.js +1 -0
  129. package/web/index.html +15 -0
@@ -4,12 +4,50 @@ 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
+ THEMES,
9
+ applyTheme,
10
+ findTheme,
11
+ nextThemeName,
12
+ themeNames
13
+ } from "./chunk-GAZO6UMI.mjs";
7
14
  import {
8
15
  DaemonClient
9
- } from "./chunk-IMVMSU3A.mjs";
16
+ } from "./chunk-X6R32YVE.mjs";
10
17
  import {
11
18
  auth_flow_exports
12
- } from "./chunk-BHY7QDCM.mjs";
19
+ } from "./chunk-UBWWGUMU.mjs";
20
+ import {
21
+ DaemonError,
22
+ MAIN_LOOP,
23
+ PROMPT_PREFILL_KEY,
24
+ SERVER_STOPPED_TEXT,
25
+ StoreProvider,
26
+ askQuestions,
27
+ emptyTranscript,
28
+ findTracked,
29
+ folderName,
30
+ isAsyncInput,
31
+ isBusyState,
32
+ isCredentialsLocked,
33
+ isTrackedKey,
34
+ parseAskResult,
35
+ parseServer,
36
+ servedText,
37
+ serverBadge,
38
+ serverText,
39
+ shallowEqual,
40
+ shortUrl,
41
+ siteKind,
42
+ siteOf,
43
+ stoppedError,
44
+ stoppedLabel,
45
+ transcriptKey,
46
+ useActions,
47
+ useClient,
48
+ useStore,
49
+ useTuiSelector
50
+ } from "./chunk-TPA2ITKV.mjs";
13
51
  import {
14
52
  createMouseController,
15
53
  getScreenText,
@@ -104,7 +142,18 @@ import {
104
142
  validateCredentials,
105
143
  validateMcpForm,
106
144
  validateProvider
107
- } from "./chunk-2Z7X3UUR.mjs";
145
+ } from "./chunk-DHO5Z6HP.mjs";
146
+ import {
147
+ ThemeContext,
148
+ stateColor,
149
+ useTheme
150
+ } from "./chunk-NZLEPJ5M.mjs";
151
+ import {
152
+ require_jsx_runtime
153
+ } from "./chunk-7CV2SA3H.mjs";
154
+ import {
155
+ cjs
156
+ } from "./chunk-SGUTYISF.mjs";
108
157
  import {
109
158
  WELCOME_INTRO,
110
159
  WELCOME_OVERLAY,
@@ -120,21 +169,23 @@ import {
120
169
  savePrefs
121
170
  } from "./chunk-5QU5VY7N.mjs";
122
171
  import {
123
- THEMES,
124
- applyTheme,
125
- findTheme,
126
- nextThemeName,
127
- themeNames
128
- } from "./chunk-GAZO6UMI.mjs";
172
+ resource_revision_types_exports
173
+ } from "./chunk-XS46KYYY.mjs";
174
+ import "./chunk-JK6K2BMV.mjs";
175
+ import "./chunk-KBXC5EHK.mjs";
129
176
  import {
130
177
  context_breakdown_exports,
131
178
  guarded_fetch_exports,
132
179
  skills_catalog_schema_exports
133
- } from "./chunk-HBOFZRUS.mjs";
134
- import "./chunk-SOSPQPEN.mjs";
180
+ } from "./chunk-XZQVDY3U.mjs";
181
+ import "./chunk-7ADDKFT5.mjs";
182
+ import "./chunk-TDRQG5UO.mjs";
183
+ import "./chunk-NRTRTR7C.mjs";
184
+ import "./chunk-HONGRUAE.mjs";
135
185
  import {
136
186
  Box_default,
137
187
  Text,
188
+ measure_element_default,
138
189
  useAnimation,
139
190
  use_app_default,
140
191
  use_box_metrics_default,
@@ -143,61 +194,20 @@ import {
143
194
  use_stdin_default,
144
195
  use_stdout_default,
145
196
  use_window_size_default
146
- } from "./chunk-3AT7IIP7.mjs";
147
- import {
148
- ThemeContext,
149
- stateColor,
150
- useTheme
151
- } from "./chunk-NZLEPJ5M.mjs";
152
- import {
153
- DaemonError,
154
- MAIN_LOOP,
155
- PROMPT_PREFILL_KEY,
156
- SERVER_STOPPED_TEXT,
157
- StoreProvider,
158
- askQuestion,
159
- emptyTranscript,
160
- findTracked,
161
- folderName,
162
- isAsyncInput,
163
- isBusyState,
164
- isCredentialsLocked,
165
- isTrackedKey,
166
- parseServer,
167
- servedText,
168
- serverBadge,
169
- serverText,
170
- shallowEqual,
171
- shortUrl,
172
- siteKind,
173
- siteOf,
174
- stoppedError,
175
- stoppedLabel,
176
- transcriptKey,
177
- useActions,
178
- useClient,
179
- useStore,
180
- useTuiSelector
181
- } from "./chunk-RJDOVMM4.mjs";
182
- import "./chunk-75DC5EWN.mjs";
183
- import {
184
- require_jsx_runtime
185
- } from "./chunk-7CV2SA3H.mjs";
186
- import {
187
- cjs
188
- } from "./chunk-SGUTYISF.mjs";
189
- import "./chunk-7JZXMDDF.mjs";
197
+ } from "./chunk-WZ6S3SQP.mjs";
190
198
  import {
191
199
  require_react
192
200
  } from "./chunk-6GJ4QHRI.mjs";
193
201
  import {
194
202
  ADF_SKILLS_REGISTRY_URL
195
- } from "./chunk-E7LC6SHP.mjs";
203
+ } from "./chunk-RIAB37IS.mjs";
196
204
  import "./chunk-UYY5M2PB.mjs";
197
205
  import "./chunk-2NAP2ZF7.mjs";
198
206
  import "./chunk-LKFHERRV.mjs";
199
- import "./chunk-AEAJDCVK.mjs";
200
- import "./chunk-BS3USVEA.mjs";
207
+ import "./chunk-ZECGH3LT.mjs";
208
+ import "./chunk-26RK7T5L.mjs";
209
+ import "./chunk-IM5JKLXO.mjs";
210
+ import "./chunk-P4G5ZEBI.mjs";
201
211
  import "./chunk-WJGPNHGX.mjs";
202
212
  import "./chunk-PAK5JCO2.mjs";
203
213
  import "./chunk-ZPB3HYM7.mjs";
@@ -217,7 +227,7 @@ import {
217
227
  } from "./chunk-M2RX3S2T.mjs";
218
228
 
219
229
  // src/main/tui/app/App.tsx
220
- var import_react60 = __toESM(require_react(), 1);
230
+ var import_react61 = __toESM(require_react(), 1);
221
231
 
222
232
  // src/main/tui/app/shell-context.ts
223
233
  var import_react = __toESM(require_react(), 1);
@@ -534,7 +544,7 @@ function useShell() {
534
544
  }
535
545
 
536
546
  // src/main/tui/app/Shell.tsx
537
- var import_react25 = __toESM(require_react(), 1);
547
+ var import_react26 = __toESM(require_react(), 1);
538
548
 
539
549
  // src/main/tui/app/clipboard.ts
540
550
  import { spawn } from "node:child_process";
@@ -971,6 +981,7 @@ function isZeroWidth(ch) {
971
981
  return cp >= 768 && cp <= 879 || cp >= 8203 && cp <= 8207 || cp >= 65024 && cp <= 65039;
972
982
  }
973
983
  function displayWidth(text) {
984
+ if (/^[\x00-\x7f]*$/.test(text)) return text.length;
974
985
  let width = 0;
975
986
  for (let ch of text)
976
987
  isZeroWidth(ch) || (width += WIDE.test(ch) ? 2 : 1);
@@ -2196,7 +2207,11 @@ function Prompt({ width, focused }) {
2196
2207
  }, []);
2197
2208
  let highlighted = Math.min(menuIndex, Math.max(0, menu.length - 1)), submit = (text) => {
2198
2209
  let trimmed = text.trim();
2199
- return trimmed ? (setHistory((prev) => [...prev.filter((h) => h !== trimmed), trimmed].slice(-HISTORY_LIMIT)), setMenuIndex(0), (async () => {
2210
+ if (!trimmed) {
2211
+ let scope2 = createScope(store, exit);
2212
+ return !config2?.onSubmit || !config2.submitsEmpty?.(scope2) ? !1 : (config2.onSubmit("", { ...scope2, args: [], rest: "" }), !0);
2213
+ }
2214
+ return setHistory((prev) => [...prev.filter((h) => h !== trimmed), trimmed].slice(-HISTORY_LIMIT)), setMenuIndex(0), (async () => {
2200
2215
  if (await runSlash(trimmed, registry, store, exit)) return;
2201
2216
  let ctx = { ...createScope(store, exit), args: [], rest: trimmed };
2202
2217
  if (config2?.onSubmit && await config2.onSubmit(trimmed, ctx)) return;
@@ -2212,7 +2227,7 @@ function Prompt({ width, focused }) {
2212
2227
  let summary = store.getState().agents[ctx.agentId]?.summary;
2213
2228
  store.actions.toast(`Sent to ${summary?.handle || summary?.name || ctx.agentId} ${theme2.glyph.pointer} ${ctx.loop ?? MAIN_LOOP}`, "success", 2500);
2214
2229
  }
2215
- })(), !0) : !1;
2230
+ })(), !0;
2216
2231
  };
2217
2232
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", width, children: [
2218
2233
  menuOpen ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { flexDirection: "column", marginBottom: 0, children: menu.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { wrap: "truncate-end", children: [
@@ -3542,8 +3557,25 @@ function NewAgentDialog({ overlay, close, width, height }) {
3542
3557
  }
3543
3558
 
3544
3559
  // src/main/tui/auth/AuthDialog.tsx
3560
+ var import_react16 = __toESM(require_react(), 1);
3561
+
3562
+ // src/main/tui/ui/Markdown.tsx
3545
3563
  var import_react15 = __toESM(require_react(), 1);
3546
3564
 
3565
+ // src/main/tui/ui/markdown-window.ts
3566
+ function measuredBlockWindow(signatures, measurements, viewport) {
3567
+ let hidden = Array(signatures.length).fill(!1), below = 0, exact = !0, bottom = Math.max(0, viewport.clipBottom), top = bottom + Math.max(1, viewport.height);
3568
+ for (let i = signatures.length - 1; i >= 0; i--) {
3569
+ let m = measurements.get(i);
3570
+ if (!m || m.signature !== signatures[i]) {
3571
+ exact = !1;
3572
+ continue;
3573
+ }
3574
+ hidden[i] = below >= top || exact && below + m.height <= bottom, below += m.height;
3575
+ }
3576
+ return hidden;
3577
+ }
3578
+
3547
3579
  // src/main/tui/ui/Markdown.tsx
3548
3580
  var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
3549
3581
  function parseBlocks(text) {
@@ -3640,11 +3672,33 @@ function renderBlock(block, index, theme2, color) {
3640
3672
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Inline, { text: block.text, color }, index);
3641
3673
  }
3642
3674
  }
3643
- function Markdown({ text, color, raw = !1 }) {
3644
- let theme2 = useTheme();
3645
- if (raw) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "wrap", color, children: text });
3646
- let blocks = parseBlocks(text);
3647
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { flexDirection: "column", children: blocks.map((block, i) => renderBlock(block, i, theme2, color)) });
3675
+ function Markdown({ text, color, raw = !1, viewport }) {
3676
+ let theme2 = useTheme(), [, measured] = (0, import_react15.useReducer)((n) => n + 1, 0), cache = (0, import_react15.useRef)(null), nodes = (0, import_react15.useRef)(/* @__PURE__ */ new Map()), blocks = raw ? [] : parseBlocks(text), signatures = viewport ? blocks.map((block) => JSON.stringify(block)) : [];
3677
+ viewport && (!cache.current || cache.current.width !== viewport.width || cache.current.theme !== theme2 || !text.startsWith(cache.current.text)) && (cache.current = { text, width: viewport.width, theme: theme2, heights: /* @__PURE__ */ new Map() });
3678
+ let heights = cache.current?.heights;
3679
+ cache.current && (cache.current.text = text);
3680
+ let hidden = viewport && heights ? measuredBlockWindow(signatures, heights, viewport) : [];
3681
+ if ((0, import_react15.useLayoutEffect)(() => {
3682
+ if (!viewport || !heights) return;
3683
+ for (let [i, node] of nodes.current)
3684
+ i < signatures.length && heights.set(i, { signature: signatures[i], height: measure_element_default(node).height });
3685
+ for (let i of heights.keys()) i >= signatures.length && heights.delete(i);
3686
+ measuredBlockWindow(signatures, heights, viewport).some((value, i) => value !== hidden[i]) && measured();
3687
+ }), raw) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "wrap", color, children: text });
3688
+ if (!viewport || !heights) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { flexDirection: "column", children: blocks.map((block, i) => renderBlock(block, i, theme2, color)) });
3689
+ let children = [], spacer = 0, flush = (i) => {
3690
+ spacer > 0 && children.push(/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { height: spacer, flexShrink: 0 }, `space:${i}`)), spacer = 0;
3691
+ };
3692
+ for (let i = 0; i < blocks.length; i++) {
3693
+ if (hidden[i]) {
3694
+ spacer += heights.get(i).height;
3695
+ continue;
3696
+ }
3697
+ flush(i), children.push(/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { flexDirection: "column", flexShrink: 0, ref: (node) => {
3698
+ node ? nodes.current.set(i, node) : nodes.current.delete(i);
3699
+ }, children: renderBlock(blocks[i], i, theme2, color) }, i));
3700
+ }
3701
+ return flush(blocks.length), /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { flexDirection: "column", children });
3648
3702
  }
3649
3703
 
3650
3704
  // src/main/tui/views/chat/model.ts
@@ -3872,9 +3926,40 @@ function sayText(item) {
3872
3926
  let message = inputRecord(item.input)?.message;
3873
3927
  return typeof message == "string" ? message : prettyJson(item.input);
3874
3928
  }
3875
- function askAnswer(item) {
3876
- if (item.result !== void 0)
3877
- return item.result.startsWith("Human answered: ") ? item.result.slice(16) : item.result;
3929
+ function askAnswers(item) {
3930
+ if (!(item.result === void 0 || item.status === "error"))
3931
+ return parseAskResult(askQuestions(item.input), item.result);
3932
+ }
3933
+ function askFormHeight(questions, w, answers) {
3934
+ return questions.reduce((n, q) => n + wrappedHeight(q.question || " ", w) + (answers ? 1 : 0), 0);
3935
+ }
3936
+ function askFormText(questions, answers) {
3937
+ return questions.map((q, i) => answers ? `${q.question}
3938
+ ${answers[i] ?? "(skipped)"}` : q.question).join(`
3939
+
3940
+ `);
3941
+ }
3942
+ function askStep(ask, answers) {
3943
+ let index = Math.min(answers.length, ask.questions.length - 1);
3944
+ return { index, question: ask.questions[index] };
3945
+ }
3946
+ function askHint(q) {
3947
+ return q.options ? `Type ${q.multiple ? "numbers (1,3)" : "a number"}, or your own answer` : "Type your answer";
3948
+ }
3949
+ function readAskReply(q, text) {
3950
+ let reply = text.trim();
3951
+ if (!reply) return { answer: null };
3952
+ let options = q.options;
3953
+ if (!options) return { answer: reply };
3954
+ if (/^\d+(\s*[,\s]\s*\d+)*$/.test(reply)) {
3955
+ let picks = [...new Set(reply.split(/[\s,]+/).map(Number))];
3956
+ if (picks.every((n) => n >= 1 && n <= options.length)) {
3957
+ if (!q.multiple && picks.length > 1) return { error: "This question takes one pick" };
3958
+ let labels = picks.map((n) => options[n - 1].label);
3959
+ return { answer: q.multiple ? labels : labels[0] };
3960
+ }
3961
+ }
3962
+ return { answer: q.multiple ? [reply] : reply };
3878
3963
  }
3879
3964
  function statusLineText(item, sep4 = "\xB7", arrow = "\u2192") {
3880
3965
  let input = inputRecord(item.input);
@@ -3910,8 +3995,10 @@ function itemHeight(item, width, flags) {
3910
3995
  switch (view2) {
3911
3996
  case "say":
3912
3997
  return markdownHeight(sayText(item) || " ", w) + (item.status === "error" ? 1 : 0) + 1;
3913
- case "ask":
3914
- return 1 + wrappedHeight(askQuestion(item.input) || " ", w) + (item.result !== void 0 ? 1 : 0) + 1;
3998
+ case "ask": {
3999
+ let answers = askAnswers(item);
4000
+ return 1 + askFormHeight(askQuestions(item.input), w, answers) + (item.result !== void 0 && !answers ? 1 : 0) + 1;
4001
+ }
3915
4002
  case "status":
3916
4003
  return 2;
3917
4004
  case "row":
@@ -3922,7 +4009,7 @@ function itemHeight(item, width, flags) {
3922
4009
  case "hil":
3923
4010
  return 2 + (item.reason ? 1 : 0) + (item.feedback ? 1 : 0) + (flags.expanded ? wrappedHeight(prettyJson(item.input), w - 4) : 0) + 1;
3924
4011
  case "ask":
3925
- return 1 + wrappedHeight(item.question || " ", w) + (item.answer ? 1 : 0) + 1;
4012
+ return 1 + askFormHeight(item.questions, w) + 1;
3926
4013
  case "notice":
3927
4014
  return 1;
3928
4015
  case "context":
@@ -3951,12 +4038,8 @@ function itemText(item) {
3951
4038
  switch (toolView(item)) {
3952
4039
  case "say":
3953
4040
  return sayText(item);
3954
- case "ask": {
3955
- let answer = askAnswer(item);
3956
- return answer ? `${askQuestion(item.input)}
3957
-
3958
- ${answer}` : askQuestion(item.input);
3959
- }
4041
+ case "ask":
4042
+ return askFormText(askQuestions(item.input), askAnswers(item));
3960
4043
  default:
3961
4044
  return [`${item.name} ${prettyJson(item.input)}`, item.result ?? ""].filter(Boolean).join(`
3962
4045
 
@@ -3965,9 +4048,7 @@ ${answer}` : askQuestion(item.input);
3965
4048
  case "hil":
3966
4049
  return `${item.tool} ${prettyJson(item.input)}`;
3967
4050
  case "ask":
3968
- return item.answer ? `${item.question}
3969
-
3970
- ${item.answer}` : item.question;
4051
+ return askFormText(item.questions);
3971
4052
  case "context":
3972
4053
  return item.ownerCommand ? `${item.ownerCommand.command} [${item.ownerCommand.status}${item.ownerCommand.authorized ? ", authorized" : ""}]
3973
4054
  ${item.text}` : item.text;
@@ -4090,8 +4171,8 @@ async function signIn(client, provider, signal, handlers) {
4090
4171
  // src/main/tui/auth/AuthDialog.tsx
4091
4172
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
4092
4173
  function AuthDialog({ overlay, close, width }) {
4093
- let theme2 = useTheme(), store = useStore(), auth = useTuiSelector((s) => s.auth), props = overlay.props ?? {}, [cursor, setCursor] = (0, import_react15.useState)(Math.max(0, SUBSCRIPTIONS.indexOf(props.login ?? "chatgpt"))), [flow, setFlow] = (0, import_react15.useState)({ kind: "list" }), [note, setNote] = (0, import_react15.useState)(null), [pasted, setPasted] = (0, import_react15.useState)(""), abort = (0, import_react15.useRef)(null), dialogWidth = Math.max(50, Math.min(width - 4, 84));
4094
- (0, import_react15.useEffect)(() => (store.actions.refreshAuth(), props.login && start(props.login), () => abort.current?.abort()), []);
4174
+ let theme2 = useTheme(), store = useStore(), auth = useTuiSelector((s) => s.auth), props = overlay.props ?? {}, [cursor, setCursor] = (0, import_react16.useState)(Math.max(0, SUBSCRIPTIONS.indexOf(props.login ?? "chatgpt"))), [flow, setFlow] = (0, import_react16.useState)({ kind: "list" }), [note, setNote] = (0, import_react16.useState)(null), [pasted, setPasted] = (0, import_react16.useState)(""), abort = (0, import_react16.useRef)(null), dialogWidth = Math.max(50, Math.min(width - 4, 84));
4175
+ (0, import_react16.useEffect)(() => (store.actions.refreshAuth(), props.login && start(props.login), () => abort.current?.abort()), []);
4095
4176
  let start = (provider) => {
4096
4177
  abort.current?.abort();
4097
4178
  let ctrl = new AbortController();
@@ -4274,11 +4355,11 @@ function TerminalSetupDialog({ close, width, height }) {
4274
4355
  }
4275
4356
 
4276
4357
  // src/main/tui/setup/WelcomeDialog.tsx
4277
- var import_react16 = __toESM(require_react(), 1);
4358
+ var import_react17 = __toESM(require_react(), 1);
4278
4359
  var import_jsx_runtime20 = __toESM(require_jsx_runtime(), 1), LABEL = 21;
4279
4360
  function WelcomeDialog({ close, width, height }) {
4280
- let theme2 = useTheme(), store = useStore(), { registry, exit } = useShell(), identity = useTuiSelector((s) => s.identity), auth = useTuiSelector((s) => s.auth), agents = useTuiSelector((s) => s.agents), agentOrder = useTuiSelector((s) => s.agentOrder), [extras, setExtras] = (0, import_react16.useState)({ adapters: {}, timers: {} });
4281
- (0, import_react16.useEffect)(() => {
4361
+ let theme2 = useTheme(), store = useStore(), { registry, exit } = useShell(), identity = useTuiSelector((s) => s.identity), auth = useTuiSelector((s) => s.auth), agents = useTuiSelector((s) => s.agents), agentOrder = useTuiSelector((s) => s.agentOrder), [extras, setExtras] = (0, import_react17.useState)({ adapters: {}, timers: {} });
4362
+ (0, import_react17.useEffect)(() => {
4282
4363
  let live = !0, ids = store.getState().agentOrder;
4283
4364
  return Promise.all(ids.map(async (id) => {
4284
4365
  let entry = store.getState().agents[id], [config2, timers] = await Promise.all([
@@ -4296,10 +4377,10 @@ function WelcomeDialog({ close, width, height }) {
4296
4377
  live = !1;
4297
4378
  };
4298
4379
  }, [store, agentOrder.join("|")]);
4299
- let steps = (0, import_react16.useMemo)(
4380
+ let steps = (0, import_react17.useMemo)(
4300
4381
  () => welcomeSteps(welcomeFacts({ identity, auth, agents, agentOrder }, extras)),
4301
4382
  [identity, auth, agents, agentOrder, extras]
4302
- ), [index, setIndex] = (0, import_react16.useState)(() => nextStepIndex(steps)), selected = Math.min(index, steps.length - 1), start = () => {
4383
+ ), [index, setIndex] = (0, import_react17.useState)(() => nextStepIndex(steps)), selected = Math.min(index, steps.length - 1), start = () => {
4303
4384
  let step = steps[selected];
4304
4385
  close(), step && runSlash(step.run, registry, store, exit);
4305
4386
  };
@@ -4334,10 +4415,10 @@ function WelcomeDialog({ close, width, height }) {
4334
4415
  }
4335
4416
 
4336
4417
  // src/main/tui/setup/ChannelsDialog.tsx
4337
- var import_react18 = __toESM(require_react(), 1);
4418
+ var import_react19 = __toESM(require_react(), 1);
4338
4419
 
4339
4420
  // src/main/tui/ui/List.tsx
4340
- var import_react17 = __toESM(require_react(), 1);
4421
+ var import_react18 = __toESM(require_react(), 1);
4341
4422
  var import_jsx_runtime21 = __toESM(require_jsx_runtime(), 1);
4342
4423
  function List(props) {
4343
4424
  let {
@@ -4356,19 +4437,19 @@ function List(props) {
4356
4437
  active = !0,
4357
4438
  emptyText = "Nothing here.",
4358
4439
  wheelSelects = !1
4359
- } = props, theme2 = useTheme(), [internalIndex, setInternalIndex] = (0, import_react17.useState)(0), [query, setQuery] = (0, import_react17.useState)(""), [filtering, setFiltering] = (0, import_react17.useState)(!1), offsetRef = (0, import_react17.useRef)(0), visible = (0, import_react17.useMemo)(
4440
+ } = props, theme2 = useTheme(), [internalIndex, setInternalIndex] = (0, import_react18.useState)(0), [query, setQuery] = (0, import_react18.useState)(""), [filtering, setFiltering] = (0, import_react18.useState)(!1), offsetRef = (0, import_react18.useRef)(0), visible = (0, import_react18.useMemo)(
4360
4441
  () => filter && query ? items.filter((item) => filter(item, query)) : items,
4361
4442
  [items, filter, query]
4362
4443
  ), showFilterBar = filtering || query.length > 0, bodyRows = Math.max(1, height - (showFilterBar ? 1 : 0)), perPage = Math.max(1, Math.floor(bodyRows / itemHeight2)), rawIndex = selectedIndex ?? internalIndex, index = visible.length === 0 ? 0 : Math.min(Math.max(0, rawIndex), visible.length - 1), select = (next) => {
4363
4444
  let clamped = visible.length === 0 ? 0 : Math.min(Math.max(0, next), visible.length - 1);
4364
4445
  selectedIndex === void 0 && setInternalIndex(clamped), onSelectedIndexChange?.(clamped, visible[clamped]);
4365
4446
  };
4366
- (0, import_react17.useEffect)(() => {
4447
+ (0, import_react18.useEffect)(() => {
4367
4448
  rawIndex !== index && visible.length > 0 && select(index);
4368
4449
  }, [rawIndex, index, visible.length]);
4369
- let revealed = (0, import_react17.useRef)(null), [, redraw] = (0, import_react17.useState)(0);
4450
+ let revealed = (0, import_react18.useRef)(null), [, redraw] = (0, import_react18.useState)(0);
4370
4451
  revealed.current !== `${index}|${perPage}` && (revealed.current = `${index}|${perPage}`, index < offsetRef.current && (offsetRef.current = index), index >= offsetRef.current + perPage && (offsetRef.current = index - perPage + 1)), offsetRef.current = Math.max(0, Math.min(offsetRef.current, Math.max(0, visible.length - perPage)));
4371
- let boxRef = (0, import_react17.useRef)(null);
4452
+ let boxRef = (0, import_react18.useRef)(null);
4372
4453
  useWheel(boxRef, (delta) => {
4373
4454
  if (wheelSelects) {
4374
4455
  select(index + delta * WHEEL_STEP);
@@ -4452,8 +4533,8 @@ function LockedCredential({ name, title, width, confirming, onUnlock, onReplace,
4452
4533
  // src/main/tui/setup/ChannelsDialog.tsx
4453
4534
  var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1), POLL_MS = 1e3, POLL_FOR_MS = 2e4;
4454
4535
  function ChannelsDialog({ overlay, close, width, height }) {
4455
- let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, entries = (0, import_react18.useMemo)(channelEntries, []), direct = findChannel(props.channel), [step, setStep] = (0, import_react18.useState)(direct ? { kind: "form", entry: direct, editing: !1 } : { kind: "list" }), [index, setIndex] = (0, import_react18.useState)(0), [diag, setDiag] = (0, import_react18.useState)(null), [values, setValues] = (0, import_react18.useState)({}), [errors, setErrors] = (0, import_react18.useState)({}), [formError, setFormError] = (0, import_react18.useState)(null), [stored, setStored] = (0, import_react18.useState)(null), alive = (0, import_react18.useRef)(!0);
4456
- (0, import_react18.useEffect)(() => () => {
4536
+ let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, entries = (0, import_react19.useMemo)(channelEntries, []), direct = findChannel(props.channel), [step, setStep] = (0, import_react19.useState)(direct ? { kind: "form", entry: direct, editing: !1 } : { kind: "list" }), [index, setIndex] = (0, import_react19.useState)(0), [diag, setDiag] = (0, import_react19.useState)(null), [values, setValues] = (0, import_react19.useState)({}), [errors, setErrors] = (0, import_react19.useState)({}), [formError, setFormError] = (0, import_react19.useState)(null), [stored, setStored] = (0, import_react19.useState)(null), alive = (0, import_react19.useRef)(!0);
4537
+ (0, import_react19.useEffect)(() => () => {
4457
4538
  alive.current = !1;
4458
4539
  }, []);
4459
4540
  let configured = diag ? diag.configured.map((c) => c.type) : configuredChannels(agent2?.config), isOn = (type) => configured.includes(type), stateOf = (type) => adapterLiveState(diag, type), refresh2 = async () => {
@@ -4464,9 +4545,9 @@ function ChannelsDialog({ overlay, close, width, height }) {
4464
4545
  return null;
4465
4546
  }
4466
4547
  };
4467
- (0, import_react18.useEffect)(() => {
4548
+ (0, import_react19.useEffect)(() => {
4468
4549
  agentId && refresh2();
4469
- }, [agentId]), (0, import_react18.useEffect)(() => {
4550
+ }, [agentId]), (0, import_react19.useEffect)(() => {
4470
4551
  if (step.kind !== "detail") return;
4471
4552
  let stopped = !1, timer, started = Date.now(), tick = async () => {
4472
4553
  let d = await refresh2();
@@ -4724,10 +4805,10 @@ function LiveLine({ state }) {
4724
4805
  }
4725
4806
 
4726
4807
  // src/main/tui/setup/ProviderDialog.tsx
4727
- var import_react20 = __toESM(require_react(), 1);
4808
+ var import_react21 = __toESM(require_react(), 1);
4728
4809
 
4729
4810
  // src/main/tui/views/inspect/model-picker.tsx
4730
- var import_react19 = __toESM(require_react(), 1);
4811
+ var import_react20 = __toESM(require_react(), 1);
4731
4812
  var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1), MODEL_OVERLAY = "inspect.model";
4732
4813
  function providerChoices(providers, auth) {
4733
4814
  return providers.map((p) => {
@@ -4773,8 +4854,8 @@ async function applyModel(store, agentId, loop, choice) {
4773
4854
  return await actions4.run("Model", (c) => c.putConfig(agentId, next)) ? (await actions4.loadConfig(agentId), actions4.toast(`${who} now runs ${choice.provider}/${choice.model}`, "success"), !0) : !1;
4774
4855
  }
4775
4856
  function ModelOverlay({ overlay, close, width }) {
4776
- let theme2 = useTheme(), store = useStore(), agentId = String(overlay.props?.agentId ?? ""), loop = String(overlay.props?.loop ?? MAIN_LOOP), current = currentModel(store.getState(), agentId, loop), [providers, setProviders] = (0, import_react19.useState)(null), [models, setModels] = (0, import_react19.useState)(null), [error, setError] = (0, import_react19.useState)(null), [step, setStep] = (0, import_react19.useState)({ kind: "provider" }), [query, setQuery] = (0, import_react19.useState)(""), [index, setIndex] = (0, import_react19.useState)(0);
4777
- (0, import_react19.useEffect)(() => {
4857
+ let theme2 = useTheme(), store = useStore(), agentId = String(overlay.props?.agentId ?? ""), loop = String(overlay.props?.loop ?? MAIN_LOOP), current = currentModel(store.getState(), agentId, loop), [providers, setProviders] = (0, import_react20.useState)(null), [models, setModels] = (0, import_react20.useState)(null), [error, setError] = (0, import_react20.useState)(null), [step, setStep] = (0, import_react20.useState)({ kind: "provider" }), [query, setQuery] = (0, import_react20.useState)(""), [index, setIndex] = (0, import_react20.useState)(0);
4858
+ (0, import_react20.useEffect)(() => {
4778
4859
  store.client.providers().then(
4779
4860
  (d) => {
4780
4861
  let list = providerChoices(d.providers, store.getState().auth);
@@ -4793,7 +4874,7 @@ function ModelOverlay({ overlay, close, width }) {
4793
4874
  setModels([]), setError(err instanceof Error ? err.message : String(err));
4794
4875
  }
4795
4876
  );
4796
- }, providerRows2 = [...loop === MAIN_LOOP ? [] : [{ id: "", name: "inherit", type: "", access: "use the agent\u2019s model", ready: !0 }], ...providers ?? []], shownModels = (0, import_react19.useMemo)(() => (models ?? []).filter((m) => m.toLowerCase().includes(query.toLowerCase())), [models, query]), apply = (choice) => {
4877
+ }, providerRows2 = [...loop === MAIN_LOOP ? [] : [{ id: "", name: "inherit", type: "", access: "use the agent\u2019s model", ready: !0 }], ...providers ?? []], shownModels = (0, import_react20.useMemo)(() => (models ?? []).filter((m) => m.toLowerCase().includes(query.toLowerCase())), [models, query]), apply = (choice) => {
4797
4878
  close(), applyModel(store, agentId, loop, choice);
4798
4879
  };
4799
4880
  useKeys((input, key) => key.escape || key.ctrl && input === "c" ? step.kind === "model" && !(key.ctrl && input === "c") ? query ? (setQuery(""), !0) : (setStep({ kind: "provider" }), setIndex(Math.max(0, providerRows2.findIndex((p) => p.id === step.provider.id))), !0) : (close(), !0) : step.kind !== "model" || key.ctrl || key.meta ? !1 : key.backspace || key.delete ? (setQuery((q) => q.slice(0, -1)), setIndex(0), !0) : key.leftArrow ? (setStep({ kind: "provider" }), !0) : input && !/[\u0000-\u001f\u007f]/.test(input) && !key.return && !key.tab ? (setQuery((q) => q + input), setIndex(0), !0) : !1, { layer: "overlay" });
@@ -4926,8 +5007,8 @@ var complete = (partial) => ["chatgpt", "grok", "claude"].filter((v) => v.starts
4926
5007
  // src/main/tui/setup/ProviderDialog.tsx
4927
5008
  var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1), GROUP_LABEL = { subscription: "sign in", api: "API key", local: "local", other: "any URL" };
4928
5009
  function ProviderDialog({ overlay, close, width, height }) {
4929
- let theme2 = useTheme(), store = useStore(), rows = (0, import_react20.useMemo)(providerRows, []), preset = findProviderRow(String(overlay.props?.preset ?? "")), [step, setStep] = (0, import_react20.useState)(preset && !preset.signIn ? { kind: "form", entry: preset.entry } : { kind: "pick" }), [index, setIndex] = (0, import_react20.useState)(() => Math.max(0, rows.findIndex((r) => r.entry.group === "api"))), [values, setValues] = (0, import_react20.useState)(() => preset && !preset.signIn ? initialValues(preset.entry) : {}), [errors, setErrors] = (0, import_react20.useState)({}), [formError, setFormError] = (0, import_react20.useState)(null), alive = (0, import_react20.useRef)(!0);
4930
- (0, import_react20.useEffect)(() => () => {
5010
+ let theme2 = useTheme(), store = useStore(), rows = (0, import_react21.useMemo)(providerRows, []), preset = findProviderRow(String(overlay.props?.preset ?? "")), [step, setStep] = (0, import_react21.useState)(preset && !preset.signIn ? { kind: "form", entry: preset.entry } : { kind: "pick" }), [index, setIndex] = (0, import_react21.useState)(() => Math.max(0, rows.findIndex((r) => r.entry.group === "api"))), [values, setValues] = (0, import_react21.useState)(() => preset && !preset.signIn ? initialValues(preset.entry) : {}), [errors, setErrors] = (0, import_react21.useState)({}), [formError, setFormError] = (0, import_react21.useState)(null), alive = (0, import_react21.useRef)(!0);
5011
+ (0, import_react21.useEffect)(() => () => {
4931
5012
  alive.current = !1;
4932
5013
  }, []);
4933
5014
  let dialogWidth = Math.max(50, Math.min(width - 4, 84)), inner = dialogWidth - 4, choose = (row4) => {
@@ -5067,20 +5148,20 @@ function initialValues(entry) {
5067
5148
  }
5068
5149
 
5069
5150
  // src/main/tui/setup/McpDialog.tsx
5070
- var import_react21 = __toESM(require_react(), 1);
5151
+ var import_react22 = __toESM(require_react(), 1);
5071
5152
  var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
5072
5153
  function McpDialog({ overlay, close, width, height }) {
5073
- let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, sources2 = (0, import_react21.useMemo)(mcpSourceRows, []), [diag, setDiag] = (0, import_react21.useState)(null), [config2, setConfig] = (0, import_react21.useState)(null), [loadError, setLoadError] = (0, import_react21.useState)(null), initial = () => {
5154
+ let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, sources2 = (0, import_react22.useMemo)(mcpSourceRows, []), [diag, setDiag] = (0, import_react22.useState)(null), [config2, setConfig] = (0, import_react22.useState)(null), [loadError, setLoadError] = (0, import_react22.useState)(null), initial = () => {
5074
5155
  if (props.add !== void 0) {
5075
5156
  let target2 = parseAddTarget(props.add);
5076
5157
  return target2.row ? { kind: "form", row: target2.row } : { kind: "source" };
5077
5158
  }
5078
5159
  return props.server ? { kind: props.view === "logs" ? "logs" : "detail", name: props.server } : { kind: "list" };
5079
- }, [step, setStep] = (0, import_react21.useState)(initial), [index, setIndex] = (0, import_react21.useState)(0), [values, setValues] = (0, import_react21.useState)(() => {
5160
+ }, [step, setStep] = (0, import_react22.useState)(initial), [index, setIndex] = (0, import_react22.useState)(0), [values, setValues] = (0, import_react22.useState)(() => {
5080
5161
  let target2 = parseAddTarget(props.add);
5081
5162
  return target2.row ? initialForm(target2.row, target2.value) : {};
5082
- }), [errors, setErrors] = (0, import_react21.useState)({}), [formError, setFormError] = (0, import_react21.useState)(null), [stored, setStored] = (0, import_react21.useState)(null), pending = (0, import_react21.useRef)(null), alive = (0, import_react21.useRef)(!0);
5083
- (0, import_react21.useEffect)(() => () => {
5163
+ }), [errors, setErrors] = (0, import_react22.useState)({}), [formError, setFormError] = (0, import_react22.useState)(null), [stored, setStored] = (0, import_react22.useState)(null), pending = (0, import_react22.useRef)(null), alive = (0, import_react22.useRef)(!0);
5164
+ (0, import_react22.useEffect)(() => () => {
5084
5165
  alive.current = !1;
5085
5166
  }, []);
5086
5167
  let direct = props.add !== void 0 || !!props.server, refresh2 = async () => {
@@ -5092,13 +5173,13 @@ function McpDialog({ overlay, close, width, height }) {
5092
5173
  alive.current && setLoadError(err instanceof Error ? err.message : String(err));
5093
5174
  }
5094
5175
  };
5095
- (0, import_react21.useEffect)(() => {
5176
+ (0, import_react22.useEffect)(() => {
5096
5177
  agentId && refresh2();
5097
5178
  }, [agentId]);
5098
5179
  let servers = config2?.mcp?.servers ?? [], stateOf = (name2) => diag?.states.find((s) => s.name === name2), serverOf = (name2) => servers.find((s) => s.name === name2), hostAllowed = !!config2?.compute?.host_access, dialogWidth = Math.max(56, Math.min(width - 4, 96)), inner = dialogWidth - 4, back = () => {
5099
5180
  direct ? close() : setStep({ kind: "list" });
5100
5181
  };
5101
- (0, import_react21.useEffect)(() => {
5182
+ (0, import_react22.useEffect)(() => {
5102
5183
  config2 && !hostAllowed && values.runOn === "host" && setValues((v) => ({ ...v, runOn: "container" }));
5103
5184
  }, [config2, step.kind]);
5104
5185
  let restart = async (name2) => {
@@ -5598,7 +5679,7 @@ function parseEnvPairs(text) {
5598
5679
  }
5599
5680
 
5600
5681
  // src/main/tui/templates/TemplatesDialog.tsx
5601
- var import_react22 = __toESM(require_react(), 1);
5682
+ var import_react23 = __toESM(require_react(), 1);
5602
5683
 
5603
5684
  // src/main/tui/templates/model.ts
5604
5685
  var TEMPLATES_OVERLAY = "templates", SHIPPED_ORDER = ["standard", "sandboxed", "full-access"], INSTANTIATE_RULE = "New agents get everything in a template except its identity and history.", NAME_HINT = "Use letters, digits, dashes, underscores and spaces.", NAME_RULE = /^[A-Za-z0-9 _-]+$/;
@@ -5915,9 +5996,9 @@ function errorOf(err) {
5915
5996
  return { message: err instanceof Error ? err.message : String(err) };
5916
5997
  }
5917
5998
  function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
5918
- let theme2 = useTheme(), store = useStore(), { suspendTerminal } = use_app_default(), props = overlay.props ?? {}, slotKey = `${TEMPLATES_OVERLAY}.dialog:${overlay.id}`, initial = (0, import_react22.useRef)({ step: props.id ? { kind: "detail", id: props.id } : { kind: "list" }, index: 0, fileIndex: 0, list: null, detail: null, loadError: null, error: null }).current, read = () => store.getState().viewState[slotKey] ?? initial, patch = (next) => store.actions.setViewState(slotKey, { ...read(), ...next }), { step, index, fileIndex, list, detail, loadError, error } = useTuiSelector((s) => s.viewState[slotKey] ?? initial), setList = (value) => patch({ list: value }), setDetail = (value) => patch({ detail: value }), setLoadError = (value) => patch({ loadError: value }), setError = (value) => patch({ error: value }), setStep = (value) => patch({ step: value }), setIndex = (value) => patch({ index: value }), setFileIndex = (value) => patch({ fileIndex: value }), close = () => {
5999
+ let theme2 = useTheme(), store = useStore(), { suspendTerminal } = use_app_default(), props = overlay.props ?? {}, slotKey = `${TEMPLATES_OVERLAY}.dialog:${overlay.id}`, initial = (0, import_react23.useRef)({ step: props.id ? { kind: "detail", id: props.id } : { kind: "list" }, index: 0, fileIndex: 0, list: null, detail: null, loadError: null, error: null }).current, read = () => store.getState().viewState[slotKey] ?? initial, patch = (next) => store.actions.setViewState(slotKey, { ...read(), ...next }), { step, index, fileIndex, list, detail, loadError, error } = useTuiSelector((s) => s.viewState[slotKey] ?? initial), setList = (value) => patch({ list: value }), setDetail = (value) => patch({ detail: value }), setLoadError = (value) => patch({ loadError: value }), setError = (value) => patch({ error: value }), setStep = (value) => patch({ step: value }), setIndex = (value) => patch({ index: value }), setFileIndex = (value) => patch({ fileIndex: value }), close = () => {
5919
6000
  closeOverlay(), store.actions.setViewState(slotKey, null);
5920
- }, [values, setValues] = (0, import_react22.useState)({}), [errors, setErrors] = (0, import_react22.useState)({}), dialogWidth = Math.max(56, Math.min(width - 4, 104)), inner = dialogWidth - 4, templates = sortTemplates(list?.templates ?? []), byId = (id) => templates.find((t) => t.id === id), label2 = (id) => byId(id)?.name ?? id, loadList = async () => {
6001
+ }, [values, setValues] = (0, import_react23.useState)({}), [errors, setErrors] = (0, import_react23.useState)({}), dialogWidth = Math.max(56, Math.min(width - 4, 104)), inner = dialogWidth - 4, templates = sortTemplates(list?.templates ?? []), byId = (id) => templates.find((t) => t.id === id), label2 = (id) => byId(id)?.name ?? id, loadList = async () => {
5921
6002
  try {
5922
6003
  let next = await store.client.templates();
5923
6004
  patch({ list: next, loadError: null });
@@ -5934,11 +6015,11 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
5934
6015
  }, refresh2 = async (id) => {
5935
6016
  await loadList(), id && await loadDetail(id);
5936
6017
  };
5937
- (0, import_react22.useEffect)(() => {
6018
+ (0, import_react23.useEffect)(() => {
5938
6019
  !read().list && !read().loadError && refresh2(props.id);
5939
6020
  }, []);
5940
6021
  let stepId = "id" in step ? step.id : void 0;
5941
- (0, import_react22.useEffect)(() => {
6022
+ (0, import_react23.useEffect)(() => {
5942
6023
  (step.kind === "detail" || step.kind === "files") && step.id !== detail?.template?.id && loadDetail(step.id);
5943
6024
  }, [step.kind, stepId]);
5944
6025
  let act = async (labelText, back, fn) => {
@@ -6266,7 +6347,7 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
6266
6347
  }
6267
6348
 
6268
6349
  // src/main/tui/skills/SkillsDialog.tsx
6269
- var import_react23 = __toESM(require_react(), 1);
6350
+ var import_react24 = __toESM(require_react(), 1);
6270
6351
 
6271
6352
  // src/shared/utils/skill-preview.ts
6272
6353
  var skill_preview_exports = {};
@@ -6587,25 +6668,8 @@ function describeDiff(before, after, preview = 6) {
6587
6668
  return diff.changes.length > preview && lines.push(` \u2026 ${diff.changes.length - preview} more changed lines`), { summary, lines };
6588
6669
  }
6589
6670
 
6590
- // src/shared/types/resource-revision.types.ts
6591
- var resource_revision_types_exports = {};
6592
- __export(resource_revision_types_exports, {
6593
- describeWriter: () => describeWriter
6594
- });
6595
- function describeWriter(writer2) {
6596
- if (!writer2) return "someone else";
6597
- switch (writer2.kind) {
6598
- case "agent":
6599
- return "the agent";
6600
- case "cli":
6601
- return "the CLI or another API client";
6602
- case "client":
6603
- return writer2.client === "studio" ? "another Studio window" : writer2.client === "tui" ? "the terminal app" : `another client (${writer2.client})`;
6604
- }
6605
- }
6606
-
6607
6671
  // src/main/tui/util/revisions.ts
6608
- var { describeWriter: describeWriter2 } = cjs(resource_revision_types_exports);
6672
+ var { describeWriter } = cjs(resource_revision_types_exports);
6609
6673
  function revisionOf(result) {
6610
6674
  let revision = result?.revision;
6611
6675
  return typeof revision == "number" ? revision : void 0;
@@ -6616,7 +6680,7 @@ function staleRevisionOf(err) {
6616
6680
  return body?.code !== "stale_revision" || typeof body.revision != "number" ? null : { revision: body.revision, writer: body.writer ?? null };
6617
6681
  }
6618
6682
  function changedBy(stale) {
6619
- return `changed by ${describeWriter2(stale.writer)}`;
6683
+ return `changed by ${describeWriter(stale.writer)}`;
6620
6684
  }
6621
6685
  async function writeOver(write2) {
6622
6686
  try {
@@ -7101,7 +7165,7 @@ async function readLocalPackage(input, cwd = process.cwd()) {
7101
7165
  // src/main/tui/skills/SkillsDialog.tsx
7102
7166
  var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1), { catalogSourceLabel: catalogSourceLabel2, filterCatalogEntries: filterCatalogEntries2, mergeCatalogResults: mergeCatalogResults2, unindexedHint: unindexedHint2, MAX_SKILL_FILE_BYTES: MAX_SKILL_FILE_BYTES3 } = cjs(skills_panel_exports), { elideMiddle: elideMiddle2 } = cjs(skill_preview_exports), errorText3 = (err) => err instanceof Error ? err.message : String(err);
7103
7167
  function SkillsDialog({ overlay, close, width, height }) {
7104
- let theme2 = useTheme(), store = useStore(), { suspendTerminal } = use_app_default(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, direct = props.add !== void 0 || !!props.skill, fresh = (0, import_react23.useMemo)(() => {
7168
+ let theme2 = useTheme(), store = useStore(), { suspendTerminal } = use_app_default(), props = overlay.props ?? {}, agentId = props.agentId ?? store.getState().selectedAgentId ?? "", agent2 = useTuiSelector((s) => s.agents[agentId]), who = agent2?.summary.handle || agent2?.summary.name || agentId, direct = props.add !== void 0 || !!props.skill, fresh = (0, import_react24.useMemo)(() => {
7105
7169
  let start = initialStep(props);
7106
7170
  return { ...EMPTY_VIEW_STATE, overlayId: overlay.id, step: start.step, query: start.query, extra: start.extra };
7107
7171
  }, [overlay.id]), raw = useTuiSelector((s) => s.viewState[SKILLS_OVERLAY]), vs = raw && raw.overlayId === overlay.id ? raw : fresh, read = () => {
@@ -7113,13 +7177,13 @@ function SkillsDialog({ overlay, close, width, height }) {
7113
7177
  let base2 = read();
7114
7178
  store.actions.setViewState(SKILLS_OVERLAY, { ...base2, ...typeof next == "function" ? next(base2) : next, overlayId: overlay.id });
7115
7179
  };
7116
- (0, import_react23.useEffect)(() => {
7180
+ (0, import_react24.useEffect)(() => {
7117
7181
  (!raw || raw.overlayId !== overlay.id) && patch({});
7118
7182
  }, [overlay.id]);
7119
- let step = vs.step, setStep = (next) => patch({ step: next }), [data, setData] = (0, import_react23.useState)(null), [loadError, setLoadError] = (0, import_react23.useState)(null), alive = (0, import_react23.useRef)(!0);
7120
- (0, import_react23.useEffect)(() => () => {
7183
+ let step = vs.step, setStep = (next) => patch({ step: next }), [data, setData] = (0, import_react24.useState)(null), [loadError, setLoadError] = (0, import_react24.useState)(null), alive = (0, import_react24.useRef)(!0);
7184
+ (0, import_react24.useEffect)(() => () => {
7121
7185
  alive.current = !1;
7122
- }, []), (0, import_react23.useEffect)(() => {
7186
+ }, []), (0, import_react24.useEffect)(() => {
7123
7187
  if (!agentId) return;
7124
7188
  let cancelled = !1;
7125
7189
  return loadInstalled(store.client, agentId).then((next) => {
@@ -7130,13 +7194,13 @@ function SkillsDialog({ overlay, close, width, height }) {
7130
7194
  cancelled = !0;
7131
7195
  };
7132
7196
  }, [agentId, vs.rev]);
7133
- let model2 = (0, import_react23.useMemo)(() => data ? buildInstalled(data.files, data.registryText, vs.overrides) : null, [data, vs.overrides]), rows = (0, import_react23.useMemo)(() => model2 ? [
7197
+ let model2 = (0, import_react24.useMemo)(() => data ? buildInstalled(data.files, data.registryText, vs.overrides) : null, [data, vs.overrides]), rows = (0, import_react24.useMemo)(() => model2 ? [
7134
7198
  ...model2.skills.map((skill) => ({ type: "skill", key: `s:${skill.name}`, skill })),
7135
7199
  ...model2.problems.map((p) => ({ type: "problem", key: `p:${p.key}`, label: p.label, path: p.path, reason: p.reason, isPackage: p.isPackage }))
7136
7200
  ] : [], [model2]), bump = () => {
7137
7201
  patch((s) => ({ rev: s.rev + 1 })), setTimeout(() => patch((s) => ({ rev: s.rev + 1 })), 700);
7138
7202
  }, needsCatalog = step.kind === "catalog" || step.kind === "package" && step.source.type === "catalog";
7139
- (0, import_react23.useEffect)(() => {
7203
+ (0, import_react24.useEffect)(() => {
7140
7204
  if (!needsCatalog || read().catalog) return;
7141
7205
  let extra = read().extra;
7142
7206
  patch({ catalog: { loading: !0, sources: extra, results: [] } }), (async () => {
@@ -7151,18 +7215,18 @@ function SkillsDialog({ overlay, close, width, height }) {
7151
7215
  }
7152
7216
  })();
7153
7217
  }, [needsCatalog]);
7154
- let merged = (0, import_react23.useMemo)(() => mergeCatalogResults2(vs.catalog?.results ?? []), [vs.catalog?.results]), visible = (0, import_react23.useMemo)(() => filterCatalogEntries2(merged, vs.query), [merged, vs.query]), pkgKey = step.kind === "package" ? packageKey(step.source) : null, pkgState = pkgKey ? vs.packages[pkgKey] : void 0, loadPkg = (force = !1) => {
7218
+ let merged = (0, import_react24.useMemo)(() => mergeCatalogResults2(vs.catalog?.results ?? []), [vs.catalog?.results]), visible = (0, import_react24.useMemo)(() => filterCatalogEntries2(merged, vs.query), [merged, vs.query]), pkgKey = step.kind === "package" ? packageKey(step.source) : null, pkgState = pkgKey ? vs.packages[pkgKey] : void 0, loadPkg = (force = !1) => {
7155
7219
  if (step.kind !== "package" || !pkgKey || !force && read().packages[pkgKey]) return;
7156
7220
  let source = step.source;
7157
7221
  patch((s) => ({ packages: { ...s.packages, [pkgKey]: { status: "loading" } } })), loadPackage(source).then((result) => {
7158
7222
  patch((s) => ({ packages: { ...s.packages, [pkgKey]: result.ok ? { status: "ready", pkg: result.pkg } : { status: "error", error: result.error } } }));
7159
7223
  }, (err) => patch((s) => ({ packages: { ...s.packages, [pkgKey]: { status: "error", error: errorText3(err) } } })));
7160
7224
  };
7161
- (0, import_react23.useEffect)(() => {
7225
+ (0, import_react24.useEffect)(() => {
7162
7226
  loadPkg();
7163
7227
  }, [pkgKey]);
7164
- let [doc, setDoc] = (0, import_react23.useState)(null), viewPath = step.kind === "view" ? step.path : null;
7165
- (0, import_react23.useEffect)(() => {
7228
+ let [doc, setDoc] = (0, import_react24.useState)(null), viewPath = step.kind === "view" ? step.path : null;
7229
+ (0, import_react24.useEffect)(() => {
7166
7230
  if (!viewPath || !agentId) return;
7167
7231
  let cancelled = !1;
7168
7232
  return readSkillFile(store.client, agentId, viewPath).then(
@@ -7399,7 +7463,7 @@ function CatalogRow({ entry, installed, selected, width }) {
7399
7463
  ] });
7400
7464
  }
7401
7465
  function SkillDoc({ manifest, width, height }) {
7402
- let theme2 = useTheme(), parts = (0, import_react23.useMemo)(() => previewParts(manifest), [manifest]), [offset, setOffset] = (0, import_react23.useState)(0), innerRef = (0, import_react23.useRef)(null), outerRef = (0, import_react23.useRef)(null), metrics = use_box_metrics_default(innerRef), rows = Math.max(1, height - 1), total = metrics.hasMeasured ? metrics.height : 0, maxOffset = Math.max(0, total - rows), at = Math.min(offset, maxOffset), move = (next) => setOffset(Math.max(0, Math.min(maxOffset, next)));
7466
+ let theme2 = useTheme(), parts = (0, import_react24.useMemo)(() => previewParts(manifest), [manifest]), [offset, setOffset] = (0, import_react24.useState)(0), innerRef = (0, import_react24.useRef)(null), outerRef = (0, import_react24.useRef)(null), metrics = use_box_metrics_default(innerRef), rows = Math.max(1, height - 1), total = metrics.hasMeasured ? metrics.height : 0, maxOffset = Math.max(0, total - rows), at = Math.min(offset, maxOffset), move = (next) => setOffset(Math.max(0, Math.min(maxOffset, next)));
7403
7467
  useWheel(outerRef, (delta) => move(at + delta * WHEEL_STEP), { layer: "overlay" }), useKeys((input, key) => key.upArrow || input === "k" && !key.ctrl ? (move(at - 1), !0) : key.downArrow || input === "j" && !key.ctrl ? (move(at + 1), !0) : key.pageUp ? (move(at - rows), !0) : key.pageDown ? (move(at + rows), !0) : key.home || input === "g" ? (move(0), !0) : key.end || input === "G" ? (move(maxOffset), !0) : !1, { layer: "overlay" });
7404
7468
  let keyWidth = Math.min(16, Math.max(4, ...parts.fields.map((f) => f.key.length)) + 1);
7405
7469
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Box_default, { ref: outerRef, flexDirection: "column", width, height, marginTop: 1, children: [
@@ -7416,7 +7480,7 @@ function SkillDoc({ manifest, width, height }) {
7416
7480
  }
7417
7481
 
7418
7482
  // src/main/tui/context/ContextDialog.tsx
7419
- var import_react24 = __toESM(require_react(), 1);
7483
+ var import_react25 = __toESM(require_react(), 1);
7420
7484
 
7421
7485
  // src/main/tui/context/model.ts
7422
7486
  var { resolveLoopThreshold, calibrationNote } = cjs(context_breakdown_exports), CONTEXT_OVERLAY = "context";
@@ -7486,7 +7550,7 @@ function pressureColor(theme2, percent) {
7486
7550
  return p === "high" ? theme2.color.error : p === "warn" ? theme2.color.warn : theme2.color.success;
7487
7551
  }
7488
7552
  function ContextDialog({ overlay, close: closeOverlay, width, height }) {
7489
- let theme2 = useTheme(), store = useStore(), g = theme2.glyph, props = overlay.props ?? {}, agentId = props.agentId ?? "", slotKey = `${CONTEXT_OVERLAY}.dialog:${overlay.id}`, initial = (0, import_react24.useRef)({ loop: props.loop || MAIN_LOOP, data: null, error: null, loading: !1, compacting: !1, cursor: null, expanded: null, start: 0, measuredAt: null }).current, read = () => store.getState().viewState[slotKey] ?? initial, alive = () => store.getState().overlays.some((o) => o.id === overlay.id), patch = (next) => {
7553
+ let theme2 = useTheme(), store = useStore(), g = theme2.glyph, props = overlay.props ?? {}, agentId = props.agentId ?? "", slotKey = `${CONTEXT_OVERLAY}.dialog:${overlay.id}`, initial = (0, import_react25.useRef)({ loop: props.loop || MAIN_LOOP, data: null, error: null, loading: !1, compacting: !1, cursor: null, expanded: null, start: 0, measuredAt: null }).current, read = () => store.getState().viewState[slotKey] ?? initial, alive = () => store.getState().overlays.some((o) => o.id === overlay.id), patch = (next) => {
7490
7554
  alive() && store.actions.setViewState(slotKey, { ...read(), ...next });
7491
7555
  }, s = useTuiSelector((state) => state.viewState[slotKey] ?? initial), agent2 = useTuiSelector((state) => state.agents[agentId]), close = () => {
7492
7556
  closeOverlay(), store.actions.setViewState(slotKey, null);
@@ -7504,7 +7568,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
7504
7568
  }
7505
7569
  }
7506
7570
  };
7507
- (0, import_react24.useEffect)(() => {
7571
+ (0, import_react25.useEffect)(() => {
7508
7572
  !read().data && !read().error && load(read().loop), agentId && !store.getState().agents[agentId]?.loops && store.actions.refreshLoops(agentId);
7509
7573
  }, []);
7510
7574
  let compact2 = async () => {
@@ -7518,7 +7582,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
7518
7582
  let done = await store.actions.compactLoop(agentId, loop);
7519
7583
  patch({ compacting: !1 }), done && await load(loop);
7520
7584
  }, categories = s.data?.categories ?? [], cursor = categoryIndex(categories, s.cursor), selected = categories[cursor], rows = contextRows(categories, s.expanded), cursorRow = rows.findIndex((r) => r.kind === "category" && r.category.id === selected?.id), dialogWidth = Math.max(40, Math.min(width - 4, 96)), inner = dialogWidth - 4, rowsHeight = Math.max(3, height - 16), start = windowStart(rows.length, Math.max(0, cursorRow), rowsHeight, s.start);
7521
- (0, import_react24.useEffect)(() => {
7585
+ (0, import_react25.useEffect)(() => {
7522
7586
  start !== s.start && patch({ start });
7523
7587
  }, [start]), useKeys((input, key) => {
7524
7588
  if (key.escape) return !1;
@@ -7729,7 +7793,7 @@ async function copySiteUrl(store, agentId) {
7729
7793
  }
7730
7794
 
7731
7795
  // src/main/tui/app/Shell.tsx
7732
- var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1), SIDEBAR_MIN_COLUMNS = 70, PROMPT_ROWS = 3, RESIZE_SETTLE_MS = 150, CLEAR_SCREEN = "\x1B[2J\x1B[H", DOUBLE_ESC_MS = 600, ViewErrorBoundary = class extends import_react25.Component {
7796
+ var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1), SIDEBAR_MIN_COLUMNS = 70, PROMPT_ROWS = 3, RESIZE_SETTLE_MS = 150, CLEAR_SCREEN = "\x1B[2J\x1B[H", DOUBLE_ESC_MS = 600, ViewErrorBoundary = class extends import_react26.Component {
7733
7797
  state = { error: null };
7734
7798
  static getDerivedStateFromError(error) {
7735
7799
  return { error };
@@ -7760,8 +7824,8 @@ function cycleLoop2(store, delta) {
7760
7824
  store.actions.selectLoop(agentId, loops2[(at + delta + loops2.length) % loops2.length].info.name);
7761
7825
  }
7762
7826
  function Shell() {
7763
- let theme2 = useTheme(), store = useStore(), router = useKeyRouter(), { views, exit, reserveRows = 0, reserveColumns = 0 } = useShell(), { columns: windowColumns, rows: windowRows } = use_window_size_default(), columns = Math.max(20, windowColumns - reserveColumns), rows = Math.max(6, windowRows - reserveRows), { write: write2 } = use_stdout_default(), { waitUntilRenderFlush } = use_app_default(), sized = (0, import_react25.useRef)(`${windowColumns}x${windowRows}`);
7764
- (0, import_react25.useEffect)(() => {
7827
+ let theme2 = useTheme(), store = useStore(), router = useKeyRouter(), { views, exit, reserveRows = 0, reserveColumns = 0 } = useShell(), { columns: windowColumns, rows: windowRows } = use_window_size_default(), columns = Math.max(20, windowColumns - reserveColumns), rows = Math.max(6, windowRows - reserveRows), { write: write2 } = use_stdout_default(), { waitUntilRenderFlush } = use_app_default(), sized = (0, import_react26.useRef)(`${windowColumns}x${windowRows}`);
7828
+ (0, import_react26.useEffect)(() => {
7765
7829
  let size = `${windowColumns}x${windowRows}`;
7766
7830
  if (sized.current === size) return;
7767
7831
  sized.current = size;
@@ -7774,23 +7838,23 @@ function Shell() {
7774
7838
  cancelled = !0, clearTimeout(timer);
7775
7839
  };
7776
7840
  }, [windowColumns, windowRows]);
7777
- let activeView = useActiveView(), focus = useFocus(), overlays = useOverlays(), toasts = useToasts(), viewRef = (0, import_react25.useRef)(null), sidebarRef = (0, import_react25.useRef)(null), promptRef = (0, import_react25.useRef)(null), sidebarHidden = useTuiSelector((s) => readLayout(s).sidebarHidden), headerRef = (0, import_react25.useRef)(null), headerHits = (0, import_react25.useMemo)(() => createHeaderHits(), []), metrics = use_box_metrics_default(viewRef), quitGuard = (0, import_react25.useMemo)(() => createQuitGuard(), []), lastEscAt = (0, import_react25.useRef)(0), view2 = views.find((v) => v.id === activeView) ?? views[0], showSidebar = !!view2 && !view2.fullWidth && !sidebarHidden && columns >= SIDEBAR_MIN_COLUMNS, sidebarWidth = Math.max(22, Math.min(34, Math.floor(columns * 0.24))), mainWidth = Math.max(10, columns - (showSidebar ? sidebarWidth : 0)), promptShown = !!view2 && view2.prompt !== !1, toastRows = Math.min(3, toasts.length), bodyHeight = Math.max(3, rows - 2 - toastRows), viewHeight = metrics.hasMeasured ? metrics.height : Math.max(1, bodyHeight - (promptShown ? PROMPT_ROWS : 0)), viewWidth = metrics.hasMeasured ? metrics.width : mainWidth, overlayOpen = overlays.length > 0, zones = [...showSidebar ? ["sidebar"] : [], "main", ...promptShown ? ["input"] : []];
7778
- (0, import_react25.useEffect)(() => {
7841
+ let activeView = useActiveView(), focus = useFocus(), overlays = useOverlays(), toasts = useToasts(), viewRef = (0, import_react26.useRef)(null), sidebarRef = (0, import_react26.useRef)(null), promptRef = (0, import_react26.useRef)(null), sidebarHidden = useTuiSelector((s) => readLayout(s).sidebarHidden), headerRef = (0, import_react26.useRef)(null), headerHits = (0, import_react26.useMemo)(() => createHeaderHits(), []), metrics = use_box_metrics_default(viewRef), quitGuard = (0, import_react26.useMemo)(() => createQuitGuard(), []), lastEscAt = (0, import_react26.useRef)(0), view2 = views.find((v) => v.id === activeView) ?? views[0], showSidebar = !!view2 && !view2.fullWidth && !sidebarHidden && columns >= SIDEBAR_MIN_COLUMNS, sidebarWidth = Math.max(22, Math.min(34, Math.floor(columns * 0.24))), mainWidth = Math.max(10, columns - (showSidebar ? sidebarWidth : 0)), promptShown = !!view2 && view2.prompt !== !1, toastRows = Math.min(3, toasts.length), bodyHeight = Math.max(3, rows - 2 - toastRows), viewHeight = metrics.hasMeasured ? metrics.height : Math.max(1, bodyHeight - (promptShown ? PROMPT_ROWS : 0)), viewWidth = metrics.hasMeasured ? metrics.width : mainWidth, overlayOpen = overlays.length > 0, zones = [...showSidebar ? ["sidebar"] : [], "main", ...promptShown ? ["input"] : []];
7842
+ (0, import_react26.useEffect)(() => {
7779
7843
  focus !== "tabs" && !zones.includes(focus) && store.actions.setFocus("main");
7780
- }, [focus, showSidebar, promptShown]), (0, import_react25.useEffect)(() => {
7844
+ }, [focus, showSidebar, promptShown]), (0, import_react26.useEffect)(() => {
7781
7845
  store.getState().viewState[TABS_CURSOR_KEY] && store.actions.setViewState(TABS_CURSOR_KEY, null);
7782
7846
  }, [activeView]);
7783
- let enterZone = (id) => id === "chat" && views.find((v) => v.id === id)?.prompt !== !1 ? "input" : "main", live = (0, import_react25.useRef)({ columns: windowColumns, rows: windowRows, promptShown });
7847
+ let enterZone = (id) => id === "chat" && views.find((v) => v.id === id)?.prompt !== !1 ? "input" : "main", live = (0, import_react26.useRef)({ columns: windowColumns, rows: windowRows, promptShown });
7784
7848
  live.current = { columns: windowColumns, rows: windowRows, promptShown };
7785
7849
  let { internal_eventEmitter: stdinEvents } = use_stdin_default();
7786
- (0, import_react25.useLayoutEffect)(() => {
7850
+ (0, import_react26.useLayoutEffect)(() => {
7787
7851
  if (!stdinEvents) return;
7788
7852
  let onInput = (data) => noteRawInput(typeof data == "string" ? data : String(data));
7789
7853
  return stdinEvents.prependListener("input", onInput), () => {
7790
7854
  stdinEvents.removeListener("input", onInput);
7791
7855
  };
7792
- }, [stdinEvents]), (0, import_react25.useEffect)(() => (setRepaint(() => write2("")), () => setRepaint(null)), [write2]);
7793
- let mouseCtl = (0, import_react25.useMemo)(() => createMouseController({
7856
+ }, [stdinEvents]), (0, import_react26.useEffect)(() => (setRepaint(() => write2("")), () => setRepaint(null)), [write2]);
7857
+ let mouseCtl = (0, import_react26.useMemo)(() => createMouseController({
7794
7858
  now: () => Date.now(),
7795
7859
  screen: getScreenText,
7796
7860
  paneAt: (x, y) => {
@@ -8781,10 +8845,10 @@ var url = {
8781
8845
  ], BUILTIN_COMMANDS = { commands, actions };
8782
8846
 
8783
8847
  // src/main/tui/ui/Table.tsx
8784
- var import_react26 = __toESM(require_react(), 1);
8848
+ var import_react27 = __toESM(require_react(), 1);
8785
8849
  var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
8786
8850
  function Table({ columns, rows, getKey, width, selectedIndex, height, emptyText = "No rows.", onWheel }) {
8787
- let theme2 = useTheme(), boxRef = (0, import_react26.useRef)(null);
8851
+ let theme2 = useTheme(), boxRef = (0, import_react27.useRef)(null);
8788
8852
  useWheel(boxRef, (delta) => onWheel?.(delta), { active: !!onWheel });
8789
8853
  let gap = 1, fixed = columns.reduce((sum, c) => sum + (c.width ?? 0), 0), flexible = columns.filter((c) => c.width === void 0), spare = Math.max(0, width - fixed - gap * (columns.length - 1) - 2), share = flexible.length ? Math.floor(spare / flexible.length) : 0, widths = columns.map((c) => c.width ?? Math.max(c.minWidth ?? 6, share)), bodyRows = height === void 0 ? rows.length : Math.max(0, height - 1), selected = selectedIndex ?? -1, start = selected >= bodyRows ? selected - bodyRows + 1 : 0, visible = rows.slice(start, start + bodyRows), line = (cells2) => cells2.join(" ".repeat(gap));
8790
8854
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Box_default, { ref: boxRef, flexDirection: "column", width, children: [
@@ -9155,12 +9219,12 @@ var agentsCommand = {
9155
9219
  };
9156
9220
 
9157
9221
  // src/main/tui/views/fleet/LoadDialog.tsx
9158
- var import_react27 = __toESM(require_react(), 1);
9222
+ var import_react28 = __toESM(require_react(), 1);
9159
9223
  import { existsSync as existsSync2, statSync as statSync2 } from "node:fs";
9160
9224
  import { sep as sep2 } from "node:path";
9161
9225
  var import_jsx_runtime33 = __toESM(require_jsx_runtime(), 1), LAST_DIR_KEY = "fleet.load.lastDir", MAX_CANDIDATES = 8;
9162
9226
  function LoadDialog({ overlay, close, width }) {
9163
- let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, [lastDir, setLastDir] = useViewState(LAST_DIR_KEY, ""), [value, setValue] = (0, import_react27.useState)(props.path ?? (lastDir || `${process.cwd()}${sep2}`)), [candidates, setCandidates] = (0, import_react27.useState)([]), [requireReview, setRequireReview] = (0, import_react27.useState)(!!props.requireReview), [start, setStart] = (0, import_react27.useState)(!!props.start), [problem, setProblem] = (0, import_react27.useState)(null), [warned, setWarned] = (0, import_react27.useState)(null), dialogWidth = Math.max(40, Math.min(width - 4, 90)), submit = (text) => {
9227
+ let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, [lastDir, setLastDir] = useViewState(LAST_DIR_KEY, ""), [value, setValue] = (0, import_react28.useState)(props.path ?? (lastDir || `${process.cwd()}${sep2}`)), [candidates, setCandidates] = (0, import_react28.useState)([]), [requireReview, setRequireReview] = (0, import_react28.useState)(!!props.requireReview), [start, setStart] = (0, import_react28.useState)(!!props.start), [problem, setProblem] = (0, import_react28.useState)(null), [warned, setWarned] = (0, import_react28.useState)(null), dialogWidth = Math.max(40, Math.min(width - 4, 90)), submit = (text) => {
9164
9228
  let raw = text.trim();
9165
9229
  if (!raw)
9166
9230
  return setProblem("Type a path to an .adf file"), !1;
@@ -9243,11 +9307,11 @@ function LoadDialog({ overlay, close, width }) {
9243
9307
  }
9244
9308
 
9245
9309
  // src/main/tui/views/fleet/TrackDialog.tsx
9246
- var import_react29 = __toESM(require_react(), 1);
9310
+ var import_react30 = __toESM(require_react(), 1);
9247
9311
  import { sep as sep3 } from "node:path";
9248
9312
 
9249
9313
  // src/main/tui/views/fleet/FolderAgentsDialog.tsx
9250
- var import_react28 = __toESM(require_react(), 1);
9314
+ var import_react29 = __toESM(require_react(), 1);
9251
9315
  var import_jsx_runtime34 = __toESM(require_jsx_runtime(), 1);
9252
9316
  function glyphOf(theme2, agent2) {
9253
9317
  if (agent2.error || agent2.status === "unreadable") return { glyph: theme2.glyph.cross, color: theme2.color.error };
@@ -9271,8 +9335,8 @@ function reviewLines2(info) {
9271
9335
  return triggers.length && lines.push(`Triggers: ${triggers.join(", ")}`), lines;
9272
9336
  }
9273
9337
  function FolderAgentsDialog({ overlay, close, width, height }) {
9274
- let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, folder = props.folder, [agents, setAgents] = (0, import_react28.useState)(props.result?.agents ?? null), [loadError, setLoadError] = (0, import_react28.useState)(null), [cursor, setCursor] = (0, import_react28.useState)(0), [mode, setMode] = (0, import_react28.useState)({ kind: "list" }), [busy, setBusy] = (0, import_react28.useState)(null), [note, setNote] = (0, import_react28.useState)(null), [rev, setRev] = (0, import_react28.useState)(props.result?.agents ? 0 : 1), [pendingReview, setPendingReview] = (0, import_react28.useState)(props.review ?? null), [errors, setErrors] = (0, import_react28.useState)(() => Object.fromEntries((props.result?.agents ?? []).filter((a) => a.error && a.status !== "unreadable").map((a) => [a.filePath, a.error]))), dialogWidth = Math.max(44, Math.min(width - 4, 100)), inner = dialogWidth - 4;
9275
- (0, import_react28.useEffect)(() => {
9338
+ let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, folder = props.folder, [agents, setAgents] = (0, import_react29.useState)(props.result?.agents ?? null), [loadError, setLoadError] = (0, import_react29.useState)(null), [cursor, setCursor] = (0, import_react29.useState)(0), [mode, setMode] = (0, import_react29.useState)({ kind: "list" }), [busy, setBusy] = (0, import_react29.useState)(null), [note, setNote] = (0, import_react29.useState)(null), [rev, setRev] = (0, import_react29.useState)(props.result?.agents ? 0 : 1), [pendingReview, setPendingReview] = (0, import_react29.useState)(props.review ?? null), [errors, setErrors] = (0, import_react29.useState)(() => Object.fromEntries((props.result?.agents ?? []).filter((a) => a.error && a.status !== "unreadable").map((a) => [a.filePath, a.error]))), dialogWidth = Math.max(44, Math.min(width - 4, 100)), inner = dialogWidth - 4;
9339
+ (0, import_react29.useEffect)(() => {
9276
9340
  if (rev === 0) return;
9277
9341
  let live = !0;
9278
9342
  return store.client.folderAgents(folder).then(
@@ -9287,7 +9351,7 @@ function FolderAgentsDialog({ overlay, close, width, height }) {
9287
9351
  };
9288
9352
  }, [rev, folder]);
9289
9353
  let rows = (agents ?? []).map((a) => a.status !== "loaded" && !a.error && errors[a.filePath] ? { ...a, error: errors[a.filePath] } : a), at = Math.min(cursor, Math.max(0, rows.length - 1)), selected = rows[at];
9290
- (0, import_react28.useEffect)(() => {
9354
+ (0, import_react29.useEffect)(() => {
9291
9355
  if (!pendingReview || !agents) return;
9292
9356
  let index = rows.findIndex((r) => r.filePath === pendingReview);
9293
9357
  setPendingReview(null), !(index < 0) && (setCursor(index), rows[index].status === "needs_review" && openReview(rows[index]));
@@ -9433,7 +9497,7 @@ function TrackDialog(props) {
9433
9497
  return props.overlay.props?.folder ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(FolderAgentsDialog, { ...props }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TrackFolderInput, { ...props });
9434
9498
  }
9435
9499
  function TrackFolderInput({ overlay, close, width }) {
9436
- let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, [lastDir, setLastDir] = useViewState(LAST_DIR_KEY2, ""), [value, setValue] = (0, import_react29.useState)(props.path ?? (lastDir || `${process.cwd()}${sep3}`)), [candidates, setCandidates] = (0, import_react29.useState)([]), [problem, setProblem] = (0, import_react29.useState)(null), [busy, setBusy] = (0, import_react29.useState)(!1), dialogWidth = Math.max(40, Math.min(width - 4, 90)), submit = (text) => {
9500
+ let theme2 = useTheme(), store = useStore(), props = overlay.props ?? {}, [lastDir, setLastDir] = useViewState(LAST_DIR_KEY2, ""), [value, setValue] = (0, import_react30.useState)(props.path ?? (lastDir || `${process.cwd()}${sep3}`)), [candidates, setCandidates] = (0, import_react30.useState)([]), [problem, setProblem] = (0, import_react30.useState)(null), [busy, setBusy] = (0, import_react30.useState)(!1), dialogWidth = Math.max(40, Math.min(width - 4, 90)), submit = (text) => {
9437
9501
  if (busy) return !1;
9438
9502
  let raw = text.trim();
9439
9503
  if (!raw)
@@ -9502,10 +9566,10 @@ function TrackFolderInput({ overlay, close, width }) {
9502
9566
  }
9503
9567
 
9504
9568
  // src/main/tui/views/fleet/UntrackDialog.tsx
9505
- var import_react30 = __toESM(require_react(), 1);
9569
+ var import_react31 = __toESM(require_react(), 1);
9506
9570
  var import_jsx_runtime36 = __toESM(require_jsx_runtime(), 1);
9507
9571
  function UntrackDialog({ overlay, close, width }) {
9508
- let theme2 = useTheme(), store = useStore(), path = String(overlay.props?.path ?? ""), [unload, setUnload] = (0, import_react30.useState)(!1);
9572
+ let theme2 = useTheme(), store = useStore(), path = String(overlay.props?.path ?? ""), [unload, setUnload] = (0, import_react31.useState)(!1);
9509
9573
  return useKeys((input, key) => key.return || input === "y" || input === "Y" ? (close(), untrackFolder(store, path, unload), !0) : key.escape || input === "n" || input === "N" || key.ctrl && input === "c" ? (close(), !0) : ((input === "u" || input === " ") && setUnload((v) => !v), !0), { layer: "overlay" }), /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
9510
9574
  Modal,
9511
9575
  {
@@ -9899,16 +9963,33 @@ var fleet = {
9899
9963
  }, fleet_default = fleet;
9900
9964
 
9901
9965
  // src/main/tui/views/chat/index.tsx
9902
- var import_react35 = __toESM(require_react(), 1);
9966
+ var import_react36 = __toESM(require_react(), 1);
9903
9967
 
9904
9968
  // src/main/tui/views/chat/Transcript.tsx
9905
- var import_react31 = __toESM(require_react(), 1);
9969
+ var import_react32 = __toESM(require_react(), 1);
9906
9970
  var import_jsx_runtime38 = __toESM(require_jsx_runtime(), 1);
9907
9971
  function lineCount(text) {
9908
9972
  return text ? text.split(`
9909
9973
  `).length : 0;
9910
9974
  }
9911
- function ToolBody({ item, w, expanded }) {
9975
+ function AskForm({ questions, answers }) {
9976
+ let theme2 = useTheme(), g = theme2.glyph;
9977
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_jsx_runtime38.Fragment, { children: questions.map((q, i) => {
9978
+ let answer = answers?.[i];
9979
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", children: [
9980
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: q.question || " " }),
9981
+ answers ? answer != null ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.user, children: [
9982
+ g.pointer,
9983
+ " ",
9984
+ oneLine(answer) || "(empty)"
9985
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: [
9986
+ g.pointer,
9987
+ " skipped"
9988
+ ] }) : null
9989
+ ] }, i);
9990
+ }) });
9991
+ }
9992
+ function ToolBody({ item, w, expanded, viewportHeight, clipBottom = 0 }) {
9912
9993
  let theme2 = useTheme(), g = theme2.glyph, view2 = toolView(item), failed = item.status === "error", status = item.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Spinner, { color: theme2.color.tool }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: failed ? theme2.color.error : theme2.color.success, children: failed ? g.cross : g.check }), asyncBadge = isAsyncTool(item) ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: theme2.color.dim, children: " [async]" }) : null;
9913
9994
  if (expanded && isExpandable(item)) {
9914
9995
  let input = capLines(prettyJson(item.input), EXPANDED_TOOL_LINES), ref = shownTaskRef(item), task = ref !== void 0 ? capLines(ref, EXPANDED_TOOL_LINES) : null, result2 = capLines(item.result ?? "", EXPANDED_TOOL_LINES);
@@ -9959,7 +10040,7 @@ ${g.ellipsis} ${result2.more} more lines` : ""
9959
10040
  " "
9960
10041
  ] }),
9961
10042
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { width: w - 2, flexDirection: "column", children: [
9962
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: sayText(item) || " ", color: theme2.color.assistant }),
10043
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: sayText(item) || " ", color: theme2.color.assistant, viewport: viewportHeight === void 0 ? void 0 : { width: w - 2, height: viewportHeight + 2, clipBottom: Math.max(0, clipBottom - 1 - (failed ? 1 : 0)) } }),
9963
10044
  failed ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.error, children: [
9964
10045
  g.cross,
9965
10046
  " say failed: ",
@@ -9969,7 +10050,7 @@ ${g.ellipsis} ${result2.more} more lines` : ""
9969
10050
  ] })
9970
10051
  ] });
9971
10052
  case "ask": {
9972
- let pending = item.status === "running", answer = askAnswer(item), reason2 = toolReason(item);
10053
+ let pending = item.status === "running", answers = askAnswers(item), reason2 = toolReason(item);
9973
10054
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", width: w, borderStyle: theme2.ascii ? "classic" : "single", borderLeft: !0, borderRight: !1, borderTop: !1, borderBottom: !1, borderColor: pending ? theme2.color.warn : theme2.color.dim, paddingLeft: 1, children: [
9974
10055
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", children: [
9975
10056
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { bold: !0, color: pending ? theme2.color.warn : theme2.color.muted, children: [
@@ -9983,11 +10064,11 @@ ${g.ellipsis} ${result2.more} more lines` : ""
9983
10064
  reason2
9984
10065
  ] }) : null
9985
10066
  ] }),
9986
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: askQuestion(item.input) || " " }),
9987
- answer !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: failed ? theme2.color.error : theme2.color.user, children: [
9988
- failed ? g.cross : g.pointer,
10067
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(AskForm, { questions: askQuestions(item.input), answers }),
10068
+ item.result !== void 0 && !answers ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.error, children: [
10069
+ g.cross,
9989
10070
  " ",
9990
- oneLine(answer) || "(empty)"
10071
+ oneLine(item.result) || "(no detail)"
9991
10072
  ] }) : null
9992
10073
  ] });
9993
10074
  }
@@ -10045,7 +10126,7 @@ ${g.ellipsis} ${result2.more} more lines` : ""
10045
10126
  ] }) : null
10046
10127
  ] });
10047
10128
  }
10048
- function ItemBody({ item, width, expanded, showThinking, queued }) {
10129
+ function ItemBody({ item, width, expanded, showThinking, queued, viewportHeight, clipBottom = 0 }) {
10049
10130
  let theme2 = useTheme(), g = theme2.glyph, w = Math.max(8, width);
10050
10131
  switch (item.kind) {
10051
10132
  case "user": {
@@ -10106,7 +10187,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10106
10187
  " "
10107
10188
  ] }),
10108
10189
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { width: w - 2, flexDirection: "column", children: [
10109
- item.text ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: item.text, color: theme2.color.assistant }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { children: " " }),
10190
+ item.text ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: item.text, color: theme2.color.assistant, viewport: viewportHeight === void 0 ? void 0 : { width: w - 2, height: viewportHeight + 2, clipBottom: Math.max(0, clipBottom - 1 - (item.interrupted ? 1 : 0)) } }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { children: " " }),
10110
10191
  item.interrupted ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: theme2.color.dim, children: "[interrupted]" }) : null
10111
10192
  ] })
10112
10193
  ] });
@@ -10130,7 +10211,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10130
10211
  ] });
10131
10212
  }
10132
10213
  case "tool":
10133
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ToolBody, { item, w, expanded });
10214
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ToolBody, { item, w, expanded, viewportHeight, clipBottom });
10134
10215
  case "hil": {
10135
10216
  let tone = item.status === "pending" ? theme2.color.warn : item.status === "approved" || item.status === "completed" ? theme2.color.success : theme2.color.error;
10136
10217
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", width: w, borderStyle: theme2.ascii ? "classic" : "single", borderLeft: !0, borderRight: !1, borderTop: !1, borderBottom: !1, borderColor: tone, paddingLeft: 1, children: [
@@ -10168,12 +10249,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10168
10249
  "? ",
10169
10250
  item.status === "pending" ? "the agent asks you" : "answered"
10170
10251
  ] }),
10171
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: item.question }),
10172
- item.answer ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.user, children: [
10173
- g.pointer,
10174
- " ",
10175
- item.answer
10176
- ] }) : null
10252
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(AskForm, { questions: item.questions })
10177
10253
  ] });
10178
10254
  case "notice":
10179
10255
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: item.level === "warn" ? theme2.color.warn : item.event === "marker" ? theme2.color.info : theme2.color.muted, children: [
@@ -10238,7 +10314,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10238
10314
  ] });
10239
10315
  }
10240
10316
  }
10241
- var TranscriptItemView = (0, import_react31.memo)(function(props) {
10317
+ var TranscriptItemView = (0, import_react32.memo)(function(props) {
10242
10318
  let theme2 = useTheme(), gap = props.item.kind === "notice" || props.item.kind === "context" && !props.expanded ? 0 : 1;
10243
10319
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Box_default, { flexDirection: "row", width: props.width, marginBottom: gap, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
10244
10320
  Box_default,
@@ -10302,7 +10378,7 @@ function LoopTabs({ agentLabel: agentLabel5, tabs, selected, unseen, pending, wi
10302
10378
  }
10303
10379
 
10304
10380
  // src/main/tui/views/chat/Dock.tsx
10305
- var import_react32 = __toESM(require_react(), 1);
10381
+ var import_react33 = __toESM(require_react(), 1);
10306
10382
 
10307
10383
  // src/main/tui/views/chat/approvals.ts
10308
10384
  var FEEDBACK_OVERLAY = "chat.deny";
@@ -10326,7 +10402,11 @@ var import_jsx_runtime40 = __toESM(require_jsx_runtime(), 1);
10326
10402
  function topCard(model2) {
10327
10403
  return model2.tasks.length > 0 ? "hil" : model2.asks.length > 0 ? "ask" : model2.suspended ? "suspend" : null;
10328
10404
  }
10329
- var ASK_LINES = 3;
10405
+ var ASK_LINES = 3, ASK_OPTIONS = 6;
10406
+ function askRows(ask, answers, inner) {
10407
+ let { question } = askStep(ask, answers), options = question.options?.length ?? 0, optionRows = Math.min(options, ASK_OPTIONS) + (options > ASK_OPTIONS ? 1 : 0);
10408
+ return 1 + Math.min(ASK_LINES, wrappedHeight(question.question || " ", inner)) + optionRows + 1 + 1;
10409
+ }
10330
10410
  function taskReason(task) {
10331
10411
  let meta = task.approval_meta;
10332
10412
  if (meta)
@@ -10338,7 +10418,7 @@ function dockHeight(model2, width) {
10338
10418
  case "hil":
10339
10419
  return queued + 2 + 3 + (taskReason(model2.tasks[0]) ? 1 : 0);
10340
10420
  case "ask":
10341
- return queued + 2 + 2 + Math.min(ASK_LINES, wrappedHeight(model2.asks[0].question || " ", Math.max(8, width - 4)));
10421
+ return queued + 2 + askRows(model2.asks[0], model2.askAnswers ?? [], Math.max(8, width - 4));
10342
10422
  case "suspend":
10343
10423
  return queued + 2 + 2;
10344
10424
  default:
@@ -10346,7 +10426,7 @@ function dockHeight(model2, width) {
10346
10426
  }
10347
10427
  }
10348
10428
  function ActionRow({ buttons: all, focused, width, onAction }) {
10349
- let theme2 = useTheme(), ref = (0, import_react32.useRef)(null), sep4 = ` ${theme2.glyph.sep} `, prefix = focused ? "" : "Shift+Tab: ", spans = [], x = displayWidth(prefix);
10429
+ let theme2 = useTheme(), ref = (0, import_react33.useRef)(null), sep4 = ` ${theme2.glyph.sep} `, prefix = focused ? "" : "Shift+Tab: ", spans = [], x = displayWidth(prefix);
10350
10430
  for (let [i, button] of all.entries()) {
10351
10431
  let text = button.off ? `${button.label}: one-time only` : `${keyLabel(button.keys)} ${button.label}`, start = x + (i > 0 ? displayWidth(sep4) : 0);
10352
10432
  if (start + displayWidth(text) > width) break;
@@ -10423,21 +10503,56 @@ function Dock({ model: model2, width, focused, agentLabel: agentLabel5, onAction
10423
10503
  ].sort((a, b) => (a.off ? 1 : 0) - (b.off ? 1 : 0)))
10424
10504
  ] }));
10425
10505
  })() : null,
10426
- card === "ask" ? border(theme2.color.warn, /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
10427
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { wrap: "truncate-end", bold: !0, color: theme2.color.warn, children: [
10428
- "? ",
10429
- agentLabel5,
10430
- " asks you",
10431
- model2.asks.length > 1 ? ` (+${model2.asks.length - 1} more)` : ""
10432
- ] }),
10433
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box_default, { height: Math.min(ASK_LINES, wrappedHeight(model2.asks[0].question || " ", inner)), overflow: "hidden", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: model2.asks[0].question }) }),
10434
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: [
10435
- "Type the answer in the prompt ",
10436
- g.sep,
10437
- " Enter sends it to the agent ",
10438
- focused ? `${g.sep} a to focus the prompt` : ""
10439
- ] })
10440
- ] })) : null,
10506
+ card === "ask" ? (() => {
10507
+ let ask = model2.asks[0], { index, question } = askStep(ask, model2.askAnswers ?? []), options = question.options ?? [], total = ask.questions.length, number = (n) => `${n}.`.padStart(String(options.length).length + 1);
10508
+ return border(theme2.color.warn, /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
10509
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { wrap: "truncate-end", children: [
10510
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { bold: !0, color: theme2.color.warn, children: [
10511
+ "? ",
10512
+ agentLabel5,
10513
+ " asks you"
10514
+ ] }),
10515
+ total > 1 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { color: theme2.color.muted, children: [
10516
+ " ",
10517
+ index + 1,
10518
+ "/",
10519
+ total
10520
+ ] }) : null,
10521
+ model2.asks.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { color: theme2.color.muted, children: [
10522
+ " (+",
10523
+ model2.asks.length - 1,
10524
+ " more)"
10525
+ ] }) : null
10526
+ ] }),
10527
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box_default, { height: Math.min(ASK_LINES, wrappedHeight(question.question || " ", inner)), overflow: "hidden", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: question.question }) }),
10528
+ options.slice(0, ASK_OPTIONS).map((option, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { wrap: "truncate-end", children: [
10529
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { color: theme2.color.accent, children: number(i + 1) }),
10530
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { color: theme2.color.text, children: [
10531
+ " ",
10532
+ option.label
10533
+ ] }),
10534
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { color: theme2.color.dim, children: [
10535
+ " ",
10536
+ option.description
10537
+ ] }) : null
10538
+ ] }, i)),
10539
+ options.length > ASK_OPTIONS ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: [
10540
+ g.ellipsis,
10541
+ " ",
10542
+ options.length - ASK_OPTIONS,
10543
+ " more, ",
10544
+ ASK_OPTIONS + 1,
10545
+ "\u2013",
10546
+ options.length,
10547
+ " by number"
10548
+ ] }) : null,
10549
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: askHint(question) }),
10550
+ act([
10551
+ { keys: "a", label: "answer", action: "answer" },
10552
+ { keys: "x", label: index > 0 ? "skip the rest" : total > 1 ? "skip all" : "skip", action: "skip" }
10553
+ ])
10554
+ ] }));
10555
+ })() : null,
10441
10556
  card === "suspend" ? border(theme2.color.warn, /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
10442
10557
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Text, { bold: !0, color: theme2.color.warn, children: [
10443
10558
  g.warn,
@@ -10451,15 +10566,15 @@ function Dock({ model: model2, width, focused, agentLabel: agentLabel5, onAction
10451
10566
  }
10452
10567
 
10453
10568
  // src/main/tui/views/chat/Footer.tsx
10454
- var import_react33 = __toESM(require_react(), 1);
10569
+ var import_react34 = __toESM(require_react(), 1);
10455
10570
  var import_jsx_runtime41 = __toESM(require_jsx_runtime(), 1);
10456
10571
  function elapsed(ms) {
10457
10572
  let s = Math.max(0, Math.floor(ms / 1e3));
10458
10573
  return s < 60 ? `${s}s` : `${Math.floor(s / 60)}m${String(s % 60).padStart(2, "0")}s`;
10459
10574
  }
10460
10575
  function Footer({ width, running: running2, state, turn, since, model: model2, error, contextPercent }) {
10461
- let theme2 = useTheme(), g = theme2.glyph, [now, setNow] = (0, import_react33.useState)(Date.now());
10462
- (0, import_react33.useEffect)(() => {
10576
+ let theme2 = useTheme(), g = theme2.glyph, [now, setNow] = (0, import_react34.useState)(Date.now());
10577
+ (0, import_react34.useEffect)(() => {
10463
10578
  if (!running2) return;
10464
10579
  setNow(Date.now());
10465
10580
  let timer = setInterval(() => setNow(Date.now()), 1e3);
@@ -10543,13 +10658,13 @@ function Footer({ width, running: running2, state, turn, since, model: model2, e
10543
10658
  }
10544
10659
 
10545
10660
  // src/main/tui/views/chat/overlays.tsx
10546
- var import_react34 = __toESM(require_react(), 1);
10661
+ var import_react35 = __toESM(require_react(), 1);
10547
10662
  var import_jsx_runtime42 = __toESM(require_jsx_runtime(), 1), DENY_OVERLAY = "chat.deny", DETAILS_OVERLAY = "chat.approval";
10548
10663
  function taskProps(props) {
10549
10664
  return props.overlay.props ?? {};
10550
10665
  }
10551
10666
  function DenyOverlay(props) {
10552
- let theme2 = useTheme(), actions4 = useActions(), { agentId, taskId, tool } = taskProps(props), [reason, setReason] = (0, import_react34.useState)("");
10667
+ let theme2 = useTheme(), actions4 = useActions(), { agentId, taskId, tool } = taskProps(props), [reason, setReason] = (0, import_react35.useState)("");
10553
10668
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
10554
10669
  Modal,
10555
10670
  {
@@ -10579,7 +10694,7 @@ function DenyOverlay(props) {
10579
10694
  }
10580
10695
  function ApprovalDetailsOverlay(props) {
10581
10696
  let theme2 = useTheme(), actions4 = useActions(), { agentId, taskId, tool } = taskProps(props), agent2 = useAgent(agentId), task = agent2?.pendingTasks.find((t) => t.id === taskId), body = task ? prettyJson(parseArgs(task.args)) : "(no longer pending)", dialogWidth = Math.min(props.width - 4, 96), lines = body.split(`
10582
- `).flatMap((line) => chunk(line, Math.max(8, dialogWidth - 4))), room = Math.max(4, props.height - 12), [top, setTop] = (0, import_react34.useState)(0), maxTop = Math.max(0, lines.length - room);
10697
+ `).flatMap((line) => chunk(line, Math.max(8, dialogWidth - 4))), room = Math.max(4, props.height - 12), [top, setTop] = (0, import_react35.useState)(0), maxTop = Math.max(0, lines.length - room);
10583
10698
  useKeys((input, key) => key.escape ? (props.close(), !0) : input === "y" && task ? (props.close(), actions4.resolveTask(agentId, taskId, "approve"), !0) : input === "a" && task ? (props.close(), alwaysApprove(actions4, agentId, agent2?.summary.handle || agent2?.summary.name || agentId, task), !0) : input === "n" && task ? (props.close(), actions4.resolveTask(agentId, taskId, "deny"), !0) : input === "f" && task ? (props.close(), actions4.pushOverlay({ kind: DENY_OVERLAY, props: { agentId, taskId, tool } }), !0) : key.downArrow || input === "j" ? (setTop((t) => Math.min(maxTop, t + 1)), !0) : key.upArrow || input === "k" ? (setTop((t) => Math.max(0, t - 1)), !0) : key.pageDown ? (setTop((t) => Math.min(maxTop, t + room)), !0) : (key.pageUp && setTop((t) => Math.max(0, t - room)), !0), { layer: "overlay" });
10584
10699
  let reason = task ? taskReason(task) : void 0;
10585
10700
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
@@ -10619,6 +10734,41 @@ function chunk(line, width) {
10619
10734
  return out;
10620
10735
  }
10621
10736
 
10737
+ // src/main/tui/views/chat/asks.ts
10738
+ var ASK_PROGRESS_KEY = "chat:askProgress";
10739
+ function progressKey(agentId, loop, requestId) {
10740
+ return `${transcriptKey(agentId, loop)}\0${requestId}`;
10741
+ }
10742
+ function askProgress(state, agentId, loop, ask) {
10743
+ return state.viewState[ASK_PROGRESS_KEY]?.[progressKey(agentId, loop, ask.requestId)] ?? [];
10744
+ }
10745
+ function setProgress(store, key, answers) {
10746
+ let next = { ...store.getState().viewState[ASK_PROGRESS_KEY] };
10747
+ answers ? next[key] = answers : delete next[key], store.actions.setViewState(ASK_PROGRESS_KEY, next);
10748
+ }
10749
+ function pendingAskFor(state, agentId, loop) {
10750
+ if (!agentId) return;
10751
+ let agent2 = state.agents[agentId], asks = pendingAsksFor(agent2, loop, state.transcripts);
10752
+ return topCard({ tasks: pendingTasksFor(agent2, loop), asks, suspended: !1, queued: [] }) === "ask" ? asks[0] : void 0;
10753
+ }
10754
+ async function replyToAsk(store, agentId, loop, ask, text) {
10755
+ let key = progressKey(agentId, loop, ask.requestId), sofar = askProgress(store.getState(), agentId, loop, ask), { index, question } = askStep(ask, sofar), read = readAskReply(question, text);
10756
+ if ("error" in read) {
10757
+ store.actions.toast(read.error, "warn");
10758
+ return;
10759
+ }
10760
+ let answers = [...sofar.slice(0, index), read.answer];
10761
+ if (answers.length < ask.questions.length) {
10762
+ setProgress(store, key, answers);
10763
+ return;
10764
+ }
10765
+ await store.actions.answerAsk(agentId, ask.requestId, answers, ask.loop ?? loop), setProgress(store, key, null);
10766
+ }
10767
+ async function skipAsk(store, agentId, loop, ask) {
10768
+ let sofar = askProgress(store.getState(), agentId, loop, ask);
10769
+ await store.actions.answerAsk(agentId, ask.requestId, ask.questions.map((_, i) => sofar[i] ?? null), ask.loop ?? loop), setProgress(store, progressKey(agentId, loop, ask.requestId), null);
10770
+ }
10771
+
10622
10772
  // src/main/tui/views/chat/commands.ts
10623
10773
  var TRIGGER_TYPES = ["startup", "timer", "inbox", "outbox", "file_change", "chat", "tool_call", "task_create", "task_complete", "log_entry", "llm_call"];
10624
10774
  function readChatState(scope) {
@@ -10789,22 +10939,22 @@ function LateKeys({ handler, layer }) {
10789
10939
  return useKeys(handler, { layer }), null;
10790
10940
  }
10791
10941
  function ChatView({ width: paneWidth, height, focused }) {
10792
- let width = Math.max(10, paneWidth - 2), theme2 = useTheme(), g = theme2.glyph, store = useStore(), actions4 = useActions(), client = useClient(), agent2 = useSelectedAgent(), stopped = useSelectedTracked(), authNeed = useAuthNeed(agent2?.summary.id), agentId = agent2?.summary.id ?? null, loopName = useSelectedLoop(), loop = useLoop(agentId, loopName), transcript = useTranscript(agentId, loopName), [chat2, setChat] = useViewState(CHAT_VIEW, INITIAL_CHAT_STATE), focusZone = useFocus(), key = agentId ? transcriptKey(agentId, loopName) : "", mountedAt = (0, import_react35.useRef)(Date.now()), [late, setLate] = (0, import_react35.useState)(!1);
10793
- (0, import_react35.useEffect)(() => {
10942
+ let width = Math.max(10, paneWidth - 2), theme2 = useTheme(), g = theme2.glyph, store = useStore(), actions4 = useActions(), client = useClient(), agent2 = useSelectedAgent(), stopped = useSelectedTracked(), authNeed = useAuthNeed(agent2?.summary.id), agentId = agent2?.summary.id ?? null, loopName = useSelectedLoop(), loop = useLoop(agentId, loopName), transcript = useTranscript(agentId, loopName), [chat2, setChat] = useViewState(CHAT_VIEW, INITIAL_CHAT_STATE), focusZone = useFocus(), key = agentId ? transcriptKey(agentId, loopName) : "", mountedAt = (0, import_react36.useRef)(Date.now()), [late, setLate] = (0, import_react36.useState)(!1);
10943
+ (0, import_react36.useEffect)(() => {
10794
10944
  setLate(!0);
10795
- }, []), (0, import_react35.useEffect)(() => {
10945
+ }, []), (0, import_react36.useEffect)(() => {
10796
10946
  agentId && actions4.ensureTranscript(agentId, loopName);
10797
10947
  }, [agentId, loopName]);
10798
- let [timers, setTimers] = (0, import_react35.useState)({}), refetchTimers = (id) => {
10948
+ let [timers, setTimers] = (0, import_react36.useState)({}), refetchTimers = (id) => {
10799
10949
  client.timers(id).then((result) => setTimers((prev) => ({ ...prev, [id]: result.timers }))).catch(() => {
10800
10950
  setTimers((prev) => prev[id] ? prev : { ...prev, [id]: [] });
10801
10951
  });
10802
10952
  }, loopCount = agent2?.loops?.length ?? 0;
10803
- (0, import_react35.useEffect)(() => {
10953
+ (0, import_react36.useEffect)(() => {
10804
10954
  agentId && refetchTimers(agentId);
10805
10955
  }, [agentId, loopCount]);
10806
- let lastEvents = useTuiSelector((s) => s.lastEvents), digested = (0, import_react35.useRef)(null), timerAttempts = (0, import_react35.useRef)(/* @__PURE__ */ new Set());
10807
- (0, import_react35.useEffect)(() => {
10956
+ let lastEvents = useTuiSelector((s) => s.lastEvents), digested = (0, import_react36.useRef)(null), timerAttempts = (0, import_react36.useRef)(/* @__PURE__ */ new Set());
10957
+ (0, import_react36.useEffect)(() => {
10808
10958
  let current = store.getState().viewState[CHAT_VIEW] ?? INITIAL_CHAT_STATE;
10809
10959
  digested.current || (digested.current = current.digested);
10810
10960
  let lookup = (id, timerId) => {
@@ -10821,7 +10971,7 @@ function ChatView({ width: paneWidth, height, focused }) {
10821
10971
  for (let a of s.activity) a.agentId === agentId && a.loop !== loopName && UNSEEN_EVENTS.has(a.type) && (out[a.loop] = a.at);
10822
10972
  return out;
10823
10973
  }, shallowEqual);
10824
- (0, import_react35.useEffect)(() => {
10974
+ (0, import_react36.useEffect)(() => {
10825
10975
  if (!agentId) return;
10826
10976
  let k = transcriptKey(agentId, loopName);
10827
10977
  return () => {
@@ -10830,14 +10980,14 @@ function ChatView({ width: paneWidth, height, focused }) {
10830
10980
  };
10831
10981
  }, [agentId, loopName]);
10832
10982
  let transcripts = useTuiSelector((s) => s.transcripts);
10833
- useTuiSelector((s) => s.web?.server);
10834
- let site = siteOf(store.getState(), agentId), tabs = loopTabs(agent2), running2 = loopRunning2(agent2, loop) || transcript.live, state = loopStateLabel(agent2, loop, loopName), turn = chat2.turns[key], turnStart = running2 ? turn && turn.endedAt === void 0 ? turn.startedAt : mountedAt.current : null, tasks2 = pendingTasksFor(agent2, loopName), asks = pendingAsksFor(agent2, loopName, transcripts), queued = queuedItems(transcript.items, running2, turnStart), queuedIds = new Set(queued.map((q) => q.id)), dockModel = { tasks: tasks2, asks, suspended: loopName === MAIN_LOOP && agent2?.executorState === "suspended", queued }, unseen = new Set(Object.entries(latest).filter(([name, at]) => at > (chat2.seen[agentId ? transcriptKey(agentId, name) : ""] ?? 0)).map(([name]) => name)), pendingLoops = new Set((agent2?.pendingTasks ?? []).filter((t) => t.status === "pending_approval").map((t) => typeof t.origin == "string" && t.origin.startsWith("loop:") ? t.origin.slice(5) : MAIN_LOOP)), markers = chat2.markers[key], older = transcript.oldestOffset > 0 ? [{ id: "chat:older", at: 0, local: !0, kind: "notice", level: "info", text: transcript.loading ? `loading earlier history${g.ellipsis}` : `${transcript.oldestOffset} earlier rows ${g.sep} scroll up or Home to load` }] : [], items = useMergedItems(transcript.items, markers, older), heightCache = (0, import_react35.useRef)(/* @__PURE__ */ new WeakMap()), isExpanded = (item) => !!chat2.expanded[`${key}|${item.id}`], heights = items.map((item) => {
10983
+ useTuiSelector((s) => s.web?.server), useTuiSelector((s) => s.viewState[ASK_PROGRESS_KEY]);
10984
+ let site = siteOf(store.getState(), agentId), tabs = loopTabs(agent2), running2 = loopRunning2(agent2, loop) || transcript.live, state = loopStateLabel(agent2, loop, loopName), turn = chat2.turns[key], turnStart = running2 ? turn && turn.endedAt === void 0 ? turn.startedAt : mountedAt.current : null, tasks2 = pendingTasksFor(agent2, loopName), asks = pendingAsksFor(agent2, loopName, transcripts), queued = queuedItems(transcript.items, running2, turnStart), queuedIds = new Set(queued.map((q) => q.id)), askAnswers2 = agentId && asks[0] ? askProgress(store.getState(), agentId, loopName, asks[0]) : void 0, dockModel = { tasks: tasks2, asks, askAnswers: askAnswers2, suspended: loopName === MAIN_LOOP && agent2?.executorState === "suspended", queued }, unseen = new Set(Object.entries(latest).filter(([name, at]) => at > (chat2.seen[agentId ? transcriptKey(agentId, name) : ""] ?? 0)).map(([name]) => name)), pendingLoops = new Set((agent2?.pendingTasks ?? []).filter((t) => t.status === "pending_approval").map((t) => typeof t.origin == "string" && t.origin.startsWith("loop:") ? t.origin.slice(5) : MAIN_LOOP)), markers = chat2.markers[key], older = transcript.oldestOffset > 0 ? [{ id: "chat:older", at: 0, local: !0, kind: "notice", level: "info", text: transcript.loading ? `loading earlier history${g.ellipsis}` : `${transcript.oldestOffset} earlier rows ${g.sep} scroll up or Home to load` }] : [], items = useMergedItems(transcript.items, markers, older), heightCache = (0, import_react36.useRef)(/* @__PURE__ */ new WeakMap()), isExpanded = (item) => !!chat2.expanded[`${key}|${item.id}`], heights = items.map((item) => {
10835
10985
  let expanded = isExpanded(item), f = `${expanded ? 1 : 0}${chat2.showThinking ? 1 : 0}${queuedIds.has(item.id) ? 1 : 0}`, cached = heightCache.current.get(item);
10836
10986
  if (cached && cached.w === width && cached.f === f) return cached.h;
10837
10987
  let h = Math.max(1, itemHeight(item, width, { expanded, showThinking: chat2.showThinking }));
10838
10988
  return heightCache.current.set(item, { w: width, f, h }), h;
10839
- }), keys = items.map((item) => item.id), infoRows = 1, dockRows = agentId ? dockHeight(dockModel, width) : 0, paneHeight = Math.max(2, height - 1 - infoRows - 1 - dockRows), offset = offsetOf(chat2.scroll[key], keys, heights), scrolled = offset > 0, viewport = Math.max(1, paneHeight - (scrolled ? 1 : 0)), win = windowAt(heights, offset, viewport), selectedId = chat2.selected[key] ?? null, topVisible = win.start === 0 && heights.slice(0, win.end + 1).reduce((a, b) => a + b, 0) - win.clip <= viewport, loadOlderGuard = (0, import_react35.useRef)("");
10840
- (0, import_react35.useEffect)(() => {
10989
+ }), keys = items.map((item) => item.id), infoRows = 1, dockRows = agentId ? dockHeight(dockModel, width) : 0, paneHeight = Math.max(2, height - 1 - infoRows - 1 - dockRows), offset = offsetOf(chat2.scroll[key], keys, heights), scrolled = offset > 0, viewport = Math.max(1, paneHeight - (scrolled ? 1 : 0)), win = windowAt(heights, offset, viewport), selectedId = chat2.selected[key] ?? null, topVisible = win.start === 0 && heights.slice(0, win.end + 1).reduce((a, b) => a + b, 0) - win.clip <= viewport, loadOlderGuard = (0, import_react36.useRef)("");
10990
+ (0, import_react36.useEffect)(() => {
10841
10991
  if (!agentId || !scrolled || !topVisible || transcript.loading || transcript.oldestOffset <= 0) return;
10842
10992
  let guard = `${key}:${transcript.oldestOffset}`;
10843
10993
  loadOlderGuard.current !== guard && (loadOlderGuard.current = guard, actions4.loadOlder(agentId, loopName));
@@ -10900,6 +11050,15 @@ function ChatView({ width: paneWidth, height, focused }) {
10900
11050
  actions4.respondSuspend(agentId, !0);
10901
11051
  return;
10902
11052
  }
11053
+ if (action === "answer") {
11054
+ actions4.setFocus("input");
11055
+ return;
11056
+ }
11057
+ if (action === "skip") {
11058
+ let ask = asks[0];
11059
+ ask && skipAsk(store, agentId, loopName, ask);
11060
+ return;
11061
+ }
10903
11062
  if (action === "shutdown") {
10904
11063
  actions4.confirm({ title: "Shut down", message: `Shut ${agentLabel4(agent2)} down instead of resuming?`, danger: !0 }).then((ok) => {
10905
11064
  ok && actions4.respondSuspend(agentId, !1);
@@ -10910,7 +11069,7 @@ function ChatView({ width: paneWidth, height, focused }) {
10910
11069
  if (!target2) return;
10911
11070
  let task = target2.task ?? { id: target2.taskId, tool: target2.tool, args: "{}", status: "pending_approval", created_at: 0 };
10912
11071
  action === "approve" ? actions4.resolveTask(agentId, target2.taskId, "approve") : action === "always" ? alwaysApprove(actions4, agentId, agentLabel4(agent2), task) : action === "reject" ? actions4.resolveTask(agentId, target2.taskId, "deny") : action === "feedback" ? rejectWithFeedback(actions4, agentId, task) : actions4.pushOverlay({ kind: DETAILS_OVERLAY, props: { agentId, taskId: target2.taskId, tool: target2.tool } });
10913
- }, interrupt = () => agentId ? (actions4.interrupt(agentId, loopName), !0) : !1, armed = (0, import_react35.useRef)(null), router = useKeyRouter(), pendingArrow = (0, import_react35.useRef)(null), replaying = (0, import_react35.useRef)(!1), queueArrow = (input, k, items2) => {
11072
+ }, interrupt = () => agentId ? (actions4.interrupt(agentId, loopName), !0) : !1, armed = (0, import_react36.useRef)(null), router = useKeyRouter(), pendingArrow = (0, import_react36.useRef)(null), replaying = (0, import_react36.useRef)(!1), queueArrow = (input, k, items2) => {
10914
11073
  let step = k.upArrow ? 1 : -1, pending = pendingArrow.current;
10915
11074
  return pending ? (pending.delta += step, pending.count++, !0) : (pendingArrow.current = { input, key: k, delta: step, count: 1, items: items2 }, setImmediate(() => {
10916
11075
  let p = pendingArrow.current;
@@ -10972,11 +11131,11 @@ function ChatView({ width: paneWidth, height, focused }) {
10972
11131
  let explicit = selectedItem?.kind === "hil" && selectedItem.status === "pending" && selectedItem.taskId === target2.taskId, prior = armed.current;
10973
11132
  return explicit || prior && prior.taskId === target2.taskId && prior.key === input && Date.now() - prior.at < APPROVE_ARM_MS ? (armed.current = null, dockAction(input === "y" ? "approve" : "always")) : (armed.current = { taskId: target2.taskId, key: input, at: Date.now() }, actions4.toast(`Press ${input} again to ${input === "y" ? "approve" : "always approve"} ${target2.tool} (${target2.taskId})`, "warn", APPROVE_ARM_MS)), !0;
10974
11133
  }
10975
- return card === "hil" && (input === "n" || input === "f" || input === "v") ? (dockAction(input === "n" ? "reject" : input === "f" ? "feedback" : "details"), !0) : card === "suspend" && (input === "y" || input === "n") ? (dockAction(input === "y" ? "resume" : "shutdown"), !0) : input === "a" && card === "ask" ? (actions4.setFocus("input"), !0) : !1;
11134
+ return card === "hil" && (input === "n" || input === "f" || input === "v") ? (dockAction(input === "n" ? "reject" : input === "f" ? "feedback" : "details"), !0) : card === "suspend" && (input === "y" || input === "n") ? (dockAction(input === "y" ? "resume" : "shutdown"), !0) : card === "ask" && (input === "a" || input === "x") ? (dockAction(input === "a" ? "answer" : "skip"), !0) : !1;
10976
11135
  }, { layer: "main", active: focused }), useKeys((_input, k) => !k.escape || store.getState().focus === "sidebar" ? !1 : running2 ? interrupt() : !1, { layer: "view" });
10977
- let transcriptRef = (0, import_react35.useRef)(null);
11136
+ let transcriptRef = (0, import_react36.useRef)(null);
10978
11137
  useWheel(transcriptRef, (delta) => scrollBy(-delta * WHEEL_STEP), { active: !!agentId });
10979
- let itemRefs = (0, import_react35.useRef)(/* @__PURE__ */ new Map());
11138
+ let itemRefs = (0, import_react36.useRef)(/* @__PURE__ */ new Map());
10980
11139
  useClick(transcriptRef, (event) => {
10981
11140
  let box = elementRect(transcriptRef.current);
10982
11141
  if (!box || event.y >= box.y + viewport) return !1;
@@ -11040,7 +11199,13 @@ function ChatView({ width: paneWidth, height, focused }) {
11040
11199
  selected: showSelection && item.id === selectedId,
11041
11200
  expanded: isExpanded(item),
11042
11201
  showThinking: chat2.showThinking,
11043
- queued: queuedIds.has(item.id)
11202
+ queued: queuedIds.has(item.id),
11203
+ viewportHeight: (
11204
+ // Raw height estimates can exceed Ink's styled height,
11205
+ // so clipping may extend into earlier visible items.
11206
+ viewport + (item === visible[visible.length - 1] ? 0 : win.clip)
11207
+ ),
11208
+ clipBottom: item === visible[visible.length - 1] ? win.clip : 0
11044
11209
  }
11045
11210
  ) }, item.id)) }) }),
11046
11211
  scrolled ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.accent, children: [
@@ -11060,7 +11225,7 @@ function ChatView({ width: paneWidth, height, focused }) {
11060
11225
  ] });
11061
11226
  }
11062
11227
  function useMergedItems(items, markers, older) {
11063
- let cache = (0, import_react35.useRef)(null), olderKey = older.map((o) => o.kind === "notice" ? o.text : "").join(), c = cache.current;
11228
+ let cache = (0, import_react36.useRef)(null), olderKey = older.map((o) => o.kind === "notice" ? o.text : "").join(), c = cache.current;
11064
11229
  if (c && c.items === items && c.markers === markers && c.older === olderKey) return c.out;
11065
11230
  let out = [...older, ...withMarkers(items, markers)];
11066
11231
  return cache.current = { items, markers, older: olderKey, out }, out;
@@ -11091,16 +11256,12 @@ function infoStyle(key, theme2) {
11091
11256
  return { color: theme2.color.dim };
11092
11257
  }
11093
11258
  }
11094
- function pendingAskFor(state, agentId, loop) {
11095
- if (agentId)
11096
- return pendingAsksFor(state.agents[agentId], loop, state.transcripts)[0];
11097
- }
11098
11259
  function placeholder(scope) {
11099
11260
  let state = scope.state(), agent2 = scope.agentId ? state.agents[scope.agentId] : void 0, stopped = scope.stoppedKey ? findTracked(state, scope.stoppedKey) : void 0;
11100
11261
  if (stopped) return stopped.agent.status === "needs_review" ? `${stopped.agent.name} is stopped and needs review \xB7 Shift+Tab, then s reviews it` : `${stopped.agent.name} is stopped \xB7 a message starts it, then sends \xB7 or Shift+Tab, then s`;
11101
11262
  if (!agent2 || !scope.agentId) return "Select an agent (Tab \u2192 sidebar) or type /help";
11102
11263
  let label2 = agentLabel4(agent2), target2 = scope.loop === MAIN_LOOP ? label2 : `${label2} \u203A ${scope.loop}`;
11103
- if (pendingAskFor(state, scope.agentId, scope.loop)) return `Answer ${label2}'s question \xB7 Enter sends the answer`;
11264
+ if (pendingAskFor(state, scope.agentId, scope.loop)) return `Answer ${label2}'s question \xB7 Enter on empty skips it`;
11104
11265
  let loopState = agent2.loops?.find((l) => l.info.name === scope.loop);
11105
11266
  return loopState && !loopState.info.enabled ? `${scope.loop} is disabled \xB7 /loop on ${scope.loop} to enable it` : loopRunning2(agent2, loopState) ? `Message ${target2} \xB7 queued until the turn ends \xB7 Esc interrupts` : `Message ${target2} / commands \xB7 ${keyLabel(newlineKey())} newline`;
11106
11267
  }
@@ -11126,8 +11287,10 @@ var chat = {
11126
11287
  placeholder,
11127
11288
  onSubmit: async (text, ctx) => {
11128
11289
  let ask = pendingAskFor(ctx.state(), ctx.agentId, ctx.loop);
11129
- return !ask || !ctx.agentId ? !1 : (await ctx.actions.answerAsk(ctx.agentId, ask.requestId, text, ask.loop ?? ctx.loop), !0);
11290
+ return !ask || !ctx.agentId ? !1 : (await replyToAsk(ctx.store, ctx.agentId, ctx.loop, ask, text), !0);
11130
11291
  },
11292
+ // Enter on an empty prompt skips the question the dock shows.
11293
+ submitsEmpty: (scope) => !!pendingAskFor(scope.state(), scope.agentId, scope.loop),
11131
11294
  historyKey: (scope) => scope.agentId ? transcriptKey(scope.agentId, scope.loop) : "none",
11132
11295
  draftKey: (scope) => scope.agentId ? `chat:${transcriptKey(scope.agentId, scope.loop)}` : "chat",
11133
11296
  complete: completeFiles
@@ -11176,7 +11339,8 @@ var chat = {
11176
11339
  title: "Approvals and questions (the card under the transcript)",
11177
11340
  keys: [
11178
11341
  { keys: "y", label: "Approve: press twice, or once on a selected approval \xB7 resume a suspended agent. Mouse mode: click the card\u2019s buttons" },
11179
- { keys: "a", label: "Always approve this tool for the agent (twice, then confirm; it won\u2019t ask again). Not offered for protection overrides: those are one-time only \xB7 on a question card: answer it" },
11342
+ { keys: "a", label: "Always approve this tool for the agent (twice, then confirm; it won\u2019t ask again). Not offered for protection overrides: those are one-time only \xB7 on a question card: answer it in the prompt" },
11343
+ { keys: "x", label: "On a question card: skip the questions not answered yet and send the answers" },
11180
11344
  { keys: "n", label: "Reject \xB7 shut a suspended agent down (asks)" },
11181
11345
  { keys: "f", label: "Reject with feedback: the agent sees your text" },
11182
11346
  { keys: "v", label: "Full details of the tool call" },
@@ -11192,7 +11356,7 @@ var chat = {
11192
11356
  }, chat_default = chat;
11193
11357
 
11194
11358
  // src/main/tui/views/files/index.tsx
11195
- var import_react40 = __toESM(require_react(), 1);
11359
+ var import_react41 = __toESM(require_react(), 1);
11196
11360
 
11197
11361
  // src/main/tui/views/files/state.ts
11198
11362
  var VIEW_ID = "files", TABS2 = ["files", "inbox", "outbox", "meta"], INITIAL_STATE = { tab: "files", pane: "list", agents: {} };
@@ -11352,10 +11516,10 @@ var tabAction = (tab, title, keywords) => ({
11352
11516
  };
11353
11517
 
11354
11518
  // src/main/tui/views/files/DataTab.tsx
11355
- var import_react37 = __toESM(require_react(), 1);
11519
+ var import_react38 = __toESM(require_react(), 1);
11356
11520
 
11357
11521
  // src/main/tui/views/files/Viewer.tsx
11358
- var import_react36 = __toESM(require_react(), 1);
11522
+ var import_react37 = __toESM(require_react(), 1);
11359
11523
  var import_jsx_runtime44 = __toESM(require_jsx_runtime(), 1);
11360
11524
  function toneColor3(theme2, tone) {
11361
11525
  switch (tone) {
@@ -11380,11 +11544,11 @@ function toneColor3(theme2, tone) {
11380
11544
  }
11381
11545
  }
11382
11546
  function Viewer(props) {
11383
- let { width, height, active, title, meta = [], notice, name, text, bytes, mime, loading, error, plain: plain2 = !1, resetKey, onBack, onEdit, onOpenExternal, onSaveBack, emptyText } = props, theme2 = useTheme(), [top, setTop] = (0, import_react36.useState)(0), [query, setQuery] = (0, import_react36.useState)(""), [typing, setTyping] = (0, import_react36.useState)(!1), [current, setCurrent] = (0, import_react36.useState)(0);
11384
- (0, import_react36.useEffect)(() => {
11547
+ let { width, height, active, title, meta = [], notice, name, text, bytes, mime, loading, error, plain: plain2 = !1, resetKey, onBack, onEdit, onOpenExternal, onSaveBack, emptyText } = props, theme2 = useTheme(), [top, setTop] = (0, import_react37.useState)(0), [query, setQuery] = (0, import_react37.useState)(""), [typing, setTyping] = (0, import_react37.useState)(!1), [current, setCurrent] = (0, import_react37.useState)(0);
11548
+ (0, import_react37.useEffect)(() => {
11385
11549
  setTop(0), setQuery(""), setTyping(!1), setCurrent(0);
11386
11550
  }, [resetKey]);
11387
- let binary = bytes !== void 0, prepared = (0, import_react36.useMemo)(() => binary ? { lines: hexDump(bytes), lang: "text", pretty: !1 } : prepareContent(text ?? "", name), [text, bytes, name, binary]), matches = (0, import_react36.useMemo)(() => findMatches(prepared.lines, query), [prepared, query]), currentIndex = matches.length ? Math.min(current, matches.length - 1) : -1, gutter = plain2 ? 0 : String(prepared.lines.length).length + 1, bodyWidth = Math.max(4, width - gutter - 1), { rows, lineStart: lineStart2 } = (0, import_react36.useMemo)(() => {
11551
+ let binary = bytes !== void 0, prepared = (0, import_react37.useMemo)(() => binary ? { lines: hexDump(bytes), lang: "text", pretty: !1 } : prepareContent(text ?? "", name), [text, bytes, name, binary]), matches = (0, import_react37.useMemo)(() => findMatches(prepared.lines, query), [prepared, query]), currentIndex = matches.length ? Math.min(current, matches.length - 1) : -1, gutter = plain2 ? 0 : String(prepared.lines.length).length + 1, bodyWidth = Math.max(4, width - gutter - 1), { rows, lineStart: lineStart2 } = (0, import_react37.useMemo)(() => {
11388
11552
  let styled = styleLines(prepared.lines, prepared.lang), byLine = /* @__PURE__ */ new Map();
11389
11553
  matches.forEach((m, i) => {
11390
11554
  let list = byLine.get(m.line) ?? [];
@@ -11406,13 +11570,13 @@ function Viewer(props) {
11406
11570
  let next = (currentIndex + delta + matches.length) % matches.length;
11407
11571
  setCurrent(next), reveal(next);
11408
11572
  };
11409
- (0, import_react36.useEffect)(() => {
11573
+ (0, import_react37.useEffect)(() => {
11410
11574
  if (typing && matches.length > 0) {
11411
11575
  let firstVisible = matches.findIndex((m) => (lineStart2[m.line] ?? 0) >= clampedTop), index = firstVisible >= 0 ? firstVisible : 0;
11412
11576
  setCurrent(index), reveal(index);
11413
11577
  }
11414
11578
  }, [query]), useKeys((input, key) => typing ? key.escape ? (setTyping(!1), setQuery(""), !0) : key.return ? (setTyping(!1), !0) : key.backspace || key.delete ? (setQuery((q) => q.slice(0, -1)), !0) : (key.leftArrow || key.rightArrow) && !key.ctrl && !key.shift ? !0 : input && !key.ctrl && !key.meta && !/[\r\n\t]/.test(input) ? (setQuery((q) => q + input), !0) : !1 : (key.ctrl || key.shift) && (key.leftArrow || key.rightArrow) ? !1 : key.upArrow || input === "k" && !key.ctrl ? (scrollTo(clampedTop - 1), !0) : key.downArrow || input === "j" && !key.ctrl ? (scrollTo(clampedTop + 1), !0) : key.pageUp || key.ctrl && input === "u" ? (scrollTo(clampedTop - Math.max(1, bodyRows - 1)), !0) : key.pageDown || input === " " || key.ctrl && input === "d" ? (scrollTo(clampedTop + Math.max(1, bodyRows - 1)), !0) : key.home || input === "g" ? (scrollTo(0), !0) : key.end || input === "G" ? (scrollTo(maxTop), !0) : input === "/" ? (setTyping(!0), setQuery(""), !0) : input === "n" && query ? (jump(1), !0) : input === "N" && query ? (jump(-1), !0) : input === "e" && onEdit ? (onEdit(), !0) : input === "o" && onOpenExternal ? (onOpenExternal(), !0) : input === "s" && onSaveBack ? (onSaveBack(), !0) : key.escape && query ? (setQuery(""), !0) : (key.escape || key.backspace && !key.ctrl && !key.meta) && onBack ? (onBack(), !0) : !1, { layer: "main", active });
11415
- let boxRef = (0, import_react36.useRef)(null);
11579
+ let boxRef = (0, import_react37.useRef)(null);
11416
11580
  useWheel(boxRef, (delta) => scrollTo(clampedTop + delta * WHEEL_STEP));
11417
11581
  let visible = rows.slice(clampedTop, clampedTop + bodyRows), lastLine = visible.length ? visible[visible.length - 1].line + 1 : 0, firstLine2 = visible.length ? visible[0].line + 1 : 0, position = rows.length === 0 ? "" : `L${firstLine2}-${lastLine}/${prepared.lines.length}${maxTop > 0 ? ` ${Math.round(clampedTop / maxTop * 100)}%` : ""}`, search = typing ? `/${query}` : query ? `/${query} ${matches.length ? `${currentIndex + 1}/${matches.length}` : "no match"} n/N` : "", header2 = /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(Text, { wrap: "truncate-end", children: [
11418
11582
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Text, { bold: !0, color: active ? theme2.color.accent : theme2.color.text, inverse: theme2.mono && active, children: truncate(title, Math.max(8, width - 20)) }),
@@ -11564,7 +11728,7 @@ var LIVE_EVENTS = {
11564
11728
  meta: []
11565
11729
  };
11566
11730
  function DataTab({ kind, width, height, focused, agentId, agentLabel: agentLabel5, pane, setPane }) {
11567
- let theme2 = useTheme(), client = useClient(), [records, setRecords] = (0, import_react37.useState)(null), [error, setError] = (0, import_react37.useState)(null), [filterIndex, setFilterIndex] = (0, import_react37.useState)(0), [cursor, setCursor] = (0, import_react37.useState)(void 0), [loadedAt, setLoadedAt] = (0, import_react37.useState)(null), status = STATUS_FILTERS[kind][filterIndex], reload = (0, import_react37.useCallback)(async () => {
11731
+ let theme2 = useTheme(), client = useClient(), [records, setRecords] = (0, import_react38.useState)(null), [error, setError] = (0, import_react38.useState)(null), [filterIndex, setFilterIndex] = (0, import_react38.useState)(0), [cursor, setCursor] = (0, import_react38.useState)(void 0), [loadedAt, setLoadedAt] = (0, import_react38.useState)(null), status = STATUS_FILTERS[kind][filterIndex], reload = (0, import_react38.useCallback)(async () => {
11568
11732
  try {
11569
11733
  let next;
11570
11734
  kind === "inbox" ? next = [...(await client.inbox(agentId, status)).messages].sort((a, b) => b.received_at - a.received_at).map(inboxRecord) : kind === "outbox" ? next = [...(await client.outbox(agentId, status)).messages].sort((a, b) => b.created_at - a.created_at).map(outboxRecord) : next = [...(await client.meta(agentId)).entries].sort((a, b) => a.key.localeCompare(b.key)).map(metaRecord), setRecords(next), setError(null);
@@ -11573,11 +11737,11 @@ function DataTab({ kind, width, height, focused, agentId, agentLabel: agentLabel
11573
11737
  }
11574
11738
  setLoadedAt(Date.now());
11575
11739
  }, [client, agentId, kind, status]);
11576
- (0, import_react37.useEffect)(() => {
11740
+ (0, import_react38.useEffect)(() => {
11577
11741
  setRecords(null), reload();
11578
11742
  }, [reload]);
11579
- let lastEvents = useTuiSelector((s) => s.lastEvents), seen = (0, import_react37.useRef)(lastEvents[lastEvents.length - 1]);
11580
- (0, import_react37.useEffect)(() => {
11743
+ let lastEvents = useTuiSelector((s) => s.lastEvents), seen = (0, import_react38.useRef)(lastEvents[lastEvents.length - 1]);
11744
+ (0, import_react38.useEffect)(() => {
11581
11745
  let hit = !1;
11582
11746
  for (let i = lastEvents.length - 1; i >= 0 && lastEvents[i] !== seen.current; i--)
11583
11747
  lastEvents[i].agent_id === agentId && LIVE_EVENTS[kind].includes(lastEvents[i].event_type) && (hit = !0);
@@ -11687,7 +11851,7 @@ function DataTab({ kind, width, height, focused, agentId, agentLabel: agentLabel
11687
11851
  }
11688
11852
 
11689
11853
  // src/main/tui/views/files/FilesTab.tsx
11690
- var import_react38 = __toESM(require_react(), 1);
11854
+ var import_react39 = __toESM(require_react(), 1);
11691
11855
 
11692
11856
  // src/main/tui/views/files/external.ts
11693
11857
  import { promises as fs4, rmSync, statSync as statSync3 } from "node:fs";
@@ -11756,7 +11920,9 @@ async function saveBackExternal(deps, target2) {
11756
11920
  cancelLabel: "Cancel",
11757
11921
  danger: !!concurrent
11758
11922
  })) return "discarded";
11759
- let written = copy.binary && target2.kind === "file" ? await actions4.run(`Write ${label2}`, (c) => c.writeFile(agentId, target2.path, { contentBase64: edited.toString("base64"), ...copy.mime ? { mimeType: copy.mime } : {} }).then(() => !0)) : await writeOverConflicts(actions4, label2, copy.file, (base2) => actions4.run(`Write ${label2}`, (c) => writeOver(() => writeTarget(c, agentId, target2, edited.toString("utf-8"), base2))), baseRevision);
11923
+ let written = await writeOverConflicts(actions4, label2, copy.file, (base2) => actions4.run(`Write ${label2}`, (c) => writeOver(
11924
+ () => copy.binary && target2.kind === "file" ? c.writeFile(agentId, target2.path, { contentBase64: edited.toString("base64"), ...copy.mime ? { mimeType: copy.mime } : {}, ...base2 !== void 0 ? { baseRevision: base2 } : {} }) : writeTarget(c, agentId, target2, edited.toString("utf-8"), base2)
11925
+ )), baseRevision);
11760
11926
  return written === "reloaded" ? "discarded" : written ? (copy.original = edited, copy.mtimeMs = (await fs4.stat(copy.file)).mtimeMs, actions4.toast(`Saved ${label2} from the app`, "success"), "written") : (actions4.toast(`Write failed. Your copy is still at ${copy.file}`, "error", 12e3), "failed");
11761
11927
  }
11762
11928
 
@@ -11776,18 +11942,18 @@ function parentsOf(path) {
11776
11942
  return parts.map((_p, i) => parts.slice(0, i + 1).join("/"));
11777
11943
  }
11778
11944
  function FilesTab(props) {
11779
- let { width, height, focused, agentId, agentLabel: agentLabel5, pane, setPane, agentState, setAgentState, request, clearRequest } = props, theme2 = useTheme(), actions4 = useActions(), client = useClient(), { suspendTerminal } = use_app_default(), [files2, setFiles] = (0, import_react38.useState)(null), [listError, setListError] = (0, import_react38.useState)(null), [query, setQuery] = (0, import_react38.useState)(""), [filtering, setFiltering] = (0, import_react38.useState)(!1), [content, setContent] = (0, import_react38.useState)({}), [notice, setNotice] = (0, import_react38.useState)(null), [, setTick] = (0, import_react38.useState)(0), busy = (0, import_react38.useRef)(!1), collapsed = (0, import_react38.useMemo)(() => new Set(agentState.collapsed ?? []), [agentState.collapsed]), rows = (0, import_react38.useMemo)(() => buildRows(files2 ?? [], collapsed, query), [files2, collapsed, query]), cursorIndex = Math.max(0, rows.findIndex((r) => r.key === agentState.cursor)), cursorRow = rows[cursorIndex], viewerKey = isOpenable(cursorRow) ? cursorRow.key : agentState.open ?? DOCUMENT_KEY;
11780
- (0, import_react38.useEffect)(() => {
11945
+ let { width, height, focused, agentId, agentLabel: agentLabel5, pane, setPane, agentState, setAgentState, request, clearRequest } = props, theme2 = useTheme(), actions4 = useActions(), client = useClient(), { suspendTerminal } = use_app_default(), [files2, setFiles] = (0, import_react39.useState)(null), [listError, setListError] = (0, import_react39.useState)(null), [query, setQuery] = (0, import_react39.useState)(""), [filtering, setFiltering] = (0, import_react39.useState)(!1), [content, setContent] = (0, import_react39.useState)({}), [notice, setNotice] = (0, import_react39.useState)(null), [, setTick] = (0, import_react39.useState)(0), busy = (0, import_react39.useRef)(!1), collapsed = (0, import_react39.useMemo)(() => new Set(agentState.collapsed ?? []), [agentState.collapsed]), rows = (0, import_react39.useMemo)(() => buildRows(files2 ?? [], collapsed, query), [files2, collapsed, query]), cursorIndex = Math.max(0, rows.findIndex((r) => r.key === agentState.cursor)), cursorRow = rows[cursorIndex], viewerKey = isOpenable(cursorRow) ? cursorRow.key : agentState.open ?? DOCUMENT_KEY;
11946
+ (0, import_react39.useEffect)(() => {
11781
11947
  pane === "viewer" && viewerKey.startsWith("file:") && recordRecentFile(agentId, viewerKey.slice(5));
11782
11948
  }, [pane, viewerKey, agentId]);
11783
- let viewerTarget = targetFromKey(viewerKey), reloadList = (0, import_react38.useCallback)(async () => {
11949
+ let viewerTarget = targetFromKey(viewerKey), reloadList = (0, import_react39.useCallback)(async () => {
11784
11950
  try {
11785
11951
  let next = await listFiles(client, agentId);
11786
11952
  setFiles(next), setListError(null);
11787
11953
  } catch (err) {
11788
11954
  setListError(err instanceof Error ? err.message : String(err)), setFiles((prev) => prev ?? []);
11789
11955
  }
11790
- }, [client, agentId]), loadContent = (0, import_react38.useCallback)(async (key) => {
11956
+ }, [client, agentId]), loadContent = (0, import_react39.useCallback)(async (key) => {
11791
11957
  let target2 = targetFromKey(key);
11792
11958
  if (target2)
11793
11959
  try {
@@ -11797,17 +11963,17 @@ function FilesTab(props) {
11797
11963
  setContent((prev) => ({ ...prev, [key]: { error: err instanceof Error ? err.message : String(err) } }));
11798
11964
  }
11799
11965
  }, [client, agentId]);
11800
- (0, import_react38.useEffect)(() => {
11966
+ (0, import_react39.useEffect)(() => {
11801
11967
  setFiles(null), setContent({}), setNotice(null), reloadList();
11802
- }, [agentId]), (0, import_react38.useEffect)(() => {
11968
+ }, [agentId]), (0, import_react39.useEffect)(() => {
11803
11969
  if (!viewerTarget || content[viewerKey]) return;
11804
11970
  let timer = setTimeout(() => {
11805
11971
  loadContent(viewerKey);
11806
11972
  }, 90);
11807
11973
  return () => clearTimeout(timer);
11808
11974
  }, [viewerKey, content[viewerKey] === void 0]);
11809
- let lastEvents = useTuiSelector((s) => s.lastEvents), seen = (0, import_react38.useRef)(lastEvents[lastEvents.length - 1]);
11810
- (0, import_react38.useEffect)(() => {
11975
+ let lastEvents = useTuiSelector((s) => s.lastEvents), seen = (0, import_react39.useRef)(lastEvents[lastEvents.length - 1]);
11976
+ (0, import_react39.useEffect)(() => {
11811
11977
  let fresh = [];
11812
11978
  for (let i = lastEvents.length - 1; i >= 0 && lastEvents[i] !== seen.current; i--) fresh.unshift(lastEvents[i]);
11813
11979
  seen.current = lastEvents[lastEvents.length - 1];
@@ -11832,7 +11998,7 @@ function FilesTab(props) {
11832
11998
  for (let key of touched) delete next[key];
11833
11999
  return next;
11834
12000
  });
11835
- }, [lastEvents]), (0, import_react38.useEffect)(() => {
12001
+ }, [lastEvents]), (0, import_react39.useEffect)(() => {
11836
12002
  let timer = setInterval(() => setTick((t) => t + 1), 15e3);
11837
12003
  return () => clearInterval(timer);
11838
12004
  }, []);
@@ -11884,7 +12050,7 @@ function FilesTab(props) {
11884
12050
  busy.current = !1, setTick((t) => t + 1);
11885
12051
  }
11886
12052
  }, viewedCopy = viewerTarget ? externalCopy(agentId, viewerTarget) : void 0, copyChanged = viewedCopy ? externalChanged(viewedCopy) : !1;
11887
- (0, import_react38.useEffect)(() => {
12053
+ (0, import_react39.useEffect)(() => {
11888
12054
  if (!viewedCopy || copyChanged) return;
11889
12055
  let timer = setInterval(() => {
11890
12056
  externalChanged(viewedCopy) && setTick((t) => t + 1);
@@ -11957,7 +12123,7 @@ function FilesTab(props) {
11957
12123
  let next = wantCollapsed ? [...collapsed, row4.path] : [...collapsed].filter((p) => p !== row4.path);
11958
12124
  return setAgentState({ collapsed: next }), !0;
11959
12125
  };
11960
- (0, import_react38.useEffect)(() => {
12126
+ (0, import_react39.useEffect)(() => {
11961
12127
  if (request)
11962
12128
  if (clearRequest(), request.kind === "open")
11963
12129
  reveal(request.key), invalidate(request.key), setPane("viewer");
@@ -12122,10 +12288,10 @@ function FilesTab(props) {
12122
12288
  }
12123
12289
 
12124
12290
  // src/main/tui/views/files/InputDialog.tsx
12125
- var import_react39 = __toESM(require_react(), 1);
12291
+ var import_react40 = __toESM(require_react(), 1);
12126
12292
  var import_jsx_runtime47 = __toESM(require_jsx_runtime(), 1);
12127
12293
  function InputDialog({ overlay, close, width }) {
12128
- let theme2 = useTheme(), options = overlay.props ?? {}, [value, setValue] = (0, import_react39.useState)(options.initial ?? ""), finish = (result) => {
12294
+ let theme2 = useTheme(), options = overlay.props ?? {}, [value, setValue] = (0, import_react40.useState)(options.initial ?? ""), finish = (result) => {
12129
12295
  resolveAsk(overlay.id, result), close();
12130
12296
  };
12131
12297
  return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
@@ -12158,13 +12324,13 @@ function InputDialog({ overlay, close, width }) {
12158
12324
  // src/main/tui/views/files/index.tsx
12159
12325
  var import_jsx_runtime48 = __toESM(require_jsx_runtime(), 1), TAB_TITLES = { files: "Files", inbox: "Inbox", outbox: "Outbox", meta: "Meta" };
12160
12326
  function FilesView({ width, height, focused }) {
12161
- let theme2 = useTheme(), store = useStore(), agent2 = useSelectedAgent(), stopped = useSelectedTracked(), loop = useSelectedLoop(), [state, setState] = useViewState(VIEW_ID, INITIAL_STATE), agentId = agent2?.summary.id ?? null, agentLabel5 = agent2 ? agent2.summary.handle || agent2.summary.name : "", patch = (0, import_react40.useCallback)((next) => {
12327
+ let theme2 = useTheme(), store = useStore(), agent2 = useSelectedAgent(), stopped = useSelectedTracked(), loop = useSelectedLoop(), [state, setState] = useViewState(VIEW_ID, INITIAL_STATE), agentId = agent2?.summary.id ?? null, agentLabel5 = agent2 ? agent2.summary.handle || agent2.summary.name : "", patch = (0, import_react41.useCallback)((next) => {
12162
12328
  setState({ ...readViewState(store.getState()), ...next });
12163
- }, [store, setState]), setPane = (0, import_react40.useCallback)((pane) => patch({ pane }), [patch]), setTab = (tab) => patch({ tab, pane: "list" }), setAgentState = (0, import_react40.useCallback)((next) => {
12329
+ }, [store, setState]), setPane = (0, import_react41.useCallback)((pane) => patch({ pane }), [patch]), setTab = (tab) => patch({ tab, pane: "list" }), setAgentState = (0, import_react41.useCallback)((next) => {
12164
12330
  if (!agentId) return;
12165
12331
  let current = readViewState(store.getState());
12166
12332
  patch({ agents: { ...current.agents, [agentId]: { ...current.agents[agentId], ...next } } });
12167
- }, [agentId, store, patch]), clearRequest = (0, import_react40.useCallback)(() => patch({ request: void 0 }), [patch]);
12333
+ }, [agentId, store, patch]), clearRequest = (0, import_react41.useCallback)(() => patch({ request: void 0 }), [patch]);
12168
12334
  if (useKeys((input, key) => {
12169
12335
  if (key.ctrl || key.meta || key.shift && (key.leftArrow || key.rightArrow)) return !1;
12170
12336
  let step = key.rightArrow || input === "]" ? 1 : key.leftArrow || input === "[" ? -1 : 0;
@@ -12410,7 +12576,7 @@ function row2(cells2, width) {
12410
12576
  }
12411
12577
 
12412
12578
  // src/main/tui/views/loops/hooks.ts
12413
- var import_react41 = __toESM(require_react(), 1);
12579
+ var import_react42 = __toESM(require_react(), 1);
12414
12580
  var LOOPS_REV_KEY = "loops.rev", revCounter = 0;
12415
12581
  function bumpLoopsData(actions4, _state) {
12416
12582
  actions4.setViewState(LOOPS_REV_KEY, ++revCounter);
@@ -12431,15 +12597,15 @@ function useEventTick(agentId, types) {
12431
12597
  });
12432
12598
  }
12433
12599
  function useNow(ms = 3e4) {
12434
- let [now, setNow] = (0, import_react41.useState)(() => Date.now());
12435
- return (0, import_react41.useEffect)(() => {
12600
+ let [now, setNow] = (0, import_react42.useState)(() => Date.now());
12601
+ return (0, import_react42.useEffect)(() => {
12436
12602
  let timer = setInterval(() => setNow(Date.now()), ms);
12437
12603
  return () => clearInterval(timer);
12438
12604
  }, [ms]), now;
12439
12605
  }
12440
12606
  function useAsyncData(load, deps) {
12441
- let client = useClient(), [data, setData] = (0, import_react41.useState)(void 0), [error, setError] = (0, import_react41.useState)(void 0), [loading, setLoading] = (0, import_react41.useState)(!1), [nonce2, setNonce] = (0, import_react41.useState)(0), seq = (0, import_react41.useRef)(0);
12442
- (0, import_react41.useEffect)(() => {
12607
+ let client = useClient(), [data, setData] = (0, import_react42.useState)(void 0), [error, setError] = (0, import_react42.useState)(void 0), [loading, setLoading] = (0, import_react42.useState)(!1), [nonce2, setNonce] = (0, import_react42.useState)(0), seq = (0, import_react42.useRef)(0);
12608
+ (0, import_react42.useEffect)(() => {
12443
12609
  if (!load) {
12444
12610
  setData(void 0), setError(void 0), setLoading(!1);
12445
12611
  return;
@@ -12454,7 +12620,7 @@ function useAsyncData(load, deps) {
12454
12620
  }
12455
12621
  );
12456
12622
  }, [...deps, nonce2, client]);
12457
- let reload = (0, import_react41.useCallback)(() => setNonce((n) => n + 1), []);
12623
+ let reload = (0, import_react42.useCallback)(() => setNonce((n) => n + 1), []);
12458
12624
  return { data, error, loading, reload };
12459
12625
  }
12460
12626
  var TIMER_EVENTS = ["timer.fired", "config.changed", "agent.loaded"];
@@ -12464,7 +12630,7 @@ function useAgentTimers(agentId) {
12464
12630
  }
12465
12631
  function useFleetTimers(enabled) {
12466
12632
  let rev = useLoopsRev(), tick = useEventTick(void 0, TIMER_EVENTS), agents = useTuiSelector((s) => s.agentOrder.map((id) => `${id}\0${s.agents[id]?.summary.handle || s.agents[id]?.summary.name || id}`).join(`
12467
- `)), [failures, setFailures] = (0, import_react41.useState)([]);
12633
+ `)), [failures, setFailures] = (0, import_react42.useState)([]);
12468
12634
  return { ...useAsyncData(enabled ? async (c) => {
12469
12635
  let list = agents ? agents.split(`
12470
12636
  `).map((line) => {
@@ -13099,7 +13265,7 @@ var TIMERS_TAB_HINTS = [
13099
13265
  ];
13100
13266
 
13101
13267
  // src/main/tui/views/loops/TriggersTab.tsx
13102
- var import_react42 = __toESM(require_react(), 1);
13268
+ var import_react43 = __toESM(require_react(), 1);
13103
13269
 
13104
13270
  // src/main/tui/views/loops/trigger-ops.ts
13105
13271
  function diffText(before, after, maxLines = 24) {
@@ -13142,7 +13308,7 @@ It has no targets yet, so it will not wake anything. Add a target with e.` : "";
13142
13308
  var import_jsx_runtime52 = __toESM(require_jsx_runtime(), 1);
13143
13309
  function TriggersTab({ agentId, width, height, focused, view: view2, setView, tabKeys }) {
13144
13310
  let theme2 = useTheme(), actions4 = useActions(), agent2 = useAgent(agentId), runtime3 = useRuntimeTriggers(agentId), config2 = agent2?.config;
13145
- (0, import_react42.useEffect)(() => {
13311
+ (0, import_react43.useEffect)(() => {
13146
13312
  config2 || actions4.loadConfig(agentId);
13147
13313
  }, [agentId, !!config2]);
13148
13314
  let label2 = agent2?.summary.handle || agent2?.summary.name || agentId, index = Math.min(view2.triggerIndex, TRIGGER_TYPES2.length - 1), selectedType = TRIGGER_TYPES2[index], selectedCfg = config2?.triggers?.[selectedType], w = width, detailRows = Math.max(0, Math.min(8, height - TRIGGER_TYPES2.length - 5)), listRows = Math.max(1, height - 4 - detailRows - (runtime3.error ? 1 : 0)), runtimeOf = (type) => runtime3.data?.configured.find((c) => c.type === type), cols = (type) => {
@@ -13310,7 +13476,7 @@ var HISTORY_TAB_HINTS = [
13310
13476
  ];
13311
13477
 
13312
13478
  // src/main/tui/views/loops/LoopWizard.tsx
13313
- var import_react43 = __toESM(require_react(), 1);
13479
+ var import_react44 = __toESM(require_react(), 1);
13314
13480
 
13315
13481
  // src/main/tui/views/loops/templates.ts
13316
13482
  var base = [...DEFAULT_NEW_LOOP_TOOLS], LOOP_TEMPLATES = [
@@ -13418,7 +13584,7 @@ function draftFromValues(v) {
13418
13584
  return { kind: v.scheduleKind ?? "none", value: String(v.scheduleValue ?? ""), payload: String(v.payload ?? ""), maxRuns: String(v.maxRuns ?? "") };
13419
13585
  }
13420
13586
  function LoopWizard({ overlay, close, width, height }) {
13421
- let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), agent2 = useAgent(props.agentId), loops2 = useLoops(props.agentId) ?? [], timers = useAgentTimers(props.agentId), { suspendTerminal } = use_app_default(), config2 = agent2?.config, host = hostLoopTools(config2), existing = props.mode === "edit" ? loops2.find((l) => l.info.name === props.name)?.info.config ?? void 0 : void 0, provider = config2?.model?.provider, models = useModelList(props.agentId, provider), takenNames = loops2.map((l) => l.info.name), initialTemplate = props.mode === "create" ? findTemplate(props.template) : void 0, [step, setStep] = (0, import_react43.useState)(props.mode === "create" && !initialTemplate ? "template" : "form"), [template, setTemplate] = (0, import_react43.useState)(initialTemplate), [values, setValues] = (0, import_react43.useState)(() => initialValues2(props, existing, initialTemplate, host, takenNames)), [touched, setTouched] = (0, import_react43.useState)(!1), [outcome, setOutcome] = (0, import_react43.useState)(null), dialogWidth = Math.max(40, Math.min(width - 4, 96)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), label2 = agent2 ? agentName3(store.getState(), props.agentId) : props.agentId, wanted = Array.isArray(values.tools) ? values.tools : [], options = toolOptions(host, [...wanted, ...existing?.tools ?? [], ...template?.tools ?? []]), draft = draftFromValues(values), loopName = props.mode === "edit" ? props.name ?? "" : String(values.name ?? ""), schedule = scheduleToTimer(draft, loopName), existingTimers = timers.data ? timersForLoop(timers.data, loopName) : [], errors = (0, import_react43.useMemo)(() => {
13587
+ let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), agent2 = useAgent(props.agentId), loops2 = useLoops(props.agentId) ?? [], timers = useAgentTimers(props.agentId), { suspendTerminal } = use_app_default(), config2 = agent2?.config, host = hostLoopTools(config2), existing = props.mode === "edit" ? loops2.find((l) => l.info.name === props.name)?.info.config ?? void 0 : void 0, provider = config2?.model?.provider, models = useModelList(props.agentId, provider), takenNames = loops2.map((l) => l.info.name), initialTemplate = props.mode === "create" ? findTemplate(props.template) : void 0, [step, setStep] = (0, import_react44.useState)(props.mode === "create" && !initialTemplate ? "template" : "form"), [template, setTemplate] = (0, import_react44.useState)(initialTemplate), [values, setValues] = (0, import_react44.useState)(() => initialValues2(props, existing, initialTemplate, host, takenNames)), [touched, setTouched] = (0, import_react44.useState)(!1), [outcome, setOutcome] = (0, import_react44.useState)(null), dialogWidth = Math.max(40, Math.min(width - 4, 96)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), label2 = agent2 ? agentName3(store.getState(), props.agentId) : props.agentId, wanted = Array.isArray(values.tools) ? values.tools : [], options = toolOptions(host, [...wanted, ...existing?.tools ?? [], ...template?.tools ?? []]), draft = draftFromValues(values), loopName = props.mode === "edit" ? props.name ?? "" : String(values.name ?? ""), schedule = scheduleToTimer(draft, loopName), existingTimers = timers.data ? timersForLoop(timers.data, loopName) : [], errors = (0, import_react44.useMemo)(() => {
13422
13588
  let e = {};
13423
13589
  props.mode === "create" && (e.name = validateLoopName(String(values.name ?? ""), takenNames) ?? void 0), e.goal = validateGoal(String(values.goal ?? ""), !!values.autostart) ?? void 0;
13424
13590
  let compact2 = String(values.compact ?? "").trim();
@@ -13674,7 +13840,7 @@ function MissingLoop({ title, name, close, width }) {
13674
13840
  }
13675
13841
 
13676
13842
  // src/main/tui/views/loops/TimerDialog.tsx
13677
- var import_react44 = __toESM(require_react(), 1);
13843
+ var import_react45 = __toESM(require_react(), 1);
13678
13844
  var import_jsx_runtime55 = __toESM(require_jsx_runtime(), 1), WHEN_LABEL2 = { none: "When", every: "Every", daily: "Daily at", cron: "Cron", in: "After", at: "At" }, WHEN_HINT2 = {
13679
13845
  none: "",
13680
13846
  every: "15m, 2h, 1h30m, 1d",
@@ -13691,13 +13857,13 @@ function choiceOf(scope) {
13691
13857
  return agent2 && system ? "both" : system ? "system" : "agent";
13692
13858
  }
13693
13859
  function TimerDialog({ overlay, close, width, height }) {
13694
- let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), agent2 = useAgent(props.agentId), loops2 = useLoops(props.agentId) ?? [], timers = useAgentTimers(props.agentId), existing = props.timerId !== void 0 ? timers.data?.find((t) => t.id === props.timerId) : void 0, editing = props.timerId !== void 0, [values, setValues] = (0, import_react44.useState)(() => editing ? null : initialValues3(void 0, props.loop)), [step, setStep] = (0, import_react44.useState)("form"), [touched, setTouched] = (0, import_react44.useState)(!1), [outcome, setOutcome] = (0, import_react44.useState)([]), current = values ?? (existing ? initialValues3(existing) : null), dialogWidth = Math.max(40, Math.min(width - 4, 90)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), label2 = agentName3(store.getState(), props.agentId), loopNames2 = [MAIN_LOOP, ...loops2.filter((l) => !l.info.isMain).map((l) => l.info.name)];
13860
+ let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), agent2 = useAgent(props.agentId), loops2 = useLoops(props.agentId) ?? [], timers = useAgentTimers(props.agentId), existing = props.timerId !== void 0 ? timers.data?.find((t) => t.id === props.timerId) : void 0, editing = props.timerId !== void 0, [values, setValues] = (0, import_react45.useState)(() => editing ? null : initialValues3(void 0, props.loop)), [step, setStep] = (0, import_react45.useState)("form"), [touched, setTouched] = (0, import_react45.useState)(!1), [outcome, setOutcome] = (0, import_react45.useState)([]), current = values ?? (existing ? initialValues3(existing) : null), dialogWidth = Math.max(40, Math.min(width - 4, 90)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), label2 = agentName3(store.getState(), props.agentId), loopNames2 = [MAIN_LOOP, ...loops2.filter((l) => !l.info.isMain).map((l) => l.info.name)];
13695
13861
  current && !loopNames2.includes(String(current.loop)) && loopNames2.push(String(current.loop));
13696
13862
  let scopeChoice = current?.scope ?? "agent", kind = current?.scheduleKind ?? "every", targetLoop = scopeChoice === "system" ? void 0 : String(current?.loop ?? MAIN_LOOP), result = current ? scheduleToTimer(
13697
13863
  { kind, value: String(current.scheduleValue ?? ""), payload: String(current.payload ?? ""), maxRuns: String(current.maxRuns ?? "") },
13698
13864
  targetLoop,
13699
13865
  { scope: scopeOf(scopeChoice), lambda: String(current.lambda ?? "").trim() || void 0 }
13700
- ) : null, input = result?.input ? { ...result.input, ...current?.locked ? { locked: !0 } : {} } : void 0, oldLoop = existing ? timerLoop2(existing) : null, loopChanged = !!existing && (targetLoop ?? null) !== oldLoop && targetLoop !== void 0 && oldLoop !== null, errors = (0, import_react44.useMemo)(() => {
13866
+ ) : null, input = result?.input ? { ...result.input, ...current?.locked ? { locked: !0 } : {} } : void 0, oldLoop = existing ? timerLoop2(existing) : null, loopChanged = !!existing && (targetLoop ?? null) !== oldLoop && targetLoop !== void 0 && oldLoop !== null, errors = (0, import_react45.useMemo)(() => {
13701
13867
  let e = {};
13702
13868
  return result?.error && (e.scheduleValue = result.error), scopeChoice !== "agent" && !String(current?.lambda ?? "").trim() && (e.lambda = "System-scope timers run a lambda: path/file.ts:functionName"), e;
13703
13869
  }, [result?.error, scopeChoice, current?.lambda]), hasErrors = Object.values(errors).some(Boolean), fields = [
@@ -13822,10 +13988,10 @@ function initialValues3(timer, loop) {
13822
13988
  }
13823
13989
 
13824
13990
  // src/main/tui/views/loops/TriggerDialog.tsx
13825
- var import_react45 = __toESM(require_react(), 1);
13991
+ var import_react46 = __toESM(require_react(), 1);
13826
13992
  var import_jsx_runtime56 = __toESM(require_jsx_runtime(), 1);
13827
13993
  function TriggerDialog({ overlay, close, width, height }) {
13828
- let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), loops2 = useLoops(props.agentId) ?? [], loaded = useAsyncData((c) => c.config(props.agentId), [props.agentId]), original = loaded.data?.config.triggers?.[props.type], [draft, setDraft] = (0, import_react45.useState)(null), current = draft ?? (loaded.data ? original ?? { enabled: !1, targets: [] } : null), [step, setStep] = (0, import_react45.useState)("targets"), [index, setIndex] = (0, import_react45.useState)(0), [editing, setEditing] = (0, import_react45.useState)(null), [targetValues, setTargetValues] = (0, import_react45.useState)({}), [targetErrors, setTargetErrors] = (0, import_react45.useState)({}), [message, setMessage] = (0, import_react45.useState)(""), dialogWidth = Math.max(44, Math.min(width - 4, 96)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), title = `Trigger ${props.type} ${theme2.glyph.sep} ${agentName3(store.getState(), props.agentId)}`, loopNames2 = [MAIN_LOOP, ...loops2.filter((l) => !l.info.isMain).map((l) => l.info.name)], dirty = !!draft && JSON.stringify(draft) !== JSON.stringify(original ?? { enabled: !1, targets: [] }), [confirmClose, setConfirmClose] = (0, import_react45.useState)(!1), update = (next) => setDraft(next), openTarget = (i) => {
13994
+ let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), loops2 = useLoops(props.agentId) ?? [], loaded = useAsyncData((c) => c.config(props.agentId), [props.agentId]), original = loaded.data?.config.triggers?.[props.type], [draft, setDraft] = (0, import_react46.useState)(null), current = draft ?? (loaded.data ? original ?? { enabled: !1, targets: [] } : null), [step, setStep] = (0, import_react46.useState)("targets"), [index, setIndex] = (0, import_react46.useState)(0), [editing, setEditing] = (0, import_react46.useState)(null), [targetValues, setTargetValues] = (0, import_react46.useState)({}), [targetErrors, setTargetErrors] = (0, import_react46.useState)({}), [message, setMessage] = (0, import_react46.useState)(""), dialogWidth = Math.max(44, Math.min(width - 4, 96)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), title = `Trigger ${props.type} ${theme2.glyph.sep} ${agentName3(store.getState(), props.agentId)}`, loopNames2 = [MAIN_LOOP, ...loops2.filter((l) => !l.info.isMain).map((l) => l.info.name)], dirty = !!draft && JSON.stringify(draft) !== JSON.stringify(original ?? { enabled: !1, targets: [] }), [confirmClose, setConfirmClose] = (0, import_react46.useState)(!1), update = (next) => setDraft(next), openTarget = (i) => {
13829
13995
  let target2 = i === null ? void 0 : current?.targets[i];
13830
13996
  setEditing(i), setTargetValues(targetToValues(target2)), setTargetErrors({}), setStep("target");
13831
13997
  }, saveTarget = () => {
@@ -13981,7 +14147,7 @@ function valuesToTarget(v, base2) {
13981
14147
  }
13982
14148
 
13983
14149
  // src/main/tui/views/loops/EntryDialog.tsx
13984
- var import_react46 = __toESM(require_react(), 1);
14150
+ var import_react47 = __toESM(require_react(), 1);
13985
14151
  var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
13986
14152
  function entryLines(entry, width) {
13987
14153
  let out = [], push = (text, tone) => {
@@ -14023,7 +14189,7 @@ function pretty(value) {
14023
14189
  }
14024
14190
  }
14025
14191
  function EntryDialog({ overlay, close, width, height }) {
14026
- let { entry, loop } = overlay.props ?? {}, theme2 = useTheme(), dialogWidth = Math.max(40, Math.min(width - 4, 110)), inner = dialogWidth - 4, rows = Math.max(4, height - 10), lines = entry ? entryLines(entry, inner) : [], [top, setTop] = (0, import_react46.useState)(0), maxTop = Math.max(0, lines.length - rows);
14192
+ let { entry, loop } = overlay.props ?? {}, theme2 = useTheme(), dialogWidth = Math.max(40, Math.min(width - 4, 110)), inner = dialogWidth - 4, rows = Math.max(4, height - 10), lines = entry ? entryLines(entry, inner) : [], [top, setTop] = (0, import_react47.useState)(0), maxTop = Math.max(0, lines.length - rows);
14027
14193
  if (useKeys((input, key) => key.escape || key.backspace || key.return || input === "q" ? (close(), !0) : key.downArrow || input === "j" ? (setTop((t) => Math.min(maxTop, t + 1)), !0) : key.upArrow || input === "k" ? (setTop((t) => Math.max(0, t - 1)), !0) : key.pageDown || input === " " ? (setTop((t) => Math.min(maxTop, t + rows)), !0) : key.pageUp ? (setTop((t) => Math.max(0, t - rows)), !0) : key.home || input === "g" ? (setTop(0), !0) : ((key.end || input === "G") && setTop(maxTop), !0), { layer: "overlay" }), !entry) return null;
14028
14194
  let tokens = formatTokens(entry);
14029
14195
  return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Modal, { title: `${loop} ${theme2.glyph.sep} entry #${entry.seq}`, width: dialogWidth, hints: [{ keys: "up down", label: "scroll" }, { keys: "pgup pgdn", label: "page" }, { keys: "backspace esc", label: "back" }], children: [
@@ -14051,14 +14217,14 @@ function EntryDialog({ overlay, close, width, height }) {
14051
14217
  }
14052
14218
 
14053
14219
  // src/main/tui/views/loops/SendDialog.tsx
14054
- var import_react47 = __toESM(require_react(), 1);
14220
+ var import_react48 = __toESM(require_react(), 1);
14055
14221
  var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
14056
14222
  async function sendToLoop(actions4, agentId, loop, text, agentLabel5) {
14057
14223
  let ok = await actions4.sendChat(text, { agentId, loop });
14058
14224
  return ok ? actions4.toast(`Sent to ${agentLabel5} ${loop}: turn queued (its reply is in the ${loop} transcript)`, "success") : actions4.toast(`Not sent to ${loop}: see the error in the ${loop} transcript`, "error"), ok;
14059
14225
  }
14060
14226
  function SendDialog({ overlay, close, width }) {
14061
- let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), loop = useLoop(props.agentId, props.loop), [values, setValues] = (0, import_react47.useState)({ text: props.text ?? "" }), [error, setError] = (0, import_react47.useState)(), label2 = agentName3(store.getState(), props.agentId), dialogWidth = Math.max(40, Math.min(width - 4, 90));
14227
+ let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), loop = useLoop(props.agentId, props.loop), [values, setValues] = (0, import_react48.useState)({ text: props.text ?? "" }), [error, setError] = (0, import_react48.useState)(), label2 = agentName3(store.getState(), props.agentId), dialogWidth = Math.max(40, Math.min(width - 4, 90));
14062
14228
  return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Modal, { title: `Send to ${props.loop} ${theme2.glyph.sep} ${label2}`, width: dialogWidth, hints: [{ keys: "enter", label: "send & wake" }, { keys: "esc", label: "cancel" }], children: [
14063
14229
  loop && !loop.info.enabled ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Text, { color: theme2.color.warn, children: [
14064
14230
  theme2.glyph.warn,
@@ -14567,7 +14733,7 @@ function resolutionText(task) {
14567
14733
  }
14568
14734
 
14569
14735
  // src/main/tui/views/inspect/SettingsTab.tsx
14570
- var import_react48 = __toESM(require_react(), 1);
14736
+ var import_react49 = __toESM(require_react(), 1);
14571
14737
 
14572
14738
  // src/main/tui/views/inspect/settings-model.ts
14573
14739
  var TOOL_GROUPS = [
@@ -15032,16 +15198,16 @@ async function actOnSetting(actions4, agentId, row4, config2) {
15032
15198
  }
15033
15199
  }
15034
15200
  function SettingsTab({ agentId, width, height, focused }) {
15035
- let theme2 = useTheme(), actions4 = useActions(), client = useClient(), agent2 = useAgent(agentId), [inspect3, update] = useInspectState(), [extras, setExtras] = (0, import_react48.useState)({}), config2 = agent2?.config, loopNames2 = [MAIN_LOOP, ...(config2?.loops ?? []).map((l) => l.name)], reload = async (announce = !1) => {
15201
+ let theme2 = useTheme(), actions4 = useActions(), client = useClient(), agent2 = useAgent(agentId), [inspect3, update] = useInspectState(), [extras, setExtras] = (0, import_react49.useState)({}), config2 = agent2?.config, loopNames2 = [MAIN_LOOP, ...(config2?.loops ?? []).map((l) => l.name)], reload = async (announce = !1) => {
15036
15202
  let cfg = await actions4.loadConfig(agentId), names = [MAIN_LOOP, ...(cfg?.loops ?? []).map((l) => l.name)], [context, host] = await Promise.all([
15037
15203
  loadContextUsage(client, agentId, names),
15038
15204
  client.setting("compute").then((r) => !!r.value?.hostAccessEnabled, () => null)
15039
15205
  ]);
15040
15206
  setExtras({ context, daemonHostAccess: host }), announce && cfg && actions4.toast("Settings reloaded", "info", 1500);
15041
15207
  };
15042
- (0, import_react48.useEffect)(() => {
15208
+ (0, import_react49.useEffect)(() => {
15043
15209
  reload();
15044
- }, [agentId]), (0, import_react48.useEffect)(() => {
15210
+ }, [agentId]), (0, import_react49.useEffect)(() => {
15045
15211
  config2 && loadContextUsage(client, agentId, loopNames2).then((context) => setExtras((e) => ({ ...e, context })));
15046
15212
  }, [loopNames2.join(",")]);
15047
15213
  let rows = config2 ? settingRows(config2, extras) : [], index = Math.min(inspect3.settingsIndex ?? 0, Math.max(0, rows.length - 1));
@@ -15104,7 +15270,7 @@ function SettingsTab({ agentId, width, height, focused }) {
15104
15270
  }
15105
15271
 
15106
15272
  // src/main/tui/views/inspect/SettingDialogs.tsx
15107
- var import_react49 = __toESM(require_react(), 1);
15273
+ var import_react50 = __toESM(require_react(), 1);
15108
15274
  var import_jsx_runtime62 = __toESM(require_jsx_runtime(), 1);
15109
15275
  function compactionRows(config2) {
15110
15276
  let main = mainThreshold(config2);
@@ -15123,8 +15289,8 @@ async function applyThreshold(store, agentId, loop, value) {
15123
15289
  return loop === MAIN_LOOP ? applyChange(actions4, agentId, (cfg) => setMainThreshold(cfg, value), "Compaction") : await actions4.updateLoop(agentId, loop, { compact_threshold: value }) ? (await actions4.loadConfig(agentId), actions4.toast(value === null ? `${loop} inherits main\u2019s threshold again` : `${loop} compacts at ${formatTokens2(value)} tokens`, "success", 2500), !0) : !1;
15124
15290
  }
15125
15291
  function CompactionOverlay({ overlay, close, width, height }) {
15126
- let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), agent2 = useAgent(agentId), config2 = agent2?.config, rows = config2 ? compactionRows(config2) : [], initial = Math.max(0, rows.findIndex((r) => r.loop === overlay.props?.loop)), [index, setIndex] = (0, import_react49.useState)(initial), [editing, setEditing] = (0, import_react49.useState)(null), [draft, setDraft] = (0, import_react49.useState)(""), [error, setError] = (0, import_react49.useState)(null), [context, setContext] = (0, import_react49.useState)({});
15127
- (0, import_react49.useEffect)(() => {
15292
+ let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), agent2 = useAgent(agentId), config2 = agent2?.config, rows = config2 ? compactionRows(config2) : [], initial = Math.max(0, rows.findIndex((r) => r.loop === overlay.props?.loop)), [index, setIndex] = (0, import_react50.useState)(initial), [editing, setEditing] = (0, import_react50.useState)(null), [draft, setDraft] = (0, import_react50.useState)(""), [error, setError] = (0, import_react50.useState)(null), [context, setContext] = (0, import_react50.useState)({});
15293
+ (0, import_react50.useEffect)(() => {
15128
15294
  config2 || actions4.loadConfig(agentId), loadContextUsage(store.client, agentId, [MAIN_LOOP, ...(config2?.loops ?? []).map((l) => l.name)]).then(setContext);
15129
15295
  }, [agentId]);
15130
15296
  let row4 = rows[Math.min(index, Math.max(0, rows.length - 1))], submit = async (value) => {
@@ -15207,7 +15373,7 @@ function CompactionOverlay({ overlay, close, width, height }) {
15207
15373
  );
15208
15374
  }
15209
15375
  function SettingChoiceOverlay({ overlay, close, width }) {
15210
- let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), setting = overlay.props?.setting === "send" ? "send" : "visibility", m = useAgent(agentId)?.config?.messaging, options = setting === "send" ? SEND_MODES.map((v) => ({ value: v, hint: SEND_MODE_HINTS[v] })) : VISIBILITY_TIERS.map((v) => ({ value: v, hint: VISIBILITY_HINTS[v] })), current = setting === "send" ? m?.mode ?? "respond_only" : m?.visibility ?? "localhost", [index, setIndex] = (0, import_react49.useState)(Math.max(0, options.findIndex((o) => o.value === current))), apply = async (value) => {
15376
+ let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), setting = overlay.props?.setting === "send" ? "send" : "visibility", m = useAgent(agentId)?.config?.messaging, options = setting === "send" ? SEND_MODES.map((v) => ({ value: v, hint: SEND_MODE_HINTS[v] })) : VISIBILITY_TIERS.map((v) => ({ value: v, hint: VISIBILITY_HINTS[v] })), current = setting === "send" ? m?.mode ?? "respond_only" : m?.visibility ?? "localhost", [index, setIndex] = (0, import_react50.useState)(Math.max(0, options.findIndex((o) => o.value === current))), apply = async (value) => {
15211
15377
  close(), value !== current && (setting === "visibility" && (value === "lan" || value === "public") && !await actions4.confirm({
15212
15378
  title: `Make the agent reachable ${value === "public" ? "from the internet" : "on the local network"}?`,
15213
15379
  message: `Visibility ${value}: ${VISIBILITY_HINTS[value]}. Other agents there can send it messages.`,
@@ -15437,13 +15603,13 @@ var inspect = {
15437
15603
  ], inspectCommands = { commands: [inspect, model, config, tasks, instructions, tools, compaction, media], actions: actions2 };
15438
15604
 
15439
15605
  // src/main/tui/views/inspect/EventsTab.tsx
15440
- var import_react51 = __toESM(require_react(), 1);
15606
+ var import_react52 = __toESM(require_react(), 1);
15441
15607
 
15442
15608
  // src/main/tui/views/inspect/hooks.ts
15443
- var import_react50 = __toESM(require_react(), 1);
15609
+ var import_react51 = __toESM(require_react(), 1);
15444
15610
  function useDaemonData(key, load) {
15445
- let store = useStore(), [data, setData] = (0, import_react50.useState)(void 0), [error, setError] = (0, import_react50.useState)(void 0), [loading, setLoading] = (0, import_react50.useState)(!1), [loadedAt, setLoadedAt] = (0, import_react50.useState)(void 0), [nonce2, setNonce] = (0, import_react50.useState)(0), loadRef = (0, import_react50.useRef)(load);
15446
- loadRef.current = load, (0, import_react50.useEffect)(() => {
15611
+ let store = useStore(), [data, setData] = (0, import_react51.useState)(void 0), [error, setError] = (0, import_react51.useState)(void 0), [loading, setLoading] = (0, import_react51.useState)(!1), [loadedAt, setLoadedAt] = (0, import_react51.useState)(void 0), [nonce2, setNonce] = (0, import_react51.useState)(0), loadRef = (0, import_react51.useRef)(load);
15612
+ loadRef.current = load, (0, import_react51.useEffect)(() => {
15447
15613
  if (key === null) {
15448
15614
  setData(void 0), setError(void 0);
15449
15615
  return;
@@ -15460,12 +15626,12 @@ function useDaemonData(key, load) {
15460
15626
  cancelled = !0;
15461
15627
  };
15462
15628
  }, [store, key, nonce2]);
15463
- let reload = (0, import_react50.useCallback)(() => setNonce((n) => n + 1), []);
15629
+ let reload = (0, import_react51.useCallback)(() => setNonce((n) => n + 1), []);
15464
15630
  return { data, error, loading, loadedAt, reload };
15465
15631
  }
15466
15632
  function useAgentName() {
15467
15633
  let store = useStore();
15468
- return (0, import_react50.useCallback)((agentId) => {
15634
+ return (0, import_react51.useCallback)((agentId) => {
15469
15635
  if (!agentId) return "daemon";
15470
15636
  let summary = store.getState().agents[agentId]?.summary;
15471
15637
  return summary?.handle || summary?.name || agentId.slice(0, 8);
@@ -15573,7 +15739,7 @@ function eventRow(event) {
15573
15739
  // src/main/tui/views/inspect/EventsTab.tsx
15574
15740
  var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1), EMPTY2 = [], EVENTS_REFRESH_MS = 100;
15575
15741
  function EventsTab({ width, height, focused, filters: stored, update, scope, json: json2 }) {
15576
- let theme2 = useTheme(), filters = scope === "agent" ? { ...stored, agent: "selected" } : stored, live = useThrottledSelector((s) => s.lastEvents ?? EMPTY2, EVENTS_REFRESH_MS), selectedAgentId = useSelectedAgentId(), selectedLoop = useSelectedLoop(), nameOf = useAgentName(), [frozen, setFrozen] = (0, import_react51.useState)(null), [clearedAfter, setClearedAfter] = (0, import_react51.useState)(0), [anchor, setAnchor] = (0, import_react51.useState)(null), [pinned, setPinned] = (0, import_react51.useState)(!0), [detail, setDetail] = (0, import_react51.useState)(!1), [editing, setEditing] = (0, import_react51.useState)(null), [draft, setDraft] = (0, import_react51.useState)(filters.types), [query, setQuery] = (0, import_react51.useState)(""), source = frozen ?? live, { types, agent: agent2, loop } = filters, events2 = (0, import_react51.useMemo)(
15742
+ let theme2 = useTheme(), filters = scope === "agent" ? { ...stored, agent: "selected" } : stored, live = useThrottledSelector((s) => s.lastEvents ?? EMPTY2, EVENTS_REFRESH_MS), selectedAgentId = useSelectedAgentId(), selectedLoop = useSelectedLoop(), nameOf = useAgentName(), [frozen, setFrozen] = (0, import_react52.useState)(null), [clearedAfter, setClearedAfter] = (0, import_react52.useState)(0), [anchor, setAnchor] = (0, import_react52.useState)(null), [pinned, setPinned] = (0, import_react52.useState)(!0), [detail, setDetail] = (0, import_react52.useState)(!1), [editing, setEditing] = (0, import_react52.useState)(null), [draft, setDraft] = (0, import_react52.useState)(filters.types), [query, setQuery] = (0, import_react52.useState)(""), source = frozen ?? live, { types, agent: agent2, loop } = filters, events2 = (0, import_react52.useMemo)(
15577
15743
  () => {
15578
15744
  let matched = filterEvents(source, { types, agent: agent2, loop, follow: !0 }, { selectedAgentId, selectedLoop });
15579
15745
  clearedAfter && (matched = matched.filter((e) => e.timestamp > clearedAfter));
@@ -15581,10 +15747,10 @@ function EventsTab({ width, height, focused, filters: stored, update, scope, jso
15581
15747
  return q && (matched = matched.filter((e) => eventRow(e).search.includes(q) || nameOf(e.agent_id).toLowerCase().includes(q))), matched;
15582
15748
  },
15583
15749
  [source, types, agent2, loop, selectedAgentId, selectedLoop, clearedAfter, query, nameOf]
15584
- ), indexOf = (0, import_react51.useMemo)(() => {
15750
+ ), indexOf = (0, import_react52.useMemo)(() => {
15585
15751
  let map = /* @__PURE__ */ new Map();
15586
15752
  return events2.forEach((e, i) => map.set(eventKey(e), i)), map;
15587
- }, [events2]), lastFrozen = frozen?.at(-1), newWhileFrozen = lastFrozen ? live.length - 1 - live.lastIndexOf(lastFrozen) : 0, following = filters.follow && pinned && !frozen, anchored = anchor === null ? -1 : indexOf.get(anchor) ?? -1, index = following || anchored < 0 ? Math.max(0, events2.length - 1) : anchored, current = events2[index], detailRows = detail && current ? Math.max(4, Math.floor((height - 3) / 2)) : 0, listHeight = Math.max(1, height - 2 - (editing ? 1 : 0) - (detailRows ? detailRows + 1 : 0)), nameWidth = 10, loopWidth = 12, typeWidth = 22, agentLabel5 = filters.agent === "selected" || filters.loop === "selected" ? selectedAgentId ? nameOf(selectedAgentId) : "selected (none)" : "all agents", loopLabel = filters.loop === "selected" ? selectedLoop : "all loops", onSelect = (0, import_react51.useCallback)((i, item) => {
15753
+ }, [events2]), lastFrozen = frozen?.at(-1), newWhileFrozen = lastFrozen ? live.length - 1 - live.lastIndexOf(lastFrozen) : 0, following = filters.follow && pinned && !frozen, anchored = anchor === null ? -1 : indexOf.get(anchor) ?? -1, index = following || anchored < 0 ? Math.max(0, events2.length - 1) : anchored, current = events2[index], detailRows = detail && current ? Math.max(4, Math.floor((height - 3) / 2)) : 0, listHeight = Math.max(1, height - 2 - (editing ? 1 : 0) - (detailRows ? detailRows + 1 : 0)), nameWidth = 10, loopWidth = 12, typeWidth = 22, agentLabel5 = filters.agent === "selected" || filters.loop === "selected" ? selectedAgentId ? nameOf(selectedAgentId) : "selected (none)" : "all agents", loopLabel = filters.loop === "selected" ? selectedLoop : "all loops", onSelect = (0, import_react52.useCallback)((i, item) => {
15588
15754
  setAnchor(item ? eventKey(item) : null), setPinned(i >= events2.length - 1);
15589
15755
  }, [events2.length]), onKey = (input, key) => key.ctrl || key.meta ? !1 : key.return ? (setDetail((d) => !d), !0) : (key.escape || key.backspace) && detail ? (setDetail(!1), !0) : input === " " ? (frozen ? (setFrozen(null), setPinned(!0)) : setFrozen(live), !0) : input === "a" && scope === "all" ? (update({ agent: filters.agent === "all" ? "selected" : "all", loop: filters.agent === "all" ? filters.loop : "all" }), !0) : input === "l" ? (update({ loop: filters.loop === "all" ? "selected" : "all" }), !0) : input === "t" ? (setDraft(filters.types), setEditing("type"), !0) : input === "/" ? (setDraft(query), setEditing("search"), !0) : key.escape && query ? (setQuery(""), !0) : input === "f" ? (update({ follow: !filters.follow }), setPinned(!0), !0) : input === "c" ? (setClearedAfter(Date.now()), !0) : input === "x" && (filters.types || scope === "all" && filters.agent !== "all" || filters.loop !== "all") ? (update({ types: "", agent: scope === "all" ? "all" : "selected", loop: "all" }), !0) : !1, status = [
15590
15756
  frozen ? `paused${newWhileFrozen > 0 ? ` (+${newWhileFrozen} new)` : ""}` : following ? "following" : "scrolled (End follows)",
@@ -15593,7 +15759,7 @@ function EventsTab({ width, height, focused, filters: stored, update, scope, jso
15593
15759
  filters.types ? `type: ${filters.types}` : "all types",
15594
15760
  query ? `search: ${query}` : "",
15595
15761
  clearedAfter ? `cleared ${formatClock(clearedAfter)}` : ""
15596
- ].filter(Boolean).join(` ${theme2.glyph.sep} `), detailLines2 = (0, import_react51.useMemo)(() => detailRows && current ? valueLines(current, json2).slice(0, detailRows) : [], [detailRows, current, json2]);
15762
+ ].filter(Boolean).join(` ${theme2.glyph.sep} `), detailLines2 = (0, import_react52.useMemo)(() => detailRows && current ? valueLines(current, json2).slice(0, detailRows) : [], [detailRows, current, json2]);
15597
15763
  return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(Box_default, { flexDirection: "column", width, height, children: [
15598
15764
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(Text, { wrap: "truncate-end", children: [
15599
15765
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Text, { bold: !0, color: theme2.color.live, children: "Umbilical " }),
@@ -15691,7 +15857,7 @@ function typeColor(theme2, type) {
15691
15857
  }
15692
15858
 
15693
15859
  // src/main/tui/views/inspect/ConfigTab.tsx
15694
- var import_react52 = __toESM(require_react(), 1);
15860
+ var import_react53 = __toESM(require_react(), 1);
15695
15861
  var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
15696
15862
  import { promises as fs5 } from "node:fs";
15697
15863
  import { tmpdir as tmpdir4 } from "node:os";
@@ -15760,12 +15926,12 @@ Warning: ${check.warnings.join("; ")}` : ""}`,
15760
15926
  }
15761
15927
  }
15762
15928
  function ConfigTab({ agentId, label: label2, width, height, focused }) {
15763
- let theme2 = useTheme(), actions4 = useActions(), { suspendTerminal } = use_app_default(), agent2 = useAgent(agentId), [inspect3, update] = useInspectState(), [busy, setBusy] = (0, import_react52.useState)(!1), config2 = agent2?.config, edit = () => {
15929
+ let theme2 = useTheme(), actions4 = useActions(), { suspendTerminal } = use_app_default(), agent2 = useAgent(agentId), [inspect3, update] = useInspectState(), [busy, setBusy] = (0, import_react53.useState)(!1), config2 = agent2?.config, edit = () => {
15764
15930
  setBusy(!0), editConfigFlow(agentId, label2, actions4, suspendTerminal).finally(() => setBusy(!1));
15765
15931
  };
15766
- (0, import_react52.useEffect)(() => {
15932
+ (0, import_react53.useEffect)(() => {
15767
15933
  !inspect3.editRequest || busy || (update({ editRequest: void 0 }), edit());
15768
- }, [inspect3.editRequest]), (0, import_react52.useEffect)(() => {
15934
+ }, [inspect3.editRequest]), (0, import_react53.useEffect)(() => {
15769
15935
  config2 || actions4.loadConfig(agentId);
15770
15936
  }, [agentId]), useKeys((input, key) => key.ctrl || key.meta || busy ? !1 : input === "e" ? (edit(), !0) : input === "r" ? (actions4.loadConfig(agentId).then((c) => {
15771
15937
  c && actions4.toast("Config reloaded", "info", 1500);
@@ -15799,7 +15965,7 @@ function ConfigTab({ agentId, label: label2, width, height, focused }) {
15799
15965
  }
15800
15966
 
15801
15967
  // src/main/tui/views/inspect/DiagTabs.tsx
15802
- var import_react53 = __toESM(require_react(), 1);
15968
+ var import_react54 = __toESM(require_react(), 1);
15803
15969
 
15804
15970
  // src/main/tui/views/inspect/diag-lines.ts
15805
15971
  function stamp(at) {
@@ -15901,7 +16067,7 @@ var import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
15901
16067
  function DiagTab({ agentId, width, height, focused, load, build, hint, prefix, onKey }) {
15902
16068
  let theme2 = useTheme(), [inspect3] = useInspectState(), { data, error, loading, loadedAt, reload } = useDaemonData(agentId, load);
15903
16069
  useKeys((input, key) => key.ctrl || key.meta ? !1 : input === "r" ? (reload(), !0) : onKey?.(input, key) ?? !1, { layer: "main", active: focused });
15904
- let lines = (0, import_react53.useMemo)(() => {
16070
+ let lines = (0, import_react54.useMemo)(() => {
15905
16071
  let head = prefix && !inspect3.json ? prefix : [];
15906
16072
  return error ? [...head, plain(`Could not load: ${error}`, "error"), plain("r retries.", "muted")] : data === void 0 ? head : inspect3.json ? valueLines(data, !0) : [...head, ...build(data)];
15907
16073
  }, [data, error, inspect3.json, build, prefix]);
@@ -15919,7 +16085,7 @@ function DiagTab({ agentId, width, height, focused, load, build, hint, prefix, o
15919
16085
  ] });
15920
16086
  }
15921
16087
  function RuntimeTab(props) {
15922
- let store = useStore(), loops2 = useLoops(props.agentId), build = (0, import_react53.useMemo)(() => (d) => runtimeLines(d, loops2), [loops2]), web = useTuiSelector((s) => s.web), config2 = useTuiSelector((s) => s.agents[props.agentId]?.config), site = siteOf(store.getState(), props.agentId), prefix = (0, import_react53.useMemo)(() => site ? siteLines(site) : void 0, [web, config2, props.agentId]);
16088
+ let store = useStore(), loops2 = useLoops(props.agentId), build = (0, import_react54.useMemo)(() => (d) => runtimeLines(d, loops2), [loops2]), web = useTuiSelector((s) => s.web), config2 = useTuiSelector((s) => s.agents[props.agentId]?.config), site = siteOf(store.getState(), props.agentId), prefix = (0, import_react54.useMemo)(() => site ? siteLines(site) : void 0, [web, config2, props.agentId]);
15923
16089
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(DiagTab, { ...props, load: (c) => c.agentRuntime(props.agentId), build, prefix, onKey: (input, key) => !site || key.ctrl || key.meta ? !1 : input === "w" ? (openSite(store, props.agentId), !0) : input === "W" ? (copySiteUrl(store, props.agentId), !0) : !1, hint: site ? "w open site \xB7 W copy URL" : void 0 });
15924
16090
  }
15925
16091
  function siteLines(site) {
@@ -15932,7 +16098,7 @@ function siteLines(site) {
15932
16098
  return out.push([{ text: " server ", tone: "key" }, { text: serverText(site.server), tone: site.url ? "success" : "muted" }]), out.push([{ text: " serves ", tone: "key" }, { text: servedText(site) }]), out.push(blank()), out;
15933
16099
  }
15934
16100
  function UsageTab(props) {
15935
- let agent2 = useAgent(props.agentId), build = (0, import_react53.useMemo)(() => (d) => usageLines(d, agent2?.tokens, agent2?.lastModel), [agent2?.tokens, agent2?.lastModel]);
16101
+ let agent2 = useAgent(props.agentId), build = (0, import_react54.useMemo)(() => (d) => usageLines(d, agent2?.tokens, agent2?.lastModel), [agent2?.tokens, agent2?.lastModel]);
15936
16102
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(DiagTab, { ...props, load: (c) => c.agentUsage(props.agentId), build });
15937
16103
  }
15938
16104
  function McpTab(props) {
@@ -15948,7 +16114,7 @@ function IdentityTab(props) {
15948
16114
  }
15949
16115
  var LOG_LIMIT = 200, LOG_POLL_MS = 2e3;
15950
16116
  function LogsTab({ agentId, width, height, focused }) {
15951
- let theme2 = useTheme(), actions4 = useActions(), { client } = useStore(), [inspect3, update] = useInspectState(), follow = inspect3.logsFollow, [logs, setLogs] = (0, import_react53.useState)([]), [error, setError] = (0, import_react53.useState)(void 0), [cursor, setCursor] = (0, import_react53.useState)(0), [pinned, setPinned] = (0, import_react53.useState)(!0), [detail, setDetail] = (0, import_react53.useState)(!1), lastId = (0, import_react53.useRef)(0), loadAll = async () => {
16117
+ let theme2 = useTheme(), actions4 = useActions(), { client } = useStore(), [inspect3, update] = useInspectState(), follow = inspect3.logsFollow, [logs, setLogs] = (0, import_react54.useState)([]), [error, setError] = (0, import_react54.useState)(void 0), [cursor, setCursor] = (0, import_react54.useState)(0), [pinned, setPinned] = (0, import_react54.useState)(!0), [detail, setDetail] = (0, import_react54.useState)(!1), lastId = (0, import_react54.useRef)(0), loadAll = async () => {
15952
16118
  let result = await actions4.run("Logs", (c) => c.logs(agentId, { limit: LOG_LIMIT }));
15953
16119
  if (!result) {
15954
16120
  setError("could not load logs");
@@ -15957,9 +16123,9 @@ function LogsTab({ agentId, width, height, focused }) {
15957
16123
  let sorted = [...result.logs].sort((a, b) => a.id - b.id);
15958
16124
  lastId.current = sorted.at(-1)?.id ?? 0, setLogs(sorted), setError(void 0);
15959
16125
  };
15960
- (0, import_react53.useEffect)(() => {
16126
+ (0, import_react54.useEffect)(() => {
15961
16127
  lastId.current = 0, setLogs([]), loadAll();
15962
- }, [agentId]), (0, import_react53.useEffect)(() => {
16128
+ }, [agentId]), (0, import_react54.useEffect)(() => {
15963
16129
  if (!follow) return;
15964
16130
  let stopped = !1, timer = setInterval(async () => {
15965
16131
  try {
@@ -16047,8 +16213,8 @@ function parseMaybeJson2(text) {
16047
16213
  }
16048
16214
  var PAGE = 50;
16049
16215
  function TablesTab({ agentId, width, height, focused }) {
16050
- let theme2 = useTheme(), [inspect3] = useInspectState(), tables = useDaemonData(agentId, (c) => c.tables(agentId)), [open2, setOpen] = (0, import_react53.useState)(null), [offset, setOffset] = (0, import_react53.useState)(0), [rowIndex, setRowIndex] = (0, import_react53.useState)(0), [rowDetail, setRowDetail] = (0, import_react53.useState)(!1), rows = useDaemonData(open2 ? `${agentId}:${open2}:${offset}` : null, (c) => c.table(agentId, open2 ?? "", { limit: PAGE, offset })), total = tables.data?.tables.find((t) => t.name === open2)?.row_count;
16051
- if ((0, import_react53.useEffect)(() => {
16216
+ let theme2 = useTheme(), [inspect3] = useInspectState(), tables = useDaemonData(agentId, (c) => c.tables(agentId)), [open2, setOpen] = (0, import_react54.useState)(null), [offset, setOffset] = (0, import_react54.useState)(0), [rowIndex, setRowIndex] = (0, import_react54.useState)(0), [rowDetail, setRowDetail] = (0, import_react54.useState)(!1), rows = useDaemonData(open2 ? `${agentId}:${open2}:${offset}` : null, (c) => c.table(agentId, open2 ?? "", { limit: PAGE, offset })), total = tables.data?.tables.find((t) => t.name === open2)?.row_count;
16217
+ if ((0, import_react54.useEffect)(() => {
16052
16218
  setOpen(null), setOffset(0);
16053
16219
  }, [agentId]), useKeys((input, key) => {
16054
16220
  if (!open2 || key.ctrl || key.meta) return !1;
@@ -16123,7 +16289,7 @@ function rowKey(row4, all) {
16123
16289
  }
16124
16290
 
16125
16291
  // src/main/tui/views/inspect/TasksTab.tsx
16126
- var import_react54 = __toESM(require_react(), 1);
16292
+ var import_react55 = __toESM(require_react(), 1);
16127
16293
  var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1), TASKS_RELOAD_MS = 250, FILTER_LABEL = {
16128
16294
  pending: "pending (awaiting approval or resolve)",
16129
16295
  active: "active (pending + running)",
@@ -16131,7 +16297,7 @@ var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1), TASKS_RELOAD_MS =
16131
16297
  };
16132
16298
  function useTaskEventReload(agentId, reload) {
16133
16299
  let store = useStore();
16134
- (0, import_react54.useEffect)(() => {
16300
+ (0, import_react55.useEffect)(() => {
16135
16301
  let seen = store.getState().lastEvents.at(-1), timer = null, unsubscribe = store.subscribe(() => {
16136
16302
  let events2 = store.getState().lastEvents, last = events2.at(-1);
16137
16303
  if (last === seen) return;
@@ -16151,12 +16317,12 @@ function useTaskEventReload(agentId, reload) {
16151
16317
  }, [store, agentId, reload]);
16152
16318
  }
16153
16319
  function TasksTab({ agentId, width, height, focused }) {
16154
- let theme2 = useTheme(), actions4 = useActions(), agent2 = useAgent(agentId), agentLabel5 = agent2?.summary.handle || agent2?.summary.name || agentId, [inspect3, update] = useInspectState(), filter = inspect3.tasksFilter, [tick, setTick] = (0, import_react54.useState)(0), refresh2 = (0, import_react54.useMemo)(() => () => setTick((n) => n + 1), []), tasks2 = useDaemonData(`${agentId}:${filter}:${tick}`, (c) => loadTasks(c, agentId, filter)), [selectedId, setSelectedId] = (0, import_react54.useState)(null), [detailId, setDetailId] = (0, import_react54.useState)(null), detail = useDaemonData(detailId ? `${agentId}:${detailId}:${tick}` : null, (c) => c.task(agentId, detailId ?? "")), [editing, setEditing] = (0, import_react54.useState)(!1), [draft, setDraft] = (0, import_react54.useState)(""), [query, setQuery] = (0, import_react54.useState)("");
16155
- useTaskEventReload(agentId, refresh2), (0, import_react54.useEffect)(() => {
16320
+ let theme2 = useTheme(), actions4 = useActions(), agent2 = useAgent(agentId), agentLabel5 = agent2?.summary.handle || agent2?.summary.name || agentId, [inspect3, update] = useInspectState(), filter = inspect3.tasksFilter, [tick, setTick] = (0, import_react55.useState)(0), refresh2 = (0, import_react55.useMemo)(() => () => setTick((n) => n + 1), []), tasks2 = useDaemonData(`${agentId}:${filter}:${tick}`, (c) => loadTasks(c, agentId, filter)), [selectedId, setSelectedId] = (0, import_react55.useState)(null), [detailId, setDetailId] = (0, import_react55.useState)(null), detail = useDaemonData(detailId ? `${agentId}:${detailId}:${tick}` : null, (c) => c.task(agentId, detailId ?? "")), [editing, setEditing] = (0, import_react55.useState)(!1), [draft, setDraft] = (0, import_react55.useState)(""), [query, setQuery] = (0, import_react55.useState)("");
16321
+ useTaskEventReload(agentId, refresh2), (0, import_react55.useEffect)(() => {
16156
16322
  setSelectedId(null), setDetailId(null);
16157
16323
  }, [agentId]);
16158
- let all = (0, import_react54.useMemo)(() => tasks2.data ?? [], [tasks2.data]), visible = (0, import_react54.useMemo)(() => searchTasks(all.filter((t) => matchesFilter(t, filter)), query), [all, filter, query]), found = selectedId ? visible.findIndex((t) => t.id === selectedId) : -1, index = found >= 0 ? found : 0, current = visible[index], adrift = selectedId !== null && found < 0;
16159
- (0, import_react54.useEffect)(() => {
16324
+ let all = (0, import_react55.useMemo)(() => tasks2.data ?? [], [tasks2.data]), visible = (0, import_react55.useMemo)(() => searchTasks(all.filter((t) => matchesFilter(t, filter)), query), [all, filter, query]), found = selectedId ? visible.findIndex((t) => t.id === selectedId) : -1, index = found >= 0 ? found : 0, current = visible[index], adrift = selectedId !== null && found < 0;
16325
+ (0, import_react55.useEffect)(() => {
16160
16326
  selectedId === null && visible[0] && setSelectedId(visible[0].id);
16161
16327
  }, [selectedId, visible]);
16162
16328
  let shown = detailId ? detail.data?.task ?? all.find((t) => t.id === detailId) : void 0, act = (input, task, drifted = !1) => {
@@ -16316,18 +16482,18 @@ function TasksTab({ agentId, width, height, focused }) {
16316
16482
  }
16317
16483
 
16318
16484
  // src/main/tui/views/inspect/ToolsDialog.tsx
16319
- var import_react55 = __toESM(require_react(), 1);
16485
+ var import_react56 = __toESM(require_react(), 1);
16320
16486
  var import_jsx_runtime67 = __toESM(require_jsx_runtime(), 1);
16321
16487
  function stateWords(row4) {
16322
16488
  let parts = [row4.enabled ? "enabled" : "disabled"];
16323
16489
  return row4.enabled && parts.push(row4.visible ? "in the agent\u2019s tool list" : "hidden from the tool list (still callable from code)"), row4.restricted && parts.push(row4.enabled ? "every LLM call waits for your approval" : "needs approval when enabled"), row4.locked && parts.push("locked: the agent cannot change it"), row4.status && parts.push(`MCP: ${row4.status}${row4.status === "changed" ? " (schema changed, review before enabling)" : ""}`), parts.join(" \xB7 ");
16324
16490
  }
16325
16491
  function ToolsOverlay({ overlay, close, width, height }) {
16326
- let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), agent2 = useAgent(agentId), config2 = agent2?.config, [catalog, setCatalog] = (0, import_react55.useState)(null), [live, setLive] = (0, import_react55.useState)(null), [query, setQuery] = (0, import_react55.useState)(typeof overlay.props?.query == "string" ? overlay.props.query : ""), [typing, setTyping] = (0, import_react55.useState)(!1), [index, setIndex] = (0, import_react55.useState)(0), [busy, setBusy] = (0, import_react55.useState)(0);
16327
- (0, import_react55.useEffect)(() => {
16492
+ let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, agentId = String(overlay.props?.agentId ?? ""), agent2 = useAgent(agentId), config2 = agent2?.config, [catalog, setCatalog] = (0, import_react56.useState)(null), [live, setLive] = (0, import_react56.useState)(null), [query, setQuery] = (0, import_react56.useState)(typeof overlay.props?.query == "string" ? overlay.props.query : ""), [typing, setTyping] = (0, import_react56.useState)(!1), [index, setIndex] = (0, import_react56.useState)(0), [busy, setBusy] = (0, import_react56.useState)(0);
16493
+ (0, import_react56.useEffect)(() => {
16328
16494
  config2 || actions4.loadConfig(agentId), store.client.agentTools(agentId).then((r) => setCatalog(r.tools), () => setCatalog(null)), store.client.agentMcp(agentId).then(setLive, () => setLive(null));
16329
16495
  }, [agentId]);
16330
- let rows = (0, import_react55.useMemo)(() => config2 ? filterToolRows(buildToolRows(config2, catalog), query) : [], [config2, catalog, query]), at = Math.min(index, Math.max(0, rows.length - 1)), row4 = rows[at], act = (field) => {
16496
+ let rows = (0, import_react56.useMemo)(() => config2 ? filterToolRows(buildToolRows(config2, catalog), query) : [], [config2, catalog, query]), at = Math.min(index, Math.max(0, rows.length - 1)), row4 = rows[at], act = (field) => {
16331
16497
  if (!row4) return;
16332
16498
  setBusy((n) => n + 1);
16333
16499
  let done = () => setBusy((n) => n - 1);
@@ -16457,17 +16623,17 @@ function ToolsOverlay({ overlay, close, width, height }) {
16457
16623
  }
16458
16624
 
16459
16625
  // src/main/tui/views/inspect/InstructionsDialog.tsx
16460
- var import_react56 = __toESM(require_react(), 1);
16626
+ var import_react57 = __toESM(require_react(), 1);
16461
16627
  var import_jsx_runtime68 = __toESM(require_jsx_runtime(), 1);
16462
16628
  function InstructionsOverlay({ overlay, close, width, height }) {
16463
- let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, { suspendTerminal } = use_app_default(), agentId = String(overlay.props?.agentId ?? ""), external = overlay.props?.editor === !0, who = store.getState().agents[agentId]?.summary.handle || store.getState().agents[agentId]?.summary.name || agentId, [original, setOriginal] = (0, import_react56.useState)(null), [text, setText] = (0, import_react56.useState)(""), [locked, setLocked] = (0, import_react56.useState)(!1), [busy, setBusy] = (0, import_react56.useState)(external ? `editing in ${editorLabel()}\u2026` : null), closed = (0, import_react56.useRef)(!1), done = () => {
16629
+ let theme2 = useTheme(), store = useStore(), { actions: actions4 } = store, { suspendTerminal } = use_app_default(), agentId = String(overlay.props?.agentId ?? ""), external = overlay.props?.editor === !0, who = store.getState().agents[agentId]?.summary.handle || store.getState().agents[agentId]?.summary.name || agentId, [original, setOriginal] = (0, import_react57.useState)(null), [text, setText] = (0, import_react57.useState)(""), [locked, setLocked] = (0, import_react57.useState)(!1), [busy, setBusy] = (0, import_react57.useState)(external ? `editing in ${editorLabel()}\u2026` : null), closed = (0, import_react57.useRef)(!1), done = () => {
16464
16630
  closed.current || (closed.current = !0, close());
16465
16631
  }, openEditor = async (from) => {
16466
16632
  setBusy(`editing in ${editorLabel()}\u2026`);
16467
16633
  let edited = await editInstructionsExternally(actions4, who, from, suspendTerminal);
16468
16634
  return setBusy(null), edited ?? null;
16469
16635
  };
16470
- (0, import_react56.useEffect)(() => {
16636
+ (0, import_react57.useEffect)(() => {
16471
16637
  (async () => {
16472
16638
  let fresh = await actions4.run("Instructions", (c) => c.config(agentId));
16473
16639
  if (!fresh) {
@@ -16546,13 +16712,13 @@ function InstructionsOverlay({ overlay, close, width, height }) {
16546
16712
  }
16547
16713
 
16548
16714
  // src/main/tui/views/inspect/overlays.tsx
16549
- var import_react57 = __toESM(require_react(), 1);
16715
+ var import_react58 = __toESM(require_react(), 1);
16550
16716
  var import_jsx_runtime69 = __toESM(require_jsx_runtime(), 1);
16551
16717
  function ThemeOverlay({ overlay, close, width }) {
16552
- let theme2 = useTheme(), store = useStore(), requested = typeof overlay.props?.name == "string" ? overlay.props.name : "", currentIndex = Math.max(0, THEMES.findIndex((t) => t.name === theme2.name)), [index, setIndex] = (0, import_react57.useState)(currentIndex), apply = (choice) => {
16718
+ let theme2 = useTheme(), store = useStore(), requested = typeof overlay.props?.name == "string" ? overlay.props.name : "", currentIndex = Math.max(0, THEMES.findIndex((t) => t.name === theme2.name)), [index, setIndex] = (0, import_react58.useState)(currentIndex), apply = (choice) => {
16553
16719
  applyTheme(theme2, choice), close(), store.actions.toast(`Theme: ${choice.label}${choice.colors ? "" : " (no color)"}`, "success", 2500);
16554
16720
  };
16555
- if ((0, import_react57.useEffect)(() => {
16721
+ if ((0, import_react58.useEffect)(() => {
16556
16722
  if (!requested) return;
16557
16723
  let choice = requested === "next" ? findTheme(nextThemeName(theme2.name)) : findTheme(requested);
16558
16724
  choice ? apply(choice) : (close(), store.actions.toast(`No theme "${requested}". Themes: ${THEMES.map((t) => t.name).join(", ")}`, "warn"));
@@ -16777,7 +16943,7 @@ var inspect2 = {
16777
16943
  }, inspect_default = inspect2;
16778
16944
 
16779
16945
  // src/main/tui/views/runtime/index.tsx
16780
- var import_react59 = __toESM(require_react(), 1);
16946
+ var import_react60 = __toESM(require_react(), 1);
16781
16947
 
16782
16948
  // src/main/tui/views/runtime/commands.ts
16783
16949
  var open = (ctx, tab) => openRuntime(ctx.actions, ctx.state(), { tab }), runtime = {
@@ -16833,11 +16999,11 @@ var events = {
16833
16999
  })), runtimeCommands = { commands: commands2, actions: actions3 };
16834
17000
 
16835
17001
  // src/main/tui/views/runtime/FoldersTab.tsx
16836
- var import_react58 = __toESM(require_react(), 1);
17002
+ var import_react59 = __toESM(require_react(), 1);
16837
17003
  var import_jsx_runtime71 = __toESM(require_jsx_runtime(), 1), CURSOR_KEY = "runtime.folders.cursor";
16838
17004
  function FoldersTab({ width, height, focused }) {
16839
17005
  let theme2 = useTheme(), store = useStore(), rev = useTuiSelector((s) => readFolders(s).rev), { data, error, loading, loadedAt, reload } = useDaemonData(`folders:${rev}`, () => loadFolders(store)), [cursor, setCursor] = useViewState(CURSOR_KEY, 0), rows = data ?? [], at = Math.min(cursor, Math.max(0, rows.length - 1));
16840
- (0, import_react58.useEffect)(() => {
17006
+ (0, import_react59.useEffect)(() => {
16841
17007
  at !== cursor && setCursor(at);
16842
17008
  }, [at, cursor, setCursor]), useKeys((input, key) => {
16843
17009
  if (key.ctrl || key.meta) return !1;
@@ -16895,7 +17061,7 @@ var import_jsx_runtime72 = __toESM(require_jsx_runtime(), 1);
16895
17061
  function ReportTab({ kind, width, height, focused, onKey, hint }) {
16896
17062
  let theme2 = useTheme(), store = useStore(), json2 = useStoreJson(), report2 = REPORTS[kind], { data, error, loading, loadedAt, reload } = useDaemonData(kind, (client) => report2.load(client, store.getState()));
16897
17063
  useKeys((input, key) => key.ctrl || key.meta ? !1 : input === "r" ? (reload(), !0) : onKey?.(input, key, reload) ?? !1, { layer: "main", active: focused });
16898
- let lines = (0, import_react59.useMemo)(() => error ? [plain(`Could not load: ${error}`, "error"), plain("r retries.", "muted")] : data ? json2 ? jsonLines(data.data) : data.lines : [], [data, error, json2]);
17064
+ let lines = (0, import_react60.useMemo)(() => error ? [plain(`Could not load: ${error}`, "error"), plain("r retries.", "muted")] : data ? json2 ? jsonLines(data.data) : data.lines : [], [data, error, json2]);
16899
17065
  return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(Box_default, { flexDirection: "column", width, height, children: [
16900
17066
  /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(LinesView, { lines, width, height: Math.max(1, height - 1), active: focused, emptyText: loading ? `Asking the daemon at ${store.getState().daemonUrl}\u2026` : "Nothing to show." }),
16901
17067
  /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: [
@@ -16923,7 +17089,7 @@ function IdentityTab2({ width, height, focused }) {
16923
17089
  let choice = choices.find((c) => c.key === input);
16924
17090
  return choice ? (openIdentity(store, { mode: choice.mode }), !0) : !1;
16925
17091
  }, { layer: "main", active: focused });
16926
- let lines = (0, import_react59.useMemo)(() => {
17092
+ let lines = (0, import_react60.useMemo)(() => {
16927
17093
  if (!identity) return [plain("This daemon does not report an owner identity (update the daemon).", "muted")];
16928
17094
  let badge = identityBadge(identity), { title, next } = onboardingLines(identity), out = [heading(title)];
16929
17095
  next && out.push(plain(` ${next}`, "warn")), badge && out.push([{ text: " " }, { text: badge.text, tone: badge.tone === "warn" ? "warn" : "muted" }]), out.push(blank(), ...treeLines(redactSecrets(identity), 2)), out.push(blank(), heading("Actions")), out.push(plain(" Enter identity dialog (status, backup, lock / unlock)", "accent"));
@@ -17039,9 +17205,9 @@ var VIEWS = [chat_default, files_default, loops_default, inspect_default, fleet_
17039
17205
  // src/main/tui/app/App.tsx
17040
17206
  var import_jsx_runtime73 = __toESM(require_jsx_runtime(), 1);
17041
17207
  function App({ store, theme: theme2, views = VIEWS, builtins = [BUILTIN_COMMANDS], onExit, reserveRows = 0, reserveColumns = 0 }) {
17042
- let app = use_app_default(), router = (0, import_react60.useMemo)(() => createKeyRouter(), []), registry = (0, import_react60.useMemo)(() => collectCommands(views, builtins), [views, builtins]), exit = (0, import_react60.useCallback)(() => {
17208
+ let app = use_app_default(), router = (0, import_react61.useMemo)(() => createKeyRouter(), []), registry = (0, import_react61.useMemo)(() => collectCommands(views, builtins), [views, builtins]), exit = (0, import_react61.useCallback)(() => {
17043
17209
  onExit?.(), app.exit();
17044
- }, [app, onExit]), shell = (0, import_react60.useMemo)(() => ({ views, registry, exit, reserveRows, reserveColumns }), [views, registry, exit, reserveRows, reserveColumns]);
17210
+ }, [app, onExit]), shell = (0, import_react61.useMemo)(() => ({ views, registry, exit, reserveRows, reserveColumns }), [views, registry, exit, reserveRows, reserveColumns]);
17045
17211
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(ThemeContext.Provider, { value: theme2, children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(StoreProvider, { store, children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(KeyRouterProvider, { router, children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(ShellContext.Provider, { value: shell, children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(Shell, {}) }) }) }) });
17046
17212
  }
17047
17213
  export {