zidane 5.1.13 → 5.1.14

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 (45) hide show
  1. package/dist/{agent-skiQGYs2.d.ts → agent-BuGxYfqh.d.ts} +11 -4
  2. package/dist/agent-BuGxYfqh.d.ts.map +1 -0
  3. package/dist/chat.d.ts +172 -6
  4. package/dist/chat.d.ts.map +1 -1
  5. package/dist/chat.js +2 -2
  6. package/dist/{index-CjPh6CRE.d.ts → index-Aaa1tP6E.d.ts} +2 -2
  7. package/dist/{index-CjPh6CRE.d.ts.map → index-Aaa1tP6E.d.ts.map} +1 -1
  8. package/dist/{index-YM7SipFz.d.ts → index-Cv5wED8j.d.ts} +2 -2
  9. package/dist/{index-YM7SipFz.d.ts.map → index-Cv5wED8j.d.ts.map} +1 -1
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +5 -5
  12. package/dist/{login-Cc6Q-Fpu.js → login-DJscx_sS.js} +4 -4
  13. package/dist/{login-Cc6Q-Fpu.js.map → login-DJscx_sS.js.map} +1 -1
  14. package/dist/{mcp-CUt-N8zn.js → mcp-Bq_rD6e9.js} +2 -2
  15. package/dist/{mcp-CUt-N8zn.js.map → mcp-Bq_rD6e9.js.map} +1 -1
  16. package/dist/mcp.d.ts +1 -1
  17. package/dist/mcp.js +1 -1
  18. package/dist/{presets-Ce79MK4J.js → presets-BEruW0Ji.js} +2 -2
  19. package/dist/{presets-Ce79MK4J.js.map → presets-BEruW0Ji.js.map} +1 -1
  20. package/dist/presets.d.ts +2 -2
  21. package/dist/presets.js +1 -1
  22. package/dist/providers.d.ts +1 -1
  23. package/dist/session/sqlite.d.ts +1 -1
  24. package/dist/session.d.ts +1 -1
  25. package/dist/skills.d.ts +2 -2
  26. package/dist/{tools-BG2wMa3X.js → tools-BBFu1UsV.js} +3 -3
  27. package/dist/{tools-BG2wMa3X.js.map → tools-BBFu1UsV.js.map} +1 -1
  28. package/dist/tools.d.ts +2 -2
  29. package/dist/tools.js +1 -1
  30. package/dist/{tool-formatters-0aOMYbH-.d.ts → transcript-anchors-FJMZyLS4.d.ts} +242 -97
  31. package/dist/transcript-anchors-FJMZyLS4.d.ts.map +1 -0
  32. package/dist/tui.d.ts +55 -39
  33. package/dist/tui.d.ts.map +1 -1
  34. package/dist/tui.js +335 -314
  35. package/dist/tui.js.map +1 -1
  36. package/dist/{turn-operations-CDmQ2h-T.js → turn-operations-CeLlc7jt.js} +572 -91
  37. package/dist/turn-operations-CeLlc7jt.js.map +1 -0
  38. package/dist/{types-Bx_F8jet.js → types-IcokUOyC.js} +11 -4
  39. package/dist/{types-Bx_F8jet.js.map → types-IcokUOyC.js.map} +1 -1
  40. package/dist/types.d.ts +2 -2
  41. package/dist/types.js +1 -1
  42. package/package.json +1 -1
  43. package/dist/agent-skiQGYs2.d.ts.map +0 -1
  44. package/dist/tool-formatters-0aOMYbH-.d.ts.map +0 -1
  45. package/dist/turn-operations-CDmQ2h-T.js.map +0 -1
@@ -1,9 +1,9 @@
1
- import { a as multiEdit, c as grep, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, r as shell, t as writeFile$1, u as edit } from "./tools-BG2wMa3X.js";
2
- import { n as toolResultToText } from "./types-Bx_F8jet.js";
3
- import { r as normalizeMcpServers } from "./mcp-CUt-N8zn.js";
1
+ import { a as multiEdit, c as grep, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, r as shell, t as writeFile$1, u as edit } from "./tools-BBFu1UsV.js";
2
+ import { n as toolResultToText } from "./types-IcokUOyC.js";
3
+ import { r as normalizeMcpServers } from "./mcp-Bq_rD6e9.js";
4
4
  import { a as discoverSkills } from "./interpolate-BI6ovwag.js";
5
5
  import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
