gsd-pi 2.34.0-dev.ed0bfbf → 2.35.0-dev.30eec3f

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 (334) hide show
  1. package/dist/cli.js +7 -2
  2. package/dist/resource-loader.d.ts +1 -1
  3. package/dist/resource-loader.js +13 -1
  4. package/dist/resources/extensions/async-jobs/await-tool.js +0 -2
  5. package/dist/resources/extensions/async-jobs/job-manager.js +0 -6
  6. package/dist/resources/extensions/bg-shell/output-formatter.js +1 -19
  7. package/dist/resources/extensions/bg-shell/process-manager.js +0 -4
  8. package/dist/resources/extensions/bg-shell/types.js +0 -2
  9. package/dist/resources/extensions/context7/index.js +5 -0
  10. package/dist/resources/extensions/get-secrets-from-user.js +2 -30
  11. package/dist/resources/extensions/google-search/index.js +5 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-loop.js +10 -1
  14. package/dist/resources/extensions/gsd/auto-recovery.js +35 -0
  15. package/dist/resources/extensions/gsd/auto-start.js +35 -2
  16. package/dist/resources/extensions/gsd/auto.js +59 -4
  17. package/dist/resources/extensions/gsd/changelog.js +162 -0
  18. package/dist/resources/extensions/gsd/commands-bootstrap.js +1 -0
  19. package/dist/resources/extensions/gsd/commands-handlers.js +2 -2
  20. package/dist/resources/extensions/gsd/commands-inspect.js +10 -3
  21. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +5 -1
  22. package/dist/resources/extensions/gsd/commands.js +8 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  24. package/dist/resources/extensions/gsd/doctor-checks.js +113 -5
  25. package/dist/resources/extensions/gsd/doctor-environment.js +26 -17
  26. package/dist/resources/extensions/gsd/doctor-proactive.js +22 -0
  27. package/dist/resources/extensions/gsd/doctor.js +36 -0
  28. package/dist/resources/extensions/gsd/files.js +11 -2
  29. package/dist/resources/extensions/gsd/gitignore.js +54 -7
  30. package/dist/resources/extensions/gsd/guided-flow.js +5 -3
  31. package/dist/resources/extensions/gsd/health-widget-core.js +96 -0
  32. package/dist/resources/extensions/gsd/health-widget.js +97 -46
  33. package/dist/resources/extensions/gsd/index.js +10 -1
  34. package/dist/resources/extensions/gsd/migrate-external.js +55 -2
  35. package/dist/resources/extensions/gsd/paths.js +74 -7
  36. package/dist/resources/extensions/gsd/post-unit-hooks.js +4 -1
  37. package/dist/resources/extensions/gsd/preferences-validation.js +54 -1
  38. package/dist/resources/extensions/gsd/preferences.js +2 -0
  39. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  40. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  41. package/dist/resources/extensions/gsd/roadmap-mutations.js +55 -0
  42. package/dist/resources/extensions/gsd/session-lock.js +26 -2
  43. package/dist/resources/extensions/gsd/templates/plan.md +8 -0
  44. package/dist/resources/extensions/gsd/worktree-resolver.js +12 -0
  45. package/dist/resources/extensions/remote-questions/remote-command.js +2 -22
  46. package/dist/resources/extensions/shared/mod.js +1 -1
  47. package/dist/resources/extensions/shared/sanitize.js +30 -0
  48. package/dist/resources/extensions/subagent/index.js +6 -14
  49. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  50. package/package.json +2 -1
  51. package/packages/pi-agent-core/dist/agent-loop.d.ts +14 -0
  52. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  53. package/packages/pi-agent-core/dist/agent-loop.js +24 -27
  54. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  55. package/packages/pi-agent-core/dist/agent.d.ts +1 -0
  56. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  57. package/packages/pi-agent-core/dist/agent.js +11 -22
  58. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  59. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  60. package/packages/pi-agent-core/dist/proxy.js +2 -8
  61. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  62. package/packages/pi-agent-core/src/agent-loop.ts +30 -27
  63. package/packages/pi-agent-core/src/agent.ts +12 -23
  64. package/packages/pi-agent-core/src/proxy.ts +2 -8
  65. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  66. package/packages/pi-ai/dist/providers/azure-openai-responses.js +5 -41
  67. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  68. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  69. package/packages/pi-ai/dist/providers/openai-completions.js +10 -73
  70. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  71. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  72. package/packages/pi-ai/dist/providers/openai-responses.js +9 -80
  73. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  74. package/packages/pi-ai/dist/providers/openai-shared.d.ts +65 -0
  75. package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -0
  76. package/packages/pi-ai/dist/providers/openai-shared.js +146 -0
  77. package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -0
  78. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  79. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +7 -135
  80. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  81. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  82. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +7 -135
  83. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  84. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts +46 -0
  85. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts.map +1 -0
  86. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js +160 -0
  87. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js.map +1 -0
  88. package/packages/pi-ai/src/providers/azure-openai-responses.ts +11 -45
  89. package/packages/pi-ai/src/providers/openai-completions.ts +16 -86
  90. package/packages/pi-ai/src/providers/openai-responses.ts +16 -96
  91. package/packages/pi-ai/src/providers/openai-shared.ts +193 -0
  92. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +14 -162
  93. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +13 -161
  94. package/packages/pi-ai/src/utils/oauth/google-oauth-utils.ts +201 -0
  95. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +16 -63
  96. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/agent-session.js +104 -641
  98. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +0 -1
  100. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/auth-storage.js +4 -35
  102. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js +5 -43
  105. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  106. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  107. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +11 -69
  108. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +40 -0
  110. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/compaction/utils.js +78 -0
  112. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +77 -0
  114. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -0
  115. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +331 -0
  116. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -0
  117. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +2 -2
  118. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/extensions/index.js +1 -1
  120. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +15 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/runner.js +129 -243
  124. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +49 -42
  126. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/extensions/types.js +2 -21
  128. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts +39 -0
  130. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/core/lock-utils.js +89 -0
  132. package/packages/pi-coding-agent/dist/core/lock-utils.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +2 -0
  134. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/lsp/config.js +4 -1
  136. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/lsp/index.js +52 -107
  139. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +2 -21
  142. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +0 -1
  144. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/lsp/types.js +0 -28
  146. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/package-manager.js +2 -4
  149. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +2 -4
  151. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/resource-loader.js +46 -60
  153. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +87 -0
  155. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -0
  156. package/packages/pi-coding-agent/dist/core/retry-handler.js +295 -0
  157. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -0
  158. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +0 -1
  159. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -28
  161. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +8 -0
  163. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/settings-manager.js +76 -166
  165. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/skills.js +1 -3
  168. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  170. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  171. package/packages/pi-coding-agent/dist/index.js +1 -1
  172. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +9 -26
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -13
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts +44 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts.map +1 -0
  182. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js +61 -0
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js.map +1 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js +6 -9
  186. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +65 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +6 -16
  190. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts +12 -0
  192. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  193. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +175 -0
  194. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -0
  195. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts +6 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts.map +1 -0
  197. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js +15 -0
  198. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js.map +1 -0
  199. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/print-mode.js +2 -30
  201. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -28
  204. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts +19 -0
  206. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts.map +1 -0
  207. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js +45 -0
  208. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js.map +1 -0
  209. package/packages/pi-coding-agent/dist/utils/error.d.ts +5 -0
  210. package/packages/pi-coding-agent/dist/utils/error.d.ts.map +1 -0
  211. package/packages/pi-coding-agent/dist/utils/error.js +7 -0
  212. package/packages/pi-coding-agent/dist/utils/error.js.map +1 -0
  213. package/packages/pi-coding-agent/package.json +1 -1
  214. package/packages/pi-coding-agent/src/core/agent-session.ts +117 -745
  215. package/packages/pi-coding-agent/src/core/auth-storage.ts +4 -38
  216. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +7 -53
  217. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +14 -74
  218. package/packages/pi-coding-agent/src/core/compaction/utils.ts +100 -0
  219. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +424 -0
  220. package/packages/pi-coding-agent/src/core/extensions/index.ts +1 -21
  221. package/packages/pi-coding-agent/src/core/extensions/runner.ts +119 -243
  222. package/packages/pi-coding-agent/src/core/extensions/types.ts +50 -69
  223. package/packages/pi-coding-agent/src/core/lock-utils.ts +113 -0
  224. package/packages/pi-coding-agent/src/core/lsp/config.ts +4 -1
  225. package/packages/pi-coding-agent/src/core/lsp/index.ts +83 -152
  226. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +2 -22
  227. package/packages/pi-coding-agent/src/core/lsp/types.ts +0 -29
  228. package/packages/pi-coding-agent/src/core/package-manager.ts +1 -4
  229. package/packages/pi-coding-agent/src/core/resource-loader.ts +56 -69
  230. package/packages/pi-coding-agent/src/core/retry-handler.ts +359 -0
  231. package/packages/pi-coding-agent/src/core/session-manager.ts +3 -30
  232. package/packages/pi-coding-agent/src/core/settings-manager.ts +85 -164
  233. package/packages/pi-coding-agent/src/core/skills.ts +1 -4
  234. package/packages/pi-coding-agent/src/index.ts +1 -7
  235. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +17 -29
  236. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -13
  237. package/packages/pi-coding-agent/src/modes/interactive/components/tree-render-utils.ts +81 -0
  238. package/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts +14 -19
  239. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +7 -18
  240. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +196 -0
  241. package/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts +14 -0
  242. package/packages/pi-coding-agent/src/modes/print-mode.ts +2 -30
  243. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -28
  244. package/packages/pi-coding-agent/src/modes/shared/command-context-actions.ts +53 -0
  245. package/packages/pi-coding-agent/src/utils/error.ts +6 -0
  246. package/packages/pi-tui/dist/components/markdown.d.ts +5 -0
  247. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  248. package/packages/pi-tui/dist/components/markdown.js +25 -31
  249. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  250. package/packages/pi-tui/dist/keys.d.ts +0 -4
  251. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  252. package/packages/pi-tui/dist/keys.js +94 -162
  253. package/packages/pi-tui/dist/keys.js.map +1 -1
  254. package/packages/pi-tui/src/components/markdown.ts +25 -29
  255. package/packages/pi-tui/src/keys.ts +94 -173
  256. package/pkg/dist/modes/interactive/theme/theme.d.ts +65 -0
  257. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  258. package/pkg/dist/modes/interactive/theme/theme.js +6 -16
  259. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  260. package/pkg/dist/modes/interactive/theme/themes.d.ts +12 -0
  261. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  262. package/pkg/dist/modes/interactive/theme/themes.js +175 -0
  263. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -0
  264. package/pkg/package.json +1 -1
  265. package/src/resources/extensions/async-jobs/await-tool.ts +0 -2
  266. package/src/resources/extensions/async-jobs/job-manager.ts +0 -7
  267. package/src/resources/extensions/bg-shell/output-formatter.ts +0 -17
  268. package/src/resources/extensions/bg-shell/process-manager.ts +0 -4
  269. package/src/resources/extensions/bg-shell/types.ts +0 -12
  270. package/src/resources/extensions/context7/index.ts +7 -0
  271. package/src/resources/extensions/get-secrets-from-user.ts +2 -35
  272. package/src/resources/extensions/google-search/index.ts +7 -0
  273. package/src/resources/extensions/gsd/auto-dispatch.ts +49 -1
  274. package/src/resources/extensions/gsd/auto-loop.ts +11 -1
  275. package/src/resources/extensions/gsd/auto-recovery.ts +39 -0
  276. package/src/resources/extensions/gsd/auto-start.ts +42 -2
  277. package/src/resources/extensions/gsd/auto.ts +61 -3
  278. package/src/resources/extensions/gsd/changelog.ts +213 -0
  279. package/src/resources/extensions/gsd/commands-bootstrap.ts +1 -0
  280. package/src/resources/extensions/gsd/commands-handlers.ts +2 -2
  281. package/src/resources/extensions/gsd/commands-inspect.ts +10 -3
  282. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +5 -1
  283. package/src/resources/extensions/gsd/commands.ts +9 -1
  284. package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  285. package/src/resources/extensions/gsd/doctor-checks.ts +107 -5
  286. package/src/resources/extensions/gsd/doctor-environment.ts +26 -16
  287. package/src/resources/extensions/gsd/doctor-proactive.ts +24 -0
  288. package/src/resources/extensions/gsd/doctor-types.ts +9 -1
  289. package/src/resources/extensions/gsd/doctor.ts +35 -0
  290. package/src/resources/extensions/gsd/files.ts +12 -2
  291. package/src/resources/extensions/gsd/gitignore.ts +54 -7
  292. package/src/resources/extensions/gsd/guided-flow.ts +5 -3
  293. package/src/resources/extensions/gsd/health-widget-core.ts +129 -0
  294. package/src/resources/extensions/gsd/health-widget.ts +103 -59
  295. package/src/resources/extensions/gsd/index.ts +10 -1
  296. package/src/resources/extensions/gsd/migrate-external.ts +47 -2
  297. package/src/resources/extensions/gsd/paths.ts +73 -7
  298. package/src/resources/extensions/gsd/post-unit-hooks.ts +5 -1
  299. package/src/resources/extensions/gsd/preferences-validation.ts +54 -1
  300. package/src/resources/extensions/gsd/preferences.ts +2 -0
  301. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  302. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  303. package/src/resources/extensions/gsd/roadmap-mutations.ts +66 -0
  304. package/src/resources/extensions/gsd/session-lock.ts +29 -2
  305. package/src/resources/extensions/gsd/templates/plan.md +8 -0
  306. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
  307. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +98 -2
  308. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +59 -3
  309. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +20 -0
  310. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +214 -0
  311. package/src/resources/extensions/gsd/tests/health-widget.test.ts +158 -0
  312. package/src/resources/extensions/gsd/tests/paths.test.ts +113 -0
  313. package/src/resources/extensions/gsd/tests/preferences.test.ts +40 -2
  314. package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
  315. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +15 -0
  316. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -0
  317. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +32 -0
  318. package/src/resources/extensions/gsd/worktree-resolver.ts +11 -0
  319. package/src/resources/extensions/remote-questions/remote-command.ts +2 -23
  320. package/src/resources/extensions/shared/mod.ts +1 -1
  321. package/src/resources/extensions/shared/sanitize.ts +36 -0
  322. package/src/resources/extensions/subagent/index.ts +6 -12
  323. package/src/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  324. package/dist/resources/extensions/shared/wizard-ui.js +0 -478
  325. package/packages/pi-coding-agent/dist/modes/interactive/theme/dark.json +0 -85
  326. package/packages/pi-coding-agent/dist/modes/interactive/theme/light.json +0 -84
  327. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json +0 -335
  328. package/packages/pi-coding-agent/src/modes/interactive/theme/dark.json +0 -85
  329. package/packages/pi-coding-agent/src/modes/interactive/theme/light.json +0 -84
  330. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.json +0 -335
  331. package/pkg/dist/modes/interactive/theme/dark.json +0 -85
  332. package/pkg/dist/modes/interactive/theme/light.json +0 -84
  333. package/pkg/dist/modes/interactive/theme/theme-schema.json +0 -335
  334. package/src/resources/extensions/shared/wizard-ui.ts +0 -551
