zidane 5.4.2 → 5.5.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 (86) hide show
  1. package/README.md +45 -1
  2. package/dist/{agent-DxBoKDba.d.ts → agent-CvImMxMQ.d.ts} +256 -5
  3. package/dist/agent-CvImMxMQ.d.ts.map +1 -0
  4. package/dist/chat.d.ts +137 -16
  5. package/dist/chat.d.ts.map +1 -1
  6. package/dist/chat.js +3 -2
  7. package/dist/contexts/docker.d.ts +1 -1
  8. package/dist/contexts-DhmMlT2W.js +472 -0
  9. package/dist/contexts-DhmMlT2W.js.map +1 -0
  10. package/dist/contexts.d.ts +3 -3
  11. package/dist/contexts.js +1 -1
  12. package/dist/{errors-Byb0F8B9.js → errors-CDwtPIMX.js} +4 -2
  13. package/dist/{errors-Byb0F8B9.js.map → errors-CDwtPIMX.js.map} +1 -1
  14. package/dist/{index-BOtXdQkW.d.ts → index-B0uc2C5x.d.ts} +9 -3
  15. package/dist/index-B0uc2C5x.d.ts.map +1 -0
  16. package/dist/{index-BiO_5Hm4.d.ts → index-CbS75MD3.d.ts} +2 -2
  17. package/dist/index-CbS75MD3.d.ts.map +1 -0
  18. package/dist/{index-B2VOOijU.d.ts → index-CtXksgqb.d.ts} +73 -4
  19. package/dist/index-CtXksgqb.d.ts.map +1 -0
  20. package/dist/index.d.ts +6 -6
  21. package/dist/index.js +11 -11
  22. package/dist/{interpolate-ERgZUxgg.js → interpolate-BaaKaKzN.js} +156 -19
  23. package/dist/interpolate-BaaKaKzN.js.map +1 -0
  24. package/dist/{login-CJbeAadS.js → login-iTy-0wYz.js} +3 -3
  25. package/dist/{login-CJbeAadS.js.map → login-iTy-0wYz.js.map} +1 -1
  26. package/dist/{mcp-DhmmJfxK.js → mcp-CNUbvbsy.js} +2 -2
  27. package/dist/{mcp-DhmmJfxK.js.map → mcp-CNUbvbsy.js.map} +1 -1
  28. package/dist/mcp.d.ts +1 -1
  29. package/dist/mcp.js +1 -1
  30. package/dist/{messages-D0xT979U.js → messages-fTR19Ga6.js} +2 -2
  31. package/dist/{messages-D0xT979U.js.map → messages-fTR19Ga6.js.map} +1 -1
  32. package/dist/{presets-MCcvxiNT.js → presets-h6UWhghO.js} +3 -2
  33. package/dist/presets-h6UWhghO.js.map +1 -0
  34. package/dist/presets.d.ts +2 -2
  35. package/dist/presets.js +1 -1
  36. package/dist/{providers-x3LZByR5.js → providers-G0VBZK9j.js} +4 -4
  37. package/dist/{providers-x3LZByR5.js.map → providers-G0VBZK9j.js.map} +1 -1
  38. package/dist/providers.d.ts +1 -1
  39. package/dist/providers.js +2 -2
  40. package/dist/session/sqlite.d.ts +1 -1
  41. package/dist/session/sqlite.d.ts.map +1 -1
  42. package/dist/session/sqlite.js +2 -1
  43. package/dist/session/sqlite.js.map +1 -1
  44. package/dist/{session-BHZwxmfr.js → session-CbkiJDlH.js} +3 -2
  45. package/dist/session-CbkiJDlH.js.map +1 -0
  46. package/dist/session.d.ts +1 -1
  47. package/dist/session.js +2 -2
  48. package/dist/skills.d.ts +2 -2
  49. package/dist/skills.js +1 -1
  50. package/dist/{tools-BNfyY14s.js → tools-D_icxa-V.js} +813 -284
  51. package/dist/tools-D_icxa-V.js.map +1 -0
  52. package/dist/tools.d.ts +3 -3
  53. package/dist/tools.js +2 -2
  54. package/dist/{transcript-anchors-DonKvoh4.d.ts → transcript-anchors-3FFw2xuk.d.ts} +98 -15
  55. package/dist/transcript-anchors-3FFw2xuk.d.ts.map +1 -0
  56. package/dist/tui.d.ts +29 -5
  57. package/dist/tui.d.ts.map +1 -1
  58. package/dist/tui.js +879 -70
  59. package/dist/tui.js.map +1 -1
  60. package/dist/{turn-operations-TKvy0q29.js → turn-operations-CtgBlBHn.js} +412 -125
  61. package/dist/turn-operations-CtgBlBHn.js.map +1 -0
  62. package/dist/types-IcokUOyC.js.map +1 -1
  63. package/dist/types-KukEp-mi.d.ts +253 -0
  64. package/dist/types-KukEp-mi.d.ts.map +1 -0
  65. package/dist/types.d.ts +4 -4
  66. package/dist/types.js +1 -1
  67. package/docs/ARCHITECTURE.md +37 -3
  68. package/docs/CHAT.md +4 -2
  69. package/docs/RUN_IN_BACKGROUND.md +612 -0
  70. package/docs/SKILL.md +83 -14
  71. package/docs/TUI.md +40 -2
  72. package/package.json +4 -4
  73. package/dist/agent-DxBoKDba.d.ts.map +0 -1
  74. package/dist/contexts-BwiHIr2w.js +0 -129
  75. package/dist/contexts-BwiHIr2w.js.map +0 -1
  76. package/dist/index-B2VOOijU.d.ts.map +0 -1
  77. package/dist/index-BOtXdQkW.d.ts.map +0 -1
  78. package/dist/index-BiO_5Hm4.d.ts.map +0 -1
  79. package/dist/interpolate-ERgZUxgg.js.map +0 -1
  80. package/dist/presets-MCcvxiNT.js.map +0 -1
  81. package/dist/session-BHZwxmfr.js.map +0 -1
  82. package/dist/tools-BNfyY14s.js.map +0 -1
  83. package/dist/transcript-anchors-DonKvoh4.d.ts.map +0 -1
  84. package/dist/turn-operations-TKvy0q29.js.map +0 -1
  85. package/dist/types-Ce78ds4h.d.ts +0 -88
  86. package/dist/types-Ce78ds4h.d.ts.map +0 -1
@@ -1,17 +1,17 @@
1
- import { 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, r as shell, t as writeFile$1, u as edit } from "./tools-BNfyY14s.js";
2
- import { s as errorMessage } from "./errors-Byb0F8B9.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-D_icxa-V.js";
2
+ import { s as errorMessage } from "./errors-CDwtPIMX.js";
3
3
  import { n as toolResultToText } from "./types-IcokUOyC.js";
4
- import { r as normalizeMcpServers } from "./mcp-DhmmJfxK.js";
5
- import { a as discoverSkills } from "./interpolate-ERgZUxgg.js";
4
+ import { r as normalizeMcpServers } from "./mcp-CNUbvbsy.js";
5
+ import { a as discoverSkills } from "./interpolate-BaaKaKzN.js";
6
6
  import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
7
- import { n as definePreset, t as composePresets } from "./presets-MCcvxiNT.js";
8
- import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-x3LZByR5.js";
7
+ import { n as definePreset, t as composePresets } from "./presets-h6UWhghO.js";
8
+ import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-G0VBZK9j.js";
9
+ import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
10
+ import { homedir } from "node:os";
9
11
  import { spawn } from "node:child_process";
12
+ import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
10
13
  import { readdir, stat, writeFile } from "node:fs/promises";
11
- import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
12
14
  import { getModel, getModels } from "@mariozechner/pi-ai";
13
- import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
14
- import { homedir } from "node:os";
15
15
  import { anthropicOAuthProvider, openaiCodexOAuthProvider } from "@mariozechner/pi-ai/oauth";
