zidane 5.4.3 → 5.5.2

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 (88) hide show
  1. package/README.md +30 -1
  2. package/dist/{agent-Yu8uhpy-.d.ts → agent-CvImMxMQ.d.ts} +183 -3
  3. package/dist/agent-CvImMxMQ.d.ts.map +1 -0
  4. package/dist/chat.d.ts +371 -15
  5. package/dist/chat.d.ts.map +1 -1
  6. package/dist/chat.js +203 -2
  7. package/dist/chat.js.map +1 -0
  8. package/dist/contexts/docker.d.ts +1 -1
  9. package/dist/contexts-BOtMvzli.js +472 -0
  10. package/dist/contexts-BOtMvzli.js.map +1 -0
  11. package/dist/contexts.d.ts +3 -3
  12. package/dist/contexts.js +1 -1
  13. package/dist/{errors-CDwtPIMX.js → errors-C5VSakmT.js} +1 -1
  14. package/dist/{errors-CDwtPIMX.js.map → errors-C5VSakmT.js.map} +1 -1
  15. package/dist/{index-DklfxeYy.d.ts → index-B0uc2C5x.d.ts} +3 -3
  16. package/dist/{index-DklfxeYy.d.ts.map → index-B0uc2C5x.d.ts.map} +1 -1
  17. package/dist/{index-BiO_5Hm4.d.ts → index-CbS75MD3.d.ts} +2 -2
  18. package/dist/index-CbS75MD3.d.ts.map +1 -0
  19. package/dist/{index-j9tY28ah.d.ts → index-CtXksgqb.d.ts} +60 -4
  20. package/dist/index-CtXksgqb.d.ts.map +1 -0
  21. package/dist/index.d.ts +6 -6
  22. package/dist/index.js +13 -13
  23. package/dist/{interpolate-CmtjEyRJ.js → interpolate-Cvjy8gpk.js} +3 -3
  24. package/dist/{interpolate-CmtjEyRJ.js.map → interpolate-Cvjy8gpk.js.map} +1 -1
  25. package/dist/{login-DxyAERe1.js → login-DthdFNzR.js} +4 -4
  26. package/dist/{login-DxyAERe1.js.map → login-DthdFNzR.js.map} +1 -1
  27. package/dist/{mcp-CNUbvbsy.js → mcp-C8XUNC_R.js} +3 -3
  28. package/dist/{mcp-CNUbvbsy.js.map → mcp-C8XUNC_R.js.map} +1 -1
  29. package/dist/mcp.d.ts +1 -1
  30. package/dist/mcp.js +1 -1
  31. package/dist/{messages-fTR19Ga6.js → messages-BBWakTN6.js} +2 -2
  32. package/dist/{messages-fTR19Ga6.js.map → messages-BBWakTN6.js.map} +1 -1
  33. package/dist/{presets-D9IbaI40.js → presets-C5E9hokO.js} +3 -2
  34. package/dist/presets-C5E9hokO.js.map +1 -0
  35. package/dist/presets.d.ts +2 -2
  36. package/dist/presets.js +1 -1
  37. package/dist/{providers-CEzRFYtS.js → providers-CsUyN_FJ.js} +4 -4
  38. package/dist/{providers-CEzRFYtS.js.map → providers-CsUyN_FJ.js.map} +1 -1
  39. package/dist/providers.d.ts +1 -1
  40. package/dist/providers.js +2 -2
  41. package/dist/session/sqlite.d.ts +1 -1
  42. package/dist/session/sqlite.d.ts.map +1 -1
  43. package/dist/session/sqlite.js +2 -1
  44. package/dist/session/sqlite.js.map +1 -1
  45. package/dist/{session-kwsNnOmt.js → session-DzfRacU_.js} +3 -2
  46. package/dist/session-DzfRacU_.js.map +1 -0
  47. package/dist/session.d.ts +1 -1
  48. package/dist/session.js +2 -2
  49. package/dist/skills.d.ts +2 -2
  50. package/dist/skills.js +1 -1
  51. package/dist/{stats-DgOvY7wd.js → stats-Lc3zL3RM.js} +1 -1
  52. package/dist/{stats-DgOvY7wd.js.map → stats-Lc3zL3RM.js.map} +1 -1
  53. package/dist/{tools-BK2vG9UX.js → tools-BavL6n7q.js} +673 -261
  54. package/dist/tools-BavL6n7q.js.map +1 -0
  55. package/dist/tools.d.ts +3 -3
  56. package/dist/tools.js +2 -2
  57. package/dist/{transcript-anchors-DnaBcJej.d.ts → transcript-anchors-BMZRmrYk.d.ts} +182 -73
  58. package/dist/transcript-anchors-BMZRmrYk.d.ts.map +1 -0
  59. package/dist/tui.d.ts +27 -5
  60. package/dist/tui.d.ts.map +1 -1
  61. package/dist/tui.js +260 -47
  62. package/dist/tui.js.map +1 -1
  63. package/dist/{turn-operations-OzKEOXul.js → turn-operations-DtMApNGT.js} +992 -85
  64. package/dist/turn-operations-DtMApNGT.js.map +1 -0
  65. package/dist/{types-IcokUOyC.js → types-C-9h2drI.js} +1 -1
  66. package/dist/{types-IcokUOyC.js.map → types-C-9h2drI.js.map} +1 -1
  67. package/dist/types-KukEp-mi.d.ts +253 -0
  68. package/dist/types-KukEp-mi.d.ts.map +1 -0
  69. package/dist/types.d.ts +4 -4
  70. package/dist/types.js +3 -3
  71. package/docs/ARCHITECTURE.md +21 -0
  72. package/docs/CHAT.md +3 -1
  73. package/docs/RUN_IN_BACKGROUND.md +612 -0
  74. package/docs/SKILL.md +59 -0
  75. package/docs/TUI.md +88 -3
  76. package/package.json +2 -2
  77. package/dist/agent-Yu8uhpy-.d.ts.map +0 -1
  78. package/dist/contexts-BwiHIr2w.js +0 -129
  79. package/dist/contexts-BwiHIr2w.js.map +0 -1
  80. package/dist/index-BiO_5Hm4.d.ts.map +0 -1
  81. package/dist/index-j9tY28ah.d.ts.map +0 -1
  82. package/dist/presets-D9IbaI40.js.map +0 -1
  83. package/dist/session-kwsNnOmt.js.map +0 -1
  84. package/dist/tools-BK2vG9UX.js.map +0 -1
  85. package/dist/transcript-anchors-DnaBcJej.d.ts.map +0 -1
  86. package/dist/turn-operations-OzKEOXul.js.map +0 -1
  87. package/dist/types-Ce78ds4h.d.ts +0 -88
  88. package/dist/types-Ce78ds4h.d.ts.map +0 -1
@@ -1,20 +1,26 @@
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-BK2vG9UX.js";
2
- import { s as errorMessage } from "./errors-CDwtPIMX.js";
3
- import { n as toolResultToText } from "./types-IcokUOyC.js";
4
- import { r as normalizeMcpServers } from "./mcp-CNUbvbsy.js";
5
- import { a as discoverSkills } from "./interpolate-CmtjEyRJ.js";
6
- import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
7
- import { n as definePreset, t as composePresets } from "./presets-D9IbaI40.js";
8
- import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CEzRFYtS.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-BavL6n7q.js";
2
+ import { s as errorMessage } from "./errors-C5VSakmT.js";
3
+ import { n as toolResultToText } from "./types-C-9h2drI.js";
4
+ import { r as normalizeMcpServers } from "./mcp-C8XUNC_R.js";
5
+ import { a as discoverSkills } from "./interpolate-Cvjy8gpk.js";
6
+ import { n as formatTokenUsage } from "./stats-Lc3zL3RM.js";
7
+ import { n as definePreset, t as composePresets } from "./presets-C5E9hokO.js";
8
+ import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CsUyN_FJ.js";
9
+ import { createRequire } from "node:module";
10
+ import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
11
+ import { homedir, tmpdir } from "node:os";
9
12
  import { spawn } from "node:child_process";
13
+ import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
10
14
  import { readdir, stat, writeFile } from "node:fs/promises";
11
- import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
12
15
  import { getModel, getModels } from "@mariozechner/pi-ai";
13
- import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
14
- import { homedir } from "node:os";
15
16
  import { anthropicOAuthProvider, openaiCodexOAuthProvider } from "@mariozechner/pi-ai/oauth";
17
+ import { createHash } from "node:crypto";
18
+ import { createGunzip } from "node:zlib";
16
19
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
17
20
  import { jsx } from "react/jsx-runtime";
21
+ //#region \0rolldown/runtime.js
22
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
23
+ //#endregion
18
24
  //#region src/chat/agent-prompt.ts
