@agentdocumentformat/cli 0.7.7 → 0.8.0

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 (102) hide show
  1. package/README.md +1 -1
  2. package/dist/adf.mjs +59 -8
  3. package/dist/chunks/{APEv2Parser-2CNNHMXV.mjs → APEv2Parser-WIXRJLHB.mjs} +2 -2
  4. package/dist/chunks/{AiffParser-7BR4RL6G.mjs → AiffParser-ZC4QFOVJ.mjs} +5 -5
  5. package/dist/chunks/{App-5KXVPMBV.mjs → App-A5GUFCFJ.mjs} +279 -291
  6. package/dist/chunks/{DsdiffParser-CMD4AX7A.mjs → DsdiffParser-UAPAJHFX.mjs} +5 -5
  7. package/dist/chunks/{DsfParser-UOGZDS2M.mjs → DsfParser-NNYZK2QX.mjs} +6 -6
  8. package/dist/chunks/{FlacParser-HB3T3CD4.mjs → FlacParser-MW2W4LO3.mjs} +6 -6
  9. package/dist/chunks/{MP4Parser-66HBRUSX.mjs → MP4Parser-Z57SYOOQ.mjs} +4 -4
  10. package/dist/chunks/{MpegParser-YW6LIUEW.mjs → MpegParser-XIIPAZVM.mjs} +7 -7
  11. package/dist/chunks/{MusepackParser-PAUSXP7D.mjs → MusepackParser-QWNDEYHJ.mjs} +6 -6
  12. package/dist/chunks/{OggParser-NUBV3GWC.mjs → OggParser-WRX53F77.mjs} +9 -9
  13. package/dist/chunks/{WavPackParser-WQAGT7TC.mjs → WavPackParser-MJ7WCSJ5.mjs} +2 -2
  14. package/dist/chunks/{WaveParser-EWLQVDX4.mjs → WaveParser-RAVLHZ5S.mjs} +7 -7
  15. package/dist/chunks/{adf-schema-US4NFHMR.mjs → adf-schema-YJSGLMA4.mjs} +2 -2
  16. package/dist/chunks/auth-manager-AJ32FZWS.mjs +19 -0
  17. package/dist/chunks/auth-manager-C5OBEQK2.mjs +18 -0
  18. package/dist/chunks/auth-manager-TBNKCJ45.mjs +17 -0
  19. package/dist/chunks/{chatgpt-subscription-E4MXTIAT.mjs → chatgpt-subscription-MMGNW5KJ.mjs} +5 -2
  20. package/dist/chunks/chunk-3UGZFWIF.mjs +26 -0
  21. package/dist/chunks/{chunk-5PO5PKRV.mjs → chunk-4OGZFUKA.mjs} +126 -67
  22. package/dist/chunks/{chunk-VN7UH7I5.mjs → chunk-6XQZGYMK.mjs} +246 -67
  23. package/dist/chunks/{chunk-XNPZBLYL.mjs → chunk-75DC5EWN.mjs} +13 -2
  24. package/dist/chunks/chunk-AZYOXXVL.mjs +865 -0
  25. package/dist/chunks/{chunk-6VQEXLE2.mjs → chunk-BHY7QDCM.mjs} +41 -3
  26. package/dist/chunks/chunk-C2S64Y6F.mjs +203 -0
  27. package/dist/chunks/chunk-C4GA5SI4.mjs +12799 -0
  28. package/dist/chunks/chunk-DDTTSKGG.mjs +2443 -0
  29. package/dist/chunks/{chunk-VAUOM3IN.mjs → chunk-DLWCKKIO.mjs} +1 -1
  30. package/dist/chunks/{chunk-HPVFJYXR.mjs → chunk-ESP3VNMX.mjs} +1 -1
  31. package/dist/chunks/{chunk-QPLEAE6V.mjs → chunk-G6NBFYG5.mjs} +152 -824
  32. package/dist/chunks/{chunk-KXEF4F4E.mjs → chunk-GAZO6UMI.mjs} +1 -1
  33. package/dist/chunks/{chunk-XYTWGHFS.mjs → chunk-H3XLRWVE.mjs} +1 -1
  34. package/dist/chunks/{chunk-7T2YMTWL.mjs → chunk-H4C65MTP.mjs} +4 -4
  35. package/dist/chunks/chunk-HBOFZRUS.mjs +738 -0
  36. package/dist/chunks/chunk-JVPZIMXW.mjs +976 -0
  37. package/dist/chunks/{chunk-XYV3VCIX.mjs → chunk-JZFONJSL.mjs} +79 -20
  38. package/dist/chunks/chunk-KDDVQKCG.mjs +65 -0
  39. package/dist/chunks/chunk-KRPKWOMB.mjs +290 -0
  40. package/dist/chunks/{chunk-4N4ASPH6.mjs → chunk-LCMANRYY.mjs} +4 -254
  41. package/dist/chunks/{chunk-TPRZQ7Z4.mjs → chunk-LGL6ML37.mjs} +4 -4
  42. package/dist/chunks/chunk-LKFHERRV.mjs +145 -0
  43. package/dist/chunks/chunk-LTX74NU6.mjs +29 -0
  44. package/dist/chunks/chunk-M2F7C2UJ.mjs +425 -0
  45. package/dist/chunks/{chunk-62NE4LG4.mjs → chunk-MQAMI5BF.mjs} +5 -5
  46. package/dist/chunks/chunk-MZRXFWPQ.mjs +278 -0
  47. package/dist/chunks/{chunk-PRMGZZM5.mjs → chunk-NZLEPJ5M.mjs} +2 -0
  48. package/dist/chunks/{chunk-CD3ATSXE.mjs → chunk-NZO5O4VN.mjs} +1 -1
  49. package/dist/chunks/{chunk-I3UYSITV.mjs → chunk-O7XKQ6CH.mjs} +1 -1
  50. package/dist/chunks/chunk-P3RG5LQA.mjs +244 -0
  51. package/dist/chunks/chunk-PAK5JCO2.mjs +48 -0
  52. package/dist/chunks/chunk-PC63YFB7.mjs +34 -0
  53. package/dist/chunks/{daemon-control-HKFVSQTQ.mjs → chunk-PRPTKMQW.mjs} +67 -26
  54. package/dist/chunks/{chunk-LFMB4PAA.mjs → chunk-TKXIH27X.mjs} +974 -113
  55. package/dist/chunks/{chunk-5W7KES6P.mjs → chunk-UZPDETEU.mjs} +1 -1
  56. package/dist/chunks/chunk-V2T6NZX2.mjs +517 -0
  57. package/dist/chunks/chunk-V3MM6PCH.mjs +366 -0
  58. package/dist/chunks/chunk-WJGPNHGX.mjs +67 -0
  59. package/dist/chunks/chunk-WVTPPOKK.mjs +290 -0
  60. package/dist/chunks/{chunk-J74STFKE.mjs → chunk-WX6QCUWI.mjs} +272 -51
  61. package/dist/chunks/{chunk-Y5ZLKFLE.mjs → chunk-XNNJQCZP.mjs} +196 -165
  62. package/dist/chunks/{chunk-HDBPBORT.mjs → chunk-XT2BJUFC.mjs} +15 -6
  63. package/dist/chunks/chunk-YRMKSHW3.mjs +9076 -0
  64. package/dist/chunks/{chunk-BNXUAOO4.mjs → chunk-ZGXUOAWZ.mjs} +3186 -959
  65. package/dist/chunks/chunk-ZPB3HYM7.mjs +45 -0
  66. package/dist/chunks/claude-subscription-33BMZB6I.mjs +29 -0
  67. package/dist/chunks/{cli-AFHQ2XTN.mjs → cli-I47IFDHJ.mjs} +797 -56
  68. package/dist/chunks/{commands-XNJMCD5L.mjs → commands-E4EQUHE5.mjs} +5 -2
  69. package/dist/chunks/{daemon-CHZHTLGR.mjs → daemon-FQ5BV3AP.mjs} +84550 -70518
  70. package/dist/chunks/daemon-control-L3CLG63P.mjs +59 -0
  71. package/dist/chunks/{daemon-token-WRSULP7G.mjs → daemon-token-L5QKTHU5.mjs} +3 -1
  72. package/dist/chunks/{discord-DSP4HUWI.mjs → discord-IR62565M.mjs} +3 -52
  73. package/dist/chunks/{email-BRG7KUO2.mjs → email-KHHTJBDW.mjs} +4 -2
  74. package/dist/chunks/{environment-NX277MQG.mjs → environment-R47X44GM.mjs} +1 -1
  75. package/dist/chunks/{grok-subscription-4PYX7TBF.mjs → grok-subscription-E74FS5EG.mjs} +5 -2
  76. package/dist/chunks/{lib-N7FCZWKH.mjs → lib-L27L5PXM.mjs} +22 -22
  77. package/dist/chunks/{open-VAU7PXT6.mjs → open-TLGS2Z3Q.mjs} +4 -4
  78. package/dist/chunks/{parser-JVY2PWSM.mjs → parser-7GARNT5L.mjs} +1 -1
  79. package/dist/chunks/{pipeline-executor-U6IMCCP3.mjs → pipeline-executor-FD4FBWQA.mjs} +8 -5
  80. package/dist/chunks/prompt-RRHZX4YT.mjs +13 -0
  81. package/dist/chunks/remote-access-cli-XXAPQWH6.mjs +268 -0
  82. package/dist/chunks/remote-hello-UFWUBDQI.mjs +37 -0
  83. package/dist/chunks/sdk-5FD2ZP7N.mjs +28422 -0
  84. package/dist/chunks/{slack-OCNNF4DX.mjs → slack-IYC5RAB5.mjs} +3 -4
  85. package/dist/chunks/{store-HUVDJPYN.mjs → store-ZRN2WCFB.mjs} +6 -3
  86. package/dist/chunks/tailscale-WLJATFMB.mjs +25 -0
  87. package/dist/chunks/{theme-SFE3JMA2.mjs → theme-HLBDTF6F.mjs} +1 -1
  88. package/dist/chunks/{themes-YLXLOIJF.mjs → themes-BQ72P446.mjs} +2 -2
  89. package/dist/chunks/{token-6G3HCMNX.mjs → token-6D22WECM.mjs} +20 -16
  90. package/dist/chunks/{token-util-UXYSDQIW.mjs → token-util-YF3ZWBZ4.mjs} +1 -2
  91. package/dist/chunks/{tui-4ZWZKD4C.mjs → tui-SPSPDADM.mjs} +17 -14
  92. package/dist/chunks/{welcome-XHXFV7SH.mjs → welcome-J5JZZAM5.mjs} +1 -1
  93. package/dist/chunks/{whatsapp-AVKT3CTJ.mjs → whatsapp-YJFFVN4Q.mjs} +8 -8
  94. package/package.json +1 -1
  95. package/dist/chunks/chunk-GKKCMXIZ.mjs +0 -94
  96. package/dist/chunks/chunk-IHDDCZBS.mjs +0 -112
  97. package/dist/chunks/chunk-KWFOS5WC.mjs +0 -41
  98. package/dist/chunks/chunk-UEZR2CNS.mjs +0 -65
  99. package/dist/chunks/chunk-VMHTYDH4.mjs +0 -172
  100. package/dist/chunks/chunk-ZROSGV65.mjs +0 -3112
  101. package/dist/chunks/{chunk-NBTUWMGP.mjs → chunk-2MTE22CR.mjs} +3 -3
  102. package/dist/chunks/{telegram-YI2OHNTD.mjs → telegram-JYY2VDTI.mjs} +4 -4
@@ -5,9 +5,11 @@ const require = __adfCreateRequire(import.meta.url);
5
5
  const __filename = __adfFileURLToPath(import.meta.url);
6
6
  const __dirname = __adfDirname(__filename);
