@ashx-j/lunr 0.2.9 → 0.2.11
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/builtin-extensions/ashxj-spinners.d.ts +1 -4
- package/dist/builtin-extensions/ashxj-spinners.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-spinners.js +3 -29
- package/dist/builtin-extensions/ashxj-spinners.js.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +5 -4
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-cron.js +6 -1
- package/dist/builtin-extensions/lunr-cron.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +3 -4
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +4 -4
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +5 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +8 -7
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +4 -3
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +4 -6
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +26 -18
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +3 -1
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/nvidia.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/opencode.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/providers/xai.json +1 -1
- package/dist/catalog/publication.json +3 -3
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +11 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/customize.d.ts +1 -0
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +3 -0
- package/dist/core/customize.js.map +1 -1
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +13 -1
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/permissions.d.ts +9 -0
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +60 -20
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +49 -7
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/swarm.d.ts +17 -4
- package/dist/core/swarm.d.ts.map +1 -1
- package/dist/core/swarm.js +36 -4
- package/dist/core/swarm.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +9 -6
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +2 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +2 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +2 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +13 -3
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +10 -2
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -3
- package/dist/core/tools/write.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +2 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +11 -1
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +2 -1
- package/dist/gateway/commands.js.map +1 -1
- package/dist/gateway/cron.d.ts +4 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +17 -8
- package/dist/gateway/cron.js.map +1 -1
- package/dist/gateway/router.d.ts +1 -1
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +11 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.d.ts +1 -0
- package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.js +2 -6
- package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +75 -16
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +15 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +139 -34
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/terminal-setup.md +2 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
package/dist/core/plan-mode.js
CHANGED
|
@@ -369,17 +369,59 @@ function isMutatingSegment(segment) {
|
|
|
369
369
|
// Final gate: the command must be in the read-only allowlist.
|
|
370
370
|
return !ALLOWED_COMMANDS.has(command);
|
|
371
371
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
372
|
+
/** Global git options that take no value. Unknown leading flags are treated as mutating. */
|
|
373
|
+
const GIT_GLOBAL_FLAGS = new Set([
|
|
374
|
+
"--no-pager",
|
|
375
|
+
"--paginate",
|
|
376
|
+
"-p",
|
|
377
|
+
"--version",
|
|
378
|
+
"--help",
|
|
379
|
+
"-h",
|
|
380
|
+
"--bare",
|
|
381
|
+
"--no-replace-objects",
|
|
382
|
+
"--no-optional-locks",
|
|
383
|
+
"--literal-pathspecs",
|
|
384
|
+
"--glob-pathspecs",
|
|
385
|
+
"--noglob-pathspecs",
|
|
386
|
+
"--icase-pathspecs",
|
|
387
|
+
]);
|
|
388
|
+
/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */
|
|
389
|
+
function gitSubcommandIndex(args) {
|
|
375
390
|
let index = 0;
|
|
376
|
-
while (
|
|
377
|
-
index
|
|
391
|
+
while (index < args.length) {
|
|
392
|
+
const token = args[index];
|
|
393
|
+
if (!token.startsWith("-"))
|
|
394
|
+
return index;
|
|
395
|
+
if (token === "--")
|
|
396
|
+
return index + 1;
|
|
397
|
+
if (GIT_GLOBAL_FLAGS.has(token)) {
|
|
398
|
+
index++;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (token === "-C" || token === "-c" || token === "--git-dir" || token === "--work-tree" || token === "--namespace") {
|
|
402
|
+
if (args[index + 1] === undefined)
|
|
403
|
+
return -1;
|
|
404
|
+
index += 2;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (token.startsWith("--git-dir=") ||
|
|
408
|
+
token.startsWith("--work-tree=") ||
|
|
409
|
+
token.startsWith("--namespace=") ||
|
|
410
|
+
token.startsWith("--config-env=")) {
|
|
411
|
+
index++;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
return -1;
|
|
415
|
+
}
|
|
416
|
+
return index;
|
|
417
|
+
}
|
|
418
|
+
function isMutatingGit(args) {
|
|
419
|
+
const index = gitSubcommandIndex(args);
|
|
420
|
+
if (index < 0)
|
|
421
|
+
return true;
|
|
378
422
|
const subcommand = args[index]?.toLowerCase();
|
|
379
423
|
if (!subcommand)
|
|
380
424
|
return false;
|
|
381
|
-
if (subcommand.startsWith("-"))
|
|
382
|
-
return false; // bare `git --version` etc. is read-only
|
|
383
425
|
if (MUTATING_GIT_SUBCOMMANDS.has(subcommand))
|
|
384
426
|
return true;
|
|
385
427
|
if (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-mode.js","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAC9B,yRAAuR,CAAC;AAEzR,4EAA4E;AAC5E,MAAM,CAAC,MAAM,uBAAuB,GAAG,0DAAwD,CAAC;AAEhG,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC7B,MAAM;IACN,OAAO;IACP,cAAc;IACd,iBAAiB;IACjB,YAAY;IACZ,eAAe;IACf,MAAM;CACN,CAAC,CAAC;AAEH,iGAAiG;AACjG,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAChC,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,IAAI;IACJ,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,GAAG;IACH,MAAM;IACN,OAAO;IACP,OAAO;IACP,SAAS;IACT,MAAM;IACN,MAAM;IACN,IAAI;IACJ,QAAQ;IACR,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,UAAU;IACV,OAAO;IACP,UAAU;IACV,QAAQ;IACR,OAAO;IACP,MAAM;IACN,KAAK;IACL,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;CACL,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACxC,KAAK;IACL,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;IACV,QAAQ;IACR,SAAS;IACT,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,aAAa;IACb,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,IAAI;IACJ,MAAM;IACN,OAAO;IACP,WAAW;IACX,UAAU;IACV,IAAI;IACJ,OAAO;IACP,cAAc;CACd,CAAC,CAAC;AAEH,gFAAgF;AAChF,sFAAsF;AACtF,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AACzE,MAAM,8BAA8B,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAErF,MAAM,yBAAyB,GAAgC;IAC9D,GAAG,EAAE,IAAI,GAAG,CAAC;QACZ,SAAS;QACT,KAAK;QACL,QAAQ;QACR,WAAW;QACX,QAAQ;QACR,SAAS;QACT,SAAS;QACT,MAAM;QACN,QAAQ;QACR,IAAI;QACJ,MAAM;KACN,CAAC;IACF,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClH,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxG,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;CACjH,CAAC;AAEF,8CAA8C;AAC9C,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACxC,KAAK;IACL,SAAS;IACT,MAAM;IACN,KAAK;IACL,KAAK;IACL,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,OAAO;CACP,CAAC,CAAC;AAEH,0FAA0F;AAC1F,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACpC,IAAI;IACJ,QAAQ;IACR,IAAI;IACJ,SAAS;IACT,IAAI;IACJ,WAAW;IACX,UAAU;IACV,IAAI;IACJ,eAAe;CACf,CAAC,CAAC;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC;AAE5E,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CAAC,KAAc,EAAW;IAC9D,OAAQ,KAA2C,EAAE,OAAO,KAAK,KAAK,CAAC;AAAA,CACvE;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,KAAc,EAAsB;IACzF,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,uBAAuB,CAAC;IAChC,CAAC;IACD,IAAI,QAAQ,KAAK,cAAc,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,OAAO,uBAAuB,CAAC;IAChC,CAAC;IACD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,OAAO,IAAI,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,OAAO,GAAG,uBAAuB,qBAAqB,OAAO,EAAE,CAAC;QACjE,CAAC;IACF,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,eAAe,CAAC,KAAc,EAAU;IAChD,MAAM,OAAO,GAAI,KAA2C,EAAE,OAAO,CAAC;IACtE,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CAClD;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAAW;IAC/D,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAElC,uDAAuD;IACvD,IAAI,mBAAmB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,0EAA0E;IAC1E,sCAAsC;IACtC,IAAI,oBAAoB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/C,yEAAyE;IACzE,KAAK,MAAM,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,iBAAiB,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,mBAAmB,CAAC,OAAe,EAAW;IACtD,IAAI,KAA4B,CAAC;IACjC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClC,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACV,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACX,IAAI,EAAE,KAAK,KAAK;gBAAE,KAAK,GAAG,SAAS,CAAC;YACpC,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,KAAK,GAAG,EAAE,CAAC;YACX,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,kBAAkB,CAAC,OAAe,EAAY;IACtD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAA4B,CAAC;IACjC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5B,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClC,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACV,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACX,IAAI,EAAE,KAAK,KAAK;gBAAE,KAAK,GAAG,SAAS,CAAC;YACpC,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,KAAK,GAAG,EAAE,CAAC;YACX,SAAS;QACV,CAAC;QACD,sDAAsD;QACtD,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAClE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,CAAC,EAAE,CAAC;YACJ,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACF,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAAA,CACjE;AAED,kFAAkF;AAClF,SAAS,oBAAoB,CAAC,OAAe,EAAW;IACvD,IAAI,KAA4B,CAAC;IACjC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClC,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACV,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACX,IAAI,EAAE,KAAK,KAAK;gBAAE,KAAK,GAAG,SAAS,CAAC;YACpC,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,KAAK,GAAG,EAAE,CAAC;YACX,SAAS;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAC5B,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;IACvD,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,iBAAiB,CAAC,OAAe,EAAW;IACpD,IAAI,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9D,4FAA0F;IAC1F,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7B,IAAI,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACtB,qEAAqE;QACrE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC;YACP,SAAS;YACT,SAAS;YACT,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,cAAc;YACd,WAAW;YACX,cAAc;YACd,cAAc;YACd,UAAU;YACV,UAAU;YACV,QAAQ;SACR,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvF,qFAAmF;QACnF,wFAAwF;QACxF,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,YAAY,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;QACvE,OAAO,UAAU,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjE,CAAC;IAED,oFAAoF;IACpF,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IAED,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAAA,CACtC;AAED,SAAS,aAAa,CAAC,IAAc,EAAW;IAC/C,oFAAoF;IACpF,wFAAwF;IACxF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,YAAY;QAAE,KAAK,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IAC9C,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,yCAAyC;IAEvF,IAAI,wBAAwB,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,2BAA2B,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,8BAA8B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,UAAU,CAAC,KAAa,EAAU;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;AAAA,CACxC","sourcesContent":["/**\n * lunr: plan permission mode — read-only tool-gating heuristics + system-prompt addendum.\n *\n * Plan is a first-class permission mode (`PermissionMode = \"plan\"`). `gateToolCall`\n * in permissions.ts applies `planModeBlockReason` when the session is in plan:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `PLAN_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or exit plan mode with /plan off.\n */\n\n/** Appended to the system prompt while plan mode is active. */\nexport const PLAN_MODE_ADDENDUM =\n\t\"You are in plan mode. Investigate read-only, then present your plan by calling the present_plan tool with a concise summary — the user approves or declines it in a dialog. Do not make changes until the plan is approved. The user can also exit plan mode manually with /plan off.\";\n\n/** Error returned to the model when a tool call is blocked by plan mode. */\nexport const PLAN_MODE_BLOCK_MESSAGE = \"Plan mode is active — propose a plan; no file changes.\";\n\nconst BLOCKED_TOOLS = new Set([\n\t\"edit\",\n\t\"write\",\n\t\"behavior_add\",\n\t\"behavior_remove\",\n\t\"memory_add\",\n\t\"memory_remove\",\n\t\"cron\",\n]);\n\n/** Small allowlist of read-only commands permitted in plan mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in plan mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when plan mode should block this tool call, else undefined.\n */\nexport function planModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn PLAN_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn PLAN_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${PLAN_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Plan-mode bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\t// Skip global flags like --no-pager / -C <dir> / -c key=val crudely: find the first\n\t// token that doesn't start with \"-\" (imperfect for -C/-c values; conservative is fine).\n\tlet index = 0;\n\twhile (args[index] === \"--no-pager\") index++;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\tif (subcommand.startsWith(\"-\")) return false; // bare `git --version` etc. is read-only\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plan-mode.js","sourceRoot":"","sources":["../../src/core/plan-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunr: plan permission mode — read-only tool-gating heuristics + system-prompt addendum.\n *\n * Plan is a first-class permission mode (`PermissionMode = \"plan\"`). `gateToolCall`\n * in permissions.ts applies `planModeBlockReason` when the session is in plan:\n * `edit`/`write` and mutating `bash` are hard-blocked; read tools stay open.\n * InteractiveMode installs `PLAN_MODE_ADDENDUM` via the shared system-prompt\n * append slot (same slot auto mode uses).\n *\n * Bash heuristic (conservative, blocklist-based — NOT a security boundary):\n * - any `>`/`>>` redirect outside quotes blocks the whole command;\n * - the command is split on `;`, `|`, `&` separators (outside quotes) and every segment's\n * leading command must be read-only:\n * - known mutating commands (rm, mv, cp, mkdir, sed -i, tee, …) are blocked;\n * - `git` is limited to read-only subcommands (status/log/diff/show/… plus flag-only\n * branch/tag/remote); mutating subcommands (add/commit/push/checkout/…) are blocked;\n * - package managers are limited to read-only subcommands (install/add/remove/… blocked);\n * - arbitrary runners (sudo, xargs, npx, sh -c …) are blocked.\n * Unknown-but-not-listed commands are ALLOWED (blocklist, not allowlist) — the model is\n * additionally steered by the system-prompt addendum. False positives are expected; the\n * user can run the command themselves or exit plan mode with /plan off.\n */\n\n/** Appended to the system prompt while plan mode is active. */\nexport const PLAN_MODE_ADDENDUM =\n\t\"You are in plan mode. Investigate read-only, then present your plan by calling the present_plan tool with a concise summary — the user approves or declines it in a dialog. Do not make changes until the plan is approved. The user can also exit plan mode manually with /plan off.\";\n\n/** Error returned to the model when a tool call is blocked by plan mode. */\nexport const PLAN_MODE_BLOCK_MESSAGE = \"Plan mode is active — propose a plan; no file changes.\";\n\nconst BLOCKED_TOOLS = new Set([\n\t\"edit\",\n\t\"write\",\n\t\"behavior_add\",\n\t\"behavior_remove\",\n\t\"memory_add\",\n\t\"memory_remove\",\n\t\"cron\",\n]);\n\n/** Small allowlist of read-only commands permitted in plan mode. Everything else is rejected. */\nconst ALLOWED_COMMANDS = new Set([\n\t\"ls\",\n\t\"ll\",\n\t\"cat\",\n\t\"tac\",\n\t\"grep\",\n\t\"rg\",\n\t\"find\",\n\t\"pwd\",\n\t\"echo\",\n\t\"printf\",\n\t\"head\",\n\t\"tail\",\n\t\"wc\",\n\t\"less\",\n\t\"more\",\n\t\"sort\",\n\t\"uniq\",\n\t\"diff\",\n\t\"cmp\",\n\t\"comm\",\n\t\"test\",\n\t\"[\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"whereis\",\n\t\"stat\",\n\t\"file\",\n\t\"id\",\n\t\"whoami\",\n\t\"who\",\n\t\"date\",\n\t\"cal\",\n\t\"env\",\n\t\"printenv\",\n\t\"uname\",\n\t\"hostname\",\n\t\"uptime\",\n\t\"nproc\",\n\t\"tput\",\n\t\"git\",\n\t\"gh\",\n\t\"node\",\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn\",\n\t\"bun\",\n]);\n\nconst MUTATING_GIT_SUBCOMMANDS = new Set([\n\t\"add\",\n\t\"commit\",\n\t\"push\",\n\t\"pull\",\n\t\"merge\",\n\t\"rebase\",\n\t\"reset\",\n\t\"checkout\",\n\t\"switch\",\n\t\"restore\",\n\t\"rm\",\n\t\"mv\",\n\t\"stash\",\n\t\"cherry-pick\",\n\t\"revert\",\n\t\"clean\",\n\t\"fetch\",\n\t\"config\",\n\t\"apply\",\n\t\"am\",\n\t\"init\",\n\t\"clone\",\n\t\"submodule\",\n\t\"worktree\",\n\t\"gc\",\n\t\"prune\",\n\t\"update-index\",\n]);\n\n// git subcommands that are read-only only when they carry no positional args or\n// mutating flags (`git branch` lists, `git branch foo` / `git branch -d foo` mutate).\nconst CONDITIONAL_GIT_SUBCOMMANDS = new Set([\"branch\", \"tag\", \"remote\"]);\nconst CONDITIONAL_GIT_MUTATING_FLAGS = new Set([\"-d\", \"-D\", \"-m\", \"-M\", \"-c\", \"-C\"]);\n\nconst PACKAGE_MANAGER_MUTATIONS: Record<string, Set<string>> = {\n\tnpm: new Set([\n\t\t\"install\",\n\t\t\"add\",\n\t\t\"remove\",\n\t\t\"uninstall\",\n\t\t\"update\",\n\t\t\"upgrade\",\n\t\t\"publish\",\n\t\t\"link\",\n\t\t\"unlink\",\n\t\t\"ci\",\n\t\t\"init\",\n\t]),\n\tpnpm: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tyarn: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n\tbun: new Set([\"install\", \"add\", \"remove\", \"uninstall\", \"update\", \"upgrade\", \"publish\", \"link\", \"unlink\", \"init\"]),\n};\n\n// Almost every subcommand mutates the system.\nconst ALWAYS_MUTATING_MANAGERS = new Set([\n\t\"apt\",\n\t\"apt-get\",\n\t\"brew\",\n\t\"dnf\",\n\t\"yum\",\n\t\"pacman\",\n\t\"choco\",\n\t\"winget\",\n\t\"scoop\",\n]);\n\n/** Flags that cause an interpreter to execute code and are never allowed in plan mode. */\nconst EXECUTING_NODE_FLAGS = new Set([\n\t\"-e\",\n\t\"--eval\",\n\t\"-p\",\n\t\"--print\",\n\t\"-r\",\n\t\"--require\",\n\t\"--import\",\n\t\"-i\",\n\t\"--interactive\",\n]);\nconst EXECUTING_PYTHON_FLAGS = new Set([\"-c\", \"-m\", \"-i\", \"--interactive\"]);\n\n/** Apply-mode rewrite only. Default / omitted `dry_run` is preview and stays allowed. */\nexport function isCodeRewriteMutating(input: unknown): boolean {\n\treturn (input as { dry_run?: unknown } | undefined)?.dry_run === false;\n}\n\n/**\n * Returns the block reason when plan mode should block this tool call, else undefined.\n */\nexport function planModeBlockReason(toolName: string, input: unknown): string | undefined {\n\tif (BLOCKED_TOOLS.has(toolName)) {\n\t\treturn PLAN_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"code_rewrite\" && isCodeRewriteMutating(input)) {\n\t\treturn PLAN_MODE_BLOCK_MESSAGE;\n\t}\n\tif (toolName === \"bash\") {\n\t\tconst command = readBashCommand(input);\n\t\tif (command && isMutatingBashCommand(command)) {\n\t\t\treturn `${PLAN_MODE_BLOCK_MESSAGE} Blocked command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction readBashCommand(input: unknown): string {\n\tconst command = (input as { command?: unknown } | undefined)?.command;\n\treturn typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Plan-mode bash allowlist. A command is mutating unless every segment is a\n * known read-only command used safely (no redirects, no command substitution,\n * no process substitution, no executing-interpreter flags).\n */\nexport function isMutatingBashCommand(command: string): boolean {\n\tif (!command.trim()) return false;\n\n\t// Any output redirect outside quotes can write a file.\n\tif (hasUnquotedRedirect(command)) return true;\n\n\t// Command substitution / process substitution / grouped redirect syntaxes\n\t// bypass a simple command-name check.\n\tif (hasShellSubstitution(command)) return true;\n\n\t// Every segment separated by ; | & && || must individually be read-only.\n\tfor (const segment of splitShellSegments(command)) {\n\t\tif (isMutatingSegment(segment)) return true;\n\t}\n\treturn false;\n}\n\nfunction hasUnquotedRedirect(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction splitShellSegments(command: string): string[] {\n\tconst segments: string[] = [];\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tlet start = 0;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tconst next = command[i + 1];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\t// Combined operators && and || split as one boundary.\n\t\tif ((ch === \"&\" && next === \"&\") || (ch === \"|\" && next === \"|\")) {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\ti++;\n\t\t\tstart = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \";\" || ch === \"|\" || ch === \"&\" || ch === \"\\n\") {\n\t\t\tsegments.push(command.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tsegments.push(command.slice(start));\n\treturn segments.map((s) => s.trim()).filter((s) => s.length > 0);\n}\n\n/** True when the command contains command/process substitution outside quotes. */\nfunction hasShellSubstitution(command: string): boolean {\n\tlet quote: \"'\" | '\"' | undefined;\n\tlet escaped = false;\n\tfor (let i = 0; i < command.length; i++) {\n\t\tconst ch = command[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"'\" || ch === '\"') {\n\t\t\tquote = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"`\") return true;\n\t\tif (ch === \"$\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"<\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \">\" && command[i + 1] === \"(\") return true;\n\t\tif (ch === \"&\" && command[i + 1] === \">\") return true;\n\t}\n\treturn false;\n}\n\nfunction isMutatingSegment(segment: string): boolean {\n\tlet tokens = segment.split(/\\s+/).filter((t) => t.length > 0);\n\t// Skip leading env assignments (FOO=bar cmd …) and command wrappers we can't see through.\n\twhile (tokens.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {\n\t\ttokens = tokens.slice(1);\n\t}\n\tif (tokens.length === 0) return false;\n\n\tconst command = basenameOf(tokens[0]).toLowerCase();\n\tconst args = tokens.slice(1);\n\n\tif (ALWAYS_MUTATING_MANAGERS.has(command)) return true;\n\n\tif (command === \"sed\") {\n\t\treturn args.some((a) => a === \"-i\" || a.startsWith(\"-i\") || a.startsWith(\"--in-place\") || /^-[^-]*i/.test(a));\n\t}\n\tif (command === \"find\") {\n\t\treturn args.some((a) => [\"-delete\", \"-exec\", \"-execdir\", \"-ok\", \"-okdir\"].includes(a));\n\t}\n\tif (command === \"git\") {\n\t\treturn isMutatingGit(args);\n\t}\n\tif (command === \"gh\") {\n\t\t// Allow read-only views; block everything that changes remote state.\n\t\tconst sub = `${args[0] ?? \"\"} ${args[1] ?? \"\"}`;\n\t\treturn ![\n\t\t\t\"pr view\",\n\t\t\t\"pr list\",\n\t\t\t\"pr status\",\n\t\t\t\"issue view\",\n\t\t\t\"issue list\",\n\t\t\t\"issue status\",\n\t\t\t\"repo view\",\n\t\t\t\"release view\",\n\t\t\t\"release list\",\n\t\t\t\"run list\",\n\t\t\t\"run view\",\n\t\t\t\"status\",\n\t\t].includes(sub.trim());\n\t}\n\tif (command === \"sh\" || command === \"bash\" || command === \"zsh\" || command === \"dash\") {\n\t\t// `sh -c '…'` runs arbitrary code; bare `sh script` also executes. Block -c; allow\n\t\t// nothing else is too restrictive for `bash --version`, so allow flag-only invocations.\n\t\treturn args.some((a) => a === \"-c\" || a === \"-s\") || args.some((a) => !a.startsWith(\"-\"));\n\t}\n\n\tconst pkgMutations = PACKAGE_MANAGER_MUTATIONS[command];\n\tif (pkgMutations) {\n\t\tconst subcommand = args.find((a) => !a.startsWith(\"-\"))?.toLowerCase();\n\t\treturn subcommand !== undefined && pkgMutations.has(subcommand);\n\t}\n\n\t// Node / Python interpreters: flag-only, no executing flags, no positional scripts.\n\tif (command === \"node\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_NODE_FLAGS.has(a));\n\t}\n\tif (command === \"python\" || command === \"python3\") {\n\t\treturn args.some((a) => !a.startsWith(\"-\")) || args.some((a) => EXECUTING_PYTHON_FLAGS.has(a));\n\t}\n\n\t// Final gate: the command must be in the read-only allowlist.\n\treturn !ALLOWED_COMMANDS.has(command);\n}\n\n/** Global git options that take no value. Unknown leading flags are treated as mutating. */\nconst GIT_GLOBAL_FLAGS = new Set([\n\t\"--no-pager\",\n\t\"--paginate\",\n\t\"-p\",\n\t\"--version\",\n\t\"--help\",\n\t\"-h\",\n\t\"--bare\",\n\t\"--no-replace-objects\",\n\t\"--no-optional-locks\",\n\t\"--literal-pathspecs\",\n\t\"--glob-pathspecs\",\n\t\"--noglob-pathspecs\",\n\t\"--icase-pathspecs\",\n]);\n\n/** Walk past known `git` globals. Returns the subcommand index, or -1 to block. */\nfunction gitSubcommandIndex(args: string[]): number {\n\tlet index = 0;\n\twhile (index < args.length) {\n\t\tconst token = args[index];\n\t\tif (!token.startsWith(\"-\")) return index;\n\t\tif (token === \"--\") return index + 1;\n\t\tif (GIT_GLOBAL_FLAGS.has(token)) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token === \"-C\" || token === \"-c\" || token === \"--git-dir\" || token === \"--work-tree\" || token === \"--namespace\") {\n\t\t\tif (args[index + 1] === undefined) return -1;\n\t\t\tindex += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttoken.startsWith(\"--git-dir=\") ||\n\t\t\ttoken.startsWith(\"--work-tree=\") ||\n\t\t\ttoken.startsWith(\"--namespace=\") ||\n\t\t\ttoken.startsWith(\"--config-env=\")\n\t\t) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn -1;\n\t}\n\treturn index;\n}\n\nfunction isMutatingGit(args: string[]): boolean {\n\tconst index = gitSubcommandIndex(args);\n\tif (index < 0) return true;\n\tconst subcommand = args[index]?.toLowerCase();\n\tif (!subcommand) return false;\n\n\tif (MUTATING_GIT_SUBCOMMANDS.has(subcommand)) return true;\n\tif (CONDITIONAL_GIT_SUBCOMMANDS.has(subcommand)) {\n\t\tconst rest = args.slice(index + 1);\n\t\treturn rest.some((a) => !a.startsWith(\"-\") || CONDITIONAL_GIT_MUTATING_FLAGS.has(a));\n\t}\n\treturn false;\n}\n\nfunction basenameOf(token: string): string {\n\tconst parts = token.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] ?? token;\n}\n"]}
|
|
@@ -123,6 +123,7 @@ export interface Settings {
|
|
|
123
123
|
footerLsp?: boolean;
|
|
124
124
|
footerContext?: boolean;
|
|
125
125
|
footerTokens?: boolean;
|
|
126
|
+
footerTps?: boolean;
|
|
126
127
|
footerStatuses?: boolean;
|
|
127
128
|
footerGit?: boolean;
|
|
128
129
|
footerPlan?: boolean;
|
|
@@ -290,6 +291,8 @@ export declare class SettingsManager {
|
|
|
290
291
|
setFooterContext(enabled: boolean): void;
|
|
291
292
|
getFooterTokens(): boolean;
|
|
292
293
|
setFooterTokens(enabled: boolean): void;
|
|
294
|
+
getFooterTps(): boolean;
|
|
295
|
+
setFooterTps(enabled: boolean): void;
|
|
293
296
|
getFooterStatuses(): boolean;
|
|
294
297
|
setFooterStatuses(enabled: boolean): void;
|
|
295
298
|
getFooterGit(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Transport } from \"@ashx-j/lunr-ai\";\nimport { randomUUID } from \"crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { normalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { type BehaviorPreset, isBehaviorPreset } from \"./behavior-preset.ts\";\nimport { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from \"./http-dispatcher.ts\";\nimport { MEMORY_CHAR_CAP_DEFAULT, MEMORY_CHAR_CAP_MAX, MEMORY_CHAR_CAP_MIN } from \"./memory-cap.ts\";\n\nexport type { BehaviorPreset };\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport type ModelTierName = \"light\" | \"standard\" | \"heavy\";\n\nexport interface ModelTiersSettings {\n\tenabled?: boolean; // default: false - route subagents to per-tier models\n\tlight?: string; // provider/model string (same format as /model)\n\tstandard?: string;\n\theavy?: string;\n\t/** Unset = inherit the parent session thinking level. */\n\tlightThinking?: ThinkingLevel;\n\tstandardThinking?: ThinkingLevel;\n\theavyThinking?: ThinkingLevel;\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport type DefaultProjectTrust = \"ask\" | \"always\" | \"never\";\nexport type DefaultPermissionMode = \"manual\" | \"yolo\" | \"plan\" | \"auto\";\nexport type RollbackCapture = \"copies\" | \"shadow-git\" | \"hybrid\";\nexport type RollbackScope = \"tools\" | \"tree\";\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n * - autoload=false: start empty and only apply explicit resource patterns\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\tautoload?: boolean;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\t// lunr: gateway-daemon cron fallback models, \"provider/modelId\" entries tried\n\t// in order when a cron fire fails (timeout or any error). Hand-edited.\n\tcronFallbackModels?: string[];\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tthinkingCollapse?: boolean; // default: true - collapse completed thinking blocks to \"Thought for Xs\" + first sentence\n\tshowCacheMissNotices?: boolean; // default: false - show transcript notices for significant prompt-cache misses\n\tcacheRetention?: \"none\" | \"short\" | \"long\"; // default: unset - falls back to PI_CACHE_RETENTION env, then \"short\" (packages/ai)\n\texternalEditor?: string; // Command for Ctrl+G external editor; takes precedence over VISUAL/EDITOR\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows); supports leading ~ expansion\n\tquietStartup?: boolean;\n\tsmoothStreaming?: boolean; // default: false - reveal streamed responses grapheme by grapheme (~30 FPS)\n\tdefaultProjectTrust?: DefaultProjectTrust; // default: \"ask\"; global setting only\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tenableAnalytics?: boolean; // default: false - opt-in analytics data sharing\n\ttrackingId?: string; // analytics tracking identifier, generated when analytics is enabled\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\toutputPad?: 0 | 1; // Horizontal padding for chat message output (default: 1)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\tmodelTiers?: ModelTiersSettings;\n\tsessionRetentionDays?: number; // default: 30 - delete session files older than N days at launch; 0 = keep forever\n\tmemoryCharCap?: number; // default: 5000 - simple-pi-memory character cap (1..30000)\n\tbehaviorPreset?: BehaviorPreset; // default: \"default\" - built-in behavior.md preset; custom = file is source of truth\n\t// lunr: TUI customize settings (gutter rail, prompt symbol)\n\tgutterRail?: boolean; // default: true - render a thin left rail around each turn\n\tpromptSymbol?: boolean; // default: true - show the ☾ › prompt glyph on the editor's first line\n\t// lunr: footer element toggles (ashxj-tui stats line)\n\tfooterMcp?: boolean; // default: true - show the pi-mcp-adapter mcp/mcp-auth status segments\n\tfooterLsp?: boolean; // default: false - show the pi-lsp-extension lsp status segment\n\tfooterContext?: boolean; // default: true - show the context-usage pct/window segment\n\tfooterTokens?: boolean; // default: true - show the ↑in ↓out token totals segment\n\tfooterStatuses?: boolean; // default: true - show the plan/goal/swarm/research/tps status segments\n\tfooterGit?: boolean; // default: true - show git branch + added/removed in the footer\n\tfooterPlan?: boolean; // default: true - show the subscription usage segment\n\tfooterPlanBar?: boolean; // default: true - show the █░ bar; off keeps the percent only\n\tplanUsageWindow?: \"5h\" | \"weekly\"; // preferred plan window for the footer bar\n\t// lunr: permission mode default (per-session mode is in-memory; this is the startup default)\n\tdefaultPermissionMode?: DefaultPermissionMode; // default \"manual\"\n\t// lunr: rollback settings\n\trollbackEnabled?: boolean; // default false\n\trollbackTurns?: number; // default 2 — how many user-turns of snapshots to retain\n\trollbackCapture?: RollbackCapture; // default \"copies\"\n\trollbackScope?: RollbackScope; // default \"tools\"\n\tautoManageSubscriptions?: boolean; // lunr: when true, subscription key switching is fully automatic (no manual picker)\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n\thttpProxy?: string; // Proxy URL applied as HTTP_PROXY and HTTPS_PROXY for Pi-managed HTTP clients\n\thttpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it\n\twebsocketConnectTimeoutMs?: number; // WebSocket connect/open handshake timeout in milliseconds; 0 disables it\n}\n\n/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */\nfunction deepMergeSettings(base: Settings, overrides: Settings): Settings {\n\tconst result: Settings = { ...base };\n\n\tfor (const key of Object.keys(overrides) as (keyof Settings)[]) {\n\t\tconst overrideValue = overrides[key];\n\t\tconst baseValue = base[key];\n\n\t\tif (overrideValue === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// For nested objects, merge recursively\n\t\tif (\n\t\t\ttypeof overrideValue === \"object\" &&\n\t\t\toverrideValue !== null &&\n\t\t\t!Array.isArray(overrideValue) &&\n\t\t\ttypeof baseValue === \"object\" &&\n\t\t\tbaseValue !== null &&\n\t\t\t!Array.isArray(baseValue)\n\t\t) {\n\t\t\t(result as Record<string, unknown>)[key] = { ...baseValue, ...overrideValue };\n\t\t} else {\n\t\t\t// For primitives and arrays, override value wins\n\t\t\t(result as Record<string, unknown>)[key] = overrideValue;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseTimeoutSetting(value: unknown, settingName: string): number | undefined {\n\tconst timeoutMs = parseHttpIdleTimeoutMs(value);\n\tif (timeoutMs !== undefined) {\n\t\treturn timeoutMs;\n\t}\n\tif (value !== undefined) {\n\t\tthrow new Error(`Invalid ${settingName} setting: ${String(value)}`);\n\t}\n\treturn undefined;\n}\n\nexport type SettingsScope = \"global\" | \"project\";\n\nexport interface SettingsManagerCreateOptions {\n\tprojectTrusted?: boolean;\n}\n\nexport interface SettingsStorage {\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void;\n}\n\nexport interface SettingsError {\n\tscope: SettingsScope;\n\terror: Error;\n}\n\nexport class FileSettingsStorage implements SettingsStorage {\n\tprivate globalSettingsPath: string;\n\tprivate projectSettingsPath: string;\n\n\tconstructor(cwd: string, agentDir: string) {\n\t\tconst resolvedCwd = resolvePath(cwd);\n\t\tconst resolvedAgentDir = resolvePath(agentDir);\n\t\tthis.globalSettingsPath = join(resolvedAgentDir, \"settings.json\");\n\t\tthis.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, \"settings.json\");\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire settings lock\");\n\t}\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst path = scope === \"global\" ? this.globalSettingsPath : this.projectSettingsPath;\n\t\tconst dir = dirname(path);\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Only create directory and lock if file exists or we need to write\n\t\t\tconst fileExists = existsSync(path);\n\t\t\tif (fileExists) {\n\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t}\n\t\t\tconst current = fileExists ? readFileSync(path, \"utf-8\") : undefined;\n\t\t\tconst next = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\t// Only create directory when we actually need to write\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t\t}\n\t\t\t\tif (!release) {\n\t\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t\t}\n\t\t\t\twriteFileSync(path, next, \"utf-8\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemorySettingsStorage implements SettingsStorage {\n\tprivate global: string | undefined;\n\tprivate project: string | undefined;\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst current = scope === \"global\" ? this.global : this.project;\n\t\tconst next = fn(current);\n\t\tif (next !== undefined) {\n\t\t\tif (scope === \"global\") {\n\t\t\t\tthis.global = next;\n\t\t\t} else {\n\t\t\t\tthis.project = next;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class SettingsManager {\n\tprivate storage: SettingsStorage;\n\tprivate globalSettings: Settings;\n\tprivate projectSettings: Settings;\n\tprivate settings: Settings;\n\tprivate projectTrusted: boolean;\n\tprivate modifiedFields = new Set<keyof Settings>(); // Track global fields modified during session\n\tprivate modifiedNestedFields = new Map<keyof Settings, Set<string>>(); // Track global nested field modifications\n\tprivate modifiedProjectFields = new Set<keyof Settings>(); // Track project fields modified during session\n\tprivate modifiedProjectNestedFields = new Map<keyof Settings, Set<string>>(); // Track project nested field modifications\n\tprivate globalSettingsLoadError: Error | null = null; // Track if global settings file had parse errors\n\tprivate projectSettingsLoadError: Error | null = null; // Track if project settings file had parse errors\n\tprivate writeQueue: Promise<void> = Promise.resolve();\n\tprivate errors: SettingsError[];\n\n\tprivate constructor(\n\t\tstorage: SettingsStorage,\n\t\tinitialGlobal: Settings,\n\t\tinitialProject: Settings,\n\t\tglobalLoadError: Error | null = null,\n\t\tprojectLoadError: Error | null = null,\n\t\tinitialErrors: SettingsError[] = [],\n\t\tprojectTrusted = true,\n\t) {\n\t\tthis.storage = storage;\n\t\tthis.globalSettings = initialGlobal;\n\t\tthis.projectSettings = initialProject;\n\t\tthis.projectTrusted = projectTrusted;\n\t\tthis.globalSettingsLoadError = globalLoadError;\n\t\tthis.projectSettingsLoadError = projectLoadError;\n\t\tthis.errors = [...initialErrors];\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Create a SettingsManager that loads from files */\n\tstatic create(\n\t\tcwd: string,\n\t\tagentDir: string = getAgentDir(),\n\t\toptions: SettingsManagerCreateOptions = {},\n\t): SettingsManager {\n\t\tconst storage = new FileSettingsStorage(cwd, agentDir);\n\t\treturn SettingsManager.fromStorage(storage, options);\n\t}\n\n\t/** Create a SettingsManager from an arbitrary storage backend */\n\tstatic fromStorage(storage: SettingsStorage, options: SettingsManagerCreateOptions = {}): SettingsManager {\n\t\tconst projectTrusted = options.projectTrusted ?? true;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(storage, \"global\");\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(storage, \"project\", projectTrusted);\n\t\tconst initialErrors: SettingsError[] = [];\n\t\tif (globalLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"global\", error: globalLoad.error });\n\t\t}\n\t\tif (projectLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"project\", error: projectLoad.error });\n\t\t}\n\n\t\treturn new SettingsManager(\n\t\t\tstorage,\n\t\t\tglobalLoad.settings,\n\t\t\tprojectLoad.settings,\n\t\t\tglobalLoad.error,\n\t\t\tprojectLoad.error,\n\t\t\tinitialErrors,\n\t\t\tprojectTrusted,\n\t\t);\n\t}\n\n\t/** Create an in-memory SettingsManager (no file I/O) */\n\tstatic inMemory(settings: Partial<Settings> = {}, options: SettingsManagerCreateOptions = {}): SettingsManager {\n\t\tconst storage = new InMemorySettingsStorage();\n\t\tconst initialSettings = SettingsManager.migrateSettings(structuredClone(settings) as Record<string, unknown>);\n\t\tstorage.withLock(\"global\", () => JSON.stringify(initialSettings, null, 2));\n\t\treturn SettingsManager.fromStorage(storage, options);\n\t}\n\n\tprivate static loadFromStorage(storage: SettingsStorage, scope: SettingsScope, projectTrusted = true): Settings {\n\t\tif (scope === \"project\" && !projectTrusted) {\n\t\t\treturn {};\n\t\t}\n\n\t\tlet content: string | undefined;\n\t\tstorage.withLock(scope, (current) => {\n\t\t\tcontent = current;\n\t\t\treturn undefined;\n\t\t});\n\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\tconst settings = JSON.parse(content);\n\t\treturn SettingsManager.migrateSettings(settings);\n\t}\n\n\tprivate static tryLoadFromStorage(\n\t\tstorage: SettingsStorage,\n\t\tscope: SettingsScope,\n\t\tprojectTrusted = true,\n\t): { settings: Settings; error: Error | null } {\n\t\ttry {\n\t\t\treturn { settings: SettingsManager.loadFromStorage(storage, scope, projectTrusted), error: null };\n\t\t} catch (error) {\n\t\t\treturn { settings: {}, error: error as Error };\n\t\t}\n\t}\n\n\t/** Migrate old settings format to new format */\n\tprivate static migrateSettings(settings: Record<string, unknown>): Settings {\n\t\t// Migrate queueMode -> steeringMode\n\t\tif (\"queueMode\" in settings && !(\"steeringMode\" in settings)) {\n\t\t\tsettings.steeringMode = settings.queueMode;\n\t\t\tdelete settings.queueMode;\n\t\t}\n\n\t\t// Migrate legacy websockets boolean -> transport enum\n\t\tif (!(\"transport\" in settings) && typeof settings.websockets === \"boolean\") {\n\t\t\tsettings.transport = settings.websockets ? \"websocket\" : \"sse\";\n\t\t\tdelete settings.websockets;\n\t\t}\n\n\t\t// Migrate old skills object format to new array format\n\t\tif (\n\t\t\t\"skills\" in settings &&\n\t\t\ttypeof settings.skills === \"object\" &&\n\t\t\tsettings.skills !== null &&\n\t\t\t!Array.isArray(settings.skills)\n\t\t) {\n\t\t\tconst skillsSettings = settings.skills as {\n\t\t\t\tenableSkillCommands?: boolean;\n\t\t\t\tcustomDirectories?: unknown;\n\t\t\t};\n\t\t\tif (skillsSettings.enableSkillCommands !== undefined && settings.enableSkillCommands === undefined) {\n\t\t\t\tsettings.enableSkillCommands = skillsSettings.enableSkillCommands;\n\t\t\t}\n\t\t\tif (Array.isArray(skillsSettings.customDirectories) && skillsSettings.customDirectories.length > 0) {\n\t\t\t\tsettings.skills = skillsSettings.customDirectories;\n\t\t\t} else {\n\t\t\t\tdelete settings.skills;\n\t\t\t}\n\t\t}\n\n\t\t// Migrate retry.maxDelayMs -> retry.provider.maxRetryDelayMs\n\t\tif (\n\t\t\t\"retry\" in settings &&\n\t\t\ttypeof settings.retry === \"object\" &&\n\t\t\tsettings.retry !== null &&\n\t\t\t!Array.isArray(settings.retry)\n\t\t) {\n\t\t\tconst retrySettings = settings.retry as Record<string, unknown>;\n\t\t\tconst providerSettings =\n\t\t\t\ttypeof retrySettings.provider === \"object\" && retrySettings.provider !== null\n\t\t\t\t\t? (retrySettings.provider as Record<string, unknown>)\n\t\t\t\t\t: undefined;\n\t\t\tif (\n\t\t\t\ttypeof retrySettings.maxDelayMs === \"number\" &&\n\t\t\t\t(providerSettings?.maxRetryDelayMs === undefined || providerSettings?.maxRetryDelayMs === null)\n\t\t\t) {\n\t\t\t\tretrySettings.provider = {\n\t\t\t\t\t...(providerSettings ?? {}),\n\t\t\t\t\tmaxRetryDelayMs: retrySettings.maxDelayMs,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdelete retrySettings.maxDelayMs;\n\t\t}\n\n\t\treturn settings as Settings;\n\t}\n\n\tgetGlobalSettings(): Settings {\n\t\treturn structuredClone(this.globalSettings);\n\t}\n\n\tgetProjectSettings(): Settings {\n\t\treturn structuredClone(this.projectSettings);\n\t}\n\n\tisProjectTrusted(): boolean {\n\t\treturn this.projectTrusted;\n\t}\n\n\tsetProjectTrusted(trusted: boolean): void {\n\t\tif (this.projectTrusted === trusted) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.projectTrusted = trusted;\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tif (!trusted) {\n\t\t\tthis.projectSettings = {};\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t\t\treturn;\n\t\t}\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\", trusted);\n\t\tthis.projectSettings = projectLoad.settings;\n\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\tif (projectLoad.error) {\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.writeQueue;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(this.storage, \"global\");\n\t\tif (!globalLoad.error) {\n\t\t\tthis.globalSettings = globalLoad.settings;\n\t\t\tthis.globalSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.globalSettingsLoadError = globalLoad.error;\n\t\t\tthis.recordError(\"global\", globalLoad.error);\n\t\t}\n\n\t\tthis.modifiedFields.clear();\n\t\tthis.modifiedNestedFields.clear();\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\", this.projectTrusted);\n\t\tif (!projectLoad.error) {\n\t\t\tthis.projectSettings = projectLoad.settings;\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Apply additional overrides on top of current settings */\n\tapplyOverrides(overrides: Partial<Settings>): void {\n\t\tthis.settings = deepMergeSettings(this.settings, overrides);\n\t}\n\n\t/** Mark a global field as modified during this session */\n\tprivate markModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedNestedFields.has(field)) {\n\t\t\t\tthis.modifiedNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\t/** Mark a project field as modified during this session */\n\tprivate markProjectModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedProjectFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedProjectNestedFields.has(field)) {\n\t\t\t\tthis.modifiedProjectNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedProjectNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\tprivate assertProjectTrustedForWrite(): void {\n\t\tif (!this.projectTrusted) {\n\t\t\tthrow new Error(\"Project is not trusted; refusing to write project settings\");\n\t\t}\n\t}\n\n\tprivate recordError(scope: SettingsScope, error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push({ scope, error: normalizedError });\n\t}\n\n\tprivate clearModifiedScope(scope: SettingsScope): void {\n\t\tif (scope === \"global\") {\n\t\t\tthis.modifiedFields.clear();\n\t\t\tthis.modifiedNestedFields.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\t}\n\n\tprivate enqueueWrite(scope: SettingsScope, task: () => void): void {\n\t\tthis.writeQueue = this.writeQueue\n\t\t\t.then(() => {\n\t\t\t\tif (scope === \"project\") {\n\t\t\t\t\tthis.assertProjectTrustedForWrite();\n\t\t\t\t}\n\t\t\t\ttask();\n\t\t\t\tthis.clearModifiedScope(scope);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.recordError(scope, error);\n\t\t\t});\n\t}\n\n\tprivate cloneModifiedNestedFields(source: Map<keyof Settings, Set<string>>): Map<keyof Settings, Set<string>> {\n\t\tconst snapshot = new Map<keyof Settings, Set<string>>();\n\t\tfor (const [key, value] of source.entries()) {\n\t\t\tsnapshot.set(key, new Set(value));\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate persistScopedSettings(\n\t\tscope: SettingsScope,\n\t\tsnapshotSettings: Settings,\n\t\tmodifiedFields: Set<keyof Settings>,\n\t\tmodifiedNestedFields: Map<keyof Settings, Set<string>>,\n\t): void {\n\t\tthis.storage.withLock(scope, (current) => {\n\t\t\tconst currentFileSettings = current\n\t\t\t\t? SettingsManager.migrateSettings(JSON.parse(current) as Record<string, unknown>)\n\t\t\t\t: {};\n\t\t\tconst mergedSettings: Settings = { ...currentFileSettings };\n\t\t\tfor (const field of modifiedFields) {\n\t\t\t\tconst value = snapshotSettings[field];\n\t\t\t\tif (modifiedNestedFields.has(field) && typeof value === \"object\" && value !== null) {\n\t\t\t\t\tconst nestedModified = modifiedNestedFields.get(field)!;\n\t\t\t\t\tconst baseNested = (currentFileSettings[field] as Record<string, unknown>) ?? {};\n\t\t\t\t\tconst inMemoryNested = value as Record<string, unknown>;\n\t\t\t\t\tconst mergedNested = { ...baseNested };\n\t\t\t\t\tfor (const nestedKey of nestedModified) {\n\t\t\t\t\t\tmergedNested[nestedKey] = inMemoryNested[nestedKey];\n\t\t\t\t\t}\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = mergedNested;\n\t\t\t\t} else {\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn JSON.stringify(mergedSettings, null, 2);\n\t\t});\n\t}\n\n\tprivate save(): void {\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.globalSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotGlobalSettings = structuredClone(this.globalSettings);\n\t\tconst modifiedFields = new Set(this.modifiedFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);\n\n\t\tthis.enqueueWrite(\"global\", () => {\n\t\t\tthis.persistScopedSettings(\"global\", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate saveProjectSettings(settings: Settings): void {\n\t\tthis.assertProjectTrustedForWrite();\n\t\tthis.projectSettings = structuredClone(settings);\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.projectSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotProjectSettings = structuredClone(this.projectSettings);\n\t\tconst modifiedFields = new Set(this.modifiedProjectFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);\n\t\tthis.enqueueWrite(\"project\", () => {\n\t\t\tthis.persistScopedSettings(\"project\", snapshotProjectSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate updateProjectSettings(field: keyof Settings, update: (settings: Settings) => void): void {\n\t\tthis.assertProjectTrustedForWrite();\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tupdate(projectSettings);\n\t\tthis.markProjectModified(field);\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeQueue;\n\t}\n\n\tdrainErrors(): SettingsError[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\tgetSessionDir(): string | undefined {\n\t\tconst sessionDir = this.settings.sessionDir;\n\t\treturn sessionDir ? normalizePath(sessionDir) : sessionDir;\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\t/** lunr: cron fallback models (\"provider/modelId\"), tried in order after a gateway cron fire's default model fails. */\n\tgetCronFallbackModels(): string[] {\n\t\treturn this.settings.cronFallbackModels ?? [];\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tgetSteeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.steeringMode || \"one-at-a-time\";\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.steeringMode = mode;\n\t\tthis.markModified(\"steeringMode\");\n\t\tthis.save();\n\t}\n\n\tgetFollowUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.followUpMode || \"one-at-a-time\";\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.followUpMode = mode;\n\t\tthis.markModified(\"followUpMode\");\n\t\tthis.save();\n\t}\n\n\tgetThemeSetting(): string | undefined {\n\t\tconst value = this.settings.theme;\n\t\tif (typeof value === \"string\") return value;\n\t\treturn undefined;\n\t}\n\n\tgetTheme(): string | undefined {\n\t\tconst theme = this.getThemeSetting();\n\t\treturn theme?.includes(\"/\") ? undefined : theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.globalSettings.theme = theme;\n\t\tthis.markModified(\"theme\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): ThinkingLevel | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: ThinkingLevel): void {\n\t\tthis.globalSettings.defaultThinkingLevel = level;\n\t\tthis.markModified(\"defaultThinkingLevel\");\n\t\tthis.save();\n\t}\n\n\tgetTransport(): TransportSetting {\n\t\treturn this.settings.transport ?? \"auto\";\n\t}\n\n\tsetTransport(transport: TransportSetting): void {\n\t\tthis.globalSettings.transport = transport;\n\t\tthis.markModified(\"transport\");\n\t\tthis.save();\n\t}\n\n\tgetCacheRetention(): \"none\" | \"short\" | \"long\" | undefined {\n\t\treturn this.settings.cacheRetention;\n\t}\n\n\tsetCacheRetention(cacheRetention: \"none\" | \"short\" | \"long\"): void {\n\t\tthis.globalSettings.cacheRetention = cacheRetention;\n\t\tthis.markModified(\"cacheRetention\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.compaction) {\n\t\t\tthis.globalSettings.compaction = {};\n\t\t}\n\t\tthis.globalSettings.compaction.enabled = enabled;\n\t\tthis.markModified(\"compaction\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetBranchSummarySettings(): { reserveTokens: number; skipPrompt: boolean } {\n\t\treturn {\n\t\t\treserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,\n\t\t\tskipPrompt: this.settings.branchSummary?.skipPrompt ?? false,\n\t\t};\n\t}\n\n\tgetBranchSummarySkipPrompt(): boolean {\n\t\treturn this.settings.branchSummary?.skipPrompt ?? false;\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.retry) {\n\t\t\tthis.globalSettings.retry = {};\n\t\t}\n\t\tthis.globalSettings.retry.enabled = enabled;\n\t\tthis.markModified(\"retry\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHttpIdleTimeoutMs(): number {\n\t\treturn parseTimeoutSetting(this.settings.httpIdleTimeoutMs, \"httpIdleTimeoutMs\") ?? DEFAULT_HTTP_IDLE_TIMEOUT_MS;\n\t}\n\n\tsetHttpIdleTimeoutMs(timeoutMs: number): void {\n\t\tif (!Number.isFinite(timeoutMs) || timeoutMs < 0) {\n\t\t\tthrow new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`);\n\t\t}\n\t\tthis.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs);\n\t\tthis.markModified(\"httpIdleTimeoutMs\");\n\t\tthis.save();\n\t}\n\n\tgetProviderRetrySettings(): { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs: number } {\n\t\treturn {\n\t\t\ttimeoutMs: this.settings.retry?.provider?.timeoutMs,\n\t\t\tmaxRetries: this.settings.retry?.provider?.maxRetries,\n\t\t\tmaxRetryDelayMs: this.settings.retry?.provider?.maxRetryDelayMs ?? 60000,\n\t\t};\n\t}\n\n\tgetWebSocketConnectTimeoutMs(): number | undefined {\n\t\treturn parseTimeoutSetting(this.settings.websocketConnectTimeoutMs, \"websocketConnectTimeoutMs\");\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tgetThinkingCollapse(): boolean {\n\t\treturn this.settings.thinkingCollapse ?? true;\n\t}\n\n\tgetShowCacheMissNotices(): boolean {\n\t\treturn this.settings.showCacheMissNotices ?? false;\n\t}\n\n\tgetExternalEditorCommand(): string | undefined {\n\t\tconst configuredEditor = this.settings.externalEditor;\n\t\tif (typeof configuredEditor === \"string\" && configuredEditor.trim() !== \"\") {\n\t\t\treturn configuredEditor;\n\t\t}\n\t\tconst environmentEditor = process.env.VISUAL || process.env.EDITOR;\n\t\tif (environmentEditor) {\n\t\t\treturn environmentEditor;\n\t\t}\n\t\treturn process.platform === \"win32\" ? \"notepad\" : \"nano\";\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.globalSettings.hideThinkingBlock = hide;\n\t\tthis.markModified(\"hideThinkingBlock\");\n\t\tthis.save();\n\t}\n\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.globalSettings.thinkingCollapse = collapse;\n\t\tthis.markModified(\"thinkingCollapse\");\n\t\tthis.save();\n\t}\n\n\tsetShowCacheMissNotices(show: boolean): void {\n\t\tthis.globalSettings.showCacheMissNotices = show;\n\t\tthis.markModified(\"showCacheMissNotices\");\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\tconst shellPath = this.settings.shellPath;\n\t\treturn shellPath ? normalizePath(shellPath) : shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.globalSettings.shellPath = path;\n\t\tthis.markModified(\"shellPath\");\n\t\tthis.save();\n\t}\n\n\tgetQuietStartup(): boolean {\n\t\treturn this.settings.quietStartup ?? false;\n\t}\n\n\tsetQuietStartup(quiet: boolean): void {\n\t\tthis.globalSettings.quietStartup = quiet;\n\t\tthis.markModified(\"quietStartup\");\n\t\tthis.save();\n\t}\n\n\tgetSmoothStreaming(): boolean {\n\t\treturn this.settings.smoothStreaming ?? false;\n\t}\n\n\tsetSmoothStreaming(enabled: boolean): void {\n\t\tthis.globalSettings.smoothStreaming = enabled;\n\t\tthis.markModified(\"smoothStreaming\");\n\t\tthis.save();\n\t}\n\n\tgetSessionRetentionDays(): number {\n\t\tconst value = this.settings.sessionRetentionDays;\n\t\tif (typeof value === \"number\" && Number.isFinite(value) && value >= 0) {\n\t\t\treturn Math.floor(value);\n\t\t}\n\t\treturn 30;\n\t}\n\n\tsetSessionRetentionDays(days: number): void {\n\t\tthis.globalSettings.sessionRetentionDays = Math.max(0, Math.floor(days));\n\t\tthis.markModified(\"sessionRetentionDays\");\n\t\tthis.save();\n\t}\n\n\tgetMemoryCharCap(): number {\n\t\tconst value = this.settings.memoryCharCap;\n\t\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\t\treturn Math.min(MEMORY_CHAR_CAP_MAX, Math.max(MEMORY_CHAR_CAP_MIN, Math.floor(value)));\n\t\t}\n\t\treturn MEMORY_CHAR_CAP_DEFAULT;\n\t}\n\n\tsetMemoryCharCap(cap: number): void {\n\t\tthis.globalSettings.memoryCharCap = Math.min(MEMORY_CHAR_CAP_MAX, Math.max(MEMORY_CHAR_CAP_MIN, Math.floor(cap)));\n\t\tthis.markModified(\"memoryCharCap\");\n\t\tthis.save();\n\t}\n\n\tgetBehaviorPreset(): BehaviorPreset {\n\t\tconst value = this.settings.behaviorPreset;\n\t\treturn isBehaviorPreset(value) ? value : \"default\";\n\t}\n\n\tsetBehaviorPreset(preset: BehaviorPreset): void {\n\t\tthis.globalSettings.behaviorPreset = preset;\n\t\tthis.markModified(\"behaviorPreset\");\n\t\tthis.save();\n\t}\n\n\t// lunr: TUI customize settings getters/setters.\n\tgetGutterRail(): boolean {\n\t\treturn this.settings.gutterRail ?? true;\n\t}\n\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.globalSettings.gutterRail = enabled;\n\t\tthis.markModified(\"gutterRail\");\n\t\tthis.save();\n\t}\n\n\tgetPromptSymbol(): boolean {\n\t\treturn this.settings.promptSymbol ?? true;\n\t}\n\n\tsetPromptSymbol(enabled: boolean): void {\n\t\tthis.globalSettings.promptSymbol = enabled;\n\t\tthis.markModified(\"promptSymbol\");\n\t\tthis.save();\n\t}\n\n\t// lunr: footer element toggle getters/setters.\n\tgetFooterMcp(): boolean {\n\t\treturn this.settings.footerMcp ?? true;\n\t}\n\n\tsetFooterMcp(enabled: boolean): void {\n\t\tthis.globalSettings.footerMcp = enabled;\n\t\tthis.markModified(\"footerMcp\");\n\t\tthis.save();\n\t}\n\n\tgetFooterLsp(): boolean {\n\t\treturn this.settings.footerLsp ?? false;\n\t}\n\n\tsetFooterLsp(enabled: boolean): void {\n\t\tthis.globalSettings.footerLsp = enabled;\n\t\tthis.markModified(\"footerLsp\");\n\t\tthis.save();\n\t}\n\n\tgetFooterContext(): boolean {\n\t\treturn this.settings.footerContext ?? true;\n\t}\n\n\tsetFooterContext(enabled: boolean): void {\n\t\tthis.globalSettings.footerContext = enabled;\n\t\tthis.markModified(\"footerContext\");\n\t\tthis.save();\n\t}\n\n\tgetFooterTokens(): boolean {\n\t\treturn this.settings.footerTokens ?? true;\n\t}\n\n\tsetFooterTokens(enabled: boolean): void {\n\t\tthis.globalSettings.footerTokens = enabled;\n\t\tthis.markModified(\"footerTokens\");\n\t\tthis.save();\n\t}\n\n\tgetFooterStatuses(): boolean {\n\t\treturn this.settings.footerStatuses ?? true;\n\t}\n\n\tsetFooterStatuses(enabled: boolean): void {\n\t\tthis.globalSettings.footerStatuses = enabled;\n\t\tthis.markModified(\"footerStatuses\");\n\t\tthis.save();\n\t}\n\n\tgetFooterGit(): boolean {\n\t\treturn this.settings.footerGit ?? true;\n\t}\n\n\tsetFooterGit(enabled: boolean): void {\n\t\tthis.globalSettings.footerGit = enabled;\n\t\tthis.markModified(\"footerGit\");\n\t\tthis.save();\n\t}\n\n\tgetFooterPlan(): boolean {\n\t\treturn this.settings.footerPlan ?? true;\n\t}\n\n\tsetFooterPlan(enabled: boolean): void {\n\t\tthis.globalSettings.footerPlan = enabled;\n\t\tthis.markModified(\"footerPlan\");\n\t\tthis.save();\n\t}\n\n\tgetFooterPlanBar(): boolean {\n\t\treturn this.settings.footerPlanBar ?? true;\n\t}\n\n\tsetFooterPlanBar(enabled: boolean): void {\n\t\tthis.globalSettings.footerPlanBar = enabled;\n\t\tthis.markModified(\"footerPlanBar\");\n\t\tthis.save();\n\t}\n\n\tgetPlanUsageWindow(): \"5h\" | \"weekly\" {\n\t\treturn this.settings.planUsageWindow === \"5h\" ? \"5h\" : \"weekly\";\n\t}\n\n\tsetPlanUsageWindow(window: \"5h\" | \"weekly\"): void {\n\t\tthis.globalSettings.planUsageWindow = window;\n\t\tthis.markModified(\"planUsageWindow\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultProjectTrust(): DefaultProjectTrust {\n\t\tconst value = this.globalSettings.defaultProjectTrust;\n\t\treturn value === \"always\" || value === \"never\" ? value : \"ask\";\n\t}\n\n\tsetDefaultProjectTrust(defaultProjectTrust: DefaultProjectTrust): void {\n\t\tthis.globalSettings.defaultProjectTrust = defaultProjectTrust;\n\t\tthis.markModified(\"defaultProjectTrust\");\n\t\tthis.save();\n\t}\n\n\t// lunr: default permission mode (startup default; per-session mode is in-memory)\n\tgetDefaultPermissionMode(): DefaultPermissionMode {\n\t\tconst value = this.settings.defaultPermissionMode;\n\t\treturn value === \"manual\" || value === \"yolo\" || value === \"plan\" || value === \"auto\" ? value : \"manual\";\n\t}\n\n\tsetDefaultPermissionMode(mode: DefaultPermissionMode): void {\n\t\tthis.globalSettings.defaultPermissionMode = mode;\n\t\tthis.markModified(\"defaultPermissionMode\");\n\t\tthis.save();\n\t}\n\n\t// lunr: rollback settings getters/setters\n\tgetRollbackEnabled(): boolean {\n\t\treturn this.settings.rollbackEnabled ?? false;\n\t}\n\n\tsetRollbackEnabled(enabled: boolean): void {\n\t\tthis.globalSettings.rollbackEnabled = enabled;\n\t\tthis.markModified(\"rollbackEnabled\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackTurns(): number {\n\t\tconst value = this.settings.rollbackTurns;\n\t\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\t\treturn Math.min(20, Math.max(1, Math.floor(value)));\n\t\t}\n\t\treturn 2;\n\t}\n\n\tsetRollbackTurns(turns: number): void {\n\t\tthis.globalSettings.rollbackTurns = Math.min(20, Math.max(1, Math.floor(turns)));\n\t\tthis.markModified(\"rollbackTurns\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackCapture(): RollbackCapture {\n\t\tconst value = this.settings.rollbackCapture;\n\t\treturn value === \"copies\" || value === \"shadow-git\" || value === \"hybrid\" ? value : \"copies\";\n\t}\n\n\tsetRollbackCapture(mode: RollbackCapture): void {\n\t\tthis.globalSettings.rollbackCapture = mode;\n\t\tthis.markModified(\"rollbackCapture\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackScope(): RollbackScope {\n\t\tconst value = this.settings.rollbackScope;\n\t\treturn value === \"tools\" || value === \"tree\" ? value : \"tools\";\n\t}\n\n\tsetRollbackScope(scope: RollbackScope): void {\n\t\tthis.globalSettings.rollbackScope = scope;\n\t\tthis.markModified(\"rollbackScope\");\n\t\tthis.save();\n\t}\n\n\t// lunr: multi-subscription auto-management toggle\n\tgetAutoManageSubscriptions(): boolean {\n\t\treturn this.settings.autoManageSubscriptions ?? false;\n\t}\n\n\tsetAutoManageSubscriptions(enabled: boolean): void {\n\t\tthis.globalSettings.autoManageSubscriptions = enabled;\n\t\tthis.markModified(\"autoManageSubscriptions\");\n\t\tthis.save();\n\t}\n\n\tgetShellCommandPrefix(): string | undefined {\n\t\treturn this.settings.shellCommandPrefix;\n\t}\n\n\tsetShellCommandPrefix(prefix: string | undefined): void {\n\t\tthis.globalSettings.shellCommandPrefix = prefix;\n\t\tthis.markModified(\"shellCommandPrefix\");\n\t\tthis.save();\n\t}\n\n\tgetNpmCommand(): string[] | undefined {\n\t\treturn this.settings.npmCommand ? [...this.settings.npmCommand] : undefined;\n\t}\n\n\tsetNpmCommand(command: string[] | undefined): void {\n\t\tthis.globalSettings.npmCommand = command ? [...command] : undefined;\n\t\tthis.markModified(\"npmCommand\");\n\t\tthis.save();\n\t}\n\n\tgetEnableAnalytics(): boolean {\n\t\treturn this.settings.enableAnalytics ?? false;\n\t}\n\n\tgetTrackingId(): string | undefined {\n\t\treturn this.settings.trackingId;\n\t}\n\n\t/** Set the analytics opt-in preference; generates a tracking identifier on first opt-in */\n\tsetEnableAnalytics(enabled: boolean): void {\n\t\tthis.globalSettings.enableAnalytics = enabled;\n\t\tthis.markModified(\"enableAnalytics\");\n\t\tif (enabled && !this.globalSettings.trackingId) {\n\t\t\tthis.globalSettings.trackingId = randomUUID();\n\t\t\tthis.markModified(\"trackingId\");\n\t\t}\n\t\tthis.save();\n\t}\n\n\tgetPackages(): PackageSource[] {\n\t\treturn [...(this.settings.packages ?? [])];\n\t}\n\n\tsetPackages(packages: PackageSource[]): void {\n\t\tthis.globalSettings.packages = packages;\n\t\tthis.markModified(\"packages\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPackages(packages: PackageSource[]): void {\n\t\tthis.updateProjectSettings(\"packages\", (settings) => {\n\t\t\tsettings.packages = packages;\n\t\t});\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn [...(this.settings.extensions ?? [])];\n\t}\n\n\tsetExtensionPaths(paths: string[]): void {\n\t\tthis.globalSettings.extensions = paths;\n\t\tthis.markModified(\"extensions\");\n\t\tthis.save();\n\t}\n\n\tsetProjectExtensionPaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"extensions\", (settings) => {\n\t\t\tsettings.extensions = paths;\n\t\t});\n\t}\n\n\tgetSkillPaths(): string[] {\n\t\treturn [...(this.settings.skills ?? [])];\n\t}\n\n\tsetSkillPaths(paths: string[]): void {\n\t\tthis.globalSettings.skills = paths;\n\t\tthis.markModified(\"skills\");\n\t\tthis.save();\n\t}\n\n\tsetProjectSkillPaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"skills\", (settings) => {\n\t\t\tsettings.skills = paths;\n\t\t});\n\t}\n\n\tgetPromptTemplatePaths(): string[] {\n\t\treturn [...(this.settings.prompts ?? [])];\n\t}\n\n\tsetPromptTemplatePaths(paths: string[]): void {\n\t\tthis.globalSettings.prompts = paths;\n\t\tthis.markModified(\"prompts\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPromptTemplatePaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"prompts\", (settings) => {\n\t\t\tsettings.prompts = paths;\n\t\t});\n\t}\n\n\tgetThemePaths(): string[] {\n\t\treturn [...(this.settings.themes ?? [])];\n\t}\n\n\tsetThemePaths(paths: string[]): void {\n\t\tthis.globalSettings.themes = paths;\n\t\tthis.markModified(\"themes\");\n\t\tthis.save();\n\t}\n\n\tsetProjectThemePaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"themes\", (settings) => {\n\t\t\tsettings.themes = paths;\n\t\t});\n\t}\n\n\tgetEnableSkillCommands(): boolean {\n\t\treturn this.settings.enableSkillCommands ?? true;\n\t}\n\n\tsetEnableSkillCommands(enabled: boolean): void {\n\t\tthis.globalSettings.enableSkillCommands = enabled;\n\t\tthis.markModified(\"enableSkillCommands\");\n\t\tthis.save();\n\t}\n\n\tgetThinkingBudgets(): ThinkingBudgetsSettings | undefined {\n\t\treturn this.settings.thinkingBudgets;\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showImages = show;\n\t\tthis.markModified(\"terminal\", \"showImages\");\n\t\tthis.save();\n\t}\n\n\tgetImageWidthCells(): number {\n\t\tconst width = this.settings.terminal?.imageWidthCells;\n\t\tif (typeof width !== \"number\" || !Number.isFinite(width)) {\n\t\t\treturn 60;\n\t\t}\n\t\treturn Math.max(1, Math.floor(width));\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.markModified(\"terminal\", \"imageWidthCells\");\n\t\tthis.save();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\t// Settings takes precedence, then env var, then default false\n\t\tif (this.settings.terminal?.clearOnShrink !== undefined) {\n\t\t\treturn this.settings.terminal.clearOnShrink;\n\t\t}\n\t\treturn process.env.PI_CLEAR_ON_SHRINK === \"1\";\n\t}\n\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.clearOnShrink = enabled;\n\t\tthis.markModified(\"terminal\", \"clearOnShrink\");\n\t\tthis.save();\n\t}\n\n\tgetShowTerminalProgress(): boolean {\n\t\treturn this.settings.terminal?.showTerminalProgress ?? false;\n\t}\n\n\tsetShowTerminalProgress(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showTerminalProgress = enabled;\n\t\tthis.markModified(\"terminal\", \"showTerminalProgress\");\n\t\tthis.save();\n\t}\n\n\tgetImageAutoResize(): boolean {\n\t\treturn this.settings.images?.autoResize ?? true;\n\t}\n\n\tsetImageAutoResize(enabled: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.autoResize = enabled;\n\t\tthis.markModified(\"images\", \"autoResize\");\n\t\tthis.save();\n\t}\n\n\tgetBlockImages(): boolean {\n\t\treturn this.settings.images?.blockImages ?? false;\n\t}\n\n\tsetBlockImages(blocked: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.blockImages = blocked;\n\t\tthis.markModified(\"images\", \"blockImages\");\n\t\tthis.save();\n\t}\n\n\tgetEnabledModels(): string[] | undefined {\n\t\treturn this.settings.enabledModels;\n\t}\n\n\tsetEnabledModels(patterns: string[] | undefined): void {\n\t\tthis.globalSettings.enabledModels = patterns;\n\t\tthis.markModified(\"enabledModels\");\n\t\tthis.save();\n\t}\n\n\tgetDoubleEscapeAction(): \"fork\" | \"tree\" | \"none\" {\n\t\treturn this.settings.doubleEscapeAction ?? \"tree\";\n\t}\n\n\tsetDoubleEscapeAction(action: \"fork\" | \"tree\" | \"none\"): void {\n\t\tthis.globalSettings.doubleEscapeAction = action;\n\t\tthis.markModified(\"doubleEscapeAction\");\n\t\tthis.save();\n\t}\n\n\tgetTreeFilterMode(): \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\" {\n\t\tconst mode = this.settings.treeFilterMode;\n\t\tconst valid = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n\t\treturn mode && valid.includes(mode) ? mode : \"default\";\n\t}\n\n\tsetTreeFilterMode(mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"): void {\n\t\tthis.globalSettings.treeFilterMode = mode;\n\t\tthis.markModified(\"treeFilterMode\");\n\t\tthis.save();\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === \"1\";\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tthis.globalSettings.showHardwareCursor = enabled;\n\t\tthis.markModified(\"showHardwareCursor\");\n\t\tthis.save();\n\t}\n\n\tgetEditorPaddingX(): number {\n\t\treturn this.settings.editorPaddingX ?? 0;\n\t}\n\n\tsetEditorPaddingX(padding: number): void {\n\t\tthis.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));\n\t\tthis.markModified(\"editorPaddingX\");\n\t\tthis.save();\n\t}\n\n\tgetOutputPad(): 0 | 1 {\n\t\treturn this.settings.outputPad === 0 ? 0 : 1;\n\t}\n\n\tsetOutputPad(padding: 0 | 1): void {\n\t\tthis.globalSettings.outputPad = padding;\n\t\tthis.markModified(\"outputPad\");\n\t\tthis.save();\n\t}\n\n\tgetAutocompleteMaxVisible(): number {\n\t\treturn this.settings.autocompleteMaxVisible ?? 5;\n\t}\n\n\tsetAutocompleteMaxVisible(maxVisible: number): void {\n\t\tthis.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));\n\t\tthis.markModified(\"autocompleteMaxVisible\");\n\t\tthis.save();\n\t}\n\n\tgetCodeBlockIndent(): string {\n\t\treturn this.settings.markdown?.codeBlockIndent ?? \" \";\n\t}\n\n\tgetModelTiers(): ModelTiersSettings {\n\t\treturn { ...(this.settings.modelTiers ?? {}) };\n\t}\n\n\tgetModelTiersEnabled(): boolean {\n\t\treturn this.settings.modelTiers?.enabled ?? false;\n\t}\n\n\tsetModelTiersEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tthis.globalSettings.modelTiers.enabled = enabled;\n\t\tthis.markModified(\"modelTiers\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetTierModel(tier: ModelTierName): string | undefined {\n\t\treturn this.settings.modelTiers?.[tier];\n\t}\n\n\tsetTierModel(tier: ModelTierName, model: string): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tthis.globalSettings.modelTiers[tier] = model;\n\t\tthis.markModified(\"modelTiers\", tier);\n\t\tthis.save();\n\t}\n\n\tgetTierThinking(tier: ModelTierName): ThinkingLevel | undefined {\n\t\treturn this.settings.modelTiers?.[tierThinkingKey(tier)];\n\t}\n\n\tsetTierThinking(tier: ModelTierName, level: ThinkingLevel | undefined): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tconst key = tierThinkingKey(tier);\n\t\tif (level === undefined) {\n\t\t\tdelete this.globalSettings.modelTiers[key];\n\t\t} else {\n\t\t\tthis.globalSettings.modelTiers[key] = level;\n\t\t}\n\t\tthis.markModified(\"modelTiers\", key);\n\t\tthis.save();\n\t}\n}\n\nfunction tierThinkingKey(tier: ModelTierName): \"lightThinking\" | \"standardThinking\" | \"heavyThinking\" {\n\tif (tier === \"light\") return \"lightThinking\";\n\tif (tier === \"standard\") return \"standardThinking\";\n\treturn \"heavyThinking\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Transport } from \"@ashx-j/lunr-ai\";\nimport { randomUUID } from \"crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { normalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { type BehaviorPreset, isBehaviorPreset } from \"./behavior-preset.ts\";\nimport { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from \"./http-dispatcher.ts\";\nimport { MEMORY_CHAR_CAP_DEFAULT, MEMORY_CHAR_CAP_MAX, MEMORY_CHAR_CAP_MIN } from \"./memory-cap.ts\";\n\nexport type { BehaviorPreset };\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport type ModelTierName = \"light\" | \"standard\" | \"heavy\";\n\nexport interface ModelTiersSettings {\n\tenabled?: boolean; // default: false - route subagents to per-tier models\n\tlight?: string; // provider/model string (same format as /model)\n\tstandard?: string;\n\theavy?: string;\n\t/** Unset = inherit the parent session thinking level. */\n\tlightThinking?: ThinkingLevel;\n\tstandardThinking?: ThinkingLevel;\n\theavyThinking?: ThinkingLevel;\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport type DefaultProjectTrust = \"ask\" | \"always\" | \"never\";\nexport type DefaultPermissionMode = \"manual\" | \"yolo\" | \"plan\" | \"auto\";\nexport type RollbackCapture = \"copies\" | \"shadow-git\" | \"hybrid\";\nexport type RollbackScope = \"tools\" | \"tree\";\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n * - autoload=false: start empty and only apply explicit resource patterns\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\tautoload?: boolean;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\t// lunr: gateway-daemon cron fallback models, \"provider/modelId\" entries tried\n\t// in order when a cron fire fails (timeout or any error). Hand-edited.\n\tcronFallbackModels?: string[];\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tthinkingCollapse?: boolean; // default: true - collapse completed thinking blocks to \"Thought for Xs\" + first sentence\n\tshowCacheMissNotices?: boolean; // default: false - show transcript notices for significant prompt-cache misses\n\tcacheRetention?: \"none\" | \"short\" | \"long\"; // default: unset - falls back to PI_CACHE_RETENTION env, then \"short\" (packages/ai)\n\texternalEditor?: string; // Command for Ctrl+G external editor; takes precedence over VISUAL/EDITOR\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows); supports leading ~ expansion\n\tquietStartup?: boolean;\n\tsmoothStreaming?: boolean; // default: false - reveal streamed responses grapheme by grapheme (~30 FPS)\n\tdefaultProjectTrust?: DefaultProjectTrust; // default: \"ask\"; global setting only\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tenableAnalytics?: boolean; // default: false - opt-in analytics data sharing\n\ttrackingId?: string; // analytics tracking identifier, generated when analytics is enabled\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\toutputPad?: 0 | 1; // Horizontal padding for chat message output (default: 1)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\tmodelTiers?: ModelTiersSettings;\n\tsessionRetentionDays?: number; // default: 30 - delete session files older than N days at launch; 0 = keep forever\n\tmemoryCharCap?: number; // default: 5000 - simple-pi-memory character cap (1..30000)\n\tbehaviorPreset?: BehaviorPreset; // default: \"default\" - built-in behavior.md preset; custom = file is source of truth\n\t// lunr: TUI customize settings (gutter rail, prompt symbol)\n\tgutterRail?: boolean; // default: true - render a thin left rail around each turn\n\tpromptSymbol?: boolean; // default: true - show the ☾ › prompt glyph on the editor's first line\n\t// lunr: footer element toggles (ashxj-tui stats line)\n\tfooterMcp?: boolean; // default: true - show the pi-mcp-adapter mcp/mcp-auth status segments\n\tfooterLsp?: boolean; // default: false - show the pi-lsp-extension lsp status segment\n\tfooterContext?: boolean; // default: true - show the context-usage pct/window segment\n\tfooterTokens?: boolean; // default: true - show the ↑in ↓out token totals segment\n\tfooterTps?: boolean; // default: true - show the pi-tps t/s segment\n\tfooterStatuses?: boolean; // default: true - show the plan/goal/swarm/research status segments\n\tfooterGit?: boolean; // default: true - show git branch + added/removed in the footer\n\tfooterPlan?: boolean; // default: true - show the subscription usage segment\n\tfooterPlanBar?: boolean; // default: true - show the █░ bar; off keeps the percent only\n\tplanUsageWindow?: \"5h\" | \"weekly\"; // preferred plan window for the footer bar\n\t// lunr: permission mode default (per-session mode is in-memory; this is the startup default)\n\tdefaultPermissionMode?: DefaultPermissionMode; // default \"manual\"\n\t// lunr: rollback settings\n\trollbackEnabled?: boolean; // default false\n\trollbackTurns?: number; // default 2 — how many user-turns of snapshots to retain\n\trollbackCapture?: RollbackCapture; // default \"copies\"\n\trollbackScope?: RollbackScope; // default \"tools\"\n\tautoManageSubscriptions?: boolean; // lunr: when true, subscription key switching is fully automatic (no manual picker)\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n\thttpProxy?: string; // Proxy URL applied as HTTP_PROXY and HTTPS_PROXY for Pi-managed HTTP clients\n\thttpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it\n\twebsocketConnectTimeoutMs?: number; // WebSocket connect/open handshake timeout in milliseconds; 0 disables it\n}\n\n/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */\nfunction deepMergeSettings(base: Settings, overrides: Settings): Settings {\n\tconst result: Settings = { ...base };\n\n\tfor (const key of Object.keys(overrides) as (keyof Settings)[]) {\n\t\tconst overrideValue = overrides[key];\n\t\tconst baseValue = base[key];\n\n\t\tif (overrideValue === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// For nested objects, merge recursively\n\t\tif (\n\t\t\ttypeof overrideValue === \"object\" &&\n\t\t\toverrideValue !== null &&\n\t\t\t!Array.isArray(overrideValue) &&\n\t\t\ttypeof baseValue === \"object\" &&\n\t\t\tbaseValue !== null &&\n\t\t\t!Array.isArray(baseValue)\n\t\t) {\n\t\t\t(result as Record<string, unknown>)[key] = { ...baseValue, ...overrideValue };\n\t\t} else {\n\t\t\t// For primitives and arrays, override value wins\n\t\t\t(result as Record<string, unknown>)[key] = overrideValue;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseTimeoutSetting(value: unknown, settingName: string): number | undefined {\n\tconst timeoutMs = parseHttpIdleTimeoutMs(value);\n\tif (timeoutMs !== undefined) {\n\t\treturn timeoutMs;\n\t}\n\tif (value !== undefined) {\n\t\tthrow new Error(`Invalid ${settingName} setting: ${String(value)}`);\n\t}\n\treturn undefined;\n}\n\nexport type SettingsScope = \"global\" | \"project\";\n\nexport interface SettingsManagerCreateOptions {\n\tprojectTrusted?: boolean;\n}\n\nexport interface SettingsStorage {\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void;\n}\n\nexport interface SettingsError {\n\tscope: SettingsScope;\n\terror: Error;\n}\n\nexport class FileSettingsStorage implements SettingsStorage {\n\tprivate globalSettingsPath: string;\n\tprivate projectSettingsPath: string;\n\n\tconstructor(cwd: string, agentDir: string) {\n\t\tconst resolvedCwd = resolvePath(cwd);\n\t\tconst resolvedAgentDir = resolvePath(agentDir);\n\t\tthis.globalSettingsPath = join(resolvedAgentDir, \"settings.json\");\n\t\tthis.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, \"settings.json\");\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire settings lock\");\n\t}\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst path = scope === \"global\" ? this.globalSettingsPath : this.projectSettingsPath;\n\t\tconst dir = dirname(path);\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Only create directory and lock if file exists or we need to write\n\t\t\tconst fileExists = existsSync(path);\n\t\t\tif (fileExists) {\n\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t}\n\t\t\tconst current = fileExists ? readFileSync(path, \"utf-8\") : undefined;\n\t\t\tconst next = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\t// Only create directory when we actually need to write\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t\t}\n\t\t\t\tif (!release) {\n\t\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t\t}\n\t\t\t\twriteFileSync(path, next, \"utf-8\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemorySettingsStorage implements SettingsStorage {\n\tprivate global: string | undefined;\n\tprivate project: string | undefined;\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst current = scope === \"global\" ? this.global : this.project;\n\t\tconst next = fn(current);\n\t\tif (next !== undefined) {\n\t\t\tif (scope === \"global\") {\n\t\t\t\tthis.global = next;\n\t\t\t} else {\n\t\t\t\tthis.project = next;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class SettingsManager {\n\tprivate storage: SettingsStorage;\n\tprivate globalSettings: Settings;\n\tprivate projectSettings: Settings;\n\tprivate settings: Settings;\n\tprivate projectTrusted: boolean;\n\tprivate modifiedFields = new Set<keyof Settings>(); // Track global fields modified during session\n\tprivate modifiedNestedFields = new Map<keyof Settings, Set<string>>(); // Track global nested field modifications\n\tprivate modifiedProjectFields = new Set<keyof Settings>(); // Track project fields modified during session\n\tprivate modifiedProjectNestedFields = new Map<keyof Settings, Set<string>>(); // Track project nested field modifications\n\tprivate globalSettingsLoadError: Error | null = null; // Track if global settings file had parse errors\n\tprivate projectSettingsLoadError: Error | null = null; // Track if project settings file had parse errors\n\tprivate writeQueue: Promise<void> = Promise.resolve();\n\tprivate errors: SettingsError[];\n\n\tprivate constructor(\n\t\tstorage: SettingsStorage,\n\t\tinitialGlobal: Settings,\n\t\tinitialProject: Settings,\n\t\tglobalLoadError: Error | null = null,\n\t\tprojectLoadError: Error | null = null,\n\t\tinitialErrors: SettingsError[] = [],\n\t\tprojectTrusted = true,\n\t) {\n\t\tthis.storage = storage;\n\t\tthis.globalSettings = initialGlobal;\n\t\tthis.projectSettings = initialProject;\n\t\tthis.projectTrusted = projectTrusted;\n\t\tthis.globalSettingsLoadError = globalLoadError;\n\t\tthis.projectSettingsLoadError = projectLoadError;\n\t\tthis.errors = [...initialErrors];\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Create a SettingsManager that loads from files */\n\tstatic create(\n\t\tcwd: string,\n\t\tagentDir: string = getAgentDir(),\n\t\toptions: SettingsManagerCreateOptions = {},\n\t): SettingsManager {\n\t\tconst storage = new FileSettingsStorage(cwd, agentDir);\n\t\treturn SettingsManager.fromStorage(storage, options);\n\t}\n\n\t/** Create a SettingsManager from an arbitrary storage backend */\n\tstatic fromStorage(storage: SettingsStorage, options: SettingsManagerCreateOptions = {}): SettingsManager {\n\t\tconst projectTrusted = options.projectTrusted ?? true;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(storage, \"global\");\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(storage, \"project\", projectTrusted);\n\t\tconst initialErrors: SettingsError[] = [];\n\t\tif (globalLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"global\", error: globalLoad.error });\n\t\t}\n\t\tif (projectLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"project\", error: projectLoad.error });\n\t\t}\n\n\t\treturn new SettingsManager(\n\t\t\tstorage,\n\t\t\tglobalLoad.settings,\n\t\t\tprojectLoad.settings,\n\t\t\tglobalLoad.error,\n\t\t\tprojectLoad.error,\n\t\t\tinitialErrors,\n\t\t\tprojectTrusted,\n\t\t);\n\t}\n\n\t/** Create an in-memory SettingsManager (no file I/O) */\n\tstatic inMemory(settings: Partial<Settings> = {}, options: SettingsManagerCreateOptions = {}): SettingsManager {\n\t\tconst storage = new InMemorySettingsStorage();\n\t\tconst initialSettings = SettingsManager.migrateSettings(structuredClone(settings) as Record<string, unknown>);\n\t\tstorage.withLock(\"global\", () => JSON.stringify(initialSettings, null, 2));\n\t\treturn SettingsManager.fromStorage(storage, options);\n\t}\n\n\tprivate static loadFromStorage(storage: SettingsStorage, scope: SettingsScope, projectTrusted = true): Settings {\n\t\tif (scope === \"project\" && !projectTrusted) {\n\t\t\treturn {};\n\t\t}\n\n\t\tlet content: string | undefined;\n\t\tstorage.withLock(scope, (current) => {\n\t\t\tcontent = current;\n\t\t\treturn undefined;\n\t\t});\n\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\tconst settings = JSON.parse(content);\n\t\treturn SettingsManager.migrateSettings(settings);\n\t}\n\n\tprivate static tryLoadFromStorage(\n\t\tstorage: SettingsStorage,\n\t\tscope: SettingsScope,\n\t\tprojectTrusted = true,\n\t): { settings: Settings; error: Error | null } {\n\t\ttry {\n\t\t\treturn { settings: SettingsManager.loadFromStorage(storage, scope, projectTrusted), error: null };\n\t\t} catch (error) {\n\t\t\treturn { settings: {}, error: error as Error };\n\t\t}\n\t}\n\n\t/** Migrate old settings format to new format */\n\tprivate static migrateSettings(settings: Record<string, unknown>): Settings {\n\t\t// Migrate queueMode -> steeringMode\n\t\tif (\"queueMode\" in settings && !(\"steeringMode\" in settings)) {\n\t\t\tsettings.steeringMode = settings.queueMode;\n\t\t\tdelete settings.queueMode;\n\t\t}\n\n\t\t// Migrate legacy websockets boolean -> transport enum\n\t\tif (!(\"transport\" in settings) && typeof settings.websockets === \"boolean\") {\n\t\t\tsettings.transport = settings.websockets ? \"websocket\" : \"sse\";\n\t\t\tdelete settings.websockets;\n\t\t}\n\n\t\t// Migrate old skills object format to new array format\n\t\tif (\n\t\t\t\"skills\" in settings &&\n\t\t\ttypeof settings.skills === \"object\" &&\n\t\t\tsettings.skills !== null &&\n\t\t\t!Array.isArray(settings.skills)\n\t\t) {\n\t\t\tconst skillsSettings = settings.skills as {\n\t\t\t\tenableSkillCommands?: boolean;\n\t\t\t\tcustomDirectories?: unknown;\n\t\t\t};\n\t\t\tif (skillsSettings.enableSkillCommands !== undefined && settings.enableSkillCommands === undefined) {\n\t\t\t\tsettings.enableSkillCommands = skillsSettings.enableSkillCommands;\n\t\t\t}\n\t\t\tif (Array.isArray(skillsSettings.customDirectories) && skillsSettings.customDirectories.length > 0) {\n\t\t\t\tsettings.skills = skillsSettings.customDirectories;\n\t\t\t} else {\n\t\t\t\tdelete settings.skills;\n\t\t\t}\n\t\t}\n\n\t\t// Migrate retry.maxDelayMs -> retry.provider.maxRetryDelayMs\n\t\tif (\n\t\t\t\"retry\" in settings &&\n\t\t\ttypeof settings.retry === \"object\" &&\n\t\t\tsettings.retry !== null &&\n\t\t\t!Array.isArray(settings.retry)\n\t\t) {\n\t\t\tconst retrySettings = settings.retry as Record<string, unknown>;\n\t\t\tconst providerSettings =\n\t\t\t\ttypeof retrySettings.provider === \"object\" && retrySettings.provider !== null\n\t\t\t\t\t? (retrySettings.provider as Record<string, unknown>)\n\t\t\t\t\t: undefined;\n\t\t\tif (\n\t\t\t\ttypeof retrySettings.maxDelayMs === \"number\" &&\n\t\t\t\t(providerSettings?.maxRetryDelayMs === undefined || providerSettings?.maxRetryDelayMs === null)\n\t\t\t) {\n\t\t\t\tretrySettings.provider = {\n\t\t\t\t\t...(providerSettings ?? {}),\n\t\t\t\t\tmaxRetryDelayMs: retrySettings.maxDelayMs,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdelete retrySettings.maxDelayMs;\n\t\t}\n\n\t\treturn settings as Settings;\n\t}\n\n\tgetGlobalSettings(): Settings {\n\t\treturn structuredClone(this.globalSettings);\n\t}\n\n\tgetProjectSettings(): Settings {\n\t\treturn structuredClone(this.projectSettings);\n\t}\n\n\tisProjectTrusted(): boolean {\n\t\treturn this.projectTrusted;\n\t}\n\n\tsetProjectTrusted(trusted: boolean): void {\n\t\tif (this.projectTrusted === trusted) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.projectTrusted = trusted;\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tif (!trusted) {\n\t\t\tthis.projectSettings = {};\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t\t\treturn;\n\t\t}\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\", trusted);\n\t\tthis.projectSettings = projectLoad.settings;\n\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\tif (projectLoad.error) {\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.writeQueue;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(this.storage, \"global\");\n\t\tif (!globalLoad.error) {\n\t\t\tthis.globalSettings = globalLoad.settings;\n\t\t\tthis.globalSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.globalSettingsLoadError = globalLoad.error;\n\t\t\tthis.recordError(\"global\", globalLoad.error);\n\t\t}\n\n\t\tthis.modifiedFields.clear();\n\t\tthis.modifiedNestedFields.clear();\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\", this.projectTrusted);\n\t\tif (!projectLoad.error) {\n\t\t\tthis.projectSettings = projectLoad.settings;\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Apply additional overrides on top of current settings */\n\tapplyOverrides(overrides: Partial<Settings>): void {\n\t\tthis.settings = deepMergeSettings(this.settings, overrides);\n\t}\n\n\t/** Mark a global field as modified during this session */\n\tprivate markModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedNestedFields.has(field)) {\n\t\t\t\tthis.modifiedNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\t/** Mark a project field as modified during this session */\n\tprivate markProjectModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedProjectFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedProjectNestedFields.has(field)) {\n\t\t\t\tthis.modifiedProjectNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedProjectNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\tprivate assertProjectTrustedForWrite(): void {\n\t\tif (!this.projectTrusted) {\n\t\t\tthrow new Error(\"Project is not trusted; refusing to write project settings\");\n\t\t}\n\t}\n\n\tprivate recordError(scope: SettingsScope, error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push({ scope, error: normalizedError });\n\t}\n\n\tprivate clearModifiedScope(scope: SettingsScope): void {\n\t\tif (scope === \"global\") {\n\t\t\tthis.modifiedFields.clear();\n\t\t\tthis.modifiedNestedFields.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\t}\n\n\tprivate enqueueWrite(scope: SettingsScope, task: () => void): void {\n\t\tthis.writeQueue = this.writeQueue\n\t\t\t.then(() => {\n\t\t\t\tif (scope === \"project\") {\n\t\t\t\t\tthis.assertProjectTrustedForWrite();\n\t\t\t\t}\n\t\t\t\ttask();\n\t\t\t\tthis.clearModifiedScope(scope);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.recordError(scope, error);\n\t\t\t});\n\t}\n\n\tprivate cloneModifiedNestedFields(source: Map<keyof Settings, Set<string>>): Map<keyof Settings, Set<string>> {\n\t\tconst snapshot = new Map<keyof Settings, Set<string>>();\n\t\tfor (const [key, value] of source.entries()) {\n\t\t\tsnapshot.set(key, new Set(value));\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate persistScopedSettings(\n\t\tscope: SettingsScope,\n\t\tsnapshotSettings: Settings,\n\t\tmodifiedFields: Set<keyof Settings>,\n\t\tmodifiedNestedFields: Map<keyof Settings, Set<string>>,\n\t): void {\n\t\tthis.storage.withLock(scope, (current) => {\n\t\t\tconst currentFileSettings = current\n\t\t\t\t? SettingsManager.migrateSettings(JSON.parse(current) as Record<string, unknown>)\n\t\t\t\t: {};\n\t\t\tconst mergedSettings: Settings = { ...currentFileSettings };\n\t\t\tfor (const field of modifiedFields) {\n\t\t\t\tconst value = snapshotSettings[field];\n\t\t\t\tif (modifiedNestedFields.has(field) && typeof value === \"object\" && value !== null) {\n\t\t\t\t\tconst nestedModified = modifiedNestedFields.get(field)!;\n\t\t\t\t\tconst baseNested = (currentFileSettings[field] as Record<string, unknown>) ?? {};\n\t\t\t\t\tconst inMemoryNested = value as Record<string, unknown>;\n\t\t\t\t\tconst mergedNested = { ...baseNested };\n\t\t\t\t\tfor (const nestedKey of nestedModified) {\n\t\t\t\t\t\tmergedNested[nestedKey] = inMemoryNested[nestedKey];\n\t\t\t\t\t}\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = mergedNested;\n\t\t\t\t} else {\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn JSON.stringify(mergedSettings, null, 2);\n\t\t});\n\t}\n\n\tprivate save(): void {\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.globalSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotGlobalSettings = structuredClone(this.globalSettings);\n\t\tconst modifiedFields = new Set(this.modifiedFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);\n\n\t\tthis.enqueueWrite(\"global\", () => {\n\t\t\tthis.persistScopedSettings(\"global\", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate saveProjectSettings(settings: Settings): void {\n\t\tthis.assertProjectTrustedForWrite();\n\t\tthis.projectSettings = structuredClone(settings);\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.projectSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotProjectSettings = structuredClone(this.projectSettings);\n\t\tconst modifiedFields = new Set(this.modifiedProjectFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);\n\t\tthis.enqueueWrite(\"project\", () => {\n\t\t\tthis.persistScopedSettings(\"project\", snapshotProjectSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate updateProjectSettings(field: keyof Settings, update: (settings: Settings) => void): void {\n\t\tthis.assertProjectTrustedForWrite();\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tupdate(projectSettings);\n\t\tthis.markProjectModified(field);\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeQueue;\n\t}\n\n\tdrainErrors(): SettingsError[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\tgetSessionDir(): string | undefined {\n\t\tconst sessionDir = this.settings.sessionDir;\n\t\treturn sessionDir ? normalizePath(sessionDir) : sessionDir;\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\t/** lunr: cron fallback models (\"provider/modelId\"), tried in order after a gateway cron fire's default model fails. */\n\tgetCronFallbackModels(): string[] {\n\t\treturn this.settings.cronFallbackModels ?? [];\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tgetSteeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.steeringMode || \"one-at-a-time\";\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.steeringMode = mode;\n\t\tthis.markModified(\"steeringMode\");\n\t\tthis.save();\n\t}\n\n\tgetFollowUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.followUpMode || \"one-at-a-time\";\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.followUpMode = mode;\n\t\tthis.markModified(\"followUpMode\");\n\t\tthis.save();\n\t}\n\n\tgetThemeSetting(): string | undefined {\n\t\tconst value = this.settings.theme;\n\t\tif (typeof value === \"string\") return value;\n\t\treturn undefined;\n\t}\n\n\tgetTheme(): string | undefined {\n\t\tconst theme = this.getThemeSetting();\n\t\treturn theme?.includes(\"/\") ? undefined : theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.globalSettings.theme = theme;\n\t\tthis.markModified(\"theme\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): ThinkingLevel | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: ThinkingLevel): void {\n\t\tthis.globalSettings.defaultThinkingLevel = level;\n\t\tthis.markModified(\"defaultThinkingLevel\");\n\t\tthis.save();\n\t}\n\n\tgetTransport(): TransportSetting {\n\t\treturn this.settings.transport ?? \"auto\";\n\t}\n\n\tsetTransport(transport: TransportSetting): void {\n\t\tthis.globalSettings.transport = transport;\n\t\tthis.markModified(\"transport\");\n\t\tthis.save();\n\t}\n\n\tgetCacheRetention(): \"none\" | \"short\" | \"long\" | undefined {\n\t\treturn this.settings.cacheRetention;\n\t}\n\n\tsetCacheRetention(cacheRetention: \"none\" | \"short\" | \"long\"): void {\n\t\tthis.globalSettings.cacheRetention = cacheRetention;\n\t\tthis.markModified(\"cacheRetention\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.compaction) {\n\t\t\tthis.globalSettings.compaction = {};\n\t\t}\n\t\tthis.globalSettings.compaction.enabled = enabled;\n\t\tthis.markModified(\"compaction\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetBranchSummarySettings(): { reserveTokens: number; skipPrompt: boolean } {\n\t\treturn {\n\t\t\treserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,\n\t\t\tskipPrompt: this.settings.branchSummary?.skipPrompt ?? false,\n\t\t};\n\t}\n\n\tgetBranchSummarySkipPrompt(): boolean {\n\t\treturn this.settings.branchSummary?.skipPrompt ?? false;\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.retry) {\n\t\t\tthis.globalSettings.retry = {};\n\t\t}\n\t\tthis.globalSettings.retry.enabled = enabled;\n\t\tthis.markModified(\"retry\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHttpIdleTimeoutMs(): number {\n\t\treturn parseTimeoutSetting(this.settings.httpIdleTimeoutMs, \"httpIdleTimeoutMs\") ?? DEFAULT_HTTP_IDLE_TIMEOUT_MS;\n\t}\n\n\tsetHttpIdleTimeoutMs(timeoutMs: number): void {\n\t\tif (!Number.isFinite(timeoutMs) || timeoutMs < 0) {\n\t\t\tthrow new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`);\n\t\t}\n\t\tthis.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs);\n\t\tthis.markModified(\"httpIdleTimeoutMs\");\n\t\tthis.save();\n\t}\n\n\tgetProviderRetrySettings(): { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs: number } {\n\t\treturn {\n\t\t\ttimeoutMs: this.settings.retry?.provider?.timeoutMs,\n\t\t\tmaxRetries: this.settings.retry?.provider?.maxRetries,\n\t\t\tmaxRetryDelayMs: this.settings.retry?.provider?.maxRetryDelayMs ?? 60000,\n\t\t};\n\t}\n\n\tgetWebSocketConnectTimeoutMs(): number | undefined {\n\t\treturn parseTimeoutSetting(this.settings.websocketConnectTimeoutMs, \"websocketConnectTimeoutMs\");\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tgetThinkingCollapse(): boolean {\n\t\treturn this.settings.thinkingCollapse ?? true;\n\t}\n\n\tgetShowCacheMissNotices(): boolean {\n\t\treturn this.settings.showCacheMissNotices ?? false;\n\t}\n\n\tgetExternalEditorCommand(): string | undefined {\n\t\tconst configuredEditor = this.settings.externalEditor;\n\t\tif (typeof configuredEditor === \"string\" && configuredEditor.trim() !== \"\") {\n\t\t\treturn configuredEditor;\n\t\t}\n\t\tconst environmentEditor = process.env.VISUAL || process.env.EDITOR;\n\t\tif (environmentEditor) {\n\t\t\treturn environmentEditor;\n\t\t}\n\t\treturn process.platform === \"win32\" ? \"notepad\" : \"nano\";\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.globalSettings.hideThinkingBlock = hide;\n\t\tthis.markModified(\"hideThinkingBlock\");\n\t\tthis.save();\n\t}\n\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.globalSettings.thinkingCollapse = collapse;\n\t\tthis.markModified(\"thinkingCollapse\");\n\t\tthis.save();\n\t}\n\n\tsetShowCacheMissNotices(show: boolean): void {\n\t\tthis.globalSettings.showCacheMissNotices = show;\n\t\tthis.markModified(\"showCacheMissNotices\");\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\tconst shellPath = this.settings.shellPath;\n\t\treturn shellPath ? normalizePath(shellPath) : shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.globalSettings.shellPath = path;\n\t\tthis.markModified(\"shellPath\");\n\t\tthis.save();\n\t}\n\n\tgetQuietStartup(): boolean {\n\t\treturn this.settings.quietStartup ?? false;\n\t}\n\n\tsetQuietStartup(quiet: boolean): void {\n\t\tthis.globalSettings.quietStartup = quiet;\n\t\tthis.markModified(\"quietStartup\");\n\t\tthis.save();\n\t}\n\n\tgetSmoothStreaming(): boolean {\n\t\treturn this.settings.smoothStreaming ?? false;\n\t}\n\n\tsetSmoothStreaming(enabled: boolean): void {\n\t\tthis.globalSettings.smoothStreaming = enabled;\n\t\tthis.markModified(\"smoothStreaming\");\n\t\tthis.save();\n\t}\n\n\tgetSessionRetentionDays(): number {\n\t\tconst value = this.settings.sessionRetentionDays;\n\t\tif (typeof value === \"number\" && Number.isFinite(value) && value >= 0) {\n\t\t\treturn Math.floor(value);\n\t\t}\n\t\treturn 30;\n\t}\n\n\tsetSessionRetentionDays(days: number): void {\n\t\tthis.globalSettings.sessionRetentionDays = Math.max(0, Math.floor(days));\n\t\tthis.markModified(\"sessionRetentionDays\");\n\t\tthis.save();\n\t}\n\n\tgetMemoryCharCap(): number {\n\t\tconst value = this.settings.memoryCharCap;\n\t\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\t\treturn Math.min(MEMORY_CHAR_CAP_MAX, Math.max(MEMORY_CHAR_CAP_MIN, Math.floor(value)));\n\t\t}\n\t\treturn MEMORY_CHAR_CAP_DEFAULT;\n\t}\n\n\tsetMemoryCharCap(cap: number): void {\n\t\tthis.globalSettings.memoryCharCap = Math.min(MEMORY_CHAR_CAP_MAX, Math.max(MEMORY_CHAR_CAP_MIN, Math.floor(cap)));\n\t\tthis.markModified(\"memoryCharCap\");\n\t\tthis.save();\n\t}\n\n\tgetBehaviorPreset(): BehaviorPreset {\n\t\tconst value = this.settings.behaviorPreset;\n\t\treturn isBehaviorPreset(value) ? value : \"default\";\n\t}\n\n\tsetBehaviorPreset(preset: BehaviorPreset): void {\n\t\tthis.globalSettings.behaviorPreset = preset;\n\t\tthis.markModified(\"behaviorPreset\");\n\t\tthis.save();\n\t}\n\n\t// lunr: TUI customize settings getters/setters.\n\tgetGutterRail(): boolean {\n\t\treturn this.settings.gutterRail ?? true;\n\t}\n\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.globalSettings.gutterRail = enabled;\n\t\tthis.markModified(\"gutterRail\");\n\t\tthis.save();\n\t}\n\n\tgetPromptSymbol(): boolean {\n\t\treturn this.settings.promptSymbol ?? true;\n\t}\n\n\tsetPromptSymbol(enabled: boolean): void {\n\t\tthis.globalSettings.promptSymbol = enabled;\n\t\tthis.markModified(\"promptSymbol\");\n\t\tthis.save();\n\t}\n\n\t// lunr: footer element toggle getters/setters.\n\tgetFooterMcp(): boolean {\n\t\treturn this.settings.footerMcp ?? true;\n\t}\n\n\tsetFooterMcp(enabled: boolean): void {\n\t\tthis.globalSettings.footerMcp = enabled;\n\t\tthis.markModified(\"footerMcp\");\n\t\tthis.save();\n\t}\n\n\tgetFooterLsp(): boolean {\n\t\treturn this.settings.footerLsp ?? false;\n\t}\n\n\tsetFooterLsp(enabled: boolean): void {\n\t\tthis.globalSettings.footerLsp = enabled;\n\t\tthis.markModified(\"footerLsp\");\n\t\tthis.save();\n\t}\n\n\tgetFooterContext(): boolean {\n\t\treturn this.settings.footerContext ?? true;\n\t}\n\n\tsetFooterContext(enabled: boolean): void {\n\t\tthis.globalSettings.footerContext = enabled;\n\t\tthis.markModified(\"footerContext\");\n\t\tthis.save();\n\t}\n\n\tgetFooterTokens(): boolean {\n\t\treturn this.settings.footerTokens ?? true;\n\t}\n\n\tsetFooterTokens(enabled: boolean): void {\n\t\tthis.globalSettings.footerTokens = enabled;\n\t\tthis.markModified(\"footerTokens\");\n\t\tthis.save();\n\t}\n\n\tgetFooterTps(): boolean {\n\t\treturn this.settings.footerTps ?? true;\n\t}\n\n\tsetFooterTps(enabled: boolean): void {\n\t\tthis.globalSettings.footerTps = enabled;\n\t\tthis.markModified(\"footerTps\");\n\t\tthis.save();\n\t}\n\n\tgetFooterStatuses(): boolean {\n\t\treturn this.settings.footerStatuses ?? true;\n\t}\n\n\tsetFooterStatuses(enabled: boolean): void {\n\t\tthis.globalSettings.footerStatuses = enabled;\n\t\tthis.markModified(\"footerStatuses\");\n\t\tthis.save();\n\t}\n\n\tgetFooterGit(): boolean {\n\t\treturn this.settings.footerGit ?? true;\n\t}\n\n\tsetFooterGit(enabled: boolean): void {\n\t\tthis.globalSettings.footerGit = enabled;\n\t\tthis.markModified(\"footerGit\");\n\t\tthis.save();\n\t}\n\n\tgetFooterPlan(): boolean {\n\t\treturn this.settings.footerPlan ?? true;\n\t}\n\n\tsetFooterPlan(enabled: boolean): void {\n\t\tthis.globalSettings.footerPlan = enabled;\n\t\tthis.markModified(\"footerPlan\");\n\t\tthis.save();\n\t}\n\n\tgetFooterPlanBar(): boolean {\n\t\treturn this.settings.footerPlanBar ?? true;\n\t}\n\n\tsetFooterPlanBar(enabled: boolean): void {\n\t\tthis.globalSettings.footerPlanBar = enabled;\n\t\tthis.markModified(\"footerPlanBar\");\n\t\tthis.save();\n\t}\n\n\tgetPlanUsageWindow(): \"5h\" | \"weekly\" {\n\t\treturn this.settings.planUsageWindow === \"5h\" ? \"5h\" : \"weekly\";\n\t}\n\n\tsetPlanUsageWindow(window: \"5h\" | \"weekly\"): void {\n\t\tthis.globalSettings.planUsageWindow = window;\n\t\tthis.markModified(\"planUsageWindow\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultProjectTrust(): DefaultProjectTrust {\n\t\tconst value = this.globalSettings.defaultProjectTrust;\n\t\treturn value === \"always\" || value === \"never\" ? value : \"ask\";\n\t}\n\n\tsetDefaultProjectTrust(defaultProjectTrust: DefaultProjectTrust): void {\n\t\tthis.globalSettings.defaultProjectTrust = defaultProjectTrust;\n\t\tthis.markModified(\"defaultProjectTrust\");\n\t\tthis.save();\n\t}\n\n\t// lunr: default permission mode (startup default; per-session mode is in-memory)\n\tgetDefaultPermissionMode(): DefaultPermissionMode {\n\t\tconst value = this.settings.defaultPermissionMode;\n\t\treturn value === \"manual\" || value === \"yolo\" || value === \"plan\" || value === \"auto\" ? value : \"manual\";\n\t}\n\n\tsetDefaultPermissionMode(mode: DefaultPermissionMode): void {\n\t\tthis.globalSettings.defaultPermissionMode = mode;\n\t\tthis.markModified(\"defaultPermissionMode\");\n\t\tthis.save();\n\t}\n\n\t// lunr: rollback settings getters/setters\n\tgetRollbackEnabled(): boolean {\n\t\treturn this.settings.rollbackEnabled ?? false;\n\t}\n\n\tsetRollbackEnabled(enabled: boolean): void {\n\t\tthis.globalSettings.rollbackEnabled = enabled;\n\t\tthis.markModified(\"rollbackEnabled\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackTurns(): number {\n\t\tconst value = this.settings.rollbackTurns;\n\t\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\t\treturn Math.min(20, Math.max(1, Math.floor(value)));\n\t\t}\n\t\treturn 2;\n\t}\n\n\tsetRollbackTurns(turns: number): void {\n\t\tthis.globalSettings.rollbackTurns = Math.min(20, Math.max(1, Math.floor(turns)));\n\t\tthis.markModified(\"rollbackTurns\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackCapture(): RollbackCapture {\n\t\tconst value = this.settings.rollbackCapture;\n\t\treturn value === \"copies\" || value === \"shadow-git\" || value === \"hybrid\" ? value : \"copies\";\n\t}\n\n\tsetRollbackCapture(mode: RollbackCapture): void {\n\t\tthis.globalSettings.rollbackCapture = mode;\n\t\tthis.markModified(\"rollbackCapture\");\n\t\tthis.save();\n\t}\n\n\tgetRollbackScope(): RollbackScope {\n\t\tconst value = this.settings.rollbackScope;\n\t\treturn value === \"tools\" || value === \"tree\" ? value : \"tools\";\n\t}\n\n\tsetRollbackScope(scope: RollbackScope): void {\n\t\tthis.globalSettings.rollbackScope = scope;\n\t\tthis.markModified(\"rollbackScope\");\n\t\tthis.save();\n\t}\n\n\t// lunr: multi-subscription auto-management toggle\n\tgetAutoManageSubscriptions(): boolean {\n\t\treturn this.settings.autoManageSubscriptions ?? false;\n\t}\n\n\tsetAutoManageSubscriptions(enabled: boolean): void {\n\t\tthis.globalSettings.autoManageSubscriptions = enabled;\n\t\tthis.markModified(\"autoManageSubscriptions\");\n\t\tthis.save();\n\t}\n\n\tgetShellCommandPrefix(): string | undefined {\n\t\treturn this.settings.shellCommandPrefix;\n\t}\n\n\tsetShellCommandPrefix(prefix: string | undefined): void {\n\t\tthis.globalSettings.shellCommandPrefix = prefix;\n\t\tthis.markModified(\"shellCommandPrefix\");\n\t\tthis.save();\n\t}\n\n\tgetNpmCommand(): string[] | undefined {\n\t\treturn this.settings.npmCommand ? [...this.settings.npmCommand] : undefined;\n\t}\n\n\tsetNpmCommand(command: string[] | undefined): void {\n\t\tthis.globalSettings.npmCommand = command ? [...command] : undefined;\n\t\tthis.markModified(\"npmCommand\");\n\t\tthis.save();\n\t}\n\n\tgetEnableAnalytics(): boolean {\n\t\treturn this.settings.enableAnalytics ?? false;\n\t}\n\n\tgetTrackingId(): string | undefined {\n\t\treturn this.settings.trackingId;\n\t}\n\n\t/** Set the analytics opt-in preference; generates a tracking identifier on first opt-in */\n\tsetEnableAnalytics(enabled: boolean): void {\n\t\tthis.globalSettings.enableAnalytics = enabled;\n\t\tthis.markModified(\"enableAnalytics\");\n\t\tif (enabled && !this.globalSettings.trackingId) {\n\t\t\tthis.globalSettings.trackingId = randomUUID();\n\t\t\tthis.markModified(\"trackingId\");\n\t\t}\n\t\tthis.save();\n\t}\n\n\tgetPackages(): PackageSource[] {\n\t\treturn [...(this.settings.packages ?? [])];\n\t}\n\n\tsetPackages(packages: PackageSource[]): void {\n\t\tthis.globalSettings.packages = packages;\n\t\tthis.markModified(\"packages\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPackages(packages: PackageSource[]): void {\n\t\tthis.updateProjectSettings(\"packages\", (settings) => {\n\t\t\tsettings.packages = packages;\n\t\t});\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn [...(this.settings.extensions ?? [])];\n\t}\n\n\tsetExtensionPaths(paths: string[]): void {\n\t\tthis.globalSettings.extensions = paths;\n\t\tthis.markModified(\"extensions\");\n\t\tthis.save();\n\t}\n\n\tsetProjectExtensionPaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"extensions\", (settings) => {\n\t\t\tsettings.extensions = paths;\n\t\t});\n\t}\n\n\tgetSkillPaths(): string[] {\n\t\treturn [...(this.settings.skills ?? [])];\n\t}\n\n\tsetSkillPaths(paths: string[]): void {\n\t\tthis.globalSettings.skills = paths;\n\t\tthis.markModified(\"skills\");\n\t\tthis.save();\n\t}\n\n\tsetProjectSkillPaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"skills\", (settings) => {\n\t\t\tsettings.skills = paths;\n\t\t});\n\t}\n\n\tgetPromptTemplatePaths(): string[] {\n\t\treturn [...(this.settings.prompts ?? [])];\n\t}\n\n\tsetPromptTemplatePaths(paths: string[]): void {\n\t\tthis.globalSettings.prompts = paths;\n\t\tthis.markModified(\"prompts\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPromptTemplatePaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"prompts\", (settings) => {\n\t\t\tsettings.prompts = paths;\n\t\t});\n\t}\n\n\tgetThemePaths(): string[] {\n\t\treturn [...(this.settings.themes ?? [])];\n\t}\n\n\tsetThemePaths(paths: string[]): void {\n\t\tthis.globalSettings.themes = paths;\n\t\tthis.markModified(\"themes\");\n\t\tthis.save();\n\t}\n\n\tsetProjectThemePaths(paths: string[]): void {\n\t\tthis.updateProjectSettings(\"themes\", (settings) => {\n\t\t\tsettings.themes = paths;\n\t\t});\n\t}\n\n\tgetEnableSkillCommands(): boolean {\n\t\treturn this.settings.enableSkillCommands ?? true;\n\t}\n\n\tsetEnableSkillCommands(enabled: boolean): void {\n\t\tthis.globalSettings.enableSkillCommands = enabled;\n\t\tthis.markModified(\"enableSkillCommands\");\n\t\tthis.save();\n\t}\n\n\tgetThinkingBudgets(): ThinkingBudgetsSettings | undefined {\n\t\treturn this.settings.thinkingBudgets;\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showImages = show;\n\t\tthis.markModified(\"terminal\", \"showImages\");\n\t\tthis.save();\n\t}\n\n\tgetImageWidthCells(): number {\n\t\tconst width = this.settings.terminal?.imageWidthCells;\n\t\tif (typeof width !== \"number\" || !Number.isFinite(width)) {\n\t\t\treturn 60;\n\t\t}\n\t\treturn Math.max(1, Math.floor(width));\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.markModified(\"terminal\", \"imageWidthCells\");\n\t\tthis.save();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\t// Settings takes precedence, then env var, then default false\n\t\tif (this.settings.terminal?.clearOnShrink !== undefined) {\n\t\t\treturn this.settings.terminal.clearOnShrink;\n\t\t}\n\t\treturn process.env.PI_CLEAR_ON_SHRINK === \"1\";\n\t}\n\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.clearOnShrink = enabled;\n\t\tthis.markModified(\"terminal\", \"clearOnShrink\");\n\t\tthis.save();\n\t}\n\n\tgetShowTerminalProgress(): boolean {\n\t\treturn this.settings.terminal?.showTerminalProgress ?? false;\n\t}\n\n\tsetShowTerminalProgress(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showTerminalProgress = enabled;\n\t\tthis.markModified(\"terminal\", \"showTerminalProgress\");\n\t\tthis.save();\n\t}\n\n\tgetImageAutoResize(): boolean {\n\t\treturn this.settings.images?.autoResize ?? true;\n\t}\n\n\tsetImageAutoResize(enabled: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.autoResize = enabled;\n\t\tthis.markModified(\"images\", \"autoResize\");\n\t\tthis.save();\n\t}\n\n\tgetBlockImages(): boolean {\n\t\treturn this.settings.images?.blockImages ?? false;\n\t}\n\n\tsetBlockImages(blocked: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.blockImages = blocked;\n\t\tthis.markModified(\"images\", \"blockImages\");\n\t\tthis.save();\n\t}\n\n\tgetEnabledModels(): string[] | undefined {\n\t\treturn this.settings.enabledModels;\n\t}\n\n\tsetEnabledModels(patterns: string[] | undefined): void {\n\t\tthis.globalSettings.enabledModels = patterns;\n\t\tthis.markModified(\"enabledModels\");\n\t\tthis.save();\n\t}\n\n\tgetDoubleEscapeAction(): \"fork\" | \"tree\" | \"none\" {\n\t\treturn this.settings.doubleEscapeAction ?? \"tree\";\n\t}\n\n\tsetDoubleEscapeAction(action: \"fork\" | \"tree\" | \"none\"): void {\n\t\tthis.globalSettings.doubleEscapeAction = action;\n\t\tthis.markModified(\"doubleEscapeAction\");\n\t\tthis.save();\n\t}\n\n\tgetTreeFilterMode(): \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\" {\n\t\tconst mode = this.settings.treeFilterMode;\n\t\tconst valid = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n\t\treturn mode && valid.includes(mode) ? mode : \"default\";\n\t}\n\n\tsetTreeFilterMode(mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"): void {\n\t\tthis.globalSettings.treeFilterMode = mode;\n\t\tthis.markModified(\"treeFilterMode\");\n\t\tthis.save();\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === \"1\";\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tthis.globalSettings.showHardwareCursor = enabled;\n\t\tthis.markModified(\"showHardwareCursor\");\n\t\tthis.save();\n\t}\n\n\tgetEditorPaddingX(): number {\n\t\treturn this.settings.editorPaddingX ?? 0;\n\t}\n\n\tsetEditorPaddingX(padding: number): void {\n\t\tthis.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));\n\t\tthis.markModified(\"editorPaddingX\");\n\t\tthis.save();\n\t}\n\n\tgetOutputPad(): 0 | 1 {\n\t\treturn this.settings.outputPad === 0 ? 0 : 1;\n\t}\n\n\tsetOutputPad(padding: 0 | 1): void {\n\t\tthis.globalSettings.outputPad = padding;\n\t\tthis.markModified(\"outputPad\");\n\t\tthis.save();\n\t}\n\n\tgetAutocompleteMaxVisible(): number {\n\t\treturn this.settings.autocompleteMaxVisible ?? 5;\n\t}\n\n\tsetAutocompleteMaxVisible(maxVisible: number): void {\n\t\tthis.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));\n\t\tthis.markModified(\"autocompleteMaxVisible\");\n\t\tthis.save();\n\t}\n\n\tgetCodeBlockIndent(): string {\n\t\treturn this.settings.markdown?.codeBlockIndent ?? \" \";\n\t}\n\n\tgetModelTiers(): ModelTiersSettings {\n\t\treturn { ...(this.settings.modelTiers ?? {}) };\n\t}\n\n\tgetModelTiersEnabled(): boolean {\n\t\treturn this.settings.modelTiers?.enabled ?? false;\n\t}\n\n\tsetModelTiersEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tthis.globalSettings.modelTiers.enabled = enabled;\n\t\tthis.markModified(\"modelTiers\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetTierModel(tier: ModelTierName): string | undefined {\n\t\treturn this.settings.modelTiers?.[tier];\n\t}\n\n\tsetTierModel(tier: ModelTierName, model: string): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tthis.globalSettings.modelTiers[tier] = model;\n\t\tthis.markModified(\"modelTiers\", tier);\n\t\tthis.save();\n\t}\n\n\tgetTierThinking(tier: ModelTierName): ThinkingLevel | undefined {\n\t\treturn this.settings.modelTiers?.[tierThinkingKey(tier)];\n\t}\n\n\tsetTierThinking(tier: ModelTierName, level: ThinkingLevel | undefined): void {\n\t\tif (!this.globalSettings.modelTiers) {\n\t\t\tthis.globalSettings.modelTiers = {};\n\t\t}\n\t\tconst key = tierThinkingKey(tier);\n\t\tif (level === undefined) {\n\t\t\tdelete this.globalSettings.modelTiers[key];\n\t\t} else {\n\t\t\tthis.globalSettings.modelTiers[key] = level;\n\t\t}\n\t\tthis.markModified(\"modelTiers\", key);\n\t\tthis.save();\n\t}\n}\n\nfunction tierThinkingKey(tier: ModelTierName): \"lightThinking\" | \"standardThinking\" | \"heavyThinking\" {\n\tif (tier === \"light\") return \"lightThinking\";\n\tif (tier === \"standard\") return \"standardThinking\";\n\treturn \"heavyThinking\";\n}\n"]}
|
|
@@ -727,6 +727,14 @@ export class SettingsManager {
|
|
|
727
727
|
this.markModified("footerTokens");
|
|
728
728
|
this.save();
|
|
729
729
|
}
|
|
730
|
+
getFooterTps() {
|
|
731
|
+
return this.settings.footerTps ?? true;
|
|
732
|
+
}
|
|
733
|
+
setFooterTps(enabled) {
|
|
734
|
+
this.globalSettings.footerTps = enabled;
|
|
735
|
+
this.markModified("footerTps");
|
|
736
|
+
this.save();
|
|
737
|
+
}
|
|
730
738
|
getFooterStatuses() {
|
|
731
739
|
return this.settings.footerStatuses ?? true;
|
|
732
740
|
}
|