19
25
  /**
20
26
  * Agent system-prompt fragments — composable doctrine for built-in profiles.
@@ -1426,6 +1432,801 @@ function shouldAutoCompact(input) {
1426
1432
  };
1427
1433
  }
1428
1434
  //#endregion
1435
+ //#region src/chat/auto-update.ts
1436
+ const OPT_OUT_VARS = [
1437
+ "ZIDANE_NO_UPDATE",
1438
+ "NO_UPDATE_NOTIFIER",
1439
+ "CI"
1440
+ ];
1441
+ function isOptedOut(env = process.env) {
1442
+ for (const key of OPT_OUT_VARS) {
1443
+ const v = env[key];
1444
+ if (v !== void 0 && v !== "" && v !== "0" && v.toLowerCase() !== "false") return true;
1445
+ }
1446
+ return false;
1447
+ }
1448
+ function parseSemver(input) {
1449
+ const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([\w.-]+))?(?:\+[\w.-]+)?$/.exec(input.trim());
1450
+ if (!m) return null;
1451
+ return {
1452
+ major: Number(m[1]),
1453
+ minor: Number(m[2]),
1454
+ patch: Number(m[3]),
1455
+ prerelease: m[4] ? m[4].split(".") : []
1456
+ };
1457
+ }
1458
+ /** Returns `-1 / 0 / 1`. Unparseable inputs sort as `0` (assume equal). */
1459
+ function compareSemver(a, b) {
1460
+ const A = parseSemver(a);
1461
+ const B = parseSemver(b);
1462
+ if (!A || !B) return 0;
1463
+ for (const k of [
1464
+ "major",
1465
+ "minor",
1466
+ "patch"
1467
+ ]) if (A[k] !== B[k]) return A[k] < B[k] ? -1 : 1;
1468
+ if (A.prerelease.length === 0 && B.prerelease.length > 0) return 1;
1469
+ if (A.prerelease.length > 0 && B.prerelease.length === 0) return -1;
1470
+ const len = Math.max(A.prerelease.length, B.prerelease.length);
1471
+ for (let i = 0; i < len; i++) {
1472
+ const ai = A.prerelease[i];
1473
+ const bi = B.prerelease[i];
1474
+ if (ai === void 0) return -1;
1475
+ if (bi === void 0) return 1;
1476
+ const an = /^\d+$/.test(ai) ? Number(ai) : null;
1477
+ const bn = /^\d+$/.test(bi) ? Number(bi) : null;
1478
+ if (an !== null && bn !== null) {
1479
+ if (an !== bn) return an < bn ? -1 : 1;
1480
+ } else if (an !== null) return -1;
1481
+ else if (bn !== null) return 1;
1482
+ else if (ai !== bi) return ai < bi ? -1 : 1;
1483
+ }
1484
+ return 0;
1485
+ }
1486
+ function cacheFilePath(cacheDir, packageName, channel) {
1487
+ return resolve(cacheDir, `update-check-${`${packageName.replaceAll("/", "__")}@${channel}`}.json`);
1488
+ }
1489
+ function readCache(path) {
1490
+ try {
1491
+ const raw = readFileSync(path, "utf8");
1492
+ const parsed = JSON.parse(raw);
1493
+ if (typeof parsed.latest !== "string" || typeof parsed.checkedAt !== "number") return null;
1494
+ return parsed;
1495
+ } catch {
1496
+ return null;
1497
+ }
1498
+ }
1499
+ function writeCache(path, entry) {
1500
+ try {
1501
+ mkdirSync(dirname(path), { recursive: true });
1502
+ writeFileSync(path, `${JSON.stringify(entry, null, 2)}\n`);
1503
+ } catch {}
1504
+ }
1505
+ /** Strip a trailing slash so URL assembly is uniform. */
1506
+ function trimSlash(s) {
1507
+ return s.endsWith("/") ? s.slice(0, -1) : s;
1508
+ }
1509
+ async function fetchLatestRelease(opts) {
1510
+ const url = `${trimSlash(opts.registry)}/${encodeURIComponent(opts.packageName)}/${encodeURIComponent(opts.channel)}`;
1511
+ const headers = {
1512
+ "accept": "application/vnd.npm.install-v1+json, application/json",
1513
+ "user-agent": "zidane-update-check/1"
1514
+ };
1515
+ if (opts.etag) headers["if-none-match"] = opts.etag;
1516
+ const res = await opts.fetcher(url, {
1517
+ headers,
1518
+ signal: opts.signal,
1519
+ redirect: "follow"
1520
+ });
1521
+ if (res.status === 304) throw new NotModifiedError();
1522
+ if (!res.ok) throw new Error(`registry returned ${res.status}`);
1523
+ const body = await res.json();
1524
+ if (!body.version) throw new Error("registry payload missing `version`");
1525
+ return {
1526
+ latest: body.version,
1527
+ etag: res.headers.get("etag")
1528
+ };
1529
+ }
1530
+ var NotModifiedError = class extends Error {
1531
+ constructor() {
1532
+ super("not-modified");
1533
+ }
1534
+ };
1535
+ /**
1536
+ * Resolve the latest available version of `packageName`, honoring an
1537
+ * on-disk TTL cache so the warm path costs zero network. Never throws —
1538
+ * registry failures degrade to `{ source: 'error', latest: null }`.
1539
+ *
1540
+ * Designed for boot-path usage: short timeout, swallows errors, opt-outs
1541
+ * for CI / restricted shells. Consumers driving the explicit `upgrade`
1542
+ * subcommand should set `force: true` to ignore env opt-outs.
1543
+ */
1544
+ async function checkForUpdate(options) {
1545
+ const channel = options.channel ?? "latest";
1546
+ const now = options.now ?? Date.now;
1547
+ const fetcher = options.fetcher ?? globalThis.fetch;
1548
+ const ttl = options.cacheTtlMs ?? 1440 * 60 * 1e3;
1549
+ const timeoutMs = options.timeoutMs ?? 3e3;
1550
+ if (!options.force && isOptedOut()) return skipped(options.currentVersion, channel);
1551
+ const cachePath = options.cacheDir ? cacheFilePath(options.cacheDir, options.packageName, channel) : null;
1552
+ const cached = cachePath ? readCache(cachePath) : null;
1553
+ if (cached && cached.packageName === options.packageName && cached.channel === channel) {
1554
+ if (ttl > 0 && now() - cached.checkedAt < ttl) {
1555
+ const hasUpdate = compareSemver(cached.latest, options.currentVersion) > 0;
1556
+ return {
1557
+ current: options.currentVersion,
1558
+ latest: cached.latest,
1559
+ hasUpdate,
1560
+ source: "cached",
1561
+ checkedAt: cached.checkedAt,
1562
+ channel
1563
+ };
1564
+ }
1565
+ }
1566
+ if (typeof fetcher !== "function") {
1567
+ if (cached) return {
1568
+ current: options.currentVersion,
1569
+ latest: cached.latest,
1570
+ hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,
1571
+ source: "cached",
1572
+ checkedAt: cached.checkedAt,
1573
+ channel
1574
+ };
1575
+ return skipped(options.currentVersion, channel);
1576
+ }
1577
+ const controller = new AbortController();
1578
+ const timer = setTimeout(() => controller.abort(/* @__PURE__ */ new Error("timeout")), timeoutMs);
1579
+ if (options.signal) if (options.signal.aborted) controller.abort(options.signal.reason);
1580
+ else options.signal.addEventListener("abort", () => controller.abort(options.signal.reason), { once: true });
1581
+ try {
1582
+ const release = await fetchLatestRelease({
1583
+ registry: options.registry ?? "https://registry.npmjs.org",
1584
+ packageName: options.packageName,
1585
+ channel,
1586
+ etag: cached?.etag,
1587
+ fetcher,
1588
+ signal: controller.signal
1589
+ });
1590
+ const checkedAt = now();
1591
+ if (cachePath) writeCache(cachePath, {
1592
+ packageName: options.packageName,
1593
+ channel,
1594
+ latest: release.latest,
1595
+ checkedAt,
1596
+ ...release.etag ? { etag: release.etag } : {}
1597
+ });
1598
+ return {
1599
+ current: options.currentVersion,
1600
+ latest: release.latest,
1601
+ hasUpdate: compareSemver(release.latest, options.currentVersion) > 0,
1602
+ source: "fresh",
1603
+ checkedAt,
1604
+ channel
1605
+ };
1606
+ } catch (err) {
1607
+ if (err instanceof NotModifiedError && cached) {
1608
+ const checkedAt = now();
1609
+ if (cachePath) writeCache(cachePath, {
1610
+ ...cached,
1611
+ checkedAt
1612
+ });
1613
+ return {
1614
+ current: options.currentVersion,
1615
+ latest: cached.latest,
1616
+ hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,
1617
+ source: "cached",
1618
+ checkedAt,
1619
+ channel
1620
+ };
1621
+ }
1622
+ if (cached) return {
1623
+ current: options.currentVersion,
1624
+ latest: cached.latest,
1625
+ hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,
1626
+ source: "cached",
1627
+ checkedAt: cached.checkedAt,
1628
+ channel
1629
+ };
1630
+ return {
1631
+ current: options.currentVersion,
1632
+ latest: null,
1633
+ hasUpdate: false,
1634
+ source: "error",
1635
+ error: err instanceof Error ? err.message : String(err),
1636
+ checkedAt: null,
1637
+ channel
1638
+ };
1639
+ } finally {
1640
+ clearTimeout(timer);
1641
+ }
1642
+ }
1643
+ function skipped(current, channel) {
1644
+ return {
1645
+ current,
1646
+ latest: null,
1647
+ hasUpdate: false,
1648
+ source: "skipped",
1649
+ checkedAt: null,
1650
+ channel
1651
+ };
1652
+ }
1653
+ function normalizePath(path) {
1654
+ try {
1655
+ return realpathSync(path);
1656
+ } catch {
1657
+ return path;
1658
+ }
1659
+ }
1660
+ function detectPackageManager(opts = {}) {
1661
+ const env = opts.env ?? process.env;
1662
+ const home = opts.home ?? homedir();
1663
+ opts.platform ?? process.platform;
1664
+ const channel = opts.channel ?? "latest";
1665
+ const packageName = opts.packageName ?? "zidane-tui";
1666
+ const binaryPath = opts.binaryPath ?? process.execPath;
1667
+ const resolvedBinary = normalizePath(binaryPath);
1668
+ const userAgent = opts.userAgent ?? env.npm_config_user_agent;
1669
+ const target = `${packageName}@${channel}`;
1670
+ const containsSegment = (path, segment) => {
1671
+ const tail = `${segment}${sep}`;
1672
+ return path.includes(tail) || path.endsWith(segment);
1673
+ };
1674
+ const inPath = (segment) => containsSegment(resolvedBinary, segment) || containsSegment(binaryPath, segment);
1675
+ const homeSeg = (rest) => `${home}${sep}${rest}`;
1676
+ if (inPath(homeSeg(".volta"))) return {
1677
+ id: "volta",
1678
+ argv: [
1679
+ "volta",
1680
+ "install",
1681
+ target
1682
+ ],
1683
+ note: "Volta-managed install detected — refreshing via `volta install`."
1684
+ };
1685
+ if (inPath(homeSeg(".bun"))) return {
1686
+ id: "bun",
1687
+ argv: [
1688
+ "bun",
1689
+ "add",
1690
+ "--global",
1691
+ target
1692
+ ],
1693
+ note: "Bun global install detected."
1694
+ };
1695
+ if (inPath(homeSeg(".local/share/pnpm")) || inPath(homeSeg("Library/pnpm")) || resolvedBinary.includes(`${sep}pnpm${sep}`)) return {
1696
+ id: "pnpm",
1697
+ argv: [
1698
+ "pnpm",
1699
+ "add",
1700
+ "--global",
1701
+ target
1702
+ ],
1703
+ note: "pnpm global install detected."
1704
+ };
1705
+ if (inPath(homeSeg(".yarn"))) return {
1706
+ id: "yarn",
1707
+ argv: [
1708
+ "yarn",
1709
+ "global",
1710
+ "add",
1711
+ target
1712
+ ],
1713
+ note: "Yarn classic global install detected."
1714
+ };
1715
+ if (userAgent) {
1716
+ const ua = userAgent.toLowerCase();
1717
+ if (ua.startsWith("pnpm/")) return {
1718
+ id: "pnpm",
1719
+ argv: [
1720
+ "pnpm",
1721
+ "add",
1722
+ "--global",
1723
+ target
1724
+ ]
1725
+ };
1726
+ if (ua.startsWith("yarn/")) return {
1727
+ id: "yarn",
1728
+ argv: [
1729
+ "yarn",
1730
+ "global",
1731
+ "add",
1732
+ target
1733
+ ]
1734
+ };
1735
+ if (ua.startsWith("bun/")) return {
1736
+ id: "bun",
1737
+ argv: [
1738
+ "bun",
1739
+ "add",
1740
+ "--global",
1741
+ target
1742
+ ]
1743
+ };
1744
+ if (ua.startsWith("npm/")) return {
1745
+ id: "npm",
1746
+ argv: [
1747
+ "npm",
1748
+ "install",
1749
+ "--global",
1750
+ target
1751
+ ]
1752
+ };
1753
+ }
1754
+ if (env.VOLTA_HOME) return {
1755
+ id: "volta",
1756
+ argv: [
1757
+ "volta",
1758
+ "install",
1759
+ target
1760
+ ],
1761
+ note: "$VOLTA_HOME set — using `volta install`. If the install isn't Volta-managed, pass `--package-manager npm`."
1762
+ };
1763
+ if (env.BUN_INSTALL) return {
1764
+ id: "bun",
1765
+ argv: [
1766
+ "bun",
1767
+ "add",
1768
+ "--global",
1769
+ target
1770
+ ]
1771
+ };
1772
+ if (env.PNPM_HOME) return {
1773
+ id: "pnpm",
1774
+ argv: [
1775
+ "pnpm",
1776
+ "add",
1777
+ "--global",
1778
+ target
1779
+ ]
1780
+ };
1781
+ return {
1782
+ id: "npm",
1783
+ argv: [
1784
+ "npm",
1785
+ "install",
1786
+ "--global",
1787
+ target
1788
+ ]
1789
+ };
1790
+ }
1791
+ /**
1792
+ * Re-install the package globally via the host's package manager. Resolves
1793
+ * with the spawned command's exit code, or rejects only when the caller's
1794
+ * `signal` aborts. PM failures surface as a non-zero `exitCode` — the
1795
+ * caller decides whether to retry or fall back to in-place.
1796
+ */
1797
+ async function performSelfUpdate(options) {
1798
+ const detect = options.detect ?? detectPackageManager;
1799
+ const command = options.packageManager && options.packageManager !== "auto" ? overrideManager(options.packageManager, options.packageName, options.channel ?? "latest") : detect({
1800
+ packageName: options.packageName,
1801
+ channel: options.channel ?? "latest"
1802
+ });
1803
+ if (options.dryRun) return {
1804
+ command,
1805
+ exitCode: null
1806
+ };
1807
+ const useSpawn = options.spawn ?? spawn;
1808
+ return await new Promise((resolveP) => {
1809
+ const [bin, ...args] = command.argv;
1810
+ const child = useSpawn(bin, args, {
1811
+ stdio: options.stdout || options.stderr ? [
1812
+ "ignore",
1813
+ "pipe",
1814
+ "pipe"
1815
+ ] : "inherit",
1816
+ env: {
1817
+ ...process.env,
1818
+ ...options.env
1819
+ }
1820
+ });
1821
+ if (options.stdout && child.stdout) child.stdout.pipe(options.stdout);
1822
+ if (options.stderr && child.stderr) child.stderr.pipe(options.stderr);
1823
+ child.on("error", (err) => {
1824
+ resolveP({
1825
+ command,
1826
+ exitCode: null,
1827
+ spawnError: err.message
1828
+ });
1829
+ });
1830
+ child.on("exit", (code) => {
1831
+ resolveP({
1832
+ command,
1833
+ exitCode: code
1834
+ });
1835
+ });
1836
+ if (options.signal) {
1837
+ const onAbort = () => child.kill();
1838
+ if (options.signal.aborted) onAbort();
1839
+ else options.signal.addEventListener("abort", onAbort, { once: true });
1840
+ }
1841
+ });
1842
+ }
1843
+ function overrideManager(id, packageName, channel) {
1844
+ const target = `${packageName}@${channel}`;
1845
+ switch (id) {
1846
+ case "pnpm": return {
1847
+ id,
1848
+ argv: [
1849
+ "pnpm",
1850
+ "add",
1851
+ "--global",
1852
+ target
1853
+ ]
1854
+ };
1855
+ case "yarn": return {
1856
+ id,
1857
+ argv: [
1858
+ "yarn",
1859
+ "global",
1860
+ "add",
1861
+ target
1862
+ ]
1863
+ };
1864
+ case "bun": return {
1865
+ id,
1866
+ argv: [
1867
+ "bun",
1868
+ "add",
1869
+ "--global",
1870
+ target
1871
+ ]
1872
+ };
1873
+ case "volta": return {
1874
+ id,
1875
+ argv: [
1876
+ "volta",
1877
+ "install",
1878
+ target
1879
+ ]
1880
+ };
1881
+ default: return {
1882
+ id: "npm",
1883
+ argv: [
1884
+ "npm",
1885
+ "install",
1886
+ "--global",
1887
+ target
1888
+ ]
1889
+ };
1890
+ }
1891
+ }
1892
+ /**
1893
+ * Replace the running binary with the latest tarball-shipped one. Works on
1894
+ * macOS + Linux (POSIX unlink-while-running); refuses on Windows. Returns
1895
+ * a result object instead of throwing — callers usually want to print
1896
+ * `result.reason` and fall back to a PM-driven update.
1897
+ */
1898
+ async function performInPlaceSelfUpdate(options) {
1899
+ if (process.platform === "win32") return {
1900
+ status: "refused",
1901
+ reason: "in-place update not supported on Windows; use `zidane upgrade` instead."
1902
+ };
1903
+ const binaryPath = options.binaryPath ?? process.execPath;
1904
+ const resolved = normalizePath(binaryPath);
1905
+ if (options.refuseUnderPrefixes?.some((p) => resolved.startsWith(p))) return {
1906
+ status: "refused",
1907
+ reason: `binary at ${resolved} sits under a managed prefix; use \`zidane upgrade\` to update via your package manager.`
1908
+ };
1909
+ if (resolved.includes(`${homedir()}${sep}.volta${sep}`)) return {
1910
+ status: "refused",
1911
+ reason: "Volta-managed install detected. Use `zidane upgrade` (runs `volta install`) instead."
1912
+ };
1913
+ const fetcher = options.fetcher ?? globalThis.fetch;
1914
+ if (typeof fetcher !== "function") return {
1915
+ status: "failed",
1916
+ reason: "global fetch unavailable; rebuild with Node ≥ 18 or Bun."
1917
+ };
1918
+ const channel = options.channel ?? "latest";
1919
+ const registry = options.registry ?? "https://registry.npmjs.org";
1920
+ const timeoutMs = options.timeoutMs ?? 3e4;
1921
+ const controller = new AbortController();
1922
+ const timer = setTimeout(() => controller.abort(/* @__PURE__ */ new Error("timeout")), timeoutMs);
1923
+ if (options.signal) if (options.signal.aborted) controller.abort(options.signal.reason);
1924
+ else options.signal.addEventListener("abort", () => controller.abort(options.signal.reason), { once: true });
1925
+ try {
1926
+ const metaRes = await fetcher(`${trimSlash(registry)}/${encodeURIComponent(options.packageName)}/${encodeURIComponent(channel)}`, {
1927
+ headers: {
1928
+ "accept": "application/json",
1929
+ "user-agent": "zidane-update-check/1"
1930
+ },
1931
+ signal: controller.signal
1932
+ });
1933
+ if (!metaRes.ok) return {
1934
+ status: "failed",
1935
+ reason: `registry returned ${metaRes.status} for ${options.packageName}@${channel}`
1936
+ };
1937
+ const meta = await metaRes.json();
1938
+ if (!meta.version || !meta.dist?.tarball) return {
1939
+ status: "failed",
1940
+ reason: `registry payload missing version or tarball for ${options.packageName}@${channel}`
1941
+ };
1942
+ if (!meta.dist.integrity && !meta.dist.shasum) return {
1943
+ status: "failed",
1944
+ reason: `registry payload missing integrity / shasum for ${options.packageName}@${channel}; refusing to overwrite the binary.`
1945
+ };
1946
+ const targetDir = dirname(binaryPath);
1947
+ let stagingDir;
1948
+ try {
1949
+ stagingDir = mkdtempSync(join(targetDir, ".zidane-update-"));
1950
+ } catch {
1951
+ stagingDir = mkdtempSync(join(tmpdir(), "zidane-update-"));
1952
+ }
1953
+ const tarballPath = join(stagingDir, "package.tgz");
1954
+ try {
1955
+ const tgzRes = await fetcher(meta.dist.tarball, {
1956
+ headers: { "user-agent": "zidane-update-check/1" },
1957
+ signal: controller.signal
1958
+ });
1959
+ if (!tgzRes.ok || !tgzRes.body) return {
1960
+ status: "failed",
1961
+ reason: `tarball download failed: ${tgzRes.status}`
1962
+ };
1963
+ const digests = await streamToFile(tgzRes.body, tarballPath);
1964
+ const integrityCheck = verifyIntegrity(meta.dist, digests);
1965
+ if (!integrityCheck.ok) return {
1966
+ status: "failed",
1967
+ reason: `integrity check failed: ${integrityCheck.reason}`
1968
+ };
1969
+ const tarballBinaryPath = options.tarballBinaryPath ?? `bin/${binaryNameFrom(binaryPath)}`;
1970
+ const extractedPath = await extractEntryFromTarball(tarballPath, tarballBinaryPath, stagingDir);
1971
+ if (!extractedPath) return {
1972
+ status: "failed",
1973
+ reason: `tarball did not contain ${tarballBinaryPath}`
1974
+ };
1975
+ if (options.dryRun) return {
1976
+ status: "success",
1977
+ installedVersion: meta.version,
1978
+ binaryPath: extractedPath
1979
+ };
1980
+ chmodSync(extractedPath, 493);
1981
+ const targetForSwap = binaryPath;
1982
+ try {
1983
+ renameSync(extractedPath, targetForSwap);
1984
+ } catch (err) {
1985
+ return {
1986
+ status: "failed",
1987
+ reason: `failed to write ${targetForSwap}: ${err instanceof Error ? err.message : String(err)}`
1988
+ };
1989
+ }
1990
+ return {
1991
+ status: "success",
1992
+ installedVersion: meta.version,
1993
+ binaryPath: targetForSwap
1994
+ };
1995
+ } finally {
1996
+ try {
1997
+ rmSync(stagingDir, {
1998
+ recursive: true,
1999
+ force: true
2000
+ });
2001
+ } catch {}
2002
+ }
2003
+ } catch (err) {
2004
+ return {
2005
+ status: "failed",
2006
+ reason: err instanceof Error ? err.message : String(err)
2007
+ };
2008
+ } finally {
2009
+ clearTimeout(timer);
2010
+ }
2011
+ }
2012
+ function binaryNameFrom(path) {
2013
+ const last = path.split(/[\\/]/).at(-1) ?? "";
2014
+ return last.endsWith(".exe") ? last.slice(0, -4) : last;
2015
+ }
2016
+ /**
2017
+ * Stream `body` to `path` while computing integrity digests on the fly —
2018
+ * we never load the whole tarball into a Buffer just to hash it. Returns
2019
+ * SHA-1 (hex, for the legacy `dist.shasum`) and SHA-512 (base64, for SRI's
2020
+ * `sha512-<base64>`).
2021
+ */
2022
+ async function streamToFile(body, path) {
2023
+ const file = createWriteStream(path);
2024
+ const sha1 = createHash("sha1");
2025
+ const sha512 = createHash("sha512");
2026
+ let size = 0;
2027
+ const reader = body.getReader();
2028
+ try {
2029
+ while (true) {
2030
+ const { done, value } = await reader.read();
2031
+ if (done) break;
2032
+ if (value && value.byteLength > 0) {
2033
+ sha1.update(value);
2034
+ sha512.update(value);
2035
+ size += value.byteLength;
2036
+ await new Promise((res, rej) => file.write(value, (err) => err ? rej(err) : res()));
2037
+ }
2038
+ }
2039
+ } finally {
2040
+ await new Promise((res) => file.end(() => res()));
2041
+ }
2042
+ return {
2043
+ sha1: sha1.digest("hex"),
2044
+ sha512Base64: sha512.digest("base64"),
2045
+ size
2046
+ };
2047
+ }
2048
+ /**
2049
+ * Validate the downloaded tarball's digest against the registry's
2050
+ * `dist.integrity` (SRI: `sha512-<base64>` / `sha384-…` / `sha256-…`) or
2051
+ * the legacy `dist.shasum` (hex SHA-1). Either must match — we don't
2052
+ * accept "neither provided" because that's what `performInPlaceSelfUpdate`
2053
+ * already short-circuited above.
2054
+ */
2055
+ function verifyIntegrity(dist, digests) {
2056
+ if (dist.integrity) {
2057
+ const entries = dist.integrity.split(/\s+/).filter(Boolean);
2058
+ for (const entry of entries) {
2059
+ const m = /^(sha(?:256|384|512))-(.+)$/.exec(entry);
2060
+ if (!m) continue;
2061
+ const algo = m[1];
2062
+ const expected = m[2];
2063
+ if (algo === "sha512" && digests.sha512Base64 === expected) return { ok: true };
2064
+ if (algo !== "sha512") return {
2065
+ ok: false,
2066
+ reason: `unsupported SRI algorithm \`${algo}\`. Re-run via your package manager.`
2067
+ };
2068
+ }
2069
+ return {
2070
+ ok: false,
2071
+ reason: "SRI mismatch: tarball does not match the registry's `dist.integrity`."
2072
+ };
2073
+ }
2074
+ if (dist.shasum) {
2075
+ if (digests.sha1 === dist.shasum.toLowerCase()) return { ok: true };
2076
+ return {
2077
+ ok: false,
2078
+ reason: "SHA-1 mismatch: tarball does not match the registry's `dist.shasum`."
2079
+ };
2080
+ }
2081
+ return {
2082
+ ok: false,
2083
+ reason: "no integrity field shipped by the registry."
2084
+ };
2085
+ }
2086
+ async function extractEntryFromTarball(tarballPath, entryRelPath, outDir) {
2087
+ const matchSuffix = `/${entryRelPath}`;
2088
+ const out = join(outDir, "binary.bin");
2089
+ const chunks = [];
2090
+ const gunzip = createGunzip();
2091
+ const input = createReadStream(tarballPath);
2092
+ await new Promise((res, rej) => {
2093
+ gunzip.on("data", (c) => chunks.push(c));
2094
+ gunzip.on("end", () => res());
2095
+ gunzip.on("error", rej);
2096
+ input.on("error", rej);
2097
+ input.pipe(gunzip);
2098
+ });
2099
+ const tar = concatChunks(chunks);
2100
+ let offset = 0;
2101
+ while (offset + 512 <= tar.length) {
2102
+ const header = tar.subarray(offset, offset + 512);
2103
+ if (header.every((b) => b === 0)) break;
2104
+ const name = readNulString(header, 0, 100);
2105
+ const sizeOct = readNulString(header, 124, 12).trim();
2106
+ const size = sizeOct === "" ? 0 : Number.parseInt(sizeOct, 8);
2107
+ const dataStart = offset + 512;
2108
+ const dataEnd = dataStart + size;
2109
+ if (name && (name === entryRelPath || name.endsWith(matchSuffix))) {
2110
+ writeFileSync(out, tar.subarray(dataStart, dataEnd));
2111
+ return out;
2112
+ }
2113
+ offset = dataEnd + (512 - size % 512) % 512;
2114
+ }
2115
+ return null;
2116
+ }
2117
+ function readNulString(buf, start, len) {
2118
+ const end = start + len;
2119
+ let stop = end;
2120
+ for (let i = start; i < end; i++) if (buf[i] === 0) {
2121
+ stop = i;
2122
+ break;
2123
+ }
2124
+ return new TextDecoder("utf8").decode(buf.subarray(start, stop));
2125
+ }
2126
+ function concatChunks(chunks) {
2127
+ let total = 0;
2128
+ for (const c of chunks) total += c.byteLength;
2129
+ const out = new Uint8Array(total);
2130
+ let offset = 0;
2131
+ for (const c of chunks) {
2132
+ out.set(c, offset);
2133
+ offset += c.byteLength;
2134
+ }
2135
+ return out;
2136
+ }
2137
+ function resolvePlatformPackage(opts = {}) {
2138
+ const platform = opts.platform ?? process.platform;
2139
+ const arch = opts.arch ?? process.arch;
2140
+ const libc = opts.libc ?? detectLibc();
2141
+ const prefix = opts.prefix ?? "zidane-tui-";
2142
+ if (platform === "darwin") {
2143
+ if (arch === "arm64") return `${prefix}darwin-arm64`;
2144
+ if (arch === "x64") return `${prefix}darwin-x64`;
2145
+ return null;
2146
+ }
2147
+ if (platform === "linux") {
2148
+ if (libc !== "glibc") return null;
2149
+ if (arch === "arm64") return `${prefix}linux-arm64`;
2150
+ if (arch === "x64") return `${prefix}linux-x64`;
2151
+ return null;
2152
+ }
2153
+ return null;
2154
+ }
2155
+ /** Mirrors `tui/bin/zidane.mjs#detectLibc`. */
2156
+ function detectLibc() {
2157
+ if (process.platform !== "linux") return "glibc";
2158
+ try {
2159
+ const { execSync } = __require("node:child_process");
2160
+ return execSync("ldd --version 2>&1", {
2161
+ encoding: "utf8",
2162
+ stdio: [
2163
+ "ignore",
2164
+ "pipe",
2165
+ "pipe"
2166
+ ]
2167
+ }).toLowerCase().includes("musl") ? "musl" : "glibc";
2168
+ } catch {
2169
+ return "musl";
2170
+ }
2171
+ }
2172
+ //#endregion
2173
+ //#region src/chat/auto-update-hook.ts
2174
+ /**
2175
+ * Returns the current update status, refreshed once per mount (subject to
2176
+ * the on-disk TTL). `null` while the first check is in flight; the
2177
+ * `source: 'cached' | 'fresh'` distinction lets the caller decide whether
2178
+ * to show a discreet chip vs a more prominent banner.
2179
+ *
2180
+ * The hook owns its own AbortController so an unmount cancels any in-flight
2181
+ * registry request cleanly.
2182
+ */
2183
+ function useUpdateCheck(options) {
2184
+ const [status, setStatus] = useState(null);
2185
+ const optsRef = useRef(options);
2186
+ optsRef.current = options;
2187
+ useEffect(() => {
2188
+ if (!options.enabled || !options.currentVersion) return;
2189
+ const controller = new AbortController();
2190
+ const timer = setTimeout(() => {
2191
+ checkForUpdate({
2192
+ packageName: optsRef.current.packageName,
2193
+ currentVersion: optsRef.current.currentVersion,
2194
+ cacheDir: optsRef.current.cacheDir,
2195
+ registry: optsRef.current.registry,
2196
+ channel: optsRef.current.channel,
2197
+ cacheTtlMs: optsRef.current.cacheTtlMs,
2198
+ signal: controller.signal,
2199
+ now: optsRef.current.now,
2200
+ fetcher: optsRef.current.fetcher
2201
+ }).then((s) => {
2202
+ if (!controller.signal.aborted) setStatus(s);
2203
+ });
2204
+ }, options.delayMs ?? 1500);
2205
+ return () => {
2206
+ clearTimeout(timer);
2207
+ controller.abort();
2208
+ };
2209
+ }, [
2210
+ options.enabled,
2211
+ options.packageName,
2212
+ options.currentVersion
2213
+ ]);
2214
+ return status;
2215
+ }
2216
+ function buildUpdateHint(status, options) {
2217
+ if (!status?.hasUpdate || !status.latest) return null;
2218
+ const label = options.showVersion === false ? "update" : `v${stripVPrefix(status.latest)}`;
2219
+ return {
2220
+ key: options.glyph ?? "↑",
2221
+ keyColor: options.color,
2222
+ label,
2223
+ labelColor: options.color
2224
+ };
2225
+ }
2226
+ function stripVPrefix(v) {
2227
+ return v.startsWith("v") ? v.slice(1) : v;
2228
+ }
2229
+ //#endregion
1429
2230
  //#region src/chat/boot-profiler.ts