6
- import { n as definePreset } from "./presets-Ce79MK4J.js";
6
+ import { n as definePreset } from "./presets-BEruW0Ji.js";
7
7
  import { i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CvriFHFU.js";
8
8
  import { spawn } from "node:child_process";
9
9
  import { readdir, stat, writeFile } from "node:fs/promises";
@@ -14,6 +14,7 @@ import { homedir } from "node:os";
14
14
  import { anthropicOAuthProvider, openaiCodexOAuthProvider } from "@mariozechner/pi-ai/oauth";
15
15
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
16
16
  import { jsx } from "react/jsx-runtime";
17
+ import { jsx as jsx$1 } from "@opentui/react/jsx-runtime";
17
18
  //#region src/chat/agent-prompt.ts
18
19
  /**
19
20
  * Agent system-prompt fragments — composable doctrine for built-in profiles.
@@ -848,6 +849,43 @@ function shouldAutoCompact(input) {
848
849
  };
849
850
  }
850
851
  //#endregion
852
+ //#region src/chat/boot-profiler.ts
853
+ const enabled = !!process.env.ZIDANE_BOOT_PROFILE;
854
+ /**
855
+ * High-resolution origin for the running profile. Captured at module
856
+ * load time so the first {@link bootTick} call inside the same process
857
+ * reflects "time since the boot profiler was first reached", which for
858
+ * the standard `cli.ts → runTui` path is effectively "time since the
859
+ * TUI binary started executing user code".
860
+ */
861
+ const start = performance.now();
862
+ let last = start;
863
+ /**
864
+ * Record a checkpoint. No-op unless `ZIDANE_BOOT_PROFILE` is truthy in
865
+ * the environment.
866
+ *
867
+ * The leading delta is the time since the PREVIOUS tick (so a long
868
+ * delta highlights the immediately-preceding work); the trailing total
869
+ * is the time since the profiler started. Both round to one decimal of
870
+ * a millisecond.
871
+ */
872
+ function bootTick(label) {
873
+ if (!enabled) return;
874
+ const now = performance.now();
875
+ const delta = now - last;
876
+ const total = now - start;
877
+ last = now;
878
+ process.stderr.write(`[boot] +${delta.toFixed(1).padStart(7)}ms / total ${total.toFixed(1).padStart(7)}ms / ${label}\n`);
879
+ }
880
+ /**
881
+ * Returns `true` when `ZIDANE_BOOT_PROFILE` is set. Useful for guarding
882
+ * heavier instrumentation (e.g. wrapping a costly call in a span) that
883
+ * you don't want paying its own cost in the default path.
884
+ */
885
+ function bootProfileEnabled() {
886
+ return enabled;
887
+ }
888
+ //#endregion
851
889
  //#region src/chat/browser.ts
852
890
  /**
853
891
  * Best-effort cross-platform browser open.
@@ -887,6 +925,95 @@ function tryOpenBrowser(url) {
887
925
  } catch {}
888
926
  }
889
927
  //#endregion
928
+ //#region src/chat/color-gradient.ts
929
+ /** Parse `#rrggbb` (case-insensitive) into `[r, g, b]` 0–255 integers. */
930
+ function parseHex(hex) {
931
+ const h = hex.replace("#", "");
932
+ return [
933
+ Number.parseInt(h.slice(0, 2), 16),
934
+ Number.parseInt(h.slice(2, 4), 16),
935
+ Number.parseInt(h.slice(4, 6), 16)
936
+ ];
937
+ }
938
+ /** Convert sRGB 0–255 → HSL 0–1. */
939
+ function rgbToHsl(r, g, b) {
940
+ r /= 255;
941
+ g /= 255;
942
+ b /= 255;
943
+ const max = Math.max(r, g, b);
944
+ const min = Math.min(r, g, b);
945
+ const l = (max + min) / 2;
946
+ if (max === min) return [
947
+ 0,
948
+ 0,
949
+ l
950
+ ];
951
+ const d = max - min;
952
+ const s = l > .5 ? d / (2 - max - min) : d / (max + min);
953
+ let h;
954
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
955
+ else if (max === g) h = (b - r) / d + 2;
956
+ else h = (r - g) / d + 4;
957
+ return [
958
+ h / 6,
959
+ s,
960
+ l
961
+ ];
962
+ }
963
+ /** Convert HSL 0–1 → sRGB 0–255. Standard piecewise formula. */
964
+ function hslToRgb(h, s, l) {
965
+ if (s === 0) return [
966
+ l * 255,
967
+ l * 255,
968
+ l * 255
969
+ ];
970
+ const hue2rgb = (p, q, t) => {
971
+ if (t < 0) t += 1;
972
+ if (t > 1) t -= 1;
973
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
974
+ if (t < 1 / 2) return q;
975
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
976
+ return p;
977
+ };
978
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
979
+ const p = 2 * l - q;
980
+ return [
981
+ hue2rgb(p, q, h + 1 / 3) * 255,
982
+ hue2rgb(p, q, h) * 255,
983
+ hue2rgb(p, q, h - 1 / 3) * 255
984
+ ];
985
+ }
986
+ function toHex(rgb) {
987
+ const pad = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
988
+ return `#${pad(rgb[0])}${pad(rgb[1])}${pad(rgb[2])}`;
989
+ }
990
+ /**
991
+ * Blend two hex colors in HSL space with shortest-path hue interpolation.
992
+ * `t` ∈ [0, 1]; `t=0` returns `from`, `t=1` returns `to`.
993
+ */
994
+ function blendHsl(from, to, t) {
995
+ const [r1, g1, b1] = parseHex(from);
996
+ const [r2, g2, b2] = parseHex(to);
997
+ const [h1, s1, l1] = rgbToHsl(r1, g1, b1);
998
+ const [h2, s2, l2] = rgbToHsl(r2, g2, b2);
999
+ let dh = h2 - h1;
1000
+ if (dh > .5) dh -= 1;
1001
+ else if (dh < -.5) dh += 1;
1002
+ return toHex(hslToRgb((h1 + dh * t + 1) % 1, s1 + (s2 - s1) * t, l1 + (l2 - l1) * t));
1003
+ }
1004
+ /**
1005
+ * Static gradient ramp of length `n` going from `from` (index 0) to
1006
+ * `to` (index n-1) in HSL space. For the cycling A→B→A→B ramp the
1007
+ * throbber uses, see `buildCycleRamp` in `src/tui/crush-throbber.tsx`.
1008
+ */
1009
+ function buildLinearRamp(from, to, n) {
1010
+ if (n <= 0) return [];
1011
+ if (n === 1) return [blendHsl(from, to, .5)];
1012
+ const ramp = [];
1013
+ for (let i = 0; i < n; i++) ramp.push(blendHsl(from, to, i / (n - 1)));
1014
+ return ramp;
1015
+ }
1016
+ //#endregion
890
1017
  //#region src/chat/completion.ts
891
1018
  /**
892
1019
  * Prompt autocompletion framework.
@@ -1117,6 +1244,66 @@ const FILES_TRIGGER = "@";
1117
1244
  /** Cap on returned items. Keeps the popover compact + render-cheap. */
1118
1245
  const DEFAULT_RESULT_LIMIT = 50;
1119
1246
  /**
1247
+ * Rank-and-slice a file catalog against a query. Hoisted to a module
1248
+ * helper so both the sync and async branches of `suggest()` share one
1249
+ * implementation (the async branch hits this once the lazy directory
1250
+ * walk resolves; sync branch hits it on every keystroke thereafter).
1251
+ */
1252
+ function scoreFiles(catalog, query, limit) {
1253
+ const q = query.trim().toLowerCase();
1254
+ const scored = [];
1255
+ for (const file of catalog) {
1256
+ const name = file.name.toLowerCase();
1257
+ const path = file.path.toLowerCase();
1258
+ if (q.length === 0) {
1259
+ scored.push({
1260
+ entry: file,
1261
+ rank: 4
1262
+ });
1263
+ continue;
1264
+ }
1265
+ if (name === q) {
1266
+ scored.push({
1267
+ entry: file,
1268
+ rank: 0
1269
+ });
1270
+ continue;
1271
+ }
1272
+ if (name.startsWith(q)) {
1273
+ scored.push({
1274
+ entry: file,
1275
+ rank: 1
1276
+ });
1277
+ continue;
1278
+ }
1279
+ if (name.includes(q)) {
1280
+ scored.push({
1281
+ entry: file,
1282
+ rank: 2
1283
+ });
1284
+ continue;
1285
+ }
1286
+ if (path.includes(q)) {
1287
+ scored.push({
1288
+ entry: file,
1289
+ rank: 3
1290
+ });
1291
+ continue;
1292
+ }
1293
+ }
1294
+ scored.sort((a, b) => {
1295
+ if (a.rank !== b.rank) return a.rank - b.rank;
1296
+ return a.entry.path.localeCompare(b.entry.path);
1297
+ });
1298
+ return scored.slice(0, limit).map(({ entry }) => ({
1299
+ id: entry.path,
1300
+ label: entry.name,
1301
+ description: parentDir(entry.path),
1302
+ insertText: `@${entry.path} `,
1303
+ data: entry
1304
+ }));
1305
+ }
1306
+ /**
1120
1307
  * Build an `@`-prefixed files completion provider against a *live* catalog.
1121
1308
  *
1122
1309
  * The factory captures a getter so the catalog can be re-scanned (cwd
@@ -1136,59 +1323,11 @@ function createFilesCompletionProvider(opts) {
1136
1323
  trigger: "@",
1137
1324
  label: "Files",
1138
1325
  suggest(query) {
1139
- const catalog = opts.getCatalog();
1140
- const q = query.trim().toLowerCase();
1141
- const scored = [];
1142
- for (const file of catalog) {
1143
- const name = file.name.toLowerCase();
1144
- const path = file.path.toLowerCase();
1145
- if (q.length === 0) {
1146
- scored.push({
1147
- entry: file,
1148
- rank: 4
1149
- });
1150
- continue;
1151
- }
1152
- if (name === q) {
1153
- scored.push({
1154
- entry: file,
1155
- rank: 0
1156
- });
1157
- continue;
1158
- }
1159
- if (name.startsWith(q)) {
1160
- scored.push({
1161
- entry: file,
1162
- rank: 1
1163
- });
1164
- continue;
1165
- }
1166
- if (name.includes(q)) {
1167
- scored.push({
1168
- entry: file,
1169
- rank: 2
1170
- });
1171
- continue;
1172
- }
1173
- if (path.includes(q)) {
1174
- scored.push({
1175
- entry: file,
1176
- rank: 3
1177
- });
1178
- continue;
1179
- }
1326
+ if (opts.ensureCatalog) {
1327
+ const pending = opts.ensureCatalog();
1328
+ if (opts.getCatalog().length === 0) return pending.then((loaded) => scoreFiles(loaded, query, limit));
1180
1329
  }
1181
- scored.sort((a, b) => {
1182
- if (a.rank !== b.rank) return a.rank - b.rank;
1183
- return a.entry.path.localeCompare(b.entry.path);
1184
- });
1185
- return scored.slice(0, limit).map(({ entry }) => ({
1186
- id: entry.path,
1187
- label: entry.name,
1188
- description: parentDir(entry.path),
1189
- insertText: `@${entry.path} `,
1190
- data: entry
1191
- }));
1330
+ return scoreFiles(opts.getCatalog(), query, limit);
1192
1331
  },
1193
1332
  parseReferences(text, _ctx) {
1194
1333
  const catalog = opts.getCatalog();
@@ -1245,6 +1384,33 @@ const SKILLS_TRIGGER = "/";
1245
1384
  /** Valid skill-name shape (matches the parser): lowercase alnum + dashes. */
1246
1385
  const SKILL_NAME_RX = /^[a-z0-9][a-z0-9-]*$/;
1247
1386
  /**
1387
+ * Filter + rank visible skills against a query. Hoisted to a module
1388
+ * helper so the sync and async branches of `suggest()` share one
1389
+ * implementation (the async branch hits this once the lazy SKILL.md
1390
+ * scan resolves; sync branch hits it on every keystroke thereafter).
1391
+ */
1392
+ function scoreSkills(catalog, query) {
1393
+ const q = query.trim().toLowerCase();
1394
+ return catalog.filter((skill) => SKILL_NAME_RX.test(skill.name)).filter((skill) => {
1395
+ if (q.length === 0) return true;
1396
+ return skill.name.toLowerCase().includes(q) || skill.description.toLowerCase().includes(q);
1397
+ }).sort((a, b) => {
1398
+ const an = a.name.toLowerCase();
1399
+ const bn = b.name.toLowerCase();
1400
+ if (q) {
1401
+ const aPrefix = an.startsWith(q);
1402
+ if (aPrefix !== bn.startsWith(q)) return aPrefix ? -1 : 1;
1403
+ }
1404
+ return an.localeCompare(bn);
1405
+ }).map((skill) => ({
1406
+ id: skill.name,
1407
+ label: skill.name,
1408
+ description: skill.description,
1409
+ insertText: `/${skill.name} `,
1410
+ data: skill
1411
+ }));
1412
+ }
1413
+ /**
1248
1414
  * Build a slash-command completion provider against a *live* skills
1249
1415
  * catalog. The factory captures a getter so the catalog can change across
1250
1416
  * renders (toggles, reload) without re-instantiating the provider.
@@ -1265,25 +1431,11 @@ function createSkillsCompletionProvider(opts) {
1265
1431
  trigger: "/",
1266
1432
  label: "Skills",
1267
1433
  suggest(query) {
1268
- const q = query.trim().toLowerCase();
1269
- return visible().filter((skill) => SKILL_NAME_RX.test(skill.name)).filter((skill) => {
1270
- if (q.length === 0) return true;
1271
- return skill.name.toLowerCase().includes(q) || skill.description.toLowerCase().includes(q);
1272
- }).sort((a, b) => {
1273
- const an = a.name.toLowerCase();
1274
- const bn = b.name.toLowerCase();
1275
- if (q) {
1276
- const aPrefix = an.startsWith(q);
1277
- if (aPrefix !== bn.startsWith(q)) return aPrefix ? -1 : 1;
1278
- }
1279
- return an.localeCompare(bn);
1280
- }).map((skill) => ({
1281
- id: skill.name,
1282
- label: skill.name,
1283
- description: skill.description,
1284
- insertText: `/${skill.name} `,
1285
- data: skill
1286
- }));
1434
+ if (opts.ensureCatalog) {
1435
+ const pending = opts.ensureCatalog();
1436
+ if (opts.getCatalog().length === 0) return pending.then(() => scoreSkills(visible(), query));
1437
+ }
1438
+ return scoreSkills(visible(), query);
1287
1439
  },
1288
1440
  parseReferences(text, _ctx) {
1289
1441
  const catalog = visible();
@@ -2803,6 +2955,98 @@ function useConfig() {
2803
2955
  return ctx;
2804
2956
  }
2805
2957
  //#endregion
2958
+ //#region src/chat/discovery-context.tsx
2959
+ const DiscoveryContext = createContext(null);
2960
+ function DiscoveryProvider({ value, children }) {
2961
+ return /* @__PURE__ */ jsx$1(DiscoveryContext.Provider, {
2962
+ value,
2963
+ children
2964
+ });
2965
+ }
2966
+ /**
2967
+ * Read live discovery state + actions. Throws if used outside a
2968
+ * `<DiscoveryProvider>` — discovery is a load-bearing dependency for
2969
+ * settings + completion popovers; bailing loud here surfaces wiring
2970
+ * mistakes at mount instead of producing empty catalogs at first
2971
+ * keystroke.
2972
+ */
2973
+ function useDiscovery() {
2974
+ const ctx = useContext(DiscoveryContext);
2975
+ if (!ctx) throw new Error("useDiscovery must be used inside <DiscoveryProvider>");
2976
+ return ctx;
2977
+ }
2978
+ /**
2979
+ * Non-throwing variant — returns `null` when no provider is mounted.
2980
+ * Used by composable modals (`<SettingsModal>`, …) that accept catalog
2981
+ * props as a fallback for embedders who don't wire the full TUI
2982
+ * shell. The in-app flow always mounts `<DiscoveryProvider>` so the
2983
+ * modal sees live state; standalone embeds get the prop snapshot.
2984
+ */
2985
+ function useDiscoveryOptional() {
2986
+ return useContext(DiscoveryContext);
2987
+ }
2988
+ //#endregion
2989
+ //#region src/chat/discovery-slot.ts
2990
+ function createDiscoverySlot(options) {
2991
+ const throttleMs = options.throttleMs ?? 3e3;
2992
+ const abortCtrl = new AbortController();
2993
+ let firstLoad = null;
2994
+ let refreshing = null;
2995
+ let lastScannedAt = 0;
2996
+ let aborted = false;
2997
+ const handleError = (err, phase) => {
2998
+ options.onError?.(err, phase);
2999
+ };
3000
+ const startRefresh = () => {
3001
+ lastScannedAt = Date.now();
3002
+ const run = options.walk(abortCtrl.signal).then((items) => {
3003
+ if (aborted) return;
3004
+ options.onLoad(items);
3005
+ }).catch((err) => {
3006
+ if (aborted) return;
3007
+ handleError(err, "refresh");
3008
+ }).finally(() => {
3009
+ if (refreshing === run) refreshing = null;
3010
+ });
3011
+ refreshing = run;
3012
+ return run;
3013
+ };
3014
+ const slot = {
3015
+ ensure() {
3016
+ if (aborted) return Promise.resolve([]);
3017
+ if (!firstLoad) {
3018
+ lastScannedAt = Date.now();
3019
+ firstLoad = options.walk(abortCtrl.signal).then((items) => {
3020
+ if (aborted) return [];
3021
+ options.onLoad(items);
3022
+ return items;
3023
+ }).catch((err) => {
3024
+ if (!aborted) handleError(err, "first-load");
3025
+ return [];
3026
+ });
3027
+ return firstLoad;
3028
+ }
3029
+ if (!refreshing && Date.now() - lastScannedAt >= throttleMs) startRefresh();
3030
+ return firstLoad;
3031
+ },
3032
+ refresh() {
3033
+ if (aborted) return Promise.resolve();
3034
+ if (refreshing) return refreshing;
3035
+ if (!firstLoad) return slot.ensure().then(() => {});
3036
+ return startRefresh();
3037
+ },
3038
+ isRefreshing() {
3039
+ return refreshing !== null;
3040
+ },
3041
+ abort() {
3042
+ if (aborted) return;
3043
+ aborted = true;
3044
+ abortCtrl.abort();
3045
+ }
3046
+ };
3047
+ return slot;
3048
+ }
3049
+ //#endregion
2806
3050
  //#region src/chat/themes/catppuccin.ts