7
7
  import {
8
- auth_flow_exports,
9
- openBrowser
10
- } from "./chunk-6VQEXLE2.mjs";
8
+ DaemonClient
9
+ } from "./chunk-6XQZGYMK.mjs";
10
+ import {
11
+ auth_flow_exports
12
+ } from "./chunk-BHY7QDCM.mjs";
11
13
  import {
12
14
  createMouseController,
13
15
  getScreenText,
@@ -20,6 +22,8 @@ import {
20
22
  setSidebarHidden
21
23
  } from "./chunk-APRU6PHC.mjs";
22
24
  import {
25
+ DaemonError,
26
+ MAIN_LOOP,
23
27
  PROMPT_PREFILL_KEY,
24
28
  SERVER_STOPPED_TEXT,
25
29
  StoreProvider,
@@ -29,6 +33,7 @@ import {
29
33
  folderName,
30
34
  isAsyncInput,
31
35
  isBusyState,
36
+ isCredentialsLocked,
32
37
  isTrackedKey,
33
38
  parseServer,
34
39
  servedText,
@@ -45,7 +50,8 @@ import {
45
50
  useClient,
46
51
  useStore,
47
52
  useTuiSelector
48
- } from "./chunk-J74STFKE.mjs";
53
+ } from "./chunk-WX6QCUWI.mjs";
54
+ import "./chunk-75DC5EWN.mjs";
49
55
  import {
50
56
  CHANNELS_OVERLAY,
51
57
  CHANNEL_ORDER,
@@ -117,10 +123,13 @@ import {
117
123
  validateCredentials,
118
124
  validateMcpForm,
119
125
  validateProvider
120
- } from "./chunk-QPLEAE6V.mjs";
126
+ } from "./chunk-AZYOXXVL.mjs";
121
127
  import {
122
128
  require_jsx_runtime
123
129
  } from "./chunk-7CV2SA3H.mjs";
130
+ import {
131
+ cjs
132
+ } from "./chunk-SGUTYISF.mjs";
124
133
  import {
125
134
  WELCOME_INTRO,
126
135
  WELCOME_OVERLAY,
@@ -130,37 +139,25 @@ import {
130
139
  nextStepIndex,
131
140
  welcomeFacts,
132
141
  welcomeSteps
133
- } from "./chunk-I3UYSITV.mjs";
142
+ } from "./chunk-O7XKQ6CH.mjs";
143
+ import {
144
+ getPrefs,
145
+ savePrefs
146
+ } from "./chunk-5QU5VY7N.mjs";
134
147
  import {
135
148
  THEMES,
136
149
  applyTheme,
137
150
  findTheme,
138
151
  nextThemeName,
139
152
  themeNames
140
- } from "./chunk-KXEF4F4E.mjs";
141
- import {
142
- DaemonClient
143
- } from "./chunk-VN7UH7I5.mjs";
144
- import {
145
- DaemonError,
146
- MAIN_LOOP,
147
- isCredentialsLocked
148
- } from "./chunk-XNPZBLYL.mjs";
153
+ } from "./chunk-GAZO6UMI.mjs";
149
154
  import {
150
- cjs
151
- } from "./chunk-SGUTYISF.mjs";
152
- import {
153
- getPrefs,
154
- savePrefs
155
- } from "./chunk-5QU5VY7N.mjs";
156
- import {
157
- ADF_SKILLS_REGISTRY_URL,
158
- checkFetchTarget,
159
- context_breakdown_exports
160
- } from "./chunk-4N4ASPH6.mjs";
161
- import "./chunk-2NAP2ZF7.mjs";
162
- import "./chunk-5PO5PKRV.mjs";
163
- import "./chunk-VMHTYDH4.mjs";
155
+ context_breakdown_exports,
156
+ guarded_fetch_exports,
157
+ skills_catalog_schema_exports
158
+ } from "./chunk-HBOFZRUS.mjs";
159
+ import "./chunk-4OGZFUKA.mjs";
160
+ import "./chunk-G6NBFYG5.mjs";
164
161
  import {
165
162
  Box_default,
166
163
  Text,
@@ -177,7 +174,7 @@ import {
177
174
  ThemeContext,
178
175
  stateColor,
179
176
  useTheme
180
- } from "./chunk-PRMGZZM5.mjs";
177
+ } from "./chunk-NZLEPJ5M.mjs";
181
178
  import {
182
179
  isMouseGarbage,
183
180
  lastRawInput,
@@ -193,18 +190,24 @@ import {
193
190
  import {
194
191
  require_react
195
192
  } from "./chunk-6GJ4QHRI.mjs";
193
+ import {
194
+ ADF_SKILLS_REGISTRY_URL
195
+ } from "./chunk-LCMANRYY.mjs";
196
196
  import "./chunk-UYY5M2PB.mjs";
197
- import "./chunk-GKKCMXIZ.mjs";
198
- import "./chunk-UEZR2CNS.mjs";
199
- import "./chunk-IHDDCZBS.mjs";
197
+ import "./chunk-2NAP2ZF7.mjs";
198
+ import "./chunk-LKFHERRV.mjs";
199
+ import "./chunk-V2T6NZX2.mjs";
200
+ import "./chunk-WVTPPOKK.mjs";
201
+ import "./chunk-WJGPNHGX.mjs";
202
+ import "./chunk-PAK5JCO2.mjs";
203
+ import "./chunk-ZPB3HYM7.mjs";
204
+ import "./chunk-LTX74NU6.mjs";
200
205
  import {
201
206
  require_dist
202
207
  } from "./chunk-APHX6HSV.mjs";
203
- import {
204
- external_exports
205
- } from "./chunk-ZJKXHM4Q.mjs";
208
+ import "./chunk-NZO5O4VN.mjs";
209
+ import "./chunk-ZJKXHM4Q.mjs";
206
210
  import "./chunk-RIX34QHC.mjs";
207
- import "./chunk-CD3ATSXE.mjs";
208
211
  import {
209
212
  __export,
210
213
  __toESM
@@ -508,10 +511,10 @@ function TextInput(props) {
508
511
  var import_react3 = __toESM(require_react(), 1);
509
512
 
510
513
  // src/main/tui/auth/model.ts
511
- var AUTH_OVERLAY = "auth", SUBSCRIPTIONS = ["chatgpt", "grok"], SUBSCRIPTION_LABELS = { chatgpt: "ChatGPT", grok: "Grok" }, AUTH_EXPLAINER = "The daemon keeps its own sign-in, separate from ADF Studio\u2019s. Agents that use these providers need no changes.";
514
+ var AUTH_OVERLAY = "auth", SUBSCRIPTIONS = ["chatgpt", "grok", "claude"], SUBSCRIPTION_LABELS = { chatgpt: "ChatGPT", grok: "Grok", claude: "Claude" }, CLAUDE_EXPLAINER = "Claude signs in through Claude Code on the daemon host; ADF stores no Claude credentials. The sign-in is shared with Claude Code there.", AUTH_EXPLAINER = "The daemon keeps its own sign-in, separate from ADF Studio\u2019s. Agents that use these providers need no changes.";
512
515
  function subscriptionOfType(type, id) {
513
516
  let t = `${type ?? ""} ${id ?? ""}`.toLowerCase();
514
- return t.includes("chatgpt-subscription") || !type && /chatgpt/.test(t) ? "chatgpt" : t.includes("grok-subscription") || !type && /grok/.test(t) ? "grok" : null;
517
+ return t.includes("chatgpt-subscription") || !type && /chatgpt/.test(t) ? "chatgpt" : t.includes("grok-subscription") || !type && /grok/.test(t) ? "grok" : t.includes("claude-subscription") ? "claude" : null;
515
518
  }
516
519
  function statusOf(auth, provider) {
517
520
  let value = auth?.[provider];
@@ -538,9 +541,14 @@ function formatExpiry(expiresAt, now = Date.now()) {
538
541
  }
539
542
  function describeStatus(status) {
540
543
  if (!status) return { text: "unknown", ok: !1 };
544
+ if (status.installed === !1) return { text: `Claude Code not installed${status.installUrl ? ` (${status.installUrl})` : ""}`, ok: !1 };
545
+ if (status.updateRequired) return { text: `Claude Code ${status.version ?? ""} is too old \xB7 ADF needs ${status.minVersion ?? "a newer version"} or newer (run \`claude update\`)`, ok: !1 };
546
+ let cc = status.version ? ` \xB7 Claude Code ${status.version}` : "";
541
547
  if (status.authenticated) {
548
+ let failed = status.flowError && !status.flowPending ? ` \xB7 last sign-in failed: ${status.flowError}` : "";
549
+ if (status.plan) return { text: `signed in${status.email ? ` as ${status.email}` : ""} \xB7 ${status.plan} plan${cc}${failed}`, ok: !0 };
542
550
  let expiry = formatExpiry(status.expiresAt);
543
- return { text: `signed in${status.email ? ` as ${status.email}` : ""}${expiry ? ` \xB7 token ${expiry.startsWith("expired") ? expiry : `renews in ${expiry}`}` : ""}`, ok: !0 };
551
+ return { text: `signed in${status.email ? ` as ${status.email}` : ""}${expiry ? ` \xB7 token ${expiry.startsWith("expired") ? expiry : `renews in ${expiry}`}` : ""}${failed}`, ok: !0 };
544
552
  }
545
553
  return status.flowPending ? { text: "sign-in in progress", ok: !1 } : status.flowError ? { text: `not signed in (last attempt: ${status.flowError})`, ok: !1 } : { text: "not signed in", ok: !1 };
546
554
  }
@@ -1037,6 +1045,9 @@ function completePath(input, options = {}) {
1037
1045
  }
1038
1046
  return { value: dirPart + (common.length > base2.length ? common : base2), candidates };
1039
1047
  }
1048
+ function lockedNote(fields) {
1049
+ return fields && fields.length > 0 ? `; locked against agent edits: ${fields.join(", ")}` : "";
1050
+ }
1040
1051
 
1041
1052
  // src/main/tui/views/fleet/data.ts
1042
1053
  var import_react4 = __toESM(require_react(), 1);
@@ -1250,13 +1261,14 @@ ${bits}` : "";
1250
1261
  if (!await store.actions.confirm({
1251
1262
  title: "Review required",
1252
1263
  message: `${filePath} has not been reviewed on this daemon.${summary}
1253
- Accept the review and load it?`,
1264
+ Accept the review and load it? Accepting also locks its security-sensitive settings against the agent's own edits, as Studio does.`,
1254
1265
  confirmLabel: "Accept + load",
1255
1266
  danger: !0
1256
1267
  }))
1257
1268
  return store.actions.toast("Not loaded (review declined)", "warn"), !1;
1258
1269
  try {
1259
- return await store.client.acceptReview(filePath), store.actions.toast(`Review accepted for ${filePath}`, "success"), !0;
1270
+ let accepted = await store.client.acceptReview(filePath);
1271
+ return store.actions.toast(`Review accepted for ${filePath}${lockedNote(accepted.lockedFields)}`, "success", 6e3), !0;
1260
1272
  } catch (err) {
1261
1273
  return failure(store, null, "Accept review", err), !1;
1262
1274
  }
@@ -3830,7 +3842,7 @@ function wakesText(timers, now = Date.now(), sep4 = "\xB7") {
3830
3842
  }
3831
3843
 
3832
3844
  // src/main/tui/auth/flow.ts
3833
- var { loginChatGpt, loginGrok, openBrowser: openBrowser2 } = cjs(auth_flow_exports), seams = { openBrowser: openBrowser2 };
3845
+ var { loginChatGpt, loginClaude, loginGrok, openBrowser } = cjs(auth_flow_exports), seams = { openBrowser };
3834
3846
  function openUrl(url2) {
3835
3847
  seams.openBrowser(url2);
3836
3848
  }
@@ -3843,7 +3855,7 @@ async function signIn(client, provider, signal, handlers) {
3843
3855
  startCallbackServer: seams.startCallbackServer
3844
3856
  };
3845
3857
  try {
3846
- return provider === "chatgpt" ? await loginChatGpt(deps, { daemonUrl: client.baseUrl, onStart: (info) => handlers.onChatGpt?.(info) }) : await loginGrok(deps, { onStart: (info) => handlers.onGrok?.(info) });
3858
+ return provider === "claude" ? await loginClaude(deps, { onStart: (info) => handlers.onClaude?.(info) }) : provider === "chatgpt" ? await loginChatGpt(deps, { daemonUrl: client.baseUrl, onStart: (info) => handlers.onChatGpt?.(info) }) : await loginGrok(deps, { onStart: (info) => handlers.onGrok?.(info) });
3847
3859
  } catch (err) {
3848
3860
  return signal.aborted ? { ok: !1, error: "Sign-in cancelled", cancelled: !0 } : { ok: !1, error: err instanceof Error ? err.message : String(err) };
3849
3861
  }
@@ -3852,14 +3864,15 @@ async function signIn(client, provider, signal, handlers) {
3852
3864
  // src/main/tui/auth/AuthDialog.tsx
3853
3865
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
3854
3866
  function AuthDialog({ overlay, close, width }) {
3855
- 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), abort = (0, import_react15.useRef)(null), dialogWidth = Math.max(50, Math.min(width - 4, 84));
3867
+ 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));
3856
3868
  (0, import_react15.useEffect)(() => (store.actions.refreshAuth(), props.login && start(props.login), () => abort.current?.abort()), []);