@@ -595,14 +595,56 @@ export class SettingsManager {
595
595
  return drained;
596
596
  }
597
597
 
598
+ // ── Generic setter helpers ──────────────────────────────────────────
599
+
600
+ /** Set a top-level global setting field, mark modified, and save. */
601
+ private setGlobalSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
602
+ this.globalSettings[key] = value;
603
+ this.markModified(key);
604
+ this.save();
605
+ }
606
+
607
+ /** Set a top-level setting, scoped to project when project settings are active. */
608
+ private setScopedSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
609
+ if (this.hasProjectSettings()) {
610
+ this.projectSettings[key] = value;
611
+ this.markProjectModified(key);
612
+ this.saveProjectSettings(this.projectSettings);
613
+ } else {
614
+ this.setGlobalSetting(key, value);
615
+ }
616
+ }
617
+
618
+ /** Set a nested field within a global settings object (e.g. compaction.enabled). */
619
+ private setNestedGlobalSetting<K extends keyof Settings, NK extends string & keyof NonNullable<Settings[K]>>(
620
+ key: K,
621
+ nestedKey: NK,
622
+ value: NonNullable<Settings[K]>[NK],
623
+ ): void {
624
+ if (!this.globalSettings[key]) {
625
+ (this.globalSettings as Record<string, unknown>)[key] = {};
626
+ }
627
+ (this.globalSettings[key] as Record<string, unknown>)[nestedKey] = value;
628
+ this.markModified(key, nestedKey);
629
+ this.save();
630
+ }
631
+
632
+ /** Set a field on project settings (clone, set, mark modified, save). */
633
+ private setProjectSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
634
+ const projectSettings = structuredClone(this.projectSettings);
635
+ projectSettings[key] = value;
636
+ this.markProjectModified(key);
637
+ this.saveProjectSettings(projectSettings);
638
+ }
639
+
640
+ // ── Public getters and setters ──────────────────────────────────────
641
+
598
642
  getLastChangelogVersion(): string | undefined {
599
643
  return this.settings.lastChangelogVersion;
600
644
  }
