zidane 5.2.1 → 5.3.1

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 (67) hide show
  1. package/README.md +7 -5
  2. package/dist/{agent-CGQajqtC.d.ts → agent-bKs7MRT2.d.ts} +429 -4
  3. package/dist/agent-bKs7MRT2.d.ts.map +1 -0
  4. package/dist/chat.d.ts +212 -58
  5. package/dist/chat.d.ts.map +1 -1
  6. package/dist/chat.js +2 -2
  7. package/dist/{errors-COmsomd5.js → errors-Byb0F8B9.js} +44 -2
  8. package/dist/errors-Byb0F8B9.js.map +1 -0
  9. package/dist/{index-DwbcFBr_.d.ts → index-BlMvPh9X.d.ts} +29 -3
  10. package/dist/index-BlMvPh9X.d.ts.map +1 -0
  11. package/dist/{index-BDP6mA3Y.d.ts → index-CTmNaIDb.d.ts} +2 -2
  12. package/dist/{index-BDP6mA3Y.d.ts.map → index-CTmNaIDb.d.ts.map} +1 -1
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +10 -10
  15. package/dist/{interpolate-BhmHKD6x.js → interpolate-ERgZUxgg.js} +2 -2
  16. package/dist/{interpolate-BhmHKD6x.js.map → interpolate-ERgZUxgg.js.map} +1 -1
  17. package/dist/{login-D7Tp-K5f.js → login-CNS9_8Ue.js} +3 -3
  18. package/dist/{login-D7Tp-K5f.js.map → login-CNS9_8Ue.js.map} +1 -1
  19. package/dist/{mcp-B1psg7jf.js → mcp-ZsSFo4Dp.js} +2 -2
  20. package/dist/{mcp-B1psg7jf.js.map → mcp-ZsSFo4Dp.js.map} +1 -1
  21. package/dist/mcp.d.ts +1 -1
  22. package/dist/mcp.js +1 -1
  23. package/dist/{messages-DsbMYNmt.js → messages-D0xT979U.js} +631 -68
  24. package/dist/messages-D0xT979U.js.map +1 -0
  25. package/dist/{presets-AgF0RFx1.js → presets-h5i3kpOP.js} +2 -2
  26. package/dist/{presets-AgF0RFx1.js.map → presets-h5i3kpOP.js.map} +1 -1
  27. package/dist/presets.d.ts +2 -2
  28. package/dist/presets.js +1 -1
  29. package/dist/{providers-v1Rn2rqG.js → providers-x3LZByR5.js} +38 -6
  30. package/dist/providers-x3LZByR5.js.map +1 -0
  31. package/dist/providers.d.ts +2 -2
  32. package/dist/providers.js +3 -3
  33. package/dist/session/sqlite.d.ts +1 -1
  34. package/dist/session/sqlite.js +1 -1
  35. package/dist/{session-DOJgRXvF.js → session-BHZwxmfr.js} +2 -2
  36. package/dist/{session-DOJgRXvF.js.map → session-BHZwxmfr.js.map} +1 -1
  37. package/dist/session.d.ts +1 -1
  38. package/dist/session.js +2 -2
  39. package/dist/skills.d.ts +2 -2
  40. package/dist/skills.js +1 -1
  41. package/dist/{tools-BRbbfdJh.js → tools-CWEDS2ZT.js} +251 -47
  42. package/dist/tools-CWEDS2ZT.js.map +1 -0
  43. package/dist/tools.d.ts +2 -2
  44. package/dist/tools.js +1 -1
  45. package/dist/{transcript-anchors-BBuIoU0x.d.ts → transcript-anchors-DOUqyvXR.d.ts} +28 -4
  46. package/dist/transcript-anchors-DOUqyvXR.d.ts.map +1 -0
  47. package/dist/tui.d.ts +29 -3
  48. package/dist/tui.d.ts.map +1 -1
  49. package/dist/tui.js +363 -28
  50. package/dist/tui.js.map +1 -1
  51. package/dist/{turn-operations-gJ0qtLPv.js → turn-operations-D9HvatsR.js} +396 -89
  52. package/dist/turn-operations-D9HvatsR.js.map +1 -0
  53. package/dist/types-IcokUOyC.js.map +1 -1
  54. package/dist/types.d.ts +2 -2
  55. package/dist/types.js +1 -1
  56. package/docs/ARCHITECTURE.md +3 -2
  57. package/docs/CHAT.md +55 -16
  58. package/docs/TUI.md +22 -2
  59. package/package.json +1 -1
  60. package/dist/agent-CGQajqtC.d.ts.map +0 -1
  61. package/dist/errors-COmsomd5.js.map +0 -1
  62. package/dist/index-DwbcFBr_.d.ts.map +0 -1
  63. package/dist/messages-DsbMYNmt.js.map +0 -1
  64. package/dist/providers-v1Rn2rqG.js.map +0 -1
  65. package/dist/tools-BRbbfdJh.js.map +0 -1
  66. package/dist/transcript-anchors-BBuIoU0x.d.ts.map +0 -1
  67. package/dist/turn-operations-gJ0qtLPv.js.map +0 -1
@@ -1,11 +1,11 @@
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-BRbbfdJh.js";
2
- import { o as errorMessage } from "./errors-COmsomd5.js";
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-CWEDS2ZT.js";
2
+ import { s as errorMessage } from "./errors-Byb0F8B9.js";
3
3
  import { n as toolResultToText } from "./types-IcokUOyC.js";
4
- import { r as normalizeMcpServers } from "./mcp-B1psg7jf.js";
5
- import { a as discoverSkills } from "./interpolate-BhmHKD6x.js";
4
+ import { r as normalizeMcpServers } from "./mcp-ZsSFo4Dp.js";
5
+ import { a as discoverSkills } from "./interpolate-ERgZUxgg.js";
6
6
  import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
7
- import { n as definePreset, t as composePresets } from "./presets-AgF0RFx1.js";
8
- import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-v1Rn2rqG.js";
7
+ import { n as definePreset, t as composePresets } from "./presets-h5i3kpOP.js";
8
+ import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-x3LZByR5.js";
9
9
  import { spawn } from "node:child_process";
10
10
  import { readdir, stat, writeFile } from "node:fs/promises";
11
11
  import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
@@ -260,90 +260,197 @@ const TODOREAD_TOOL = "todoread";
260
260
  function isTodoTool(name) {
261
261
  return name === "todowrite" || name === "todoread";
262
262
  }
263
- /** `session.metadata[TODOS_METADATA_KEY]: Record<runId, TodoItem[]>` */
264
- const TODOS_METADATA_KEY = "todosByRun";
265
- /** `session.metadata[TODO_WRITE_COUNTS_METADATA_KEY]: Record<runId, number>` */
266
- const TODO_WRITE_COUNTS_METADATA_KEY = "todoWriteCountsByRun";
263
+ /** `session.metadata[TODOS_METADATA_KEY]: TodosBag` see {@link TodosBag}. */
264
+ const TODOS_METADATA_KEY = "todos";
265
+ /** `session.metadata[TODO_WRITE_COUNTS_METADATA_KEY]: CountsBag` mirrors `TodosBag` shape. */
266
+ const TODO_WRITE_COUNTS_METADATA_KEY = "todoWriteCounts";
267
267
  const TODO_STATUS_VALUES = [
268
268
  "pending",
269
269
  "in_progress",
270
270
  "completed",
271
271
  "cancelled"
272
272
  ];