3857
3869
  let start = (provider) => {
3858
3870
  abort.current?.abort();
3859
3871
  let ctrl = new AbortController();
3860
- abort.current = ctrl, setNote(null), setFlow({ kind: "running", provider }), signIn(store.client, provider, ctrl.signal, {
3872
+ abort.current = ctrl, setNote(null), setPasted(""), setFlow({ kind: "running", provider }), signIn(store.client, provider, ctrl.signal, {
3861
3873
  onChatGpt: (info) => setFlow({ kind: "running", provider, url: info.authUrl, relay: info.mode === "relay" ? info.redirectUri : void 0 }),
3862
- onGrok: (info) => setFlow({ kind: "running", provider, url: info.verificationUri, code: info.userCode })
3874
+ onGrok: (info) => setFlow({ kind: "running", provider, url: info.verificationUri, code: info.userCode }),
3875
+ onClaude: (info) => setFlow({ kind: "running", provider, url: info.url || void 0, started: !0 })
3863
3876
  }).then((outcome) => {
3864
3877
  if (ctrl.signal.aborted && !outcome.ok) return;
3865
3878
  abort.current = null, store.actions.refreshAuth();
@@ -3868,6 +3881,12 @@ function AuthDialog({ overlay, close, width }) {
3868
3881
  });
3869
3882
  }, cancel = () => {
3870
3883
  flow.kind === "running" && (abort.current?.abort(), abort.current = null, setNote(`${SUBSCRIPTION_LABELS[flow.provider]} sign-in cancelled.`), setFlow({ kind: "list" }));
3884
+ }, sendCode = (value) => {
3885
+ let code = value.trim();
3886
+ return code ? (setPasted(""), setNote("Sending the code to Claude Code\u2026"), store.client.submitClaudeCode(code).then(
3887
+ () => setNote("Code sent. Waiting for Claude Code to finish\u2026"),
3888
+ (err) => setNote(`Could not send the code: ${err instanceof Error ? err.message : String(err)}`)
3889
+ ), !0) : !1;
3871
3890
  }, copyUrl = (url2) => {
3872
3891
  url2 && copyToClipboard(url2).then((ok) => setNote(ok ? "URL copied to the clipboard." : "Could not copy; select the URL with the mouse instead."));
3873
3892
  };
@@ -3892,25 +3911,30 @@ function AuthDialog({ overlay, close, width }) {
3892
3911
  } else (input === "n" || key.escape) && setFlow({ kind: "list" });
3893
3912
  return !0;
3894
3913
  case "running":
3895
- return key.escape ? (cancel(), !0) : (input === "c" && copyUrl(flow.url), !0);
3914
+ return key.escape ? (cancel(), !0) : (input === "c" && flow.provider !== "claude" && copyUrl(flow.url), !0);
3896
3915
  case "done":
3897
3916
  return key.escape || key.return ? (flow.outcome.ok ? close() : setFlow({ kind: "list" }), !0) : input === "r" && !flow.outcome.ok ? (start(flow.provider), !0) : (input === "c" && copyUrl(flow.url), !0);
3898
3917
  }
3899
3918
  }, { layer: "overlay" });
3900
3919
  let noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: note }) : null;
3901
3920
  if (flow.kind === "running" || flow.kind === "done") {
3902
- let label2 = SUBSCRIPTION_LABELS[flow.provider], running2 = flow.kind === "running", code = running2 ? flow.code : void 0, url2 = flow.url, hints2 = running2 ? [...url2 ? [{ keys: "c", label: "copy URL" }] : [], { keys: "esc", label: "cancel" }] : flow.outcome.ok ? [{ keys: "enter", label: "close" }] : [{ keys: "r", label: "try again" }, { keys: "esc", label: "back" }];
3921
+ let label2 = SUBSCRIPTION_LABELS[flow.provider], running2 = flow.kind === "running", code = running2 ? flow.code : void 0, url2 = flow.url, claude = flow.provider === "claude", claudeWaiting = running2 && claude && !!flow.started, hints2 = running2 ? claude ? [...claudeWaiting ? [{ keys: "enter", label: "send code" }] : [], { keys: "esc", label: "cancel" }] : [...url2 ? [{ keys: "c", label: "copy URL" }] : [], { keys: "esc", label: "cancel" }] : flow.outcome.ok ? [{ keys: "enter", label: "close" }] : [{ keys: "r", label: "try again" }, { keys: "esc", label: "back" }];
3903
3922
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Modal, { title: `Sign in to ${label2}`, width: dialogWidth, hints: hints2, children: [
3904
- running2 && !url2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: `asking the daemon to start ${label2} sign-in\u2026` }) : null,
3923
+ running2 && !url2 && !(running2 && flow.started) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: `asking the daemon to start ${label2} sign-in\u2026` }) : null,
3924
+ claude ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: CLAUDE_EXPLAINER }) : null,
3905
3925
  code ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", alignItems: "center", marginBottom: 1, children: [
3906
3926
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: "Enter this code in the browser:" }),
3907
3927
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { borderStyle: theme2.ascii ? "classic" : "double", borderColor: theme2.color.accent, paddingX: 3, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { bold: !0, color: theme2.color.accent, children: spacedCode(code) }) })
3908
3928
  ] }) : null,
3909
3929
  url2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
3910
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: code ? "on this page (the browser should open it):" : "The browser should open. If it does not, open this URL:" }),
3930
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: code ? "on this page (the browser should open it):" : claude ? "Claude Code is opening the sign-in page in the browser on the daemon host. If it does not open there, open this URL:" : "The browser should open. If it does not, open this URL:" }),
3911
3931
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.info, wrap: "wrap", children: url2 })
3912
3932
  ] }) : null,
3913
- running2 && url2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: flow.relay ? `waiting for you to finish in the browser\u2026 (callback on ${flow.relay})` : "waiting for you to finish in the browser\u2026" }) }) : null,
3933
+ claudeWaiting ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
3934
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.text, children: "If the page shows a code, paste it here (or wait):" }),
3935
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { borderStyle: theme2.ascii ? "classic" : "round", borderColor: theme2.color.borderFocus, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TextInput, { value: pasted, onChange: setPasted, onSubmit: sendCode, focused: !0, keyLayer: "overlay", maxRows: 2, placeholder: "code from the Claude sign-in page" }) })
3936
+ ] }) : null,
3937
+ running2 && (url2 || claudeWaiting) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: flow.relay ? `waiting for you to finish in the browser\u2026 (callback on ${flow.relay})` : "waiting for you to finish in the browser\u2026" }) }) : null,
3914
3938
  running2 ? null : flow.outcome.ok ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { bold: !0, color: theme2.color.success, children: [
3915
3939
  theme2.glyph.check,
3916
3940
  " Signed in to ",
@@ -4482,8 +4506,8 @@ var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1), MODEL_OVERLAY = "i
4482
4506
  function providerChoices(providers, auth) {
4483
4507
  return providers.map((p) => {
4484
4508
  let type = String(p.type ?? ""), id = String(p.id ?? ""), name = String(p.name ?? id);
4485
- if (type === "chatgpt-subscription" || type === "grok-subscription") {
4486
- let signedIn = type === "chatgpt-subscription" ? auth?.chatgpt : auth?.grok;
4509
+ if (type === "chatgpt-subscription" || type === "grok-subscription" || type === "claude-subscription") {
4510
+ let signedIn = type === "chatgpt-subscription" ? auth?.chatgpt : type === "grok-subscription" ? auth?.grok : auth?.claude;
4487
4511
  return { id, name, type, access: signedIn?.authenticated ? "signed in" : "not signed in (/login)", ready: !!signedIn?.authenticated };
4488
4512
  }
4489
4513
  if (p.hasApiKey === !0) return { id, name, type, access: "key set", ready: !0 };
@@ -4631,14 +4655,14 @@ var { normalizeAuthProvider } = cjs(auth_flow_exports);
4631
4655
  function openAuth(actions4, props = {}) {
4632
4656
  actions4.pushOverlay({ kind: AUTH_OVERLAY, props: { ...props } });
4633
4657
  }
4634
- var complete = (partial) => ["chatgpt", "grok"].filter((v) => v.startsWith(partial.trim().toLowerCase())), authCommand = {
4658
+ var complete = (partial) => ["chatgpt", "grok", "claude"].filter((v) => v.startsWith(partial.trim().toLowerCase())), authCommand = {
4635
4659
  name: "auth",
4636
- description: "Provider sign-in: ChatGPT and Grok status, sign in, sign out",
4660
+ description: "Provider sign-in: ChatGPT, Grok and Claude status, sign in, sign out",
4637
4661
  run: (ctx) => openAuth(ctx.actions)
4638
4662
  }, loginCommand = {
4639
4663
  name: "login",
4640
- args: "[chatgpt|grok]",
4641
- description: "Sign the daemon in to ChatGPT (browser) or Grok (device code)",
4664
+ args: "[chatgpt|grok|claude]",
4665
+ description: "Sign the daemon in to ChatGPT (browser), Grok (device code) or Claude (Claude Code on the daemon host)",
4642
4666
  complete,
4643
4667
  run: (ctx) => {
4644
4668
  if (!ctx.args[0]) {
@@ -4647,29 +4671,30 @@ var complete = (partial) => ["chatgpt", "grok"].filter((v) => v.startsWith(parti
4647
4671
  }
4648
4672
  let provider = normalizeAuthProvider(ctx.args[0]);
4649
4673
  if (!provider) {
4650
- ctx.print("Usage: /login [chatgpt|grok]", "warn");
4674
+ ctx.print("Usage: /login [chatgpt|grok|claude]", "warn");
4651
4675
  return;
4652
4676
  }
4653
4677
  openAuth(ctx.actions, { login: provider });
4654
4678
  }
4655
4679
  }, logoutCommand = {
4656
4680
  name: "logout",
4657
- args: "<chatgpt|grok>",
4658
- description: "Sign the daemon out of ChatGPT or Grok (asks)",
4681
+ args: "<chatgpt|grok|claude>",
4682
+ description: "Sign the daemon out of ChatGPT, Grok or Claude (asks)",
4659
4683
  complete,
4660
4684
  run: async (ctx) => {
4661
4685
  let provider = normalizeAuthProvider(ctx.args[0]);
4662
4686
  if (!provider) {
4663
- ctx.print("Usage: /logout <chatgpt|grok>", "warn");
4687
+ ctx.print("Usage: /logout <chatgpt|grok|claude>", "warn");
4664
4688
  return;
4665
4689
  }
4666
- let label2 = SUBSCRIPTION_LABELS[provider];
4667
- await ctx.actions.confirm({ title: `Sign out of ${label2}`, message: `Sign the daemon out of ${label2}? Agents using it stop working until you sign in again.`, confirmLabel: "Sign out", danger: !0 }) && await ctx.actions.logoutSubscription(provider);
4690
+ let label2 = SUBSCRIPTION_LABELS[provider], shared = provider === "claude" ? " This also signs Claude Code out on the daemon host." : "";
4691
+ await ctx.actions.confirm({ title: `Sign out of ${label2}`, message: `Sign the daemon out of ${label2}? Agents using it stop working until you sign in again.${shared}`, confirmLabel: "Sign out", danger: !0 }) && await ctx.actions.logoutSubscription(provider);
4668
4692
  }
4669
4693
  }, authActions = [
4670
- { id: "shell.auth", title: "Provider sign-in", hint: "ChatGPT, Grok", group: "Actions", keywords: ["auth", "login", "sign in", "subscription", "account"], run: (ctx) => openAuth(ctx.actions) },
4694
+ { id: "shell.auth", title: "Provider sign-in", hint: "ChatGPT, Grok, Claude", group: "Actions", keywords: ["auth", "login", "sign in", "subscription", "account"], run: (ctx) => openAuth(ctx.actions) },
4671
4695
  { id: "shell.auth.chatgpt", title: "Sign in to ChatGPT", group: "Actions", keywords: ["login", "openai", "codex", "auth"], available: (s) => !statusOf(s.state().auth, "chatgpt")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "chatgpt" }) },
4672
- { id: "shell.auth.grok", title: "Sign in to Grok", group: "Actions", keywords: ["login", "xai", "auth", "device code"], available: (s) => !statusOf(s.state().auth, "grok")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "grok" }) }
4696
+ { id: "shell.auth.grok", title: "Sign in to Grok", group: "Actions", keywords: ["login", "xai", "auth", "device code"], available: (s) => !statusOf(s.state().auth, "grok")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "grok" }) },
4697
+ { id: "shell.auth.claude", title: "Sign in to Claude", group: "Actions", keywords: ["login", "anthropic", "claude code", "auth", "subscription"], available: (s) => !statusOf(s.state().auth, "claude")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "claude" }) }
4673
4698
  ];
