actoviq-agent-sdk 0.4.21 → 0.4.22

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 (278) hide show
  1. package/README-zh.md +50 -113
  2. package/README.md +51 -164
  3. package/assets/hadamard-icon.ico +0 -0
  4. package/assets/hadamard-icon.png +0 -0
  5. package/bin/hadamard-gui.js +31 -12
  6. package/dist/src/codeIntel/codeIntelligenceService.d.ts +16 -0
  7. package/dist/src/codeIntel/codeIntelligenceService.d.ts.map +1 -1
  8. package/dist/src/codeIntel/codeIntelligenceService.js +87 -2
  9. package/dist/src/codeIntel/codeIntelligenceService.js.map +1 -1
  10. package/dist/src/codeIntel/codeIntelligenceTools.d.ts.map +1 -1
  11. package/dist/src/codeIntel/codeIntelligenceTools.js +6 -0
  12. package/dist/src/codeIntel/codeIntelligenceTools.js.map +1 -1
  13. package/dist/src/codeIntel/index.d.ts +1 -0
  14. package/dist/src/codeIntel/index.d.ts.map +1 -1
  15. package/dist/src/codeIntel/index.js +1 -0
  16. package/dist/src/codeIntel/index.js.map +1 -1
  17. package/dist/src/codeIntel/languageServerPresets.d.ts +13 -0
  18. package/dist/src/codeIntel/languageServerPresets.d.ts.map +1 -0
  19. package/dist/src/codeIntel/languageServerPresets.js +51 -0
  20. package/dist/src/codeIntel/languageServerPresets.js.map +1 -0
  21. package/dist/src/codeIntel/languageServerRegistry.d.ts +1 -0
  22. package/dist/src/codeIntel/languageServerRegistry.d.ts.map +1 -1
  23. package/dist/src/codeIntel/languageServerRegistry.js +2 -2
  24. package/dist/src/codeIntel/languageServerRegistry.js.map +1 -1
  25. package/dist/src/config/resolveRuntimeConfig.d.ts.map +1 -1
  26. package/dist/src/config/resolveRuntimeConfig.js +5 -0
  27. package/dist/src/config/resolveRuntimeConfig.js.map +1 -1
  28. package/dist/src/extensions/builtInExtensions.d.ts +61 -0
  29. package/dist/src/extensions/builtInExtensions.d.ts.map +1 -0
  30. package/dist/src/extensions/builtInExtensions.js +218 -0
  31. package/dist/src/extensions/builtInExtensions.js.map +1 -0
  32. package/dist/src/extensions/filterOutputPolicy.d.ts +21 -0
  33. package/dist/src/extensions/filterOutputPolicy.d.ts.map +1 -0
  34. package/dist/src/extensions/filterOutputPolicy.js +121 -0
  35. package/dist/src/extensions/filterOutputPolicy.js.map +1 -0
  36. package/dist/src/extensions/securityPolicy.d.ts +27 -0
  37. package/dist/src/extensions/securityPolicy.d.ts.map +1 -0
  38. package/dist/src/extensions/securityPolicy.js +238 -0
  39. package/dist/src/extensions/securityPolicy.js.map +1 -0
  40. package/dist/src/extensions/sessionCostTracker.d.ts +63 -0
  41. package/dist/src/extensions/sessionCostTracker.d.ts.map +1 -0
  42. package/dist/src/extensions/sessionCostTracker.js +213 -0
  43. package/dist/src/extensions/sessionCostTracker.js.map +1 -0
  44. package/dist/src/extensions/taskNotifications.d.ts +31 -0
  45. package/dist/src/extensions/taskNotifications.d.ts.map +1 -0
  46. package/dist/src/extensions/taskNotifications.js +50 -0
  47. package/dist/src/extensions/taskNotifications.js.map +1 -0
  48. package/dist/src/extensions/usageBar.d.ts +35 -0
  49. package/dist/src/extensions/usageBar.d.ts.map +1 -0
  50. package/dist/src/extensions/usageBar.js +67 -0
  51. package/dist/src/extensions/usageBar.js.map +1 -0
  52. package/dist/src/gui/contextRailStore.d.ts +13 -0
  53. package/dist/src/gui/contextRailStore.d.ts.map +1 -1
  54. package/dist/src/gui/contextRailStore.js +16 -0
  55. package/dist/src/gui/contextRailStore.js.map +1 -1
  56. package/dist/src/gui/electronMain.js +45 -5
  57. package/dist/src/gui/electronMain.js.map +1 -1
  58. package/dist/src/gui/guiDesignClientScript.d.ts.map +1 -1
  59. package/dist/src/gui/guiDesignClientScript.js +31 -0
  60. package/dist/src/gui/guiDesignClientScript.js.map +1 -1
  61. package/dist/src/gui/guiUsageRoutingAssets.d.ts +7 -0
  62. package/dist/src/gui/guiUsageRoutingAssets.d.ts.map +1 -0
  63. package/dist/src/gui/guiUsageRoutingAssets.js +509 -0
  64. package/dist/src/gui/guiUsageRoutingAssets.js.map +1 -0
  65. package/dist/src/gui/guiUsageRoutingHttpController.d.ts +11 -0
  66. package/dist/src/gui/guiUsageRoutingHttpController.d.ts.map +1 -0
  67. package/dist/src/gui/guiUsageRoutingHttpController.js +125 -0
  68. package/dist/src/gui/guiUsageRoutingHttpController.js.map +1 -0
  69. package/dist/src/gui/guiUsageRoutingRuntime.d.ts +36 -0
  70. package/dist/src/gui/guiUsageRoutingRuntime.d.ts.map +1 -0
  71. package/dist/src/gui/guiUsageRoutingRuntime.js +98 -0
  72. package/dist/src/gui/guiUsageRoutingRuntime.js.map +1 -0
  73. package/dist/src/gui/hadamardGui.d.ts +5 -0
  74. package/dist/src/gui/hadamardGui.d.ts.map +1 -1
  75. package/dist/src/gui/hadamardGui.js +159 -16
  76. package/dist/src/gui/hadamardGui.js.map +1 -1
  77. package/dist/src/gui/hadamardGuiAssets.d.ts.map +1 -1
  78. package/dist/src/gui/hadamardGuiAssets.js +297 -41
  79. package/dist/src/gui/hadamardGuiAssets.js.map +1 -1
  80. package/dist/src/index.d.ts +32 -2
  81. package/dist/src/index.d.ts.map +1 -1
  82. package/dist/src/index.js +16 -1
  83. package/dist/src/index.js.map +1 -1
  84. package/dist/src/keyway/electronSecretStore.d.ts +37 -0
  85. package/dist/src/keyway/electronSecretStore.d.ts.map +1 -0
  86. package/dist/src/keyway/electronSecretStore.js +105 -0
  87. package/dist/src/keyway/electronSecretStore.js.map +1 -0
  88. package/dist/src/keyway/embeddedKeyway.d.ts +34 -0
  89. package/dist/src/keyway/embeddedKeyway.d.ts.map +1 -0
  90. package/dist/src/keyway/embeddedKeyway.js +81 -0
  91. package/dist/src/keyway/embeddedKeyway.js.map +1 -0
  92. package/dist/src/keyway/keywayLoopbackGateway.d.ts +30 -0
  93. package/dist/src/keyway/keywayLoopbackGateway.d.ts.map +1 -0
  94. package/dist/src/keyway/keywayLoopbackGateway.js +71 -0
  95. package/dist/src/keyway/keywayLoopbackGateway.js.map +1 -0
  96. package/dist/src/keyway/keywayMigrationService.d.ts +44 -0
  97. package/dist/src/keyway/keywayMigrationService.d.ts.map +1 -0
  98. package/dist/src/keyway/keywayMigrationService.js +219 -0
  99. package/dist/src/keyway/keywayMigrationService.js.map +1 -0
  100. package/dist/src/keyway/keywayModelApi.d.ts +24 -0
  101. package/dist/src/keyway/keywayModelApi.d.ts.map +1 -0
  102. package/dist/src/keyway/keywayModelApi.js +106 -0
  103. package/dist/src/keyway/keywayModelApi.js.map +1 -0
  104. package/dist/src/keyway/keywayPorts.d.ts +189 -0
  105. package/dist/src/keyway/keywayPorts.d.ts.map +1 -0
  106. package/dist/src/keyway/keywayPorts.js +2 -0
  107. package/dist/src/keyway/keywayPorts.js.map +1 -0
  108. package/dist/src/keyway/keywayProviderExecutor.d.ts +30 -0
  109. package/dist/src/keyway/keywayProviderExecutor.d.ts.map +1 -0
  110. package/dist/src/keyway/keywayProviderExecutor.js +257 -0
  111. package/dist/src/keyway/keywayProviderExecutor.js.map +1 -0
  112. package/dist/src/keyway/routingComposition.d.ts +18 -0
  113. package/dist/src/keyway/routingComposition.d.ts.map +1 -0
  114. package/dist/src/keyway/routingComposition.js +19 -0
  115. package/dist/src/keyway/routingComposition.js.map +1 -0
  116. package/dist/src/keyway/usageRoutingAdminService.d.ts +86 -0
  117. package/dist/src/keyway/usageRoutingAdminService.d.ts.map +1 -0
  118. package/dist/src/keyway/usageRoutingAdminService.js +384 -0
  119. package/dist/src/keyway/usageRoutingAdminService.js.map +1 -0
  120. package/dist/src/nativeCli/crushManagedClient.d.ts +84 -0
  121. package/dist/src/nativeCli/crushManagedClient.d.ts.map +1 -0
  122. package/dist/src/nativeCli/crushManagedClient.js +978 -0
  123. package/dist/src/nativeCli/crushManagedClient.js.map +1 -0
  124. package/dist/src/nativeCli/crushNativeCliClient.d.ts +19 -0
  125. package/dist/src/nativeCli/crushNativeCliClient.d.ts.map +1 -0
  126. package/dist/src/nativeCli/crushNativeCliClient.js +243 -0
  127. package/dist/src/nativeCli/crushNativeCliClient.js.map +1 -0
  128. package/dist/src/nativeCli/keywayNativeCliAdapter.d.ts +31 -0
  129. package/dist/src/nativeCli/keywayNativeCliAdapter.d.ts.map +1 -0
  130. package/dist/src/nativeCli/keywayNativeCliAdapter.js +35 -0
  131. package/dist/src/nativeCli/keywayNativeCliAdapter.js.map +1 -0
  132. package/dist/src/nativeCli/nativeCliAuth.d.ts +24 -0
  133. package/dist/src/nativeCli/nativeCliAuth.d.ts.map +1 -0
  134. package/dist/src/nativeCli/nativeCliAuth.js +327 -0
  135. package/dist/src/nativeCli/nativeCliAuth.js.map +1 -0
  136. package/dist/src/nativeCli/nativeCliClient.d.ts +16 -0
  137. package/dist/src/nativeCli/nativeCliClient.d.ts.map +1 -0
  138. package/dist/src/nativeCli/nativeCliClient.js +575 -0
  139. package/dist/src/nativeCli/nativeCliClient.js.map +1 -0
  140. package/dist/src/nativeCli/nativeCliCodewhaleProtocol.d.ts +18 -0
  141. package/dist/src/nativeCli/nativeCliCodewhaleProtocol.d.ts.map +1 -0
  142. package/dist/src/nativeCli/nativeCliCodewhaleProtocol.js +376 -0
  143. package/dist/src/nativeCli/nativeCliCodewhaleProtocol.js.map +1 -0
  144. package/dist/src/nativeCli/nativeCliContracts.d.ts +22 -0
  145. package/dist/src/nativeCli/nativeCliContracts.d.ts.map +1 -0
  146. package/dist/src/nativeCli/nativeCliContracts.js +2 -0
  147. package/dist/src/nativeCli/nativeCliContracts.js.map +1 -0
  148. package/dist/src/nativeCli/nativeCliCursorProtocol.d.ts +7 -0
  149. package/dist/src/nativeCli/nativeCliCursorProtocol.d.ts.map +1 -0
  150. package/dist/src/nativeCli/nativeCliCursorProtocol.js +210 -0
  151. package/dist/src/nativeCli/nativeCliCursorProtocol.js.map +1 -0
  152. package/dist/src/nativeCli/nativeCliEnvironment.d.ts +3 -0
  153. package/dist/src/nativeCli/nativeCliEnvironment.d.ts.map +1 -0
  154. package/dist/src/nativeCli/nativeCliEnvironment.js +17 -0
  155. package/dist/src/nativeCli/nativeCliEnvironment.js.map +1 -0
  156. package/dist/src/nativeCli/nativeCliExecResolver.d.ts +26 -0
  157. package/dist/src/nativeCli/nativeCliExecResolver.d.ts.map +1 -0
  158. package/dist/src/nativeCli/nativeCliExecResolver.js +152 -0
  159. package/dist/src/nativeCli/nativeCliExecResolver.js.map +1 -0
  160. package/dist/src/nativeCli/nativeCliPiProtocol.d.ts +15 -0
  161. package/dist/src/nativeCli/nativeCliPiProtocol.d.ts.map +1 -0
  162. package/dist/src/nativeCli/nativeCliPiProtocol.js +329 -0
  163. package/dist/src/nativeCli/nativeCliPiProtocol.js.map +1 -0
  164. package/dist/src/nativeCli/nativeCliProcessTree.d.ts +3 -0
  165. package/dist/src/nativeCli/nativeCliProcessTree.d.ts.map +1 -0
  166. package/dist/src/nativeCli/nativeCliProcessTree.js +104 -0
  167. package/dist/src/nativeCli/nativeCliProcessTree.js.map +1 -0
  168. package/dist/src/nativeCli/reasonixAcpSession.d.ts +35 -0
  169. package/dist/src/nativeCli/reasonixAcpSession.d.ts.map +1 -0
  170. package/dist/src/nativeCli/reasonixAcpSession.js +472 -0
  171. package/dist/src/nativeCli/reasonixAcpSession.js.map +1 -0
  172. package/dist/src/nativeCli/reasonixManagedClient.d.ts +56 -0
  173. package/dist/src/nativeCli/reasonixManagedClient.d.ts.map +1 -0
  174. package/dist/src/nativeCli/reasonixManagedClient.js +293 -0
  175. package/dist/src/nativeCli/reasonixManagedClient.js.map +1 -0
  176. package/dist/src/nativeCli/reasonixNativeCliClient.d.ts +20 -0
  177. package/dist/src/nativeCli/reasonixNativeCliClient.d.ts.map +1 -0
  178. package/dist/src/nativeCli/reasonixNativeCliClient.js +317 -0
  179. package/dist/src/nativeCli/reasonixNativeCliClient.js.map +1 -0
  180. package/dist/src/parity/bridgeExecResolver.d.ts +2 -25
  181. package/dist/src/parity/bridgeExecResolver.d.ts.map +1 -1
  182. package/dist/src/parity/bridgeExecResolver.js +2 -151
  183. package/dist/src/parity/bridgeExecResolver.js.map +1 -1
  184. package/dist/src/parity/bridgeProcessTree.d.ts +2 -2
  185. package/dist/src/parity/bridgeProcessTree.d.ts.map +1 -1
  186. package/dist/src/parity/bridgeProcessTree.js +2 -82
  187. package/dist/src/parity/bridgeProcessTree.js.map +1 -1
  188. package/dist/src/parity/crushManagedClient.d.ts +2 -83
  189. package/dist/src/parity/crushManagedClient.d.ts.map +1 -1
  190. package/dist/src/parity/crushManagedClient.js +2 -977
  191. package/dist/src/parity/crushManagedClient.js.map +1 -1
  192. package/dist/src/parity/externalCliAuth.d.ts +2 -22
  193. package/dist/src/parity/externalCliAuth.d.ts.map +1 -1
  194. package/dist/src/parity/externalCliAuth.js +2 -295
  195. package/dist/src/parity/externalCliAuth.js.map +1 -1
  196. package/dist/src/parity/hadamardBridgeSdk.d.ts.map +1 -1
  197. package/dist/src/parity/hadamardBridgeSdk.js +14 -1
  198. package/dist/src/parity/hadamardBridgeSdk.js.map +1 -1
  199. package/dist/src/parity/nativeCliBridgeAdapter.d.ts +6 -0
  200. package/dist/src/parity/nativeCliBridgeAdapter.d.ts.map +1 -0
  201. package/dist/src/parity/nativeCliBridgeAdapter.js +38 -0
  202. package/dist/src/parity/nativeCliBridgeAdapter.js.map +1 -0
  203. package/dist/src/parity/reasonixAcpSession.d.ts +2 -34
  204. package/dist/src/parity/reasonixAcpSession.d.ts.map +1 -1
  205. package/dist/src/parity/reasonixAcpSession.js +2 -471
  206. package/dist/src/parity/reasonixAcpSession.js.map +1 -1
  207. package/dist/src/parity/reasonixManagedClient.d.ts +2 -55
  208. package/dist/src/parity/reasonixManagedClient.d.ts.map +1 -1
  209. package/dist/src/parity/reasonixManagedClient.js +2 -292
  210. package/dist/src/parity/reasonixManagedClient.js.map +1 -1
  211. package/dist/src/provider/openai-client.js +2 -2
  212. package/dist/src/provider/openai-client.js.map +1 -1
  213. package/dist/src/provider/openai-model-api.d.ts.map +1 -1
  214. package/dist/src/provider/openai-model-api.js +5 -1
  215. package/dist/src/provider/openai-model-api.js.map +1 -1
  216. package/dist/src/runtime/agentClient.d.ts +14 -1
  217. package/dist/src/runtime/agentClient.d.ts.map +1 -1
  218. package/dist/src/runtime/agentClient.js +60 -6
  219. package/dist/src/runtime/agentClient.js.map +1 -1
  220. package/dist/src/runtime/toolPolicyPipeline.d.ts +32 -1
  221. package/dist/src/runtime/toolPolicyPipeline.d.ts.map +1 -1
  222. package/dist/src/runtime/toolPolicyPipeline.js +43 -3
  223. package/dist/src/runtime/toolPolicyPipeline.js.map +1 -1
  224. package/dist/src/tui/hadamardTuiController.d.ts.map +1 -1
  225. package/dist/src/tui/hadamardTuiController.js +62 -8
  226. package/dist/src/tui/hadamardTuiController.js.map +1 -1
  227. package/dist/src/tui/tuiBasicCommandHandler.d.ts +4 -0
  228. package/dist/src/tui/tuiBasicCommandHandler.d.ts.map +1 -1
  229. package/dist/src/tui/tuiBasicCommandHandler.js +23 -2
  230. package/dist/src/tui/tuiBasicCommandHandler.js.map +1 -1
  231. package/dist/src/tui/tuiCatalogCommandHandler.d.ts +2 -0
  232. package/dist/src/tui/tuiCatalogCommandHandler.d.ts.map +1 -1
  233. package/dist/src/tui/tuiCatalogCommandHandler.js +10 -1
  234. package/dist/src/tui/tuiCatalogCommandHandler.js.map +1 -1
  235. package/dist/src/tui/tuiUsageRoutingRuntime.d.ts +22 -0
  236. package/dist/src/tui/tuiUsageRoutingRuntime.d.ts.map +1 -0
  237. package/dist/src/tui/tuiUsageRoutingRuntime.js +81 -0
  238. package/dist/src/tui/tuiUsageRoutingRuntime.js.map +1 -0
  239. package/dist/src/types.d.ts +16 -0
  240. package/dist/src/types.d.ts.map +1 -1
  241. package/dist/src/types.js.map +1 -1
  242. package/dist/src/ui/commandSurface.d.ts.map +1 -1
  243. package/dist/src/ui/commandSurface.js +45 -1
  244. package/dist/src/ui/commandSurface.js.map +1 -1
  245. package/dist/src/ui/extensionsCommandView.d.ts +18 -0
  246. package/dist/src/ui/extensionsCommandView.d.ts.map +1 -0
  247. package/dist/src/ui/extensionsCommandView.js +82 -0
  248. package/dist/src/ui/extensionsCommandView.js.map +1 -0
  249. package/dist/src/ui/lspCommandView.d.ts +17 -0
  250. package/dist/src/ui/lspCommandView.d.ts.map +1 -0
  251. package/dist/src/ui/lspCommandView.js +25 -0
  252. package/dist/src/ui/lspCommandView.js.map +1 -0
  253. package/dist/src/ui/usageRoutingCommand.d.ts +13 -0
  254. package/dist/src/ui/usageRoutingCommand.d.ts.map +1 -0
  255. package/dist/src/ui/usageRoutingCommand.js +224 -0
  256. package/dist/src/ui/usageRoutingCommand.js.map +1 -0
  257. package/dist/src/usage/budgetService.d.ts +28 -0
  258. package/dist/src/usage/budgetService.d.ts.map +1 -0
  259. package/dist/src/usage/budgetService.js +50 -0
  260. package/dist/src/usage/budgetService.js.map +1 -0
  261. package/dist/src/usage/contracts.d.ts +149 -0
  262. package/dist/src/usage/contracts.d.ts.map +1 -0
  263. package/dist/src/usage/contracts.js +2 -0
  264. package/dist/src/usage/contracts.js.map +1 -0
  265. package/dist/src/usage/index.d.ts +7 -0
  266. package/dist/src/usage/index.d.ts.map +1 -0
  267. package/dist/src/usage/index.js +4 -0
  268. package/dist/src/usage/index.js.map +1 -0
  269. package/dist/src/usage/usageLedger.d.ts +19 -0
  270. package/dist/src/usage/usageLedger.d.ts.map +1 -0
  271. package/dist/src/usage/usageLedger.js +389 -0
  272. package/dist/src/usage/usageLedger.js.map +1 -0
  273. package/dist/src/usage/usageQueryService.d.ts +12 -0
  274. package/dist/src/usage/usageQueryService.d.ts.map +1 -0
  275. package/dist/src/usage/usageQueryService.js +29 -0
  276. package/dist/src/usage/usageQueryService.js.map +1 -0
  277. package/package.json +14 -2
  278. package/scripts/prepare-gui-launcher.mjs +62 -0