273
- const WRITE_DESCRIPTION = "Replace the active task list. Pass the **full** list of items every call — there is no partial update. Use the `status` field to track progress: `pending` (queued), `in_progress` (currently working), `completed` (done), `cancelled` (no longer relevant).\n\nOnly checkpoint at significant transitions:\n 1. When the user gives you a multi-step task — write the initial plan with everything `pending`.\n 2. When you transition between steps — mark the previous one `completed` and the next one `in_progress`.\n 3. When the user asks for the current status — re-emit the list unchanged so they can see it.\n\nDo NOT call this on every action. The list is for the user's situational awareness, not for self-narrating.";
274
- const READ_DESCRIPTION = "Return the current active task list (the one most recently written by `todowrite` in this run). Returns an empty list if nothing has been written yet. Use sparingly — you already see the latest list in your own `todowrite` tool_result above.";
273
+ const TODO_STATUS_GLYPHS = {
274
+ pending: "",
275
+ in_progress: "◐",
276
+ completed: "☑",
277
+ cancelled: "☒"
278
+ };
279
+ const WRITE_DESCRIPTION = "Replace the active task list. Pass the **full** list of items every call — there is no partial update. The list persists across user prompts in the same session, so an aborted run with `in_progress` items reads back on the next `todoread` and you can pick up where you left off. When every item is `completed`, the list auto-clears so the next prompt starts fresh.\n\nUse the `status` field to track progress: `pending` (queued), `in_progress` (currently working), `completed` (done), `cancelled` (no longer relevant).\n\nOnly checkpoint at significant transitions:\n 1. When the user gives you a multi-step task — write the initial plan with everything `pending`.\n 2. When you transition between steps — mark the previous one `completed` and the next one `in_progress`.\n 3. When the user asks for the current status — re-emit the list unchanged so they can see it.\n\nDo NOT call this on every action. The list is for the user's situational awareness, not for self-narrating.";
280
+ const READ_DESCRIPTION = "Return the current active task list. Returns an empty list if nothing has been written yet, or if the previous batch was auto-cleared after all items completed. Use sparingly — you already see the latest list in your own `todowrite` tool_result above.";
275
281
  function defaultReminder(count) {
276
- return `(You've called todowrite ${count} times in this run. Make sure each checkpoint reflects real progress; avoid re-planning every step.)`;
282
+ return `(You've called todowrite ${count} times. Make sure each checkpoint reflects real progress; avoid re-planning every step.)`;
277
283
  }
278
284
  /**
279
- * Read the active list for a given run. Returns a fresh `[]` (not stored
280
- * in metadata) when no slot exists the caller can mutate the result
285
+ * `true` when the run with `runId` is a subagent (has a `parentRunId`).
286
+ * Top-level runs return `false`; an unknown / missing run also returns
287
+ * `false` (defensive — should never happen in practice, but treating an
288
+ * orphan as top-level is the right fallback since the session slot is
289
+ * the more general bucket).
290
+ */
291
+ function isSubagentRun(session, runId) {
292
+ return !!session.runs.find((r) => r.id === runId)?.parentRunId;
293
+ }
294
+ /**
295
+ * Read the active list for `runId`. Top-level runs see the session-shared
296
+ * slot; subagent runs see their own. Returns a fresh `[]` (not stored in
297
+ * metadata) when no slot exists — the caller can mutate the result
281
298
  * without affecting state.
282
299
  */
283
300
  function getTodosForRun(session, runId) {
284
- const items = readTodosBag(session)[runId];
285
- return Array.isArray(items) ? [...items] : [];
301
+ const bag = readTodosBag(session);
302
+ if (isSubagentRun(session, runId)) {
303
+ const items = bag.byRun?.[runId];
304
+ return Array.isArray(items) ? [...items] : [];
305
+ }
306
+ return Array.isArray(bag.session) ? [...bag.session] : [];
286
307
  }
287
308
  /**
288
- * Replace the active list for a given run. Empty arrays don't create a
289
- * slot see the file-level "empty-payload guard" note.
309
+ * Replace the active list for `runId`. Routes to the session-shared slot
310
+ * for top-level runs and to the per-run slot for subagents. Empty arrays
311
+ * delete the slot entirely so persisted metadata stays clean.
312
+ *
313
+ * Side effect: a **non-empty** write also stashes the same list into
314
+ * `bag.archive` (same routing). Empty writes never touch the archive —
315
+ * clearing the live list (whether explicitly or via the tool's auto-
316
+ * clear) preserves the "last shown" snapshot so UI surfaces can keep
317
+ * rendering what was just completed. See {@link getArchivedTodosForRun}.
290
318
  */
291
319
  function setTodosForRun(session, runId, items) {
292
- const bag = { ...readTodosBag(session) };
293
- if (items.length === 0) delete bag[runId];
294
- else bag[runId] = items.map(normalizeItem);
295
- session.setMeta(TODOS_METADATA_KEY, bag);
320
+ const bag = readTodosBag(session);
321
+ const normalized = items.map(normalizeItem);
322
+ const subagent = isSubagentRun(session, runId);
323
+ if (subagent) {
324
+ const byRun = { ...bag.byRun ?? {} };
325
+ if (normalized.length === 0) delete byRun[runId];
326
+ else byRun[runId] = normalized;
327
+ bag.byRun = byRun;
328
+ } else if (normalized.length === 0) delete bag.session;
329
+ else bag.session = normalized;
330
+ if (normalized.length > 0) {
331
+ const archive = { ...bag.archive ?? {} };
332
+ if (subagent) {
333
+ const archiveByRun = { ...archive.byRun ?? {} };
334
+ archiveByRun[runId] = normalized;
335
+ archive.byRun = archiveByRun;
336
+ } else archive.session = normalized;
337
+ bag.archive = archive;
338
+ }
339
+ writeTodosBag(session, bag);
296
340
  }