4674
4699
 
4675
4700
  // src/main/tui/setup/ProviderDialog.tsx
@@ -5533,7 +5558,7 @@ async function editText(text, options = {}) {
5533
5558
  var schemaParse = null;
5534
5559
  async function loadSchema() {
5535
5560
  if (schemaParse) return schemaParse;
5536
- let schema = cjs(await import("./adf-schema-US4NFHMR.mjs")).AgentConfigSchema;
5561
+ let schema = cjs(await import("./adf-schema-YJSGLMA4.mjs")).AgentConfigSchema;
5537
5562
  return schemaParse = (value) => schema.safeParse(value), schemaParse;
5538
5563
  }
5539
5564
  function changedKeysBetween(a, b) {
@@ -5738,6 +5763,10 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
5738
5763
  }, openReview = async (id, back) => {
5739
5764
  let r = await act("Review", back, () => store.client.templateReview(id));
5740
5765
  if (r) {
5766
+ if (r.identityReady === !1) {
5767
+ close(), openIdentity(store, { mode: "status", then: TEMPLATES_OVERLAY, thenProps: { id }, reason: `Review: ${r.message ?? "Set up the owner identity first."}` });
5768
+ return;
5769
+ }
5741
5770
  if (!r.needsReview) {
5742
5771
  await refresh2(), done(`${label2(id)} is already reviewed`, back);
5743
5772
  return;
@@ -5881,7 +5910,7 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
5881
5910
  }
5882
5911
  if (step.kind === "review")
5883
5912
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `Review ${theme2.glyph.sep} ${label2(step.id)} template`, width: dialogWidth, hints: [{ keys: "y enter", label: "claim + accept" }, { keys: "up down", label: "scroll" }, { keys: "n esc", label: "cancel" }], children: [
5884
- step.review ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: reviewLines(step.review.summary, inner), width: inner, height: fitLines(reviewLines(step.review.summary, inner).length), keyLayer: "overlay" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }),
5913
+ step.review?.summary ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: reviewLines(step.review.summary, inner), width: inner, height: fitLines(reviewLines(step.review.summary, inner).length), keyLayer: "overlay" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }),
5885
5914
  errorLine
5886
5915
  ] });