2807
3051
  const LATTE = {
2808
3052
  rosewater: "#dc8a78",
@@ -4250,6 +4494,65 @@ function clip(text, max) {
4250
4494
  return text.length > max ? `${text.slice(0, max)}…` : text;
4251
4495
  }
4252
4496
  //#endregion
4497
+ //#region src/chat/hints.ts
4498
+ /**
4499
+ * Truncate `text` to at most `max` characters, replacing the trailing
4500
+ * overflow with `…`. Edge cases:
4501
+ * - `max <= 0` → empty string (no room to render at all).
4502
+ * - `max === 1` → just the ellipsis glyph.
4503
+ * - `text.length <= max` → unchanged.
4504
+ *
4505
+ * Trailing-style truncation matches the natural read order of titles:
4506
+ * the prefix carries enough signal to identify the surface.
4507
+ */
4508
+ function truncateTrailing(text, max) {
4509
+ if (max <= 0) return "";
4510
+ if (text.length <= max) return text;
4511
+ if (max === 1) return "…";
4512
+ return `${text.slice(0, max - 1)}…`;
4513
+ }
4514
+ /**
4515
+ * Plain-text width estimate for a list of {@link Hint}s rendered as
4516
+ * `<key> <label> · <key> <label> · …`. Exported so prompt-box overlays
4517
+ * can run the same responsive math as the bottom-bar footer when
4518
+ * deciding whether trigger hints fit. Pure / total.
4519
+ */
4520
+ function hintsLength(hints) {
4521
+ if (hints.length === 0) return 0;
4522
+ return hints.reduce((sum, h, i) => sum + hintLength(h) + (i > 0 ? 3 : 0), 0);
4523
+ }
4524
+ /** Plain-text width of a single hint as rendered by `renderHintSpans`. */
4525
+ function hintLength(h) {
4526
+ return h.key.length + 1 + h.label.length + (h.extra ? h.extra.key.length + 1 + h.extra.label.length : 0);
4527
+ }
4528
+ /** Stable empty list so callers can compare by reference. */
4529
+ const EMPTY_HINTS = Object.freeze([]);
4530
+ /**
4531
+ * Return the longest prefix of `hints` whose rendered width fits within
4532
+ * `budget`. Used to degrade hint rows gracefully at narrow terminal
4533
+ * widths instead of letting an absolutely-positioned hint row wrap
4534
+ * mid-segment (which paints the overflow over surrounding borders and
4535
+ * looks like garbled glyphs in a TUI).
4536
+ *
4537
+ * Prefix-only (no reordering, no last-hint priority) so the survivors
4538
+ * keep their authored order — the user's muscle memory for "leftmost
4539
+ * hint = primary action" stays intact as the terminal shrinks.
4540
+ */
4541
+ function clipHintsToWidth(hints, budget) {
4542
+ if (budget <= 0 || hints.length === 0) return EMPTY_HINTS;
4543
+ const out = [];
4544
+ let used = 0;
4545
+ for (let i = 0; i < hints.length; i++) {
4546
+ const h = hints[i];
4547
+ const cost = (i > 0 ? 3 : 0) + hintLength(h);
4548
+ if (used + cost > budget) break;
4549
+ out.push(h);
4550
+ used += cost;
4551
+ }
4552
+ if (out.length === 0) return EMPTY_HINTS;
4553
+ return out.length === hints.length ? hints : out;
4554
+ }
4555
+ //#endregion
4253
4556
  //#region src/chat/interactions.tsx
4254
4557
  const PRESENT_PLAN_TOOL = "present_plan";
4255
4558
  const ASK_USER_TOOL = "ask_user";
@@ -4717,6 +5020,79 @@ function makeRequestInteraction(actions) {
4717
5020
  });