297
341
  /**
298
- * Reconcile `session.metadata.todosByRun` against `session.runs`. Drops
299
- * keys whose runId isn't in the run list. Useful after `session.setRuns()`
300
- * (fork / restore) or to GC stale metadata mutated by an external caller.
342
+ * Read the archived (most-recent non-empty) list for `runId`. Same slot
343
+ * routing as {@link getTodosForRun}, but reads `bag.archive` instead of
344
+ * the live slot. Returns a fresh `[]` when no archive exists.
301
345
  *
302
- * Also prunes the parallel counter bag so it doesn't drift.
346
+ * UI surfaces use this to keep showing "what was just completed" after
347
+ * the live list auto-clears. The model never sees the archive — it's a
348
+ * read-only sidecar for human-facing rendering.
349
+ */
350
+ function getArchivedTodosForRun(session, runId) {
351
+ const archive = readTodosBag(session).archive;
352
+ if (!archive) return [];
353
+ if (isSubagentRun(session, runId)) {
354
+ const items = archive.byRun?.[runId];
355
+ return Array.isArray(items) ? [...items] : [];
356
+ }
357
+ return Array.isArray(archive.session) ? [...archive.session] : [];
358
+ }
359
+ /**
360
+ * Reconcile `session.metadata.todos.byRun` (live + archive) against
361
+ * `session.runs`. Drops subagent slots whose runId isn't in the run
362
+ * list. The top-level `session` slot is unaffected — it's session-
363
+ * scoped, not per-run, so there's no orphan to GC.
364
+ *
365
+ * Useful after `session.setRuns()` (fork / restore) or to GC stale
366
+ * metadata mutated by an external caller. Also prunes the parallel
367
+ * counter bag so the two don't drift.
368
+ *
369
+ * `dropped` reports the live-byRun orphans only (archive-only orphans
370
+ * are silently swept). The live half is the contract callers actually
371
+ * observe.
303
372
  */
304
373
  function pruneTodosByRun(session) {
305
374
  const validRunIds = new Set(session.runs.map((r) => r.id));
306
375
  const dropped = [];
307
376
  const bag = readTodosBag(session);
308
- const nextBag = {};
309
- for (const [runId, items] of Object.entries(bag)) if (validRunIds.has(runId)) nextBag[runId] = items;
310
- else dropped.push(runId);
311
- if (dropped.length > 0) session.setMeta(TODOS_METADATA_KEY, nextBag);
377
+ let bagChanged = false;
378
+ if (bag.byRun) {
379
+ const nextByRun = {};
380
+ for (const [runId, items] of Object.entries(bag.byRun)) if (validRunIds.has(runId)) nextByRun[runId] = items;
381
+ else {
382
+ dropped.push(runId);
383
+ bagChanged = true;
384
+ }
385
+ if (Object.keys(nextByRun).length !== Object.keys(bag.byRun).length) bag.byRun = nextByRun;
386
+ }
387
+ if (bag.archive?.byRun) {
388
+ const nextByRun = {};
389
+ let archiveChanged = false;
390
+ for (const [runId, items] of Object.entries(bag.archive.byRun)) if (validRunIds.has(runId)) nextByRun[runId] = items;
391
+ else archiveChanged = true;
392
+ if (archiveChanged) {
393
+ bag.archive = {
394
+ ...bag.archive,
395
+ byRun: nextByRun
396
+ };
397
+ bagChanged = true;
398
+ }
399
+ }
400
+ if (bagChanged) writeTodosBag(session, bag);
312
401
  const counts = readCountsBag(session);
313
- const nextCounts = {};
314
- let countsChanged = false;
315
- for (const [runId, n] of Object.entries(counts)) if (validRunIds.has(runId)) nextCounts[runId] = n;
316
- else countsChanged = true;
317
- if (countsChanged) session.setMeta(TODO_WRITE_COUNTS_METADATA_KEY, nextCounts);
402
+ if (counts.byRun) {
403
+ const nextByRun = {};
404
+ let changed = false;
405
+ for (const [runId, n] of Object.entries(counts.byRun)) if (validRunIds.has(runId)) nextByRun[runId] = n;
406
+ else changed = true;
407
+ if (changed) {
408
+ counts.byRun = nextByRun;
409
+ writeCountsBag(session, counts);
410
+ }
411
+ }
318
412
  return { dropped };
319
413
  }