16
16
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
17
17
  import { jsx } from "react/jsx-runtime";
@@ -1889,7 +1889,7 @@ function scoreFiles(catalog, query, limit, formatPath) {
1889
1889
  return scored.slice(0, limit).map(({ entry, display }) => ({
1890
1890
  id: display,
1891
1891
  label: entry.name,
1892
- description: parentDir(display),
1892
+ description: parentDir(entry.path),
1893
1893
  insertText: `@${display} `,
1894
1894
  data: entry
1895
1895
  }));
@@ -2144,6 +2144,12 @@ const KEYBINDING_DEFS = [
2144
2144
  label: "messages",
2145
2145
  description: "enter select-turn mode to navigate previous messages"
2146
2146
  },
2147
+ {
2148
+ action: "cancelToolCall",
2149
+ default: "ctrl+k",
2150
+ label: "cancel tool",
2151
+ description: "open the in-flight tool picker to cancel a single tool call without aborting the run (esc still aborts the whole run)"
2152
+ },
2147
2153
  {
2148
2154
  action: "enterQueueSelection",
2149
2155
  default: "",
@@ -2180,6 +2186,12 @@ const KEYBINDING_DEFS = [
2180
2186
  label: "copy",
2181
2187
  description: "copy the selected turn content to the clipboard (OSC 52)"
2182
2188
  },
2189
+ {
2190
+ action: "turnEdit",
2191
+ default: "e",
2192
+ label: "edit",
2193
+ description: "edit the text content of the selected turn"
2194
+ },
2183
2195
  {
2184
2196
  action: "sessionDelete",
2185
2197
  default: "d",
@@ -2754,7 +2766,8 @@ function extractEditPayload(name, input, priorContent) {
2754
2766
  oldString,
2755
2767
  newString,
2756
2768
  ...input.replace_all === true ? { replaceAll: true } : {}
2757
- }]
2769
+ }],
2770
+ ...priorContent !== void 0 ? { priorContent } : {}
2758
2771
  };
2759
2772
  }
2760
2773
  if (name === "multi_edit") {
@@ -2772,7 +2785,8 @@ function extractEditPayload(name, input, priorContent) {
2772
2785
  return {
2773
2786
  tool: "multi_edit",
2774
2787
  path,
2775
- hunks
2788
+ hunks,
2789
+ ...priorContent !== void 0 ? { priorContent } : {}
2776
2790
  };
2777
2791
  }
2778
2792
  if (name === "write_file") {
@@ -2784,7 +2798,8 @@ function extractEditPayload(name, input, priorContent) {
2784
2798
  hunks: [{
2785
2799
  oldString: priorContent ?? "",
2786
2800
  newString: content
2787
- }]
2801
+ }],
2802
+ ...priorContent !== void 0 ? { priorContent } : {}
2788
2803
  };
2789
2804
  }
2790
2805
  }
@@ -2985,6 +3000,104 @@ function buildContextualDiff(payload, priorContent, contextLines = 3) {
2985
3000
  }
2986
3001
  return `${parts.join("\n")}\n`;
2987
3002
  }