4718
5021
  }
4719
5022
  //#endregion
5023
+ //#region src/chat/markdown-segments.ts
5024
+ /**
5025
+ * Split markdown text into alternating prose / fenced-code segments.
5026
+ *
5027
+ * Recognizes both ` ``` ` and `~~~` fences, with arbitrary length ≥ 3,
5028
+ * matching CommonMark's "fence indicator must be at least as long to
5029
+ * close" rule. Info-strings (the bit after the opening fence) are kept
5030
+ * as the `lang` hint; any trailing whitespace is trimmed. Closing
5031
+ * fences are detected on a line of their own (whitespace tolerated).
5032
+ *
5033
+ * Unclosed fences fall back to emitting the would-be-code body as a
5034
+ * trailing prose segment so no content is dropped — finalized markdown
5035
+ * isn't expected to ship one, but the fallback keeps the renderer
5036
+ * truthful when the model produces malformed output.
5037
+ *
5038
+ * Exported for unit tests.
5039
+ */
5040
+ function splitMarkdownCodeBlocks(text) {
5041
+ const lines = text.split("\n");
5042
+ const segments = [];
5043
+ let prose = [];
5044
+ let code = [];
5045
+ let inFence = false;
5046
+ let fenceChar = "";
5047
+ let fenceLen = 0;
5048
+ let lang = "";
5049
+ const flushProse = () => {
5050
+ if (prose.length > 0 && prose[prose.length - 1] === "") prose.pop();
5051
+ if (prose.length > 0) {
5052
+ segments.push({
5053
+ kind: "prose",
5054
+ content: prose.join("\n")
5055
+ });
5056
+ prose = [];
5057
+ }
5058
+ };
5059
+ let trimLeadingProseBlank = false;
5060
+ for (const line of lines) if (!inFence) {
5061
+ const open = line.match(/^(`{3,}|~{3,})([^\n`~]*)$/);
5062
+ if (open) {
5063
+ flushProse();
5064
+ inFence = true;
5065
+ fenceChar = open[1][0];
5066
+ fenceLen = open[1].length;
5067
+ lang = open[2].trim();
5068
+ code = [];
5069
+ continue;
5070
+ }
5071
+ if (trimLeadingProseBlank) {
5072
+ trimLeadingProseBlank = false;
5073
+ if (line === "" && prose.length === 0) continue;
5074
+ }
5075
+ prose.push(line);
5076
+ } else {
5077
+ const close = line.match(/^(`{3,}|~{3,})\s*$/);
5078
+ if (close && close[1][0] === fenceChar && close[1].length >= fenceLen) {
5079
+ segments.push({
5080
+ kind: "code",
5081
+ content: code.join("\n"),
5082
+ lang
5083
+ });
5084
+ inFence = false;
5085
+ code = [];
5086
+ trimLeadingProseBlank = true;
5087
+ continue;
5088
+ }
5089
+ code.push(line);
5090
+ }
5091
+ if (inFence) prose.push(`${fenceChar.repeat(fenceLen)}${lang}`, ...code);
5092
+ flushProse();
5093
+ return segments;
5094
+ }
5095
+ //#endregion
4720
5096
  //#region src/chat/mcp-auth-state.ts
4721
5097
  /**
4722
5098
  * Apply one event to the state map. Pure, immutable — returns a new map
@@ -6040,6 +6416,19 @@ function useStreamBuffer(setEvents, options) {
6040
6416
  const tickerRef = useRef(null);
6041
6417
  const getSmoothRef = useRef(options?.getSmooth);
6042
6418
  getSmoothRef.current = options?.getSmooth;
6419
+ /**
6420
+ * Updaters queued while smooth-streaming was still draining backlog —
6421
+ * tool-call appends, finalize-markdown transforms, error events.
6422
+ * Applied in FIFO order at the END of `tick()` once every bucket is
6423
+ * empty, so the trailing typewriter characters land BEFORE the
6424
+ * follow-up event instead of being clobbered by an immediate drain.
6425
+ *
6426
+ * The buffer treats markdown deltas as the authoritative ordering
6427
+ * source: a tool call queued behind 100 buffered chars surfaces after
6428
+ * those 100 chars have typed out, preserving the visual stream order
6429
+ * the user is reading.
6430
+ */
6431
+ const pendingUpdatersRef = useRef([]);
6043
6432
  const stopTicker = useCallback(() => {
6044
6433
  if (tickerRef.current) {
6045
6434
  clearInterval(tickerRef.current);
@@ -6047,27 +6436,45 @@ function useStreamBuffer(setEvents, options) {
6047
6436
  }
6048
6437
  }, []);
6049
6438
  /**
6050
- * Drain every bucket in full and stop the ticker. Used for turn-boundary
6051
- * commits (`flush` / `appendImmediate` / `flushAndUpdate`) and teardown
6052
- * (`reset`). The accompanying `updater` (when provided) runs against the
6053
- * post-drain event list so consumers can append a synchronous event or
6054
- * apply a transform in the same `setEvents` call.
6439
+ * Has at least one bucket got unflushed *markdown* content?
6440
+ *
6441
+ * Thinking content is excluded: it always flushes in full on every
6442
+ * tick (see `tick()`), so its presence in a bucket only matters until
6443
+ * the next 16 ms cycle never long enough to justify deferring an
6444
+ * end-of-turn updater.
6055
6445
  */
6056
- const drainAll = useCallback((updater) => {
6446
+ const hasMarkdownBacklog = useCallback(() => {
6447
+ for (const bucket of bucketsRef.current.values()) if (bucket.markdown.length > 0) return true;
6448
+ return false;
6449
+ }, []);
6450
+ /**
6451
+ * Drain every bucket in full and synchronously run any queued
6452
+ * post-drain updaters plus the caller-provided one. Used by the
6453
+ * fast paths below — `reset`, batched-mode `appendImmediate` /
6454
+ * `flushAndUpdate`, and smooth-mode calls where no markdown
6455
+ * backlog remains.
6456
+ */
6457
+ const drainNow = useCallback((updater) => {
6057
6458
  stopTicker();
6058
6459
  const buckets = Array.from(bucketsRef.current.values());
6059
6460
  bucketsRef.current.clear();
6060
- if (!buckets.some((b) => b.markdown.length > 0 || b.thinking.length > 0) && !updater) return;
6461
+ const queued = pendingUpdatersRef.current;
6462
+ pendingUpdatersRef.current = [];
6463
+ if (!buckets.some((b) => b.markdown.length > 0 || b.thinking.length > 0) && !updater && queued.length === 0) return;
6061
6464
  setEvents((prev) => {
6062
6465
  let merged = prev;
6063
6466
  for (const bucket of buckets) merged = applyBucket(merged, bucket);
6064
- return updater ? updater(merged) : merged;
6467
+ for (const u of queued) merged = u(merged);
6468
+ if (updater) merged = updater(merged);
6469
+ return merged;
6065
6470
  });
6066
6471
  }, [setEvents, stopTicker]);
6067
6472
  /**
6068
6473
  * One tick of the continuous drain loop. Walks every live bucket and
6069
- * commits a portion of its content based on the current mode. Stops the
6070
- * ticker once every bucket is empty.
6474
+ * commits a portion of its content based on the current mode. Once
6475
+ * every bucket empties out, fires any post-drain updaters that were
6476
+ * queued while smooth streaming was still in progress (turn
6477
+ * finalize, tool calls, errors) and stops the ticker.
6071
6478
  *
6072
6479
  * `thinking` content always flushes immediately even in smooth mode —
6073
6480
  * it's an internal-reasoning surface, surfaced for transparency rather
@@ -6100,9 +6507,11 @@ function useStreamBuffer(setEvents, options) {
6100
6507
  });
6101
6508
  if (bucket.markdown.length > 0) stillHasContent = true;
6102
6509
  }
6103
- if (portions.length > 0) setEvents((prev) => {
6510
+ const queued = !stillHasContent && pendingUpdatersRef.current.length > 0 ? pendingUpdatersRef.current.splice(0, pendingUpdatersRef.current.length) : [];
6511
+ if (portions.length > 0 || queued.length > 0) setEvents((prev) => {
6104
6512
  let next = prev;
6105
6513
  for (const portion of portions) next = applyBucket(next, portion);
6514
+ for (const u of queued) next = u(next);
6106
6515
  return next;
6107
6516
  });
6108
6517
  if (!stillHasContent) stopTicker();
@@ -6111,9 +6520,40 @@ function useStreamBuffer(setEvents, options) {
6111
6520
  if (tickerRef.current) return;
6112
6521
  tickerRef.current = setInterval(tick, TICK_INTERVAL_MS);
6113
6522
  }, [tick]);
6114
- const flush = useCallback(() => drainAll(), [drainAll]);
6115
- const flushAndUpdate = useCallback((update) => drainAll(update), [drainAll]);
6116
- const appendImmediate = useCallback((evt) => drainAll((events) => [...events, evt]), [drainAll]);
6523
+ /**
6524
+ * Decide between fast-drain and deferred-drain for an
6525
+ * updater-bearing call (`appendImmediate`, `flushAndUpdate`).
6526
+ *
6527
+ * Smooth mode + markdown backlog → ENQUEUE the updater behind the
6528
+ * trailing characters; the ticker picks it up once buckets empty.
6529
+ * Anything else → fall through to `drainNow` so the call retains
6530
+ * its synchronous semantics.
6531
+ */
6532
+ const drainOrDefer = useCallback((updater) => {
6533
+ if ((getSmoothRef.current?.() ?? true) && hasMarkdownBacklog()) {
6534
+ pendingUpdatersRef.current.push(updater);
6535
+ ensureTicker();
6536
+ return;
6537
+ }
6538
+ drainNow(updater);
6539
+ }, [
6540
+ drainNow,
6541
+ ensureTicker,
6542
+ hasMarkdownBacklog
6543
+ ]);
6544
+ const flush = useCallback(() => {
6545
+ if ((getSmoothRef.current?.() ?? true) && hasMarkdownBacklog()) {
6546
+ ensureTicker();
6547
+ return;
6548
+ }
6549
+ drainNow();
6550
+ }, [
6551
+ drainNow,
6552
+ ensureTicker,
6553
+ hasMarkdownBacklog
6554
+ ]);
6555
+ const flushAndUpdate = useCallback((update) => drainOrDefer(update), [drainOrDefer]);
6556
+ const appendImmediate = useCallback((evt) => drainOrDefer((events) => [...events, evt]), [drainOrDefer]);
6117
6557
  const queueStreamDelta = useCallback((kind, delta, source) => {
6118
6558
  if (!delta) return;
6119
6559
  const owner = source?.childId ?? PARENT_OWNER;
@@ -6130,6 +6570,7 @@ function useStreamBuffer(setEvents, options) {
6130
6570
  const reset = useCallback(() => {
6131
6571
  stopTicker();
6132
6572
  bucketsRef.current.clear();
6573
+ pendingUpdatersRef.current = [];
6133
6574
  }, [stopTicker]);
6134
6575
  return useMemo(() => ({
6135
6576
  queueStreamDelta,
@@ -6422,6 +6863,46 @@ function formatBytes(bytes) {
6422
6863
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6423
6864
  }
6424
6865
  //#endregion
6866
+ //#region src/chat/transcript-anchors.ts
6867
+ /**
6868
+ * Per-item anchor ids for auto-scroll. Walks `items` in render order
6869
+ * and, for each event, returns either:
6870
+ * - `'turn-anchor-<turnId>'` — the first event of this turn (the
6871
+ * scroll target).
6872
+ * - `undefined` — later event of an already-tagged turn (or a
6873
+ * synthetic event with no `turnId`).
6874
+ *
6875
+ * `ids[i]` is a tuple per item: length 1 for plain events, length N
6876
+ * for subagent runs (one entry per inner event). `idByTurn` is the
6877
+ * inverse lookup used by the scroll effect. `lastTurnId` is the
6878
+ * most-recently-rendered turn — the scroll effect special-cases it to
6879
+ * snap to bottom rather than scroll the anchor into view (which would
6880
+ * stop short of the actual tail).
6881
+ *
6882
+ * Exported so the anchor-tagging matrix can be unit-tested without
6883
+ * rendering anything.
6884
+ */
6885
+ function computeTurnAnchors(items) {
6886
+ const idByTurn = /* @__PURE__ */ new Map();
6887
+ let lastTurnId;
6888
+ const tag = (turnId) => {
6889
+ if (!turnId) return void 0;
6890
+ lastTurnId = turnId;
6891
+ if (idByTurn.has(turnId)) return void 0;
6892
+ const id = `turn-anchor-${turnId}`;
6893
+ idByTurn.set(turnId, id);
6894
+ return id;
6895
+ };
6896
+ const ids = [];
6897
+ for (const item of items) if (item.kind === "event") ids.push([tag(item.event.turnId)]);
6898
+ else ids.push(item.events.map((e) => tag(e.turnId)));
6899
+ return {
6900
+ idByTurn,
6901
+ ids,
6902
+ lastTurnId
6903
+ };
6904
+ }
6905
+ //#endregion
6425
6906
  //#region src/chat/turn-operations.ts
6426
6907
  /**
6427
6908
  * Fork — keep every turn up to and including `turnId`, then strip any
@@ -6537,6 +7018,6 @@ function countNeighbors(turnIds, turnId) {
6537
7018
  };
6538
7019
  }
6539
7020
  //#endregion
6540
- export { getMcpAuthStatus as $, openrouterDescriptor as $n, toolCallPreview as $t, isOnSafelist as A, mergeReferences as An, VAPORWAVE_THEME as At, filterModelCatalog as B, setProviderCredential as Bn, eventsFromTurns as Bt, writeSessionExport as C, uniqueSkillNamesFromReferences as Cn, SettingsProvider as Ct, IMPLICITLY_SAFE_TOOLS as D, applyInsert as Dn, DEFAULT_THEME as Dt, useSafeModeQueue as E, uniqueFilesFromReferences as En, BUILTIN_THEMES as Et, writeProjects as F, applyApiKeyEnv as Fn, ConfigProvider as Ft, parseMcpsFile as G, cerebrasDescriptor as Gn, listSessionMeta as Gt, buildMcpServers as H, BUILTIN_PROVIDERS as Hn, isTurnHighlighted as Ht, splitPromptSegments as I, credentialsPath as In, useConfig as It, mcpCredentialsPath as J, getContextWindow as Jn, saveState as Jt, projectUserPaths as K, credKeyOf as Kn, loadState as Kt, runOAuthLogin as L, readCredentials as Ln, resolveConfig as Lt, projectsFilePath as M, tryOpenBrowser as Mn, CATPPUCCIN_LATTE as Mt, readProjects as N, shouldAutoCompact as Nn, CATPPUCCIN_MACCHIATO as Nt, addToSafelist as O, collectReferences as On, resolveChipColor as Ot, suggestSafelistEntry as P, detectAuth as Pn, CATPPUCCIN_MOCHA as Pt, useMcpAuthState as Q, openaiDescriptor as Qn, titleFromTurns as Qt, supportsOAuth as R, readProviderCredential as Rn, createStateStore as Rt, resolveSessionExportTarget as S, createSkillsCompletionProvider as Sn, SETTINGS_TOGGLES as St, useSafeModeActions as T, createFilesCompletionProvider as Tn, useSettings as Tt, defaultMcpsConfigPaths as U, OUTPUT_RESERVE_TOKENS as Un, isVisible as Ut, indexOfEntry as V, writeCredentials as Vn, isEditErrorResult as Vt, discoverProjectMcps as W, anthropicDescriptor as Wn, lastContextSizeFromTurns as Wt, McpAuthProvider as X, modelSupportsReasoning as Xn, stripSpawnTokensLine as Xt, patchMcpCredential as Y, getModelInfo as Yn, selectableTurnIds as Yt, useMcpAuthDispatch as Z, modelsForDescriptor as Zn, sumRunCosts as Zt, useStreamBuffer as _, mergeKeybindings as _n, SUBAGENT_GUIDANCE as _r, shortId as _t, TOOL_DISPLAY as a, computeLineDiff as an, PLAN_AGENT as ar, createInteractionTools as at, discoverProjectSkills as b, stripJsonComments as bn, buildPlanSystem as br, DEFAULT_SETTINGS as bt, ThemeProvider as c, splitLines as cn, singleAgentRegistry as cr, pendingInteractionsFromTurns as ct, useSurfaces as d, DEFAULT_KEYBINDINGS as dn, DOING_TASKS_DOCTRINE as dr, useInteractionsQueue as dt, toolResultText as en, piIdOf as er, reduceMcpAuth as et, useSyntaxStyles as f, KEYBINDING_DEFS as fn, IDENTITY_PREFIX as fr, cleanTitle as ft, turnContextSize as g, matchesBinding as gn, PLAN_MODE_DOCTRINE_NO_PROMPTS as gr, fmtTokens as gt, finalizeStreamingMarkdownForOwner as h, keybindingsPath as hn, PLAN_MODE_DOCTRINE as hr, compactPath as ht, turnAsText as i, computeInlineDiff as in, DEFAULT_PERSIST_EXCLUDE_TOOLS as ir, buildResumedToolResultsTurn as it, matchesSafelistEntry as j, useCompletion as jn, CATPPUCCIN_FRAPPE as jt, getSafelist as k, findActiveTrigger as kn, resolveTheme as kt, useColors as l, tokenize as ln, ACTIONS_WITH_CARE_DOCTRINE as lr, serializeInteractionResponse as lt, finalizeStreamingMarkdown as m, ensureKeybindingsFile as mn, INTERACTION_GUIDANCE_NO_PROMPTS as mr, ageString as mt, deleteTurnSafely as n, buildContextualDiff as nn, BUILTIN_AGENTS as nr, InteractionsProvider as nt, displayNameFor as o, extractEditPayload as on, accentColor as or, isInteractionTool as ot, useTheme as p, KEYBINDING_DEF_BY_ACTION as pn, INTERACTION_GUIDANCE as pr, generateSessionTitle as pt, createFileMcpCredentialStore as q, effectiveContextWindow as qn, marginTopFor as qt, truncateTurnsAt as r, buildUnifiedDiff as rn, DEFAULT_AGENT_ID as rr, PRESENT_PLAN_TOOL as rt, formatToolCall as s, filetypeFromPath as sn, resolveAgentId as sr, makeRequestInteraction as st, countNeighbors as t, turnSelectionOwnership as tn, BUILD_AGENT as tr, ASK_USER_TOOL as tt, useSelectStyle as u, findGitRoot$1 as un, COMMUNICATION_DOCTRINE as ur, useInteractionsActions as ut, buildSkillsConfig as v, parseBindingSpec as vn, TOKEN_DISCIPLINE_DOCTRINE as vr, listProjectFiles as vt, SafeModeProvider as w, FILES_TRIGGER as wn, clampFps as wt, renderSession as x, SKILLS_TRIGGER as xn, envSection as xr, SETTINGS_CHOICES as xt, defaultSkillScanPaths as y, readKeybindings as yn, buildBuildSystem as yr, useEnabledToggleSet as yt, buildModelCatalog as z, removeProviderCredential as zn, deriveSessionTitle as zt };
7021
+ export { useMcpAuthState as $, setProviderCredential as $n, lastContextSizeFromTurns as $t, getSafelist as A, SKILLS_TRIGGER as An, SUBAGENT_GUIDANCE as Ar, useSettings as At, buildModelCatalog as B, useCompletion as Bn, createDiscoverySlot as Bt, resolveSessionExportTarget as C, ensureKeybindingsFile as Cn, COMMUNICATION_DOCTRINE as Cr, listProjectFiles as Ct, useSafeModeQueue as D, parseBindingSpec as Dn, INTERACTION_GUIDANCE_NO_PROMPTS as Dr, SETTINGS_TOGGLES as Dt, useSafeModeActions as E, mergeKeybindings as En, INTERACTION_GUIDANCE as Er, SETTINGS_CHOICES as Et, suggestSafelistEntry as F, uniqueFilesFromReferences as Fn, VAPORWAVE_THEME as Ft, discoverProjectMcps as G, bootTick as Gn, useConfig as Gt, indexOfEntry as H, buildLinearRamp as Hn, useDiscovery as Ht, writeProjects as I, applyInsert as In, CATPPUCCIN_FRAPPE as It, createFileMcpCredentialStore as J, applyApiKeyEnv as Jn, deriveSessionTitle as Jt, parseMcpsFile as K, shouldAutoCompact as Kn, resolveConfig as Kt, splitPromptSegments as L, collectReferences as Ln, CATPPUCCIN_LATTE as Lt, matchesSafelistEntry as M, uniqueSkillNamesFromReferences as Mn, buildBuildSystem as Mr, DEFAULT_THEME as Mt, projectsFilePath as N, FILES_TRIGGER as Nn, buildPlanSystem as Nr, resolveChipColor as Nt, IMPLICITLY_SAFE_TOOLS as O, readKeybindings as On, PLAN_MODE_DOCTRINE as Or, SettingsProvider as Ot, readProjects as P, createFilesCompletionProvider as Pn, envSection as Pr, resolveTheme as Pt, useMcpAuthDispatch as Q, removeProviderCredential as Qn, isVisible as Qt, runOAuthLogin as R, findActiveTrigger as Rn, CATPPUCCIN_MACCHIATO as Rt, renderSession as S, KEYBINDING_DEF_BY_ACTION as Sn, ACTIONS_WITH_CARE_DOCTRINE as Sr, shortId as St, SafeModeProvider as T, matchesBinding as Tn, IDENTITY_PREFIX as Tr, DEFAULT_SETTINGS as Tt, buildMcpServers as U, tryOpenBrowser as Un, useDiscoveryOptional as Ut, filterModelCatalog as V, blendHsl as Vn, DiscoveryProvider as Vt, defaultMcpsConfigPaths as W, bootProfileEnabled as Wn, ConfigProvider as Wt, patchMcpCredential as X, readCredentials as Xn, isEditErrorResult as Xt, mcpCredentialsPath as Y, credentialsPath as Yn, eventsFromTurns as Yt, McpAuthProvider as Z, readProviderCredential as Zn, isTurnHighlighted as Zt, turnContextSize as _, splitLines as _n, DEFAULT_PERSIST_EXCLUDE_TOOLS as _r, cleanTitle as _t, computeTurnAnchors as a, stripSpawnTokensLine as an, credKeyOf as ar, PRESENT_PLAN_TOOL as at, defaultSkillScanPaths as b, DEFAULT_KEYBINDINGS as bn, resolveAgentId as br, compactPath as bt, formatToolCall as c, toolCallPreview as cn, getModelInfo as cr, isInteractionTool as ct, useSelectStyle as d, buildContextualDiff as dn, openaiDescriptor as dr, serializeInteractionResponse as dt, listSessionMeta as en, writeCredentials as er, getMcpAuthStatus as et, useSurfaces as f, buildUnifiedDiff as fn, openrouterDescriptor as fr, useInteractionsActions as ft, finalizeStreamingMarkdownForOwner as g, filetypeFromPath as gn, DEFAULT_AGENT_ID as gr, truncateTrailing as gt, finalizeStreamingMarkdown as h, extractEditPayload as hn, BUILTIN_AGENTS as hr, hintsLength as ht, turnAsText as i, selectableTurnIds as in, cerebrasDescriptor as ir, InteractionsProvider as it, isOnSafelist as j, createSkillsCompletionProvider as jn, TOKEN_DISCIPLINE_DOCTRINE as jr, BUILTIN_THEMES as jt, addToSafelist as k, stripJsonComments as kn, PLAN_MODE_DOCTRINE_NO_PROMPTS as kr, clampFps as kt, ThemeProvider as l, toolResultText as ln, modelSupportsReasoning as lr, makeRequestInteraction as lt, useTheme as m, computeLineDiff as mn, BUILD_AGENT as mr, clipHintsToWidth as mt, deleteTurnSafely as n, marginTopFor as nn, OUTPUT_RESERVE_TOKENS as nr, splitMarkdownCodeBlocks as nt, TOOL_DISPLAY as o, sumRunCosts as on, effectiveContextWindow as or, buildResumedToolResultsTurn as ot, useSyntaxStyles as p, computeInlineDiff as pn, piIdOf as pr, useInteractionsQueue as pt, projectUserPaths as q, detectAuth as qn, createStateStore as qt, truncateTurnsAt as r, saveState as rn, anthropicDescriptor as rr, ASK_USER_TOOL as rt, displayNameFor as s, titleFromTurns as sn, getContextWindow as sr, createInteractionTools as st, countNeighbors as t, loadState as tn, BUILTIN_PROVIDERS as tr, reduceMcpAuth as tt, useColors as u, turnSelectionOwnership as un, modelsForDescriptor as ur, pendingInteractionsFromTurns as ut, useStreamBuffer as v, tokenize as vn, PLAN_AGENT as vr, generateSessionTitle as vt, writeSessionExport as w, keybindingsPath as wn, DOING_TASKS_DOCTRINE as wr, useEnabledToggleSet as wt, discoverProjectSkills as x, KEYBINDING_DEFS as xn, singleAgentRegistry as xr, fmtTokens as xt, buildSkillsConfig as y, findGitRoot$1 as yn, accentColor as yr, ageString as yt, supportsOAuth as z, mergeReferences as zn, CATPPUCCIN_MOCHA as zt };
6541
7022
 
6542
- //# sourceMappingURL=turn-operations-CDmQ2h-T.js.map
7023
+ //# sourceMappingURL=turn-operations-CeLlc7jt.js.map