320
414
  /**
321
- * Build a `Preset` carrying the `{ todowrite, todoread }` tool pair plus the
322
- * per-run write budget that caps the model's checkpoint frequency. Identical-
323
- * payload dedup is handled inside the tool body (run-scoped) and intentionally
324
- * does NOT plumb through `behavior.dedupTools` see the `dedupIdentical`
325
- * option doc for the rationale.
326
- *
327
- * Returning a `Preset` (not a bare tool map) lets the result flow through
328
- * {@link composePresets} unchanged todos compose with any other preset
329
- * the same way every other preset does. `toolBudgets` is a tool-name-keyed
330
- * record that `composePresets` deep-merges, so a caller's custom budget
331
- * entries for other tools survive the layering, and a caller's override
332
- * for `todowrite` itself wins by being placed later in the chain.
415
+ * Build a `Preset` carrying the `{ todowrite, todoread }` tool pair.
416
+ * Identical-payload dedup is handled inside the tool body the
417
+ * comparison resolves against the active slot (session-shared for
418
+ * top-level runs, per-run for subagents) and intentionally does NOT
419
+ * plumb through `behavior.dedupTools`. See the `dedupIdentical` option
420
+ * doc for the rationale.
421
+ *
422
+ * By default the preset adds **no** `toolBudgets` entry `todowrite`
423
+ * is a state-transition tool, so a hard cap is the wrong abstraction
424
+ * (it punishes the legitimate "finish the N-item plan" path). Hosts
425
+ * that want a ceiling pass `maxWritesPerRun: N` explicitly; the
426
+ * factory then plumbs a `behavior.toolBudgets.todowrite` entry
427
+ * through.
428
+ *
429
+ * Returning a `Preset` (not a bare tool map) lets the result flow
430
+ * through {@link composePresets} unchanged — todos compose with any
431
+ * other preset the same way every other preset does. `toolBudgets` is
432
+ * a tool-name-keyed record that `composePresets` deep-merges, so a
433
+ * caller's custom budget entries for other tools survive the
434
+ * layering, and a caller's override for `todowrite` itself wins by
435
+ * being placed later in the chain.
333
436
  *
334
437
  * ```ts
335
438
  * import { basic, composePresets } from 'zidane/presets'
336
439
  * import { createTodoTools } from 'zidane/chat'
337
440
  *
441
+ * // Default: no budget — relies on the in-band reminder + dedup.
442
+ * createAgent({ ...composePresets(basic, createTodoTools()), provider })
443
+ *
444
+ * // Opt-in hard cap: refuse > 20 writes per run.
338
445
  * createAgent({
339
- * ...composePresets(basic, createTodoTools({ maxWritesPerRun: 6 })),
446
+ * ...composePresets(basic, createTodoTools({ maxWritesPerRun: 20 })),
340
447
  * provider,
341
448
  * })
342
449
  * ```
343
450
  *
344
451
  * For the trivial "just add the tools to an existing config" case, plain
345
- * spread is also fine since the returned `Preset` only sets `tools` +
346
- * `behavior`:
452
+ * spread is also fine since the returned `Preset` only sets `tools`
453
+ * (and `behavior` when a budget is opted in):
347
454
  *
348
455
  * ```ts
349
456
  * createAgent({ ...basic, ...createTodoTools(), provider })
@@ -354,7 +461,7 @@ function createTodoTools(options = {}) {
354
461
  const remindAfter = options.remindAfter ?? 3;
355
462
  const reminderText = options.reminderText ?? ((count, _items) => defaultReminder(count));
356
463
  const dedupIdentical = options.dedupIdentical ?? true;
357
- const maxWritesPerRun = options.maxWritesPerRun ?? 6;
464
+ const maxWritesPerRun = options.maxWritesPerRun ?? 0;
358
465
  const onMaxWrites = options.onMaxWrites ?? "steer";
359
466
  const tools = {
360
467
  [TODOWRITE_TOOL]: createTodoWriteTool({
@@ -425,25 +532,34 @@ function createTodoWriteTool(opts) {
425
532
  const current = getTodosForRun(session, runId);
426
533
  const unchanged = opts.dedupIdentical && todosEqual(current, normalized);
427
534
  const count = incrementCount(session, runId);
428
- if (!unchanged) setTodosForRun(session, runId, normalized);
535
+ const allCompleted = normalized.length > 0 && normalized.every((t) => t.status === "completed");
536
+ if (!unchanged) if (allCompleted) {
537
+ setTodosForRun(session, runId, normalized);
538
+ setTodosForRun(session, runId, []);
539
+ } else setTodosForRun(session, runId, normalized);
429
540
  return formatWriteResult({
430
541
  items: normalized,
431
542
  dropped,
432
543
  count,
433
544
  unchanged,
545
+ cleared: allCompleted && !unchanged,
434
546
  opts
435
547
  });
436
548
  }
437
549
  };
438
550
  }
439
551
  function formatWriteResult(input) {
440
- const { items, dropped, count, unchanged, opts } = input;
552
+ const { items, dropped, count, unchanged, cleared, opts } = input;
441
553
  const lines = [];
442
554
  const n = items.length;
443
555
  const suffix = n === 1 ? "" : "s";
444
- lines.push(unchanged ? `No change — ${n} todo item${suffix} already tracked.` : `Updated ${n} todo item${suffix}.`);
445
- const tally = summarizeStatuses(items);
446
- if (tally) lines.push(tally);
556
+ if (cleared) lines.push(`Marked ${n} item${suffix} complete list cleared.`);
557
+ else if (unchanged) lines.push(`No change — ${n} todo item${suffix} already tracked.`);
558
+ else lines.push(`Updated ${n} todo item${suffix}.`);
559
+ if (!cleared) {
560
+ const tally = summarizeStatuses(items);
561
+ if (tally) lines.push(tally);
562
+ }
447
563
  if (dropped > 0) lines.push(`Dropped ${dropped} malformed item${dropped === 1 ? "" : "s"}.`);
448
564
  const reminder = opts.remindAfter > 0 && count >= opts.remindAfter ? opts.reminderText(count, items) : void 0;
449
565
  if (reminder && reminder.length > 0) lines.push(reminder);
@@ -479,23 +595,74 @@ function requireSessionAndRun(ctx, toolName) {
479
595
  runId: ctx.runId
480
596
  };
481
597
  }
598
+ /** Read the todos bag from session metadata, normalizing the live shape. */
482
599
  function readTodosBag(session) {
483
600
  const raw = session.metadata[TODOS_METADATA_KEY];
484
- if (!raw || typeof raw !== "object") return {};
485
- return raw;
601
+ if (!isPlainObject(raw)) return {};
602
+ const archive = isPlainObject(raw.archive) ? {
603
+ session: Array.isArray(raw.archive.session) ? raw.archive.session : void 0,
604
+ byRun: isPlainObject(raw.archive.byRun) ? raw.archive.byRun : void 0
605
+ } : void 0;
606
+ return {
607
+ session: Array.isArray(raw.session) ? raw.session : void 0,
608
+ byRun: isPlainObject(raw.byRun) ? raw.byRun : void 0,
609
+ archive
610
+ };
611
+ }
612
+ function writeTodosBag(session, bag) {
613
+ const clean = {};
614
+ if (bag.session && bag.session.length > 0) clean.session = bag.session;
615
+ if (bag.byRun && Object.keys(bag.byRun).length > 0) clean.byRun = bag.byRun;
616
+ if (bag.archive) {
617
+ const archive = {};
618
+ if (bag.archive.session && bag.archive.session.length > 0) archive.session = bag.archive.session;
619
+ if (bag.archive.byRun && Object.keys(bag.archive.byRun).length > 0) archive.byRun = bag.archive.byRun;
620
+ if (archive.session || archive.byRun) clean.archive = archive;
621
+ }
622
+ session.setMeta(TODOS_METADATA_KEY, clean);
486
623
  }
487
624
  function readCountsBag(session) {
488
625
  const raw = session.metadata[TODO_WRITE_COUNTS_METADATA_KEY];
489
- if (!raw || typeof raw !== "object") return {};
490
- return raw;
626
+ if (!isPlainObject(raw)) return {};
627
+ return {
628
+ session: typeof raw.session === "number" ? raw.session : void 0,
629
+ byRun: isPlainObject(raw.byRun) ? raw.byRun : void 0
630
+ };
491
631
  }
632
+ function writeCountsBag(session, bag) {
633
+ const clean = {};
634
+ if (typeof bag.session === "number" && bag.session > 0) clean.session = bag.session;
635
+ if (bag.byRun && Object.keys(bag.byRun).length > 0) clean.byRun = bag.byRun;
636
+ session.setMeta(TODO_WRITE_COUNTS_METADATA_KEY, clean);
637
+ }
638
+ /**
639
+ * Bump the call counter for the active slot and return the new value.
640
+ * Top-level runs increment `bag.session` (cumulative across prompts);
641
+ * subagent runs increment their own entry under `bag.byRun`. Same
642
+ * keying as {@link setTodosForRun} so the counter and the data move
643
+ * together — a freshly seeded run's count starts at 1 on its first
644
+ * write, a continuing top-level run's count picks up from where the
645
+ * prior prompt left off.
646
+ */
492
647
  function incrementCount(session, runId) {
493
- const bag = { ...readCountsBag(session) };
494
- const next = (bag[runId] ?? 0) + 1;
495
- bag[runId] = next;
496
- session.setMeta(TODO_WRITE_COUNTS_METADATA_KEY, bag);
648
+ const bag = readCountsBag(session);
649
+ let next;
650
+ if (isSubagentRun(session, runId)) {
651
+ const byRun = { ...bag.byRun ?? {} };
652
+ next = (byRun[runId] ?? 0) + 1;
653
+ byRun[runId] = next;
654
+ bag.byRun = byRun;
655
+ } else {
656
+ next = (bag.session ?? 0) + 1;
657
+ bag.session = next;
658
+ }
659
+ writeCountsBag(session, bag);
497
660
  return next;
498
661
  }