3003
+ /**
3004
+ * Build a per-hunk digest used by the compact diff view.
3005
+ *
3006
+ * Strategy:
3007
+ * - When `priorContent` is present and the payload describes a real
3008
+ * file transformation, compute the contextual diff once, then walk
3009
+ * the LCS ops splitting at runs of `add` / `remove` to anchor each
3010
+ * summary entry to the **real** file line. This guarantees the
3011
+ * summary's `L<n>` matches what the user sees in their editor.
3012
+ * - Otherwise, fall back to per-hunk LCS over the (oldString,
3013
+ * newString) snippet pair. Line numbers are absent because the
3014
+ * snippet has no file position.
3015
+ */
3016
+ function summarizeEditPayload(payload) {
3017
+ const prior = payload.priorContent;
3018
+ if (prior !== void 0) return summarizeOpsByHunk(computeLineDiff(prior, applyEditPayload(payload, prior)));
3019
+ const hunks = [];
3020
+ let totalAdded = 0;
3021
+ let totalRemoved = 0;
3022
+ for (const hunk of payload.hunks) {
3023
+ const ops = computeLineDiff(hunk.oldString, hunk.newString);
3024
+ let added = 0;
3025
+ let removed = 0;
3026
+ let firstOld;
3027
+ let firstNew;
3028
+ for (const op of ops) if (op.op === "add") {
3029
+ added++;
3030
+ if (firstNew === void 0) firstNew = op.text;
3031
+ } else if (op.op === "remove") {
3032
+ removed++;
3033
+ if (firstOld === void 0) firstOld = op.text;
3034
+ }
3035
+ totalAdded += added;
3036
+ totalRemoved += removed;
3037
+ hunks.push({
3038
+ added,
3039
+ removed,
3040
+ ...firstOld !== void 0 ? { firstOld } : {},
3041
+ ...firstNew !== void 0 ? { firstNew } : {}
3042
+ });
3043
+ }
3044
+ return {
3045
+ totalAdded,
3046
+ totalRemoved,
3047
+ hunks
3048
+ };
3049
+ }
3050
+ /**
3051
+ * Walk an LCS op stream and emit one summary entry per *run* of
3052
+ * non-context ops, with the new-file line number where each run
3053
+ * starts. Adjacent add/remove ops collapse into the same entry —
3054
+ * matches git's hunk grouping at zero context.
3055
+ */
3056
+ function summarizeOpsByHunk(ops) {
3057
+ const hunks = [];
3058
+ let totalAdded = 0;
3059
+ let totalRemoved = 0;
3060
+ let nl = 1;
3061
+ let i = 0;
3062
+ while (i < ops.length) {
3063
+ if (ops[i].op === "context") {
3064
+ nl++;
3065
+ i++;
3066
+ continue;
3067
+ }
3068
+ const runStartLine = nl;
3069
+ let added = 0;
3070
+ let removed = 0;
3071
+ let firstOld;
3072
+ let firstNew;
3073
+ while (i < ops.length && ops[i].op !== "context") {
3074
+ const cur = ops[i];
3075
+ if (cur.op === "add") {
3076
+ added++;
3077
+ if (firstNew === void 0) firstNew = cur.text;
3078
+ nl++;
3079
+ } else {
3080
+ removed++;
3081
+ if (firstOld === void 0) firstOld = cur.text;
3082
+ }
3083
+ i++;
3084
+ }
3085
+ totalAdded += added;
3086
+ totalRemoved += removed;
3087
+ hunks.push({
3088
+ line: runStartLine,
3089
+ added,
3090
+ removed,
3091
+ ...firstOld !== void 0 ? { firstOld } : {},
3092
+ ...firstNew !== void 0 ? { firstNew } : {}
3093
+ });
3094
+ }
3095
+ return {
3096
+ totalAdded,
3097
+ totalRemoved,
3098
+ hunks
3099
+ };
3100
+ }
2988
3101
  function previewEditPayload(payload, priorContent, contextLines = 3) {
2989
3102
  const resolution = [];
2990
3103
  const resolvedHunks = [];
@@ -3208,9 +3321,45 @@ function deriveSessionTitle(turns, metadata) {
3208
3321
  */
3209
3322
  function eventsFromTurns(turns, runs = []) {
3210
3323
  const runById = /* @__PURE__ */ new Map();
3211
- for (const run of runs) runById.set(run.id, run);
3324
+ for (const run of runs) if (!runById.has(run.id)) runById.set(run.id, run);
3325
+ const runStack = [];
3326
+ const pendingToolCallsPerRun = /* @__PURE__ */ new Map();
3327
+ for (const turn of turns) {
3328
+ const rid = turn.runId;
3329
+ if (!rid) continue;
3330
+ const idxInStack = runStack.indexOf(rid);
3331
+ if (idxInStack >= 0) runStack.length = idxInStack + 1;
3332
+ else {
3333
+ const top = runStack[runStack.length - 1];
3334
+ if (!(top !== void 0 && (pendingToolCallsPerRun.get(top)?.size ?? 0) > 0)) runStack.length = 0;
3335
+ runStack.push(rid);
3336
+ if (!runById.has(rid)) {
3337
+ const depth = runStack.length - 1;
3338
+ const parentRunId = depth > 0 ? runStack[depth - 1] : void 0;
3339
+ let inferredPrompt = "";
3340
+ if (turn.role === "user") {
3341
+ for (const block of turn.content) if (block.type === "text" && block.text.trim()) {
3342
+ inferredPrompt = block.text;
3343
+ break;
3344
+ }
3345
+ }
3346
+ runById.set(rid, {
3347
+ id: rid,
3348
+ startedAt: turn.createdAt,
3349
+ prompt: inferredPrompt,
3350
+ status: "completed",
3351
+ depth,
3352
+ ...parentRunId ? { parentRunId } : {}
3353
+ });
3354
+ }
3355
+ }
3356
+ const pending = pendingToolCallsPerRun.get(rid) ?? /* @__PURE__ */ new Set();
3357
+ for (const block of turn.content) if (block.type === "tool_call") pending.add(block.id);
3358
+ else if (block.type === "tool_result") pending.delete(block.callId);
3359
+ pendingToolCallsPerRun.set(rid, pending);
3360
+ }
3212
3361
  const childLabelByRunId = /* @__PURE__ */ new Map();
3213
- runs.filter((r) => (r.depth ?? 0) > 0).slice().sort((a, b) => a.startedAt - b.startedAt).forEach((r, i) => childLabelByRunId.set(r.id, `child-${i + 1}`));
3362
+ [...runById.values()].filter((r) => (r.depth ?? 0) > 0).sort((a, b) => a.startedAt - b.startedAt).forEach((r, i) => childLabelByRunId.set(r.id, `child-${i + 1}`));
3214
3363
  const labelFor = (runId) => childLabelByRunId.get(runId) ?? runId;
3215
3364
  const toolByCallId = /* @__PURE__ */ new Map();
3216
3365
  for (const turn of turns) {
@@ -3256,7 +3405,7 @@ function eventsFromTurns(turns, runs = []) {
3256
3405
  });
3257
3406
  };
3258
3407
  const pushSpawnStart = (run) => {
3259
- const taskPreview = run.prompt.length > 80 ? `${run.prompt.slice(0, 80)}…` : run.prompt;
3408
+ const taskPreview = previewLine(run.prompt, 80);
3260
3409
  events.push({
3261
3410
  kind: "spawn-start",
3262
3411
  text: taskPreview,
@@ -3286,6 +3435,11 @@ function eventsFromTurns(turns, runs = []) {
3286
3435
  };
3287
3436
  if (turn.role === "user") {
3288
3437
  for (const block of turn.content) if (block.type === "text" && block.text.trim()) {
3438
+ const taskEvent = parseTaskNotificationBlock(block.text, tag);
3439
+ if (taskEvent) {
3440
+ events.push(taskEvent);
3441
+ continue;
3442
+ }
3289
3443
  if (depth === 0) {
3290
3444
  if (lastDepthAtEmission === 0) events.push({
3291
3445
  kind: "separator",
@@ -3361,6 +3515,84 @@ function eventsFromTurns(turns, runs = []) {
3361
3515
  return events;
3362
3516
  }
3363
3517
  /** Shared formatter for the `↳ name(args)` line shown on tool calls. */
3518
+ /**
3519
+ * Pattern matching the leading `<task-notification>` shape that the
3520
+ * agent's notification-injection path produces (see
3521
+ * `renderTaskNotificationXml` in `src/agent.ts`). Anchored so a stray
3522
+ * notification-shaped phrase mid-prompt doesn't trigger a false-positive
3523
+ * detection — the model's wire format always starts the user-turn
3524
+ * content block with this exact opening tag.
3525
+ */
3526
+ const TASK_NOTIFICATION_RE = /^\s*<task-notification>([\s\S]*?)<\/task-notification>\s*$/;
3527
+ /**
3528
+ * Per-field extractors. Compiled once at module load (parsing happens
3529
+ * on every session replay, and a fresh `new RegExp` per pick burns
3530
+ * cycles for no reason).
3531
+ */
3532
+ const TASK_NOTIFICATION_FIELD_RES = {
3533
+ taskId: /<task-id>([\s\S]*?)<\/task-id>/,
3534
+ status: /<status>([\s\S]*?)<\/status>/,
3535
+ exitCode: /<exit-code>([\s\S]*?)<\/exit-code>/,
3536
+ command: /<command>([\s\S]*?)<\/command>/,
3537
+ outputFile: /<output-file>([\s\S]*?)<\/output-file>/,
3538
+ durationMs: /<duration-ms>([\s\S]*?)<\/duration-ms>/,
3539
+ summary: /<summary>([\s\S]*?)<\/summary>/
3540
+ };
3541
+ /**
3542
+ * Detect a `<task-notification>` text block on replay and convert it
3543
+ * into a structured `task-notification` StreamEvent so the TUI's banner
3544
+ * renderer can paint it cleanly. Returns `null` when the block isn't a
3545
+ * notification (the caller falls back to the normal user-prompt path).
3546
+ *
3547
+ * Reads every field DIRECTLY from its tag — does NOT parse `<summary>`
3548
+ * for the underlying data. The summary is a derived display string,
3549
+ * not a source of truth: changing its format (localization, signal in
3550
+ * the label, whatever) must NEVER break replay. Each field falls back
3551
+ * to a safe default so older transcripts pre-dating a tag addition
3552
+ * still render.
3553
+ */
3554
+ function parseTaskNotificationBlock(text, tag) {
3555
+ const m = text.match(TASK_NOTIFICATION_RE);
3556
+ if (!m) return null;
3557
+ const body = m[1];
3558
+ const pick = (re) => {
3559
+ const inner = body.match(re);
3560
+ return inner ? unescapeXml(inner[1].trim()) : void 0;
3561
+ };
3562
+ const taskId = pick(TASK_NOTIFICATION_FIELD_RES.taskId) ?? "?";
3563
+ const statusRaw = pick(TASK_NOTIFICATION_FIELD_RES.status) ?? "exited";
3564
+ const status = statusRaw === "killed" ? "killed" : "exited";
3565
+ const exitCode = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.exitCode) ?? "0", 10) || 0;
3566
+ const command = pick(TASK_NOTIFICATION_FIELD_RES.command) ?? "";
3567
+ const outputPath = pick(TASK_NOTIFICATION_FIELD_RES.outputFile) ?? "";
3568
+ const durationMs = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.durationMs) ?? "0", 10) || 0;
3569
+ return {
3570
+ kind: "task-notification",
3571
+ text: pick(TASK_NOTIFICATION_FIELD_RES.summary) ?? `${taskId} ${statusRaw}${exitCode ? ` ${exitCode}` : ""}`,
3572
+ task: {
3573
+ taskId,
3574
+ status,
3575
+ exitCode,
3576
+ outputPath,
3577
+ command,
3578
+ durationMs
3579
+ },
3580
+ turnId: tag.turnId,
3581
+ ...tag.childId !== void 0 ? { childId: tag.childId } : {},
3582
+ ...tag.depth !== void 0 ? { depth: tag.depth } : {}
3583
+ };
3584
+ }
3585
+ /**
3586
+ * Reverse of `escapeXml` for the small set of entities the writer
3587
+ * emits. Not a full HTML entity decoder — just enough to round-trip
3588
+ * `<` / `>` / `&` / quotes through persistence.
3589
+ *
3590
+ * `&amp;` MUST be replaced last, otherwise `&amp;lt;` becomes `&lt;`
3591
+ * then `<` (data corruption — silent double-decode).
3592
+ */
3593
+ function unescapeXml(s) {
3594
+ return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&apos;/g, "'").replace(/&amp;/g, "&");
3595
+ }
3364
3596
  function toolCallPreview(name, input) {
3365
3597
  const args = JSON.stringify(input);
3366
3598
  return args && args !== "{}" ? `${name}(${args})` : name;
@@ -3493,7 +3725,8 @@ const MARGIN_TOP = {
3493
3725
  "markdown": 1,
3494
3726
  "spawn-start": 1,
3495
3727
  "spawn-end": 0,
3496
- "compact-summary": 1
3728
+ "compact-summary": 1,
3729
+ "task-notification": 1
3497
3730
  };
3498
3731
  const TOOL_KINDS = new Set(["tool", "tool-result"]);
3499
3732
  /**
@@ -3503,20 +3736,28 @@ const TOOL_KINDS = new Set(["tool", "tool-result"]);
3503
3736
  * - A `tool` / `tool-result` event right after another
3504
3737
  * `tool` / `tool-result` collapses to a tight list — call→result
3505
3738
  * pairs and back-to-back calls read as one logical block.
3506
- * - A parent-level event (`depth === 0`) right after a subagent event
3507
- * (`depth > 0`) collapses too. The subagent's `🌳` end marker
3508
- * already provides the separation; adding the event's default
3509
- * `marginTop` on top would produce the visible "line jump" between
3510
- * a subagent's outcome and the parent's follow-up.
3739
+ * - Consecutive `task-notification` banners stack tight a burst of
3740
+ * background-task completions reads as one log column rather than
3741
+ * scattered banners.
3742
+ *
3743
+ * NB: parent-level events (`depth === 0`) following a subagent block
3744
+ * (`depth > 0`) get their normal default margin. An earlier revision
3745
+ * collapsed this transition to 0 on the assumption that the subagent's
3746
+ * `🌳` end-marker provided enough visual separation — it didn't. A
3747
+ * 2-cell emoji on the same row as the close marker doesn't create a
3748
+ * vertical break, and in hide-subagent-output mode the SubagentBlock
3749
+ * box isn't rendered either, so the parent's follow-up markdown was
3750
+ * glued directly against the close line. Subagents should READ like
3751
+ * tool calls: open with breathing room, close tight inside, and open
3752
+ * a clean gap before the parent's next thought — that's the contract
3753
+ * the tool-call → markdown transition uses, mirrored here.
3511
3754
  *
3512
3755
  * Renderer-agnostic — TUI uses it as Yoga `marginTop`; a CSS host can
3513
3756
  * use the same number as the row's top margin in `em` / `rem`.
3514
3757
  */
3515
3758
  function marginTopFor(event, previous) {
3516
3759
  if (TOOL_KINDS.has(event.kind) && previous && TOOL_KINDS.has(previous.kind)) return 0;
3517
- const eventDepth = event.depth ?? 0;
3518
- const previousDepth = previous?.depth ?? 0;
3519
- if (eventDepth === 0 && previousDepth > 0) return 0;
3760
+ if (event.kind === "task-notification" && previous?.kind === "task-notification") return 0;
3520
3761
  return MARGIN_TOP[event.kind] ?? 0;
3521
3762
  }
3522
3763
  /**
@@ -4845,6 +5086,7 @@ const DEFAULT_SETTINGS = {
4845
5086
  autoCompact: true,
4846
5087
  autoCompactThreshold: .8,
4847
5088
  showEditDiffs: true,
5089
+ editDiffDisplay: "full",
4848
5090
  targetFps: 60,
4849
5091
  allowInteraction: true,
4850
5092
  smoothStreaming: true,
@@ -4996,6 +5238,18 @@ const SETTINGS_CHOICES = [
4996
5238
  }
4997
5239
  ]
4998
5240
  },
5241
+ {
5242
+ key: "editDiffDisplay",
5243
+ label: "Edit diff density",
5244
+ description: "full unified diff with line numbers · or compact per-hunk summary list",
5245
+ options: [{
5246
+ value: "full",
5247
+ label: "Full"
5248
+ }, {
5249
+ value: "compact",
5250
+ label: "Compact"
5251
+ }]
5252
+ },
4999
5253
  {
5000
5254
  key: "autoCompactThreshold",
5001
5255
  label: "Auto-compact threshold",
@@ -5295,51 +5549,6 @@ function toEntries(paths, source, maxFiles) {
5295
5549
  return out;
5296
5550
  }
5297
5551
  //#endregion
5298
- //#region src/chat/format.ts
5299
- /** Compact token formatter — 12_415 → "12.4k", 1_234_567 → "1.23M". */
5300
- function fmtTokens(n) {
5301
- if (n < 1e3) return String(n);
5302
- if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 2 : 1)}k`;
5303
- return `${(n / 1e6).toFixed(2)}M`;
5304
- }
5305
- /** Compact relative-time formatter — "just now / 5m / 3h / 2d". */
5306
- function ageString(ts, now = Date.now()) {
5307
- const m = Math.floor((now - ts) / 6e4);
5308
- if (m < 1) return "just now";
5309
- if (m < 60) return `${m}m ago`;
5310
- const h = Math.floor(m / 60);
5311
- if (h < 24) return `${h}h ago`;
5312
- return `${Math.floor(h / 24)}d ago`;
5313
- }
5314
- /** Six-char short form of a session id for headers and lists. */
5315
- function shortId(id) {
5316
- return id.replace(/-/g, "").slice(0, 6);
5317
- }
5318
- /**
5319
- * Compact an absolute path for display: replace the user's `$HOME`
5320
- * prefix with `~` (so `/Users/yael/Code/zidane` → `~/Code/zidane`),
5321
- * and optionally left-truncate with an ellipsis when the result
5322
- * still exceeds `maxWidth` (so the path's *tail* — the part the user
5323
- * recognizes — stays visible: `…/zidane` rather than `/Users/yaeluil…`).
5324
- *
5325
- * `maxWidth` is the maximum *display width* in cells. Omit to skip
5326
- * truncation. Paths outside `$HOME` are returned verbatim modulo
5327
- * truncation. The ellipsis (`…`) counts as one cell.
5328
- *
5329
- * `home` overrides `os.homedir()` for tests; production callers leave
5330
- * it undefined and pay the cheap one-syscall lookup per call.
5331
- */
5332
- function compactPath(path, maxWidth, home) {
5333
- const h = home ?? homedir();
5334
- let display = path;
5335
- if (h) {
5336
- if (path === h) display = "~";
5337
- else if (path.startsWith(`${h}/`)) display = `~${path.slice(h.length)}`;
5338
- }
5339
- if (maxWidth !== void 0 && maxWidth > 1 && display.length > maxWidth) return `…${display.slice(display.length - maxWidth + 1)}`;
5340
- return display;
5341
- }
5342
- //#endregion
5343
5552
  //#region src/chat/generate-title.ts
5344
5553
  /** Hard cap on the result length. Anything longer is truncated client-side. */
5345
5554
  const TITLE_MAX_CHARS = 60;
@@ -6552,13 +6761,17 @@ async function runOAuthLogin(descriptor, options) {
6552
6761
  *
6553
6762
  * Rule:
6554
6763
  *
6555
- * - When the resolved target sits inside `cwd` → return a
6556
- * CWD-relative forward-slashed path (no `..` traversal).
6557
- * - Otherwise (target sits above `cwd`, or `cwd` is outside the
6558
- * project) return the absolute path. A `..`-laden relative
6559
- * form would be valid for the tools but harder to read AND
6560
- * surprises the user, whose mental model of `@` is "pick a
6561
- * file from the project view".
6764
+ * - File at `cwd` itself `.`.
6765
+ * - File under `cwd` (subtree) forward-slashed CWD-relative,
6766
+ * no `..`.
6767
+ * - File above `cwd` but still inside the project → CWD-relative
6768
+ * with `..` traversal (e.g. `../EDIT_THIS.md`). Shorter and more
6769
+ * scannable than absolute, and the agent's tools resolve both.
6770
+ * - File outside the project (input was passed absolute) → returned
6771
+ * verbatim. Inputs that arrive as project-root-relative strings
6772
+ * are always inside the project by construction, so this branch
6773
+ * only kicks in when a direct caller hands the function an
6774
+ * absolute target.
6562
6775
  *
6563
6776
  * Pure, no I/O, deterministic.
6564
6777
  */
@@ -6569,13 +6782,18 @@ async function runOAuthLogin(descriptor, options) {
6569
6782
  *
6570
6783
  * Inputs:
6571
6784
  * - `projectRelativePath` — forward-slashed, no leading slash. Returned
6572
- * verbatim when it's empty or already absolute (defensive).
6785
+ * verbatim when it's empty or already absolute (defensive — the
6786
+ * absolute-input branch is the de-facto "outside the project"
6787
+ * escape; the catalog itself never emits absolute paths).
6573
6788
  * - `projectRoot` — absolute path of the discovery anchor.
6574
6789
  * - `cwd` — absolute path of `process.cwd()` at the moment of
6575
6790
  * insertion.
6576
6791
  *
6577
- * Output is always either an absolute path OR a CWD-relative path with
6578
- * no `..` segments. Never a `..`-prefixed relative path.
6792
+ * Output is always either an absolute path (only when the input arrived
6793
+ * absolute) OR a CWD-relative path. The relative form may include
6794
+ * `../` segments when the target sits above `cwd` within the project,
6795
+ * which keeps cross-tree references short and scannable
6796
+ * (e.g. `../EDIT_THIS.md` instead of `/Users/.../zidane/EDIT_THIS.md`).
6579
6797
  */
6580
6798
  function formatPathForCwd(projectRelativePath, projectRoot, cwd) {
6581
6799
  if (projectRelativePath.length === 0) return projectRelativePath;
@@ -6585,7 +6803,6 @@ function formatPathForCwd(projectRelativePath, projectRoot, cwd) {
6585
6803
  if (target === here) return ".";
6586
6804
  const rel = relative(here, target);
6587
6805
  if (rel.length === 0) return ".";
6588
- if (rel === ".." || rel.startsWith(`..${sep}`) || rel.startsWith("../")) return target;
6589
6806
  return sep === "/" ? rel : rel.split(sep).join(posix.sep);
6590
6807
  }
6591
6808
  //#endregion
@@ -6703,7 +6920,7 @@ function getSafelist(dataDir, projectDir) {
6703
6920
  return readProjects(dataDir)[projectDir]?.safelist ?? [];
6704
6921
  }
6705
6922
  /**
6706
- * Tools that always pass without prompting. Three categories:
6923
+ * Tools that always pass without prompting. Four categories:
6707
6924
  *
6708
6925
  * - **Pure reads** (`read_file`, `list_files`, `glob`, `grep`) — no
6709
6926
  * side effects on disk or the model's own state.
@@ -6717,6 +6934,18 @@ function getSafelist(dataDir, projectDir) {
6717
6934
  * a per-call approval prompt would drown the conversation in
6718
6935
  * interruptions that buy no safety since the tool's surface is
6719
6936
  * read/write on a metadata bag we already trust the agent with.
6937
+ * - **Skill activation** (`skills_use`) — mutates a small per-agent
6938
+ * Map of active skills and returns the activated skill's bundled
6939
+ * instructions (or releases an entry on `mode: "deactivate"`).
6940
+ * Pure state on the agent — no shell, no disk writes, no network.
6941
+ * Gating it would also defeat the "model recovers from
6942
+ * `AgentToolNotAllowedError` by calling
6943
+ * `skills_use({ mode: "deactivate", name })`" path: a stuck model
6944
+ * would have to ask the user permission to *unstick* itself on
6945
+ * every retry. `skills_read` and `skills_run_script` are
6946
+ * intentionally NOT on this list — the former touches disk and
6947
+ * the latter executes arbitrary scripts, so both keep going
6948
+ * through the regular gate.
6720
6949
  *
6721
6950
  * Users who want to gate any of these must disable safe-mode entirely
6722
6951
  * (or fork this list in their own embedding).
@@ -6729,7 +6958,8 @@ const IMPLICITLY_SAFE_TOOLS = [
6729
6958
  "ask_user",
6730
6959
  "present_plan",
6731
6960
  "todowrite",
6732
- "todoread"
6961
+ "todoread",
6962
+ "skills_use"
6733
6963
  ];
6734
6964
  /** Common input keys carrying the "primary argument" we scope safelists on. */
6735
6965
  const PRIMARY_ARG_KEYS = [
@@ -7245,33 +7475,40 @@ const TICK_INTERVAL_MS = 16;
7245
7475
  /**
7246
7476
  * Smooth-streaming display rate, in characters per second.
7247
7477
  *
7248
- * - {@link SMOOTH_BASE_CPS} calm-state cap. ~200 CPS is a fast typist's
7249
- * pace; comfortably readable without feeling like a deliberate
7250
- * typewriter performance.
7251
- * - {@link SMOOTH_BURST_CPS} — cap once the buffer is the full
7252
- * {@link SMOOTH_BURST_BACKLOG_CHARS} behind the provider. The rate
7253
- * ramps continuously from base to burst across that range (see
7254
- * {@link smoothCharsForTick}) so the typewriter cadence never visibly
7255
- * "steps up" mid-stream the old step function (BASE for <100,
7256
- * BURST for ≥100) tripled the chars-per-frame the instant the
7257
- * threshold was crossed, which read as the text jumping.
7258
- * - {@link SMOOTH_INSTANT_BACKLOG_CHARS} failsafe. If the buffer
7259
- * somehow accumulates >2K chars (paste-heavy responses, model dumping
7260
- * pre-computed text, etc.) the ticker stops smoothing entirely for
7261
- * the rest of the drain — better to commit the wall of text now than
7262
- * to type it out for ten more seconds.
7478
+ * Three-segment continuous ramp (no step functions, no cliff) so the
7479
+ * typewriter cadence never visibly "jumps" mid-stream:
7480
+ *
7481
+ * - {@link SMOOTH_BASE_CPS} — calm-state floor. ~200 CPS is a fast
7482
+ * typist's pace; comfortably readable without feeling like a
7483
+ * deliberate performance.
7484
+ * - {@link SMOOTH_BURST_CPS} at {@link SMOOTH_BURST_BACKLOG_CHARS}
7485
+ * moderate catch-up speed once the buffer is one paragraph behind
7486
+ * the provider.
7487
+ * - {@link SMOOTH_MAX_CPS} at {@link SMOOTH_MAX_BACKLOG_CHARS}
7488
+ * bounded ceiling. Past this we plateau at max-cps rather than
7489
+ * instant-draining; max-cps is already well above any human reading
7490
+ * rate so even a 10K-char dump completes in ~2.5s of fast typewriter
7491
+ * instead of a single-frame teleport.
7492
+ *
7493
+ * The previous failsafe (instant drain at 2K chars) was a literal
7494
+ * step from ~10 chars/frame to "everything in one frame" — the worst
7495
+ * jump in the smooth pipeline. The continued ramp eliminates it
7496
+ * without losing bounded latency, since CPS keeps growing with
7497
+ * backlog up to the cap.
7263
7498
  */
7264
7499
  const SMOOTH_BASE_CPS = 200;
7265
7500
  const SMOOTH_BURST_CPS = 600;
7266
7501
  const SMOOTH_BURST_BACKLOG_CHARS = 400;
7267
- const SMOOTH_INSTANT_BACKLOG_CHARS = 2e3;
7502
+ const SMOOTH_MAX_CPS = 4e3;
7503
+ const SMOOTH_MAX_BACKLOG_CHARS = 4e3;
7268
7504
  const PARENT_OWNER = "parent";
7269
7505
  function emptyBucket(owner, depth) {
7270
7506
  return {
7271
7507
  markdown: "",
7272
7508
  thinking: "",
7273
7509
  owner,
7274
- depth
7510
+ depth,
7511
+ smoothCarry: 0
7275
7512
  };
7276
7513
  }
7277
7514
  function applyBucket(prev, bucket) {
@@ -7383,23 +7620,52 @@ function turnContextSize(usage) {
7383
7620
  return (usage.input ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheCreation ?? 0);
7384
7621
  }
7385
7622
  /**
7386
- * Number of characters to drain on the next smooth-mode tick, given the
7387
- * current backlog of one bucket. Caps at the bucket length (never
7388
- * over-drains) and bypasses smoothing entirely once the backlog goes
7389
- * past {@link SMOOTH_INSTANT_BACKLOG_CHARS}.
7623
+ * Target chars-per-second for the next smooth-mode tick given the
7624
+ * current bucket backlog. Two linear segments base→burst over the
7625
+ * first {@link SMOOTH_BURST_BACKLOG_CHARS}, burst→max over the rest of
7626
+ * the ramp — so the function is continuous everywhere and plateaus
7627
+ * (rather than cliffs) once backlog passes {@link SMOOTH_MAX_BACKLOG_CHARS}.
7390
7628
  *
7391
- * The CPS ramps continuously from {@link SMOOTH_BASE_CPS} at zero backlog
7392
- * to {@link SMOOTH_BURST_CPS} at {@link SMOOTH_BURST_BACKLOG_CHARS},
7393
- * then plateaus at burst up to the instant cliff. Continuous (vs. the
7394
- * legacy step at the burst threshold) so the chars-per-frame count never
7395
- * jumps mid-stream — visible jumps in the typewriter cadence read as the
7396
- * text itself jumping.
7629
+ * Exported for tests; the runtime path goes through
7630
+ * {@link smoothCharsForTick} which folds in the per-bucket fractional
7631
+ * remainder.
7397
7632
  */
7398
- function smoothCharsForTick(backlog) {
7633
+ function smoothCpsForBacklog(backlog) {
7399
7634
  if (backlog <= 0) return 0;
7400
- if (backlog >= SMOOTH_INSTANT_BACKLOG_CHARS) return backlog;
7401
- const cps = SMOOTH_BASE_CPS + Math.min(1, backlog / SMOOTH_BURST_BACKLOG_CHARS) * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS);
7402
- return Math.max(1, Math.min(backlog, Math.ceil(cps * TICK_INTERVAL_MS / 1e3)));
7635
+ if (backlog >= SMOOTH_MAX_BACKLOG_CHARS) return SMOOTH_MAX_CPS;
7636
+ if (backlog <= SMOOTH_BURST_BACKLOG_CHARS) return SMOOTH_BASE_CPS + backlog / SMOOTH_BURST_BACKLOG_CHARS * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS);
7637
+ return SMOOTH_BURST_CPS + (backlog - SMOOTH_BURST_BACKLOG_CHARS) / (SMOOTH_MAX_BACKLOG_CHARS - SMOOTH_BURST_BACKLOG_CHARS) * (SMOOTH_MAX_CPS - SMOOTH_BURST_CPS);
7638
+ }
7639
+ /**
7640
+ * Number of characters to drain on the next smooth-mode tick + the
7641
+ * fractional remainder to carry into the next tick.
7642
+ *
7643
+ * Combining the CPS curve with a fractional accumulator means the
7644
+ * effective draining rate matches the target CPS exactly. The legacy
7645
+ * `Math.ceil(cps * dt)` rounded UP on every tick — at 200 CPS / 16ms,
7646
+ * that's 4 chars/tick (= 250 CPS effective), a 25 % speed-up. Worse,
7647
+ * `ceil` produced visible step transitions (4 → 5 → 7 → 8 → 10 as
7648
+ * backlog grew) that read as the typewriter cadence jumping.
7649
+ */
7650
+ function smoothCharsForTick(backlog, carry, dtMs) {
7651
+ if (backlog <= 0) return {
7652
+ take: 0,
7653
+ carry: 0
7654
+ };
7655
+ const want = smoothCpsForBacklog(backlog) * dtMs / 1e3 + carry;
7656
+ const take = Math.floor(want);
7657
+ if (take <= 0) return {
7658
+ take: 0,
7659
+ carry: want
7660
+ };
7661
+ if (take >= backlog) return {
7662
+ take: backlog,
7663
+ carry: 0
7664
+ };
7665
+ return {
7666
+ take,
7667
+ carry: want - take
7668
+ };
7403
7669
  }
7404
7670
  /**
7405
7671
  * Slice `n` chars off the front of `buf` without splitting a UTF-16
@@ -7423,6 +7689,7 @@ function takeChars(buf, n) {
7423
7689
  function useStreamBuffer(setEvents, options) {
7424
7690
  const bucketsRef = useRef(/* @__PURE__ */ new Map());
7425
7691
  const tickerRef = useRef(null);
7692
+ const lastTickMsRef = useRef(0);
7426
7693
  const getSmoothRef = useRef(options?.getSmooth);
7427
7694
  getSmoothRef.current = options?.getSmooth;
7428
7695
  /**
@@ -7443,6 +7710,7 @@ function useStreamBuffer(setEvents, options) {
7443
7710
  clearInterval(tickerRef.current);
7444
7711
  tickerRef.current = null;
7445
7712
  }
7713
+ lastTickMsRef.current = 0;
7446
7714
  }, []);
7447
7715
  /**
7448
7716
  * Has at least one bucket got unflushed *markdown* content?
@@ -7494,25 +7762,34 @@ function useStreamBuffer(setEvents, options) {
7494
7762
  const buckets = bucketsRef.current;
7495
7763
  const portions = [];
7496
7764
  let stillHasContent = false;
7765
+ const now = Date.now();
7766
+ const dtMs = lastTickMsRef.current === 0 ? TICK_INTERVAL_MS : Math.min(TICK_INTERVAL_MS * 4, Math.max(1, now - lastTickMsRef.current));
7767
+ lastTickMsRef.current = now;
7497
7768
  for (const bucket of buckets.values()) {
7498
7769
  const thinking = bucket.thinking;
7499
7770
  bucket.thinking = "";
7500
7771
  let taken = "";
7501
7772
  if (bucket.markdown.length > 0) if (smooth) {
7502
- const n = smoothCharsForTick(bucket.markdown.length);
7503
- const result = takeChars(bucket.markdown, n);
7504
- taken = result.taken;
7505
- bucket.markdown = result.rest;
7773
+ const { take, carry } = smoothCharsForTick(bucket.markdown.length, bucket.smoothCarry, dtMs);
7774
+ bucket.smoothCarry = carry;
7775
+ if (take > 0) {
7776
+ const result = takeChars(bucket.markdown, take);
7777
+ taken = result.taken;
7778
+ bucket.markdown = result.rest;
7779
+ if (bucket.markdown.length === 0) bucket.smoothCarry = 0;
7780
+ }
7506
7781
  } else {
7507
7782
  taken = bucket.markdown;
7508
7783
  bucket.markdown = "";
7784
+ bucket.smoothCarry = 0;
7509
7785
  }
7510
7786
  if (taken || thinking) portions.push({
7511
7787
  markdown: taken,
7512
7788
  thinking,
7513
7789
  owner: bucket.owner,
7514
7790
  depth: bucket.depth,
7515
- turnId: bucket.turnId
7791
+ turnId: bucket.turnId,
7792
+ smoothCarry: 0
7516
7793
  });
7517
7794
  if (bucket.markdown.length > 0) stillHasContent = true;
7518
7795
  }
@@ -7686,13 +7963,21 @@ const TOOL_DISPLAY = {
7686
7963
  }
7687
7964
  },
7688
7965
  shell: {
7689
- displayName: "Shell",
7966
+ displayName: (input) => input?.run_in_background === true ? "Shell (background)" : "Shell",
7690
7967
  format: (input) => {
7691
7968
  const command = stringField(input, "command");
7692
7969
  if (!command) return null;
7693
7970
  return { target: truncate(command.trim(), 200) };
7694
7971
  }
7695
7972
  },
7973
+ shell_kill: {
7974
+ displayName: "Kill task",
7975
+ format: (input) => {
7976
+ const taskId = stringField(input, "task_id");
7977
+ if (!taskId) return null;
7978
+ return { target: taskId };
7979
+ }
7980
+ },
7696
7981
  edit: {
7697
7982
  displayName: "Edit",
7698
7983
  format: (input) => {
@@ -7752,7 +8037,9 @@ const TOOL_DISPLAY = {
7752
8037
  }
7753
8038
  },
7754
8039
  skills_use: {
7755
- displayName: "Activate skill",
8040
+ displayName: (input) => {
8041
+ return (input ? stringField(input, "mode") : void 0) === "deactivate" ? "Disable skill" : "Enable skill";
8042
+ },
7756
8043
  format: (input) => {
7757
8044
  const name = stringField(input, "name");
7758
8045
  if (!name) return null;
@@ -7846,9 +8133,9 @@ const TOOL_DISPLAY = {
7846
8133
  * affordance ("everything starting with `Github` came from the github
7847
8134
  * MCP server").
7848
8135
  */
7849
- function displayNameFor(name) {
8136
+ function displayNameFor(name, input) {
7850
8137
  const entry = TOOL_DISPLAY[name];
7851
- if (entry) return entry.displayName;
8138
+ if (entry) return typeof entry.displayName === "function" ? entry.displayName(input) : entry.displayName;
7852
8139
  return sentenceCase(name.startsWith("mcp_") ? name.slice(4) : name);
7853
8140
  }
7854
8141
  /**
@@ -8058,6 +8345,6 @@ function countNeighbors(turnIds, turnId) {
8058
8345
  };
8059
8346
  }
8060
8347
  //#endregion
8061
- export { useMcpAuthDispatch as $, blendHsl as $n, INTERACTION_GUIDANCE_NO_PROMPTS as $r, isVisible as $t, getSafelist as A, summarizeOutcomes as An, PLAN_AGENT as Ar, clampFps as At, supportsOAuth as B, readKeybindings as Bn, getArchivedTodosForRun as Br, CATPPUCCIN_MOCHA as Bt, resolveSessionExportTarget as C, buildEditOutcomesAnnotation as Cn, openaiDescriptor as Cr, shortId as Ct, useSafeModeQueue as D, resolveApprovalForPayload as Dn, BUILTIN_AGENTS as Dr, SETTINGS_CHOICES as Dt, useSafeModeActions as E, parseEditOutcomesFromResult as En, BUILD_AGENT as Er, DEFAULT_SETTINGS as Et, suggestSafelistEntry as F, ensureKeybindingsFile as Fn, TODOS_METADATA_KEY as Fr, resolveTheme as Ft, defaultMcpsConfigPaths as G, FILES_TRIGGER as Gn, selectActiveTodos as Gr, ConfigProvider as Gt, filterModelCatalog as H, SKILLS_TRIGGER as Hn, isTodoTool as Hr, DiscoveryProvider as Ht, writeProjects as I, keybindingsPath as In, TODOWRITE_TOOL as Ir, VAPORWAVE_THEME as It, projectUserPaths as J, applyInsert as Jn, ACTIONS_WITH_CARE_DOCTRINE as Jr, createStateStore as Jt, discoverProjectMcps as K, createFilesCompletionProvider as Kn, setTodosForRun as Kr, useConfig as Kt, splitPromptSegments as L, matchesBinding as Ln, TODO_STATUS_GLYPHS as Lr, CATPPUCCIN_FRAPPE as Lt, matchesSafelistEntry as M, DEFAULT_KEYBINDINGS as Mn, resolveAgentId as Mr, BUILTIN_THEMES as Mt, projectsFilePath as N, KEYBINDING_DEFS as Nn, singleAgentRegistry as Nr, DEFAULT_THEME as Nt, IMPLICITLY_SAFE_TOOLS as O, rewriteMultiEditHeader as On, DEFAULT_AGENT_ID as Or, SETTINGS_TOGGLES as Ot, readProjects as P, KEYBINDING_DEF_BY_ACTION as Pn, TODOREAD_TOOL as Pr, resolveChipColor as Pt, McpAuthProvider as Q, useCompletion as Qn, INTERACTION_GUIDANCE as Qr, isTurnHighlighted as Qt, formatPathForCwd as R, mergeKeybindings as Rn, TODO_WRITE_COUNTS_METADATA_KEY as Rr, CATPPUCCIN_LATTE as Rt, renderSession as S, tokenize as Sn, modelsForDescriptor as Sr, fmtTokens as St, SafeModeProvider as T, mergeApprovalAndBodyOutcomes as Tn, piIdOf as Tr, useEnabledToggleSet as Tt, indexOfEntry as U, createSkillsCompletionProvider as Un, pickActiveRunId as Ur, useDiscovery as Ut, buildModelCatalog as V, stripJsonComments as Vn, getTodosForRun as Vr, createDiscoverySlot as Vt, buildMcpServers as W, uniqueSkillNamesFromReferences as Wn, pruneTodosByRun as Wr, useDiscoveryOptional as Wt, mcpCredentialsPath as X, findActiveTrigger as Xn, DOING_TASKS_DOCTRINE as Xr, eventsFromTurns as Xt, createFileMcpCredentialStore as Y, collectReferences as Yn, COMMUNICATION_DOCTRINE as Yr, deriveSessionTitle as Yt, patchMcpCredential as Z, mergeReferences as Zn, IDENTITY_PREFIX as Zr, isEditErrorResult as Zt, turnContextSize as _, computeLineDiff as _n, credKeyOf as _r, truncateTrailing as _t, computeTurnAnchors as a, buildPlanSystem as ai, selectableTurnIds as an, detectAuth as ar, InteractionsProvider as at, defaultSkillScanPaths as b, previewEditPayload as bn, getModelInfo as br, ageString as bt, formatToolCall as c, titleFromTurns as cn, readCredentials as cr, createInteractionTools as ct, useSelectStyle as d, turnSelectionOwnership as dn, setProviderCredential as dr, pendingInteractionsFromTurns as dt, PLAN_MODE_DOCTRINE as ei, lastContextSizeFromTurns as en, buildLinearRamp as er, useMcpAuthState as et, useSurfaces as f, updateToolEventOutcomes as fn, writeCredentials as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, computeInlineDiff as gn, cerebrasDescriptor as gr, hintsLength as gt, finalizeStreamingMarkdown as h, buildUnifiedDiff as hn, anthropicDescriptor as hr, clipHintsToWidth as ht, turnAsText as i, buildBuildSystem as ii, saveState as in, shouldAutoCompact as ir, ASK_USER_TOOL as it, isOnSafelist as j, findGitRoot$1 as jn, accentColor as jr, useSettings as jt, addToSafelist as k, stripEditOutcomesAnnotation as kn, DEFAULT_PERSIST_EXCLUDE_TOOLS as kr, SettingsProvider as kt, ThemeProvider as l, toolCallPreview as ln, readProviderCredential as lr, isInteractionTool as lt, useTheme as m, buildContextualDiff as mn, OUTPUT_RESERVE_TOKENS as mr, useInteractionsQueue as mt, deleteTurnSafely as n, SUBAGENT_GUIDANCE as ni, loadState as nn, bootProfileEnabled as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, envSection as oi, stripSpawnTokensLine as on, applyApiKeyEnv as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, applyEditPayload as pn, BUILTIN_PROVIDERS as pr, useInteractionsActions as pt, parseMcpsFile as q, uniqueFilesFromReferences as qn, useActiveTodos as qr, resolveConfig as qt, truncateTurnsAt as r, TOKEN_DISCIPLINE_DOCTRINE as ri, marginTopFor as rn, bootTick as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, sumRunCosts as sn, credentialsPath as sr, buildResumedToolResultsTurn as st, countNeighbors as t, PLAN_MODE_DOCTRINE_NO_PROMPTS as ti, listSessionMeta as tn, tryOpenBrowser as tr, getMcpAuthStatus as tt, useColors as u, toolResultText as un, removeProviderCredential as ur, makeRequestInteraction as ut, useStreamBuffer as v, extractEditPayload as vn, effectiveContextWindow as vr, cleanTitle as vt, writeSessionExport as w, maskToOutcomeKinds as wn, openrouterDescriptor as wr, listProjectFiles as wt, discoverProjectSkills as x, splitLines as xn, modelSupportsReasoning as xr, compactPath as xt, buildSkillsConfig as y, filetypeFromPath as yn, getContextWindow as yr, generateSessionTitle as yt, runOAuthLogin as z, parseBindingSpec as zn, createTodoTools as zr, CATPPUCCIN_MACCHIATO as zt };
8348
+ export { useMcpAuthDispatch as $, tryOpenBrowser as $n, PLAN_MODE_DOCTRINE_NO_PROMPTS as $r, loadState as $t, getSafelist as A, DEFAULT_KEYBINDINGS as An, resolveAgentId as Ar, resolveChipColor as At, supportsOAuth as B, SKILLS_TRIGGER as Bn, isTodoTool as Br, useDiscoveryOptional as Bt, resolveSessionExportTarget as C, mergeApprovalAndBodyOutcomes as Cn, piIdOf as Cr, SETTINGS_CHOICES as Ct, useSafeModeQueue as D, stripEditOutcomesAnnotation as Dn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Dr, useSettings as Dt, useSafeModeActions as E, rewriteMultiEditHeader as En, DEFAULT_AGENT_ID as Er, clampFps as Et, suggestSafelistEntry as F, matchesBinding as Fn, TODO_STATUS_GLYPHS as Fr, CATPPUCCIN_MACCHIATO as Ft, defaultMcpsConfigPaths as G, uniqueFilesFromReferences as Gn, useActiveTodos as Gr, createStateStore as Gt, filterModelCatalog as H, uniqueSkillNamesFromReferences as Hn, pruneTodosByRun as Hr, useConfig as Ht, writeProjects as I, mergeKeybindings as In, TODO_WRITE_COUNTS_METADATA_KEY as Ir, CATPPUCCIN_MOCHA as It, projectUserPaths as J, findActiveTrigger as Jn, DOING_TASKS_DOCTRINE as Jr, isEditErrorResult as Jt, discoverProjectMcps as K, applyInsert as Kn, ACTIONS_WITH_CARE_DOCTRINE as Kr, deriveSessionTitle as Kt, splitPromptSegments as L, parseBindingSpec as Ln, createTodoTools as Lr, createDiscoverySlot as Lt, matchesSafelistEntry as M, KEYBINDING_DEF_BY_ACTION as Mn, TODOREAD_TOOL as Mr, VAPORWAVE_THEME as Mt, projectsFilePath as N, ensureKeybindingsFile as Nn, TODOS_METADATA_KEY as Nr, CATPPUCCIN_FRAPPE as Nt, IMPLICITLY_SAFE_TOOLS as O, summarizeOutcomes as On, PLAN_AGENT as Or, BUILTIN_THEMES as Ot, readProjects as P, keybindingsPath as Pn, TODOWRITE_TOOL as Pr, CATPPUCCIN_LATTE as Pt, McpAuthProvider as Q, buildLinearRamp as Qn, PLAN_MODE_DOCTRINE as Qr, listSessionMeta as Qt, formatPathForCwd as R, readKeybindings as Rn, getArchivedTodosForRun as Rr, DiscoveryProvider as Rt, renderSession as S, maskToOutcomeKinds as Sn, openrouterDescriptor as Sr, DEFAULT_SETTINGS as St, SafeModeProvider as T, resolveApprovalForPayload as Tn, BUILTIN_AGENTS as Tr, SettingsProvider as Tt, indexOfEntry as U, FILES_TRIGGER as Un, selectActiveTodos as Ur, resolveConfig as Ut, buildModelCatalog as V, createSkillsCompletionProvider as Vn, pickActiveRunId as Vr, ConfigProvider as Vt, buildMcpServers as W, createFilesCompletionProvider as Wn, setTodosForRun as Wr, EDIT_TOOL_NAMES as Wt, mcpCredentialsPath as X, useCompletion as Xn, INTERACTION_GUIDANCE as Xr, isVisible as Xt, createFileMcpCredentialStore as Y, mergeReferences as Yn, IDENTITY_PREFIX as Yr, isTurnHighlighted as Yt, patchMcpCredential as Z, blendHsl as Zn, INTERACTION_GUIDANCE_NO_PROMPTS as Zr, lastContextSizeFromTurns as Zt, turnContextSize as _, previewEditPayload as _n, getContextWindow as _r, truncateTrailing as _t, computeTurnAnchors as a, titleFromTurns as an, credentialsPath as ar, InteractionsProvider as at, defaultSkillScanPaths as b, tokenize as bn, modelsForDescriptor as br, listProjectFiles as bt, formatToolCall as c, turnSelectionOwnership as cn, removeProviderCredential as cr, createInteractionTools as ct, useSelectStyle as d, buildContextualDiff as dn, BUILTIN_PROVIDERS as dr, pendingInteractionsFromTurns as dt, SUBAGENT_GUIDANCE as ei, marginTopFor as en, bootProfileEnabled as er, useMcpAuthState as et, useSurfaces as f, buildUnifiedDiff as fn, OUTPUT_RESERVE_TOKENS as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, filetypeFromPath as gn, effectiveContextWindow as gr, hintsLength as gt, finalizeStreamingMarkdown as h, extractEditPayload as hn, credKeyOf as hr, clipHintsToWidth as ht, turnAsText as i, envSection as ii, sumRunCosts as in, applyApiKeyEnv as ir, ASK_USER_TOOL as it, isOnSafelist as j, KEYBINDING_DEFS as jn, singleAgentRegistry as jr, resolveTheme as jt, addToSafelist as k, findGitRoot$1 as kn, accentColor as kr, DEFAULT_THEME as kt, ThemeProvider as l, updateToolEventOutcomes as ln, setProviderCredential as lr, isInteractionTool as lt, useTheme as m, computeLineDiff as mn, cerebrasDescriptor as mr, useInteractionsQueue as mt, deleteTurnSafely as n, buildBuildSystem as ni, selectableTurnIds as nn, shouldAutoCompact as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, toolCallPreview as on, readCredentials as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, computeInlineDiff as pn, anthropicDescriptor as pr, useInteractionsActions as pt, parseMcpsFile as q, collectReferences as qn, COMMUNICATION_DOCTRINE as qr, eventsFromTurns as qt, truncateTurnsAt as r, buildPlanSystem as ri, stripSpawnTokensLine as rn, detectAuth as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, toolResultText as sn, readProviderCredential as sr, buildResumedToolResultsTurn as st, countNeighbors as t, TOKEN_DISCIPLINE_DOCTRINE as ti, saveState as tn, bootTick as tr, getMcpAuthStatus as tt, useColors as u, applyEditPayload as un, writeCredentials as ur, makeRequestInteraction as ut, useStreamBuffer as v, splitLines as vn, getModelInfo as vr, cleanTitle as vt, writeSessionExport as w, parseEditOutcomesFromResult as wn, BUILD_AGENT as wr, SETTINGS_TOGGLES as wt, discoverProjectSkills as x, buildEditOutcomesAnnotation as xn, openaiDescriptor as xr, useEnabledToggleSet as xt, buildSkillsConfig as y, summarizeEditPayload as yn, modelSupportsReasoning as yr, generateSessionTitle as yt, runOAuthLogin as z, stripJsonComments as zn, getTodosForRun as zr, useDiscovery as zt };
8062
8349
 
8063
- //# sourceMappingURL=turn-operations-TKvy0q29.js.map
8350
+ //# sourceMappingURL=turn-operations-CtgBlBHn.js.map