zidane 5.5.0 → 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.
- package/dist/chat.d.ts +280 -2
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +203 -3
- package/dist/chat.js.map +1 -0
- package/dist/{contexts-DhmMlT2W.js → contexts-BOtMvzli.js} +1 -1
- package/dist/{contexts-DhmMlT2W.js.map → contexts-BOtMvzli.js.map} +1 -1
- package/dist/contexts.js +1 -1
- package/dist/{errors-CDwtPIMX.js → errors-C5VSakmT.js} +1 -1
- package/dist/{errors-CDwtPIMX.js.map → errors-C5VSakmT.js.map} +1 -1
- package/dist/index.js +12 -12
- package/dist/{interpolate-BaaKaKzN.js → interpolate-Cvjy8gpk.js} +2 -2
- package/dist/{interpolate-BaaKaKzN.js.map → interpolate-Cvjy8gpk.js.map} +1 -1
- package/dist/{login-iTy-0wYz.js → login-DthdFNzR.js} +4 -4
- package/dist/{login-iTy-0wYz.js.map → login-DthdFNzR.js.map} +1 -1
- package/dist/{mcp-CNUbvbsy.js → mcp-C8XUNC_R.js} +3 -3
- package/dist/{mcp-CNUbvbsy.js.map → mcp-C8XUNC_R.js.map} +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-fTR19Ga6.js → messages-BBWakTN6.js} +2 -2
- package/dist/{messages-fTR19Ga6.js.map → messages-BBWakTN6.js.map} +1 -1
- package/dist/{presets-h6UWhghO.js → presets-C5E9hokO.js} +2 -2
- package/dist/{presets-h6UWhghO.js.map → presets-C5E9hokO.js.map} +1 -1
- package/dist/presets.js +1 -1
- package/dist/{providers-G0VBZK9j.js → providers-CsUyN_FJ.js} +3 -3
- package/dist/{providers-G0VBZK9j.js.map → providers-CsUyN_FJ.js.map} +1 -1
- package/dist/providers.js +2 -2
- package/dist/session/sqlite.js +1 -1
- package/dist/{session-CbkiJDlH.js → session-DzfRacU_.js} +2 -2
- package/dist/{session-CbkiJDlH.js.map → session-DzfRacU_.js.map} +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.js +1 -1
- package/dist/{stats-DgOvY7wd.js → stats-Lc3zL3RM.js} +1 -1
- package/dist/{stats-DgOvY7wd.js.map → stats-Lc3zL3RM.js.map} +1 -1
- package/dist/{tools-D_icxa-V.js → tools-BavL6n7q.js} +8 -8
- package/dist/{tools-D_icxa-V.js.map → tools-BavL6n7q.js.map} +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-3FFw2xuk.d.ts → transcript-anchors-BMZRmrYk.d.ts} +134 -64
- package/dist/transcript-anchors-BMZRmrYk.d.ts.map +1 -0
- package/dist/tui.d.ts +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +25 -12
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CtgBlBHn.js → turn-operations-DtMApNGT.js} +822 -14
- package/dist/turn-operations-DtMApNGT.js.map +1 -0
- package/dist/{types-IcokUOyC.js → types-C-9h2drI.js} +1 -1
- package/dist/{types-IcokUOyC.js.map → types-C-9h2drI.js.map} +1 -1
- package/dist/types.js +3 -3
- package/docs/TUI.md +72 -1
- package/package.json +1 -1
- package/dist/transcript-anchors-3FFw2xuk.d.ts.map +0 -1
- package/dist/turn-operations-CtgBlBHn.js.map +0 -1
|
@@ -1,20 +1,26 @@
|
|
|
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-
|
|
2
|
-
import { s as errorMessage } from "./errors-
|
|
3
|
-
import { n as toolResultToText } from "./types-
|
|
4
|
-
import { r as normalizeMcpServers } from "./mcp-
|
|
5
|
-
import { a as discoverSkills } from "./interpolate-
|
|
6
|
-
import { n as formatTokenUsage } from "./stats-
|
|
7
|
-
import { n as definePreset, t as composePresets } from "./presets-
|
|
8
|
-
import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-
|
|
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";
|
|
9
10
|
import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
10
|
-
import { homedir } from "node:os";
|
|
11
|
+
import { homedir, tmpdir } from "node:os";
|
|
11
12
|
import { spawn } from "node:child_process";
|
|
12
|
-
import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
13
|
+
import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
13
14
|
import { readdir, stat, writeFile } from "node:fs/promises";
|
|
14
15
|
import { getModel, getModels } from "@mariozechner/pi-ai";
|
|
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
|
/**
|
|
@@ -3992,7 +4793,8 @@ function resolveConfig(options) {
|
|
|
3992
4793
|
initialSettings: migrateLegacySettings(initialState.settings ?? {}),
|
|
3993
4794
|
resumeProvider,
|
|
3994
4795
|
initialPicked,
|
|
3995
|
-
keybindings
|
|
4796
|
+
keybindings,
|
|
4797
|
+
autoUpdate: options.autoUpdate ?? null
|
|
3996
4798
|
};
|
|
3997
4799
|
}
|
|
3998
4800
|
/**
|
|
@@ -5091,7 +5893,8 @@ const DEFAULT_SETTINGS = {
|
|
|
5091
5893
|
allowInteraction: true,
|
|
5092
5894
|
smoothStreaming: true,
|
|
5093
5895
|
showTodoIndicator: true,
|
|
5094
|
-
showThrobber: false
|
|
5896
|
+
showThrobber: false,
|
|
5897
|
+
checkForUpdates: true
|
|
5095
5898
|
};
|
|
5096
5899
|
/**
|
|
5097
5900
|
* Hard-clamp a `targetFps` value to a safe range before handing it to
|
|
@@ -5216,6 +6019,11 @@ const SETTINGS_TOGGLES = [
|
|
|
5216
6019
|
key: "showThrobber",
|
|
5217
6020
|
label: "Streaming throbber",
|
|
5218
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."
|
|
5219
6027
|
}
|
|
5220
6028
|
];
|
|
5221
6029
|
const SETTINGS_CHOICES = [
|
|
@@ -8345,6 +9153,6 @@ function countNeighbors(turnIds, turnId) {
|
|
|
8345
9153
|
};
|
|
8346
9154
|
}
|
|
8347
9155
|
//#endregion
|
|
8348
|
-
export { useMcpAuthDispatch as $, tryOpenBrowser as $n,
|
|
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 };
|
|
8349
9157
|
|
|
8350
|
-
//# sourceMappingURL=turn-operations-
|
|
9158
|
+
//# sourceMappingURL=turn-operations-DtMApNGT.js.map
|