662
+ /** Narrow guard — `Record<string, unknown>` excluding arrays / null. */
663
+ function isPlainObject(v) {
664
+ return !!v && typeof v === "object" && !Array.isArray(v);
665
+ }
499
666
  function normalizeItem(item) {
500
667
  return {
501
668
  id: item.id,
@@ -557,6 +724,109 @@ function todosEqual(a, b) {
557
724
  }
558
725
  return true;
559
726
  }
727
+ const EMPTY_TALLY = {
728
+ pending: 0,
729
+ in_progress: 0,
730
+ completed: 0,
731
+ cancelled: 0
732
+ };
733
+ const EMPTY_ACTIVE = {
734
+ runId: null,
735
+ todos: [],
736
+ archive: [],
737
+ inProgress: null,
738
+ tally: EMPTY_TALLY
739
+ };
740
+ /**
741
+ * Pick the "active" run for UI surfaces that show one slot at a time
742
+ * (todos indicator, todos modal, footer ctx indicator). The resolved
743
+ * runId then routes through {@link getTodosForRun} — top-level runs
744
+ * land on the session-shared slot, subagent runs on their own.
745
+ *
746
+ * - A currently-running run wins (latest-started one if several).
747
+ * - Otherwise the most recently appended run wins.
748
+ * - `null` when the session has no runs.
749
+ *
750
+ * Mirrors the "most recent thing that mattered" policy that drives
751
+ * `lastContextSizeFromTurns` — but walks `session.runs` rather than
752
+ * `session.turns` because the active todo slot is a function of the
753
+ * run, not of message history.
754
+ */
755
+ function pickActiveRunId(session) {
756
+ if (!session) return null;
757
+ const runs = session.runs;
758
+ if (!runs || runs.length === 0) return null;
759
+ let latestRunning = null;
760
+ for (let i = runs.length - 1; i >= 0; i--) if (runs[i].status === "running") {
761
+ latestRunning = runs[i].id;
762
+ break;
763
+ }
764
+ if (latestRunning) return latestRunning;
765
+ return runs[runs.length - 1].id;
766
+ }
767
+ /**
768
+ * Pure selector — derive the active-todos state from a session snapshot.
769
+ * Used by {@link useActiveTodos} and directly testable without React.
770
+ *
771
+ * Resolves both `todos` (live, model-facing) and `archive` (last
772
+ * non-empty snapshot for UI fallback). The tally folds over whichever
773
+ * list is non-empty; `inProgress` is sourced strictly from `todos`
774
+ * because an archived in-progress item is by definition stale.
775
+ */
776
+ function selectActiveTodos(session) {
777
+ const runId = pickActiveRunId(session);
778
+ if (!session || !runId) return EMPTY_ACTIVE;
779
+ const todos = getTodosForRun(session, runId);
780
+ const archive = getArchivedTodosForRun(session, runId);
781
+ const display = todos.length > 0 ? todos : archive;
782
+ if (display.length === 0) return {
783
+ runId,
784
+ todos,
785
+ archive,
786
+ inProgress: null,
787
+ tally: EMPTY_TALLY
788
+ };
789
+ const tally = {
790
+ pending: 0,
791
+ in_progress: 0,
792
+ completed: 0,
793
+ cancelled: 0
794
+ };
795
+ let inProgress = null;
796
+ for (const t of display) tally[t.status] += 1;
797
+ if (todos.length > 0) {
798
+ for (const t of todos) if (t.status === "in_progress") {
799
+ inProgress = t;
800
+ break;
801
+ }
802
+ }
803
+ return {
804
+ runId,
805
+ todos,
806
+ archive,
807
+ inProgress,
808
+ tally
809
+ };
810
+ }
811
+ /**
812
+ * React hook — active-todos state for the supplied session. Recomputes
813
+ * on every parent re-render; the work is O(runs + todos), both bounded
814
+ * by small constants in practice.
815
+ *
816
+ * Why no memoization: `Session.runs` is mutated in place by `completeRun`
817
+ * / `abortRun` (status flips without changing array length or item
818
+ * identity), so any memo keyed off length / bag identity would silently
819
+ * return stale state when e.g. a child subagent run completes and the
820
+ * "active" run should reflow to the parent. The selector is cheap
821
+ * enough that running it every parent render is the simpler, correct
822
+ * answer — see `selectActiveTodos` for the O(n) cost.
823
+ *
824
+ * The hook lives in `chat/` so a GUI consumer can mount it verbatim.
825
+ * Renderer-agnostic — no `@opentui/*` imports.
826
+ */
827
+ function useActiveTodos(session) {
828
+ return selectActiveTodos(session);
829
+ }
560
830
  //#endregion
561
831
  //#region src/chat/agents.ts
562
832
  /**
@@ -1855,6 +2125,12 @@ const KEYBINDING_DEFS = [
1855
2125
  label: "effort",
1856
2126
  description: "open the reasoning-effort picker (when the active model supports it)"
1857
2127
  },
2128
+ {
2129
+ action: "openTodos",
2130
+ default: "ctrl+t",
2131
+ label: "todos",
2132
+ description: "open the active run's todo list (the agent's `todowrite` checkpoints)"
2133
+ },
1858
2134
  {
1859
2135
  action: "cycleAgent",
1860
2136
  default: "shift+tab",
@@ -2906,10 +3182,6 @@ function eventsFromTurns(turns, runs = []) {
2906
3182
  pushSpawnStart(run);
2907
3183
  openStack.push(run);
2908
3184
  }
2909
- if (depth === 0 && lastDepthAtEmission === 0) events.push({
2910
- kind: "separator",
2911
- text: ""
2912
- });
2913
3185
  const subagentTag = depth > 0 && turn.runId ? {
2914
3186
  childId: labelFor(turn.runId),
2915
3187
  depth
@@ -2920,11 +3192,17 @@ function eventsFromTurns(turns, runs = []) {
2920
3192
  };
2921
3193
  if (turn.role === "user") {
2922
3194
  for (const block of turn.content) if (block.type === "text" && block.text.trim()) {
2923
- if (depth === 0) events.push({
2924
- kind: "user-prompt",
2925
- text: block.text,
2926
- turnId: turn.id
2927
- });
3195
+ if (depth === 0) {
3196
+ if (lastDepthAtEmission === 0) events.push({
3197
+ kind: "separator",
3198
+ text: ""
3199
+ });
3200
+ events.push({
3201
+ kind: "user-prompt",
3202
+ text: block.text,
3203
+ turnId: turn.id
3204
+ });
3205
+ }
2928
3206
  } else if (block.type === "tool_result") {
2929
3207
  const tool = toolByCallId.get(block.callId);
2930
3208
  const raw = toolResultText(block.output);
@@ -4444,7 +4722,9 @@ const DEFAULT_SETTINGS = {
4444
4722
  showEditDiffs: true,
4445
4723
  targetFps: 60,
4446
4724
  allowInteraction: true,
4447
- smoothStreaming: true
4725
+ smoothStreaming: true,
4726
+ showTodoIndicator: true,
4727
+ showThrobber: false
4448
4728
  };
4449
4729
  /**
4450
4730
  * Hard-clamp a `targetFps` value to a safe range before handing it to
@@ -4559,6 +4839,16 @@ const SETTINGS_TOGGLES = [
4559
4839
  key: "smoothStreaming",
4560
4840
  label: "Smooth streaming",
4561
4841
  description: "drip-feed streamed text character-by-character at a steady cadence (typewriter effect)"
4842
+ },
4843
+ {
4844
+ key: "showTodoIndicator",
4845
+ label: "Todo indicator",
4846
+ description: "show the subtle \"in progress\" todo line above the prompt (modal stays accessible regardless)"
4847
+ },
4848
+ {
4849
+ key: "showThrobber",
4850
+ label: "Streaming throbber",
4851
+ description: "animated gradient glyphs at the transcript tail while the assistant is working"
4562
4852
  }
4563
4853
  ];
4564
4854
  const SETTINGS_CHOICES = [
@@ -6288,7 +6578,7 @@ function getSafelist(dataDir, projectDir) {
6288
6578
  return readProjects(dataDir)[projectDir]?.safelist ?? [];
6289
6579
  }
6290
6580
  /**
6291
- * Tools that always pass without prompting. Two categories:
6581
+ * Tools that always pass without prompting. Three categories:
6292
6582
  *
6293
6583
  * - **Pure reads** (`read_file`, `list_files`, `glob`, `grep`) — no
6294
6584
  * side effects on disk or the model's own state.
@@ -6296,6 +6586,12 @@ function getSafelist(dataDir, projectDir) {
6296
6586
  * itself surfaces a TUI picker the user has to answer, so prompting
6297
6587
  * for approval first would mean "approve this prompt before you see
6298
6588
  * the prompt": redundant + breaks the flow. The picker IS the gate.
6589
+ * - **Todos** (`todowrite`, `todoread`) — write to a slot on
6590
+ * `session.metadata.todos` and nothing else. No shell, no disk, no
6591
+ * network. The model uses these for checkpointing every few steps;
6592
+ * a per-call approval prompt would drown the conversation in
6593
+ * interruptions that buy no safety since the tool's surface is
6594
+ * read/write on a metadata bag we already trust the agent with.
6299
6595
  *
6300
6596
  * Users who want to gate any of these must disable safe-mode entirely
6301
6597
  * (or fork this list in their own embedding).
@@ -6306,7 +6602,9 @@ const IMPLICITLY_SAFE_TOOLS = [
6306
6602
  "glob",
6307
6603
  "grep",
6308
6604
  "ask_user",
6309
- "present_plan"
6605
+ "present_plan",
6606
+ "todowrite",
6607
+ "todoread"
6310
6608
  ];
6311
6609
  /** Common input keys carrying the "primary argument" we scope safelists on. */
6312
6610
  const PRIMARY_ARG_KEYS = [
@@ -6822,15 +7120,16 @@ const TICK_INTERVAL_MS = 16;
6822
7120
  /**
6823
7121
  * Smooth-streaming display rate, in characters per second.
6824
7122
  *
6825
- * - {@link SMOOTH_BASE_CPS} — the cap for "calm" streaming, when the
6826
- * buffer is close to caught-up to the provider. ~200 CPS is a fast
6827
- * typist's pace; comfortably readable without feeling like a deliberate
7123
+ * - {@link SMOOTH_BASE_CPS} — calm-state cap. ~200 CPS is a fast typist's
7124
+ * pace; comfortably readable without feeling like a deliberate
6828
7125
  * typewriter performance.
6829
- * - {@link SMOOTH_BURST_CPS} — when the buffer has been falling behind
6830
- * the provider (backlog > {@link SMOOTH_BURST_BACKLOG_CHARS}), the
6831
- * ticker accelerates to drain ~3x as fast. Keeps the typewriter feel
6832
- * while preventing the display from lagging multiple seconds behind
6833
- * the actual response.
7126
+ * - {@link SMOOTH_BURST_CPS} — cap once the buffer is the full
7127
+ * {@link SMOOTH_BURST_BACKLOG_CHARS} behind the provider. The rate
7128
+ * ramps continuously from base to burst across that range (see
7129
+ * {@link smoothCharsForTick}) so the typewriter cadence never visibly
7130
+ * "steps up" mid-stream — the old step function (BASE for <100,
7131
+ * BURST for ≥100) tripled the chars-per-frame the instant the
7132
+ * threshold was crossed, which read as the text jumping.
6834
7133
  * - {@link SMOOTH_INSTANT_BACKLOG_CHARS} — failsafe. If the buffer
6835
7134
  * somehow accumulates >2K chars (paste-heavy responses, model dumping
6836
7135
  * pre-computed text, etc.) the ticker stops smoothing entirely for
@@ -6839,7 +7138,7 @@ const TICK_INTERVAL_MS = 16;
6839
7138
  */
6840
7139
  const SMOOTH_BASE_CPS = 200;
6841
7140
  const SMOOTH_BURST_CPS = 600;
6842
- const SMOOTH_BURST_BACKLOG_CHARS = 100;
7141
+ const SMOOTH_BURST_BACKLOG_CHARS = 400;
6843
7142
  const SMOOTH_INSTANT_BACKLOG_CHARS = 2e3;
6844
7143
  const PARENT_OWNER = "parent";
6845
7144
  function emptyBucket(owner, depth) {
@@ -6963,11 +7262,19 @@ function turnContextSize(usage) {
6963
7262
  * current backlog of one bucket. Caps at the bucket length (never
6964
7263
  * over-drains) and bypasses smoothing entirely once the backlog goes
6965
7264
  * past {@link SMOOTH_INSTANT_BACKLOG_CHARS}.
7265
+ *
7266
+ * The CPS ramps continuously from {@link SMOOTH_BASE_CPS} at zero backlog
7267
+ * to {@link SMOOTH_BURST_CPS} at {@link SMOOTH_BURST_BACKLOG_CHARS},
7268
+ * then plateaus at burst up to the instant cliff. Continuous (vs. the
7269
+ * legacy step at the burst threshold) so the chars-per-frame count never
7270
+ * jumps mid-stream — visible jumps in the typewriter cadence read as the
7271
+ * text itself jumping.
6966
7272
  */
6967
7273
  function smoothCharsForTick(backlog) {
6968
7274
  if (backlog <= 0) return 0;
6969
7275
  if (backlog >= SMOOTH_INSTANT_BACKLOG_CHARS) return backlog;
6970
- return Math.max(1, Math.min(backlog, Math.ceil((backlog >= SMOOTH_BURST_BACKLOG_CHARS ? SMOOTH_BURST_CPS : SMOOTH_BASE_CPS) * TICK_INTERVAL_MS / 1e3)));
7276
+ const cps = SMOOTH_BASE_CPS + Math.min(1, backlog / SMOOTH_BURST_BACKLOG_CHARS) * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS);
7277
+ return Math.max(1, Math.min(backlog, Math.ceil(cps * TICK_INTERVAL_MS / 1e3)));
6971
7278
  }
6972
7279
  /**
6973
7280
  * Slice `n` chars off the front of `buf` without splitting a UTF-16
@@ -7626,6 +7933,6 @@ function countNeighbors(turnIds, turnId) {
7626
7933
  };
7627
7934
  }
7628
7935
  //#endregion
7629
- export { useMcpAuthDispatch as $, bootTick as $n, isVisible as $t, getSafelist as A, KEYBINDING_DEF_BY_ACTION as An, TODOREAD_TOOL as Ar, clampFps as At, supportsOAuth as B, uniqueSkillNamesFromReferences as Bn, COMMUNICATION_DOCTRINE as Br, CATPPUCCIN_MOCHA as Bt, resolveSessionExportTarget as C, maskToOutcomeKinds as Cn, BUILTIN_AGENTS as Cr, shortId as Ct, useSafeModeQueue as D, findGitRoot$1 as Dn, accentColor as Dr, SETTINGS_CHOICES as Dt, useSafeModeActions as E, summarizeOutcomes as En, PLAN_AGENT as Er, DEFAULT_SETTINGS as Et, suggestSafelistEntry as F, parseBindingSpec as Fn, getTodosForRun as Fr, resolveTheme as Ft, defaultMcpsConfigPaths as G, collectReferences as Gn, PLAN_MODE_DOCTRINE as Gr, ConfigProvider as Gt, filterModelCatalog as H, createFilesCompletionProvider as Hn, IDENTITY_PREFIX as Hr, DiscoveryProvider as Ht, writeProjects as I, readKeybindings as In, isTodoTool as Ir, VAPORWAVE_THEME as It, projectUserPaths as J, useCompletion as Jn, TOKEN_DISCIPLINE_DOCTRINE as Jr, createStateStore as Jt, discoverProjectMcps as K, findActiveTrigger as Kn, PLAN_MODE_DOCTRINE_NO_PROMPTS as Kr, useConfig as Kt, splitPromptSegments as L, stripJsonComments as Ln, pruneTodosByRun as Lr, CATPPUCCIN_FRAPPE as Lt, matchesSafelistEntry as M, keybindingsPath as Mn, TODOWRITE_TOOL as Mr, BUILTIN_THEMES as Mt, projectsFilePath as N, matchesBinding as Nn, TODO_WRITE_COUNTS_METADATA_KEY as Nr, DEFAULT_THEME as Nt, IMPLICITLY_SAFE_TOOLS as O, DEFAULT_KEYBINDINGS as On, resolveAgentId as Or, SETTINGS_TOGGLES as Ot, readProjects as P, mergeKeybindings as Pn, createTodoTools as Pr, resolveChipColor as Pt, McpAuthProvider as Q, bootProfileEnabled as Qn, isTurnHighlighted as Qt, formatPathForCwd as R, SKILLS_TRIGGER as Rn, setTodosForRun as Rr, CATPPUCCIN_LATTE as Rt, renderSession as S, buildEditOutcomesAnnotation as Sn, BUILD_AGENT as Sr, fmtTokens as St, SafeModeProvider as T, resolveApprovalForPayload as Tn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Tr, useEnabledToggleSet as Tt, indexOfEntry as U, uniqueFilesFromReferences as Un, INTERACTION_GUIDANCE as Ur, useDiscovery as Ut, buildModelCatalog as V, FILES_TRIGGER as Vn, DOING_TASKS_DOCTRINE as Vr, createDiscoverySlot as Vt, buildMcpServers as W, applyInsert as Wn, INTERACTION_GUIDANCE_NO_PROMPTS as Wr, useDiscoveryOptional as Wt, mcpCredentialsPath as X, buildLinearRamp as Xn, buildPlanSystem as Xr, eventsFromTurns as Xt, createFileMcpCredentialStore as Y, blendHsl as Yn, buildBuildSystem as Yr, deriveSessionTitle as Yt, patchMcpCredential as Z, tryOpenBrowser as Zn, envSection as Zr, isEditErrorResult as Zt, turnContextSize as _, extractEditPayload as _n, modelSupportsReasoning as _r, truncateTrailing as _t, computeTurnAnchors as a, selectableTurnIds as an, readProviderCredential as ar, InteractionsProvider as at, defaultSkillScanPaths as b, splitLines as bn, openrouterDescriptor as br, ageString as bt, formatToolCall as c, titleFromTurns as cn, writeCredentials as cr, createInteractionTools as ct, useSelectStyle as d, turnSelectionOwnership as dn, anthropicDescriptor as dr, pendingInteractionsFromTurns as dt, lastContextSizeFromTurns as en, shouldAutoCompact as er, useMcpAuthState as et, useSurfaces as f, applyEditPayload as fn, cerebrasDescriptor as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, computeLineDiff as gn, getModelInfo as gr, hintsLength as gt, finalizeStreamingMarkdown as h, computeInlineDiff as hn, getContextWindow as hr, clipHintsToWidth as ht, turnAsText as i, saveState as in, readCredentials as ir, ASK_USER_TOOL as it, isOnSafelist as j, ensureKeybindingsFile as jn, TODOS_METADATA_KEY as jr, useSettings as jt, addToSafelist as k, KEYBINDING_DEFS as kn, singleAgentRegistry as kr, SettingsProvider as kt, ThemeProvider as l, toolCallPreview as ln, BUILTIN_PROVIDERS as lr, isInteractionTool as lt, useTheme as m, buildUnifiedDiff as mn, effectiveContextWindow as mr, useInteractionsQueue as mt, deleteTurnSafely as n, loadState as nn, applyApiKeyEnv as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, stripSpawnTokensLine as on, removeProviderCredential as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, buildContextualDiff as pn, credKeyOf as pr, useInteractionsActions as pt, parseMcpsFile as q, mergeReferences as qn, SUBAGENT_GUIDANCE as qr, resolveConfig as qt, truncateTurnsAt as r, marginTopFor as rn, credentialsPath as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, sumRunCosts as sn, setProviderCredential as sr, buildResumedToolResultsTurn as st, countNeighbors as t, listSessionMeta as tn, detectAuth as tr, getMcpAuthStatus as tt, useColors as u, toolResultText as un, OUTPUT_RESERVE_TOKENS as ur, makeRequestInteraction as ut, useStreamBuffer as v, filetypeFromPath as vn, modelsForDescriptor as vr, cleanTitle as vt, writeSessionExport as w, parseEditOutcomesFromResult as wn, DEFAULT_AGENT_ID as wr, listProjectFiles as wt, discoverProjectSkills as x, tokenize as xn, piIdOf as xr, compactPath as xt, buildSkillsConfig as y, previewEditPayload as yn, openaiDescriptor as yr, generateSessionTitle as yt, runOAuthLogin as z, createSkillsCompletionProvider as zn, ACTIONS_WITH_CARE_DOCTRINE as zr, CATPPUCCIN_MACCHIATO as zt };
7936
+ export { useMcpAuthDispatch as $, bootTick as $n, TOKEN_DISCIPLINE_DOCTRINE as $r, isVisible as $t, getSafelist as A, KEYBINDING_DEF_BY_ACTION as An, TODOREAD_TOOL as Ar, clampFps as At, supportsOAuth as B, uniqueSkillNamesFromReferences as Bn, pruneTodosByRun as Br, CATPPUCCIN_MOCHA as Bt, resolveSessionExportTarget as C, maskToOutcomeKinds as Cn, BUILTIN_AGENTS as Cr, shortId as Ct, useSafeModeQueue as D, findGitRoot$1 as Dn, accentColor as Dr, SETTINGS_CHOICES as Dt, useSafeModeActions as E, summarizeOutcomes as En, PLAN_AGENT as Er, DEFAULT_SETTINGS as Et, suggestSafelistEntry as F, parseBindingSpec as Fn, createTodoTools as Fr, resolveTheme as Ft, defaultMcpsConfigPaths as G, collectReferences as Gn, COMMUNICATION_DOCTRINE as Gr, ConfigProvider as Gt, filterModelCatalog as H, createFilesCompletionProvider as Hn, setTodosForRun as Hr, DiscoveryProvider as Ht, writeProjects as I, readKeybindings as In, getArchivedTodosForRun as Ir, VAPORWAVE_THEME as It, projectUserPaths as J, useCompletion as Jn, INTERACTION_GUIDANCE as Jr, createStateStore as Jt, discoverProjectMcps as K, findActiveTrigger as Kn, DOING_TASKS_DOCTRINE as Kr, useConfig as Kt, splitPromptSegments as L, stripJsonComments as Ln, getTodosForRun as Lr, CATPPUCCIN_FRAPPE as Lt, matchesSafelistEntry as M, keybindingsPath as Mn, TODOWRITE_TOOL as Mr, BUILTIN_THEMES as Mt, projectsFilePath as N, matchesBinding as Nn, TODO_STATUS_GLYPHS as Nr, DEFAULT_THEME as Nt, IMPLICITLY_SAFE_TOOLS as O, DEFAULT_KEYBINDINGS as On, resolveAgentId as Or, SETTINGS_TOGGLES as Ot, readProjects as P, mergeKeybindings as Pn, TODO_WRITE_COUNTS_METADATA_KEY as Pr, resolveChipColor as Pt, McpAuthProvider as Q, bootProfileEnabled as Qn, SUBAGENT_GUIDANCE as Qr, isTurnHighlighted as Qt, formatPathForCwd as R, SKILLS_TRIGGER as Rn, isTodoTool as Rr, CATPPUCCIN_LATTE as Rt, renderSession as S, buildEditOutcomesAnnotation as Sn, BUILD_AGENT as Sr, fmtTokens as St, SafeModeProvider as T, resolveApprovalForPayload as Tn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Tr, useEnabledToggleSet as Tt, indexOfEntry as U, uniqueFilesFromReferences as Un, useActiveTodos as Ur, useDiscovery as Ut, buildModelCatalog as V, FILES_TRIGGER as Vn, selectActiveTodos as Vr, createDiscoverySlot as Vt, buildMcpServers as W, applyInsert as Wn, ACTIONS_WITH_CARE_DOCTRINE as Wr, useDiscoveryOptional as Wt, mcpCredentialsPath as X, buildLinearRamp as Xn, PLAN_MODE_DOCTRINE as Xr, eventsFromTurns as Xt, createFileMcpCredentialStore as Y, blendHsl as Yn, INTERACTION_GUIDANCE_NO_PROMPTS as Yr, deriveSessionTitle as Yt, patchMcpCredential as Z, tryOpenBrowser as Zn, PLAN_MODE_DOCTRINE_NO_PROMPTS as Zr, isEditErrorResult as Zt, turnContextSize as _, extractEditPayload as _n, modelSupportsReasoning as _r, truncateTrailing as _t, computeTurnAnchors as a, selectableTurnIds as an, readProviderCredential as ar, InteractionsProvider as at, defaultSkillScanPaths as b, splitLines as bn, openrouterDescriptor as br, ageString as bt, formatToolCall as c, titleFromTurns as cn, writeCredentials as cr, createInteractionTools as ct, useSelectStyle as d, turnSelectionOwnership as dn, anthropicDescriptor as dr, pendingInteractionsFromTurns as dt, buildBuildSystem as ei, lastContextSizeFromTurns as en, shouldAutoCompact as er, useMcpAuthState as et, useSurfaces as f, applyEditPayload as fn, cerebrasDescriptor as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, computeLineDiff as gn, getModelInfo as gr, hintsLength as gt, finalizeStreamingMarkdown as h, computeInlineDiff as hn, getContextWindow as hr, clipHintsToWidth as ht, turnAsText as i, saveState as in, readCredentials as ir, ASK_USER_TOOL as it, isOnSafelist as j, ensureKeybindingsFile as jn, TODOS_METADATA_KEY as jr, useSettings as jt, addToSafelist as k, KEYBINDING_DEFS as kn, singleAgentRegistry as kr, SettingsProvider as kt, ThemeProvider as l, toolCallPreview as ln, BUILTIN_PROVIDERS as lr, isInteractionTool as lt, useTheme as m, buildUnifiedDiff as mn, effectiveContextWindow as mr, useInteractionsQueue as mt, deleteTurnSafely as n, envSection as ni, loadState as nn, applyApiKeyEnv as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, stripSpawnTokensLine as on, removeProviderCredential as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, buildContextualDiff as pn, credKeyOf as pr, useInteractionsActions as pt, parseMcpsFile as q, mergeReferences as qn, IDENTITY_PREFIX as qr, resolveConfig as qt, truncateTurnsAt as r, marginTopFor as rn, credentialsPath as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, sumRunCosts as sn, setProviderCredential as sr, buildResumedToolResultsTurn as st, countNeighbors as t, buildPlanSystem as ti, listSessionMeta as tn, detectAuth as tr, getMcpAuthStatus as tt, useColors as u, toolResultText as un, OUTPUT_RESERVE_TOKENS as ur, makeRequestInteraction as ut, useStreamBuffer as v, filetypeFromPath as vn, modelsForDescriptor as vr, cleanTitle as vt, writeSessionExport as w, parseEditOutcomesFromResult as wn, DEFAULT_AGENT_ID as wr, listProjectFiles as wt, discoverProjectSkills as x, tokenize as xn, piIdOf as xr, compactPath as xt, buildSkillsConfig as y, previewEditPayload as yn, openaiDescriptor as yr, generateSessionTitle as yt, runOAuthLogin as z, createSkillsCompletionProvider as zn, pickActiveRunId as zr, CATPPUCCIN_MACCHIATO as zt };
7630
7937
 
7631
- //# sourceMappingURL=turn-operations-gJ0qtLPv.js.map
7938
+ //# sourceMappingURL=turn-operations-D9HvatsR.js.map