1430
2231
  const enabled = !!process.env.ZIDANE_BOOT_PROFILE;
1431
2232
  /**
@@ -1889,7 +2690,7 @@ function scoreFiles(catalog, query, limit, formatPath) {
1889
2690
  return scored.slice(0, limit).map(({ entry, display }) => ({
1890
2691
  id: display,
1891
2692
  label: entry.name,
1892
- description: parentDir(display),
2693
+ description: parentDir(entry.path),
1893
2694
  insertText: `@${display} `,
1894
2695
  data: entry
1895
2696
  }));
@@ -3321,9 +4122,45 @@ function deriveSessionTitle(turns, metadata) {
3321
4122
  */
3322
4123
  function eventsFromTurns(turns, runs = []) {
3323
4124
  const runById = /* @__PURE__ */ new Map();
3324
- for (const run of runs) runById.set(run.id, run);
4125
+ for (const run of runs) if (!runById.has(run.id)) runById.set(run.id, run);
4126
+ const runStack = [];
4127
+ const pendingToolCallsPerRun = /* @__PURE__ */ new Map();
4128
+ for (const turn of turns) {
4129
+ const rid = turn.runId;
4130
+ if (!rid) continue;
4131
+ const idxInStack = runStack.indexOf(rid);
4132
+ if (idxInStack >= 0) runStack.length = idxInStack + 1;
4133
+ else {
4134
+ const top = runStack[runStack.length - 1];
4135
+ if (!(top !== void 0 && (pendingToolCallsPerRun.get(top)?.size ?? 0) > 0)) runStack.length = 0;
4136
+ runStack.push(rid);
4137
+ if (!runById.has(rid)) {
4138
+ const depth = runStack.length - 1;
4139
+ const parentRunId = depth > 0 ? runStack[depth - 1] : void 0;
4140
+ let inferredPrompt = "";
4141
+ if (turn.role === "user") {
4142
+ for (const block of turn.content) if (block.type === "text" && block.text.trim()) {
4143
+ inferredPrompt = block.text;
4144
+ break;
4145
+ }
4146
+ }
4147
+ runById.set(rid, {
4148
+ id: rid,
4149
+ startedAt: turn.createdAt,
4150
+ prompt: inferredPrompt,
4151
+ status: "completed",
4152
+ depth,
4153
+ ...parentRunId ? { parentRunId } : {}
4154
+ });
4155
+ }
4156
+ }
4157
+ const pending = pendingToolCallsPerRun.get(rid) ?? /* @__PURE__ */ new Set();
4158
+ for (const block of turn.content) if (block.type === "tool_call") pending.add(block.id);
4159
+ else if (block.type === "tool_result") pending.delete(block.callId);
4160
+ pendingToolCallsPerRun.set(rid, pending);
4161
+ }
3325
4162
  const childLabelByRunId = /* @__PURE__ */ new Map();
3326
- 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}`));
4163
+ [...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}`));
3327
4164
  const labelFor = (runId) => childLabelByRunId.get(runId) ?? runId;