601
645
 
602
646
  setLastChangelogVersion(version: string): void {
603
- this.globalSettings.lastChangelogVersion = version;
604
- this.markModified("lastChangelogVersion");
605
- this.save();
647
+ this.setGlobalSetting("lastChangelogVersion", version);
606
648
  }
607
649
 
608
650
  getDefaultProvider(): string | undefined {
@@ -614,27 +656,11 @@ export class SettingsManager {
614
656
  }
615
657
 
616
658
  setDefaultProvider(provider: string): void {
617
- if (this.hasProjectSettings()) {
618
- this.projectSettings.defaultProvider = provider;
619
- this.markProjectModified("defaultProvider");
620
- this.saveProjectSettings(this.projectSettings);
621
- } else {
622
- this.globalSettings.defaultProvider = provider;
623
- this.markModified("defaultProvider");
624
- this.save();
625
- }
659
+ this.setScopedSetting("defaultProvider", provider);
626
660
  }
627
661
 
628
662
  setDefaultModel(modelId: string): void {
629
- if (this.hasProjectSettings()) {
630
- this.projectSettings.defaultModel = modelId;
631
- this.markProjectModified("defaultModel");
632
- this.saveProjectSettings(this.projectSettings);
633
- } else {
634
- this.globalSettings.defaultModel = modelId;
635
- this.markModified("defaultModel");
636
- this.save();
637
- }
663
+ this.setScopedSetting("defaultModel", modelId);
638
664
  }
639
665
 
640
666
  setDefaultModelAndProvider(provider: string, modelId: string): void {
@@ -658,9 +684,7 @@ export class SettingsManager {
658
684
  }
659
685
 
660
686
  setSteeringMode(mode: "all" | "one-at-a-time"): void {
661
- this.globalSettings.steeringMode = mode;
662
- this.markModified("steeringMode");
663
- this.save();
687
+ this.setGlobalSetting("steeringMode", mode);
664
688
  }
665
689
 
666
690
  getFollowUpMode(): "all" | "one-at-a-time" {
@@ -668,9 +692,7 @@ export class SettingsManager {
668
692
  }
669
693
 
670
694
  setFollowUpMode(mode: "all" | "one-at-a-time"): void {
671
- this.globalSettings.followUpMode = mode;
672
- this.markModified("followUpMode");
673
- this.save();
695
+ this.setGlobalSetting("followUpMode", mode);
674
696
  }
675
697
 
676
698
  getTheme(): string | undefined {
@@ -678,9 +700,7 @@ export class SettingsManager {
678
700
  }
679
701
 
680
702
  setTheme(theme: string): void {
681
- this.globalSettings.theme = theme;
682
- this.markModified("theme");
683
- this.save();
703
+ this.setGlobalSetting("theme", theme);
684
704
  }
685
705
 
686
706
  getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
@@ -688,9 +708,7 @@ export class SettingsManager {
688
708
  }
689
709
 
690
710
  setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void {
691
- this.globalSettings.defaultThinkingLevel = level;
692
- this.markModified("defaultThinkingLevel");
693
- this.save();
711
+ this.setGlobalSetting("defaultThinkingLevel", level);
694
712
  }
695
713
 
696
714
  getTransport(): TransportSetting {
@@ -698,9 +716,7 @@ export class SettingsManager {
698
716
  }
699
717
 
700
718
  setTransport(transport: TransportSetting): void {
701
- this.globalSettings.transport = transport;
702
- this.markModified("transport");
703
- this.save();
719
+ this.setGlobalSetting("transport", transport);
704
720
  }
705
721
 
706
722
  getCompactionEnabled(): boolean {
@@ -708,12 +724,7 @@ export class SettingsManager {
708
724
  }
709
725
 
710
726
  setCompactionEnabled(enabled: boolean): void {
711
- if (!this.globalSettings.compaction) {
712
- this.globalSettings.compaction = {};
713
- }
714
- this.globalSettings.compaction.enabled = enabled;
715
- this.markModified("compaction", "enabled");
716
- this.save();
727
+ this.setNestedGlobalSetting("compaction", "enabled", enabled);
717
728
  }
718
729
 
719
730
  getCompactionReserveTokens(): number {
@@ -748,12 +759,7 @@ export class SettingsManager {
748
759
  }
749
760
 
750
761
  setRetryEnabled(enabled: boolean): void {
751
- if (!this.globalSettings.retry) {
752
- this.globalSettings.retry = {};
753
- }
754
- this.globalSettings.retry.enabled = enabled;
755
- this.markModified("retry", "enabled");
756
- this.save();
762
+ this.setNestedGlobalSetting("retry", "enabled", enabled);
757
763
  }
758
764
 
759
765
  getRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number; maxDelayMs: number } {
@@ -770,9 +776,7 @@ export class SettingsManager {
770
776
  }
771
777
 
772
778
  setHideThinkingBlock(hide: boolean): void {
773
- this.globalSettings.hideThinkingBlock = hide;
774
- this.markModified("hideThinkingBlock");
775
- this.save();
779
+ this.setGlobalSetting("hideThinkingBlock", hide);
776
780
  }
777
781
 
778
782
  getShellPath(): string | undefined {
@@ -780,9 +784,7 @@ export class SettingsManager {
780
784
  }
781
785
 
782
786
  setShellPath(path: string | undefined): void {
783
- this.globalSettings.shellPath = path;
784
- this.markModified("shellPath");
785
- this.save();
787
+ this.setGlobalSetting("shellPath", path);
786
788
  }
787
789
 
788
790
  getQuietStartup(): boolean {
@@ -790,9 +792,7 @@ export class SettingsManager {
790
792
  }
791
793
 
792
794
  setQuietStartup(quiet: boolean): void {
793
- this.globalSettings.quietStartup = quiet;
794
- this.markModified("quietStartup");
795
- this.save();
795
+ this.setGlobalSetting("quietStartup", quiet);
796
796
  }
797
797
 
798
798
  getShellCommandPrefix(): string | undefined {
@@ -800,9 +800,7 @@ export class SettingsManager {
800
800
  }
801
801
 
802
802
  setShellCommandPrefix(prefix: string | undefined): void {
803
- this.globalSettings.shellCommandPrefix = prefix;
804
- this.markModified("shellCommandPrefix");
805
- this.save();
803
+ this.setGlobalSetting("shellCommandPrefix", prefix);
806
804
  }
807
805
 
808
806
  getCollapseChangelog(): boolean {
@@ -810,9 +808,7 @@ export class SettingsManager {
810
808
  }
811
809
 
812
810
  setCollapseChangelog(collapse: boolean): void {
813
- this.globalSettings.collapseChangelog = collapse;
814
- this.markModified("collapseChangelog");
815
- this.save();
811
+ this.setGlobalSetting("collapseChangelog", collapse);
816
812
  }
817
813
 
818
814
  getPackages(): PackageSource[] {
@@ -820,16 +816,11 @@ export class SettingsManager {
820
816
  }
821
817
 
822
818
  setPackages(packages: PackageSource[]): void {
823
- this.globalSettings.packages = packages;
824
- this.markModified("packages");
825
- this.save();
819
+ this.setGlobalSetting("packages", packages);
826
820
  }
827
821
 
828
822
  setProjectPackages(packages: PackageSource[]): void {
829
- const projectSettings = structuredClone(this.projectSettings);
830
- projectSettings.packages = packages;
831
- this.markProjectModified("packages");
832
- this.saveProjectSettings(projectSettings);
823
+ this.setProjectSetting("packages", packages);
833
824
  }
834
825
 
835
826
  getExtensionPaths(): string[] {
@@ -837,16 +828,11 @@ export class SettingsManager {
837
828
  }
838
829
 
839
830
  setExtensionPaths(paths: string[]): void {
840
- this.globalSettings.extensions = paths;
841
- this.markModified("extensions");
842
- this.save();
831
+ this.setGlobalSetting("extensions", paths);
843
832
  }
844
833
 
845
834
  setProjectExtensionPaths(paths: string[]): void {
846
- const projectSettings = structuredClone(this.projectSettings);
847
- projectSettings.extensions = paths;
848
- this.markProjectModified("extensions");
849
- this.saveProjectSettings(projectSettings);
835
+ this.setProjectSetting("extensions", paths);
850
836
  }
851
837
 
852
838
  getSkillPaths(): string[] {
@@ -854,16 +840,11 @@ export class SettingsManager {
854
840
  }
855
841
 
856
842
  setSkillPaths(paths: string[]): void {
857
- this.globalSettings.skills = paths;
858
- this.markModified("skills");
859
- this.save();
843
+ this.setGlobalSetting("skills", paths);
860
844
  }
861
845
 
862
846
  setProjectSkillPaths(paths: string[]): void {
863
- const projectSettings = structuredClone(this.projectSettings);
864
- projectSettings.skills = paths;
865
- this.markProjectModified("skills");
866
- this.saveProjectSettings(projectSettings);
847
+ this.setProjectSetting("skills", paths);
867
848
  }
868
849
 
869
850
  getPromptTemplatePaths(): string[] {
@@ -871,16 +852,11 @@ export class SettingsManager {
871
852
  }
872
853
 
873
854
  setPromptTemplatePaths(paths: string[]): void {
874
- this.globalSettings.prompts = paths;
875
- this.markModified("prompts");
876
- this.save();
855
+ this.setGlobalSetting("prompts", paths);
877
856
  }
878
857
 
879
858
  setProjectPromptTemplatePaths(paths: string[]): void {
880
- const projectSettings = structuredClone(this.projectSettings);
881
- projectSettings.prompts = paths;
882
- this.markProjectModified("prompts");
883
- this.saveProjectSettings(projectSettings);
859
+ this.setProjectSetting("prompts", paths);
884
860
  }
885
861
 
886
862
  getThemePaths(): string[] {
@@ -888,16 +864,11 @@ export class SettingsManager {
888
864
  }
889
865
 
890
866
  setThemePaths(paths: string[]): void {
891
- this.globalSettings.themes = paths;
892
- this.markModified("themes");
893
- this.save();
867
+ this.setGlobalSetting("themes", paths);
894
868
  }
895
869
 
896
870
  setProjectThemePaths(paths: string[]): void {
897
- const projectSettings = structuredClone(this.projectSettings);
898
- projectSettings.themes = paths;
899
- this.markProjectModified("themes");
900
- this.saveProjectSettings(projectSettings);
871
+ this.setProjectSetting("themes", paths);
901
872
  }
902
873
 
903
874
  getEnableSkillCommands(): boolean {
@@ -905,9 +876,7 @@ export class SettingsManager {
905
876
  }
906
877
 
907
878
  setEnableSkillCommands(enabled: boolean): void {
908
- this.globalSettings.enableSkillCommands = enabled;
909
- this.markModified("enableSkillCommands");
910
- this.save();
879
+ this.setGlobalSetting("enableSkillCommands", enabled);
911
880
  }
912
881
 
913
882
  getThinkingBudgets(): ThinkingBudgetsSettings | undefined {
@@ -919,12 +888,7 @@ export class SettingsManager {
919
888
  }
920
889
 
921
890
  setShowImages(show: boolean): void {
922
- if (!this.globalSettings.terminal) {
923
- this.globalSettings.terminal = {};
924
- }
925
- this.globalSettings.terminal.showImages = show;
926
- this.markModified("terminal", "showImages");
927
- this.save();
891
+ this.setNestedGlobalSetting("terminal", "showImages", show);
928
892
  }
929
893
 
930
894
  getClearOnShrink(): boolean {
@@ -936,12 +900,7 @@ export class SettingsManager {
936
900
  }
937
901
 
938
902
  setClearOnShrink(enabled: boolean): void {
939
- if (!this.globalSettings.terminal) {
940
- this.globalSettings.terminal = {};
941
- }
942
- this.globalSettings.terminal.clearOnShrink = enabled;
943
- this.markModified("terminal", "clearOnShrink");
944
- this.save();
903
+ this.setNestedGlobalSetting("terminal", "clearOnShrink", enabled);
945
904
  }
946
905
 
947
906
  getImageAutoResize(): boolean {
@@ -949,12 +908,7 @@ export class SettingsManager {
949
908
  }
950
909
 
951
910
  setImageAutoResize(enabled: boolean): void {
952
- if (!this.globalSettings.images) {
953
- this.globalSettings.images = {};
954
- }
955
- this.globalSettings.images.autoResize = enabled;
956
- this.markModified("images", "autoResize");
957
- this.save();
911
+ this.setNestedGlobalSetting("images", "autoResize", enabled);
958
912
  }
959
913
 
960
914
  getBlockImages(): boolean {
@@ -962,12 +916,7 @@ export class SettingsManager {
962
916
  }
963
917
 
964
918
  setBlockImages(blocked: boolean): void {
965
- if (!this.globalSettings.images) {
966
- this.globalSettings.images = {};
967
- }
968
- this.globalSettings.images.blockImages = blocked;
969
- this.markModified("images", "blockImages");
970
- this.save();
919
+ this.setNestedGlobalSetting("images", "blockImages", blocked);
971
920
  }
972
921
 
973
922
  getEnabledModels(): string[] | undefined {
@@ -975,9 +924,7 @@ export class SettingsManager {
975
924
  }
976
925
 
977
926
  setEnabledModels(patterns: string[] | undefined): void {
978
- this.globalSettings.enabledModels = patterns;
979
- this.markModified("enabledModels");
980
- this.save();
927
+ this.setGlobalSetting("enabledModels", patterns);
981
928
  }
982
929
 
983
930
  getDoubleEscapeAction(): "fork" | "tree" | "none" {
@@ -985,9 +932,7 @@ export class SettingsManager {
985
932
  }
986
933
 
987
934
  setDoubleEscapeAction(action: "fork" | "tree" | "none"): void {
988
- this.globalSettings.doubleEscapeAction = action;
989
- this.markModified("doubleEscapeAction");
990
- this.save();
935
+ this.setGlobalSetting("doubleEscapeAction", action);
991
936
  }
992
937
 
993
938
  getTreeFilterMode(): "default" | "no-tools" | "user-only" | "labeled-only" | "all" {
@@ -997,9 +942,7 @@ export class SettingsManager {
997
942
  }
998
943
 
999
944
  setTreeFilterMode(mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): void {
1000
- this.globalSettings.treeFilterMode = mode;
1001
- this.markModified("treeFilterMode");
1002
- this.save();
945
+ this.setGlobalSetting("treeFilterMode", mode);
1003
946
  }
1004
947
 
1005
948
  getShowHardwareCursor(): boolean {
@@ -1007,9 +950,7 @@ export class SettingsManager {
1007
950
  }
1008
951
 
1009
952
  setShowHardwareCursor(enabled: boolean): void {
1010
- this.globalSettings.showHardwareCursor = enabled;
1011
- this.markModified("showHardwareCursor");
1012
- this.save();
953
+ this.setGlobalSetting("showHardwareCursor", enabled);
1013
954
  }
1014
955
 
1015
956
  getEditorPaddingX(): number {
@@ -1017,9 +958,7 @@ export class SettingsManager {
1017
958
  }
1018
959
 
1019
960
  setEditorPaddingX(padding: number): void {
1020
- this.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));
1021
- this.markModified("editorPaddingX");
1022
- this.save();
961
+ this.setGlobalSetting("editorPaddingX", Math.max(0, Math.min(3, Math.floor(padding))));
1023
962
  }
1024
963
 
1025
964
  getAutocompleteMaxVisible(): number {
@@ -1027,9 +966,7 @@ export class SettingsManager {
1027
966
  }
1028
967
 
1029
968
  setAutocompleteMaxVisible(maxVisible: number): void {
1030
- this.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));
1031
- this.markModified("autocompleteMaxVisible");
1032
- this.save();
969
+ this.setGlobalSetting("autocompleteMaxVisible", Math.max(3, Math.min(20, Math.floor(maxVisible))));
1033
970
  }
1034
971
 
1035
972
  getRespectGitignoreInPicker(): boolean {
@@ -1037,9 +974,7 @@ export class SettingsManager {
1037
974
  }
1038
975
 
1039
976
  setRespectGitignoreInPicker(value: boolean): void {
1040
- this.globalSettings.respectGitignoreInPicker = value;
1041
- this.markModified("respectGitignoreInPicker");
1042
- this.save();
977
+ this.setGlobalSetting("respectGitignoreInPicker", value);
1043
978
  }
1044
979
 
1045
980
  getSearchExcludeDirs(): string[] {
@@ -1047,9 +982,7 @@ export class SettingsManager {
1047
982
  }
1048
983
 
1049
984
  setSearchExcludeDirs(dirs: string[]): void {
1050
- this.globalSettings.searchExcludeDirs = dirs.filter(Boolean);
1051
- this.markModified("searchExcludeDirs");
1052
- this.save();
985
+ this.setGlobalSetting("searchExcludeDirs", dirs.filter(Boolean));
1053
986
  }
1054
987
 
1055
988
  getCodeBlockIndent(): string {
@@ -1095,12 +1028,7 @@ export class SettingsManager {
1095
1028
  }
1096
1029
 
1097
1030
  setFallbackEnabled(enabled: boolean): void {
1098
- if (!this.globalSettings.fallback) {
1099
- this.globalSettings.fallback = {};
1100
- }
1101
- this.globalSettings.fallback.enabled = enabled;
1102
- this.markModified("fallback", "enabled");
1103
- this.save();
1031
+ this.setNestedGlobalSetting("fallback", "enabled", enabled);
1104
1032
  }
1105
1033
 
1106
1034
  getFallbackChains(): Record<string, FallbackChainEntry[]> {
@@ -1149,12 +1077,7 @@ export class SettingsManager {
1149
1077
  }
1150
1078
 
1151
1079
  setModelDiscoveryEnabled(enabled: boolean): void {
1152
- if (!this.globalSettings.modelDiscovery) {
1153
- this.globalSettings.modelDiscovery = {};
1154
- }
1155
- this.globalSettings.modelDiscovery.enabled = enabled;
1156
- this.markModified("modelDiscovery", "enabled");
1157
- this.save();
1080
+ this.setNestedGlobalSetting("modelDiscovery", "enabled", enabled);
1158
1081
  }
1159
1082
 
1160
1083
  getEditMode(): "standard" | "hashline" {
@@ -1162,8 +1085,6 @@ export class SettingsManager {
1162
1085
  }
1163
1086
 
1164
1087
  setEditMode(mode: "standard" | "hashline"): void {
1165
- this.globalSettings.editMode = mode;
1166
- this.markModified("editMode");
1167
- this.save();
1088
+ this.setGlobalSetting("editMode", mode);
1168
1089
  }
1169
1090
  }
@@ -4,6 +4,7 @@ import { homedir } from "os";
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "path";
5
5
  import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
6
6
  import { parseFrontmatter } from "../utils/frontmatter.js";
7
+ import { toPosixPath } from "../utils/path-display.js";
7
8
  import type { ResourceDiagnostic } from "./diagnostics.js";
8
9
 
9
10
  /** Max name length per spec */
@@ -16,10 +17,6 @@ const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
16
17
 
17
18
  type IgnoreMatcher = ReturnType<typeof ignore>;
18
19
 
19
- function toPosixPath(p: string): string {
20
- return p.split(sep).join("/");
21
- }
22
-
23
20
  function prefixIgnorePattern(line: string, prefix: string): string | null {
24
21
  const trimmed = line.trim();
25
22
  if (!trimmed) return null;
@@ -128,14 +128,8 @@ export {
128
128
  discoverAndLoadExtensions,
129
129
  ExtensionRunner,
130
130
  importExtensionModule,
131
- isBashToolResult,
132
- isEditToolResult,
133
- isFindToolResult,
134
- isGrepToolResult,
135
- isLsToolResult,
136
- isReadToolResult,
137
131
  isToolCallEventType,
138
- isWriteToolResult,
132
+ isToolResultEventType,
139
133
  wrapRegisteredTool,
140
134
  wrapRegisteredTools,
141
135
  wrapToolsWithExtensions,
@@ -1,7 +1,6 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { unlink } from "node:fs/promises";
4
- import * as os from "node:os";
5
4
  import {
6
5
  type Component,
7
6
  Container,
@@ -17,21 +16,19 @@ import {
17
16
  import { KeybindingsManager } from "../../../core/keybindings.js";
18
17
  import type { SessionInfo, SessionListProgress } from "../../../core/session-manager.js";
19
18
  import { theme } from "../theme/theme.js";
19
+ import { shortenPath } from "../utils/shorten-path.js";
20
20
  import { DynamicBorder } from "./dynamic-border.js";
21
21
  import { appKey, appKeyHint, keyHint } from "./keybinding-hints.js";
22
22
  import { filterAndSortSessions, hasSessionName, type NameFilter, type SortMode } from "./session-selector-search.js";
23
+ import {
24
+ applyRowHighlight,
25
+ buildTreePrefix,
26
+ computeScrollWindow,
27
+ renderCursor,
28
+ } from "./tree-render-utils.js";
23
29
 
24
30
  type SessionScope = "current" | "all";
25
31
 
26
- function shortenPath(path: string): string {
27
- const home = os.homedir();
28
- if (!path) return path;
29
- if (path.startsWith(home)) {
30
- return `~${path.slice(home.length)}`;
31
- }
32
- return path;
33
- }
34
-
35
32
  function formatSessionDate(date: Date): string {
36
33
  const now = new Date();
37
34
  const diffMs = now.getTime() - date.getTime();
@@ -420,11 +417,11 @@ class SessionList implements Component, Focusable {
420
417
  }
421
418
 
422
419
  // Calculate visible range with scrolling
423
- const startIndex = Math.max(
424
- 0,
425
- Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredSessions.length - this.maxVisible),
420
+ const { startIndex, endIndex } = computeScrollWindow(
421
+ this.selectedIndex,
422
+ this.filteredSessions.length,
423
+ this.maxVisible,
426
424
  );
427
- const endIndex = Math.min(startIndex + this.maxVisible, this.filteredSessions.length);
428
425
 
429
426
  // Render visible sessions (one line each with tree structure)
430
427
  for (let i = startIndex; i < endIndex; i++) {
@@ -435,7 +432,7 @@ class SessionList implements Component, Focusable {
435
432
  const isCurrent = this.currentSessionFilePath === session.path;
436
433
 
437
434
  // Build tree prefix
438
- const prefix = this.buildTreePrefix(node);
435
+ const prefix = this.buildNodeTreePrefix(node);
439
436
 
440
437
  // Session display text (name or first message)
441
438
  const hasName = !!session.name;
@@ -454,7 +451,7 @@ class SessionList implements Component, Focusable {
454
451
  }
455
452
 
456
453
  // Cursor
457
- const cursor = isSelected ? theme.fg("accent", "› ") : " ";
454
+ const cursor = renderCursor(isSelected);
458
455
 
459
456
  // Calculate available width for message
460
457
  const prefixWidth = visibleWidth(prefix);
@@ -483,11 +480,8 @@ class SessionList implements Component, Focusable {
483
480
  const spacing = Math.max(1, width - leftWidth - visibleWidth(rightPart));
484
481
  const styledRight = theme.fg(isConfirmingDelete ? "error" : "dim", rightPart);
485
482
 
486
- let line = leftPart + " ".repeat(spacing) + styledRight;
487
- if (isSelected) {
488
- line = theme.bg("selectedBg", line);
489
- }
490
- lines.push(truncateToWidth(line, width));
483
+ const line = leftPart + " ".repeat(spacing) + styledRight;
484
+ lines.push(applyRowHighlight(line, isSelected, width));
491
485
  }
492
486
 
493
487
  // Add scroll indicator if needed
@@ -500,14 +494,8 @@ class SessionList implements Component, Focusable {
500
494
  return lines;
501
495
  }
502
496
 
503
- private buildTreePrefix(node: FlatSessionNode): string {
504
- if (node.depth === 0) {
505
- return "";
506
- }
507
-
508
- const parts = node.ancestorContinues.map((continues) => (continues ? "│ " : " "));
509
- const branch = node.isLast ? "└─ " : "├─ ";
510
- return parts.join("") + branch;
497
+ private buildNodeTreePrefix(node: FlatSessionNode): string {
498
+ return buildTreePrefix(node.ancestorContinues, node.isLast, node.depth);
511
499
  }
512
500
 
513
501
  handleInput(keyData: string): void {
@@ -1,4 +1,3 @@
1
- import * as os from "node:os";
2
1
  import {
3
2
  Box,
4
3
  Container,
@@ -18,6 +17,7 @@ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "../../../core/
18
17
  import { convertToPng } from "../../../utils/image-convert.js";
19
18
  import { sanitizeBinaryOutput } from "../../../utils/shell.js";
20
19
  import { getLanguageFromPath, highlightCode, theme } from "../theme/theme.js";
20
+ import { shortenPath } from "../utils/shorten-path.js";
21
21
  import { renderDiff } from "./diff.js";
22
22
  import { keyHint } from "./keybinding-hints.js";
23
23
  import { truncateToVisualLines } from "./visual-truncate.js";
@@ -28,18 +28,6 @@ const BASH_PREVIEW_LINES = 5;
28
28
  // to keep multiline tokenization mostly correct without re-highlighting the full file.
29
29
  const WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;
30
30
 
31
- /**
32
- * Convert absolute path to tilde notation if it's in home directory
33
- */
34
- function shortenPath(path: unknown): string {
35
- if (typeof path !== "string") return "";
36
- const home = os.homedir();
37
- if (path.startsWith(home)) {
38
- return `~${path.slice(home.length)}`;
39
- }
40
- return path;
41
- }
42
-
43
31
  /**
44
32
  * Replace tabs with spaces for consistent rendering
45
33
  */