@@ -9,6 +9,7 @@ import { PROJECT_STATUSES, PROJECT_STATUS_LABELS } from './projectMeta.js';
9
9
  import { renderMarkdown } from './guiMarkdown.js';
10
10
  import { detectEditorLanguage, highlightCode } from './guiSyntaxHighlight.js';
11
11
  import { getTranscriptClientScript, getTranscriptStyles } from './transcript/index.js';
12
+ import { usageRoutingBindings, usageRoutingClient, usageRoutingConfigurationHeaderHtml, usageRoutingConfigurationPageHtml, usageRoutingHtml, usageRoutingStyles } from './guiUsageRoutingAssets.js';
12
13
  import { formatContextWindowTokens, STANDARD_CONTEXT_WINDOWS, } from '../config/modelContextWindow.js';
13
14
  import { GUI_SESSION_CENTER_OPEN_CLIENT_SCRIPT, GUI_SESSION_CREATE_CLIENT_SCRIPT, } from './guiSessionClientScript.js';
14
15
  import { GUI_DESIGN_CLIENT_SCRIPT } from './guiDesignClientScript.js';
@@ -93,10 +94,11 @@ export function createHadamardGuiHtml() {
93
94
  </head>
94
95
  <body>
95
96
  <div class="app" id="appView">
96
- <aside class="sidebar">
97
+ <aside class="sidebar" id="appSidebar">
97
98
  <div class="brand">
98
99
  <span class="brand-mark">${guiIcon('logo')}</span>
99
100
  <span class="brand-name">Hadamard</span>
101
+ <button type="button" id="sidebarCollapseBtn" class="icon-btn sidebar-collapse-btn" aria-label="Collapse sidebar" title="Collapse sidebar" aria-expanded="true" aria-controls="appSidebar">${guiIcon('panelLeft')}</button>
100
102
  </div>
101
103
  <nav class="primary-nav" aria-label="Primary">
102
104
  <button id="navProject" class="nav-btn region-nav active" data-region="project" aria-label="Project" title="Project"><span class="nav-icon">${guiIcon('folder')}</span><span>Project</span></button>
@@ -124,6 +126,7 @@ export function createHadamardGuiHtml() {
124
126
  <button id="settingsBtn" class="nav-btn" aria-label="Settings" title="Settings"><span class="nav-icon">${guiIcon('gear')}</span><span>Settings</span></button>
125
127
  </div>
126
128
  </aside>
129
+ <button type="button" id="sidebarExpandBtn" class="sidebar-expand-fab hidden" aria-label="Expand sidebar" title="Expand sidebar" aria-expanded="false" aria-controls="appSidebar">${guiIcon('panelRight')}</button>
127
130
  <main class="chat" data-region="project" id="regionProject">
128
131
  <section class="project-overview" id="projectOverview">
129
132
  <header class="region-header">
@@ -134,6 +137,7 @@ export function createHadamardGuiHtml() {
134
137
  <div class="region-actions">
135
138
  <button type="button" id="overviewChatsBtn" class="pill-btn">Chats</button>
136
139
  <button type="button" id="overviewNewWorkspaceBtn" class="pill-btn">+ New workspace</button>
140
+ <button type="button" id="overviewRailToggleBtn" class="icon-btn" aria-label="Show panel" title="Show panel" aria-expanded="false" aria-controls="contextRail">${guiIcon('panelLeft')}</button>
137
141
  </div>
138
142
  </header>
139
143
  <div class="overview-toolbar">
@@ -171,7 +175,7 @@ export function createHadamardGuiHtml() {
171
175
  <button type="button" id="detailOpenLocationBtn" class="icon-btn" aria-label="Open workspace folder" title="Open workspace folder">${guiIcon('folder')}</button>
172
176
  <button type="button" id="detailNewConversationBtn" class="pill-btn">+ New conversation</button>
173
177
  <button type="button" id="detailConversationsBtn" class="icon-btn detail-conversations-toggle" aria-label="Hide conversations" title="Hide conversations" aria-expanded="true" aria-controls="projectDetailSidebar">${guiIcon('panelLeft')}</button>
174
- <button type="button" id="detailAuxPanelToggleBtn" class="icon-btn" title="Hide panel" aria-label="Hide panel" aria-pressed="true">${guiIcon('panelRight')}</button>
178
+ <button type="button" id="detailAuxPanelToggleBtn" class="icon-btn" title="Show panel" aria-label="Show panel" aria-pressed="false">${guiIcon('panelLeft')}</button>
175
179
  </div>
176
180
  </header>
177
181
  <div class="detail-body" id="detailBody"></div>
@@ -244,7 +248,7 @@ export function createHadamardGuiHtml() {
244
248
  <div class="workbench-chat">
245
249
  <section class="pane pane-chat active" id="pane-chat-default">
246
250
  <div class="chat-chrome">
247
- <section id="statusbar" class="statusbar"></section>
251
+ <section id="statusbar" class="statusbar"><span id="statusText"></span><span id="usagebar" class="usagebar hidden"></span></section>
248
252
  <div id="squadRoster" class="squad-roster hidden"></div>
249
253
  </div>
250
254
  <section id="contextBar" class="context-bar hidden"></section>
@@ -512,16 +516,8 @@ export function createHadamardGuiHtml() {
512
516
  <div class="region-body devices-region-body" id="regionDevicesBody"></div>
513
517
  </section>
514
518
  <section class="region hidden" data-region="bridge" id="regionBridge" aria-label="Configuration">
515
- <header class="region-header">
516
- <div class="region-titles">
517
- <h1>Configuration</h1>
518
- <p>Configure models, providers, and local API or CLI runtimes</p>
519
- </div>
520
- <div class="region-actions">
521
- <button type="button" id="bridgeNewConfig" class="pill-btn primary">+ New config</button>
522
- </div>
523
- </header>
524
- <div class="region-body bridge-region-body">
519
+ ${usageRoutingConfigurationHeaderHtml}
520
+ <div class="region-body bridge-region-body" id="configurationModelsPage">
525
521
  <section class="settings-group">
526
522
  <h2>Bridge mode</h2>
527
523
  <label class="check-row"><input id="bridgeModeEnabled" type="checkbox">Enable bridge mode</label>
@@ -544,6 +540,7 @@ export function createHadamardGuiHtml() {
544
540
  <div id="runtimeDiscoveryList" class="settings-card-list compact runtime-list"></div>
545
541
  </section>
546
542
  </div>
543
+ ${usageRoutingConfigurationPageHtml}
547
544
  </section>
548
545
  <aside class="context-rail hidden" id="contextRail" aria-label="Context panel"></aside>
549
546
  <div id="railToast" class="rail-toast hidden" role="status" aria-live="polite"></div>
@@ -863,6 +860,7 @@ export function createHadamardGuiHtml() {
863
860
  <section>
864
861
  <h2>Agent</h2>
865
862
  <button type="button" class="settings-tab" data-settings-tab="capabilities"><span class="settings-icon">${guiIcon('tools')}</span>Capabilities</button>
863
+ <button type="button" class="settings-tab" data-settings-tab="extensions"><span class="settings-icon">${guiIcon('plug')}</span>Extensions &amp; LSP</button>
866
864
  <button type="button" class="settings-tab" data-settings-tab="sessions"><span class="settings-icon">${guiIcon('chat')}</span>Chats</button>
867
865
  </section>
868
866
  <section>
@@ -982,6 +980,7 @@ export function createHadamardGuiHtml() {
982
980
  <div class="settings-action-row"><button type="button" id="externalCliHistoryMore" class="secondary-btn hidden">Load more</button></div>
983
981
  </div>
984
982
  </section>
983
+ ${usageRoutingHtml}
985
984
  <section class="settings-panel" data-settings-panel="appearance">
986
985
  <h1>Appearance</h1>
987
986
  <div class="settings-group two-col">
@@ -1033,6 +1032,19 @@ export function createHadamardGuiHtml() {
1033
1032
  <div id="settingsTeamsList" class="settings-card-list"></div>
1034
1033
  </div>
1035
1034
  </section>
1035
+ <section class="settings-panel" data-settings-panel="extensions">
1036
+ <h1>Extensions &amp; LSP</h1>
1037
+ <div class="settings-group">
1038
+ <h2>Built-in extensions</h2>
1039
+ <p class="muted">Enable Hadamard-owned runtime and interface features. Changes apply to subsequent runs.</p>
1040
+ <div id="settingsExtensionsList" class="settings-card-list"></div>
1041
+ </div>
1042
+ <div class="settings-group">
1043
+ <h2>Language servers</h2>
1044
+ <div class="settings-help-row"><span><strong>Detect installed language servers automatically</strong><small>Uses supported servers found on PATH when no explicit server with the same id is configured.</small></span><label class="switch-field"><input type="checkbox" id="settingsAutoDetectLanguageServers"></label></div>
1045
+ <div id="settingsLanguageServersList" class="settings-card-list compact"></div>
1046
+ </div>
1047
+ </section>
1036
1048
  <section class="settings-panel" data-settings-panel="sessions">
1037
1049
  <h1>Chats</h1>
1038
1050
  <div class="settings-group">
@@ -1740,14 +1752,14 @@ body[data-theme="dark"] {
1740
1752
  .project-doc-rich:focus { caret-color: var(--brand); }
1741
1753
  .project-doc-formatbar { display: none; align-items: center; gap: 4px; margin: -30px -38px 24px; padding: 7px 10px; border-bottom: 1px solid var(--border); background: var(--bg-surface); overflow-x: auto; position: sticky; top: -30px; z-index: 2; }
1742
1754
  .project-doc-scroll.editing .project-doc-formatbar { display: flex; }
1743
- .project-doc-formatbar button { flex: 0 0 auto; min-width: 30px; height: 28px; border: 0; border-radius: 6px; background: transparent; color: var(--text-2); font: inherit; font-size: 12px; font-weight: 650; }
1744
- .project-doc-formatbar button:hover { background: var(--surface-hover); color: var(--text-1); }
1755
+ .project-doc-formatbar button, .project-doc-formatbar select { flex: 0 0 auto; min-width: 30px; height: 28px; border: 0; border-radius: 6px; background: transparent; color: var(--text-2); font: inherit; font-size: 12px; font-weight: 650; } .project-doc-formatbar select { min-width: 50px; padding: 0 20px 0 8px; cursor: pointer; }
1756
+ .project-doc-formatbar button:hover, .project-doc-formatbar select:hover { background: var(--surface-hover); color: var(--text-1); } .project-doc-formatbar select:focus-visible { outline: 2px solid var(--border-active); outline-offset: -2px; }
1745
1757
  .project-doc-view.md-prose { font-size: 13px; line-height: 1.9; color: var(--text-1); cursor: text; }
1746
1758
  .project-doc-view.md-prose .design-header { font-size: 12px; letter-spacing: .01em; }
1747
1759
  .project-doc-view.md-prose .md-h:first-child { margin-top: 0; }
1748
1760
  .project-doc-view.md-prose h1.md-h { font-size: 1.2em; font-weight: 650; margin: 1em 0 .45em; line-height: 1.45; color: var(--text-1); }
1749
1761
  .project-doc-view.md-prose h2.md-h { font-size: 1.08em; font-weight: 650; margin: .85em 0 .4em; line-height: 1.45; color: var(--text-1); }
1750
- .project-doc-view.md-prose h3.md-h, .project-doc-view.md-prose h4.md-h { font-size: 1em; font-weight: 650; margin: .7em 0 .32em; line-height: 1.45; color: var(--text-1); }
1762
+ .project-doc-view.md-prose h3.md-h, .project-doc-view.md-prose h4.md-h, .project-doc-view.md-prose h5.md-h, .project-doc-view.md-prose h6.md-h { font-size: 1em; font-weight: 650; margin: .7em 0 .32em; line-height: 1.45; color: var(--text-1); }
1751
1763
  .project-doc-view.md-prose p.md-p { margin: 0 0 .8em; }
1752
1764
  .project-doc-view.md-prose p.md-p:last-child { margin-bottom: 0; }
1753
1765
  .project-doc-view.md-prose ul.md-ul, .project-doc-view.md-prose ol.md-ol { margin: .3em 0 .8em; padding-left: 1.25em; }
@@ -2715,7 +2727,7 @@ body[data-theme="dark"] .git-diff-line.hunk { color: #d2a8ff; }
2715
2727
  .graph-mode-pill { font-size: 11px; font-weight: 600; border-radius: 999px; padding: 3px 10px; background: var(--accent); color: var(--text-2); }
2716
2728
  .graph-unreachable { opacity: .65; }
2717
2729
  .context-rail { width: 320px; flex: 0 0 320px; border-left: 1px solid var(--border); background: var(--bg-app); overflow: auto; padding: 14px; }
2718
- .app { height: 100vh; display: flex; overflow: hidden; border: 1px solid var(--border); background: var(--bg-app); }
2730
+ .app { height: 100vh; display: flex; position: relative; overflow: hidden; border: 1px solid var(--border); background: var(--bg-app); }
2719
2731
  .sidebar {
2720
2732
  width: 240px;
2721
2733
  flex: 0 0 240px;
@@ -2727,6 +2739,16 @@ body[data-theme="dark"] .git-diff-line.hunk { color: #d2a8ff; }
2727
2739
  background: var(--bg-app);
2728
2740
  border-right: 1px solid var(--border);
2729
2741
  }
2742
+ .sidebar.collapsed { display: none; }
2743
+ .sidebar .sidebar-collapse-btn { margin-left: auto; width: 24px; height: 24px; min-height: 24px; padding: 0; display: inline-grid; place-items: center; color: var(--text-2); }
2744
+ .sidebar .sidebar-collapse-btn:hover { color: var(--text-1); }
2745
+ .sidebar-expand-fab { position: absolute; top: 12px; left: 12px; z-index: 20; width: 32px; height: 32px; min-height: 32px; padding: 0; display: inline-grid; place-items: center; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-surface); color: var(--text-2); cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,.1); }
2746
+ .sidebar-expand-fab:hover { color: var(--text-1); background: var(--surface-hover); }
2747
+ .sidebar-expand-fab .ui-icon, .sidebar .sidebar-collapse-btn .ui-icon { width: 15px; height: 15px; }
2748
+ @media (min-width: 861px) {
2749
+ .app:has(> .sidebar.collapsed) .region-header,
2750
+ .app:has(> .sidebar.collapsed) .topbar { padding-left: 54px; }
2751
+ }
2730
2752
  /* Sidebar is nav + Pinned/Recent only. Chat lists live in the project detail
2731
2753
  conversation sidebar; workspace open uses the overview "+ New workspace". */
2732
2754
  body[data-sidebar-mode="nav"] .sidebar .sidebar-footer .nav-btn span:not(.nav-icon) { display: inline; }
@@ -2918,7 +2940,7 @@ body[data-sidebar-mode="nav"] .sidebar .sidebar-footer .nav-btn span:not(.nav-ic
2918
2940
  .aux-splitter:hover, .aux-splitter.dragging { background: var(--brand); opacity: .55; }
2919
2941
  .workbench-split.aux-collapsed .aux-splitter,
2920
2942
  .workbench-split.aux-collapsed .aux-splitter { display: none; }
2921
- .aux-panel { flex: 0 0 var(--aux-panel-width, 340px); width: var(--aux-panel-width, 340px); min-width: 240px; max-width: min(70vw, 720px); border-left: 1px solid var(--border); background: var(--bg-surface); display: flex; flex-direction: column; min-height: 0; transition: flex-basis .15s ease, width .15s ease, min-width .15s ease; }
2943
+ .aux-panel { flex: 0 0 var(--aux-panel-width, 340px); width: var(--aux-panel-width, 340px); min-width: 240px; max-width: min(82vw, 1600px); border-left: 1px solid var(--border); background: var(--bg-surface); display: flex; flex-direction: column; min-height: 0; transition: flex-basis .15s ease, width .15s ease, min-width .15s ease; }
2922
2944
  .workbench-split.resizing-aux .aux-panel { transition: none; }
2923
2945
  .aux-panel.collapsed { flex: 0 0 40px; width: 40px; min-width: 40px; max-width: 40px; }
2924
2946
  .aux-panel.collapsed .aux-body,
@@ -2989,9 +3011,16 @@ body[data-sidebar-mode="nav"] .sidebar .sidebar-footer .nav-btn span:not(.nav-ic
2989
3011
  .aux-browser-frame-host { flex: 1 1 auto; min-height: 240px; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: #fff; }
2990
3012
  .aux-browser-frame { display: block; width: 100%; height: 100%; min-height: 240px; border: 0; }
2991
3013
  .aux-file-preview { margin: 0; padding: 10px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface-muted); font-size: 12px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; max-height: calc(100% - 40px); overflow: auto; }
3014
+ .aux-file-editor-head .aux-view-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
3015
+ .aux-file-editor-head .files-preview-modes { margin-left: auto; }
2992
3016
  .aux-file-editor-body { display: flex; flex-direction: column; overflow: hidden; }
2993
3017
  .aux-file-editor-path { flex: 0 0 auto; margin: 0 0 8px; font-size: 11.5px; word-break: break-all; }
2994
- .aux-file-editor { flex: 1 1 auto; width: 100%; min-height: 0; resize: none; border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; background: var(--code-bg, var(--bg-app)); color: var(--text-1); font: 12px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre; overflow: auto; }
3018
+ .aux-file-editor-content { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; overflow: hidden; border: 1px solid var(--border); border-radius: 8px; background: var(--code-bg, var(--bg-app)); }
3019
+ .aux-file-editor { flex: 1 1 auto; width: 100%; min-height: 0; resize: none; border: 0; border-radius: 0; padding: 10px 12px; background: var(--code-bg, var(--bg-app)); color: var(--text-1); font: 12px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre; overflow: auto; }
3020
+ .aux-file-rendered-preview { flex: 1 1 auto; width: 100%; min-width: 0; min-height: 0; overflow: auto; padding: 16px 18px; background: var(--bg-surface); color: var(--text-1); }
3021
+ .aux-file-rendered-preview.md-prose { font-size: 13px; line-height: 1.75; }
3022
+ .aux-file-rendered-preview.md-prose .md-h:first-child { margin-top: 0; }
3023
+ .aux-file-html-preview { display: block; flex: 1 1 auto; width: 100%; min-width: 0; min-height: 0; border: 0; background: #fff; }
2995
3024
  .aux-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2996
3025
  .aux-path-bar { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
2997
3026
  .aux-path-bar input { flex: 1; min-width: 0; height: 30px; border: 1px solid var(--border); border-radius: 7px; padding: 0 10px; font-size: 12.5px; background: var(--bg-surface); color: var(--text-1); }
@@ -3052,6 +3081,9 @@ select { border: 1px solid var(--border); background: var(--bg-surface); color:
3052
3081
  .statusbar { min-height: 34px; padding: 8px 18px; color: #6b6f75; font-size: 13px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
3053
3082
  .statusbar.running::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--brand); box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 45%, transparent); animation: pulse 1.2s infinite; }
3054
3083
  .statusbar.error::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--err); }
3084
+ .usagebar { margin-left: auto; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11.5px; font-weight: 400; white-space: nowrap; }
3085
+ .usagebar.warn { color: var(--warn); }
3086
+ .usagebar.critical { color: var(--err); }
3055
3087
  .transcript { flex: 1; overflow: auto; }
3056
3088
  .code-block { position: relative; margin: 10px 0; padding: 12px 14px; background: var(--code-bg); color: var(--code-fg); border-radius: 8px; overflow: auto; border: 1px solid var(--code-border); }
3057
3089
  .code-block code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 12.5px; line-height: 1.5; white-space: pre; }
@@ -4351,6 +4383,7 @@ body { margin: 0; color: var(--text-1); background: var(--bg-app); }
4351
4383
  .dialog-actions button { border: 1px solid var(--border); border-radius: 8px; min-height: 34px; padding: 0 12px; background: var(--bg-surface); }
4352
4384
  .dialog-actions .primary { background: var(--btn-primary-bg); color: var(--btn-primary-fg); }
4353
4385
  .settings-view { position: fixed; inset: 0; z-index: 20; display: flex; background: var(--bg-sidebar); color: var(--text-1); }
4386
+ body.settings-open .manager-shell { display: none; }
4354
4387
  .settings-sidebar {
4355
4388
  width: 240px;
4356
4389
  flex: 0 0 240px;
@@ -4452,6 +4485,7 @@ body { margin: 0; color: var(--text-1); background: var(--bg-app); }
4452
4485
  font-size: 12.5px;
4453
4486
  line-height: 1.55;
4454
4487
  }
4488
+ ${usageRoutingStyles}
4455
4489
  .mode-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
4456
4490
  .mode-card {
4457
4491
  min-height: 56px;
@@ -4777,6 +4811,8 @@ body[data-density="compact"] .composer-meta { padding: 5px 12px; }
4777
4811
  /* Dark-theme reserves for the new workbench regions (plan/UI_PLAN §2 — U9). */
4778
4812
  @media (max-width: 860px) {
4779
4813
  .sidebar { width: 56px; flex-basis: 56px; padding: 12px 8px; }
4814
+ .sidebar.collapsed { display: flex; }
4815
+ .sidebar .sidebar-collapse-btn, .sidebar-expand-fab { display: none; }
4780
4816
  .sidebar .search, .sidebar-recents, .command-section, .project-section h2, .project-session-list, .sidebar-link, .brand-name { display: none; }
4781
4817
  .sidebar .brand, .sidebar .nav-btn { justify-content: center; padding-left: 0; padding-right: 0; }
4782
4818
  .sidebar .nav-btn > span:not(.nav-icon) { display: none !important; }
@@ -5228,11 +5264,12 @@ const state = {
5228
5264
  auxView: null,
5229
5265
  auxCollapsed: false,
5230
5266
  auxPanelWidth: 340,
5267
+ auxFileViewMode: 'source',
5231
5268
  terminalDockHeight: 260,
5232
5269
  activeWorkbenchSurface: 'conversation',
5233
5270
  workbenchLayouts: {
5234
5271
  conversation: { auxWidth: 340, terminalHeight: 260, auxView: null, auxCollapsed: false, terminalVisible: false },
5235
- project: { auxWidth: 340, terminalHeight: 260, auxView: null, auxCollapsed: false, terminalVisible: false },
5272
+ project: { auxWidth: 340, terminalHeight: 260, auxView: null, auxCollapsed: true, terminalVisible: false },
5236
5273
  },
5237
5274
  filesBrowsePath: null,
5238
5275
  browserUrl: 'https://',
@@ -5248,6 +5285,10 @@ const state = {
5248
5285
  gitSidebarWidth: 320,
5249
5286
  detailSidebarWidth: 300,
5250
5287
  detailConversationOpen: true,
5288
+ // App shell panels: the left sidebar defaults expanded, the overview's right
5289
+ // context rail defaults collapsed; both persist to localStorage on toggle.
5290
+ sidebarCollapsed: false,
5291
+ railCollapsed: true,
5251
5292
  conversationListOpen: false,
5252
5293
  conversationListQuery: '',
5253
5294
  sessionUnread: new Set(),
@@ -5534,7 +5575,8 @@ function refreshOpenTerminalThemes() {
5534
5575
  const AUX_PANEL_WIDTH_KEY = 'hadamard.gui.auxPanelWidth';
5535
5576
  const WORKBENCH_LAYOUT_KEY = 'hadamard.gui.workbenchLayouts';
5536
5577
  const AUX_PANEL_MIN_WIDTH = 240;
5537
- const AUX_PANEL_MAX_WIDTH = 720;
5578
+ const AUX_PANEL_MAX_WIDTH = 1600;
5579
+ const AUX_PRIMARY_MIN_WIDTH = 360;
5538
5580
  const TERMINAL_DOCK_MIN_HEIGHT = 160;
5539
5581
  const TERMINAL_DOCK_MAX_HEIGHT = 720;
5540
5582
 
@@ -5561,7 +5603,7 @@ function loadAuxPanelWidth() {
5561
5603
  if (Number.isFinite(auxWidth)) state.workbenchLayouts[surface].auxWidth = Math.round(Math.max(AUX_PANEL_MIN_WIDTH, Math.min(AUX_PANEL_MAX_WIDTH, auxWidth)));
5562
5604
  if (Number.isFinite(terminalHeight)) state.workbenchLayouts[surface].terminalHeight = Math.round(Math.max(TERMINAL_DOCK_MIN_HEIGHT, Math.min(TERMINAL_DOCK_MAX_HEIGHT, terminalHeight)));
5563
5605
  if (saved.auxView === null || ['review', 'git', 'browser', 'files'].includes(saved.auxView)) state.workbenchLayouts[surface].auxView = saved.auxView;
5564
- if (typeof saved.auxCollapsed === 'boolean') state.workbenchLayouts[surface].auxCollapsed = saved.auxCollapsed;
5606
+ if (typeof saved.auxCollapsed === 'boolean' && (surface !== 'project' || parsed.version === 2)) state.workbenchLayouts[surface].auxCollapsed = saved.auxCollapsed;
5565
5607
  if (typeof saved.terminalVisible === 'boolean') state.workbenchLayouts[surface].terminalVisible = saved.terminalVisible;
5566
5608
  }
5567
5609
  const legacy = Number(localStorage.getItem(AUX_PANEL_WIDTH_KEY));
@@ -5572,7 +5614,7 @@ function loadAuxPanelWidth() {
5572
5614
  }
5573
5615
 
5574
5616
  function persistAuxPanelWidth() {
5575
- try { localStorage.setItem(WORKBENCH_LAYOUT_KEY, JSON.stringify(state.workbenchLayouts)); } catch { /* optional */ }
5617
+ try { localStorage.setItem(WORKBENCH_LAYOUT_KEY, JSON.stringify({ version: 2, ...state.workbenchLayouts })); } catch { /* optional */ }
5576
5618
  }
5577
5619
 
5578
5620
  function applyAuxPanelWidth(width) {
@@ -5626,8 +5668,8 @@ function ensureAuxVisible() {
5626
5668
  persistAuxPanelWidth();
5627
5669
  syncAuxChrome();
5628
5670
  }
5629
- function openAuxView(kind) {
5630
- ensureAuxVisible();
5671
+ function openAuxView(kind, reveal = true) {
5672
+ if (reveal) ensureAuxVisible();
5631
5673
  state.auxView = kind;
5632
5674
  activeWorkbenchLayout().auxView = kind;
5633
5675
  persistAuxPanelWidth();
@@ -5661,7 +5703,10 @@ function bindAuxPanelResize() {
5661
5703
  const split = activeWorkbenchSplit();
5662
5704
  if (!split) return;
5663
5705
  const bounds = split.getBoundingClientRect();
5664
- const maxByViewport = Math.min(AUX_PANEL_MAX_WIDTH, Math.floor(bounds.width * 0.7));
5706
+ const maxByViewport = Math.max(
5707
+ AUX_PANEL_MIN_WIDTH,
5708
+ Math.min(AUX_PANEL_MAX_WIDTH, Math.floor(bounds.width - AUX_PRIMARY_MIN_WIDTH)),
5709
+ );
5665
5710
  const delta = startX - event.clientX; // dragging left widens the right panel
5666
5711
  const next = Math.max(AUX_PANEL_MIN_WIDTH, Math.min(maxByViewport, startWidth + delta));
5667
5712
  applyAuxPanelWidth(next);
@@ -6687,7 +6732,8 @@ function flashStatus(message) {
6687
6732
  setTimeout(() => { if (!state.running) setRunStatus(readyLabel()); }, 2600);
6688
6733
  }
6689
6734
  function setRunStatus(message, kind = '') {
6690
- statusbar.textContent = message || '';
6735
+ const statusText = el('statusText');
6736
+ if (statusText) statusText.textContent = message || '';
6691
6737
  statusbar.classList.toggle('running', kind === 'running');
6692
6738
  statusbar.classList.toggle('error', kind === 'error');
6693
6739
  updateSendButton();
@@ -7877,15 +7923,37 @@ function updateConversationSummary() {
7877
7923
  || 'default';
7878
7924
  el('workspace').textContent = (snap.workDir || '') + ' - ' + model + ' - ' + permissionPresetForValue(permissionSelectValue(snap.permissionMode)).title + ' - mode:' + (snap.agentMode || 'react') + ' - effort:' + snap.effort + ' - team:' + (snap.activeTeamName || 'none');
7879
7925
  }
7926
+ function workspaceHtmlPreviewDocument(source) {
7927
+ const parsed = new DOMParser().parseFromString(String(source || ''), 'text/html');
7928
+ parsed.querySelectorAll('script, iframe, object, embed, base, link, meta[http-equiv]').forEach(node => node.remove());
7929
+ parsed.querySelectorAll('*').forEach(node => {
7930
+ for (const attribute of [...node.attributes]) {
7931
+ const name = attribute.name.toLowerCase();
7932
+ const value = String(attribute.value || '').trim();
7933
+ if (/^on/i.test(name) || ['srcset', 'action', 'formaction', 'poster', 'data', 'xlink:href'].includes(name)) {
7934
+ node.removeAttribute(attribute.name);
7935
+ } else if (name === 'src' && !/^data:image\\/(?:png|gif|jpe?g|webp|svg\\+xml);/i.test(value)) {
7936
+ node.removeAttribute(attribute.name);
7937
+ } else if (name === 'href' && !value.startsWith('#')) {
7938
+ node.removeAttribute(attribute.name);
7939
+ }
7940
+ }
7941
+ });
7942
+ const meta = parsed.createElement('meta');
7943
+ meta.httpEquiv = 'Content-Security-Policy';
7944
+ meta.content = "default-src 'none'; style-src 'unsafe-inline'; img-src data:; font-src data:; script-src 'none'; connect-src 'none'; frame-src 'none'; media-src 'none'; object-src 'none'; form-action 'none'; base-uri 'none'";
7945
+ parsed.head.prepend(meta);
7946
+ return '<!doctype html>' + parsed.documentElement.outerHTML;
7947
+ }
7880
7948
  async function renderAuxFileEditor(filePath) {
7881
7949
  const view = el('auxView');
7882
7950
  if (!view) return;
7883
7951
  view.textContent = '';
7884
7952
  const head = document.createElement('div');
7885
- head.className = 'aux-view-header';
7953
+ head.className = 'aux-view-header aux-file-editor-head';
7886
7954
  const title = document.createElement('span');
7887
7955
  title.className = 'aux-view-title';
7888
- title.textContent = filePath.split(/[\\/]/).pop() || 'File';
7956
+ title.textContent = String(filePath || '').replaceAll(String.fromCharCode(92), '/').split('/').pop() || 'File';
7889
7957
  const backBtn = document.createElement('button');
7890
7958
  backBtn.type = 'button';
7891
7959
  backBtn.className = 'pill-btn';
@@ -7920,6 +7988,31 @@ async function renderAuxFileEditor(filePath) {
7920
7988
  body.appendChild(note);
7921
7989
  return;
7922
7990
  }
7991
+ const language = detectEditorLanguage(data.path || filePath);
7992
+ const previewKind = language === 'markdown'
7993
+ ? 'markdown'
7994
+ : /\\.html?$/i.test(String(data.path || filePath)) ? 'html' : null;
7995
+ let viewMode = state.auxFileViewMode === 'preview' ? 'preview' : 'source';
7996
+ const modeButtons = [];
7997
+ if (previewKind) {
7998
+ const modes = document.createElement('div');
7999
+ modes.className = 'files-preview-modes aux-file-preview-modes';
8000
+ modes.setAttribute('role', 'tablist');
8001
+ modes.setAttribute('aria-label', previewKind === 'markdown' ? 'Markdown display mode' : 'HTML display mode');
8002
+ for (const mode of ['source', 'preview']) {
8003
+ const button = document.createElement('button');
8004
+ button.type = 'button';
8005
+ button.className = 'files-preview-mode';
8006
+ button.textContent = mode === 'source' ? 'Source' : 'Preview';
8007
+ button.setAttribute('role', 'tab');
8008
+ button.addEventListener('click', () => applyViewMode(mode));
8009
+ modeButtons.push({ button, mode });
8010
+ modes.appendChild(button);
8011
+ }
8012
+ head.insertBefore(modes, backBtn);
8013
+ }
8014
+ const content = document.createElement('div');
8015
+ content.className = 'aux-file-editor-content';
7923
8016
  const editor = document.createElement('textarea');
7924
8017
  editor.className = 'aux-file-editor';
7925
8018
  editor.value = typeof data.text === 'string' ? data.text : '';
@@ -7927,7 +8020,42 @@ async function renderAuxFileEditor(filePath) {
7927
8020
  editor.spellcheck = false;
7928
8021
  editor.wrap = 'off';
7929
8022
  editor.setAttribute('aria-label', 'File editor');
7930
- body.appendChild(editor);
8023
+ content.appendChild(editor);
8024
+ let renderedPreview = null;
8025
+ if (previewKind === 'markdown') {
8026
+ renderedPreview = document.createElement('div');
8027
+ renderedPreview.className = 'aux-file-rendered-preview md-prose hidden';
8028
+ renderedPreview.setAttribute('aria-label', 'Markdown preview');
8029
+ content.appendChild(renderedPreview);
8030
+ } else if (previewKind === 'html') {
8031
+ renderedPreview = document.createElement('iframe');
8032
+ renderedPreview.className = 'aux-file-html-preview hidden';
8033
+ renderedPreview.title = 'HTML preview';
8034
+ renderedPreview.setAttribute('sandbox', '');
8035
+ renderedPreview.setAttribute('referrerpolicy', 'no-referrer');
8036
+ content.appendChild(renderedPreview);
8037
+ }
8038
+ body.appendChild(content);
8039
+ function renderCurrentPreview() {
8040
+ if (previewKind === 'markdown' && renderedPreview) {
8041
+ renderMarkdownInto(renderedPreview, editor.value);
8042
+ } else if (previewKind === 'html' && renderedPreview) {
8043
+ renderedPreview.srcdoc = workspaceHtmlPreviewDocument(editor.value);
8044
+ }
8045
+ }
8046
+ function applyViewMode(mode) {
8047
+ viewMode = mode === 'preview' && renderedPreview ? 'preview' : 'source';
8048
+ state.auxFileViewMode = viewMode;
8049
+ editor.classList.toggle('hidden', viewMode !== 'source');
8050
+ if (renderedPreview) renderedPreview.classList.toggle('hidden', viewMode !== 'preview');
8051
+ for (const item of modeButtons) {
8052
+ const active = item.mode === viewMode;
8053
+ item.button.classList.toggle('active', active);
8054
+ item.button.setAttribute('aria-selected', active ? 'true' : 'false');
8055
+ item.button.tabIndex = active ? 0 : -1;
8056
+ }
8057
+ if (viewMode === 'preview') renderCurrentPreview();
8058
+ }
7931
8059
  let savedText = editor.value;
7932
8060
  editor.addEventListener('input', () => { saveBtn.disabled = editor.value === savedText; });
7933
8061
  const save = async () => {
@@ -7956,6 +8084,7 @@ async function renderAuxFileEditor(filePath) {
7956
8084
  void save();
7957
8085
  }
7958
8086
  });
8087
+ applyViewMode(viewMode);
7959
8088
  if (data.truncated) {
7960
8089
  const note = document.createElement('p');
7961
8090
  note.className = 'muted';
@@ -8028,8 +8157,24 @@ function renderComposerMeta() {
8028
8157
  branchChip.disabled = !isRepo;
8029
8158
  }
8030
8159
  }
8160
+ function renderUsageBar() {
8161
+ const bar = el('usagebar');
8162
+ if (!bar) return;
8163
+ const snap = state.snapshot || {};
8164
+ if (!snap.usageBarText) {
8165
+ bar.classList.add('hidden');
8166
+ bar.textContent = '';
8167
+ return;
8168
+ }
8169
+ bar.textContent = snap.usageBarText;
8170
+ bar.title = 'Context / session usage';
8171
+ bar.classList.remove('hidden');
8172
+ bar.classList.toggle('warn', snap.usageBarLevel === 'warn');
8173
+ bar.classList.toggle('critical', snap.usageBarLevel === 'critical');
8174
+ }
8031
8175
  function renderStatusExtras() {
8032
8176
  const snap = state.snapshot || {};
8177
+ renderUsageBar();
8033
8178
  const bar = el('contextBar');
8034
8179
  bar.textContent = '';
8035
8180
  const addBadge = (cls, text, title) => {
@@ -9116,6 +9261,42 @@ function toggleDetailConversationDrawer() {
9116
9261
  : !sidebar?.classList.contains('desktop-collapsed');
9117
9262
  setDetailConversationDrawer(!open);
9118
9263
  }
9264
+ // --- App shell panels: collapsible left sidebar + right context rail. ---
9265
+ function setSidebarCollapsed(collapsed, persist) {
9266
+ state.sidebarCollapsed = Boolean(collapsed);
9267
+ const sidebar = el('appSidebar');
9268
+ const expander = el('sidebarExpandBtn');
9269
+ const toggle = el('sidebarCollapseBtn');
9270
+ sidebar?.classList.toggle('collapsed', state.sidebarCollapsed);
9271
+ expander?.classList.toggle('hidden', !state.sidebarCollapsed);
9272
+ toggle?.setAttribute('aria-expanded', state.sidebarCollapsed ? 'false' : 'true');
9273
+ expander?.setAttribute('aria-expanded', state.sidebarCollapsed ? 'false' : 'true');
9274
+ if (persist !== false) try { localStorage.setItem('hadamard.gui.sidebarCollapsed', state.sidebarCollapsed ? '1' : '0'); } catch { /* optional */ }
9275
+ }
9276
+ function loadSidebarCollapsed() {
9277
+ let saved = false;
9278
+ try { saved = localStorage.getItem('hadamard.gui.sidebarCollapsed') === '1'; } catch { /* optional */ }
9279
+ setSidebarCollapsed(saved, false);
9280
+ }
9281
+ function setContextRailCollapsed(collapsed, persist) {
9282
+ state.railCollapsed = Boolean(collapsed);
9283
+ if (persist !== false) try { localStorage.setItem('hadamard.gui.railCollapsed', state.railCollapsed ? '1' : '0'); } catch { /* optional */ }
9284
+ const toggle = el('overviewRailToggleBtn');
9285
+ if (toggle) {
9286
+ const expanded = !state.railCollapsed;
9287
+ toggle.setAttribute('aria-expanded', expanded ? 'true' : 'false');
9288
+ toggle.setAttribute('aria-label', expanded ? 'Hide panel' : 'Show panel');
9289
+ toggle.setAttribute('title', expanded ? 'Hide panel' : 'Show panel');
9290
+ toggle.innerHTML = guiIcon(expanded ? 'panelRight' : 'panelLeft');
9291
+ }
9292
+ renderContextRail();
9293
+ }
9294
+ function loadContextRailCollapsed() {
9295
+ // Default is collapsed: only an explicit '0' reopens the rail on startup.
9296
+ let saved = true;
9297
+ try { saved = localStorage.getItem('hadamard.gui.railCollapsed') !== '0'; } catch { /* optional */ }
9298
+ setContextRailCollapsed(saved, false);
9299
+ }
9119
9300
  function runningSessionIds() {
9120
9301
  return new Set((state.snapshot?.runs || []).filter(run => run.status === 'running' && run.sessionId).map(run => run.sessionId));
9121
9302
  }
@@ -10179,9 +10360,9 @@ function richTextToMarkdown(root) {
10179
10360
  if (node.nodeType === Node.TEXT_NODE) return (node.textContent || '').trim();
10180
10361
  if (node.nodeType !== Node.ELEMENT_NODE) return '';
10181
10362
  const tag = node.tagName.toLowerCase();
10182
- if (/^h[1-6]$/.test(tag)) return '#'.repeat(Number(tag[1])) + ' ' + inline(node).trim();
10363
+ if ((tag === 'p' || tag === 'div') && node.children.length === 1 && /^(ul|ol)$/i.test(node.firstElementChild?.tagName || '')) return block(node.firstElementChild); if (/^h[1-6]$/.test(tag)) return '#'.repeat(Number(tag[1])) + ' ' + inline(node).trim();
10183
10364
  if (tag === 'blockquote') return inline(node).trim().split('\\n').map(line => '> ' + line).join('\\n');
10184
- if (tag === 'pre') return String.fromCharCode(96).repeat(3) + '\\n' + (node.textContent || '').replace(/\\n$/, '') + '\\n' + String.fromCharCode(96).repeat(3);
10365
+ if (tag === 'pre') { const language = node.querySelector(':scope > .code-lang')?.textContent?.trim() || ''; const code = node.querySelector(':scope > code')?.textContent ?? node.textContent ?? ''; return String.fromCharCode(96).repeat(3) + language + '\\n' + code.replace(/\\n$/, '') + '\\n' + String.fromCharCode(96).repeat(3); }
10185
10366
  if (tag === 'hr') return '---';
10186
10367
  if (tag === 'ul' || tag === 'ol') return Array.from(node.children).map((item, index) => {
10187
10368
  const checkbox = item.querySelector(':scope > input[type="checkbox"]');
@@ -10225,7 +10406,7 @@ function runProjectDocFormat(command, value) {
10225
10406
  rich.focus();
10226
10407
  if (command === 'codeBlock') document.execCommand('formatBlock', false, 'pre');
10227
10408
  else if (command === 'blockquote') document.execCommand('formatBlock', false, 'blockquote');
10228
- else if (command === 'heading') document.execCommand('formatBlock', false, value || 'h2');
10409
+ else if (command === 'heading') document.execCommand('formatBlock', false, value || 'p');
10229
10410
  else if (command === 'link') {
10230
10411
  const href = window.prompt('Link URL', 'https://');
10231
10412
  if (href && /^https?:\\/\\//i.test(href)) document.execCommand('createLink', false, href);
@@ -10240,9 +10421,9 @@ function runProjectDocFormat(command, value) {
10240
10421
  scheduleProjectDocSave();
10241
10422
  }
10242
10423
  function createProjectDocFormatBar() {
10243
- const bar = document.createElement('div'); bar.className = 'project-doc-formatbar'; bar.setAttribute('role', 'toolbar'); bar.setAttribute('aria-label', 'Markdown formatting');
10424
+ const bar = document.createElement('div'); bar.className = 'project-doc-formatbar'; bar.setAttribute('role', 'toolbar'); bar.setAttribute('aria-label', 'Markdown formatting'); bar.appendChild(createProjectDocHeadingSelect());
10244
10425
  const actions = [
10245
- ['H2', 'heading', 'h2', 'Heading'], ['B', 'bold', '', 'Bold'], ['I', 'italic', '', 'Italic'], ['S', 'strikeThrough', '', 'Strikethrough'],
10426
+ ['B', 'bold', '', 'Bold'], ['I', 'italic', '', 'Italic'], ['S', 'strikeThrough', '', 'Strikethrough'],
10246
10427
  ['•', 'insertUnorderedList', '', 'Bulleted list'], ['1.', 'insertOrderedList', '', 'Numbered list'], ['☑', 'task', '', 'Task list'],
10247
10428
  ['❝', 'blockquote', '', 'Quote'], ['</>', 'codeBlock', '', 'Code block'], ['↗', 'link', '', 'Link'], ['▧', 'image', '', 'Image'], ['▦', 'table', '', 'Table'],
10248
10429
  ['↶', 'undo', '', 'Undo'], ['↷', 'redo', '', 'Redo'], ['MD', 'source', '', 'Markdown source'],
@@ -11228,7 +11409,7 @@ function mountWorkbenchTools(surface) {
11228
11409
  state.auxCollapsed = layout.auxCollapsed === true;
11229
11410
  applyAuxPanelWidth(layout.auxWidth);
11230
11411
  applyTerminalDockHeight(layout.terminalHeight);
11231
- if (state.auxView) openAuxView(state.auxView);
11412
+ if (state.auxView) openAuxView(state.auxView, !state.auxCollapsed);
11232
11413
  else showAuxLauncher();
11233
11414
  dock.classList.toggle('hidden', layout.terminalVisible !== true);
11234
11415
  syncAuxChrome();
@@ -13178,7 +13359,7 @@ function renderProjectDetail() {
13178
13359
  docRich.setAttribute('role', 'textbox');
13179
13360
  docRich.setAttribute('aria-multiline', 'true');
13180
13361
  docRich.setAttribute('aria-label', 'Rich text document editor');
13181
- docRich.addEventListener('input', () => scheduleProjectDocSave());
13362
+ for (const eventName of ['focus', 'input', 'keyup', 'mouseup']) docRich.addEventListener(eventName, () => { if (eventName === 'input') scheduleProjectDocSave(); syncProjectDocHeadingSelect(); });
13182
13363
  docRich.addEventListener('keydown', event => {
13183
13364
  if (event.key === 'Escape') {
13184
13365
  event.preventDefault();
@@ -13588,7 +13769,7 @@ function renderContextRail() {
13588
13769
  const rail = el('contextRail');
13589
13770
  if (!rail) return;
13590
13771
  rail.textContent = '';
13591
- if (state.activeRegion !== 'project' || state.projectView !== 'overview') {
13772
+ if (state.activeRegion !== 'project' || state.projectView !== 'overview' || state.railCollapsed) {
13592
13773
  rail.classList.add('hidden');
13593
13774
  return;
13594
13775
  }
@@ -13837,12 +14018,13 @@ async function requestRailNotificationPermission() {
13837
14018
  }
13838
14019
  function showRailNotification(note) {
13839
14020
  const text = note?.text || 'Reminder';
14021
+ const title = note?.title || 'Reminder';
13840
14022
  if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {
13841
- try { new Notification('Hadamard reminder', { body: text }); } catch { /* ignore */ }
14023
+ try { new Notification(note?.title || 'Hadamard reminder', { body: text }); } catch { /* ignore */ }
13842
14024
  }
13843
14025
  const toast = el('railToast');
13844
14026
  if (!toast) return;
13845
- toast.innerHTML = '<strong>Reminder</strong>' + escapeHtml(text);
14027
+ toast.innerHTML = '<strong>' + escapeHtml(title) + '</strong> ' + escapeHtml(text);
13846
14028
  toast.classList.remove('hidden');
13847
14029
  clearTimeout(showRailNotification._timer);
13848
14030
  showRailNotification._timer = setTimeout(() => toast.classList.add('hidden'), 8000);
@@ -25478,6 +25660,7 @@ function openProjectGitFromSettings() {
25478
25660
  switchProjectView('detail');
25479
25661
  setProjectDetailTab('git');
25480
25662
  }
25663
+ ${usageRoutingClient}
25481
25664
  function showSettingsTab(tab) {
25482
25665
  const requested = String(tab || 'general');
25483
25666
  const hasTab = !!document.querySelector('.settings-tab[data-settings-tab="' + requested + '"]');
@@ -25490,6 +25673,7 @@ function showSettingsTab(tab) {
25490
25673
  if (active === 'models') renderBridgeConfigs();
25491
25674
  if (active === 'mcp') renderMcpServers();
25492
25675
  if (active === 'sessions') renderArchived();
25676
+ if (active === 'usage-routing') void refreshUsageRouting();
25493
25677
  }
25494
25678
  // ── Assistant widget (global FAB + Global/Project scope) ───
25495
25679
  // Talks to /api/manager/* with scope=global|project. Global uses assistant
@@ -26765,6 +26949,7 @@ async function openSettings(tab = 'general') {
26765
26949
  setChecked('settingsShowRouterProfilesInComposer', preferences.showRouterProfilesInComposer !== false);
26766
26950
  setChecked('settingsUseDefaultModelAsFallback', preferences.useDefaultModelAsFallback !== false);
26767
26951
  setChecked('settingsShowBuiltInSubagents', preferences.showBuiltInSubagents === true);
26952
+ renderExtensionSettings(settings);
26768
26953
  updateFallbackHint();
26769
26954
  const terminalGroup = el('settingsTerminalGroup');
26770
26955
  if (terminalGroup) {
@@ -26779,10 +26964,14 @@ async function openSettings(tab = 'general') {
26779
26964
  renderShortcutsPanel();
26780
26965
  el('settingsStatus').textContent = '';
26781
26966
  renderSettingsCommandPanels();
26967
+ document.body.classList.add('settings-open');
26782
26968
  el('settingsModal').classList.remove('hidden');
26783
26969
  showSettingsTab(tab);
26784
26970
  }
26785
- function closeSettings() { el('settingsModal').classList.add('hidden'); }
26971
+ function closeSettings() {
26972
+ el('settingsModal').classList.add('hidden');
26973
+ document.body.classList.remove('settings-open');
26974
+ }
26786
26975
  function derivePermissionPreset() {
26787
26976
  if (el('settingsPermissionPreset').value) return el('settingsPermissionPreset').value;
26788
26977
  if (el('settingsFullAccess').checked) return 'full';
@@ -26792,9 +26981,68 @@ function derivePermissionPreset() {
26792
26981
  }
26793
26982
  let settingsAutosaveTimer = null;
26794
26983
  let settingsAutosaveSeq = 0;
26984
+ function renderExtensionSettings(settings) {
26985
+ const extensionRoot = el('settingsExtensionsList');
26986
+ if (extensionRoot) {
26987
+ extensionRoot.textContent = '';
26988
+ const extensions = Array.isArray(settings.extensions) ? settings.extensions : [];
26989
+ if (extensions.length === 0) {
26990
+ extensionRoot.innerHTML = '<p class="muted">Built-in extensions are unavailable until the runtime is configured.</p>';
26991
+ } else {
26992
+ extensions.forEach(extension => {
26993
+ const row = document.createElement('div');
26994
+ row.className = 'settings-help-row';
26995
+ const copy = document.createElement('span');
26996
+ const title = document.createElement('strong');
26997
+ title.textContent = extension.title || extension.id;
26998
+ const description = document.createElement('small');
26999
+ const defaultState = extension.defaultEnabled ? 'on' : 'off';
27000
+ description.textContent = (extension.description || '') + ' Default: ' + defaultState + ' · ' + (extension.kind || 'runtime') + '.';
27001
+ copy.append(title, description);
27002
+ const label = document.createElement('label');
27003
+ label.className = 'switch-field';
27004
+ const toggle = document.createElement('input');
27005
+ toggle.type = 'checkbox';
27006
+ toggle.id = 'settingsExtension-' + extension.id;
27007
+ toggle.dataset.extensionId = extension.id;
27008
+ toggle.checked = extension.enabled === true;
27009
+ label.append(toggle);
27010
+ row.append(copy, label);
27011
+ extensionRoot.append(row);
27012
+ });
27013
+ }
27014
+ }
27015
+ setChecked('settingsAutoDetectLanguageServers', settings.autoDetectLanguageServers !== false);
27016
+ const lspRoot = el('settingsLanguageServersList');
27017
+ if (!lspRoot) return;
27018
+ lspRoot.textContent = '';
27019
+ const servers = Array.isArray(settings.languageServers) ? settings.languageServers : [];
27020
+ if (servers.length === 0) {
27021
+ lspRoot.innerHTML = '<p class="muted">No language servers are configured or currently detected.</p>';
27022
+ return;
27023
+ }
27024
+ servers.forEach(server => {
27025
+ const row = document.createElement('div');
27026
+ row.className = 'settings-help-row';
27027
+ const copy = document.createElement('span');
27028
+ const title = document.createElement('strong');
27029
+ title.textContent = server.id || 'Language server';
27030
+ const description = document.createElement('small');
27031
+ description.textContent = [Array.isArray(server.languages) ? server.languages.join(', ') : '', server.command || ''].filter(Boolean).join(' · ');
27032
+ copy.append(title, description);
27033
+ row.append(copy);
27034
+ lspRoot.append(row);
27035
+ });
27036
+ }
26795
27037
  function collectSettingsBody() {
27038
+ const extensions = {};
27039
+ document.querySelectorAll('#settingsExtensionsList input[data-extension-id]').forEach(toggle => {
27040
+ extensions[toggle.dataset.extensionId] = { enabled: toggle.checked };
27041
+ });
26796
27042
  return {
26797
27043
  permissionPreset: derivePermissionPreset(),
27044
+ extensions,
27045
+ autoDetectLanguageServers: el('settingsAutoDetectLanguageServers')?.checked !== false,
26798
27046
  preferences: {
26799
27047
  theme: el('settingsTheme').value,
26800
27048
  density: el('settingsDensity').value,
@@ -26827,6 +27075,7 @@ async function persistSettingsNow() {
26827
27075
  if (seq !== settingsAutosaveSeq) return;
26828
27076
  if (!res.ok) {
26829
27077
  if (status) status.textContent = 'Save failed';
27078
+ renderExtensionSettings(state.snapshot?.settings || {});
26830
27079
  addMessage('error', await res.text());
26831
27080
  return;
26832
27081
  }
@@ -26849,6 +27098,7 @@ async function persistSettingsNow() {
26849
27098
  } catch (error) {
26850
27099
  if (seq !== settingsAutosaveSeq) return;
26851
27100
  if (status) status.textContent = 'Save failed';
27101
+ renderExtensionSettings(state.snapshot?.settings || {});
26852
27102
  addMessage('error', error?.message || String(error));
26853
27103
  }
26854
27104
  }
@@ -26899,6 +27149,7 @@ document.querySelectorAll('[data-decision]').forEach(button => {
26899
27149
  });
26900
27150
  });
26901
27151
  document.querySelectorAll('.settings-tab').forEach(button => button.addEventListener('click', () => showSettingsTab(button.dataset.settingsTab)));
27152
+ ${usageRoutingBindings}
26902
27153
  el('composer').addEventListener('submit', async (event) => {
26903
27154
  event.preventDefault();
26904
27155
  if (state.running) {
@@ -27142,6 +27393,9 @@ el('detailRemoveWorkPathBtn')?.addEventListener('click', () => {
27142
27393
  });
27143
27394
  el('detailOpenLocationBtn').addEventListener('click', openLocation);
27144
27395
  el('detailConversationsBtn').addEventListener('click', toggleDetailConversationDrawer);
27396
+ el('sidebarCollapseBtn').addEventListener('click', () => setSidebarCollapsed(true));
27397
+ el('sidebarExpandBtn').addEventListener('click', () => setSidebarCollapsed(false));
27398
+ el('overviewRailToggleBtn').addEventListener('click', () => setContextRailCollapsed(!state.railCollapsed));
27145
27399
  el('sessionCenterBack').addEventListener('click', () => switchProjectView('overview'));
27146
27400
  el('sessionCenterNew').addEventListener('click', async () => {
27147
27401
  const projectPath = el('sessionCenterProject')?.value || state.snapshot?.workDir;
@@ -27512,6 +27766,8 @@ el('terminalDockClose').addEventListener('click', () => {
27512
27766
  });
27513
27767
  loadAuxPanelWidth();
27514
27768
  loadSessionIndicatorState();
27769
+ loadSidebarCollapsed();
27770
+ loadContextRailCollapsed();
27515
27771
  applyAuxPanelWidth(activeWorkbenchLayout().auxWidth);
27516
27772
  applyTerminalDockHeight(activeWorkbenchLayout().terminalHeight);
27517
27773
  bindAuxPanelResize();