3328
4165
  const toolByCallId = /* @__PURE__ */ new Map();
3329
4166
  for (const turn of turns) {
@@ -3369,7 +4206,7 @@ function eventsFromTurns(turns, runs = []) {
3369
4206
  });
3370
4207
  };
3371
4208
  const pushSpawnStart = (run) => {
3372
- const taskPreview = run.prompt.length > 80 ? `${run.prompt.slice(0, 80)}…` : run.prompt;
4209
+ const taskPreview = previewLine(run.prompt, 80);
3373
4210
  events.push({
3374
4211
  kind: "spawn-start",
3375
4212
  text: taskPreview,
@@ -3399,6 +4236,11 @@ function eventsFromTurns(turns, runs = []) {
3399
4236
  };
3400
4237
  if (turn.role === "user") {
3401
4238
  for (const block of turn.content) if (block.type === "text" && block.text.trim()) {
4239
+ const taskEvent = parseTaskNotificationBlock(block.text, tag);
4240
+ if (taskEvent) {
4241
+ events.push(taskEvent);
4242
+ continue;
4243
+ }
3402
4244
  if (depth === 0) {
3403
4245
  if (lastDepthAtEmission === 0) events.push({
3404
4246
  kind: "separator",
@@ -3474,6 +4316,84 @@ function eventsFromTurns(turns, runs = []) {
3474
4316
  return events;
3475
4317
  }
3476
4318
  /** Shared formatter for the `↳ name(args)` line shown on tool calls. */
4319
+ /**
4320
+ * Pattern matching the leading `<task-notification>` shape that the
4321
+ * agent's notification-injection path produces (see
4322
+ * `renderTaskNotificationXml` in `src/agent.ts`). Anchored so a stray
4323
+ * notification-shaped phrase mid-prompt doesn't trigger a false-positive
4324
+ * detection — the model's wire format always starts the user-turn
4325
+ * content block with this exact opening tag.
4326
+ */
4327
+ const TASK_NOTIFICATION_RE = /^\s*<task-notification>([\s\S]*?)<\/task-notification>\s*$/;
4328
+ /**
4329
+ * Per-field extractors. Compiled once at module load (parsing happens
4330
+ * on every session replay, and a fresh `new RegExp` per pick burns
4331
+ * cycles for no reason).
4332
+ */
4333
+ const TASK_NOTIFICATION_FIELD_RES = {
4334
+ taskId: /<task-id>([\s\S]*?)<\/task-id>/,
4335
+ status: /<status>([\s\S]*?)<\/status>/,
4336
+ exitCode: /<exit-code>([\s\S]*?)<\/exit-code>/,
4337
+ command: /<command>([\s\S]*?)<\/command>/,
4338
+ outputFile: /<output-file>([\s\S]*?)<\/output-file>/,
4339
+ durationMs: /<duration-ms>([\s\S]*?)<\/duration-ms>/,
4340
+ summary: /<summary>([\s\S]*?)<\/summary>/
4341
+ };
4342
+ /**
4343
+ * Detect a `<task-notification>` text block on replay and convert it
4344
+ * into a structured `task-notification` StreamEvent so the TUI's banner
4345
+ * renderer can paint it cleanly. Returns `null` when the block isn't a
4346
+ * notification (the caller falls back to the normal user-prompt path).
4347
+ *
4348
+ * Reads every field DIRECTLY from its tag — does NOT parse `<summary>`
4349
+ * for the underlying data. The summary is a derived display string,
4350
+ * not a source of truth: changing its format (localization, signal in
4351
+ * the label, whatever) must NEVER break replay. Each field falls back
4352
+ * to a safe default so older transcripts pre-dating a tag addition
4353
+ * still render.
4354
+ */
4355
+ function parseTaskNotificationBlock(text, tag) {
4356
+ const m = text.match(TASK_NOTIFICATION_RE);
4357
+ if (!m) return null;
4358
+ const body = m[1];
4359
+ const pick = (re) => {
4360
+ const inner = body.match(re);
4361
+ return inner ? unescapeXml(inner[1].trim()) : void 0;
4362
+ };
4363
+ const taskId = pick(TASK_NOTIFICATION_FIELD_RES.taskId) ?? "?";
4364
+ const statusRaw = pick(TASK_NOTIFICATION_FIELD_RES.status) ?? "exited";
4365
+ const status = statusRaw === "killed" ? "killed" : "exited";
4366
+ const exitCode = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.exitCode) ?? "0", 10) || 0;
4367
+ const command = pick(TASK_NOTIFICATION_FIELD_RES.command) ?? "";
4368
+ const outputPath = pick(TASK_NOTIFICATION_FIELD_RES.outputFile) ?? "";
4369
+ const durationMs = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.durationMs) ?? "0", 10) || 0;
4370
+ return {
4371
+ kind: "task-notification",
4372
+ text: pick(TASK_NOTIFICATION_FIELD_RES.summary) ?? `${taskId} ${statusRaw}${exitCode ? ` ${exitCode}` : ""}`,
4373
+ task: {
4374
+ taskId,
4375
+ status,
4376
+ exitCode,
4377
+ outputPath,
4378
+ command,
4379
+ durationMs
4380
+ },
4381
+ turnId: tag.turnId,
4382
+ ...tag.childId !== void 0 ? { childId: tag.childId } : {},
4383
+ ...tag.depth !== void 0 ? { depth: tag.depth } : {}
4384
+ };
4385
+ }
4386
+ /**
4387
+ * Reverse of `escapeXml` for the small set of entities the writer
4388
+ * emits. Not a full HTML entity decoder — just enough to round-trip
4389
+ * `<` / `>` / `&` / quotes through persistence.
4390
+ *
4391
+ * `&amp;` MUST be replaced last, otherwise `&amp;lt;` becomes `&lt;`
4392
+ * then `<` (data corruption — silent double-decode).
4393
+ */
4394
+ function unescapeXml(s) {
4395
+ return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&apos;/g, "'").replace(/&amp;/g, "&");
4396
+ }
3477
4397
  function toolCallPreview(name, input) {
3478
4398
  const args = JSON.stringify(input);
3479
4399
  return args && args !== "{}" ? `${name}(${args})` : name;
@@ -3606,7 +4526,8 @@ const MARGIN_TOP = {
3606
4526
  "markdown": 1,
3607
4527
  "spawn-start": 1,
3608
4528
  "spawn-end": 0,
3609
- "compact-summary": 1
4529
+ "compact-summary": 1,
4530
+ "task-notification": 1
3610
4531
  };
3611
4532
  const TOOL_KINDS = new Set(["tool", "tool-result"]);
3612
4533
  /**
@@ -3616,20 +4537,28 @@ const TOOL_KINDS = new Set(["tool", "tool-result"]);
3616
4537
  * - A `tool` / `tool-result` event right after another
3617
4538
  * `tool` / `tool-result` collapses to a tight list — call→result
3618
4539
  * pairs and back-to-back calls read as one logical block.
3619
- * - A parent-level event (`depth === 0`) right after a subagent event
3620
- * (`depth > 0`) collapses too. The subagent's `🌳` end marker
3621
- * already provides the separation; adding the event's default
3622
- * `marginTop` on top would produce the visible "line jump" between
3623
- * a subagent's outcome and the parent's follow-up.
4540
+ * - Consecutive `task-notification` banners stack tight a burst of
4541
+ * background-task completions reads as one log column rather than
4542
+ * scattered banners.
4543
+ *
4544
+ * NB: parent-level events (`depth === 0`) following a subagent block
4545
+ * (`depth > 0`) get their normal default margin. An earlier revision
4546
+ * collapsed this transition to 0 on the assumption that the subagent's
4547
+ * `🌳` end-marker provided enough visual separation — it didn't. A
4548
+ * 2-cell emoji on the same row as the close marker doesn't create a
4549
+ * vertical break, and in hide-subagent-output mode the SubagentBlock
4550
+ * box isn't rendered either, so the parent's follow-up markdown was
4551
+ * glued directly against the close line. Subagents should READ like
4552
+ * tool calls: open with breathing room, close tight inside, and open
4553
+ * a clean gap before the parent's next thought — that's the contract
4554
+ * the tool-call → markdown transition uses, mirrored here.
3624
4555
  *
3625
4556
  * Renderer-agnostic — TUI uses it as Yoga `marginTop`; a CSS host can
3626
4557
  * use the same number as the row's top margin in `em` / `rem`.
3627
4558
  */
3628
4559
  function marginTopFor(event, previous) {
3629
4560
  if (TOOL_KINDS.has(event.kind) && previous && TOOL_KINDS.has(previous.kind)) return 0;
3630
- const eventDepth = event.depth ?? 0;
3631
- const previousDepth = previous?.depth ?? 0;
3632
- if (eventDepth === 0 && previousDepth > 0) return 0;
4561
+ if (event.kind === "task-notification" && previous?.kind === "task-notification") return 0;
3633
4562
  return MARGIN_TOP[event.kind] ?? 0;
3634
4563
  }
3635
4564
  /**
@@ -3864,7 +4793,8 @@ function resolveConfig(options) {
3864
4793
  initialSettings: migrateLegacySettings(initialState.settings ?? {}),
3865
4794
  resumeProvider,
3866
4795
  initialPicked,
3867
- keybindings
4796
+ keybindings,
4797
+ autoUpdate: options.autoUpdate ?? null
3868
4798
  };
3869
4799
  }
3870
4800
  /**
@@ -4963,7 +5893,8 @@ const DEFAULT_SETTINGS = {
4963
5893
  allowInteraction: true,
4964
5894
  smoothStreaming: true,
4965
5895
  showTodoIndicator: true,
4966
- showThrobber: false
5896
+ showThrobber: false,
5897
+ checkForUpdates: true
4967
5898
  };
4968
5899
  /**
4969
5900
  * Hard-clamp a `targetFps` value to a safe range before handing it to
@@ -5088,6 +6019,11 @@ const SETTINGS_TOGGLES = [
5088
6019
  key: "showThrobber",
5089
6020
  label: "Streaming throbber",
5090
6021
  description: "animated gradient glyphs at the transcript tail while the assistant is working"
6022
+ },
6023
+ {
6024
+ key: "checkForUpdates",
6025
+ label: "Check for updates",
6026
+ description: "quietly check npm once a day; footer chip surfaces newer releases. `zidane upgrade` always works regardless."
5091
6027
  }
5092
6028
  ];
5093
6029
  const SETTINGS_CHOICES = [
@@ -5421,51 +6357,6 @@ function toEntries(paths, source, maxFiles) {
5421
6357
  return out;
5422
6358
  }
5423
6359
  //#endregion
5424
- //#region src/chat/format.ts
5425
- /** Compact token formatter — 12_415 → "12.4k", 1_234_567 → "1.23M". */
5426
- function fmtTokens(n) {
5427
- if (n < 1e3) return String(n);
5428
- if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 2 : 1)}k`;
5429
- return `${(n / 1e6).toFixed(2)}M`;
5430
- }
5431
- /** Compact relative-time formatter — "just now / 5m / 3h / 2d". */
5432
- function ageString(ts, now = Date.now()) {
5433
- const m = Math.floor((now - ts) / 6e4);
5434
- if (m < 1) return "just now";
5435
- if (m < 60) return `${m}m ago`;
5436
- const h = Math.floor(m / 60);
5437
- if (h < 24) return `${h}h ago`;
5438
- return `${Math.floor(h / 24)}d ago`;
5439
- }
5440
- /** Six-char short form of a session id for headers and lists. */
5441
- function shortId(id) {
5442
- return id.replace(/-/g, "").slice(0, 6);
5443
- }
5444
- /**
5445
- * Compact an absolute path for display: replace the user's `$HOME`
5446
- * prefix with `~` (so `/Users/yael/Code/zidane` → `~/Code/zidane`),
5447
- * and optionally left-truncate with an ellipsis when the result
5448
- * still exceeds `maxWidth` (so the path's *tail* — the part the user
5449
- * recognizes — stays visible: `…/zidane` rather than `/Users/yaeluil…`).
5450
- *
5451
- * `maxWidth` is the maximum *display width* in cells. Omit to skip
5452
- * truncation. Paths outside `$HOME` are returned verbatim modulo
5453
- * truncation. The ellipsis (`…`) counts as one cell.
5454
- *
5455
- * `home` overrides `os.homedir()` for tests; production callers leave
5456
- * it undefined and pay the cheap one-syscall lookup per call.
5457
- */
5458
- function compactPath(path, maxWidth, home) {
5459
- const h = home ?? homedir();
5460
- let display = path;
5461
- if (h) {
5462
- if (path === h) display = "~";
5463
- else if (path.startsWith(`${h}/`)) display = `~${path.slice(h.length)}`;
5464
- }
5465
- if (maxWidth !== void 0 && maxWidth > 1 && display.length > maxWidth) return `…${display.slice(display.length - maxWidth + 1)}`;
5466
- return display;
5467
- }
5468
- //#endregion
5469
6360
  //#region src/chat/generate-title.ts
5470
6361
  /** Hard cap on the result length. Anything longer is truncated client-side. */
5471
6362
  const TITLE_MAX_CHARS = 60;
@@ -6678,13 +7569,17 @@ async function runOAuthLogin(descriptor, options) {
6678
7569
  *
6679
7570
  * Rule:
6680
7571
  *
6681
- * - When the resolved target sits inside `cwd` → return a
6682
- * CWD-relative forward-slashed path (no `..` traversal).
6683
- * - Otherwise (target sits above `cwd`, or `cwd` is outside the
6684
- * project) return the absolute path. A `..`-laden relative
6685
- * form would be valid for the tools but harder to read AND
6686
- * surprises the user, whose mental model of `@` is "pick a
6687
- * file from the project view".
7572
+ * - File at `cwd` itself `.`.
7573
+ * - File under `cwd` (subtree) forward-slashed CWD-relative,
7574
+ * no `..`.
7575
+ * - File above `cwd` but still inside the project → CWD-relative
7576
+ * with `..` traversal (e.g. `../EDIT_THIS.md`). Shorter and more
7577
+ * scannable than absolute, and the agent's tools resolve both.
7578
+ * - File outside the project (input was passed absolute) → returned
7579
+ * verbatim. Inputs that arrive as project-root-relative strings
7580
+ * are always inside the project by construction, so this branch
7581
+ * only kicks in when a direct caller hands the function an
7582
+ * absolute target.
6688
7583
  *
6689
7584
  * Pure, no I/O, deterministic.
6690
7585
  */
@@ -6695,13 +7590,18 @@ async function runOAuthLogin(descriptor, options) {
6695
7590
  *
6696
7591
  * Inputs:
6697
7592
  * - `projectRelativePath` — forward-slashed, no leading slash. Returned
6698
- * verbatim when it's empty or already absolute (defensive).
7593
+ * verbatim when it's empty or already absolute (defensive — the
7594
+ * absolute-input branch is the de-facto "outside the project"
7595
+ * escape; the catalog itself never emits absolute paths).
6699
7596
  * - `projectRoot` — absolute path of the discovery anchor.
6700
7597
  * - `cwd` — absolute path of `process.cwd()` at the moment of
6701
7598
  * insertion.
6702
7599
  *
6703
- * Output is always either an absolute path OR a CWD-relative path with
6704
- * no `..` segments. Never a `..`-prefixed relative path.
7600
+ * Output is always either an absolute path (only when the input arrived
7601
+ * absolute) OR a CWD-relative path. The relative form may include
7602
+ * `../` segments when the target sits above `cwd` within the project,
7603
+ * which keeps cross-tree references short and scannable
7604
+ * (e.g. `../EDIT_THIS.md` instead of `/Users/.../zidane/EDIT_THIS.md`).
6705
7605
  */
6706
7606
  function formatPathForCwd(projectRelativePath, projectRoot, cwd) {
6707
7607
  if (projectRelativePath.length === 0) return projectRelativePath;
@@ -6711,7 +7611,6 @@ function formatPathForCwd(projectRelativePath, projectRoot, cwd) {
6711
7611
  if (target === here) return ".";
6712
7612
  const rel = relative(here, target);
6713
7613
  if (rel.length === 0) return ".";
6714
- if (rel === ".." || rel.startsWith(`..${sep}`) || rel.startsWith("../")) return target;
6715
7614
  return sep === "/" ? rel : rel.split(sep).join(posix.sep);
6716
7615
  }
6717
7616
  //#endregion
@@ -7872,13 +8771,21 @@ const TOOL_DISPLAY = {
7872
8771
  }
7873
8772
  },
7874
8773
  shell: {
7875
- displayName: "Shell",
8774
+ displayName: (input) => input?.run_in_background === true ? "Shell (background)" : "Shell",
7876
8775
  format: (input) => {
7877
8776
  const command = stringField(input, "command");
7878
8777
  if (!command) return null;
7879
8778
  return { target: truncate(command.trim(), 200) };
7880
8779
  }
7881
8780
  },
8781
+ shell_kill: {
8782
+ displayName: "Kill task",
8783
+ format: (input) => {
8784
+ const taskId = stringField(input, "task_id");
8785
+ if (!taskId) return null;
8786
+ return { target: taskId };
8787
+ }
8788
+ },
7882
8789
  edit: {
7883
8790
  displayName: "Edit",
7884
8791
  format: (input) => {
@@ -8246,6 +9153,6 @@ function countNeighbors(turnIds, turnId) {
8246
9153
  };
8247
9154
  }
8248
9155
  //#endregion
8249
- export { useMcpAuthDispatch as $, mergeReferences as $n, IDENTITY_PREFIX as $r, isTurnHighlighted as $t, getSafelist as A, rewriteMultiEditHeader as An, DEFAULT_AGENT_ID as Ar, clampFps as At, supportsOAuth as B, mergeKeybindings as Bn, TODO_WRITE_COUNTS_METADATA_KEY as Br, CATPPUCCIN_MOCHA as Bt, resolveSessionExportTarget as C, summarizeEditPayload as Cn, modelSupportsReasoning as Cr, shortId as Ct, useSafeModeQueue as D, mergeApprovalAndBodyOutcomes as Dn, piIdOf as Dr, SETTINGS_CHOICES as Dt, useSafeModeActions as E, maskToOutcomeKinds as En, openrouterDescriptor as Er, DEFAULT_SETTINGS as Et, suggestSafelistEntry as F, KEYBINDING_DEFS as Fn, singleAgentRegistry as Fr, resolveTheme as Ft, defaultMcpsConfigPaths as G, createSkillsCompletionProvider as Gn, pickActiveRunId as Gr, ConfigProvider as Gt, filterModelCatalog as H, readKeybindings as Hn, getArchivedTodosForRun as Hr, DiscoveryProvider as Ht, writeProjects as I, KEYBINDING_DEF_BY_ACTION as In, TODOREAD_TOOL as Ir, VAPORWAVE_THEME as It, projectUserPaths as J, createFilesCompletionProvider as Jn, setTodosForRun as Jr, EDIT_TOOL_NAMES as Jt, discoverProjectMcps as K, uniqueSkillNamesFromReferences as Kn, pruneTodosByRun as Kr, useConfig as Kt, splitPromptSegments as L, ensureKeybindingsFile as Ln, TODOS_METADATA_KEY as Lr, CATPPUCCIN_FRAPPE as Lt, matchesSafelistEntry as M, summarizeOutcomes as Mn, PLAN_AGENT as Mr, BUILTIN_THEMES as Mt, projectsFilePath as N, findGitRoot$1 as Nn, accentColor as Nr, DEFAULT_THEME as Nt, IMPLICITLY_SAFE_TOOLS as O, parseEditOutcomesFromResult as On, BUILD_AGENT as Or, SETTINGS_TOGGLES as Ot, readProjects as P, DEFAULT_KEYBINDINGS as Pn, resolveAgentId as Pr, resolveChipColor as Pt, McpAuthProvider as Q, findActiveTrigger as Qn, DOING_TASKS_DOCTRINE as Qr, isEditErrorResult as Qt, formatPathForCwd as R, keybindingsPath as Rn, TODOWRITE_TOOL as Rr, CATPPUCCIN_LATTE as Rt, renderSession as S, splitLines as Sn, getModelInfo as Sr, fmtTokens as St, SafeModeProvider as T, buildEditOutcomesAnnotation as Tn, openaiDescriptor as Tr, useEnabledToggleSet as Tt, indexOfEntry as U, stripJsonComments as Un, getTodosForRun as Ur, useDiscovery as Ut, buildModelCatalog as V, parseBindingSpec as Vn, createTodoTools as Vr, createDiscoverySlot as Vt, buildMcpServers as W, SKILLS_TRIGGER as Wn, isTodoTool as Wr, useDiscoveryOptional as Wt, mcpCredentialsPath as X, applyInsert as Xn, ACTIONS_WITH_CARE_DOCTRINE as Xr, deriveSessionTitle as Xt, createFileMcpCredentialStore as Y, uniqueFilesFromReferences as Yn, useActiveTodos as Yr, createStateStore as Yt, patchMcpCredential as Z, collectReferences as Zn, COMMUNICATION_DOCTRINE as Zr, eventsFromTurns as Zt, turnContextSize as _, computeInlineDiff as _n, anthropicDescriptor as _r, truncateTrailing as _t, computeTurnAnchors as a, TOKEN_DISCIPLINE_DOCTRINE as ai, saveState as an, bootTick as ar, InteractionsProvider as at, defaultSkillScanPaths as b, filetypeFromPath as bn, effectiveContextWindow as br, ageString as bt, formatToolCall as c, envSection as ci, sumRunCosts as cn, applyApiKeyEnv as cr, createInteractionTools as ct, useSelectStyle as d, toolResultText as dn, readProviderCredential as dr, pendingInteractionsFromTurns as dt, INTERACTION_GUIDANCE as ei, isVisible as en, useCompletion as er, useMcpAuthState as et, useSurfaces as f, turnSelectionOwnership as fn, removeProviderCredential as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, buildUnifiedDiff as gn, OUTPUT_RESERVE_TOKENS as gr, hintsLength as gt, finalizeStreamingMarkdown as h, buildContextualDiff as hn, BUILTIN_PROVIDERS as hr, clipHintsToWidth as ht, turnAsText as i, SUBAGENT_GUIDANCE as ii, marginTopFor as in, bootProfileEnabled as ir, ASK_USER_TOOL as it, isOnSafelist as j, stripEditOutcomesAnnotation as jn, DEFAULT_PERSIST_EXCLUDE_TOOLS as jr, useSettings as jt, addToSafelist as k, resolveApprovalForPayload as kn, BUILTIN_AGENTS as kr, SettingsProvider as kt, ThemeProvider as l, titleFromTurns as ln, credentialsPath as lr, isInteractionTool as lt, useTheme as m, applyEditPayload as mn, writeCredentials as mr, useInteractionsQueue as mt, deleteTurnSafely as n, PLAN_MODE_DOCTRINE as ni, listSessionMeta as nn, buildLinearRamp as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, buildBuildSystem as oi, selectableTurnIds as on, shouldAutoCompact as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, updateToolEventOutcomes as pn, setProviderCredential as pr, useInteractionsActions as pt, parseMcpsFile as q, FILES_TRIGGER as qn, selectActiveTodos as qr, resolveConfig as qt, truncateTurnsAt as r, PLAN_MODE_DOCTRINE_NO_PROMPTS as ri, loadState as rn, tryOpenBrowser as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, buildPlanSystem as si, stripSpawnTokensLine as sn, detectAuth as sr, buildResumedToolResultsTurn as st, countNeighbors as t, INTERACTION_GUIDANCE_NO_PROMPTS as ti, lastContextSizeFromTurns as tn, blendHsl as tr, getMcpAuthStatus as tt, useColors as u, toolCallPreview as un, readCredentials as ur, makeRequestInteraction as ut, useStreamBuffer as v, computeLineDiff as vn, cerebrasDescriptor as vr, cleanTitle as vt, writeSessionExport as w, tokenize as wn, modelsForDescriptor as wr, listProjectFiles as wt, discoverProjectSkills as x, previewEditPayload as xn, getContextWindow as xr, compactPath as xt, buildSkillsConfig as y, extractEditPayload as yn, credKeyOf as yr, generateSessionTitle as yt, runOAuthLogin as z, matchesBinding as zn, TODO_STATUS_GLYPHS as zr, CATPPUCCIN_MACCHIATO as zt };
9156
+ export { useMcpAuthDispatch as $, tryOpenBrowser as $n, selectActiveTodos as $r, loadState as $t, getSafelist as A, DEFAULT_KEYBINDINGS as An, modelsForDescriptor as Ar, resolveChipColor as At, supportsOAuth as B, SKILLS_TRIGGER as Bn, resolveAgentId as Br, useDiscoveryOptional as Bt, resolveSessionExportTarget as C, mergeApprovalAndBodyOutcomes as Cn, anthropicDescriptor as Cr, SETTINGS_CHOICES as Ct, useSafeModeQueue as D, stripEditOutcomesAnnotation as Dn, getContextWindow as Dr, useSettings as Dt, useSafeModeActions as E, rewriteMultiEditHeader as En, effectiveContextWindow as Er, clampFps as Et, suggestSafelistEntry as F, matchesBinding as Fn, BUILTIN_AGENTS as Fr, CATPPUCCIN_MACCHIATO as Ft, defaultMcpsConfigPaths as G, uniqueFilesFromReferences as Gn, TODO_STATUS_GLYPHS as Gr, createStateStore as Gt, filterModelCatalog as H, uniqueSkillNamesFromReferences as Hn, TODOREAD_TOOL as Hr, useConfig as Ht, writeProjects as I, mergeKeybindings as In, DEFAULT_AGENT_ID as Ir, CATPPUCCIN_MOCHA as It, projectUserPaths as J, findActiveTrigger as Jn, getArchivedTodosForRun as Jr, isEditErrorResult as Jt, discoverProjectMcps as K, applyInsert as Kn, TODO_WRITE_COUNTS_METADATA_KEY as Kr, deriveSessionTitle as Kt, splitPromptSegments as L, parseBindingSpec as Ln, DEFAULT_PERSIST_EXCLUDE_TOOLS as Lr, createDiscoverySlot as Lt, matchesSafelistEntry as M, KEYBINDING_DEF_BY_ACTION as Mn, openrouterDescriptor as Mr, VAPORWAVE_THEME as Mt, projectsFilePath as N, ensureKeybindingsFile as Nn, piIdOf as Nr, CATPPUCCIN_FRAPPE as Nt, IMPLICITLY_SAFE_TOOLS as O, summarizeOutcomes as On, getModelInfo as Or, BUILTIN_THEMES as Ot, readProjects as P, keybindingsPath as Pn, BUILD_AGENT as Pr, CATPPUCCIN_LATTE as Pt, McpAuthProvider as Q, buildLinearRamp as Qn, pruneTodosByRun as Qr, listSessionMeta as Qt, formatPathForCwd as R, readKeybindings as Rn, PLAN_AGENT as Rr, DiscoveryProvider as Rt, renderSession as S, maskToOutcomeKinds as Sn, OUTPUT_RESERVE_TOKENS as Sr, DEFAULT_SETTINGS as St, SafeModeProvider as T, resolveApprovalForPayload as Tn, credKeyOf as Tr, SettingsProvider as Tt, indexOfEntry as U, FILES_TRIGGER as Un, TODOS_METADATA_KEY as Ur, resolveConfig as Ut, buildModelCatalog as V, createSkillsCompletionProvider as Vn, singleAgentRegistry as Vr, ConfigProvider as Vt, buildMcpServers as W, createFilesCompletionProvider as Wn, TODOWRITE_TOOL as Wr, EDIT_TOOL_NAMES as Wt, mcpCredentialsPath as X, useCompletion as Xn, isTodoTool as Xr, isVisible as Xt, createFileMcpCredentialStore as Y, mergeReferences as Yn, getTodosForRun as Yr, isTurnHighlighted as Yt, patchMcpCredential as Z, blendHsl as Zn, pickActiveRunId as Zr, lastContextSizeFromTurns as Zt, turnContextSize as _, previewEditPayload as _n, readProviderCredential as _r, truncateTrailing as _t, computeTurnAnchors as a, IDENTITY_PREFIX as ai, titleFromTurns as an, compareSemver as ar, InteractionsProvider as at, defaultSkillScanPaths as b, tokenize as bn, writeCredentials as br, listProjectFiles as bt, formatToolCall as c, PLAN_MODE_DOCTRINE as ci, turnSelectionOwnership as cn, parseSemver as cr, createInteractionTools as ct, useSelectStyle as d, TOKEN_DISCIPLINE_DOCTRINE as di, buildContextualDiff as dn, resolvePlatformPackage as dr, pendingInteractionsFromTurns as dt, setTodosForRun as ei, marginTopFor as en, bootProfileEnabled as er, useMcpAuthState as et, useSurfaces as f, buildBuildSystem as fi, buildUnifiedDiff as fn, shouldAutoCompact as fr, serializeInteractionResponse as ft, finalizeStreamingMarkdownForOwner as g, filetypeFromPath as gn, readCredentials as gr, hintsLength as gt, finalizeStreamingMarkdown as h, extractEditPayload as hn, credentialsPath as hr, clipHintsToWidth as ht, turnAsText as i, DOING_TASKS_DOCTRINE as ii, sumRunCosts as in, checkForUpdate as ir, ASK_USER_TOOL as it, isOnSafelist as j, KEYBINDING_DEFS as jn, openaiDescriptor as jr, resolveTheme as jt, addToSafelist as k, findGitRoot$1 as kn, modelSupportsReasoning as kr, DEFAULT_THEME as kt, ThemeProvider as l, PLAN_MODE_DOCTRINE_NO_PROMPTS as li, updateToolEventOutcomes as ln, performInPlaceSelfUpdate as lr, isInteractionTool as lt, useTheme as m, envSection as mi, computeLineDiff as mn, applyApiKeyEnv as mr, useInteractionsQueue as mt, deleteTurnSafely as n, ACTIONS_WITH_CARE_DOCTRINE as ni, selectableTurnIds as nn, buildUpdateHint as nr, reduceMcpAuth as nt, TOOL_DISPLAY as o, INTERACTION_GUIDANCE as oi, toolCallPreview as on, detectLibc as or, PRESENT_PLAN_TOOL as ot, useSyntaxStyles as p, buildPlanSystem as pi, computeInlineDiff as pn, detectAuth as pr, useInteractionsActions as pt, parseMcpsFile as q, collectReferences as qn, createTodoTools as qr, eventsFromTurns as qt, truncateTurnsAt as r, COMMUNICATION_DOCTRINE as ri, stripSpawnTokensLine as rn, useUpdateCheck as rr, splitMarkdownCodeBlocks as rt, displayNameFor as s, INTERACTION_GUIDANCE_NO_PROMPTS as si, toolResultText as sn, detectPackageManager as sr, buildResumedToolResultsTurn as st, countNeighbors as t, useActiveTodos as ti, saveState as tn, bootTick as tr, getMcpAuthStatus as tt, useColors as u, SUBAGENT_GUIDANCE as ui, applyEditPayload as un, performSelfUpdate as ur, makeRequestInteraction as ut, useStreamBuffer as v, splitLines as vn, removeProviderCredential as vr, cleanTitle as vt, writeSessionExport as w, parseEditOutcomesFromResult as wn, cerebrasDescriptor as wr, SETTINGS_TOGGLES as wt, discoverProjectSkills as x, buildEditOutcomesAnnotation as xn, BUILTIN_PROVIDERS as xr, useEnabledToggleSet as xt, buildSkillsConfig as y, summarizeEditPayload as yn, setProviderCredential as yr, generateSessionTitle as yt, runOAuthLogin as z, stripJsonComments as zn, accentColor as zr, useDiscovery as zt };
8250
9157
 
8251
- //# sourceMappingURL=turn-operations-OzKEOXul.js.map
9158
+ //# sourceMappingURL=turn-operations-DtMApNGT.js.map