@ashx-j/lunr 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +211 -236
  3. package/dist/builtin-extensions/ashxj-tui.d.ts +3 -0
  4. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.js +28 -11
  6. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +0 -2
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/lunr-cron.d.ts +1 -1
  11. package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
  12. package/dist/builtin-extensions/lunr-cron.js +7 -2
  13. package/dist/builtin-extensions/lunr-cron.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js +3 -3
  16. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts +0 -2
  18. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js +1 -23
  20. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +7 -8
  23. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +10 -18
  27. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +12 -9
  29. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +38 -34
  31. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  32. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
  33. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +32 -47
  35. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts +2 -2
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +7 -10
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +90 -109
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +3 -2
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +37 -50
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +1 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts +4 -0
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js +5 -5
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +31 -13
  56. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts +2 -2
  58. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts +4 -3
  61. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +48 -20
  63. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts +2 -2
  65. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +90 -64
  67. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +6 -8
  69. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +269 -167
  71. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  72. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +24 -33
  75. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
  76. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +25 -0
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -0
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +51 -0
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -0
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.d.ts.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js +20 -3
  82. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js.map +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +4 -1
  84. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  86. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +5 -0
  87. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  88. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +9 -3
  89. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  90. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +2 -2
  92. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts +2 -2
  94. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts.map +1 -1
  95. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js +20 -17
  96. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js.map +1 -1
  97. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +70 -0
  98. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -0
  99. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +153 -0
  100. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -0
  101. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts +13 -8
  102. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts.map +1 -1
  103. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js +20 -51
  104. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js.map +1 -1
  105. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +82 -21
  106. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  107. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +10 -2
  108. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  109. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +2 -2
  110. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
  111. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +20 -32
  112. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
  113. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -1
  114. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  115. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +23 -449
  116. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  117. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
  118. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  119. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +13 -11
  120. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  121. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts +2 -1
  122. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts.map +1 -1
  123. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js +18 -17
  124. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js.map +1 -1
  125. package/dist/builtin-extensions/simple-pi-memory.d.ts +2 -2
  126. package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
  127. package/dist/builtin-extensions/simple-pi-memory.js +41 -17
  128. package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
  129. package/dist/catalog/models.json +1 -1
  130. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  131. package/dist/catalog/providers/azure-openai-responses.json +1 -1
  132. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  133. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  134. package/dist/catalog/providers/fireworks.json +1 -1
  135. package/dist/catalog/providers/github-copilot.json +1 -1
  136. package/dist/catalog/providers/huggingface.json +1 -1
  137. package/dist/catalog/providers/minimax-cn.json +1 -1
  138. package/dist/catalog/providers/minimax.json +1 -1
  139. package/dist/catalog/providers/mistral.json +1 -1
  140. package/dist/catalog/providers/nvidia.json +1 -1
  141. package/dist/catalog/providers/openai.json +1 -1
  142. package/dist/catalog/providers/opencode-go.json +1 -1
  143. package/dist/catalog/providers/opencode.json +1 -1
  144. package/dist/catalog/providers/openrouter.json +1 -1
  145. package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
  146. package/dist/catalog/providers/qwen-cloud.json +1 -1
  147. package/dist/catalog/providers/qwen-token-plan-cn.json +1 -1
  148. package/dist/catalog/providers/qwen-token-plan.json +1 -1
  149. package/dist/catalog/providers/together.json +1 -1
  150. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  151. package/dist/catalog/providers/xai.json +1 -1
  152. package/dist/catalog/providers/zai-coding-cn.json +1 -1
  153. package/dist/catalog/providers/zai.json +1 -1
  154. package/dist/catalog/publication.json +3 -3
  155. package/dist/core/agent-session.d.ts +7 -1
  156. package/dist/core/agent-session.d.ts.map +1 -1
  157. package/dist/core/agent-session.js +36 -6
  158. package/dist/core/agent-session.js.map +1 -1
  159. package/dist/core/customize.d.ts +2 -0
  160. package/dist/core/customize.d.ts.map +1 -1
  161. package/dist/core/customize.js +6 -0
  162. package/dist/core/customize.js.map +1 -1
  163. package/dist/core/memory-cap.d.ts +4 -8
  164. package/dist/core/memory-cap.d.ts.map +1 -1
  165. package/dist/core/memory-cap.js +8 -8
  166. package/dist/core/memory-cap.js.map +1 -1
  167. package/dist/core/models-store.d.ts.map +1 -1
  168. package/dist/core/models-store.js +13 -1
  169. package/dist/core/models-store.js.map +1 -1
  170. package/dist/core/permissions.d.ts +11 -0
  171. package/dist/core/permissions.d.ts.map +1 -1
  172. package/dist/core/permissions.js +90 -34
  173. package/dist/core/permissions.js.map +1 -1
  174. package/dist/core/plan-mode.d.ts.map +1 -1
  175. package/dist/core/plan-mode.js +50 -16
  176. package/dist/core/plan-mode.js.map +1 -1
  177. package/dist/core/rollback.d.ts.map +1 -1
  178. package/dist/core/rollback.js +1 -1
  179. package/dist/core/rollback.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +9 -5
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js +24 -10
  183. package/dist/core/settings-manager.js.map +1 -1
  184. package/dist/core/slash-commands.d.ts.map +1 -1
  185. package/dist/core/slash-commands.js +1 -5
  186. package/dist/core/slash-commands.js.map +1 -1
  187. package/dist/core/subagent-permission-inherit.d.ts +34 -22
  188. package/dist/core/subagent-permission-inherit.d.ts.map +1 -1
  189. package/dist/core/subagent-permission-inherit.js +37 -80
  190. package/dist/core/subagent-permission-inherit.js.map +1 -1
  191. package/dist/core/swarm.d.ts +17 -4
  192. package/dist/core/swarm.d.ts.map +1 -1
  193. package/dist/core/swarm.js +48 -10
  194. package/dist/core/swarm.js.map +1 -1
  195. package/dist/core/system-prompt.d.ts +6 -4
  196. package/dist/core/system-prompt.d.ts.map +1 -1
  197. package/dist/core/system-prompt.js +38 -48
  198. package/dist/core/system-prompt.js.map +1 -1
  199. package/dist/core/usage-adapters/openai-codex.d.ts +1 -1
  200. package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
  201. package/dist/core/usage-adapters/openai-codex.js +22 -17
  202. package/dist/core/usage-adapters/openai-codex.js.map +1 -1
  203. package/dist/core/usage-service.d.ts +10 -1
  204. package/dist/core/usage-service.d.ts.map +1 -1
  205. package/dist/core/usage-service.js +17 -6
  206. package/dist/core/usage-service.js.map +1 -1
  207. package/dist/gateway/agent-bridge.d.ts +1 -1
  208. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  209. package/dist/gateway/agent-bridge.js +12 -5
  210. package/dist/gateway/agent-bridge.js.map +1 -1
  211. package/dist/gateway/commands.d.ts.map +1 -1
  212. package/dist/gateway/commands.js +2 -1
  213. package/dist/gateway/commands.js.map +1 -1
  214. package/dist/gateway/cron.d.ts +4 -1
  215. package/dist/gateway/cron.d.ts.map +1 -1
  216. package/dist/gateway/cron.js +18 -12
  217. package/dist/gateway/cron.js.map +1 -1
  218. package/dist/gateway/router.d.ts +1 -1
  219. package/dist/gateway/router.d.ts.map +1 -1
  220. package/dist/gateway/router.js.map +1 -1
  221. package/dist/main.d.ts.map +1 -1
  222. package/dist/main.js +0 -5
  223. package/dist/main.js.map +1 -1
  224. package/dist/migrations.d.ts +2 -0
  225. package/dist/migrations.d.ts.map +1 -1
  226. package/dist/migrations.js +21 -0
  227. package/dist/migrations.js.map +1 -1
  228. package/dist/modes/interactive/components/settings-selector.d.ts +4 -3
  229. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/settings-selector.js +21 -77
  231. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  232. package/dist/modes/interactive/components/usage-view.d.ts +1 -1
  233. package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/usage-view.js +7 -4
  235. package/dist/modes/interactive/components/usage-view.js.map +1 -1
  236. package/dist/modes/interactive/interactive-mode.d.ts +1 -2
  237. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  238. package/dist/modes/interactive/interactive-mode.js +39 -93
  239. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  240. package/docs/compaction.md +23 -23
  241. package/docs/containerization.md +24 -24
  242. package/docs/custom-provider.md +18 -18
  243. package/docs/development.md +16 -15
  244. package/docs/docs.json +6 -2
  245. package/docs/extensions.md +82 -80
  246. package/docs/features.md +102 -0
  247. package/docs/index.md +25 -19
  248. package/docs/json.md +7 -7
  249. package/docs/keybindings.md +4 -4
  250. package/docs/models.md +2 -2
  251. package/docs/packages.md +38 -42
  252. package/docs/prompt-templates.md +4 -4
  253. package/docs/providers.md +22 -10
  254. package/docs/quickstart.md +81 -46
  255. package/docs/rpc.md +7 -13
  256. package/docs/sdk.md +43 -41
  257. package/docs/security.md +18 -18
  258. package/docs/session-format.md +9 -9
  259. package/docs/sessions.md +13 -12
  260. package/docs/settings.md +62 -24
  261. package/docs/shell-aliases.md +2 -2
  262. package/docs/skills.md +11 -11
  263. package/docs/terminal-setup.md +5 -5
  264. package/docs/termux.md +7 -7
  265. package/docs/themes.md +12 -14
  266. package/docs/tmux.md +4 -4
  267. package/docs/tui.md +23 -23
  268. package/docs/usage.md +112 -87
  269. package/docs/windows.md +10 -2
  270. package/examples/README.md +3 -1
  271. package/examples/extensions/README.md +6 -6
  272. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  273. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  274. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  275. package/examples/extensions/doom-overlay/README.md +2 -2
  276. package/examples/extensions/gondolin/package-lock.json +2 -2
  277. package/examples/extensions/gondolin/package.json +1 -1
  278. package/examples/extensions/plan-mode/README.md +3 -1
  279. package/examples/extensions/sandbox/package-lock.json +2 -2
  280. package/examples/extensions/sandbox/package.json +1 -1
  281. package/examples/extensions/subagent/README.md +13 -11
  282. package/examples/extensions/todo.ts +2 -1
  283. package/examples/extensions/with-deps/package-lock.json +2 -2
  284. package/examples/extensions/with-deps/package.json +1 -1
  285. package/examples/sdk/README.md +9 -5
  286. package/package.json +6 -7
  287. package/dist/builtin-extensions/lunr-behavior.d.ts +0 -44
  288. package/dist/builtin-extensions/lunr-behavior.d.ts.map +0 -1
  289. package/dist/builtin-extensions/lunr-behavior.js +0 -213
  290. package/dist/builtin-extensions/lunr-behavior.js.map +0 -1
  291. package/dist/builtin-extensions/pi-subagents/agents/context-builder.md +0 -46
  292. package/dist/builtin-extensions/pi-subagents/agents/deep-researcher.md +0 -36
  293. package/dist/builtin-extensions/pi-subagents/agents/delegate.md +0 -12
  294. package/dist/builtin-extensions/pi-subagents/agents/oracle.md +0 -73
  295. package/dist/builtin-extensions/pi-subagents/agents/planner.md +0 -55
  296. package/dist/builtin-extensions/pi-subagents/agents/research-writer.md +0 -37
  297. package/dist/builtin-extensions/pi-subagents/agents/researcher.md +0 -52
  298. package/dist/builtin-extensions/pi-subagents/agents/reviewer.md +0 -79
  299. package/dist/builtin-extensions/pi-subagents/agents/scout.md +0 -50
  300. package/dist/builtin-extensions/pi-subagents/agents/worker.md +0 -55
  301. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts +0 -20
  302. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +0 -1
  303. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +0 -1273
  304. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +0 -1
  305. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts +0 -49
  306. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts.map +0 -1
  307. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js +0 -252
  308. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js.map +0 -1
  309. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts +0 -3
  310. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts.map +0 -1
  311. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js +0 -6
  312. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js.map +0 -1
  313. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts +0 -3
  314. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts.map +0 -1
  315. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js +0 -23
  316. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js.map +0 -1
  317. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts +0 -8
  318. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts.map +0 -1
  319. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js +0 -143
  320. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js.map +0 -1
  321. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts +0 -176
  322. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts.map +0 -1
  323. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js +0 -1326
  324. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js.map +0 -1
  325. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts +0 -7
  326. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts.map +0 -1
  327. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js +0 -307
  328. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js.map +0 -1
  329. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts +0 -8
  330. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts.map +0 -1
  331. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js +0 -30
  332. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js.map +0 -1
  333. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts +0 -35
  334. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts.map +0 -1
  335. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js +0 -151
  336. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js.map +0 -1
  337. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts +0 -131
  338. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts.map +0 -1
  339. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js +0 -491
  340. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js.map +0 -1
  341. package/dist/core/behavior-preset.d.ts +0 -60
  342. package/dist/core/behavior-preset.d.ts.map +0 -1
  343. package/dist/core/behavior-preset.js +0 -257
  344. package/dist/core/behavior-preset.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/core/rollback.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: rollback service — pre-edit file snapshots for /rollback.\n *\n * Captures pre-write file content before edit/write tools mutate files, keyed\n * by user-turn and session id. `/rollback` restores the newest non-empty turn's\n * snapshots and then rewinds the conversation via a session fork (persistent,\n * unlike /undo and /edit, which stay in the same session file).\n *\n * Capture modes (setting `rollbackCapture`):\n * - copies: snapshot pre-write content; restore = write back + delete files\n * the agent created with edit/write.\n * - hybrid: copies + also delete files created OUTSIDE tools (tree scope).\n * - shadow-git: hidden git repo (deferred — behaves like copies).\n *\n * Scope (setting `rollbackScope`):\n * - tools: only edit/write tool changes.\n * - tree: also catches bash side-effects. Baseline = `git status --porcelain`\n * at turn START (pre-change content); at agent_end, files that are\n * dirty but were clean/absent at baseline are captured too (untracked\n * = created during the turn; tracked = restored from HEAD). Skipped\n * with a one-time warning when cwd is not a repo.\n *\n * Snapshots persist on disk under `~/.lunr/rollback/<session-id>/<turn-n>/`\n * (manifest.json + sha1-named .snap payloads) and are reloaded on init, so\n * rollback survives restarts. Turn granularity = one user message → agent_end.\n * Retention prunes beyond `rollbackTurns` turns.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n\tcpSync,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\trmSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, normalize, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\nexport interface Snapshot {\n\texisted: boolean;\n\tcontent?: Buffer;\n\tcreatedByTool: boolean;\n}\n\ninterface TurnSnapshots {\n\tturnIndex: number;\n\tcwd?: string;\n\tfiles: Map<string, Snapshot>;\n}\n\ninterface ManifestEntry {\n\texisted: boolean;\n\tcreatedByTool: boolean;\n\tsnapFile?: string;\n}\n\ninterface TurnManifest {\n\tcwd?: string;\n\tfiles: Record<string, ManifestEntry>;\n}\n\nconst ROLLBACK_BASE = join(homedir(), \".lunr\", \"rollback\");\n\ninterface RollbackContext {\n\tsessionId: string;\n\tsettingsManager: SettingsManager | undefined;\n\tsessionForceEnabled: boolean;\n\tturns: TurnSnapshots[];\n\tcurrentTurnIndex: number;\n\trepoWarningShown: boolean;\n\texternalModWarningShown: boolean;\n\t/** Last cwd seen by beginTurn — reused by auto-started turns (mid-turn enable). */\n\tlastCwd?: string;\n}\n\nconst contexts = new Map<string, RollbackContext>();\nlet lastSessionId: string | undefined;\nlet globalSettingsManager: SettingsManager | undefined;\nlet warningHandler: ((message: string) => void) | undefined;\n\n/** Register a sink for one-time user-facing warnings (e.g. tree scope outside a git repo). */\nexport function setRollbackWarningHandler(handler: ((message: string) => void) | undefined): void {\n\twarningHandler = handler;\n}\n\nfunction createContext(sessionId: string): RollbackContext {\n\treturn {\n\t\tsessionId,\n\t\tsettingsManager: globalSettingsManager,\n\t\tsessionForceEnabled: false,\n\t\tturns: [],\n\t\tcurrentTurnIndex: -1,\n\t\trepoWarningShown: false,\n\t\texternalModWarningShown: false,\n\t};\n}\n\nfunction getContext(sessionId?: string): RollbackContext {\n\tconst sid = sessionId ?? lastSessionId ?? \"default\";\n\tlet ctx = contexts.get(sid);\n\tif (!ctx) {\n\t\tctx = createContext(sid);\n\t\tcontexts.set(sid, ctx);\n\t}\n\treturn ctx;\n}\n\nexport function initRollback(sm: SettingsManager, sid: string): void {\n\tglobalSettingsManager = sm;\n\tlastSessionId = sid;\n\tcontexts.set(sid, createContext(sid));\n\tconst ctx = contexts.get(sid)!;\n\tctx.settingsManager = sm;\n\tloadPersistedTurns(ctx);\n}\n\nexport function isRollbackEnabled(sessionId?: string): boolean {\n\tconst ctx = getContext(sessionId);\n\treturn (ctx.settingsManager?.getRollbackEnabled() ?? false) || ctx.sessionForceEnabled;\n}\n\n/** Whether rollback is force-enabled for this session (e.g. by auto permission mode). */\nexport function isRollbackSessionForceEnabled(sessionId?: string): boolean {\n\treturn getContext(sessionId).sessionForceEnabled;\n}\n\nexport function enableRollbackForSession(sessionId?: string): void {\n\tgetContext(sessionId).sessionForceEnabled = true;\n}\n\nexport function disableRollbackForSession(sessionId?: string): void {\n\tgetContext(sessionId).sessionForceEnabled = false;\n}\n\nfunction pruneTurns(ctx: RollbackContext): void {\n\tconst maxTurns = ctx.settingsManager?.getRollbackTurns() ?? 2;\n\twhile (ctx.turns.length > maxTurns) {\n\t\tconst old = ctx.turns.shift();\n\t\tif (old) cleanupTurnFiles(ctx, old);\n\t}\n}\n\n/**\n * Begin a new turn: push a new snapshot map, prune old turns beyond retention.\n * When `cwd` is given and scope is `tree`, also capture the pre-turn baseline\n * (content of all currently dirty/untracked files) so bash side-effects can be\n * restored later.\n */\nexport function beginTurn(cwd?: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\t// lunr: remember the session cwd so auto-started turns (mid-turn enable) can\n\t// still be constrained by the allowed-roots check.\n\tif (cwd) ctx.lastCwd = cwd;\n\tctx.currentTurnIndex++;\n\tconst turn: TurnSnapshots = { turnIndex: ctx.currentTurnIndex, cwd, files: new Map() };\n\tctx.turns.push(turn);\n\tpruneTurns(ctx);\n\tif (cwd && ctx.settingsManager?.getRollbackScope() === \"tree\") {\n\t\tcaptureTreeBaseline(ctx, cwd);\n\t}\n}\n\n/** Capture pre-write content for a file path, recording under the current turn. */\nexport function rollbackSnapshotBeforeWrite(absPath: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\t// lunr: auto-started turn inherits the last known cwd so restores stay\n\t// root-checked; without any recorded cwd the allowed roots still apply.\n\tif (ctx.currentTurnIndex < 0 || ctx.turns.length === 0) beginTurn(ctx.lastCwd, ctx.sessionId);\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\tif (turn.files.has(absPath)) return; // already snapshotted this turn\n\n\ttry {\n\t\tconst existed = existsSync(absPath);\n\t\tlet content: Buffer | undefined;\n\t\tif (existed) {\n\t\t\tcontent = readFileSync(absPath);\n\t\t}\n\t\tturn.files.set(absPath, {\n\t\t\texisted,\n\t\t\tcontent,\n\t\t\tcreatedByTool: true,\n\t\t});\n\t\tpersistSnapshot(ctx, turn, absPath);\n\t} catch {\n\t\t// snapshot failures are non-fatal\n\t}\n}\n\n/**\n * Tree scope, turn START: snapshot the current (pre-turn) content of every\n * dirty/untracked file so modifications made during the turn can be restored.\n */\nfunction captureTreeBaseline(ctx: RollbackContext, cwd: string): void {\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\tconst entries = gitPorcelain(ctx, cwd);\n\tif (!entries) return;\n\tfor (const { path } of entries) {\n\t\tif (!path) continue;\n\t\tconst abs = join(cwd, path);\n\t\tif (turn.files.has(abs)) continue;\n\t\ttry {\n\t\t\tconst existed = existsSync(abs);\n\t\t\tturn.files.set(abs, {\n\t\t\t\texisted,\n\t\t\t\tcontent: existed ? readFileSync(abs) : undefined,\n\t\t\t\tcreatedByTool: false,\n\t\t\t});\n\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t} catch {\n\t\t\t// skip unreadable\n\t\t}\n\t}\n}\n\n/**\n * Tree scope, turn END: pick up files that became dirty during the turn but\n * were clean/absent at baseline. Untracked = created during the turn (deleted\n * on restore under hybrid); tracked-modified = restore from HEAD content.\n */\nexport function captureTreeChanges(cwd: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\tif (ctx.settingsManager?.getRollbackScope() !== \"tree\") return;\n\tif (ctx.currentTurnIndex < 0 || ctx.turns.length === 0) return;\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\n\tconst entries = gitPorcelain(ctx, cwd);\n\tif (!entries) return;\n\tfor (const { status, path, source } of entries) {\n\t\tif (!path) continue;\n\t\tconst abs = join(cwd, path);\n\t\tif (turn.files.has(abs)) continue; // already captured (baseline or tool snapshot)\n\t\ttry {\n\t\t\tif (status === \"??\" || status.includes(\"R\")) {\n\t\t\t\t// lunr: untracked now (or rename dest) and not in the baseline — created\n\t\t\t\t// during this turn (deleted on restore under hybrid/shadow-git).\n\t\t\t\tturn.files.set(abs, { existed: false, createdByTool: false });\n\t\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t\t\t// lunr: rename source existed at HEAD and is gone now — restore its\n\t\t\t\t// HEAD content on rollback, like a tracked file deleted mid-turn.\n\t\t\t\tif (status.includes(\"R\") && source) {\n\t\t\t\t\tconst sourceAbs = join(cwd, source);\n\t\t\t\t\tif (!turn.files.has(sourceAbs)) {\n\t\t\t\t\t\tconst headSrc = spawnSync(\"git\", [\"show\", `HEAD:${source}`], {\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\ttimeout: 5000,\n\t\t\t\t\t\t\tmaxBuffer: 32 * 1024 * 1024,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!headSrc.error && headSrc.status === 0 && headSrc.stdout) {\n\t\t\t\t\t\t\tturn.files.set(sourceAbs, {\n\t\t\t\t\t\t\t\texisted: true,\n\t\t\t\t\t\t\t\tcontent: headSrc.stdout as Buffer,\n\t\t\t\t\t\t\t\tcreatedByTool: false,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tpersistSnapshot(ctx, turn, sourceAbs);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Tracked file that was clean at turn start; original = HEAD content.\n\t\t\t\tconst head = spawnSync(\"git\", [\"show\", `HEAD:${path}`], {\n\t\t\t\t\tcwd,\n\t\t\t\t\ttimeout: 5000,\n\t\t\t\t\tmaxBuffer: 32 * 1024 * 1024,\n\t\t\t\t});\n\t\t\t\tif (head.error || head.status !== 0 || !head.stdout) continue;\n\t\t\t\tturn.files.set(abs, {\n\t\t\t\t\texisted: true,\n\t\t\t\t\tcontent: head.stdout as Buffer,\n\t\t\t\t\tcreatedByTool: false,\n\t\t\t\t});\n\t\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t\t}\n\t\t} catch {\n\t\t\t// skip unreadable\n\t\t}\n\t}\n}\n\n/**\n * Run `git status --porcelain -z` and parse entries, or return undefined (with\n * a one-time warning) when cwd is not a repo / git fails. Rename/copy entries\n * carry their source path in a separate bare field — parsed into `source`.\n */\nfunction gitPorcelain(\n\tctx: RollbackContext,\n\tcwd: string,\n): Array<{ status: string; path: string; source?: string }> | undefined {\n\ttry {\n\t\tconst result = spawnSync(\"git\", [\"status\", \"--porcelain\", \"-z\"], { cwd, encoding: \"utf8\", timeout: 5000 });\n\t\tif (result.error || result.status !== 0) {\n\t\t\twarnOnce(\n\t\t\t\tctx,\n\t\t\t\t\"Rollback tree scope: not a git repository (or git failed) — bash side-effects won't be captured.\",\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\tconst fields = (result.stdout ?? \"\").split(\"\\0\").filter((f) => f.length > 0);\n\t\tconst entries: Array<{ status: string; path: string; source?: string }> = [];\n\t\tfor (let i = 0; i < fields.length; i++) {\n\t\t\tconst field = fields[i];\n\t\t\tconst status = field.slice(0, 2);\n\t\t\tconst path = field.slice(3);\n\t\t\tlet source: string | undefined;\n\t\t\tif (status.includes(\"R\") || status.includes(\"C\")) {\n\t\t\t\t// Rename/copy: the bare field after this entry is the source path.\n\t\t\t\tsource = fields[i + 1];\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tentries.push({ status, path, source });\n\t\t}\n\t\treturn entries;\n\t} catch {\n\t\twarnOnce(ctx, \"Rollback tree scope: not a git repository (or git failed) — bash side-effects won't be captured.\");\n\t\treturn undefined;\n\t}\n}\n\nfunction warnOnce(ctx: RollbackContext, message: string): void {\n\tif (ctx.repoWarningShown) return;\n\tctx.repoWarningShown = true;\n\ttry {\n\t\twarningHandler?.(message);\n\t} catch {\n\t\t// warning delivery is best-effort\n\t}\n}\n\nfunction persistSnapshot(ctx: RollbackContext, turn: TurnSnapshots, absPath: string): void {\n\ttry {\n\t\tconst snap = turn.files.get(absPath);\n\t\tif (!snap) return;\n\t\tconst turnDir = getTurnDir(ctx, turn.turnIndex);\n\t\tmkdirSync(turnDir, { recursive: true });\n\t\tconst manifestPath = join(turnDir, \"manifest.json\");\n\t\tconst manifest = readManifest(manifestPath);\n\t\tconst entry: ManifestEntry = { existed: snap.existed, createdByTool: snap.createdByTool };\n\t\tif (snap.content) {\n\t\t\tconst snapFile = snapFileName(absPath);\n\t\t\twriteFileSync(join(turnDir, snapFile), snap.content);\n\t\t\tentry.snapFile = snapFile;\n\t\t}\n\t\tmanifest.files[absPath] = entry;\n\t\tif (turn.cwd) manifest.cwd = turn.cwd;\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n\t} catch {\n\t\t// disk persistence failures are non-fatal\n\t}\n}\n\nfunction readManifest(path: string): TurnManifest {\n\tif (!existsSync(path)) return { files: {} };\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n\t\t\tconst files = (parsed as Record<string, unknown>).files;\n\t\t\treturn {\n\t\t\t\tcwd: typeof parsed.cwd === \"string\" ? parsed.cwd : undefined,\n\t\t\t\tfiles:\n\t\t\t\t\tfiles && typeof files === \"object\" && !Array.isArray(files)\n\t\t\t\t\t\t? (files as Record<string, ManifestEntry>)\n\t\t\t\t\t\t: {},\n\t\t\t};\n\t\t}\n\t\treturn { files: {} };\n\t} catch {\n\t\treturn { files: {} };\n\t}\n}\n\n/** Reload persisted turns from disk (called by initRollback) so rollback survives restarts. */\nfunction loadPersistedTurns(ctx: RollbackContext): void {\n\ttry {\n\t\tconst sessionDir = join(ROLLBACK_BASE, ctx.sessionId);\n\t\tif (!existsSync(sessionDir)) return;\n\t\tconst loaded: TurnSnapshots[] = [];\n\t\tfor (const dirName of readdirSync(sessionDir)) {\n\t\t\tconst match = /^turn-(\\d+)$/.exec(dirName);\n\t\t\tif (!match) continue;\n\t\t\tconst turnIndex = Number(match[1]);\n\t\t\tconst turnDir = join(sessionDir, dirName);\n\t\t\tconst manifest = readManifest(join(turnDir, \"manifest.json\"));\n\t\t\tconst files = new Map<string, Snapshot>();\n\t\t\tfor (const [absPath, meta] of Object.entries(manifest.files)) {\n\t\t\t\tlet content: Buffer | undefined;\n\t\t\t\tif (meta.snapFile) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = readFileSync(join(turnDir, meta.snapFile));\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontent = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfiles.set(absPath, { existed: meta.existed, content, createdByTool: meta.createdByTool });\n\t\t\t}\n\t\t\tloaded.push({ turnIndex, cwd: manifest.cwd, files });\n\t\t}\n\t\tloaded.sort((a, b) => a.turnIndex - b.turnIndex);\n\t\tctx.turns = loaded;\n\t\tctx.currentTurnIndex = loaded.length > 0 ? loaded[loaded.length - 1].turnIndex : -1;\n\t\tpruneTurns(ctx);\n\t} catch {\n\t\t// reload failures are non-fatal — start empty\n\t}\n}\n\nfunction getTurnDir(ctx: RollbackContext, turnIndex: number): string {\n\treturn join(ROLLBACK_BASE, ctx.sessionId, `turn-${turnIndex}`);\n}\n\nfunction cleanupTurnFiles(ctx: RollbackContext, turn: TurnSnapshots): void {\n\ttry {\n\t\tconst dir = getTurnDir(ctx, turn.turnIndex);\n\t\tif (existsSync(dir)) rmSync(dir, { recursive: true, force: true });\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport interface RollbackResult {\n\trestored: string[];\n\tdeleted: string[];\n\t/** Number of turns consumed: the restored turn plus any empty turns skipped above it. */\n\tturnsConsumed: number;\n}\n\n/**\n * Restore the newest NON-EMPTY turn's snapshots, drop it (and any empty turns\n * on top of it), and return what actually happened. Files the agent created\n * with edit/write are deleted in every capture mode; files created outside\n * tools (tree scope) are deleted only under hybrid/shadow-git.\n */\nfunction isPathUnderRoot(absPath: string, root: string): boolean {\n\tlet normRoot = normalize(root).replace(/\\\\$/g, \"\");\n\tlet normPath = normalize(absPath).replace(/\\\\$/g, \"\");\n\t// lunr: Windows drive-letter/directory casing differs by launch context and\n\t// resolve() preserves input casing — compare case-insensitively there.\n\tif (process.platform === \"win32\") {\n\t\tnormRoot = normRoot.toLowerCase();\n\t\tnormPath = normPath.toLowerCase();\n\t}\n\treturn normPath === normRoot || normPath.startsWith(`${normRoot}/`) || normPath.startsWith(`${normRoot}\\\\`);\n}\n\nfunction isWithinAllowedRoots(absPath: string, turn: TurnSnapshots): boolean {\n\tif (!turn.cwd) return true; // no recorded cwd: cannot validate, allow (tests / legacy)\n\tconst roots = [\n\t\tROLLBACK_BASE,\n\t\tjoin(homedir(), CONFIG_DIR_NAME), // lunr: behavior.md / cron jobs.json live under the config dir\n\t\t// lunr: simple-memory lives next to the lunr agent dir (~/.lunr/simple-memory)\n\t\tjoin(dirname(getAgentDir()), \"simple-memory\"),\n\t\tresolve(turn.cwd),\n\t];\n\treturn roots.some((root) => isPathUnderRoot(absPath, root));\n}\n\nfunction warnExternalModification(ctx: RollbackContext, message: string): void {\n\tif (ctx.externalModWarningShown || !warningHandler) return;\n\tctx.externalModWarningShown = true;\n\ttry {\n\t\twarningHandler(message);\n\t} catch {\n\t\t// warning delivery is best-effort\n\t}\n}\n\n/** Count how many turns a rollback would consume (trailing empty turns + the newest non-empty one). */\nexport function peekRollbackTurnsConsumed(sessionId?: string): number {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return 0;\n\tif (ctx.turns.length === 0) return 0;\n\tlet consumed = 0;\n\tfor (let i = ctx.turns.length - 1; i >= 0; i--) {\n\t\tconsumed++;\n\t\tif (ctx.turns[i].files.size > 0) break;\n\t}\n\treturn consumed;\n}\n\nexport function rollbackLastTurn(sessionId?: string): RollbackResult {\n\tconst ctx = getContext(sessionId);\n\tconst empty: RollbackResult = { restored: [], deleted: [], turnsConsumed: 0 };\n\tif (!isRollbackEnabled(ctx.sessionId)) return empty;\n\n\tlet turnsConsumed = 0;\n\twhile (ctx.turns.length > 0 && ctx.turns[ctx.turns.length - 1].files.size === 0) {\n\t\tconst skipped = ctx.turns.pop();\n\t\tif (skipped) {\n\t\t\tcleanupTurnFiles(ctx, skipped);\n\t\t\tturnsConsumed++;\n\t\t}\n\t}\n\tif (ctx.turns.length === 0) return empty;\n\tturnsConsumed++;\n\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tconst capture = ctx.settingsManager?.getRollbackCapture() ?? \"copies\";\n\tconst restored: string[] = [];\n\tconst deleted: string[] = [];\n\n\tfor (const [absPath, snap] of turn.files) {\n\t\ttry {\n\t\t\tif (!isWithinAllowedRoots(absPath, turn)) {\n\t\t\t\twarnExternalModification(\n\t\t\t\t\tctx,\n\t\t\t\t\t`Rollback skipped ${absPath}: outside the session working directory or lunR config dir.`,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (snap.existed && snap.content) {\n\t\t\t\t// For tree-scope baseline snapshots, skip the write if the file is\n\t\t\t\t// already identical to the snapshot (no actual change occurred during the\n\t\t\t\t// turn). Tool snapshots are always written so /rollback reports them.\n\t\t\t\tif (!snap.createdByTool && existsSync(absPath)) {\n\t\t\t\t\tconst current = readFileSync(absPath);\n\t\t\t\t\tif (current.equals(snap.content)) continue;\n\t\t\t\t}\n\t\t\t\tmkdirSync(dirname(absPath), { recursive: true });\n\t\t\t\twriteFileSync(absPath, snap.content);\n\t\t\t\trestored.push(absPath);\n\t\t\t} else if (!snap.existed) {\n\t\t\t\tconst shouldDelete = snap.createdByTool || capture === \"hybrid\" || capture === \"shadow-git\";\n\t\t\t\tif (shouldDelete && existsSync(absPath)) {\n\t\t\t\t\tunlinkSync(absPath);\n\t\t\t\t\tdeleted.push(absPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// existed but content unreadable — skip\n\t\t} catch {\n\t\t\t// individual file restore failures are non-fatal\n\t\t}\n\t}\n\n\tcleanupTurnFiles(ctx, turn);\n\tctx.turns.pop();\n\n\treturn { restored, deleted, turnsConsumed };\n}\n\nexport function getRollbackStatus(sessionId?: string): { enabled: boolean; turns: number; files: number } {\n\tconst ctx = getContext(sessionId);\n\treturn {\n\t\tenabled: isRollbackEnabled(ctx.sessionId),\n\t\tturns: ctx.turns.length,\n\t\tfiles: ctx.turns.reduce((sum, t) => sum + t.files.size, 0),\n\t};\n}\n\n/**\n * lunr: carry a session's rollback state across a fork — re-key the in-memory\n * context and move the on-disk dir to the forked session's id. No-op when the\n * old session has no state. Fork teardown deliberately skips clearRollback so\n * this can run right after (see interactive-mode beforeSessionInvalidate).\n */\nexport function migrateRollbackSession(oldSessionId: string, newSessionId: string): void {\n\tif (oldSessionId === newSessionId) return;\n\tconst ctx = contexts.get(oldSessionId);\n\tif (ctx) {\n\t\tcontexts.delete(oldSessionId);\n\t\tctx.sessionId = newSessionId;\n\t\tcontexts.set(newSessionId, ctx);\n\t}\n\ttry {\n\t\tconst oldDir = join(ROLLBACK_BASE, oldSessionId);\n\t\tconst newDir = join(ROLLBACK_BASE, newSessionId);\n\t\tif (existsSync(oldDir)) {\n\t\t\tif (existsSync(newDir)) rmSync(newDir, { recursive: true, force: true });\n\t\t\ttry {\n\t\t\t\trenameSync(oldDir, newDir);\n\t\t\t} catch {\n\t\t\t\t// Cross-device or locked-dir fallback: copy then delete.\n\t\t\t\tcpSync(oldDir, newDir, { recursive: true });\n\t\t\t\trmSync(oldDir, { recursive: true, force: true });\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// migration failures are non-fatal — in-memory state was still re-keyed\n\t}\n}\n\n/** Clear rollback state for a session (or all sessions when no id is passed). */\nexport function clearRollback(sessionId?: string): void {\n\tif (sessionId === undefined) {\n\t\tfor (const ctx of contexts.values()) {\n\t\t\tfor (const turn of ctx.turns) {\n\t\t\t\tcleanupTurnFiles(ctx, turn);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst sessionDir = join(ROLLBACK_BASE, ctx.sessionId);\n\t\t\t\tif (existsSync(sessionDir)) rmSync(sessionDir, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\t\t}\n\t\tcontexts.clear();\n\t\treturn;\n\t}\n\n\tconst ctx = contexts.get(sessionId);\n\tif (!ctx) return;\n\tfor (const turn of ctx.turns) {\n\t\tcleanupTurnFiles(ctx, turn);\n\t}\n\ttry {\n\t\tconst sessionDir = join(ROLLBACK_BASE, sessionId);\n\t\tif (existsSync(sessionDir)) rmSync(sessionDir, { recursive: true, force: true });\n\t} catch {\n\t\t// ignore\n\t}\n\tcontexts.delete(sessionId);\n}\n\nfunction snapFileName(absPath: string): string {\n\treturn `${createHash(\"sha1\").update(absPath).digest(\"hex\")}.snap`;\n}\n"]}
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/core/rollback.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: rollback service — pre-edit file snapshots for /rollback.\n *\n * Captures pre-write file content before edit/write tools mutate files, keyed\n * by user-turn and session id. `/rollback` restores the newest non-empty turn's\n * snapshots and then rewinds the conversation via a session fork (persistent,\n * unlike /undo and /edit, which stay in the same session file).\n *\n * Capture modes (setting `rollbackCapture`):\n * - copies: snapshot pre-write content; restore = write back + delete files\n * the agent created with edit/write.\n * - hybrid: copies + also delete files created OUTSIDE tools (tree scope).\n * - shadow-git: hidden git repo (deferred — behaves like copies).\n *\n * Scope (setting `rollbackScope`):\n * - tools: only edit/write tool changes.\n * - tree: also catches bash side-effects. Baseline = `git status --porcelain`\n * at turn START (pre-change content); at agent_end, files that are\n * dirty but were clean/absent at baseline are captured too (untracked\n * = created during the turn; tracked = restored from HEAD). Skipped\n * with a one-time warning when cwd is not a repo.\n *\n * Snapshots persist on disk under `~/.lunr/rollback/<session-id>/<turn-n>/`\n * (manifest.json + sha1-named .snap payloads) and are reloaded on init, so\n * rollback survives restarts. Turn granularity = one user message → agent_end.\n * Retention prunes beyond `rollbackTurns` turns.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n\tcpSync,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\trmSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, normalize, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\nexport interface Snapshot {\n\texisted: boolean;\n\tcontent?: Buffer;\n\tcreatedByTool: boolean;\n}\n\ninterface TurnSnapshots {\n\tturnIndex: number;\n\tcwd?: string;\n\tfiles: Map<string, Snapshot>;\n}\n\ninterface ManifestEntry {\n\texisted: boolean;\n\tcreatedByTool: boolean;\n\tsnapFile?: string;\n}\n\ninterface TurnManifest {\n\tcwd?: string;\n\tfiles: Record<string, ManifestEntry>;\n}\n\nconst ROLLBACK_BASE = join(homedir(), \".lunr\", \"rollback\");\n\ninterface RollbackContext {\n\tsessionId: string;\n\tsettingsManager: SettingsManager | undefined;\n\tsessionForceEnabled: boolean;\n\tturns: TurnSnapshots[];\n\tcurrentTurnIndex: number;\n\trepoWarningShown: boolean;\n\texternalModWarningShown: boolean;\n\t/** Last cwd seen by beginTurn — reused by auto-started turns (mid-turn enable). */\n\tlastCwd?: string;\n}\n\nconst contexts = new Map<string, RollbackContext>();\nlet lastSessionId: string | undefined;\nlet globalSettingsManager: SettingsManager | undefined;\nlet warningHandler: ((message: string) => void) | undefined;\n\n/** Register a sink for one-time user-facing warnings (e.g. tree scope outside a git repo). */\nexport function setRollbackWarningHandler(handler: ((message: string) => void) | undefined): void {\n\twarningHandler = handler;\n}\n\nfunction createContext(sessionId: string): RollbackContext {\n\treturn {\n\t\tsessionId,\n\t\tsettingsManager: globalSettingsManager,\n\t\tsessionForceEnabled: false,\n\t\tturns: [],\n\t\tcurrentTurnIndex: -1,\n\t\trepoWarningShown: false,\n\t\texternalModWarningShown: false,\n\t};\n}\n\nfunction getContext(sessionId?: string): RollbackContext {\n\tconst sid = sessionId ?? lastSessionId ?? \"default\";\n\tlet ctx = contexts.get(sid);\n\tif (!ctx) {\n\t\tctx = createContext(sid);\n\t\tcontexts.set(sid, ctx);\n\t}\n\treturn ctx;\n}\n\nexport function initRollback(sm: SettingsManager, sid: string): void {\n\tglobalSettingsManager = sm;\n\tlastSessionId = sid;\n\tcontexts.set(sid, createContext(sid));\n\tconst ctx = contexts.get(sid)!;\n\tctx.settingsManager = sm;\n\tloadPersistedTurns(ctx);\n}\n\nexport function isRollbackEnabled(sessionId?: string): boolean {\n\tconst ctx = getContext(sessionId);\n\treturn (ctx.settingsManager?.getRollbackEnabled() ?? false) || ctx.sessionForceEnabled;\n}\n\n/** Whether rollback is force-enabled for this session (e.g. by auto permission mode). */\nexport function isRollbackSessionForceEnabled(sessionId?: string): boolean {\n\treturn getContext(sessionId).sessionForceEnabled;\n}\n\nexport function enableRollbackForSession(sessionId?: string): void {\n\tgetContext(sessionId).sessionForceEnabled = true;\n}\n\nexport function disableRollbackForSession(sessionId?: string): void {\n\tgetContext(sessionId).sessionForceEnabled = false;\n}\n\nfunction pruneTurns(ctx: RollbackContext): void {\n\tconst maxTurns = ctx.settingsManager?.getRollbackTurns() ?? 2;\n\twhile (ctx.turns.length > maxTurns) {\n\t\tconst old = ctx.turns.shift();\n\t\tif (old) cleanupTurnFiles(ctx, old);\n\t}\n}\n\n/**\n * Begin a new turn: push a new snapshot map, prune old turns beyond retention.\n * When `cwd` is given and scope is `tree`, also capture the pre-turn baseline\n * (content of all currently dirty/untracked files) so bash side-effects can be\n * restored later.\n */\nexport function beginTurn(cwd?: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\t// lunr: remember the session cwd so auto-started turns (mid-turn enable) can\n\t// still be constrained by the allowed-roots check.\n\tif (cwd) ctx.lastCwd = cwd;\n\tctx.currentTurnIndex++;\n\tconst turn: TurnSnapshots = { turnIndex: ctx.currentTurnIndex, cwd, files: new Map() };\n\tctx.turns.push(turn);\n\tpruneTurns(ctx);\n\tif (cwd && ctx.settingsManager?.getRollbackScope() === \"tree\") {\n\t\tcaptureTreeBaseline(ctx, cwd);\n\t}\n}\n\n/** Capture pre-write content for a file path, recording under the current turn. */\nexport function rollbackSnapshotBeforeWrite(absPath: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\t// lunr: auto-started turn inherits the last known cwd so restores stay\n\t// root-checked; without any recorded cwd the allowed roots still apply.\n\tif (ctx.currentTurnIndex < 0 || ctx.turns.length === 0) beginTurn(ctx.lastCwd, ctx.sessionId);\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\tif (turn.files.has(absPath)) return; // already snapshotted this turn\n\n\ttry {\n\t\tconst existed = existsSync(absPath);\n\t\tlet content: Buffer | undefined;\n\t\tif (existed) {\n\t\t\tcontent = readFileSync(absPath);\n\t\t}\n\t\tturn.files.set(absPath, {\n\t\t\texisted,\n\t\t\tcontent,\n\t\t\tcreatedByTool: true,\n\t\t});\n\t\tpersistSnapshot(ctx, turn, absPath);\n\t} catch {\n\t\t// snapshot failures are non-fatal\n\t}\n}\n\n/**\n * Tree scope, turn START: snapshot the current (pre-turn) content of every\n * dirty/untracked file so modifications made during the turn can be restored.\n */\nfunction captureTreeBaseline(ctx: RollbackContext, cwd: string): void {\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\tconst entries = gitPorcelain(ctx, cwd);\n\tif (!entries) return;\n\tfor (const { path } of entries) {\n\t\tif (!path) continue;\n\t\tconst abs = join(cwd, path);\n\t\tif (turn.files.has(abs)) continue;\n\t\ttry {\n\t\t\tconst existed = existsSync(abs);\n\t\t\tturn.files.set(abs, {\n\t\t\t\texisted,\n\t\t\t\tcontent: existed ? readFileSync(abs) : undefined,\n\t\t\t\tcreatedByTool: false,\n\t\t\t});\n\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t} catch {\n\t\t\t// skip unreadable\n\t\t}\n\t}\n}\n\n/**\n * Tree scope, turn END: pick up files that became dirty during the turn but\n * were clean/absent at baseline. Untracked = created during the turn (deleted\n * on restore under hybrid); tracked-modified = restore from HEAD content.\n */\nexport function captureTreeChanges(cwd: string, sessionId?: string): void {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return;\n\tif (ctx.settingsManager?.getRollbackScope() !== \"tree\") return;\n\tif (ctx.currentTurnIndex < 0 || ctx.turns.length === 0) return;\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tif (!turn) return;\n\n\tconst entries = gitPorcelain(ctx, cwd);\n\tif (!entries) return;\n\tfor (const { status, path, source } of entries) {\n\t\tif (!path) continue;\n\t\tconst abs = join(cwd, path);\n\t\tif (turn.files.has(abs)) continue; // already captured (baseline or tool snapshot)\n\t\ttry {\n\t\t\tif (status === \"??\" || status.includes(\"R\")) {\n\t\t\t\t// lunr: untracked now (or rename dest) and not in the baseline — created\n\t\t\t\t// during this turn (deleted on restore under hybrid/shadow-git).\n\t\t\t\tturn.files.set(abs, { existed: false, createdByTool: false });\n\t\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t\t\t// lunr: rename source existed at HEAD and is gone now — restore its\n\t\t\t\t// HEAD content on rollback, like a tracked file deleted mid-turn.\n\t\t\t\tif (status.includes(\"R\") && source) {\n\t\t\t\t\tconst sourceAbs = join(cwd, source);\n\t\t\t\t\tif (!turn.files.has(sourceAbs)) {\n\t\t\t\t\t\tconst headSrc = spawnSync(\"git\", [\"show\", `HEAD:${source}`], {\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\ttimeout: 5000,\n\t\t\t\t\t\t\tmaxBuffer: 32 * 1024 * 1024,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!headSrc.error && headSrc.status === 0 && headSrc.stdout) {\n\t\t\t\t\t\t\tturn.files.set(sourceAbs, {\n\t\t\t\t\t\t\t\texisted: true,\n\t\t\t\t\t\t\t\tcontent: headSrc.stdout as Buffer,\n\t\t\t\t\t\t\t\tcreatedByTool: false,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tpersistSnapshot(ctx, turn, sourceAbs);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Tracked file that was clean at turn start; original = HEAD content.\n\t\t\t\tconst head = spawnSync(\"git\", [\"show\", `HEAD:${path}`], {\n\t\t\t\t\tcwd,\n\t\t\t\t\ttimeout: 5000,\n\t\t\t\t\tmaxBuffer: 32 * 1024 * 1024,\n\t\t\t\t});\n\t\t\t\tif (head.error || head.status !== 0 || !head.stdout) continue;\n\t\t\t\tturn.files.set(abs, {\n\t\t\t\t\texisted: true,\n\t\t\t\t\tcontent: head.stdout as Buffer,\n\t\t\t\t\tcreatedByTool: false,\n\t\t\t\t});\n\t\t\t\tpersistSnapshot(ctx, turn, abs);\n\t\t\t}\n\t\t} catch {\n\t\t\t// skip unreadable\n\t\t}\n\t}\n}\n\n/**\n * Run `git status --porcelain -z` and parse entries, or return undefined (with\n * a one-time warning) when cwd is not a repo / git fails. Rename/copy entries\n * carry their source path in a separate bare field — parsed into `source`.\n */\nfunction gitPorcelain(\n\tctx: RollbackContext,\n\tcwd: string,\n): Array<{ status: string; path: string; source?: string }> | undefined {\n\ttry {\n\t\tconst result = spawnSync(\"git\", [\"status\", \"--porcelain\", \"-z\"], { cwd, encoding: \"utf8\", timeout: 5000 });\n\t\tif (result.error || result.status !== 0) {\n\t\t\twarnOnce(\n\t\t\t\tctx,\n\t\t\t\t\"Rollback tree scope: not a git repository (or git failed) — bash side-effects won't be captured.\",\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\tconst fields = (result.stdout ?? \"\").split(\"\\0\").filter((f) => f.length > 0);\n\t\tconst entries: Array<{ status: string; path: string; source?: string }> = [];\n\t\tfor (let i = 0; i < fields.length; i++) {\n\t\t\tconst field = fields[i];\n\t\t\tconst status = field.slice(0, 2);\n\t\t\tconst path = field.slice(3);\n\t\t\tlet source: string | undefined;\n\t\t\tif (status.includes(\"R\") || status.includes(\"C\")) {\n\t\t\t\t// Rename/copy: the bare field after this entry is the source path.\n\t\t\t\tsource = fields[i + 1];\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tentries.push({ status, path, source });\n\t\t}\n\t\treturn entries;\n\t} catch {\n\t\twarnOnce(ctx, \"Rollback tree scope: not a git repository (or git failed) — bash side-effects won't be captured.\");\n\t\treturn undefined;\n\t}\n}\n\nfunction warnOnce(ctx: RollbackContext, message: string): void {\n\tif (ctx.repoWarningShown) return;\n\tctx.repoWarningShown = true;\n\ttry {\n\t\twarningHandler?.(message);\n\t} catch {\n\t\t// warning delivery is best-effort\n\t}\n}\n\nfunction persistSnapshot(ctx: RollbackContext, turn: TurnSnapshots, absPath: string): void {\n\ttry {\n\t\tconst snap = turn.files.get(absPath);\n\t\tif (!snap) return;\n\t\tconst turnDir = getTurnDir(ctx, turn.turnIndex);\n\t\tmkdirSync(turnDir, { recursive: true });\n\t\tconst manifestPath = join(turnDir, \"manifest.json\");\n\t\tconst manifest = readManifest(manifestPath);\n\t\tconst entry: ManifestEntry = { existed: snap.existed, createdByTool: snap.createdByTool };\n\t\tif (snap.content) {\n\t\t\tconst snapFile = snapFileName(absPath);\n\t\t\twriteFileSync(join(turnDir, snapFile), snap.content);\n\t\t\tentry.snapFile = snapFile;\n\t\t}\n\t\tmanifest.files[absPath] = entry;\n\t\tif (turn.cwd) manifest.cwd = turn.cwd;\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n\t} catch {\n\t\t// disk persistence failures are non-fatal\n\t}\n}\n\nfunction readManifest(path: string): TurnManifest {\n\tif (!existsSync(path)) return { files: {} };\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n\t\t\tconst files = (parsed as Record<string, unknown>).files;\n\t\t\treturn {\n\t\t\t\tcwd: typeof parsed.cwd === \"string\" ? parsed.cwd : undefined,\n\t\t\t\tfiles:\n\t\t\t\t\tfiles && typeof files === \"object\" && !Array.isArray(files)\n\t\t\t\t\t\t? (files as Record<string, ManifestEntry>)\n\t\t\t\t\t\t: {},\n\t\t\t};\n\t\t}\n\t\treturn { files: {} };\n\t} catch {\n\t\treturn { files: {} };\n\t}\n}\n\n/** Reload persisted turns from disk (called by initRollback) so rollback survives restarts. */\nfunction loadPersistedTurns(ctx: RollbackContext): void {\n\ttry {\n\t\tconst sessionDir = join(ROLLBACK_BASE, ctx.sessionId);\n\t\tif (!existsSync(sessionDir)) return;\n\t\tconst loaded: TurnSnapshots[] = [];\n\t\tfor (const dirName of readdirSync(sessionDir)) {\n\t\t\tconst match = /^turn-(\\d+)$/.exec(dirName);\n\t\t\tif (!match) continue;\n\t\t\tconst turnIndex = Number(match[1]);\n\t\t\tconst turnDir = join(sessionDir, dirName);\n\t\t\tconst manifest = readManifest(join(turnDir, \"manifest.json\"));\n\t\t\tconst files = new Map<string, Snapshot>();\n\t\t\tfor (const [absPath, meta] of Object.entries(manifest.files)) {\n\t\t\t\tlet content: Buffer | undefined;\n\t\t\t\tif (meta.snapFile) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = readFileSync(join(turnDir, meta.snapFile));\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontent = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfiles.set(absPath, { existed: meta.existed, content, createdByTool: meta.createdByTool });\n\t\t\t}\n\t\t\tloaded.push({ turnIndex, cwd: manifest.cwd, files });\n\t\t}\n\t\tloaded.sort((a, b) => a.turnIndex - b.turnIndex);\n\t\tctx.turns = loaded;\n\t\tctx.currentTurnIndex = loaded.length > 0 ? loaded[loaded.length - 1].turnIndex : -1;\n\t\tpruneTurns(ctx);\n\t} catch {\n\t\t// reload failures are non-fatal — start empty\n\t}\n}\n\nfunction getTurnDir(ctx: RollbackContext, turnIndex: number): string {\n\treturn join(ROLLBACK_BASE, ctx.sessionId, `turn-${turnIndex}`);\n}\n\nfunction cleanupTurnFiles(ctx: RollbackContext, turn: TurnSnapshots): void {\n\ttry {\n\t\tconst dir = getTurnDir(ctx, turn.turnIndex);\n\t\tif (existsSync(dir)) rmSync(dir, { recursive: true, force: true });\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport interface RollbackResult {\n\trestored: string[];\n\tdeleted: string[];\n\t/** Number of turns consumed: the restored turn plus any empty turns skipped above it. */\n\tturnsConsumed: number;\n}\n\n/**\n * Restore the newest NON-EMPTY turn's snapshots, drop it (and any empty turns\n * on top of it), and return what actually happened. Files the agent created\n * with edit/write are deleted in every capture mode; files created outside\n * tools (tree scope) are deleted only under hybrid/shadow-git.\n */\nfunction isPathUnderRoot(absPath: string, root: string): boolean {\n\tlet normRoot = normalize(root).replace(/\\\\$/g, \"\");\n\tlet normPath = normalize(absPath).replace(/\\\\$/g, \"\");\n\t// lunr: Windows drive-letter/directory casing differs by launch context and\n\t// resolve() preserves input casing — compare case-insensitively there.\n\tif (process.platform === \"win32\") {\n\t\tnormRoot = normRoot.toLowerCase();\n\t\tnormPath = normPath.toLowerCase();\n\t}\n\treturn normPath === normRoot || normPath.startsWith(`${normRoot}/`) || normPath.startsWith(`${normRoot}\\\\`);\n}\n\nfunction isWithinAllowedRoots(absPath: string, turn: TurnSnapshots): boolean {\n\tif (!turn.cwd) return true; // no recorded cwd: cannot validate, allow (tests / legacy)\n\tconst roots = [\n\t\tROLLBACK_BASE,\n\t\tjoin(homedir(), CONFIG_DIR_NAME), // lunr: agent settings / cron jobs.json live under the config dir\n\t\t// lunr: simple-memory lives next to the lunr agent dir (~/.lunr/simple-memory)\n\t\tjoin(dirname(getAgentDir()), \"simple-memory\"),\n\t\tresolve(turn.cwd),\n\t];\n\treturn roots.some((root) => isPathUnderRoot(absPath, root));\n}\n\nfunction warnExternalModification(ctx: RollbackContext, message: string): void {\n\tif (ctx.externalModWarningShown || !warningHandler) return;\n\tctx.externalModWarningShown = true;\n\ttry {\n\t\twarningHandler(message);\n\t} catch {\n\t\t// warning delivery is best-effort\n\t}\n}\n\n/** Count how many turns a rollback would consume (trailing empty turns + the newest non-empty one). */\nexport function peekRollbackTurnsConsumed(sessionId?: string): number {\n\tconst ctx = getContext(sessionId);\n\tif (!isRollbackEnabled(ctx.sessionId)) return 0;\n\tif (ctx.turns.length === 0) return 0;\n\tlet consumed = 0;\n\tfor (let i = ctx.turns.length - 1; i >= 0; i--) {\n\t\tconsumed++;\n\t\tif (ctx.turns[i].files.size > 0) break;\n\t}\n\treturn consumed;\n}\n\nexport function rollbackLastTurn(sessionId?: string): RollbackResult {\n\tconst ctx = getContext(sessionId);\n\tconst empty: RollbackResult = { restored: [], deleted: [], turnsConsumed: 0 };\n\tif (!isRollbackEnabled(ctx.sessionId)) return empty;\n\n\tlet turnsConsumed = 0;\n\twhile (ctx.turns.length > 0 && ctx.turns[ctx.turns.length - 1].files.size === 0) {\n\t\tconst skipped = ctx.turns.pop();\n\t\tif (skipped) {\n\t\t\tcleanupTurnFiles(ctx, skipped);\n\t\t\tturnsConsumed++;\n\t\t}\n\t}\n\tif (ctx.turns.length === 0) return empty;\n\tturnsConsumed++;\n\n\tconst turn = ctx.turns[ctx.turns.length - 1];\n\tconst capture = ctx.settingsManager?.getRollbackCapture() ?? \"copies\";\n\tconst restored: string[] = [];\n\tconst deleted: string[] = [];\n\n\tfor (const [absPath, snap] of turn.files) {\n\t\ttry {\n\t\t\tif (!isWithinAllowedRoots(absPath, turn)) {\n\t\t\t\twarnExternalModification(\n\t\t\t\t\tctx,\n\t\t\t\t\t`Rollback skipped ${absPath}: outside the session working directory or lunR config dir.`,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (snap.existed && snap.content) {\n\t\t\t\t// For tree-scope baseline snapshots, skip the write if the file is\n\t\t\t\t// already identical to the snapshot (no actual change occurred during the\n\t\t\t\t// turn). Tool snapshots are always written so /rollback reports them.\n\t\t\t\tif (!snap.createdByTool && existsSync(absPath)) {\n\t\t\t\t\tconst current = readFileSync(absPath);\n\t\t\t\t\tif (current.equals(snap.content)) continue;\n\t\t\t\t}\n\t\t\t\tmkdirSync(dirname(absPath), { recursive: true });\n\t\t\t\twriteFileSync(absPath, snap.content);\n\t\t\t\trestored.push(absPath);\n\t\t\t} else if (!snap.existed) {\n\t\t\t\tconst shouldDelete = snap.createdByTool || capture === \"hybrid\" || capture === \"shadow-git\";\n\t\t\t\tif (shouldDelete && existsSync(absPath)) {\n\t\t\t\t\tunlinkSync(absPath);\n\t\t\t\t\tdeleted.push(absPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// existed but content unreadable — skip\n\t\t} catch {\n\t\t\t// individual file restore failures are non-fatal\n\t\t}\n\t}\n\n\tcleanupTurnFiles(ctx, turn);\n\tctx.turns.pop();\n\n\treturn { restored, deleted, turnsConsumed };\n}\n\nexport function getRollbackStatus(sessionId?: string): { enabled: boolean; turns: number; files: number } {\n\tconst ctx = getContext(sessionId);\n\treturn {\n\t\tenabled: isRollbackEnabled(ctx.sessionId),\n\t\tturns: ctx.turns.length,\n\t\tfiles: ctx.turns.reduce((sum, t) => sum + t.files.size, 0),\n\t};\n}\n\n/**\n * lunr: carry a session's rollback state across a fork — re-key the in-memory\n * context and move the on-disk dir to the forked session's id. No-op when the\n * old session has no state. Fork teardown deliberately skips clearRollback so\n * this can run right after (see interactive-mode beforeSessionInvalidate).\n */\nexport function migrateRollbackSession(oldSessionId: string, newSessionId: string): void {\n\tif (oldSessionId === newSessionId) return;\n\tconst ctx = contexts.get(oldSessionId);\n\tif (ctx) {\n\t\tcontexts.delete(oldSessionId);\n\t\tctx.sessionId = newSessionId;\n\t\tcontexts.set(newSessionId, ctx);\n\t}\n\ttry {\n\t\tconst oldDir = join(ROLLBACK_BASE, oldSessionId);\n\t\tconst newDir = join(ROLLBACK_BASE, newSessionId);\n\t\tif (existsSync(oldDir)) {\n\t\t\tif (existsSync(newDir)) rmSync(newDir, { recursive: true, force: true });\n\t\t\ttry {\n\t\t\t\trenameSync(oldDir, newDir);\n\t\t\t} catch {\n\t\t\t\t// Cross-device or locked-dir fallback: copy then delete.\n\t\t\t\tcpSync(oldDir, newDir, { recursive: true });\n\t\t\t\trmSync(oldDir, { recursive: true, force: true });\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// migration failures are non-fatal — in-memory state was still re-keyed\n\t}\n}\n\n/** Clear rollback state for a session (or all sessions when no id is passed). */\nexport function clearRollback(sessionId?: string): void {\n\tif (sessionId === undefined) {\n\t\tfor (const ctx of contexts.values()) {\n\t\t\tfor (const turn of ctx.turns) {\n\t\t\t\tcleanupTurnFiles(ctx, turn);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst sessionDir = join(ROLLBACK_BASE, ctx.sessionId);\n\t\t\t\tif (existsSync(sessionDir)) rmSync(sessionDir, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\t\t}\n\t\tcontexts.clear();\n\t\treturn;\n\t}\n\n\tconst ctx = contexts.get(sessionId);\n\tif (!ctx) return;\n\tfor (const turn of ctx.turns) {\n\t\tcleanupTurnFiles(ctx, turn);\n\t}\n\ttry {\n\t\tconst sessionDir = join(ROLLBACK_BASE, sessionId);\n\t\tif (existsSync(sessionDir)) rmSync(sessionDir, { recursive: true, force: true });\n\t} catch {\n\t\t// ignore\n\t}\n\tcontexts.delete(sessionId);\n}\n\nfunction snapFileName(absPath: string): string {\n\treturn `${createHash(\"sha1\").update(absPath).digest(\"hex\")}.snap`;\n}\n"]}
@@ -1,7 +1,5 @@
1
1
  import type { ThinkingLevel } from "@ashx-j/lunr-agent";
