zidane 5.6.3 → 5.6.7
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 +158 -3
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +3 -3
- package/dist/{index-DKpXHp1c.d.ts → index-8mn3PIaa.d.ts} +24 -1
- package/dist/{index-DKpXHp1c.d.ts.map → index-8mn3PIaa.d.ts.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/{login-YckkS-Bq.js → login-Btpliwct.js} +2 -2
- package/dist/{login-YckkS-Bq.js.map → login-Btpliwct.js.map} +1 -1
- package/dist/{presets-ZT3TJDEb.js → presets-BXmWG3kd.js} +2 -2
- package/dist/{presets-ZT3TJDEb.js.map → presets-BXmWG3kd.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{tools-Bgx8OBqK.js → tools-FerA0zSl.js} +72 -9
- package/dist/tools-FerA0zSl.js.map +1 -0
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-CtSVZeBi.d.ts → transcript-anchors-C5Sp1Snh.d.ts} +256 -18
- package/dist/transcript-anchors-C5Sp1Snh.d.ts.map +1 -0
- package/dist/tui.d.ts +47 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +456 -175
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CH7rnULP.js → turn-operations-D-OQYUgS.js} +524 -125
- package/dist/turn-operations-D-OQYUgS.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/docs/CHAT.md +52 -20
- package/docs/TUI.md +5 -5
- package/package.json +1 -1
- package/dist/tools-Bgx8OBqK.js.map +0 -1
- package/dist/transcript-anchors-CtSVZeBi.d.ts.map +0 -1
- package/dist/turn-operations-CH7rnULP.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { H as previewLine, R as fmtTokens, U as shortId, a as multiEdit, c as grep, d as resolveOldString, f as styleReplacementForVia, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, t as writeFile$1, u as edit, y as shell } from "./tools-
|
|
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-FerA0zSl.js";
|
|
2
2
|
import { c as errorMessage } from "./errors-DdZXnyXE.js";
|
|
3
3
|
import { r as toolResultToText } from "./types-oKPBdCmL.js";
|
|
4
4
|
import { r as normalizeMcpServers } from "./mcp-ngMS0S6N.js";
|
|
5
5
|
import { a as discoverSkills } from "./interpolate-DM1UcKeQ.js";
|
|
6
6
|
import { n as formatTokenUsage } from "./stats-Lc3zL3RM.js";
|
|
7
|
-
import { n as definePreset, t as composePresets } from "./presets-
|
|
7
|
+
import { n as definePreset, t as composePresets } from "./presets-BXmWG3kd.js";
|
|
8
8
|
import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CaJE2ToS.js";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
@@ -237,7 +237,8 @@ function buildBuildSystem(opts = {}) {
|
|
|
237
237
|
TOKEN_DISCIPLINE_DOCTRINE,
|
|
238
238
|
SUBAGENT_GUIDANCE,
|
|
239
239
|
COMMUNICATION_DOCTRINE,
|
|
240
|
-
interactionGuidance
|
|
240
|
+
interactionGuidance,
|
|
241
|
+
opts.userInstructions || null
|
|
241
242
|
]);
|
|
242
243
|
}
|
|
243
244
|
/**
|
|
@@ -253,7 +254,8 @@ function buildPlanSystem(opts = {}) {
|
|
|
253
254
|
noPrompts ? PLAN_MODE_DOCTRINE_NO_PROMPTS : PLAN_MODE_DOCTRINE,
|
|
254
255
|
TOKEN_DISCIPLINE_DOCTRINE,
|
|
255
256
|
COMMUNICATION_DOCTRINE,
|
|
256
|
-
noPrompts ? INTERACTION_GUIDANCE_NO_PROMPTS : INTERACTION_GUIDANCE
|
|
257
|
+
noPrompts ? INTERACTION_GUIDANCE_NO_PROMPTS : INTERACTION_GUIDANCE,
|
|
258
|
+
opts.userInstructions || null
|
|
257
259
|
]);
|
|
258
260
|
}
|
|
259
261
|
function joinPrompt(parts) {
|
|
@@ -1048,6 +1050,227 @@ function singleAgentRegistry(preset) {
|
|
|
1048
1050
|
} };
|
|
1049
1051
|
}
|
|
1050
1052
|
//#endregion
|
|
1053
|
+
//#region src/chat/project-root.ts
|
|
1054
|
+
/**
|
|
1055
|
+
* Git root detection — walks parents from `cwd` looking for a `.git`
|
|
1056
|
+
* entry, returning the absolute path of the repo root or `null` when
|
|
1057
|
+
* the search reaches the filesystem root.
|
|
1058
|
+
*
|
|
1059
|
+
* Why parent-walk over `git rev-parse --show-toplevel`:
|
|
1060
|
+
*
|
|
1061
|
+
* - Zero dependencies (no shell-out, no git binary requirement,
|
|
1062
|
+
* works even when `git` is missing from `PATH`).
|
|
1063
|
+
* - Pure-sync, deterministic, easy to test against tmp dirs.
|
|
1064
|
+
* - Equally fast in practice — most lookups are a single `existsSync`.
|
|
1065
|
+
*
|
|
1066
|
+
* Recognizes `.git` as either:
|
|
1067
|
+
*
|
|
1068
|
+
* - A directory (standard repo layout).
|
|
1069
|
+
* - A file containing `gitdir: …` (worktrees + submodules).
|
|
1070
|
+
*
|
|
1071
|
+
* Bare repos (no working tree) are intentionally NOT detected here —
|
|
1072
|
+
* the TUI's data dir contract is "project working tree", and a bare
|
|
1073
|
+
* repo has no working files to scope sessions against.
|
|
1074
|
+
*/
|
|
1075
|
+
/**
|
|
1076
|
+
* Walk parents of `cwd` looking for a `.git` entry. Returns the
|
|
1077
|
+
* absolute path of the directory containing `.git`, or `null` when no
|
|
1078
|
+
* git repo is found above `cwd`.
|
|
1079
|
+
*
|
|
1080
|
+
* Stops at the filesystem root (`/`) — no infinite loop on `dirname`'s
|
|
1081
|
+
* idempotent root case (`dirname('/')` returns `/`).
|
|
1082
|
+
*/
|
|
1083
|
+
function findGitRoot$1(cwd = process.cwd()) {
|
|
1084
|
+
let dir = resolve(cwd);
|
|
1085
|
+
for (let depth = 0; depth < 64; depth++) {
|
|
1086
|
+
if (hasGitMarker(dir)) return dir;
|
|
1087
|
+
const parent = dirname(dir);
|
|
1088
|
+
if (parent === dir) return null;
|
|
1089
|
+
dir = parent;
|
|
1090
|
+
}
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* `.git` exists as a directory (standard repo) OR as a file containing
|
|
1095
|
+
* a `gitdir:` pointer (worktree / submodule). Tolerant on stat failures
|
|
1096
|
+
* — a permission error on a parent directory shouldn't crash the walk.
|
|
1097
|
+
*/
|
|
1098
|
+
function hasGitMarker(dir) {
|
|
1099
|
+
const candidate = resolve(dir, ".git");
|
|
1100
|
+
try {
|
|
1101
|
+
if (!existsSync(candidate)) return false;
|
|
1102
|
+
const stat = statSync(candidate);
|
|
1103
|
+
return stat.isDirectory() || stat.isFile();
|
|
1104
|
+
} catch {
|
|
1105
|
+
return false;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
//#endregion
|
|
1109
|
+
//#region src/chat/agents-md.ts
|
|
1110
|
+
/**
|
|
1111
|
+
* Personal instructions discovery — load user + project `AGENTS.md` /
|
|
1112
|
+
* `CLAUDE.md` files.
|
|
1113
|
+
*
|
|
1114
|
+
* Every file that exists is loaded — no shadowing within a scope.
|
|
1115
|
+
* Users routinely split doctrine across files ("`~/.agents/AGENTS.md`
|
|
1116
|
+
* for cross-tool portable rules, `~/.zidane/AGENTS.md` for
|
|
1117
|
+
* zidane-specific tweaks") and silently dropping a file they committed
|
|
1118
|
+
* is surprising. Empty or whitespace-only files are skipped.
|
|
1119
|
+
*
|
|
1120
|
+
* Two conventions are supported in each scope:
|
|
1121
|
+
* - `AGENTS.md` — Codex / Cursor / agentic-tools convention.
|
|
1122
|
+
* - `CLAUDE.md` — Claude Code convention.
|
|
1123
|
+
*
|
|
1124
|
+
* Search order (broadest scope first; same order in the rendered
|
|
1125
|
+
* block, so narrower scopes land closer to the conversation and
|
|
1126
|
+
* override broader ones in the model's eyes):
|
|
1127
|
+
*
|
|
1128
|
+
* user scope:
|
|
1129
|
+
* 1. `~/.agents/AGENTS.md` — agnostic
|
|
1130
|
+
* 2. `~/.{prefix}/AGENTS.md` — zidane (`.zidane` default)
|
|
1131
|
+
* 3. `~/.claude/CLAUDE.md` — Claude Code
|
|
1132
|
+
*
|
|
1133
|
+
* project scope (anchored at git root, else cwd):
|
|
1134
|
+
* 4. `<root>/AGENTS.md` — Codex convention
|
|
1135
|
+
* 5. `<root>/.agents/AGENTS.md` — agnostic
|
|
1136
|
+
* 6. `<root>/.{prefix}/AGENTS.md` — zidane
|
|
1137
|
+
* 7. `<root>/CLAUDE.md` — Claude Code
|
|
1138
|
+
*
|
|
1139
|
+
* The {@link DiscoverAgentsMdOptions.scope} option restricts which
|
|
1140
|
+
* scopes contribute. Defaults to `'both'` (the historical behavior).
|
|
1141
|
+
*
|
|
1142
|
+
* Each file is rendered as a section with its absolute path as the
|
|
1143
|
+
* header so the model can cite the source verbatim when it asks the
|
|
1144
|
+
* user about something that came from there.
|
|
1145
|
+
*/
|
|
1146
|
+
/** Sane upper bound per file so a runaway log dumped as AGENTS.md doesn't blow the prompt. */
|
|
1147
|
+
const MAX_BYTES_PER_FILE = 64 * 1024;
|
|
1148
|
+
/**
|
|
1149
|
+
* Walk the candidate paths and load every `AGENTS.md` that exists.
|
|
1150
|
+
*
|
|
1151
|
+
* Project paths anchor at the git root when one exists above `cwd`,
|
|
1152
|
+
* else at `cwd` itself — same anchor logic as `projectUserPaths` so the
|
|
1153
|
+
* three discovery surfaces (skills, mcps, AGENTS.md) stay in lock-step.
|
|
1154
|
+
*
|
|
1155
|
+
* All matching files are loaded (no shadowing within a scope). Empty
|
|
1156
|
+
* or whitespace-only files are skipped. Render order matches the
|
|
1157
|
+
* search order — broader scopes first, narrower scopes last so the
|
|
1158
|
+
* project-specific file lands closest to the conversation.
|
|
1159
|
+
*
|
|
1160
|
+
* Tolerant on read failures: an unreadable file is skipped silently
|
|
1161
|
+
* (logged under `ZIDANE_DEBUG`). The loader never throws — bootstrap
|
|
1162
|
+
* paths can't afford to crash on a permission glitch.
|
|
1163
|
+
*
|
|
1164
|
+
* Defensive dedup: when `<git-root> === ~` (the user launched zidane
|
|
1165
|
+
* directly from `$HOME` and `$HOME` happens to be a git repo) the
|
|
1166
|
+
* project + user candidate sets would otherwise overlap. We dedup by
|
|
1167
|
+
* absolute path so the same file never lands in the block twice.
|
|
1168
|
+
*/
|
|
1169
|
+
function discoverAgentsMd(opts = {}) {
|
|
1170
|
+
const scope = opts.scope ?? "both";
|
|
1171
|
+
if (scope === "none") return {
|
|
1172
|
+
files: [],
|
|
1173
|
+
block: null
|
|
1174
|
+
};
|
|
1175
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
1176
|
+
const home = opts.home ?? homedir();
|
|
1177
|
+
const prefix = (opts.prefix ?? ".zidane").replace(/^\./, "");
|
|
1178
|
+
const projectRoot = findGitRoot$1(cwd) ?? cwd;
|
|
1179
|
+
const userCandidates = [
|
|
1180
|
+
{
|
|
1181
|
+
path: resolve(home, `.agents/AGENTS.md`),
|
|
1182
|
+
source: "user"
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
path: resolve(home, `.${prefix}/AGENTS.md`),
|
|
1186
|
+
source: "user"
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
path: resolve(home, `.claude/CLAUDE.md`),
|
|
1190
|
+
source: "user"
|
|
1191
|
+
}
|
|
1192
|
+
];
|
|
1193
|
+
const projectCandidates = [
|
|
1194
|
+
{
|
|
1195
|
+
path: resolve(projectRoot, "AGENTS.md"),
|
|
1196
|
+
source: "project"
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
path: resolve(projectRoot, `.agents/AGENTS.md`),
|
|
1200
|
+
source: "project"
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
path: resolve(projectRoot, `.${prefix}/AGENTS.md`),
|
|
1204
|
+
source: "project"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
path: resolve(projectRoot, "CLAUDE.md"),
|
|
1208
|
+
source: "project"
|
|
1209
|
+
}
|
|
1210
|
+
];
|
|
1211
|
+
const ordered = [];
|
|
1212
|
+
if (scope !== "project") ordered.push(...userCandidates);
|
|
1213
|
+
if (scope !== "user") ordered.push(...projectCandidates);
|
|
1214
|
+
const files = [];
|
|
1215
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1216
|
+
for (const c of ordered) {
|
|
1217
|
+
if (seen.has(c.path)) continue;
|
|
1218
|
+
const file = readIfPresent(c.path, c.source);
|
|
1219
|
+
if (file) {
|
|
1220
|
+
seen.add(c.path);
|
|
1221
|
+
files.push(file);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (files.length === 0) return {
|
|
1225
|
+
files,
|
|
1226
|
+
block: null
|
|
1227
|
+
};
|
|
1228
|
+
return {
|
|
1229
|
+
files,
|
|
1230
|
+
block: renderAgentsMdBlock(files)
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Render one or more `AgentsMdFile` into a system-prompt block.
|
|
1235
|
+
*
|
|
1236
|
+
* Top header tells the model what's coming + that it's user-authored
|
|
1237
|
+
* (so it's treated as guidance, not as a system constraint that can't
|
|
1238
|
+
* be questioned). Each file becomes a sub-section with its absolute
|
|
1239
|
+
* path so the model can cite it back when asking follow-up questions.
|
|
1240
|
+
*
|
|
1241
|
+
* Exported separately so callers building custom profiles can inject
|
|
1242
|
+
* their own discovery list (e.g. an SDK consumer pulling AGENTS.md
|
|
1243
|
+
* from a remote source) without re-implementing the rendering.
|
|
1244
|
+
*/
|
|
1245
|
+
function renderAgentsMdBlock(files) {
|
|
1246
|
+
if (files.length === 0) return "";
|
|
1247
|
+
return [
|
|
1248
|
+
"# User instructions",
|
|
1249
|
+
"The following sections come from `AGENTS.md` files the user authored. Treat them as durable preferences and context that apply for this session — they extend, and where they conflict take precedence over, the doctrine above.",
|
|
1250
|
+
...files.map((f) => {
|
|
1251
|
+
const scope = f.source === "project" ? "project" : "user";
|
|
1252
|
+
return `## ${f.path} (${scope})\n\n${f.contents.trim()}`;
|
|
1253
|
+
})
|
|
1254
|
+
].join("\n\n");
|
|
1255
|
+
}
|
|
1256
|
+
function readIfPresent(path, source) {
|
|
1257
|
+
if (!existsSync(path)) return null;
|
|
1258
|
+
let raw;
|
|
1259
|
+
try {
|
|
1260
|
+
raw = readFileSync(path, "utf8");
|
|
1261
|
+
} catch (err) {
|
|
1262
|
+
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/chat] agents-md: failed to read "${path}": ${errorMessage(err)}\n`);
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
const contents = raw.length > MAX_BYTES_PER_FILE ? `${raw.slice(0, MAX_BYTES_PER_FILE)}\n\n[... truncated; ${raw.length - MAX_BYTES_PER_FILE} more bytes in source file ...]` : raw;
|
|
1266
|
+
if (contents.trim().length === 0) return null;
|
|
1267
|
+
return {
|
|
1268
|
+
path,
|
|
1269
|
+
source,
|
|
1270
|
+
contents
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
//#endregion
|
|
1051
1274
|
//#region src/chat/providers.ts
|
|
1052
1275
|
/** Convenience accessor — returns `credentialFileKey ?? key`. */
|
|
1053
1276
|
function credKeyOf(desc) {
|
|
@@ -3272,6 +3495,48 @@ function keybindingsPath(userDir) {
|
|
|
3272
3495
|
return resolve(userDir, "keybindings.json");
|
|
3273
3496
|
}
|
|
3274
3497
|
/**
|
|
3498
|
+
* Walk {@link KEYBINDING_DEFS} in order and bucket rows into contiguous
|
|
3499
|
+
* sections by `group`. Shared between the standalone `KeybindingsModal`
|
|
3500
|
+
* and the `Keybindings` tab inside `SettingsModal` so both surfaces
|
|
3501
|
+
* render the same catalog with the same ordering rules.
|
|
3502
|
+
*/
|
|
3503
|
+
function groupBindings(bindings) {
|
|
3504
|
+
const sections = [];
|
|
3505
|
+
for (const def of KEYBINDING_DEFS) {
|
|
3506
|
+
const last = sections[sections.length - 1];
|
|
3507
|
+
const spec = bindings[def.action] ?? "";
|
|
3508
|
+
if (last && last.group === def.group) {
|
|
3509
|
+
last.rows.push({
|
|
3510
|
+
def,
|
|
3511
|
+
spec
|
|
3512
|
+
});
|
|
3513
|
+
continue;
|
|
3514
|
+
}
|
|
3515
|
+
sections.push({
|
|
3516
|
+
group: def.group,
|
|
3517
|
+
rows: [{
|
|
3518
|
+
def,
|
|
3519
|
+
spec
|
|
3520
|
+
}]
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
return sections;
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Width (in cells) of the fixed key column used by every binding-row
|
|
3527
|
+
* renderer. Derived once from {@link KEYBINDING_DEFS} so a new action
|
|
3528
|
+
* with a wider default spec (`ctrl+shift+x`, …) automatically grows
|
|
3529
|
+
* the column instead of truncating the label.
|
|
3530
|
+
*/
|
|
3531
|
+
const KEYBINDING_KEY_COL_WIDTH = (() => {
|
|
3532
|
+
let max = 8;
|
|
3533
|
+
for (const def of KEYBINDING_DEFS) {
|
|
3534
|
+
const width = formatBindingForDisplay(def.default).length;
|
|
3535
|
+
if (width > max) max = width;
|
|
3536
|
+
}
|
|
3537
|
+
return max + 2;
|
|
3538
|
+
})();
|
|
3539
|
+
/**
|
|
3275
3540
|
* Load + merge the user's keybindings file (when present). Always
|
|
3276
3541
|
* returns a fully-resolved {@link KeyBindings} — defaults fill in for
|
|
3277
3542
|
* any missing / invalid entries so consumers can treat the result as
|
|
@@ -3385,62 +3650,6 @@ function stripJsonComments(input) {
|
|
|
3385
3650
|
return out;
|
|
3386
3651
|
}
|
|
3387
3652
|
//#endregion
|
|
3388
|
-
//#region src/chat/project-root.ts
|
|
3389
|
-
/**
|
|
3390
|
-
* Git root detection — walks parents from `cwd` looking for a `.git`
|
|
3391
|
-
* entry, returning the absolute path of the repo root or `null` when
|
|
3392
|
-
* the search reaches the filesystem root.
|
|
3393
|
-
*
|
|
3394
|
-
* Why parent-walk over `git rev-parse --show-toplevel`:
|
|
3395
|
-
*
|
|
3396
|
-
* - Zero dependencies (no shell-out, no git binary requirement,
|
|
3397
|
-
* works even when `git` is missing from `PATH`).
|
|
3398
|
-
* - Pure-sync, deterministic, easy to test against tmp dirs.
|
|
3399
|
-
* - Equally fast in practice — most lookups are a single `existsSync`.
|
|
3400
|
-
*
|
|
3401
|
-
* Recognizes `.git` as either:
|
|
3402
|
-
*
|
|
3403
|
-
* - A directory (standard repo layout).
|
|
3404
|
-
* - A file containing `gitdir: …` (worktrees + submodules).
|
|
3405
|
-
*
|
|
3406
|
-
* Bare repos (no working tree) are intentionally NOT detected here —
|
|
3407
|
-
* the TUI's data dir contract is "project working tree", and a bare
|
|
3408
|
-
* repo has no working files to scope sessions against.
|
|
3409
|
-
*/
|
|
3410
|
-
/**
|
|
3411
|
-
* Walk parents of `cwd` looking for a `.git` entry. Returns the
|
|
3412
|
-
* absolute path of the directory containing `.git`, or `null` when no
|
|
3413
|
-
* git repo is found above `cwd`.
|
|
3414
|
-
*
|
|
3415
|
-
* Stops at the filesystem root (`/`) — no infinite loop on `dirname`'s
|
|
3416
|
-
* idempotent root case (`dirname('/')` returns `/`).
|
|
3417
|
-
*/
|
|
3418
|
-
function findGitRoot$1(cwd = process.cwd()) {
|
|
3419
|
-
let dir = resolve(cwd);
|
|
3420
|
-
for (let depth = 0; depth < 64; depth++) {
|
|
3421
|
-
if (hasGitMarker(dir)) return dir;
|
|
3422
|
-
const parent = dirname(dir);
|
|
3423
|
-
if (parent === dir) return null;
|
|
3424
|
-
dir = parent;
|
|
3425
|
-
}
|
|
3426
|
-
return null;
|
|
3427
|
-
}
|
|
3428
|
-
/**
|
|
3429
|
-
* `.git` exists as a directory (standard repo) OR as a file containing
|
|
3430
|
-
* a `gitdir:` pointer (worktree / submodule). Tolerant on stat failures
|
|
3431
|
-
* — a permission error on a parent directory shouldn't crash the walk.
|
|
3432
|
-
*/
|
|
3433
|
-
function hasGitMarker(dir) {
|
|
3434
|
-
const candidate = resolve(dir, ".git");
|
|
3435
|
-
try {
|
|
3436
|
-
if (!existsSync(candidate)) return false;
|
|
3437
|
-
const stat = statSync(candidate);
|
|
3438
|
-
return stat.isDirectory() || stat.isFile();
|
|
3439
|
-
} catch {
|
|
3440
|
-
return false;
|
|
3441
|
-
}
|
|
3442
|
-
}
|
|
3443
|
-
//#endregion
|
|
3444
3653
|
//#region src/chat/edit-approval.ts
|
|
3445
3654
|
/**
|
|
3446
3655
|
* Convert a per-hunk approval mask into an `EditOutcome[]`. `true` →
|
|
@@ -4892,14 +5101,95 @@ function normalizeUserConfig(raw) {
|
|
|
4892
5101
|
return out;
|
|
4893
5102
|
}
|
|
4894
5103
|
//#endregion
|
|
5104
|
+
//#region src/chat/xdg.ts
|
|
5105
|
+
/**
|
|
5106
|
+
* XDG Base Directory resolution for zidane.
|
|
5107
|
+
*
|
|
5108
|
+
* The user's storage spreads across four logical slots:
|
|
5109
|
+
*
|
|
5110
|
+
* - **config** — credentials, mcp-credentials, keybindings, config.json,
|
|
5111
|
+
* mcps.json, skills (user-editable surface).
|
|
5112
|
+
* - **data** — sessions.db (long-lived chat history).
|
|
5113
|
+
* - **state** — state.json (per-machine UI bookkeeping: last provider,
|
|
5114
|
+
* last model, last agent, settings).
|
|
5115
|
+
* - **cache** — persisted tool results, background-task logs,
|
|
5116
|
+
* auto-update registry cache (regenerable, safe to wipe).
|
|
5117
|
+
*
|
|
5118
|
+
* Historically all four collapsed to `~/.zidane/`. This module adds
|
|
5119
|
+
* XDG-Base-Directory-aware defaults so a Linux user with no existing
|
|
5120
|
+
* `~/.zidane/` lands in the conventional `~/.config/zidane/`,
|
|
5121
|
+
* `~/.local/share/zidane/`, `~/.local/state/zidane/`, `~/.cache/zidane/`
|
|
5122
|
+
* trio. Existing setups (anyone with a `~/.zidane/` directory or
|
|
5123
|
+
* `ZIDANE_STORAGE_DIR` set) keep the single-dir layout unchanged.
|
|
5124
|
+
*
|
|
5125
|
+
* Resolution flow — applied in this order:
|
|
5126
|
+
*
|
|
5127
|
+
* 1. Caller passed an explicit `storageDir` (`ChatOptions.storageDir`)
|
|
5128
|
+
* OR `ZIDANE_STORAGE_DIR` is set → **legacy-explicit** single-dir
|
|
5129
|
+
* layout under `<storageDir>/<prefix>`. The four slots collapse to
|
|
5130
|
+
* the same directory.
|
|
5131
|
+
* 2. `~/<prefix>/` already exists on disk → **legacy-existing**
|
|
5132
|
+
* single-dir layout under that directory. Upgrades never silently
|
|
5133
|
+
* shift files around.
|
|
5134
|
+
* 3. Any `XDG_*_HOME` env var is set OR `process.platform === 'linux'`
|
|
5135
|
+
* → **XDG split**. Each slot lands in its own dir. Per-slot
|
|
5136
|
+
* `ZIDANE_{CONFIG,DATA,CACHE,STATE}_DIR` overrides beat the XDG
|
|
5137
|
+
* vars for surgical tweaks.
|
|
5138
|
+
* 4. Otherwise (macOS/Windows, no XDG signal, no existing dir) →
|
|
5139
|
+
* **default** single-dir layout at `~/<prefix>/`. Day-one behavior
|
|
5140
|
+
* on these platforms is unchanged.
|
|
5141
|
+
*
|
|
5142
|
+
* The `userDir` legacy alias always equals `configDir` so existing code
|
|
5143
|
+
* that still references `paths.userDir` keeps reading credentials, mcps,
|
|
5144
|
+
* etc. from the right place.
|
|
5145
|
+
*/
|
|
5146
|
+
/**
|
|
5147
|
+
* Resolve the four storage slots according to the precedence above.
|
|
5148
|
+
*
|
|
5149
|
+
* Pure aside from one filesystem probe (`existsSync(home/<prefix>)`)
|
|
5150
|
+
* — the same probe `resolveStoragePaths` would do anyway when
|
|
5151
|
+
* computing `paths.userDir`. No directories are created here; the
|
|
5152
|
+
* relevant write paths (state store, credentials writer, persist
|
|
5153
|
+
* dir) handle their own lazy `mkdirSync` already.
|
|
5154
|
+
*/
|
|
5155
|
+
function resolveStorageDirs(opts = {}) {
|
|
5156
|
+
const env = opts.env ?? process.env;
|
|
5157
|
+
const home = opts.home ?? homedir();
|
|
5158
|
+
const platform = opts.platform ?? process.platform;
|
|
5159
|
+
const rawPrefix = opts.prefix ?? ".zidane";
|
|
5160
|
+
const prefixBare = rawPrefix.replace(/^\./, "");
|
|
5161
|
+
const explicitStorageDir = opts.storageDir ?? env.ZIDANE_STORAGE_DIR;
|
|
5162
|
+
if (explicitStorageDir) return single(resolve(explicitStorageDir, rawPrefix), "legacy-explicit");
|
|
5163
|
+
const legacyHomeDir = resolve(home, rawPrefix);
|
|
5164
|
+
if (existsSync(legacyHomeDir)) return single(legacyHomeDir, "legacy-existing");
|
|
5165
|
+
if (platform === "linux" || !!env.XDG_CONFIG_HOME || !!env.XDG_DATA_HOME || !!env.XDG_CACHE_HOME || !!env.XDG_STATE_HOME || !!env.ZIDANE_CONFIG_DIR || !!env.ZIDANE_DATA_DIR || !!env.ZIDANE_STATE_DIR || !!env.ZIDANE_CACHE_DIR) return {
|
|
5166
|
+
configDir: env.ZIDANE_CONFIG_DIR ?? resolve(env.XDG_CONFIG_HOME || resolve(home, ".config"), prefixBare),
|
|
5167
|
+
dataDir: env.ZIDANE_DATA_DIR ?? resolve(env.XDG_DATA_HOME || resolve(home, ".local", "share"), prefixBare),
|
|
5168
|
+
stateDir: env.ZIDANE_STATE_DIR ?? resolve(env.XDG_STATE_HOME || resolve(home, ".local", "state"), prefixBare),
|
|
5169
|
+
cacheDir: env.ZIDANE_CACHE_DIR ?? resolve(env.XDG_CACHE_HOME || resolve(home, ".cache"), prefixBare),
|
|
5170
|
+
mode: "xdg"
|
|
5171
|
+
};
|
|
5172
|
+
return single(legacyHomeDir, "default");
|
|
5173
|
+
}
|
|
5174
|
+
function single(base, mode) {
|
|
5175
|
+
return {
|
|
5176
|
+
configDir: base,
|
|
5177
|
+
dataDir: base,
|
|
5178
|
+
stateDir: base,
|
|
5179
|
+
cacheDir: base,
|
|
5180
|
+
mode
|
|
5181
|
+
};
|
|
5182
|
+
}
|
|
5183
|
+
//#endregion
|
|
4895
5184
|
//#region src/chat/config.ts
|
|
4896
5185
|
/** Resolve user options into a fully-bound runtime config. Pure aside from disk reads. */
|
|
4897
5186
|
function resolveConfig(options) {
|
|
4898
5187
|
const prefix = options.prefix ?? process.env.ZIDANE_PREFIX ?? ".zidane";
|
|
4899
|
-
const
|
|
5188
|
+
const explicitStorageDir = options.storageDir ?? process.env.ZIDANE_STORAGE_DIR;
|
|
5189
|
+
const storageDir = explicitStorageDir ?? homedir();
|
|
4900
5190
|
const paths = resolveStoragePaths({
|
|
4901
5191
|
prefix,
|
|
4902
|
-
storageDir,
|
|
5192
|
+
...explicitStorageDir !== void 0 ? { storageDir: explicitStorageDir } : {},
|
|
4903
5193
|
cwd: options.cwd ?? process.cwd(),
|
|
4904
5194
|
projectDb: options.projectDb
|
|
4905
5195
|
});
|
|
@@ -4942,26 +5232,37 @@ function resolveConfig(options) {
|
|
|
4942
5232
|
* (CLI tools, tests, scripted bootstraps) can ask "where will sessions
|
|
4943
5233
|
* land?" without going through `resolveConfig`'s full machinery.
|
|
4944
5234
|
*
|
|
5235
|
+
* Storage-slot resolution (config / data / state / cache) is delegated
|
|
5236
|
+
* to {@link resolveStorageDirs}. In legacy modes the four slots collapse
|
|
5237
|
+
* to a single `<storageDir>/<prefix>` directory; in XDG mode they fan
|
|
5238
|
+
* out into `$XDG_CONFIG_HOME/zidane`, `$XDG_DATA_HOME/zidane`,
|
|
5239
|
+
* `$XDG_STATE_HOME/zidane`, `$XDG_CACHE_HOME/zidane`. See the module
|
|
5240
|
+
* doc on `./xdg.ts` for the full precedence chain.
|
|
5241
|
+
*
|
|
4945
5242
|
* Decision logic for project mode (least → most specific):
|
|
4946
5243
|
*
|
|
4947
|
-
* 1. Default:
|
|
4948
|
-
*
|
|
5244
|
+
* 1. Default: OFF — sessions live in the user-scoped `dataDir`
|
|
5245
|
+
* and get scoped per-project via the `SessionData.projectRoot` tag.
|
|
5246
|
+
* 2. `<configDir>/config.json` `projectDb` flag (when present).
|
|
4949
5247
|
* 3. `ZIDANE_PROJECT_DB` env var (`'0'` / `'false'` / `'off'` → off,
|
|
4950
5248
|
* anything else true if set).
|
|
4951
5249
|
* 4. `options.projectDb` (host call site).
|
|
4952
5250
|
*
|
|
4953
5251
|
* Project mode activates only when the resolution above lands on
|
|
4954
5252
|
* `true` AND a git repo is found above `cwd`. Outside git or with the
|
|
4955
|
-
* flag off, sessions + state stay at the user
|
|
5253
|
+
* flag off, sessions + state stay at the user-scoped slots.
|
|
4956
5254
|
*
|
|
4957
5255
|
* Auto-creates the project `.{prefix}/` directory when mode resolves
|
|
4958
|
-
* to ON (silent — mirrors `ensureStateDir`). User
|
|
5256
|
+
* to ON (silent — mirrors `ensureStateDir`). User slots are created
|
|
4959
5257
|
* lazily by the state-store + credentials writers; we don't pre-touch
|
|
4960
|
-
*
|
|
5258
|
+
* them here so a read-only invocation stays read-only.
|
|
4961
5259
|
*/
|
|
4962
5260
|
function resolveStoragePaths(opts) {
|
|
4963
|
-
const
|
|
4964
|
-
|
|
5261
|
+
const dirs = resolveStorageDirs({
|
|
5262
|
+
prefix: opts.prefix,
|
|
5263
|
+
...opts.storageDir !== void 0 ? { storageDir: opts.storageDir } : {}
|
|
5264
|
+
});
|
|
5265
|
+
const userConfig = loadUserConfig(dirs.configDir);
|
|
4965
5266
|
const envFlag = parseEnvFlag(process.env.ZIDANE_PROJECT_DB);
|
|
4966
5267
|
const gitRoot = opts.projectDb ?? envFlag ?? userConfig.projectDb ?? false ? findGitRoot$1(opts.cwd) : null;
|
|
4967
5268
|
const projectDir = gitRoot ? resolve(gitRoot, opts.prefix) : null;
|
|
@@ -4969,24 +5270,34 @@ function resolveStoragePaths(opts) {
|
|
|
4969
5270
|
mkdirSync(projectDir, { recursive: true });
|
|
4970
5271
|
} catch (err) {
|
|
4971
5272
|
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/chat] project-db: mkdir "${projectDir}" failed: ${errorMessage(err)}\n`);
|
|
4972
|
-
return userOnlyPaths(
|
|
5273
|
+
return userOnlyPaths(dirs);
|
|
4973
5274
|
}
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
userDir,
|
|
5275
|
+
if (projectDir) return {
|
|
5276
|
+
dir: projectDir,
|
|
5277
|
+
userDir: dirs.configDir,
|
|
4978
5278
|
projectDir,
|
|
4979
|
-
db: resolve(
|
|
4980
|
-
state: resolve(
|
|
5279
|
+
db: resolve(projectDir, "sessions.db"),
|
|
5280
|
+
state: resolve(projectDir, "state.json"),
|
|
5281
|
+
configDir: dirs.configDir,
|
|
5282
|
+
dataDir: dirs.dataDir,
|
|
5283
|
+
stateDir: dirs.stateDir,
|
|
5284
|
+
cacheDir: dirs.cacheDir,
|
|
5285
|
+
storageMode: dirs.mode
|
|
4981
5286
|
};
|
|
5287
|
+
return userOnlyPaths(dirs);
|
|
4982
5288
|
}
|
|
4983
|
-
function userOnlyPaths(
|
|
5289
|
+
function userOnlyPaths(dirs) {
|
|
4984
5290
|
return {
|
|
4985
|
-
dir:
|
|
4986
|
-
userDir,
|
|
5291
|
+
dir: dirs.configDir,
|
|
5292
|
+
userDir: dirs.configDir,
|
|
4987
5293
|
projectDir: null,
|
|
4988
|
-
db: resolve(
|
|
4989
|
-
state: resolve(
|
|
5294
|
+
db: resolve(dirs.dataDir, "sessions.db"),
|
|
5295
|
+
state: resolve(dirs.stateDir, "state.json"),
|
|
5296
|
+
configDir: dirs.configDir,
|
|
5297
|
+
dataDir: dirs.dataDir,
|
|
5298
|
+
stateDir: dirs.stateDir,
|
|
5299
|
+
cacheDir: dirs.cacheDir,
|
|
5300
|
+
storageMode: dirs.mode
|
|
4990
5301
|
};
|
|
4991
5302
|
}
|
|
4992
5303
|
/**
|
|
@@ -6035,7 +6346,8 @@ const DEFAULT_SETTINGS = {
|
|
|
6035
6346
|
showTodoIndicator: true,
|
|
6036
6347
|
showThrobber: false,
|
|
6037
6348
|
checkForUpdates: true,
|
|
6038
|
-
uiMode: "full"
|
|
6349
|
+
uiMode: "full",
|
|
6350
|
+
userInstructionsScope: "both"
|
|
6039
6351
|
};
|
|
6040
6352
|
/**
|
|
6041
6353
|
* Hard-clamp a `targetFps` value to a safe range before handing it to
|
|
@@ -6095,80 +6407,157 @@ function useSettings() {
|
|
|
6095
6407
|
if (!ctx) throw new Error("useSettings must be used inside <SettingsProvider>");
|
|
6096
6408
|
return ctx;
|
|
6097
6409
|
}
|
|
6410
|
+
/**
|
|
6411
|
+
* Ordered list of categories. Display order in any consumer (TUI tabs,
|
|
6412
|
+
* GUI sidebar, settings JSON dump) should match this array — keeps
|
|
6413
|
+
* mental model consistent across surfaces.
|
|
6414
|
+
*/
|
|
6415
|
+
const SETTINGS_CATEGORIES = [{
|
|
6416
|
+
id: "agent",
|
|
6417
|
+
label: "Agent",
|
|
6418
|
+
description: "agent behaviour, capabilities, persistence, auth"
|
|
6419
|
+
}, {
|
|
6420
|
+
id: "ui",
|
|
6421
|
+
label: "UI",
|
|
6422
|
+
description: "display, rendering, theming, animations, keybindings"
|
|
6423
|
+
}];
|
|
6098
6424
|
const SETTINGS_TOGGLES = [
|
|
6099
6425
|
{
|
|
6426
|
+
category: "agent",
|
|
6100
6427
|
key: "safeMode",
|
|
6101
6428
|
label: "Safe mode",
|
|
6102
6429
|
description: "prompt before each tool call (unless safelisted)"
|
|
6103
6430
|
},
|
|
6104
6431
|
{
|
|
6432
|
+
category: "agent",
|
|
6105
6433
|
key: "allowInteraction",
|
|
6106
6434
|
label: "Interactive prompts",
|
|
6107
6435
|
description: "let the agent pause for `ask_user` questions / `present_plan` approvals"
|
|
6108
6436
|
},
|
|
6109
6437
|
{
|
|
6438
|
+
category: "agent",
|
|
6110
6439
|
key: "resumeLastSession",
|
|
6111
6440
|
label: "Start from last session",
|
|
6112
6441
|
description: "auto-resume on launch (off = sessions list / fresh chat)"
|
|
6113
6442
|
},
|
|
6114
6443
|
{
|
|
6115
|
-
|
|
6116
|
-
label: "Hide subagent output",
|
|
6117
|
-
description: "collapse subagent runs to start/done markers"
|
|
6118
|
-
},
|
|
6119
|
-
{
|
|
6444
|
+
category: "agent",
|
|
6120
6445
|
key: "persistToolResults",
|
|
6121
6446
|
label: "Persist large tool results",
|
|
6122
6447
|
description: "write >8 KiB tool outputs to disk and inline a preview"
|
|
6123
6448
|
},
|
|
6124
6449
|
{
|
|
6450
|
+
category: "agent",
|
|
6125
6451
|
key: "autoCompact",
|
|
6126
6452
|
label: "Auto-compact",
|
|
6127
6453
|
description: "summarize the conversation when context fills past the threshold below"
|
|
6128
6454
|
},
|
|
6129
6455
|
{
|
|
6456
|
+
category: "agent",
|
|
6457
|
+
key: "checkForUpdates",
|
|
6458
|
+
label: "Check for updates",
|
|
6459
|
+
description: "quietly check npm once a day; footer chip surfaces newer releases. `zidane upgrade` always works regardless."
|
|
6460
|
+
},
|
|
6461
|
+
{
|
|
6462
|
+
category: "ui",
|
|
6130
6463
|
key: "showAllProjects",
|
|
6131
6464
|
label: "All projects",
|
|
6132
6465
|
description: "list sessions from every project (off = current only)"
|
|
6133
6466
|
},
|
|
6134
6467
|
{
|
|
6468
|
+
category: "ui",
|
|
6469
|
+
key: "hideSubagentOutput",
|
|
6470
|
+
label: "Hide subagent output",
|
|
6471
|
+
description: "collapse subagent runs to start/done markers"
|
|
6472
|
+
},
|
|
6473
|
+
{
|
|
6474
|
+
category: "ui",
|
|
6135
6475
|
key: "showThinking",
|
|
6136
6476
|
label: "Thinking blocks",
|
|
6137
6477
|
description: "agent reasoning shown inline"
|
|
6138
6478
|
},
|
|
6139
6479
|
{
|
|
6480
|
+
category: "ui",
|
|
6140
6481
|
key: "showToolResults",
|
|
6141
6482
|
label: "Tool outputs",
|
|
6142
6483
|
description: "the ┃ result blocks under tool calls"
|
|
6143
6484
|
},
|
|
6144
6485
|
{
|
|
6486
|
+
category: "ui",
|
|
6145
6487
|
key: "showEditDiffs",
|
|
6146
6488
|
label: "Edit diffs",
|
|
6147
6489
|
description: "render edit / multi_edit / write_file as a unified diff"
|
|
6148
6490
|
},
|
|
6149
6491
|
{
|
|
6492
|
+
category: "ui",
|
|
6150
6493
|
key: "smoothStreaming",
|
|
6151
6494
|
label: "Smooth streaming",
|
|
6152
6495
|
description: "drip-feed streamed text character-by-character at a steady cadence (typewriter effect)"
|
|
6153
6496
|
},
|
|
6154
6497
|
{
|
|
6498
|
+
category: "ui",
|
|
6155
6499
|
key: "showTodoIndicator",
|
|
6156
6500
|
label: "Todo indicator",
|
|
6157
6501
|
description: "show the subtle \"in progress\" todo line above the prompt (modal stays accessible regardless)"
|
|
6158
6502
|
},
|
|
6159
6503
|
{
|
|
6504
|
+
category: "ui",
|
|
6160
6505
|
key: "showThrobber",
|
|
6161
6506
|
label: "Streaming throbber",
|
|
6162
6507
|
description: "animated gradient glyphs at the transcript tail while the assistant is working"
|
|
6163
|
-
},
|
|
6164
|
-
{
|
|
6165
|
-
key: "checkForUpdates",
|
|
6166
|
-
label: "Check for updates",
|
|
6167
|
-
description: "quietly check npm once a day; footer chip surfaces newer releases. `zidane upgrade` always works regardless."
|
|
6168
6508
|
}
|
|
6169
6509
|
];
|
|
6170
6510
|
const SETTINGS_CHOICES = [
|
|
6171
6511
|
{
|
|
6512
|
+
category: "agent",
|
|
6513
|
+
key: "autoCompactThreshold",
|
|
6514
|
+
label: "Auto-compact threshold",
|
|
6515
|
+
description: "fraction of the effective context window before compaction fires",
|
|
6516
|
+
options: [
|
|
6517
|
+
{
|
|
6518
|
+
value: .6,
|
|
6519
|
+
label: "60%"
|
|
6520
|
+
},
|
|
6521
|
+
{
|
|
6522
|
+
value: .7,
|
|
6523
|
+
label: "70%"
|
|
6524
|
+
},
|
|
6525
|
+
{
|
|
6526
|
+
value: .8,
|
|
6527
|
+
label: "80%"
|
|
6528
|
+
},
|
|
6529
|
+
{
|
|
6530
|
+
value: .9,
|
|
6531
|
+
label: "90%"
|
|
6532
|
+
}
|
|
6533
|
+
]
|
|
6534
|
+
},
|
|
6535
|
+
{
|
|
6536
|
+
category: "agent",
|
|
6537
|
+
key: "userInstructionsScope",
|
|
6538
|
+
label: "User instructions",
|
|
6539
|
+
description: "which AGENTS.md / CLAUDE.md files load into the system prompt",
|
|
6540
|
+
options: [
|
|
6541
|
+
{
|
|
6542
|
+
value: "both",
|
|
6543
|
+
label: "Both (merged)"
|
|
6544
|
+
},
|
|
6545
|
+
{
|
|
6546
|
+
value: "user",
|
|
6547
|
+
label: "User only"
|
|
6548
|
+
},
|
|
6549
|
+
{
|
|
6550
|
+
value: "project",
|
|
6551
|
+
label: "Project only"
|
|
6552
|
+
},
|
|
6553
|
+
{
|
|
6554
|
+
value: "none",
|
|
6555
|
+
label: "None"
|
|
6556
|
+
}
|
|
6557
|
+
]
|
|
6558
|
+
},
|
|
6559
|
+
{
|
|
6560
|
+
category: "ui",
|
|
6172
6561
|
key: "toolCallDisplay",
|
|
6173
6562
|
label: "Tool calls display",
|
|
6174
6563
|
description: "how `↳ <tool>` lines render — hidden, clean per-tool summary, or full JSON",
|
|
@@ -6188,6 +6577,7 @@ const SETTINGS_CHOICES = [
|
|
|
6188
6577
|
]
|
|
6189
6578
|
},
|
|
6190
6579
|
{
|
|
6580
|
+
category: "ui",
|
|
6191
6581
|
key: "editDiffDisplay",
|
|
6192
6582
|
label: "Edit diff density",
|
|
6193
6583
|
description: "full unified diff with line numbers · or compact per-hunk summary list",
|
|
@@ -6200,29 +6590,7 @@ const SETTINGS_CHOICES = [
|
|
|
6200
6590
|
}]
|
|
6201
6591
|
},
|
|
6202
6592
|
{
|
|
6203
|
-
|
|
6204
|
-
label: "Auto-compact threshold",
|
|
6205
|
-
description: "fraction of the effective context window before compaction fires",
|
|
6206
|
-
options: [
|
|
6207
|
-
{
|
|
6208
|
-
value: .6,
|
|
6209
|
-
label: "60%"
|
|
6210
|
-
},
|
|
6211
|
-
{
|
|
6212
|
-
value: .7,
|
|
6213
|
-
label: "70%"
|
|
6214
|
-
},
|
|
6215
|
-
{
|
|
6216
|
-
value: .8,
|
|
6217
|
-
label: "80%"
|
|
6218
|
-
},
|
|
6219
|
-
{
|
|
6220
|
-
value: .9,
|
|
6221
|
-
label: "90%"
|
|
6222
|
-
}
|
|
6223
|
-
]
|
|
6224
|
-
},
|
|
6225
|
-
{
|
|
6593
|
+
category: "ui",
|
|
6226
6594
|
key: "theme",
|
|
6227
6595
|
label: "Theme",
|
|
6228
6596
|
description: "colors + markdown / syntax styles",
|
|
@@ -6232,9 +6600,10 @@ const SETTINGS_CHOICES = [
|
|
|
6232
6600
|
}))
|
|
6233
6601
|
},
|
|
6234
6602
|
{
|
|
6603
|
+
category: "ui",
|
|
6235
6604
|
key: "uiMode",
|
|
6236
6605
|
label: "UI mode",
|
|
6237
|
-
description: "chat-screen chrome density — full
|
|
6606
|
+
description: "chat-screen chrome density — full shows every shortcut · minimal hides them (`ctrl+y` to peek)",
|
|
6238
6607
|
options: [{
|
|
6239
6608
|
value: "full",
|
|
6240
6609
|
label: "Full"
|
|
@@ -6244,8 +6613,9 @@ const SETTINGS_CHOICES = [
|
|
|
6244
6613
|
}]
|
|
6245
6614
|
},
|
|
6246
6615
|
{
|
|
6616
|
+
category: "ui",
|
|
6247
6617
|
key: "targetFps",
|
|
6248
|
-
label: "Renderer
|
|
6618
|
+
label: "Renderer FPS",
|
|
6249
6619
|
description: "30 saves CPU · 60 recommended · 120 for ProMotion + modern terminals",
|
|
6250
6620
|
options: [
|
|
6251
6621
|
{
|
|
@@ -7587,15 +7957,44 @@ function projectUserPaths(opts) {
|
|
|
7587
7957
|
//#endregion
|
|
7588
7958
|
//#region src/chat/mcps-discovery.ts
|
|
7589
7959
|
/**
|
|
7590
|
-
*
|
|
7591
|
-
*
|
|
7592
|
-
*
|
|
7960
|
+
* File names searched in each of the four project/user roots. Order
|
|
7961
|
+
* matters within a single directory — `mcps.json` (zidane's canonical
|
|
7962
|
+
* name) beats `mcp.json` (Cursor / common ecosystem alias) when both
|
|
7963
|
+
* exist side-by-side. Across files we merge per-name with first-found
|
|
7964
|
+
* winning, so co-existing `mcp.json` entries are folded in for names
|
|
7965
|
+
* not declared in the canonical file.
|
|
7966
|
+
*/
|
|
7967
|
+
const MCP_CONFIG_FILE_NAMES = ["mcps.json", "mcp.json"];
|
|
7968
|
+
/**
|
|
7969
|
+
* Search order for MCP config files — see {@link projectUserPaths}.
|
|
7970
|
+
*
|
|
7971
|
+
* Both `mcps.json` (zidane's canonical name) and `mcp.json` (Cursor /
|
|
7972
|
+
* common ecosystem alias) are picked up from every search root. The
|
|
7973
|
+
* canonical name wins within the same directory; across files the
|
|
7974
|
+
* usual first-found-by-name dedup applies, so `mcp.json` effectively
|
|
7975
|
+
* merges its non-overlapping entries on top of `mcps.json`.
|
|
7976
|
+
*
|
|
7977
|
+
* Order per scope (project beats user):
|
|
7978
|
+
* 1. `{project}/.agents/mcps.json`
|
|
7979
|
+
* 2. `{project}/.agents/mcp.json`
|
|
7980
|
+
* 3. `{project}/.{prefix}/mcps.json`
|
|
7981
|
+
* 4. `{project}/.{prefix}/mcp.json`
|
|
7982
|
+
* 5. `~/.agents/mcps.json`
|
|
7983
|
+
* 6. `~/.agents/mcp.json`
|
|
7984
|
+
* 7. `~/.{prefix}/mcps.json`
|
|
7985
|
+
* 8. `~/.{prefix}/mcp.json`
|
|
7986
|
+
*
|
|
7987
|
+
* Non-existent files are skipped without error.
|
|
7593
7988
|
*/
|
|
7594
7989
|
function defaultMcpsConfigPaths(opts = {}) {
|
|
7595
|
-
|
|
7596
|
-
subPath:
|
|
7990
|
+
const perName = MCP_CONFIG_FILE_NAMES.map((name) => projectUserPaths({
|
|
7991
|
+
subPath: name,
|
|
7597
7992
|
...opts
|
|
7598
|
-
});
|
|
7993
|
+
}));
|
|
7994
|
+
const rootCount = perName[0].length;
|
|
7995
|
+
const out = [];
|
|
7996
|
+
for (let i = 0; i < rootCount; i++) for (const list of perName) out.push(list[i]);
|
|
7997
|
+
return out;
|
|
7599
7998
|
}
|
|
7600
7999
|
/**
|
|
7601
8000
|
* Parse one `mcps.json` file. Canonical zidane shape is a flat array; the
|
|
@@ -9789,6 +10188,6 @@ function countNeighbors(turnIds, turnId) {
|
|
|
9789
10188
|
};
|
|
9790
10189
|
}
|
|
9791
10190
|
//#endregion
|
|
9792
|
-
export { patchMcpCredential as $,
|
|
10191
|
+
export { patchMcpCredential as $, FILES_TRIGGER as $n, PLAN_AGENT as $r, createStateStore as $t, getSafelist as A, maskToOutcomeKinds as An, setProviderCredential as Ar, SETTINGS_TOGGLES as At, oauthUsesManualCodePaste as B, KEYBINDING_KEY_COL_WIDTH as Bn, modelSupportsReasoning as Br, CATPPUCCIN_LATTE as Bt, resolveSessionExportTarget as C, PLAN_MODE_DOCTRINE as Ci, extractEditPayload as Cn, shouldAutoCompact as Cr, buildHints as Ct, useSafeModeQueue as D, buildBuildSystem as Di, summarizeEditPayload as Dn, readCredentials as Dr, DEFAULT_SETTINGS as Dt, useSafeModeActions as E, TOKEN_DISCIPLINE_DOCTRINE as Ei, splitLines as En, credentialsPath as Er, useEnabledToggleSet as Et, suggestSafelistEntry as F, stripEditOutcomesAnnotation as Fn, cerebrasDescriptor as Fr, DEFAULT_THEME as Ft, indexOfEntry as G, matchesBinding as Gn, discoverAgentsMd as Gr, useDiscovery as Gt, supportsOAuth as H, formatBindingForDisplay as Hn, openaiDescriptor as Hr, CATPPUCCIN_MOCHA as Ht, writeProjects as I, summarizeOutcomes as In, credKeyOf as Ir, resolveChipColor as It, discoverProjectMcps as J, readKeybindings as Jn, BUILD_AGENT as Jr, useConfig as Jt, buildMcpServers as K, mergeKeybindings as Kn, renderAgentsMdBlock as Kr, useDiscoveryOptional as Kt, splitPromptSegments as L, DEFAULT_KEYBINDINGS as Ln, effectiveContextWindow as Lr, resolveTheme as Lt, matchesSafelistEntry as M, parseEditOutcomesFromResult as Mn, BUILTIN_PROVIDERS as Mr, clampFps as Mt, projectsFilePath as N, resolveApprovalForPayload as Nn, OUTPUT_RESERVE_TOKENS as Nr, useSettings as Nt, IMPLICITLY_SAFE_TOOLS as O, buildPlanSystem as Oi, tokenize as On, readProviderCredential as Or, SETTINGS_CATEGORIES as Ot, readProjects as P, rewriteMultiEditHeader as Pn, anthropicDescriptor as Pr, BUILTIN_THEMES as Pt, mcpCredentialsPath as Q, uniqueSkillNamesFromReferences as Qn, DEFAULT_PERSIST_EXCLUDE_TOOLS as Qr, EDIT_TOOL_NAMES as Qt, formatPathForCwd as R, KEYBINDING_DEFS as Rn, getContextWindow as Rr, VAPORWAVE_THEME as Rt, renderSession as S, INTERACTION_GUIDANCE_NO_PROMPTS as Si, computeLineDiff as Sn, AUTO_COMPACT_MIN_GROWTH_FRACTION as Sr, generateSessionTitle as St, SafeModeProvider as T, SUBAGENT_GUIDANCE as Ti, previewEditPayload as Tn, applyApiKeyEnv as Tr, listProjectFiles as Tt, buildModelCatalog as U, groupBindings as Un, openrouterDescriptor as Ur, createDiscoverySlot as Ut, runOAuthLogin as V, ensureKeybindingsFile as Vn, modelsForDescriptor as Vr, CATPPUCCIN_MACCHIATO as Vt, filterModelCatalog as W, keybindingsPath as Wn, piIdOf as Wr, DiscoveryProvider as Wt, projectUserPaths as X, SKILLS_TRIGGER as Xn, DEFAULT_AGENT_ID as Xr, resolveStoragePaths as Xt, parseMcpsFile as Y, stripJsonComments as Yn, BUILTIN_AGENTS as Yr, resolveConfig as Yt, createFileMcpCredentialStore as Z, createSkillsCompletionProvider as Zn, DEFAULT_BUDGET_EXCLUDE_TOOLS as Zr, resolveStorageDirs as Zt, turnContextSize as _, ACTIONS_WITH_CARE_DOCTRINE as _i, updateToolEventOutcomes as _n, detectPackageManager as _r, EMPTY_HINTS as _t, computeTurnAnchors as a, TODOWRITE_TOOL as ai, lastContextSizeFromTurns as an, mergeReferences as ar, splitMarkdownCodeBlocks as at, defaultSkillScanPaths as b, IDENTITY_PREFIX as bi, buildUnifiedDiff as bn, performSelfUpdate as br, truncateTrailing as bt, formatToolCall as c, createTodoTools as ci, marginTopFor as cn, buildLinearRamp as cr, PRESENT_PLAN_TOOL as ct, useSelectStyle as d, isTodoTool as di, stripSpawnTokensLine as dn, bootTick as dr, isInteractionTool as dt, accentColor as ei, deriveSessionTitle as en, createFilesCompletionProvider as er, McpAuthProvider as et, useSurfaces as f, pickActiveRunId as fi, sumRunCosts as fn, buildUpdateHint as fr, makeRequestInteraction as ft, finalizeStreamingMarkdownForOwner as g, useActiveTodos as gi, turnSelectionOwnership as gn, detectLibc as gr, useInteractionsQueue as gt, finalizeStreamingMarkdown as h, setTodosForRun as hi, toolResultText as hn, compareSemver as hr, useInteractionsActions as ht, turnAsText as i, TODOS_METADATA_KEY as ii, isVisible as in, findActiveTrigger as ir, reduceMcpAuth as it, isOnSafelist as j, mergeApprovalAndBodyOutcomes as jn, writeCredentials as jr, SettingsProvider as jt, addToSafelist as k, envSection as ki, buildEditOutcomesAnnotation as kn, removeProviderCredential as kr, SETTINGS_CHOICES as kt, ThemeProvider as l, getArchivedTodosForRun as li, saveState as ln, tryOpenBrowser as lr, buildResumedToolResultsTurn as lt, useTheme as m, selectActiveTodos as mi, toolCallPreview as mn, checkForUpdate as mr, serializeInteractionResponse as mt, deleteTurnSafely as n, singleAgentRegistry as ni, isEditErrorResult as nn, applyInsert as nr, useMcpAuthState as nt, TOOL_DISPLAY as o, TODO_STATUS_GLYPHS as oi, listSessionMeta as on, useCompletion as or, ASK_USER_TOOL as ot, useSyntaxStyles as p, pruneTodosByRun as pi, titleFromTurns as pn, useUpdateCheck as pr, pendingInteractionsFromTurns as pt, defaultMcpsConfigPaths as q, parseBindingSpec as qn, findGitRoot$1 as qr, ConfigProvider as qt, truncateTurnsAt as r, TODOREAD_TOOL as ri, isTurnHighlighted as rn, collectReferences as rr, getMcpAuthStatus as rt, displayNameFor as s, TODO_WRITE_COUNTS_METADATA_KEY as si, loadState as sn, blendHsl as sr, InteractionsProvider as st, countNeighbors as t, resolveAgentId as ti, eventsFromTurns as tn, uniqueFilesFromReferences as tr, useMcpAuthDispatch as tt, useColors as u, getTodosForRun as ui, selectableTurnIds as un, bootProfileEnabled as ur, createInteractionTools as ut, useStreamBuffer as v, COMMUNICATION_DOCTRINE as vi, applyEditPayload as vn, parseSemver as vr, clipHintsToWidth as vt, writeSessionExport as w, PLAN_MODE_DOCTRINE_NO_PROMPTS as wi, filetypeFromPath as wn, detectAuth as wr, shortChord as wt, discoverProjectSkills as x, INTERACTION_GUIDANCE as xi, computeInlineDiff as xn, resolvePlatformPackage as xr, cleanTitle as xt, buildSkillsConfig as y, DOING_TASKS_DOCTRINE as yi, buildContextualDiff as yn, performInPlaceSelfUpdate as yr, hintsLength as yt, fetchOAuthRedirect as z, KEYBINDING_DEF_BY_ACTION as zn, getModelInfo as zr, CATPPUCCIN_FRAPPE as zt };
|
|
9793
10192
|
|
|
9794
|
-
//# sourceMappingURL=turn-operations-
|
|
10193
|
+
//# sourceMappingURL=turn-operations-D-OQYUgS.js.map
|