5887
5916
  if (step.kind === "files") {
@@ -6482,20 +6511,62 @@ function describeDiff(before, after, preview = 6) {
6482
6511
  return diff.changes.length > preview && lines.push(` \u2026 ${diff.changes.length - preview} more changed lines`), { summary, lines };
6483
6512
  }
6484
6513
 
6514
+ // src/shared/types/resource-revision.types.ts
6515
+ var resource_revision_types_exports = {};
6516
+ __export(resource_revision_types_exports, {
6517
+ describeWriter: () => describeWriter
6518
+ });
6519
+ function describeWriter(writer2) {
6520
+ if (!writer2) return "someone else";
6521
+ switch (writer2.kind) {
6522
+ case "agent":
6523
+ return "the agent";
6524
+ case "cli":
6525
+ return "the CLI or another API client";
6526
+ case "client":
6527
+ return writer2.client === "studio" ? "another Studio window" : writer2.client === "tui" ? "the terminal app" : `another client (${writer2.client})`;
6528
+ }
6529
+ }
6530
+
6531
+ // src/main/tui/util/revisions.ts
6532
+ var { describeWriter: describeWriter2 } = cjs(resource_revision_types_exports);
6533
+ function revisionOf(result) {
6534
+ let revision = result?.revision;
6535
+ return typeof revision == "number" ? revision : void 0;
6536
+ }
6537
+ function staleRevisionOf(err) {
6538
+ if (!(err instanceof DaemonError) || err.status !== 409) return null;
6539
+ let body = err.body;
6540
+ return body?.code !== "stale_revision" || typeof body.revision != "number" ? null : { revision: body.revision, writer: body.writer ?? null };
6541
+ }
6542
+ function changedBy(stale) {
6543
+ return `changed by ${describeWriter2(stale.writer)}`;
6544
+ }
6545
+ async function writeOver(write2) {
6546
+ try {
6547
+ return { ok: await write2() };
6548
+ } catch (err) {
6549
+ let stale = staleRevisionOf(err);
6550
+ if (stale) return { stale };
6551
+ throw err;
6552
+ }
6553
+ }
6554
+
6485
6555
  // src/main/tui/views/files/io.ts
6486
6556
  async function loadTarget(client, agentId, target2) {
6487
6557
  if (target2.kind === "document" || target2.kind === "mind") {
6488
- let text2 = (target2.kind === "document" ? await client.document(agentId) : await client.mind(agentId)).content ?? "";
6489
- return { target: target2, text: text2, binary: !1, mime: "text/markdown", size: Buffer.byteLength(text2, "utf-8") };
6558
+ let result = target2.kind === "document" ? await client.document(agentId) : await client.mind(agentId), text2 = result.content ?? "";
6559
+ return { target: target2, text: text2, binary: !1, mime: "text/markdown", size: Buffer.byteLength(text2, "utf-8"), revision: revisionOf(result) };
6490
6560
  }
6491
- let file = await client.file(agentId, target2.path), base2 = { target: target2, mime: file.mime_type, size: file.size, protection: file.protection, authorized: file.authorized, updatedAt: file.updated_at };
6561
+ let file = await client.file(agentId, target2.path), base2 = { target: target2, mime: file.mime_type, size: file.size, protection: file.protection, authorized: file.authorized, updatedAt: file.updated_at, revision: revisionOf(file) };
6492
6562
  if (file.encoding === "base64")
6493
6563
  return { ...base2, binary: !0, bytes: Buffer.from(file.content_base64 ?? "", "base64") };
6494
6564
  let text = file.content ?? "";
6495
6565
  return looksBinary(text) ? { ...base2, binary: !0, bytes: Buffer.from(text, "utf-8") } : { ...base2, text, binary: !1 };
6496
6566
  }
6497
- async function writeTarget(client, agentId, target2, text) {
6498
- target2.kind === "document" ? await client.putDocument(agentId, text) : target2.kind === "mind" ? await client.putMind(agentId, text) : await client.writeFile(agentId, target2.path, { content: text });
6567
+ async function writeTarget(client, agentId, target2, text, baseRevision) {
6568
+ let base2 = baseRevision === "absent" ? { mustNotExist: !0 } : baseRevision !== void 0 ? { baseRevision } : {}, agent2 = `/agents/${encodeURIComponent(agentId)}`;
6569
+ return target2.kind === "document" ? revisionOf(await client.request("PUT", `${agent2}/document`, { body: { content: text, ...base2 } })) : target2.kind === "mind" ? revisionOf(await client.request("PUT", `${agent2}/mind`, { body: { content: text, ...base2 } })) : revisionOf(await client.request("PUT", `${agent2}/files/content`, { query: { path: target2.path }, body: { content: text, ...base2 } }));
6499
6570
  }
6500
6571
  var pathCache = /* @__PURE__ */ new Map();
6501
6572
  function cacheFiles(agentId, files2) {
@@ -6547,13 +6618,13 @@ async function editTarget(deps, target2, options = {}) {
6547
6618
  }
6548
6619
  if (original.charCodeAt(0) !== 65279 && (edited = stripBom2(edited)), edited === original && !options.create)
6549
6620
  return await cleanup(), actions4.toast(`No changes to ${label2}`, "info"), "unchanged";
6550
- let concurrent = null;
6621
+ let concurrent = null, baseRevision = options.create ? "absent" : void 0;
6551
6622
  if (options.create)
6552
6623
  target2.kind === "file" && (await client.files(agentId).catch(() => null))?.files.some((f) => f.path === target2.path) && (concurrent = "was created by someone else while you were editing");
6553
6624
  else
6554
6625
  try {
6555
6626
  let current = await loadTarget(client, agentId, target2);
6556
- current.text !== original && (concurrent = `changed while you were editing (their change: ${describeDiff(original, current.text ?? "", 0).summary})`);
6627
+ baseRevision = current.revision, current.text !== original && (concurrent = `changed while you were editing (their change: ${describeDiff(original, current.text ?? "", 0).summary})`);
6557
6628
  } catch (err) {
6558
6629
  concurrent = err.status === 404 ? "was deleted while you were editing" : `could not be re-checked (${err instanceof Error ? err.message : String(err)})`;
6559
6630
  }
@@ -6563,195 +6634,44 @@ async function editTarget(deps, target2, options = {}) {
6563
6634
  ...diff.lines
6564
6635
  ].filter((line) => line !== null).join(`
6565
6636
  `);
6566
- return await actions4.confirm({
6637
+ if (!await actions4.confirm({
6567
6638
  title: concurrent ? `Concurrent change: ${label2}` : `${options.create ? "Create" : "Save"} ${label2}`,
6568
6639
  message,
6569
6640
  confirmLabel: concurrent ? "Overwrite" : options.create ? "Create" : "Write",
6570
6641
  cancelLabel: "Discard",
6571
6642
  danger: !!concurrent
6572
- }) ? await actions4.run(`Write ${label2}`, (c) => writeTarget(c, agentId, target2, edited).then(() => !0)) ? (await cleanup(), actions4.toast(`${options.create ? "Created" : "Saved"} ${label2} (${diff.summary})`, "success"), "written") : (actions4.toast(`Write failed. Your edited copy is kept at ${file}`, "error", 12e3), "failed") : (actions4.toast(`Not written. Your edited copy is kept at ${file}`, "warn", 12e3), "discarded");
6573
- }
6574
-
6575
- // src/main/utils/guarded-fetch.ts
6576
- var guarded_fetch_exports = {};
6577
- __export(guarded_fetch_exports, {
6578
- DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
6579
- MAX_FETCH_REDIRECTS: () => MAX_FETCH_REDIRECTS,
6580
- daemonGuardPort: () => daemonGuardPort,
6581
- guardedFetch: () => guardedFetch,
6582
- isFetchFailure: () => isFetchFailure
6583
- });
6584
- var DEFAULT_DAEMON_PORT = 7385, MAX_FETCH_REDIRECTS = 3;
6585
- function daemonGuardPort() {
6586
- return Number(process.env.ADF_DAEMON_PORT) || DEFAULT_DAEMON_PORT;
6587
- }
6588
- function isFetchFailure(result) {
6589
- return "error" in result;
6643
+ }))
6644
+ return actions4.toast(`Not written. Your edited copy is kept at ${file}`, "warn", 12e3), "discarded";
6645
+ let written = await writeOverConflicts(actions4, label2, file, (base2) => actions4.run(`Write ${label2}`, (c) => writeOver(() => writeTarget(c, agentId, target2, edited, base2))), baseRevision);
6646
+ return written === "reloaded" ? "discarded" : written ? (await cleanup(), actions4.toast(`${options.create ? "Created" : "Saved"} ${label2} (${diff.summary})`, "success"), "written") : (actions4.toast(`Write failed. Your edited copy is kept at ${file}`, "error", 12e3), "failed");
6590
6647
  }
6591
- async function readCapped(response, maxBytes) {
6592
- let body = response.body;
6593
- if (!body) return Buffer.alloc(0);
6594
- if (typeof body.getReader != "function") {
6595
- let bytes = Buffer.from(new Uint8Array(await response.arrayBuffer()));
6596
- return bytes.length > maxBytes ? { error: `exceeds ${maxBytes} bytes` } : bytes;
6597
- }
6598
- let reader2 = body.getReader(), chunks = [], total = 0;
6648
+ async function writeOverConflicts(actions4, label2, file, write2, baseRevision) {
6649
+ let base2 = baseRevision;
6599
6650
  for (; ; ) {
6600
- let { done, value } = await reader2.read();
6601
- if (done) break;
6602
- if (value) {
6603
- if (total += value.byteLength, total > maxBytes) {
6604
- try {
6605
- await reader2.cancel();
6606
- } catch {
6607
- }
6608
- return { error: `exceeds ${maxBytes} bytes` };
6609
- }
6610
- chunks.push(Buffer.from(value));
6611
- }
6612
- }
6613
- return Buffer.concat(chunks);
6614
- }
6615
- async function guardedFetch(url2, options) {
6616
- let { maxBytes, timeoutMs } = options, maxRedirects = options.maxRedirects ?? MAX_FETCH_REDIRECTS, daemonPort = daemonGuardPort(), current;
6617
- try {
6618
- current = new URL(url2).toString();
6619
- } catch {
6620
- return { error: `invalid URL: ${String(url2).slice(0, 200)}` };
6621
- }
6622
- let controller = new AbortController(), timer = setTimeout(() => controller.abort(), timeoutMs);
6623
- try {
6624
- for (let hop = 0; ; hop++) {
6625
- let protocol = new URL(current).protocol;
6626
- if (protocol !== "https:")
6627
- return { error: `only https URLs may be fetched (got "${protocol}")` };
6628
- let blocked = await checkFetchTarget(current, { allowLocal: !1, daemonPort });
6629
- if (blocked) return { error: blocked };
6630
- let response = await fetch(current, { signal: controller.signal, redirect: "manual" });
6631
- if (response.status >= 300 && response.status <= 399) {
6632
- let location = response.headers.get("location");
6633
- if (!location) return { error: `redirect without a location header (HTTP ${response.status})` };
6634
- if (hop >= maxRedirects) return { error: `too many redirects (>${maxRedirects})` };
6635
- try {
6636
- await response.body?.cancel();
6637
- } catch {
6638
- }
6639
- try {
6640
- current = new URL(location, current).toString();
6641
- } catch {
6642
- return { error: `redirect to an unusable location: ${location.slice(0, 200)}` };
6643
- }
6644
- continue;
6645
- }
6646
- if (!response.ok) return { error: `HTTP ${response.status} ${response.statusText}`.trim() };
6647
- let lengthHeader = response.headers.get("content-length"), declared = lengthHeader === null ? NaN : Number(lengthHeader);
6648
- if (Number.isFinite(declared) && declared > maxBytes) {
6649
- try {
6650
- await response.body?.cancel();
6651
- } catch {
6652
- }
6653
- return { error: `exceeds ${maxBytes} bytes` };
6654
- }
6655
- let bytes = await readCapped(response, maxBytes);
6656
- return Buffer.isBuffer(bytes) ? { bytes, contentType: response.headers.get("content-type") ?? "" } : bytes;
6651
+ let result = await write2(base2);
6652
+ if (!result) return;
6653
+ if ("ok" in result) return !0;
6654
+ let copy = typeof file == "string" ? ` (your edited copy stays at ${file})` : file ? " (your edited version is kept in a file)" : "";
6655
+ if (!await actions4.confirm({
6656
+ title: `${label2} changed while you were editing`,
6657
+ message: `${label2} was ${changedBy(result.stale)} after you opened it.
6658
+ Overwrite replaces their version with yours. Reload keeps theirs${copy}.`,
6659
+ confirmLabel: "Overwrite",
6660
+ cancelLabel: "Reload theirs",
6661
+ danger: !0
6662
+ })) {
6663
+ let kept = typeof file == "function" ? await file().catch(() => null) : file;
6664
+ return actions4.toast(`${label2} not written: kept their version${kept ? `. Your edited copy is at ${kept}` : ""}`, "warn", 12e3), "reloaded";
6657
6665
  }
6658
- } catch (err) {
6659
- let message = err instanceof Error ? err.message : String(err);
6660
- return { error: err instanceof Error && err.name === "AbortError" ? `request timed out after ${timeoutMs}ms` : message };
6661
- } finally {
6662
- clearTimeout(timer);
6666
+ base2 = result.stale.revision;
6663
6667
  }
6664
6668
  }
6665
6669
 
6666
- // src/shared/schemas/skills-catalog.schema.ts
6667
- var skills_catalog_schema_exports = {};
6668
- __export(skills_catalog_schema_exports, {
6669
- MAX_CATALOG_BYTES: () => MAX_CATALOG_BYTES,
6670
- MAX_PACKAGE_FILES: () => MAX_PACKAGE_FILES,
6671
- MAX_SKILL_PACKAGE_BYTES: () => MAX_SKILL_PACKAGE_BYTES,
6672
- SKILL_NAME: () => SKILL_NAME,
6673
- SkillCatalogEntrySchema: () => SkillCatalogEntrySchema,
6674
- parseSkillsCatalogDocument: () => parseSkillsCatalogDocument,
6675
- resolvePackageFilePath: () => resolvePackageFilePath
6676
- });
6677
- var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/, PATH_SEGMENT = /^[A-Za-z0-9._-]+$/, MAX_PACKAGE_FILES = 32, MAX_CATALOG_BYTES = 512 * 1024, MAX_SKILL_PACKAGE_BYTES = 256 * 1024, UNSAFE_TEXT = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/, safeText = (value) => !UNSAFE_TEXT.test(value), UNSAFE_TEXT_MESSAGE = "must not contain control or bidirectional-override characters";
6678
- function resolvePackageFilePath(name, raw) {
6679
- if (typeof raw != "string") return null;
6680
- let directory = `skills/${name}/`, candidate = raw.trim().replace(/\\/g, "/");
6681
- if (!candidate) return null;
6682
- for (; candidate.startsWith("./"); ) candidate = candidate.slice(2);
6683
- if (candidate.startsWith("/")) return null;
6684
- let relative2 = candidate.startsWith(directory) ? candidate.slice(directory.length) : candidate;
6685
- return !relative2 || relative2.split("/").some((segment) => segment === "." || segment === ".." || !PATH_SEGMENT.test(segment)) || relative2 === "SKILL.md" ? null : relative2;
6686
- }
6687
- var SkillPackageFileSchema = external_exports.object({
6688
- path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE),
6689
- raw_url: external_exports.string().url()
6690
- }), SkillCatalogEntrySchema = external_exports.object({
6691
- name: external_exports.string().regex(SKILL_NAME),
6692
- description: external_exports.string().min(1).max(500).refine(safeText, UNSAFE_TEXT_MESSAGE),
6693
- /** Path inside the publishing repo — display only. */
6694
- path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE).optional(),
6695
- /** Where the SKILL.md body is fetched from on install. */
6696
- raw_url: external_exports.string().url(),
6697
- /** Resources installed beside SKILL.md, package-relative after parsing. */
6698
- files: external_exports.array(SkillPackageFileSchema).max(MAX_PACKAGE_FILES).optional()
6699
- }).superRefine((entry, ctx) => {
6700
- if (!entry.files) return;
6701
- let seen = /* @__PURE__ */ new Set();
6702
- entry.files.forEach((file, index) => {
6703
- let relative2 = resolvePackageFilePath(entry.name, file.path);
6704
- if (!relative2) {
6705
- ctx.addIssue({
6706
- code: external_exports.ZodIssueCode.custom,
6707
- path: ["files", index, "path"],
6708
- message: `must stay inside skills/${entry.name}/ and cannot be SKILL.md`
6709
- });
6710
- return;
6711
- }
6712
- if (seen.has(relative2)) {
6713
- ctx.addIssue({
6714
- code: external_exports.ZodIssueCode.custom,
6715
- path: ["files", index, "path"],
6716
- message: "duplicate package path"
6717
- });
6718
- return;
6719
- }
6720
- seen.add(relative2);
6721
- });
6722
- }).transform((entry) => entry.files ? {
6723
- ...entry,
6724
- files: entry.files.map((file) => ({
6725
- ...file,
6726
- path: resolvePackageFilePath(entry.name, file.path)
6727
- }))
6728
- } : entry);
6729
- function parseSkillsCatalogDocument(json2) {
6730
- if (typeof json2 != "object" || json2 === null || Array.isArray(json2)) return null;
6731
- let doc = json2;
6732
- if (doc.schema !== void 0 && doc.schema !== 1 || !Array.isArray(doc.skills)) return null;
6733
- let entries = [], seen = /* @__PURE__ */ new Set(), dropped = 0;
6734
- for (let raw of doc.skills) {
6735
- let result = SkillCatalogEntrySchema.safeParse(raw);
6736
- if (!result.success || seen.has(result.data.name)) {
6737
- dropped++;
6738
- continue;
6739
- }
6740
- seen.add(result.data.name), entries.push(result.data);
6741
- }
6742
- return {
6743
- entries,
6744
- publisher: typeof doc.publisher == "string" ? doc.publisher : void 0,
6745
- repository: typeof doc.repository == "string" ? doc.repository : void 0,
6746
- dropped
6747
- };
6748
- }
6749
-
6750
6670
  // src/main/tui/skills/catalog.ts
6751
- var { guardedFetch: guardedFetch2 } = cjs(guarded_fetch_exports), { parseSkillsCatalogDocument: parseSkillsCatalogDocument2, MAX_CATALOG_BYTES: MAX_CATALOG_BYTES2, MAX_SKILL_PACKAGE_BYTES: MAX_SKILL_PACKAGE_BYTES2 } = cjs(skills_catalog_schema_exports), { normalizeCatalogSources: normalizeCatalogSources2 } = cjs(skills_panel_exports), SKILLS_FETCH_TIMEOUT_MS = 1e4, CATALOG_SOURCES_SETTING = "skillCatalogSources";
6671
+ var { guardedFetch } = cjs(guarded_fetch_exports), { parseSkillsCatalogDocument, MAX_CATALOG_BYTES, MAX_SKILL_PACKAGE_BYTES } = cjs(skills_catalog_schema_exports), { normalizeCatalogSources: normalizeCatalogSources2 } = cjs(skills_panel_exports), SKILLS_FETCH_TIMEOUT_MS = 1e4, CATALOG_SOURCES_SETTING = "skillCatalogSources";
6752
6672
  async function fetchCatalogDocument(url2) {
6753
6673
  if (typeof url2 != "string" || !/^https:\/\//.test(url2)) return { ok: !1, error: "Catalog URL must be https" };
6754
- let body = await guardedFetch2(url2, { maxBytes: MAX_CATALOG_BYTES2, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
6674
+ let body = await guardedFetch(url2, { maxBytes: MAX_CATALOG_BYTES, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
6755
6675
  if ("error" in body) return { ok: !1, error: body.error };
6756
6676
  let json2;
6757
6677
  try {
@@ -6759,12 +6679,12 @@ async function fetchCatalogDocument(url2) {
6759
6679
  } catch {
6760
6680
  return { ok: !1, error: "Catalog is not valid JSON" };
6761
6681
  }
6762
- let parsed = parseSkillsCatalogDocument2(json2);
6682
+ let parsed = parseSkillsCatalogDocument(json2);
6763
6683
  return parsed ? { ok: !0, entries: parsed.entries, publisher: parsed.publisher, dropped: parsed.dropped } : { ok: !1, error: "Unrecognized catalog schema" };
6764
6684
  }
6765
6685
  async function fetchSkillText(url2) {
6766
6686
  if (typeof url2 != "string" || !/^https:\/\//.test(url2)) return { ok: !1, error: "Package URL must be https" };
6767
- let body = await guardedFetch2(url2, { maxBytes: MAX_SKILL_PACKAGE_BYTES2, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
6687
+ let body = await guardedFetch(url2, { maxBytes: MAX_SKILL_PACKAGE_BYTES, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
6768
6688
  return "error" in body ? { ok: !1, error: body.error } : body.bytes.subarray(0, 8192).includes(0) ? { ok: !1, error: "SKILL.md is not text" } : { ok: !0, content: body.bytes.toString("utf8") };
6769
6689
  }
6770
6690
  var DEFAULT_SEAMS = { catalog: fetchCatalogDocument, text: fetchSkillText }, seams2 = DEFAULT_SEAMS;
@@ -6798,7 +6718,7 @@ var {
6798
6718
  parseSkillsRegistry: parseSkillsRegistry2,
6799
6719
  sanitizeDisplayText: sanitizeDisplayText2,
6800
6720
  skillProblems: skillProblems2
6801
- } = cjs(skills_panel_exports), { splitSkillDocument: splitSkillDocument2 } = cjs(skill_preview_exports), { SKILL_NAME: SKILL_NAME2 } = cjs(skills_catalog_schema_exports), SKILLS_OVERLAY = "skills", looksLikePath = (value) => /^(\.{1,2}([\\/]|$)|[\\/]|~([\\/]|$)|[A-Za-z]:[\\/])/.test(value) || /[\\/]/.test(value) || /\.md$/i.test(value);
6721
+ } = cjs(skills_panel_exports), { splitSkillDocument: splitSkillDocument2 } = cjs(skill_preview_exports), { SKILL_NAME } = cjs(skills_catalog_schema_exports), SKILLS_OVERLAY = "skills", looksLikePath = (value) => /^(\.{1,2}([\\/]|$)|[\\/]|~([\\/]|$)|[A-Za-z]:[\\/])/.test(value) || /[\\/]/.test(value) || /\.md$/i.test(value);
6802
6722
  function parseAddTarget2(raw) {
6803
6723
  let value = (raw ?? "").trim().replace(/^(["'])(.*)\1$/, "$2");
6804
6724
  if (!value) return { kind: "catalog", query: "" };
@@ -6849,7 +6769,7 @@ function settleOverrides(overrides, registryText) {
6849
6769
  function tokenLabel(tokens) {
6850
6770
  return tokens == null ? "" : tokens >= 1e3 ? `~${(tokens / 1e3).toFixed(tokens >= 1e4 ? 0 : 1)}k tok` : `~${tokens} tok`;
6851
6771
  }
6852
- var safe = (value) => sanitizeDisplayText2(value), packageKey = (source) => source.type === "catalog" ? `catalog:${source.entry.sourceUrl}#${source.entry.name}` : source.type === "url" ? `url:${source.url}` : `disk:${source.path}`, frontmatterField = (manifest, key) => splitSkillDocument2(manifest).fields.find((f) => f.key === key)?.value, isSkillName = (value) => !!value && SKILL_NAME2.test(value);
6772
+ var safe = (value) => sanitizeDisplayText2(value), packageKey = (source) => source.type === "catalog" ? `catalog:${source.entry.sourceUrl}#${source.entry.name}` : source.type === "url" ? `url:${source.url}` : `disk:${source.path}`, frontmatterField = (manifest, key) => splitSkillDocument2(manifest).fields.find((f) => f.key === key)?.value, isSkillName = (value) => !!value && SKILL_NAME.test(value);
6853
6773
  function manifestProblem(manifest) {
6854
6774
  return Buffer.byteLength(manifest, "utf-8") > MAX_SKILL_FILE_BYTES2 ? `SKILL.md is over ${Math.round(MAX_SKILL_FILE_BYTES2 / 1024)} KB, the indexer would reject it` : manifest.slice(0, 8192).includes("\0") ? "SKILL.md is not text" : null;
6855
6775
  }
@@ -6917,7 +6837,7 @@ function exactEntry(entries, query) {
6917
6837
  import { promises as fs3 } from "node:fs";
6918
6838
  import { homedir as homedir2 } from "node:os";
6919
6839
  import { basename as basename2, dirname, join as join3, relative, resolve as resolve2, sep } from "node:path";
6920
- var { SKILLS_REGISTRY_PATH: SKILLS_REGISTRY_PATH3, SKILLS_STATE_PATH: SKILLS_STATE_PATH2, mergeDisabledList: mergeDisabledList2, parseSkillsRegistry: parseSkillsRegistry3 } = cjs(skills_panel_exports), { MAX_PACKAGE_FILES: MAX_PACKAGE_FILES2, MAX_SKILL_PACKAGE_BYTES: MAX_SKILL_PACKAGE_BYTES3, resolvePackageFilePath: resolvePackageFilePath2 } = cjs(skills_catalog_schema_exports), errorText2 = (err) => err instanceof Error ? err.message : String(err), isNotFound = (err) => err?.status === 404;
6840
+ var { SKILLS_REGISTRY_PATH: SKILLS_REGISTRY_PATH3, SKILLS_STATE_PATH: SKILLS_STATE_PATH2, mergeDisabledList: mergeDisabledList2, parseSkillsRegistry: parseSkillsRegistry3 } = cjs(skills_panel_exports), { MAX_PACKAGE_FILES, MAX_SKILL_PACKAGE_BYTES: MAX_SKILL_PACKAGE_BYTES2, resolvePackageFilePath } = cjs(skills_catalog_schema_exports), errorText2 = (err) => err instanceof Error ? err.message : String(err), isNotFound = (err) => err?.status === 404;
6921
6841
  async function must(result, what) {
6922
6842
  let outcome = await result;
6923
6843
  if (outcome && outcome.success === !1) throw new Error(`${what} was refused (protected file?)`);
@@ -7045,7 +6965,7 @@ async function readLocalPackage(input, cwd = process.cwd()) {
7045
6965
  try {
7046
6966
  let manifestStat = await fs3.stat(manifestPath);
7047
6967
  if (!manifestStat.isFile()) return { ok: !1, error: `${manifestPath} is not a file` };
7048
- if (manifestStat.size > MAX_SKILL_PACKAGE_BYTES3) return { ok: !1, error: `SKILL.md is over ${Math.round(MAX_SKILL_PACKAGE_BYTES3 / 1024)} KB` };
6968
+ if (manifestStat.size > MAX_SKILL_PACKAGE_BYTES2) return { ok: !1, error: `SKILL.md is over ${Math.round(MAX_SKILL_PACKAGE_BYTES2 / 1024)} KB` };
7049
6969
  manifestBytes = await fs3.readFile(manifestPath);
7050
6970
  } catch {
7051
6971
  return { ok: !1, error: stat.isDirectory() ? `No SKILL.md in ${target2}` : `Cannot read ${target2}` };
@@ -7077,24 +6997,24 @@ async function readLocalPackage(input, cwd = process.cwd()) {
7077
6997
  if (!entry.isFile()) continue;
7078
6998
  let rel = relative(target2, full).split(sep).join("/");
7079
6999
  if (rel === "SKILL.md") continue;
7080
- let path = resolvePackageFilePath2(identity.name, rel);
7000
+ let path = resolvePackageFilePath(identity.name, rel);
7081
7001
  if (!path) {
7082
7002
  warnings.push(`${rel}: skipped (not a package path)`);
7083
7003
  continue;
7084
7004
  }
7085
- if (resources.length >= MAX_PACKAGE_FILES2) {
7005
+ if (resources.length >= MAX_PACKAGE_FILES) {
7086
7006
  skippedOver++;
7087
7007
  continue;
7088
7008
  }
7089
- if ((await fs3.stat(full)).size > MAX_SKILL_PACKAGE_BYTES3) {
7090
- warnings.push(`${rel}: skipped (over ${Math.round(MAX_SKILL_PACKAGE_BYTES3 / 1024)} KB)`);
7009
+ if ((await fs3.stat(full)).size > MAX_SKILL_PACKAGE_BYTES2) {
7010
+ warnings.push(`${rel}: skipped (over ${Math.round(MAX_SKILL_PACKAGE_BYTES2 / 1024)} KB)`);
7091
7011
  continue;
7092
7012
  }
7093
7013
  let bytes = await fs3.readFile(full);
7094
7014
  resources.push(bytes.subarray(0, 8192).includes(0) ? { path, contentBase64: bytes.toString("base64") } : { path, content: bytes.toString("utf-8") });
7095
7015
  }
7096
7016
  };
7097
- await walk(target2, 0), skippedOver && warnings.push(`${skippedOver} more file${skippedOver === 1 ? "" : "s"} skipped (a package ships at most ${MAX_PACKAGE_FILES2} beside SKILL.md)`);
7017
+ await walk(target2, 0), skippedOver && warnings.push(`${skippedOver} more file${skippedOver === 1 ? "" : "s"} skipped (a package ships at most ${MAX_PACKAGE_FILES} beside SKILL.md)`);
7098
7018
  }
7099
7019
  return {
7100
7020
  ok: !0,
@@ -7423,7 +7343,7 @@ function SkillDoc({ manifest, width, height }) {
7423
7343
  var import_react24 = __toESM(require_react(), 1);
7424
7344
 
7425
7345
  // src/main/tui/context/model.ts
7426
- var { resolveLoopThreshold } = cjs(context_breakdown_exports), CONTEXT_OVERLAY = "context";
7346
+ var { resolveLoopThreshold, calibrationNote } = cjs(context_breakdown_exports), CONTEXT_OVERLAY = "context";
7427
7347
  function openContext(store, props) {
7428
7348
  store.actions.pushOverlay({ kind: CONTEXT_OVERLAY, props: { ...props } });
7429
7349
  }
@@ -7446,6 +7366,9 @@ var SOURCE_TEXT = {
7446
7366
  function thresholdText(r, fmt) {
7447
7367
  return `auto-compacts at ${fmt(r.compactThreshold)} (${SOURCE_TEXT[r.compactThresholdSource]})`;
7448
7368
  }
7369
+ function calibrationText(cal, approx, fmt) {
7370
+ return calibrationNote(cal, fmt, approx);
7371
+ }
7449
7372
  function contextRows(categories, expanded) {
7450
7373
  let rows = [];
7451
7374
  for (let category of categories) {
@@ -7592,7 +7515,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
7592
7515
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, flexDirection: "column", height: Math.min(rows.length, rowsHeight), children: shown.map((row4, i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RowLine, { row: row4, selectedId: selected?.id, total, labelWidth, rowBar, theme: theme2 }, `${start + i}`)) }),
7593
7516
  rows.length > rowsHeight ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, children: `${start + 1}-${Math.min(rows.length, start + rowsHeight)} of ${rows.length} rows` }) : null,
7594
7517
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.muted, wrap: "truncate-end", children: selected ? `${selected.label}: ${selected.note}` : "" }) }),
7595
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: s.compacting ? `Compacting ${s.loop}${g.ellipsis}` : s.loading ? `Re-measuring${g.ellipsis}` : s.measuredAt ? `Measured ${formatClock(s.measuredAt)} ${g.sep} conversation estimated, the rest tokenized` : "" })
7518
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: s.compacting ? `Compacting ${s.loop}${g.ellipsis}` : s.loading ? `Re-measuring${g.ellipsis}` : s.measuredAt ? `Measured ${formatClock(s.measuredAt)} ${g.sep} ${calibrationText(s.data?.breakdown?.calibration, g.approx, formatCount)}` : "" })
7596
7519
  ] });
7597
7520
  }
7598
7521
  return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Modal, { title: `Context ${g.sep} ${truncate(header2, inner - 12)}`, width: dialogWidth, hints, onClose: close, children: body });
@@ -7600,7 +7523,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
7600
7523
  function RowLine({ row: row4, selectedId, total, labelWidth, rowBar, theme: theme2 }) {
7601
7524
  let g = theme2.glyph, share = (tokens) => total > 0 ? `${Math.round(tokens / total * 100)}%` : "0%";
7602
7525
  if (row4.kind === "category") {
7603
- let c = row4.category, isSel = c.id === selectedId, label2 = `${row4.expandable ? row4.expanded ? g.expanded : g.collapsed : " "} ${c.label}${c.count !== void 0 ? ` (${c.count})` : ""}`, bar = barText(c.tokens, total, rowBar, theme2.ascii);
7526
+ let c = row4.category, isSel = c.id === selectedId, label2 = `${row4.expandable ? row4.expanded ? g.expanded : g.collapsed : " "} ${c.label}${c.count !== void 0 ? ` (${c.count})` : ""}${c.basis !== "measured" ? ` ${g.approx}` : ""}`, bar = barText(c.tokens, total, rowBar, theme2.ascii);
7604
7527
  return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && isSel, bold: isSel, children: [
7605
7528
  /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Text, { color: isSel ? theme2.color.accent : theme2.color.dim, children: [
7606
7529
  isSel ? g.pointer : " ",
@@ -8011,7 +7934,7 @@ var RUNTIME_VIEW = "runtime", RUNTIME_TABS = [
8011
7934
  { id: "status", title: "Status", description: "Daemon health, version, uptime and every agent\u2019s loops" },
8012
7935
  { id: "folders", title: "Folders", description: "Tracked agent folders: Enter its agents (review, load, errors), a add, d stop tracking, r rescan" },
8013
7936
  { id: "identity", title: "Identity", description: "Owner identity: status; Enter to create, restore, unlock or lock" },
8014
- { id: "auth", title: "Sign-in", description: "Provider sign-ins (ChatGPT, Grok) and API-key providers; Enter to sign in" },
7937
+ { id: "auth", title: "Sign-in", description: "Provider sign-ins (ChatGPT, Grok, Claude) and API-key providers; Enter to sign in" },
8015
7938
  { id: "providers", title: "Providers", description: "LLM providers and which agents use them" },
8016
7939
  { id: "usage", title: "Usage", description: "Token usage across agents, by model" },
8017
7940
  { id: "network", title: "Network", description: "Mesh, LAN, WebSocket; m mesh on/off, s server start/stop" },
@@ -8486,14 +8409,14 @@ var REPORTS = {
8486
8409
  title: "Auth",
8487
8410
  async load(client) {
8488
8411
  let d = await client.authStatus(), lines = [heading("Subscription sign-ins")];
8489
- for (let [name, status] of [["chatgpt", d.chatgpt], ["grok", d.grok]]) {
8490
- let s = status ?? {};
8491
- lines.push(indent([{ text: name.padEnd(9), tone: "key" }, s.authenticated ? { text: "signed in", tone: "success" } : { text: "not signed in", tone: "muted" }, { text: s.email ? ` ${String(s.email)}` : "", tone: "muted" }]));
8412
+ for (let [name, status] of [["chatgpt", d.chatgpt], ["grok", d.grok], ["claude", d.claude]]) {
8413
+ let s = status ?? {}, state = s.authenticated ? { text: "signed in", tone: "success" } : s.installed === !1 ? { text: "Claude Code not installed", tone: "warn" } : { text: "not signed in", tone: "muted" }, extra = [s.email ? String(s.email) : "", s.plan ? `${String(s.plan)} plan` : "", s.installed === !1 && s.installUrl ? String(s.installUrl) : ""].filter(Boolean).join(" \xB7 ");
8414
+ lines.push(indent([{ text: name.padEnd(9), tone: "key" }, state, { text: extra ? ` ${extra}` : "", tone: "muted" }]));
8492
8415
  }
8493
8416
  return lines.push(blank(), heading("API-key providers")), lines.push(...tableLines(
8494
8417
  ["id", "type", "key", "stored in"],
8495
8418
  d.providers.map((p) => [p.id, p.type, p.hasApiKey ? "set" : "missing", p.credentialStorage])
8496
- ).map(indent)), lines.push(blank(), heading("Sign in or out")), lines.push(indent(plain("Enter opens the sign-in dialog \xB7 /login chatgpt \xB7 /login grok \xB7 /logout <chatgpt|grok>", "accent"))), lines.push(indent(plain("From a shell: adf auth login <chatgpt|grok>", "muted"))), lines.push(indent(plain("API keys: Studio settings, stored by the daemon (never shown here).", "muted"))), { data: redactSecrets(d), lines };
8419
+ ).map(indent)), lines.push(blank(), heading("Sign in or out")), lines.push(indent(plain("Enter opens the sign-in dialog \xB7 /login chatgpt \xB7 /login grok \xB7 /login claude \xB7 /logout <chatgpt|grok|claude>", "accent"))), lines.push(indent(plain("From a shell: adf auth login <chatgpt|grok|claude>", "muted"))), lines.push(indent(plain("API keys: Studio settings, stored by the daemon (never shown here).", "muted"))), { data: redactSecrets(d), lines };
8497
8420
  }
8498
8421
  },
8499
8422
  network: {
@@ -8900,15 +8823,14 @@ function folderAgentsSummary(agents) {
8900
8823
  }
8901
8824
  async function loadFolderAgent(store, agent2, options = {}) {
8902
8825
  try {
8903
- options.accept && await store.client.acceptReview(agent2.filePath);
8904
- let ref = await store.client.load(agent2.filePath, !0), name = ref.config?.handle || ref.config?.name || agent2.name, started = "";
8826
+ let accepted = options.accept ? await store.client.acceptReview(agent2.filePath) : null, ref = await store.client.load(agent2.filePath, !0), name = ref.config?.handle || ref.config?.name || agent2.name, started = "";
8905
8827
  if (agent2.autostart)
8906
8828
  try {
8907
8829
  await store.client.start(ref.id), started = " and started it";
8908
8830
  } catch (err) {
8909
8831
  started = ` (start failed: ${err instanceof Error ? err.message : String(err)})`;
8910
8832
  }
8911
- return store.actions.toast(`${options.accept ? "Reviewed and loaded" : "Loaded"} ${name}${started}`, started.startsWith(" (") ? "warn" : "success", 5e3), writeFolders(store, {}, !0), await store.actions.refreshAgents(), store.actions.refreshTracked(), { ok: !0, agentId: ref.id };
8833
+ return store.actions.toast(`${options.accept ? "Reviewed and loaded" : "Loaded"} ${name}${started}${lockedNote(accepted?.lockedFields)}`, started.startsWith(" (") ? "warn" : "success", 6e3), writeFolders(store, {}, !0), await store.actions.refreshAgents(), store.actions.refreshTracked(), { ok: !0, agentId: ref.id };
8912
8834
  } catch (err) {
8913
8835
  err instanceof DaemonError && err.unreachable && store.dispatch({ type: "daemon/reachable", reachable: !1 });
8914
8836
  let error = err instanceof DaemonError && err.status === 403 ? "It needs review first." : err instanceof Error ? err.message : String(err);
@@ -10107,7 +10029,10 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10107
10029
  g.dot,
10108
10030
  " "
10109
10031
  ] }),
10110
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Box_default, { width: w - 2, flexDirection: "column", children: item.text ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: item.text, color: theme2.color.assistant }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { children: " " }) })
10032
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { width: w - 2, flexDirection: "column", children: [
10033
+ item.text ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: item.text, color: theme2.color.assistant }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { children: " " }),
10034
+ item.interrupted ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: theme2.color.dim, children: "[interrupted]" }) : null
10035
+ ] })
10111
10036
  ] });
10112
10037
  case "thinking": {
10113
10038
  let open2 = expanded || showThinking, lines = lineCount(item.text);
@@ -10131,7 +10056,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
10131
10056
  case "tool":
10132
10057
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ToolBody, { item, w, expanded });
10133
10058
  case "hil": {
10134
- let tone = item.status === "pending" ? theme2.color.warn : item.status === "approved" ? theme2.color.success : theme2.color.error;
10059
+ let tone = item.status === "pending" ? theme2.color.warn : item.status === "approved" || item.status === "completed" ? theme2.color.success : theme2.color.error;
10135
10060
  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: [
10136
10061
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", children: [
10137
10062
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { bold: !0, color: tone, children: [
@@ -11663,7 +11588,7 @@ var import_react38 = __toESM(require_react(), 1);
11663
11588
  import { promises as fs4, rmSync, statSync as statSync3 } from "node:fs";
11664
11589
  import { tmpdir as tmpdir3 } from "node:os";
11665
11590
  import { join as join4 } from "node:path";
11666
- var copies = /* @__PURE__ */ new Map(), dirs = /* @__PURE__ */ new Set(), exitHook = !1, copyKey = (agentId, target2) => `${agentId}\0${targetKey(target2)}`, errorText5 = (err) => err instanceof Error ? err.message : String(err), bytesOf = (loaded) => loaded.binary ? Buffer.from(loaded.bytes ?? new Uint8Array()) : Buffer.from(loaded.text ?? "", "utf-8");
11591
+ var { openBrowser: openBrowser2 } = cjs(auth_flow_exports), copies = /* @__PURE__ */ new Map(), dirs = /* @__PURE__ */ new Set(), exitHook = !1, copyKey = (agentId, target2) => `${agentId}\0${targetKey(target2)}`, errorText5 = (err) => err instanceof Error ? err.message : String(err), bytesOf = (loaded) => loaded.binary ? Buffer.from(loaded.bytes ?? new Uint8Array()) : Buffer.from(loaded.text ?? "", "utf-8");
11667
11592
  function externalCopy(agentId, target2) {
11668
11593
  return copies.get(copyKey(agentId, target2));
11669
11594
  }
@@ -11694,7 +11619,7 @@ async function openExternal(deps, target2) {
11694
11619
  }
11695
11620
  copies.set(copyKey(agentId, target2), { agentId, target: target2, file, original: bytes, binary: loaded.binary, mime: loaded.mime, mtimeMs: (await fs4.stat(file)).mtimeMs });
11696
11621
  }
11697
- return (deps.open ?? openBrowser)(file), actions4.toast(`Opened ${label2} in the default app \u2014 after saving there, press s to save it back (${file})`, "info", 8e3), !0;
11622
+ return (deps.open ?? openBrowser2)(file), actions4.toast(`Opened ${label2} in the default app \u2014 after saving there, press s to save it back (${file})`, "info", 8e3), !0;
11698
11623
  }
11699
11624
  async function saveBackExternal(deps, target2) {
11700
11625
  let { client, actions: actions4, agentId, agentLabel: agentLabel5 } = deps, label2 = targetLabel(target2), copy = externalCopy(agentId, target2);
@@ -11708,14 +11633,14 @@ async function saveBackExternal(deps, target2) {
11708
11633
  }
11709
11634
  if (edited.equals(copy.original))
11710
11635
  return copy.mtimeMs = (await fs4.stat(copy.file)).mtimeMs, actions4.toast(`No changes to ${label2}`, "info"), "unchanged";
11711
- let concurrent = null;
11636
+ let concurrent = null, baseRevision;
11712
11637
  try {
11713
11638
  let current = await loadTarget(client, agentId, target2);
11714
- bytesOf(current).equals(copy.original) || (concurrent = "changed in the agent since you opened it");
11639
+ baseRevision = current.revision, bytesOf(current).equals(copy.original) || (concurrent = "changed in the agent since you opened it");
11715
11640
  } catch (err) {
11716
11641
  concurrent = err.status === 404 ? "was deleted since you opened it" : `could not be re-checked (${errorText5(err)})`;
11717
11642
  }
11718
- return await actions4.confirm({
11643
+ if (!await actions4.confirm({
11719
11644
  title: concurrent ? `Concurrent change: ${label2}` : `Save ${label2}`,
11720
11645
  message: [
11721
11646
  concurrent ? `WARNING: ${label2} ${concurrent}. Writing replaces that version.` : null,
@@ -11725,7 +11650,9 @@ async function saveBackExternal(deps, target2) {
11725
11650
  confirmLabel: concurrent ? "Overwrite" : "Write",
11726
11651
  cancelLabel: "Cancel",
11727
11652
  danger: !!concurrent
11728
- }) ? await actions4.run(`Write ${label2}`, (c) => (copy.binary && target2.kind === "file" ? c.writeFile(agentId, target2.path, { contentBase64: edited.toString("base64"), ...copy.mime ? { mimeType: copy.mime } : {} }) : writeTarget(c, agentId, target2, edited.toString("utf-8"))).then(() => !0)) ? (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") : "discarded";
11653
+ })) return "discarded";
11654
+ 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);
11655
+ 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");
11729
11656
  }
11730
11657
 
11731
11658
  // src/main/tui/views/files/FilesTab.tsx
@@ -14558,8 +14485,8 @@ var TOOL_GROUPS = [
14558
14485
  off: "nobody: no inbound messages, sends still allowed",
14559
14486
  directory: "only ancestor-directory agents on this runtime",
14560
14487
  localhost: "any agent on this machine",
14561
- lan: "any agent on the local network (binds 0.0.0.0)",
14562
- public: "any agent reachable over the public internet (binds 0.0.0.0)"
14488
+ lan: "any agent on an allowed network",
14489
+ public: "any agent that reaches this computer, also only on an allowed network"
14563
14490
  }, SEND_MODES = ["proactive", "respond_only", "listen_only"], SEND_MODE_HINTS = {
14564
14491
  proactive: "can send anytime",
14565
14492
  respond_only: "sends only when a message triggered the turn",
@@ -14571,8 +14498,6 @@ function triState(items, pred) {
14571
14498
  return n === 0 ? "none" : n === items.length ? "all" : "mixed";
14572
14499
  }
14573
14500
  function groupBlocked(config2, groupId) {
14574
- let triggers = config2.triggers;
14575
- if (groupId === "messaging" && !triggers?.on_inbox?.enabled) return "needs messaging (the on_inbox trigger)";
14576
14501
  if (groupId === "inbox" && config2.messaging?.inbox_mode !== !0) return "needs inbox mode (Settings \u203A Inbox mode)";
14577
14502
  }
14578
14503
  function mcpServers(config2) {
@@ -14729,6 +14654,26 @@ function setMainThreshold(config2, value) {
14729
14654
  let next = clone(config2), context = { ...next.context ?? {} };
14730
14655
  return value === null ? delete context.compact_threshold : context.compact_threshold = value, next.context = context, { ok: !0, config: next, message: value === null ? `main compacts at the default (${formatTokens2(mainThreshold(next).value)})` : `main compacts at ${formatTokens2(value)} tokens` };
14731
14656
  }
14657
+ function requestMediaLimitOf(config2) {
14658
+ let files2 = config2.context?.max_request_media_files, mb = config2.context?.max_request_media_mb;
14659
+ return {
14660
+ files: typeof files2 == "number" && files2 > 0 ? files2 : 20,
14661
+ mb: typeof mb == "number" && mb > 0 ? mb : 20,
14662
+ set: typeof files2 == "number" && files2 > 0 || typeof mb == "number" && mb > 0
14663
+ };
14664
+ }
14665
+ function setRequestMediaLimit(config2, value) {
14666
+ let next = clone(config2), context = { ...next.context ?? {} };
14667
+ delete context.max_request_media_files, delete context.max_request_media_mb, value && (context.max_request_media_files = value.files, context.max_request_media_mb = value.mb), next.context = context;
14668
+ let now = requestMediaLimitOf(next);
14669
+ return { ok: !0, config: next, message: `Requests carry at most ${now.files} files, ${now.mb} MB${value ? "" : " (default)"}` };
14670
+ }
14671
+ function parseMediaLimit(args) {
14672
+ if (args.length === 1 && args[0].toLowerCase() === "default") return { ok: !0, value: null };
14673
+ if (args.length !== 2) return { ok: !1, error: "Give files and MB, or default" };
14674
+ let [files2, mb] = args.map((a) => Number(a));
14675
+ return [files2, mb].every((n) => Number.isInteger(n) && n > 0) ? { ok: !0, value: { files: files2, mb } } : { ok: !1, error: "Files and MB must be positive whole numbers" };
14676
+ }
14732
14677
  function parseThreshold(text) {
14733
14678
  let raw = text.trim().toLowerCase().replace(/[,_\s]/g, "");
14734
14679
  if (!raw || raw === "default" || raw === "inherit" || raw === "0") return { ok: !0, value: null };
@@ -14835,6 +14780,15 @@ function settingRows(config2, extras = {}) {
14835
14780
  value: `main at ${formatTokens2(main.value)}${main.source === "default" ? " (default)" : ""}${typeof used == "number" ? ` \xB7 in use ${formatTokens2(used)} (${Math.round(used / main.value * 100)}%)` : ""}`,
14836
14781
  hint: (config2.loops ?? []).length ? `inner loops: ${(config2.loops ?? []).map((l) => `${l.name} ${l.compact_threshold != null ? formatTokens2(l.compact_threshold) : "inherit"}`).join(", ")}` : "History is summarized when the context reaches this size",
14837
14782
  ...lock(["context"])
14783
+ });
14784
+ let media2 = requestMediaLimitOf(config2);
14785
+ rows.push({
14786
+ id: "media",
14787
+ label: "Media",
14788
+ kind: "dialog",
14789
+ value: `${media2.files} files, ${media2.mb} MB per request${media2.set ? "" : " (default)"}`,
14790
+ hint: "Past either, the oldest files are left out until half remains \xB7 /media <files> <MB> | default",
14791
+ ...lock(["context"])
14838
14792
  }), rows.push({
14839
14793
  id: "autonomous",
14840
14794
  label: "Autonomous",
@@ -14929,6 +14883,9 @@ async function actOnSetting(actions4, agentId, row4, config2) {
14929
14883
  case "compaction":
14930
14884
  actions4.pushOverlay({ kind: COMPACTION_OVERLAY, props: { agentId } });
14931
14885
  return;
14886
+ case "media":
14887
+ actions4.toast("Set with /media <files> <MB>, or /media default", "info", 3e3);
14888
+ return;
14932
14889
  case "visibility":
14933
14890
  case "send":
14934
14891
  actions4.pushOverlay({ kind: CHOICE_OVERLAY, props: { agentId, setting: row4.id } });
@@ -15302,6 +15259,24 @@ var inspect = {
15302
15259
  }
15303
15260
  await applyThreshold(ctx.store, ctx.agentId, ctx.loop, parsed.value);
15304
15261
  }
15262
+ }, media = {
15263
+ name: "media",
15264
+ args: "[<files> <MB>|default]",
15265
+ description: "Request media limit of the selected agent: most files and MB one request carries (default 20, 20). Past either, the oldest are left out until half remains",
15266
+ available: (scope) => !!scope.agentId,
15267
+ complete: (partial) => ["default"].filter((v) => v.startsWith(partial.trim())),
15268
+ run: async (ctx) => {
15269
+ if (!ctx.agentId) {
15270
+ ctx.print("No agent selected", "warn");
15271
+ return;
15272
+ }
15273
+ let parsed = parseMediaLimit(ctx.args);
15274
+ if (!parsed.ok) {
15275
+ ctx.print(`${parsed.error}. Usage: /media <files> <MB> | default`, "warn");
15276
+ return;
15277
+ }
15278
+ await applyChange(ctx.actions, ctx.agentId, (cfg) => setRequestMediaLimit(cfg, parsed.value), "Media");
15279
+ }
15305
15280
  }, TASK_FILTER_ARGS = TASK_FILTERS, tasks = {
15306
15281
  name: "tasks",
15307
15282
  args: `[${TASK_FILTERS.join("|")}]`,
@@ -15354,7 +15329,7 @@ var inspect = {
15354
15329
  patchInspectState(ctx.actions, ctx.state(), { tab: t.id }), ctx.actions.setView(INSPECT_VIEW);
15355
15330
  }
15356
15331
  }))
15357
- ], inspectCommands = { commands: [inspect, model, config, tasks, instructions, tools, compaction], actions: actions2 };
15332
+ ], inspectCommands = { commands: [inspect, model, config, tasks, instructions, tools, compaction, media], actions: actions2 };
15358
15333
 
15359
15334
  // src/main/tui/views/inspect/EventsTab.tsx
15360
15335
  var import_react51 = __toESM(require_react(), 1);
@@ -15613,6 +15588,9 @@ function typeColor(theme2, type) {
15613
15588
  // src/main/tui/views/inspect/ConfigTab.tsx
15614
15589
  var import_react52 = __toESM(require_react(), 1);
15615
15590
  var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
15591
+ import { promises as fs5 } from "node:fs";
15592
+ import { tmpdir as tmpdir4 } from "node:os";
15593
+ import { join as join5 } from "node:path";
15616
15594
  async function editConfigFlow(agentId, label2, actions4, suspend, edit = (text) => editText(text, { filename: `${label2}.config.json` })) {
15617
15595
  let original = await actions4.loadConfig(agentId);
15618
15596
  if (!original) return "failed";
@@ -15644,10 +15622,10 @@ Edit again? Discard drops your edit.`,
15644
15622
  }
15645
15623
  if (check.changedKeys.length === 0)
15646
15624
  return actions4.toast("Config unchanged (formatting only), nothing saved", "info"), "unchanged";
15647
- let fresh = await actions4.run("Re-check config", (c) => c.config(agentId).then((r) => r.config));
15648
- if (!fresh) return "failed";
15649
- let theirs = changedKeysBetween(original, fresh);
15650
- return theirs.length > 0 && !await actions4.confirm({
15625
+ let freshResult = await actions4.run("Re-check config", (c) => c.config(agentId));
15626
+ if (!freshResult) return "failed";
15627
+ let fresh = freshResult.config, baseRevision = revisionOf(freshResult), theirs = changedKeysBetween(original, fresh);
15628
+ if (theirs.length > 0 && !await actions4.confirm({
15651
15629
  title: `Config of ${label2} changed on the daemon`,
15652
15630
  message: `While you were editing, these keys changed on the daemon: ${theirs.join(", ")}.
15653
15631
  Saving your copy reverts them${theirs.includes("loops") ? " (a loop added meanwhile would be removed and archived)" : ""}.
@@ -15656,14 +15634,24 @@ Warning: ${check.warnings.join("; ")}` : ""}`,
15656
15634
  confirmLabel: "Overwrite",
15657
15635
  cancelLabel: "Discard",
15658
15636
  danger: !0
15659
- }) ? (actions4.toast("Config edit discarded (the daemon copy changed meanwhile)", "warn"), "discarded") : changedKeysBetween(fresh, check.config).length === 0 ? (actions4.toast("Config already matches the daemon, nothing saved", "info"), "unchanged") : theirs.length > 0 || await actions4.confirm({
15637
+ }))
15638
+ return actions4.toast("Config edit discarded (the daemon copy changed meanwhile)", "warn"), "discarded";
15639
+ if (changedKeysBetween(fresh, check.config).length === 0)
15640
+ return actions4.toast("Config already matches the daemon, nothing saved", "info"), "unchanged";
15641
+ if (!(theirs.length > 0 || await actions4.confirm({
15660
15642
  title: `Save config of ${label2}?`,
15661
15643
  message: `Changed: ${check.changedKeys.join(", ")}${check.warnings.length ? `
15662
15644
  Warning: ${check.warnings.join("; ")}` : ""}`,
15663
15645
  confirmLabel: "Save",
15664
15646
  cancelLabel: "Discard",
15665
15647
  danger: check.warnings.length > 0
15666
- }) ? await actions4.run("Save config", (c) => c.putConfig(agentId, check.config)) ? (actions4.toast(`Config of ${label2} saved (${check.changedKeys.join(", ")})`, "success"), await actions4.loadConfig(agentId), "saved") : "failed" : (actions4.toast("Config edit discarded", "warn"), "discarded");
15648
+ })))
15649
+ return actions4.toast("Config edit discarded", "warn"), "discarded";
15650
+ let keepCopy = async () => {
15651
+ let file = join5(tmpdir4(), `adf-tui-${label2.replace(/[^\w.-]+/g, "_")}.config-${Date.now()}.json`);
15652
+ return await fs5.writeFile(file, result.text ?? "", "utf-8"), file;
15653
+ }, saved = await writeOverConflicts(actions4, `Config of ${label2}`, keepCopy, (base2) => actions4.run("Save config", (c) => writeOver(() => c.request("PUT", `/agents/${encodeURIComponent(agentId)}/config`, { body: check.config, ...base2 !== void 0 ? { query: { baseRevision: base2 } } : {} }))), baseRevision);
15654
+ return saved === "reloaded" ? (await actions4.loadConfig(agentId), "discarded") : saved ? (actions4.toast(`Config of ${label2} saved (${check.changedKeys.join(", ")})`, "success"), await actions4.loadConfig(agentId), "saved") : "failed";
15667
15655
  }
15668
15656
  }
15669
15657
  function ConfigTab({ agentId, label: label2, width, height, focused }) {