2
2
  import type { Transport } from "@ashx-j/lunr-ai";
3
- import { type BehaviorPreset } from "./behavior-preset.ts";
4
- export type { BehaviorPreset };
5
3
  export interface CompactionSettings {
6
4
  enabled?: boolean;
7
5
  reserveTokens?: number;
@@ -75,6 +73,7 @@ export interface Settings {
75
73
  defaultProvider?: string;
76
74
  defaultModel?: string;
77
75
  defaultThinkingLevel?: ThinkingLevel;
76
+ openaiFastMode?: boolean;
78
77
  cronFallbackModels?: string[];
79
78
  transport?: TransportSetting;
80
79
  steeringMode?: "all" | "one-at-a-time";
@@ -115,14 +114,15 @@ export interface Settings {
115
114
  markdown?: MarkdownSettings;
116
115
  modelTiers?: ModelTiersSettings;
117
116
  sessionRetentionDays?: number;
117
+ memoryEnabled?: boolean;
118
118
  memoryCharCap?: number;
119
- behaviorPreset?: BehaviorPreset;
120
119
  gutterRail?: boolean;
121
120
  promptSymbol?: boolean;
122
121
  footerMcp?: boolean;
123
122
  footerLsp?: boolean;
124
123
  footerContext?: boolean;
125
124
  footerTokens?: boolean;
125
+ footerCacheHitRate?: boolean;
126
126
  footerTps?: boolean;
127
127
  footerStatuses?: boolean;
128
128
  footerGit?: boolean;
@@ -226,6 +226,8 @@ export declare class SettingsManager {
226
226
  getTheme(): string | undefined;
227
227
  setTheme(theme: string): void;
228
228
  getDefaultThinkingLevel(): ThinkingLevel | undefined;
229
+ getOpenAIFastMode(): boolean;
230
+ setOpenAIFastMode(enabled: boolean): void;
229
231
  setDefaultThinkingLevel(level: ThinkingLevel): void;
230
232
  getTransport(): TransportSetting;
231
233
  setTransport(transport: TransportSetting): void;
@@ -276,9 +278,9 @@ export declare class SettingsManager {
276
278
  getSessionRetentionDays(): number;
277
279
  setSessionRetentionDays(days: number): void;
278
280
  getMemoryCharCap(): number;
281
+ getMemoryEnabled(): boolean;
282
+ setMemoryEnabled(enabled: boolean): void;
279
283
  setMemoryCharCap(cap: number): void;
280
- getBehaviorPreset(): BehaviorPreset;
281
- setBehaviorPreset(preset: BehaviorPreset): void;
282
284
  getGutterRail(): boolean;
283
285
  setGutterRail(enabled: boolean): void;
284
286
  getPromptSymbol(): boolean;
@@ -291,6 +293,8 @@ export declare class SettingsManager {
291
293
  setFooterContext(enabled: boolean): void;
292
294
  getFooterTokens(): boolean;
293
295
  setFooterTokens(enabled: boolean): void;
296
+ getFooterCacheHitRate(): boolean;
297
+ setFooterCacheHitRate(enabled: boolean): void;
294
298
  getFooterTps(): boolean;
295
299
  setFooterTps(enabled: boolean): void;
296
300
  getFooterStatuses(): 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\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"]}
1
+ {"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAUvD,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,gBAAgB,CAAC,EAAE,aAAa,CAAC;IACjC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC7D,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AACxE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACtB,MAAM,GACN;IACA,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEL,MAAM,WAAW,QAAQ;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IACvC,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC9C,cAAc,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,KAAK,CAAC;IAC/E,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IAElC,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAE9C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACnC;AA4CD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,4BAA4B;IAC5C,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;CAC9F;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;CACb;AAED,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,mBAAmB,CAAS;IAEpC,YAAY,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAKxC;IAED,OAAO,CAAC,wBAAwB;IA2BhC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CA4B5F;CACD;AAED,qBAAa,uBAAwB,YAAW,eAAe;IAC9D,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAqB;IAEpC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CAU5F;CACD;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,oBAAoB,CAA0C;IACtE,OAAO,CAAC,qBAAqB,CAA6B;IAC1D,OAAO,CAAC,2BAA2B,CAA0C;IAC7E,OAAO,CAAC,uBAAuB,CAAsB;IACrD,OAAO,CAAC,wBAAwB,CAAsB;IACtD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAkB;IAEhC,OAAO,eAiBN;IAED,qDAAqD;IACrD,MAAM,CAAC,MAAM,CACZ,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,OAAO,GAAE,4BAAiC,GACxC,eAAe,CAGjB;IAED,iEAAiE;IACjE,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,GAAE,4BAAiC,GAAG,eAAe,CAqBxG;IAED,wDAAwD;IACxD,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAE,OAAO,CAAC,QAAQ,CAAM,EAAE,OAAO,GAAE,4BAAiC,GAAG,eAAe,CAK7G;IAED,OAAO,CAAC,MAAM,CAAC,eAAe;IAkB9B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAYjC,gDAAgD;IAChD,OAAO,CAAC,MAAM,CAAC,eAAe;IA6D9B,iBAAiB,IAAI,QAAQ,CAE5B;IAED,kBAAkB,IAAI,QAAQ,CAE7B;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuBxC;IAEK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA0B5B;IAED,4DAA4D;IAC5D,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAEjD;IAED,0DAA0D;IAC1D,OAAO,CAAC,YAAY;IAUpB,2DAA2D;IAC3D,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,4BAA4B;IAMpC,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IA+B7B,OAAO,CAAC,IAAI;IAgBZ,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,qBAAqB;IAQvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,WAAW,IAAI,aAAa,EAAE,CAI7B;IAED,aAAa,IAAI,MAAM,GAAG,SAAS,CAGlC;IAED,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,uHAAuH;IACvH,qBAAqB,IAAI,MAAM,EAAE,CAEhC;IAED,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIzC;IAED,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIrC;IAED,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlE;IAED,eAAe,IAAI,KAAK,GAAG,eAAe,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,GAAG,IAAI,CAInD;IAED,eAAe,IAAI,KAAK,GAAG,eAAe,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,GAAG,IAAI,CAInD;IAED,eAAe,IAAI,MAAM,GAAG,SAAS,CAIpC;IAED,QAAQ,IAAI,MAAM,GAAG,SAAS,CAG7B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,uBAAuB,IAAI,aAAa,GAAG,SAAS,CAEnD;IAED,iBAAiB,IAAI,OAAO,CAE3B;IAED,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIxC;IAED,uBAAuB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAIlD;IAED,YAAY,IAAI,gBAAgB,CAE/B;IAED,YAAY,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAI9C;IAED,iBAAiB,IAAI,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAEzD;IAED,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjE;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO3C;IAED,0BAA0B,IAAI,MAAM,CAEnC;IAED,6BAA6B,IAAI,MAAM,CAEtC;IAED,qBAAqB,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAM7F;IAED,wBAAwB,IAAI;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAKzE;IAED,0BAA0B,IAAI,OAAO,CAEpC;IAED,eAAe,IAAI,OAAO,CAEzB;IAED,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOtC;IAED,gBAAgB,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAMhF;IAED,oBAAoB,IAAI,MAAM,CAE7B;IAED,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAO5C;IAED,wBAAwB,IAAI;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAM/F;IAED,4BAA4B,IAAI,MAAM,GAAG,SAAS,CAEjD;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,mBAAmB,IAAI,OAAO,CAE7B;IAED,uBAAuB,IAAI,OAAO,CAEjC;IAED,wBAAwB,IAAI,MAAM,GAAG,SAAS,CAU7C;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAIxC;IAED,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAI3C;IAED,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAI3C;IAED,YAAY,IAAI,MAAM,GAAG,SAAS,CAGjC;IAED,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAI3C;IAED,eAAe,IAAI,OAAO,CAEzB;IAED,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAIpC;IAED,kBAAkB,IAAI,OAAO,CAE5B;IAED,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIzC;IAED,uBAAuB,IAAI,MAAM,CAMhC;IAED,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI1C;IAED,gBAAgB,IAAI,MAAM,CAMzB;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIvC;IAED,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIlC;IAGD,aAAa,IAAI,OAAO,CAEvB;IAED,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIpC;IAED,eAAe,IAAI,OAAO,CAEzB;IAED,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAItC;IAGD,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIvC;IAED,eAAe,IAAI,OAAO,CAEzB;IAED,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAItC;IAED,qBAAqB,IAAI,OAAO,CAE/B;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAI5C;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,iBAAiB,IAAI,OAAO,CAE3B;IAED,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIxC;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIpC;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIvC;IAED,kBAAkB,IAAI,IAAI,GAAG,QAAQ,CAEpC;IAED,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,IAAI,CAIhD;IAED,sBAAsB,IAAI,mBAAmB,CAG5C;IAED,sBAAsB,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,IAAI,CAIrE;IAGD,wBAAwB,IAAI,qBAAqB,CAGhD;IAED,wBAAwB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAI1D;IAGD,kBAAkB,IAAI,OAAO,CAE5B;IAED,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIzC;IAED,gBAAgB,IAAI,MAAM,CAMzB;IAED,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIpC;IAED,kBAAkB,IAAI,eAAe,CAGpC;IAED,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAI9C;IAED,gBAAgB,IAAI,aAAa,CAGhC;IAED,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAI3C;IAGD,0BAA0B,IAAI,OAAO,CAEpC;IAED,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIjD;IAED,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAE1C;IAED,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAItD;IAED,aAAa,IAAI,MAAM,EAAE,GAAG,SAAS,CAEpC;IAED,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAIjD;IAED,kBAAkB,IAAI,OAAO,CAE5B;IAED,aAAa,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,2FAA2F;IAC3F,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQzC;IAED,WAAW,IAAI,aAAa,EAAE,CAE7B;IAED,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAI3C;IAED,kBAAkB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAIlD;IAED,iBAAiB,IAAI,MAAM,EAAE,CAE5B;IAED,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAIvC;IAED,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAI9C;IAED,aAAa,IAAI,MAAM,EAAE,CAExB;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAInC;IAED,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAI1C;IAED,sBAAsB,IAAI,MAAM,EAAE,CAEjC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAI5C;IAED,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAInD;IAED,aAAa,IAAI,MAAM,EAAE,CAExB;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAInC;IAED,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAI1C;IAED,sBAAsB,IAAI,OAAO,CAEhC;IAED,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAI7C;IAED,kBAAkB,IAAI,uBAAuB,GAAG,SAAS,CAExD;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAOjC;IAED,kBAAkB,IAAI,MAAM,CAM3B;IAED,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAOtC;IAED,gBAAgB,IAAI,OAAO,CAM1B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOvC;IAED,uBAAuB,IAAI,OAAO,CAEjC;IAED,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO9C;IAED,kBAAkB,IAAI,OAAO,CAE5B;IAED,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOzC;IAED,cAAc,IAAI,OAAO,CAExB;IAED,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOrC;IAED,gBAAgB,IAAI,MAAM,EAAE,GAAG,SAAS,CAEvC;IAED,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAIrD;IAED,qBAAqB,IAAI,MAAM,GAAG,MAAM,GAAG,MAAM,CAEhD;IAED,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAI5D;IAED,iBAAiB,IAAI,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,KAAK,CAIjF;IAED,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,KAAK,GAAG,IAAI,CAI3F;IAED,qBAAqB,IAAI,OAAO,CAE/B;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAI5C;IAED,iBAAiB,IAAI,MAAM,CAE1B;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIvC;IAED,YAAY,IAAI,CAAC,GAAG,CAAC,CAEpB;IAED,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAIjC;IAED,yBAAyB,IAAI,MAAM,CAElC;IAED,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAIlD;IAED,kBAAkB,IAAI,MAAM,CAE3B;IAED,aAAa,IAAI,kBAAkB,CAElC;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO3C;IAED,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAEpD;IAED,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOrD;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,GAAG,SAAS,CAE9D;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAY3E;CACD","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 { 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 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\topenaiFastMode?: boolean; // default: false - OpenAI Codex subscription service tier\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\tmemoryEnabled?: boolean; // default: true - inject durable facts and expose memory tools\n\tmemoryCharCap?: number; // default: 5000 - simple-pi-memory character cap (1..30000)\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\tfooterCacheHitRate?: boolean; // default: true - show the latest prompt cache-hit rate\n\tfooterTps?: boolean; // default: true - show the pi-tps t/s segment\n\tfooterStatuses?: boolean; // default: true - show the plan/goal/swarm 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\tgetOpenAIFastMode(): boolean {\n\t\treturn this.settings.openaiFastMode ?? false;\n\t}\n\n\tsetOpenAIFastMode(enabled: boolean): void {\n\t\tthis.globalSettings.openaiFastMode = enabled;\n\t\tthis.markModified(\"openaiFastMode\");\n\t\tthis.save();\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\tgetMemoryEnabled(): boolean {\n\t\treturn this.globalSettings.memoryEnabled ?? true;\n\t}\n\n\tsetMemoryEnabled(enabled: boolean): void {\n\t\tthis.globalSettings.memoryEnabled = enabled;\n\t\tthis.markModified(\"memoryEnabled\");\n\t\tthis.save();\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\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\tgetFooterCacheHitRate(): boolean {\n\t\treturn this.settings.footerCacheHitRate ?? true;\n\t}\n\n\tsetFooterCacheHitRate(enabled: boolean): void {\n\t\tthis.globalSettings.footerCacheHitRate = enabled;\n\t\tthis.markModified(\"footerCacheHitRate\");\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"]}