cli-jaw 2.17.62 → 2.17.63

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 (360) hide show
  1. package/README.ja.md +17 -17
  2. package/README.ko.md +17 -17
  3. package/README.md +17 -17
  4. package/README.zh-CN.md +17 -17
  5. package/dist/bin/commands/tui/input-handler.js +19 -0
  6. package/dist/bin/commands/tui/input-handler.js.map +1 -1
  7. package/dist/bin/commands/tui/overlays.js +8 -4
  8. package/dist/bin/commands/tui/overlays.js.map +1 -1
  9. package/dist/bin/star-prompt.js +1 -1
  10. package/dist/bin/star-prompt.js.map +1 -1
  11. package/dist/server.js +14 -1
  12. package/dist/server.js.map +1 -1
  13. package/dist/src/agent/claude-runtime-pool.js +2 -1
  14. package/dist/src/agent/claude-runtime-pool.js.map +1 -1
  15. package/dist/src/agent/claude-runtime-run.js +28 -7
  16. package/dist/src/agent/claude-runtime-run.js.map +1 -1
  17. package/dist/src/agent/lifecycle-handler.js +34 -6
  18. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  19. package/dist/src/agent/runtime/claude-sdk-events.js +136 -9
  20. package/dist/src/agent/runtime/claude-sdk-events.js.map +1 -1
  21. package/dist/src/agent/runtime/claude-sdk-history-loader.js +24 -0
  22. package/dist/src/agent/runtime/claude-sdk-history-loader.js.map +1 -0
  23. package/dist/src/agent/runtime/claude-sdk-hooks.js +10 -4
  24. package/dist/src/agent/runtime/claude-sdk-hooks.js.map +1 -1
  25. package/dist/src/agent/runtime/claude-sdk-messages.js +25 -2
  26. package/dist/src/agent/runtime/claude-sdk-messages.js.map +1 -1
  27. package/dist/src/agent/runtime/claude-sdk-options.js +36 -3
  28. package/dist/src/agent/runtime/claude-sdk-options.js.map +1 -1
  29. package/dist/src/agent/runtime/claude-sdk-permissions.js +32 -9
  30. package/dist/src/agent/runtime/claude-sdk-permissions.js.map +1 -1
  31. package/dist/src/agent/runtime/claude-sdk-session.js +165 -17
  32. package/dist/src/agent/runtime/claude-sdk-session.js.map +1 -1
  33. package/dist/src/agent/runtime/claude-sdk-version.js +8 -0
  34. package/dist/src/agent/runtime/claude-sdk-version.js.map +1 -0
  35. package/dist/src/agent/spawn/backend-codex-app.js +619 -0
  36. package/dist/src/agent/spawn/backend-codex-app.js.map +1 -0
  37. package/dist/src/agent/spawn/backend-context.js +2 -0
  38. package/dist/src/agent/spawn/backend-context.js.map +1 -0
  39. package/dist/src/agent/spawn/backend-copilot.js +385 -0
  40. package/dist/src/agent/spawn/backend-copilot.js.map +1 -0
  41. package/dist/src/agent/spawn/backend-native-acp.js +379 -0
  42. package/dist/src/agent/spawn/backend-native-acp.js.map +1 -0
  43. package/dist/src/agent/spawn/backend-pi.js +565 -0
  44. package/dist/src/agent/spawn/backend-pi.js.map +1 -0
  45. package/dist/src/agent/spawn/types.js +2 -0
  46. package/dist/src/agent/spawn/types.js.map +1 -0
  47. package/dist/src/agent/spawn.js +44 -1858
  48. package/dist/src/agent/spawn.js.map +1 -1
  49. package/dist/src/cli/claude-default-model-boot.js +36 -0
  50. package/dist/src/cli/claude-default-model-boot.js.map +1 -0
  51. package/dist/src/cli/claude-model-discovery.js +13 -1
  52. package/dist/src/cli/claude-model-discovery.js.map +1 -1
  53. package/dist/src/cli/claude-models.js +7 -1
  54. package/dist/src/cli/claude-models.js.map +1 -1
  55. package/dist/src/cli/commands.js +5 -15
  56. package/dist/src/cli/commands.js.map +1 -1
  57. package/dist/src/cli/tui/composer.js +3 -3
  58. package/dist/src/cli/tui/composer.js.map +1 -1
  59. package/dist/src/cli/tui/skill-mention.js +15 -0
  60. package/dist/src/cli/tui/skill-mention.js.map +1 -0
  61. package/dist/src/code-mode/manager.js +174 -9
  62. package/dist/src/code-mode/manager.js.map +1 -1
  63. package/dist/src/code-mode/providers/catalog.js +5 -3
  64. package/dist/src/code-mode/providers/catalog.js.map +1 -1
  65. package/dist/src/code-mode/providers/claude-history.js +132 -0
  66. package/dist/src/code-mode/providers/claude-history.js.map +1 -0
  67. package/dist/src/code-mode/providers/claude.js +74 -7
  68. package/dist/src/code-mode/providers/claude.js.map +1 -1
  69. package/dist/src/code-mode/providers/codex-app.js +7 -1
  70. package/dist/src/code-mode/providers/codex-app.js.map +1 -1
  71. package/dist/src/code-mode/session.js +158 -11
  72. package/dist/src/code-mode/session.js.map +1 -1
  73. package/dist/src/code-mode/store.js +416 -28
  74. package/dist/src/code-mode/store.js.map +1 -1
  75. package/dist/src/command-contract/catalog.js +3 -22
  76. package/dist/src/command-contract/catalog.js.map +1 -1
  77. package/dist/src/core/codex-config.js +3 -62
  78. package/dist/src/core/codex-config.js.map +1 -1
  79. package/dist/src/core/config.js +116 -14
  80. package/dist/src/core/config.js.map +1 -1
  81. package/dist/src/core/runtime-settings.js +20 -10
  82. package/dist/src/core/runtime-settings.js.map +1 -1
  83. package/dist/src/core/settings-watch.js +1 -0
  84. package/dist/src/core/settings-watch.js.map +1 -1
  85. package/dist/src/core/skill-mentions.js +83 -0
  86. package/dist/src/core/skill-mentions.js.map +1 -0
  87. package/dist/src/manager/registry.js +5 -1
  88. package/dist/src/manager/registry.js.map +1 -1
  89. package/dist/src/manager/routes/desktop-status.js +1 -1
  90. package/dist/src/manager/routes/desktop-status.js.map +1 -1
  91. package/dist/src/orchestrator/pipeline.js +11 -1
  92. package/dist/src/orchestrator/pipeline.js.map +1 -1
  93. package/dist/src/prompt/builder.js +10 -4
  94. package/dist/src/prompt/builder.js.map +1 -1
  95. package/dist/src/prompt/templates/a1-system.md +1 -1
  96. package/dist/src/routes/code-native.js +51 -3
  97. package/dist/src/routes/code-native.js.map +1 -1
  98. package/dist/src/routes/settings.js +1 -4
  99. package/dist/src/routes/settings.js.map +1 -1
  100. package/dist/src/routes/skills.js +7 -0
  101. package/dist/src/routes/skills.js.map +1 -1
  102. package/dist/src/shared/skill-mention.js +61 -0
  103. package/dist/src/shared/skill-mention.js.map +1 -0
  104. package/dist/src/shared/tool-input.js +137 -0
  105. package/dist/src/shared/tool-input.js.map +1 -0
  106. package/package.json +7 -5
  107. package/public/css/activity.css +83 -20
  108. package/public/css/layout.css +2 -2
  109. package/public/css/sidebar.css +18 -0
  110. package/public/css/variables.css +23 -2
  111. package/public/dist/.vite/manifest.json +302 -334
  112. package/public/dist/assets/Activity-DPLlOJ46.js +1 -0
  113. package/public/dist/assets/AdvancedExport-BgOgGvc5.js +1 -0
  114. package/public/dist/assets/Agent-O_U8ny90.js +1 -0
  115. package/public/dist/assets/Browser-m6VynQXV.js +1 -0
  116. package/public/dist/assets/BrowserPanel-Bb-Bge6B.js +3 -0
  117. package/public/dist/assets/ChannelEnablementControl-BSuKQhTW.js +85 -0
  118. package/public/dist/assets/ChannelSetupEntry-DHLoZEzJ.js +1 -0
  119. package/public/dist/assets/ChannelsDiscord-B-G8vsYy.js +1 -0
  120. package/public/dist/assets/ChannelsSlack-oPuh922z.js +1 -0
  121. package/public/dist/assets/ChannelsTelegram-PmTv43KQ.js +1 -0
  122. package/public/dist/assets/CodeCanvas-CVbdp0S-.js +3 -0
  123. package/public/dist/assets/DashboardMeta-BqEiJrvr.js +1 -0
  124. package/public/dist/assets/DesignPanel-BOb-HMbl.js +2 -0
  125. package/public/dist/assets/{Developer-BdKPcw8Z.js → Developer-CbySB7_Z.js} +1 -1
  126. package/public/dist/assets/{DiffPanel-DtJuvU5y.js → DiffPanel-D9Cch5FG.js} +1 -1
  127. package/public/dist/assets/Display-C0Zdamcb.js +1 -0
  128. package/public/dist/assets/Display-DU4_76cS.js +1 -0
  129. package/public/dist/assets/DocPanel-DvtFw8AP.js +1 -0
  130. package/public/dist/assets/{Embedding-DvdTj1BF.js → Embedding-CCFMOB_2.js} +1 -1
  131. package/public/dist/assets/Employees-BanvF58d.js +1 -0
  132. package/public/dist/assets/FolderPanel-CJvwRwIV.js +3 -0
  133. package/public/dist/assets/Heartbeat-uyi_MpUd.js +1 -0
  134. package/public/dist/assets/InlineWarn-Cq4z28F3.js +1 -0
  135. package/public/dist/assets/MarkdownRenderer-Cc3DeHvm.js +1 -0
  136. package/public/dist/assets/{MarkdownRenderer-DhonsAPC.js → MarkdownRenderer-DzN66XVb.js} +1 -1
  137. package/public/dist/assets/Mcp-rjPoL_Zo.js +4 -0
  138. package/public/dist/assets/Memory-C9I33pIi.js +1 -0
  139. package/public/dist/assets/{MilkdownWysiwygEditor-D6JaLDE4.js → MilkdownWysiwygEditor-xObhviw7.js} +1 -1
  140. package/public/dist/assets/ModelProvider-fiUktMaO.js +1 -0
  141. package/public/dist/assets/Network-CuqFrOvR.js +1 -0
  142. package/public/dist/assets/NotesGraphWorkspace-DO9LtVGF.js +1 -0
  143. package/public/dist/assets/PanelLayoutProvider-DRZ4QkBC.js +1 -0
  144. package/public/dist/assets/Permissions-BltXiZnz.js +1 -0
  145. package/public/dist/assets/{Permissions-BwiMEoTV.js → Permissions-DcCbFMIq.js} +1 -1
  146. package/public/dist/assets/Profile-DUL7-RE_.js +1 -0
  147. package/public/dist/assets/Prompts-C9vY8ivQ.js +1 -0
  148. package/public/dist/assets/SpeechKeys-BJ8V7U5E.js +1 -0
  149. package/public/dist/assets/TelegramHub-DtyjLGFR.js +1 -0
  150. package/public/dist/assets/{TerminalPanel-Bu9i-P2f.js → TerminalPanel-c1xhiy53.js} +1 -1
  151. package/public/dist/assets/app-BjKzqXCv.css +1 -0
  152. package/public/dist/assets/app-CZwx0V6K.js +59 -0
  153. package/public/dist/assets/bgtask-badge-CnVkcp3c.js +1 -0
  154. package/public/dist/assets/{bgtask-badge-DfiHuzxT.js → bgtask-badge-Cp26S8Uq.js} +1 -1
  155. package/public/dist/assets/client-platform-WO8m6kPQ.js +1 -0
  156. package/public/dist/assets/{employees-BQaJNp-u.js → employees-CsvI0_5V.js} +1 -1
  157. package/public/dist/assets/error-normalize-clOi-AAA.js +1 -0
  158. package/public/dist/assets/fields-CicOWY-X.js +1 -0
  159. package/public/dist/assets/iframe-renderer-DWx9v2Iz.js +1 -0
  160. package/public/dist/assets/iframe-renderer-DmHYOI1A.js +142 -0
  161. package/public/dist/assets/{react-C_pPTFsM.js → jsx-runtime-CkEUZM6i.js} +1 -1
  162. package/public/dist/assets/manager-CCXm5Yfe.js +5 -0
  163. package/public/dist/assets/manager-D9rhKFKc.css +1 -0
  164. package/public/dist/assets/manager-shortcuts-Cqmr0mEq.js +1 -0
  165. package/public/dist/assets/{memory-EG1B51up.js → memory-C6qtAMdJ.js} +1 -1
  166. package/public/dist/assets/memory-PPofQPeB.js +1 -0
  167. package/public/dist/assets/message-history-DcjBuubA.js +4 -0
  168. package/public/dist/assets/message-history-bw4qF01Z.js +1 -0
  169. package/public/dist/assets/page-shell-DfinU3mb.js +1 -0
  170. package/public/dist/assets/react-dom-URBLzV3w.js +1 -0
  171. package/public/dist/assets/{render-Dp07lZAJ.js → render-DfYro-fG.js} +1 -1
  172. package/public/dist/assets/{settings-jlI4X-zt.js → settings-CvsLWlJn.js} +38 -30
  173. package/public/dist/assets/settings-DMiQe469.js +1 -0
  174. package/public/dist/assets/settings-DgAlohx9.js +1 -0
  175. package/public/dist/assets/settings-core-BH7J_Rbm.js +1 -0
  176. package/public/dist/assets/{settings-core-B5Uf_lWY.js → settings-core-pnpw-eZv.js} +1 -1
  177. package/public/dist/assets/{settings-embedding-BfWzWKMM.js → settings-embedding-BRW0WZvh.js} +3 -3
  178. package/public/dist/assets/{settings-embedding-DhEdT86W.css → settings-embedding-CUQ8Is3y.css} +1 -1
  179. package/public/dist/assets/settings-types-CYKy0xz4.js +1 -0
  180. package/public/dist/assets/shared-D1begqvi.js +1 -0
  181. package/public/dist/assets/{sidebar-BUemG2ZN.js → sidebar-C_80w4iY.js} +3 -3
  182. package/public/dist/assets/{skills-CKUcEN9m.js → skills-D_2adqge.js} +1 -1
  183. package/public/dist/assets/skills-DeNVAVgt.js +1 -0
  184. package/public/dist/assets/{slash-commands-D34GgHFX.js → slash-commands-B_Hq5RkC.js} +2 -2
  185. package/public/dist/assets/slash-commands-Cj5qoRWc.js +1 -0
  186. package/public/dist/assets/tool-input-DI7uu8Ah.js +2 -0
  187. package/public/dist/assets/{trace-drawer-DBmK-5F_.js → trace-drawer-B6XuPodh.js} +1 -1
  188. package/public/dist/assets/ui-BbR_fFiK.js +1 -0
  189. package/public/dist/assets/{ui-vm2iuLcS.js → ui-D8xzm7DN.js} +1 -1
  190. package/public/dist/index.html +11 -3
  191. package/public/dist/manager/index.html +3 -3
  192. package/public/dist/settings/index.html +2 -2
  193. package/public/index.html +9 -1
  194. package/public/js/features/activity-history.ts +50 -21
  195. package/public/js/features/activity-rows.ts +158 -10
  196. package/public/js/features/activity-view.ts +5 -5
  197. package/public/js/features/chat.ts +2 -0
  198. package/public/js/features/employees.ts +1 -0
  199. package/public/js/features/resize-guard.ts +39 -0
  200. package/public/js/features/settings-cli-status.ts +49 -17
  201. package/public/js/features/settings-types.ts +39 -1
  202. package/public/js/features/skill-mentions.ts +143 -0
  203. package/public/js/main.ts +15 -0
  204. package/public/js/virtual-scroll.ts +67 -1
  205. package/public/locales/en.json +2 -0
  206. package/public/locales/ja.json +2 -0
  207. package/public/locales/ko.json +2 -0
  208. package/public/locales/zh.json +2 -0
  209. package/public/manager/src/AppChrome.tsx +2 -0
  210. package/public/manager/src/InstancePreview.tsx +1 -1
  211. package/public/manager/src/SidebarRailRouter.tsx +3 -1
  212. package/public/manager/src/browser-panel/BrowserPanel.tsx +47 -12
  213. package/public/manager/src/browser-panel/browser-address-state.ts +11 -0
  214. package/public/manager/src/client-platform.ts +18 -0
  215. package/public/manager/src/code/CodeCanvas.tsx +4 -2
  216. package/public/manager/src/code/CodeComposer.tsx +22 -10
  217. package/public/manager/src/code/CodeDraftEmptyState.tsx +64 -0
  218. package/public/manager/src/code/CodeSessionList.tsx +154 -40
  219. package/public/manager/src/code/CodeTranscript.tsx +104 -16
  220. package/public/manager/src/code/CodeWorkbench.tsx +21 -11
  221. package/public/manager/src/code/CodeWorkspaceHeader.tsx +5 -10
  222. package/public/manager/src/code/ComposerFooter.tsx +9 -1
  223. package/public/manager/src/code/code-composer.css +1 -1
  224. package/public/manager/src/code/code-controller-draft-storage.ts +16 -8
  225. package/public/manager/src/code/code-controller-drafts.ts +33 -6
  226. package/public/manager/src/code/code-controller-runtime.ts +189 -17
  227. package/public/manager/src/code/code-controller-types.ts +19 -1
  228. package/public/manager/src/code/code-recent-workspaces.ts +25 -0
  229. package/public/manager/src/code/code-session-client.ts +19 -1
  230. package/public/manager/src/code/code-session-sidebar.css +38 -0
  231. package/public/manager/src/code/code-session-state.ts +2 -0
  232. package/public/manager/src/code/code-types.ts +47 -0
  233. package/public/manager/src/code/code-workbench.css +36 -1
  234. package/public/manager/src/code/code.css +171 -7
  235. package/public/manager/src/code/session-order.ts +80 -0
  236. package/public/manager/src/code/tool-summary.ts +45 -11
  237. package/public/manager/src/folder-panel/folder-shortcuts.ts +5 -9
  238. package/public/manager/src/hooks/useCommandPalette.ts +3 -7
  239. package/public/manager/src/main.tsx +1 -0
  240. package/public/manager/src/manager-components.css +25 -23
  241. package/public/manager/src/manager-dashboard-reminders.css +2 -2
  242. package/public/manager/src/manager-layout.css +1 -1
  243. package/public/manager/src/manager-shortcut-runner.ts +9 -2
  244. package/public/manager/src/manager-shortcuts.ts +83 -21
  245. package/public/manager/src/panels/desktop-bridge.ts +4 -1
  246. package/public/manager/src/panels/panels.css +9 -0
  247. package/public/manager/src/preview.ts +19 -4
  248. package/public/manager/src/settings/pages/AdvancedExport.tsx +28 -30
  249. package/public/manager/src/settings/pages/Browser.tsx +45 -47
  250. package/public/manager/src/settings/pages/ChannelsDiscord.tsx +51 -26
  251. package/public/manager/src/settings/pages/ChannelsSlack.tsx +59 -17
  252. package/public/manager/src/settings/pages/ChannelsTelegram.tsx +51 -26
  253. package/public/manager/src/settings/pages/Display.tsx +2 -1
  254. package/public/manager/src/settings/pages/Employees.tsx +3 -3
  255. package/public/manager/src/settings/pages/Mcp.tsx +220 -200
  256. package/public/manager/src/settings/pages/Memory.tsx +35 -41
  257. package/public/manager/src/settings/pages/ModelProvider.tsx +23 -98
  258. package/public/manager/src/settings/pages/Network.tsx +5 -4
  259. package/public/manager/src/settings/pages/Permissions.tsx +38 -16
  260. package/public/manager/src/settings/pages/Prompts.tsx +12 -9
  261. package/public/manager/src/settings/pages/SpeechKeys.tsx +132 -139
  262. package/public/manager/src/settings/pages/TelegramHub.tsx +67 -20
  263. package/public/manager/src/settings/pages/components/AvatarCard.tsx +9 -8
  264. package/public/manager/src/settings/pages/components/ChannelSetupEntry.tsx +2 -2
  265. package/public/manager/src/settings/pages/components/EmployeeRow.tsx +6 -12
  266. package/public/manager/src/settings/pages/components/HealthBadge.tsx +11 -6
  267. package/public/manager/src/settings/pages/components/HeartbeatJobRow.tsx +35 -16
  268. package/public/manager/src/settings/pages/components/HeartbeatJobsSection.tsx +11 -11
  269. package/public/manager/src/settings/pages/components/HeartbeatMarkdownSection.tsx +7 -7
  270. package/public/manager/src/settings/pages/components/InlineWarn.tsx +4 -9
  271. package/public/manager/src/settings/pages/components/McpServerCard.tsx +39 -27
  272. package/public/manager/src/settings/pages/components/MemoryRow.tsx +21 -16
  273. package/public/manager/src/settings/pages/components/PerCliRow.tsx +122 -121
  274. package/public/manager/src/settings/pages/components/PiProfileDialog.tsx +9 -6
  275. package/public/manager/src/settings/pages/components/SlackSetup.tsx +8 -8
  276. package/public/manager/src/settings/pages/components/TransportStatusChips.tsx +14 -10
  277. package/public/manager/src/settings/pages/components/agent/AgentEmployeesSection.tsx +26 -26
  278. package/public/manager/src/settings/pages/components/agent/PermissionQuickSection.tsx +5 -5
  279. package/public/manager/src/settings/pages/components/agent/RuntimeEmployeeRow.tsx +14 -11
  280. package/public/manager/src/settings/pages/components/agent/RuntimeHeader.tsx +1 -3
  281. package/public/manager/src/settings/pages/components/agent/agent-meta.ts +0 -2
  282. package/public/manager/src/settings/pages/components/runtime-transport-field.tsx +2 -2
  283. package/public/manager/src/settings/pages/manager/Activity.tsx +6 -2
  284. package/public/manager/src/settings/pages/manager/Display.tsx +3 -8
  285. package/public/manager/src/settings/pages/manager/shared.tsx +44 -33
  286. package/public/manager/src/settings/pages/page-shell.tsx +66 -0
  287. package/public/manager/src/settings-agent.css +185 -36
  288. package/public/manager/src/settings-standalone.tsx +1 -0
  289. package/public/manager/src/settings-surface.css +96 -0
  290. package/public/manager/src/types.ts +1 -0
  291. package/scripts/ci/install-ripgrep.sh +35 -0
  292. package/scripts/collect-fresh-install-evidence.sh +2 -2
  293. package/scripts/install-risk-gate.mjs +2 -3
  294. package/scripts/install-wsl.sh +1 -1
  295. package/scripts/install.ps1 +1 -1
  296. package/scripts/install.sh +1 -1
  297. package/scripts/release-1.6.0.sh +1 -1
  298. package/scripts/release-gates.mjs +48 -13
  299. package/scripts/release-preview.sh +2 -2
  300. package/scripts/restack-pr.sh +88 -0
  301. package/scripts/verify-electron-update-metadata.mjs +1 -1
  302. package/scripts/windows-support-contract.json +1 -1
  303. package/public/dist/assets/Activity-BUrp73Re.js +0 -1
  304. package/public/dist/assets/AdvancedExport-B7h_ZvBu.js +0 -1
  305. package/public/dist/assets/Agent-DnbZJP7b.js +0 -1
  306. package/public/dist/assets/Browser-CiBoK5Qx.js +0 -1
  307. package/public/dist/assets/BrowserPanel-SZAUc9T2.js +0 -3
  308. package/public/dist/assets/ChannelEnablementControl-Dl0uYx38.js +0 -85
  309. package/public/dist/assets/ChannelSetupEntry-DxtOrN01.js +0 -1
  310. package/public/dist/assets/ChannelsDiscord-BEGGwd_3.js +0 -1
  311. package/public/dist/assets/ChannelsSlack-BryC2Ahr.js +0 -1
  312. package/public/dist/assets/ChannelsTelegram-CGSpaImJ.js +0 -1
  313. package/public/dist/assets/CodeCanvas-DpkFi5Au.js +0 -2
  314. package/public/dist/assets/DashboardMeta-Dh-tasbY.js +0 -1
  315. package/public/dist/assets/DesignPanel-NLNK9wCo.js +0 -2
  316. package/public/dist/assets/Display-BHGFX3O0.js +0 -1
  317. package/public/dist/assets/Display-BW-_pKRf.js +0 -1
  318. package/public/dist/assets/DocPanel-BM41cYpS.js +0 -1
  319. package/public/dist/assets/Employees-BuFw6-fT.js +0 -1
  320. package/public/dist/assets/FolderPanel-C-eQT3Yq.js +0 -3
  321. package/public/dist/assets/Heartbeat-CIVtKWNc.js +0 -1
  322. package/public/dist/assets/InlineWarn-DIMbcbzk.js +0 -1
  323. package/public/dist/assets/MarkdownRenderer-DyVx6DxM.js +0 -1
  324. package/public/dist/assets/Mcp-uKjor7vh.js +0 -4
  325. package/public/dist/assets/Memory-BSDIXT0B.js +0 -1
  326. package/public/dist/assets/ModelProvider-DMh2tXUx.js +0 -1
  327. package/public/dist/assets/Network-4Pa6JkhK.js +0 -1
  328. package/public/dist/assets/NotesGraphWorkspace-CgdC-fM6.js +0 -1
  329. package/public/dist/assets/PanelLayoutProvider-mn8sI0h-.js +0 -1
  330. package/public/dist/assets/Permissions-CodIW-Yd.js +0 -1
  331. package/public/dist/assets/Profile-DPqrYA44.js +0 -1
  332. package/public/dist/assets/Prompts-CvAx7QqR.js +0 -1
  333. package/public/dist/assets/SpeechKeys-CVBCqoBn.js +0 -1
  334. package/public/dist/assets/TelegramHub-4zKwpk0P.js +0 -1
  335. package/public/dist/assets/app-ByMfeXp-.js +0 -55
  336. package/public/dist/assets/app-DAJWqs33.css +0 -1
  337. package/public/dist/assets/bgtask-badge-Ch88fnhf.js +0 -1
  338. package/public/dist/assets/error-normalize-CL69Bl7z.js +0 -1
  339. package/public/dist/assets/fields-mlGpofqQ.js +0 -1
  340. package/public/dist/assets/iframe-renderer-Bj1JolO8.js +0 -142
  341. package/public/dist/assets/iframe-renderer-DWnvUSrx.js +0 -1
  342. package/public/dist/assets/jsx-runtime-NZYk81nU.js +0 -1
  343. package/public/dist/assets/manager-Bi_xw7TW.js +0 -5
  344. package/public/dist/assets/manager-BnQHAKk6.css +0 -1
  345. package/public/dist/assets/manager-shortcuts-BDOzd8zm.js +0 -1
  346. package/public/dist/assets/memory-Bk_cb3sw.js +0 -1
  347. package/public/dist/assets/message-history-D2vniu04.js +0 -4
  348. package/public/dist/assets/message-history-GAtF_wbZ.js +0 -1
  349. package/public/dist/assets/page-shell-BeGD0rRQ.js +0 -1
  350. package/public/dist/assets/react-dom-DyUOYpVL.js +0 -1
  351. package/public/dist/assets/settings-W4KG9ivu.js +0 -1
  352. package/public/dist/assets/settings-WVGhtneN.js +0 -1
  353. package/public/dist/assets/settings-client-CmwRsVd1.js +0 -1
  354. package/public/dist/assets/settings-core-CgKGnMA5.js +0 -1
  355. package/public/dist/assets/settings-types-D3cd6SWy.js +0 -1
  356. package/public/dist/assets/shared-CiNP20HB.js +0 -1
  357. package/public/dist/assets/skills-Co7Mr-qP.js +0 -1
  358. package/public/dist/assets/slash-commands-BEr-vmIr.js +0 -1
  359. package/public/dist/assets/ui-TUyJsMUf.js +0 -1
  360. package/public/manager/src/settings/pages/components/EngineSubsection.tsx +0 -25
@@ -1,4 +1,5 @@
1
1
  import type { DashboardShortcutAction, DashboardShortcutKeymap } from './types';
2
+ import { currentClientPlatform, isMacLikePlatform } from './client-platform';
2
3
 
3
4
  export const MANAGER_SHORTCUT_ACTIONS: DashboardShortcutAction[] = [
4
5
  'toggleInstanceSettings',
@@ -11,6 +12,7 @@ export const MANAGER_SHORTCUT_ACTIONS: DashboardShortcutAction[] = [
11
12
  'toggleRightPanel',
12
13
  'focusTerminal',
13
14
  'newTerminalSession',
15
+ 'newCodeSession',
14
16
  'openDiff',
15
17
  'openFolderTree',
16
18
  'closeFocusedTab',
@@ -50,6 +52,9 @@ export const DEFAULT_MANAGER_SHORTCUT_KEYMAP: DashboardShortcutKeymap = {
50
52
  toggleRightPanel: 'Meta+B',
51
53
  focusTerminal: 'Ctrl+`',
52
54
  newTerminalSession: 'Ctrl+Shift+`',
55
+ // Alt over Meta: Meta+Shift+N is Chrome's incognito chord, so a web-hosted
56
+ // dashboard would never see the keydown. Alt+Shift+N has no browser default.
57
+ newCodeSession: 'Alt+Shift+N',
53
58
  openDiff: 'Meta+Shift+D',
54
59
  openFolderTree: 'Meta+Shift+E',
55
60
  closeFocusedTab: 'Meta+W',
@@ -84,6 +89,23 @@ const MANAGER_SHORTCUT_ALIASES: Partial<Record<DashboardShortcutAction, string[]
84
89
  newTerminalSession: ['Ctrl+Shift+`'],
85
90
  };
86
91
 
92
+ /**
93
+ * Keymap modifier tokens. `Meta` (and its spellings `Cmd`, `Command`, `Mod`) is
94
+ * the primary modifier: ⌘ on macOS, Ctrl on Windows/Linux — the same meaning as
95
+ * the Electron menu's `CommandOrControl`. Persisted keymaps keep their `Meta+…`
96
+ * strings; only the interpretation follows the client platform. `Win`/`Super`
97
+ * names the physical Windows/Super key (`metaKey`) on every platform.
98
+ */
99
+ const PRIMARY_MODIFIER_TOKENS = new Set(['meta', 'cmd', 'command', 'mod']);
100
+ const SUPER_MODIFIER_TOKENS = new Set(['win', 'windows', 'super']);
101
+ const CTRL_MODIFIER_TOKENS = new Set(['ctrl', 'control']);
102
+ const ALT_MODIFIER_TOKENS = new Set(['alt', 'option']);
103
+
104
+ export type ShortcutPlatformOptions = {
105
+ /** Client platform string; defaults to the current browser/window platform. */
106
+ platform?: string;
107
+ };
108
+
87
109
  type ParsedShortcut = {
88
110
  key: string;
89
111
  altKey: boolean;
@@ -104,7 +126,7 @@ function normalizeKey(value: string): string {
104
126
  return lower;
105
127
  }
106
128
 
107
- function parseShortcut(raw: string): ParsedShortcut | null {
129
+ function parseShortcut(raw: string, mac: boolean): ParsedShortcut | null {
108
130
  const parts = raw.split('+').map(part => part.trim()).filter(Boolean);
109
131
  if (parts.length === 0) return null;
110
132
  const parsed: ParsedShortcut = {
@@ -116,9 +138,12 @@ function parseShortcut(raw: string): ParsedShortcut | null {
116
138
  };
117
139
  for (const part of parts) {
118
140
  const lower = part.toLowerCase();
119
- if (lower === 'alt' || lower === 'option') parsed.altKey = true;
120
- else if (lower === 'ctrl' || lower === 'control') parsed.ctrlKey = true;
121
- else if (lower === 'meta' || lower === 'cmd' || lower === 'command') parsed.metaKey = true;
141
+ if (ALT_MODIFIER_TOKENS.has(lower)) parsed.altKey = true;
142
+ else if (CTRL_MODIFIER_TOKENS.has(lower)) parsed.ctrlKey = true;
143
+ else if (PRIMARY_MODIFIER_TOKENS.has(lower)) {
144
+ if (mac) parsed.metaKey = true;
145
+ else parsed.ctrlKey = true;
146
+ } else if (SUPER_MODIFIER_TOKENS.has(lower)) parsed.metaKey = true;
122
147
  else if (lower === 'shift') parsed.shiftKey = true;
123
148
  else parsed.key = normalizeKey(part);
124
149
  }
@@ -138,18 +163,18 @@ export function normalizeManagerShortcutKeymap(value: unknown): DashboardShortcu
138
163
  function resolveEventKey(event: KeyboardEvent): string {
139
164
  if (event.code === 'Backquote') return '`';
140
165
  if (event.altKey && event.code?.startsWith('Digit')) return event.code.slice(5);
141
- const k = normalizeKey(event.key);
142
- if (k.length === 1) return k;
143
- // macOS Option+letter produces special chars (e.g. ∆ for Alt+J).
144
- // Fall back to event.code to recover the original letter.
166
+ // macOS Option+letter produces special chars (e.g. ∆ for Alt+J, ˜ for
167
+ // Option+Shift+N), and those are themselves single characters -- so the
168
+ // character cannot be trusted to be the letter the chord names. The code
169
+ // wins whenever Option is held, exactly as it does for the digits above.
145
170
  if (event.altKey && event.code?.startsWith('Key')) {
146
171
  return event.code.slice(3).toLowerCase();
147
172
  }
148
- return k;
173
+ return normalizeKey(event.key);
149
174
  }
150
175
 
151
- export function shortcutMatches(event: KeyboardEvent, raw: string): boolean {
152
- const parsed = parseShortcut(raw);
176
+ export function shortcutMatches(event: KeyboardEvent, raw: string, platform: string = currentClientPlatform()): boolean {
177
+ const parsed = parseShortcut(raw, isMacLikePlatform(platform));
153
178
  if (!parsed) return false;
154
179
  return event.altKey === parsed.altKey
155
180
  && event.ctrlKey === parsed.ctrlKey
@@ -203,26 +228,63 @@ export const MENU_ACCELERATOR_SHORTCUT_CHORDS: string[] = [
203
228
  export function actionForShortcutEvent(
204
229
  event: KeyboardEvent,
205
230
  keymap: unknown,
206
- options?: { menuOwned?: boolean },
231
+ options?: { menuOwned?: boolean } & ShortcutPlatformOptions,
207
232
  ): DashboardShortcutAction | null {
208
- if (options?.menuOwned && MENU_ACCELERATOR_SHORTCUT_CHORDS.some(chord => shortcutMatches(event, chord))) {
233
+ // Resolve once: the menu-owned check and the keymap must agree on what Meta
234
+ // means, or Ctrl+W on Windows desktop would fire from both menu and renderer.
235
+ const platform = options?.platform ?? currentClientPlatform();
236
+ if (options?.menuOwned && MENU_ACCELERATOR_SHORTCUT_CHORDS.some(chord => shortcutMatches(event, chord, platform))) {
209
237
  return null;
210
238
  }
211
239
  const shortcuts = normalizeManagerShortcutKeymap(keymap);
212
240
  for (const action of MANAGER_SHORTCUT_ACTIONS) {
213
241
  if (RENDERER_DISABLED_SHORTCUT_ACTIONS.has(action)) continue;
214
- if (shortcutMatches(event, shortcuts[action])) return action;
215
- if (MANAGER_SHORTCUT_ALIASES[action]?.some(shortcut => shortcutMatches(event, shortcut))) return action;
242
+ if (shortcutMatches(event, shortcuts[action], platform)) return action;
243
+ if (MANAGER_SHORTCUT_ALIASES[action]?.some(shortcut => shortcutMatches(event, shortcut, platform))) return action;
216
244
  }
217
245
  return null;
218
246
  }
219
247
 
220
- export function formatShortcut(raw: string): string {
221
- return raw
222
- .split('+')
223
- .map(part => part.trim())
224
- .filter(Boolean)
225
- .join(' + ');
248
+ const MAC_KEY_LABELS: Record<string, string> = {
249
+ left: '←', arrowleft: '←', right: '→', arrowright: '→',
250
+ up: '↑', arrowup: '↑', down: '↓', arrowdown: '↓',
251
+ };
252
+
253
+ function macModifierLabel(lower: string): string | null {
254
+ if (PRIMARY_MODIFIER_TOKENS.has(lower) || SUPER_MODIFIER_TOKENS.has(lower)) return '⌘';
255
+ if (CTRL_MODIFIER_TOKENS.has(lower)) return '⌃';
256
+ if (ALT_MODIFIER_TOKENS.has(lower)) return '⌥';
257
+ if (lower === 'shift') return '⇧';
258
+ return null;
259
+ }
260
+
261
+ function otherModifierLabel(lower: string): string | null {
262
+ if (PRIMARY_MODIFIER_TOKENS.has(lower) || CTRL_MODIFIER_TOKENS.has(lower)) return 'Ctrl';
263
+ if (SUPER_MODIFIER_TOKENS.has(lower)) return 'Win';
264
+ if (ALT_MODIFIER_TOKENS.has(lower)) return 'Alt';
265
+ if (lower === 'shift') return 'Shift';
266
+ return null;
267
+ }
268
+
269
+ /**
270
+ * Human label for a stored chord on the client platform: `Meta+Shift+B` reads
271
+ * `⌘⇧B` on macOS and `Ctrl + Shift + B` on Windows/Linux. The stored string is
272
+ * not changed; this is display only.
273
+ */
274
+ export function formatShortcut(raw: string, platform: string = currentClientPlatform()): string {
275
+ const parts = raw.split('+').map(part => part.trim()).filter(Boolean);
276
+ const mac = isMacLikePlatform(platform);
277
+ const labels: string[] = [];
278
+ for (const part of parts) {
279
+ const lower = part.toLowerCase();
280
+ const modifier = mac ? macModifierLabel(lower) : otherModifierLabel(lower);
281
+ const label = modifier
282
+ ?? (mac ? (MAC_KEY_LABELS[lower] ?? (part.length === 1 ? part.toUpperCase() : part)) : part);
283
+ // Meta and Ctrl both read Ctrl off macOS; show a doubled modifier once.
284
+ if (modifier && labels.includes(label)) continue;
285
+ labels.push(label);
286
+ }
287
+ return labels.join(mac ? '' : ' + ');
226
288
  }
227
289
 
228
290
  export function isManagerShortcutEditableTarget(target: EventTarget | null): boolean {
@@ -193,6 +193,8 @@ export type BrowserWebviewTabState = {
193
193
  error?: string;
194
194
  favicons?: string[];
195
195
  zoomFactor?: number;
196
+ /** 'auto': fit-to-width manages zoomFactor; 'manual': user zoom wins. */
197
+ zoomMode?: 'auto' | 'manual';
196
198
  };
197
199
 
198
200
  /** v5: element resolved from the native inspect pick (CDP DOM/AX domains). */
@@ -230,7 +232,8 @@ export type BrowserWebviewCommand =
230
232
  | { kind: 'stop'; tabId: string }
231
233
  | { kind: 'zoomIn'; tabId: string }
232
234
  | { kind: 'zoomOut'; tabId: string }
233
- | { kind: 'zoomReset'; tabId: string };
235
+ | { kind: 'zoomReset'; tabId: string }
236
+ | { kind: 'fitToWidth'; tabId: string };
234
237
 
235
238
  export type BrowserWebviewNativeAction =
236
239
  | { kind: 'openExternal'; tabId: string }
@@ -46,6 +46,15 @@
46
46
  body.is-resizing-horizontal { cursor: col-resize !important; user-select: none; }
47
47
  body.is-resizing-vertical { cursor: row-resize !important; user-select: none; }
48
48
 
49
+ /* While a drag resizes the grid, no pointer may reach a framed preview and no
50
+ scrollable subtree may let scroll anchoring rewrite its scrollTop — the page
51
+ and the iframe must only reflow, never scroll. */
52
+ body.is-resizing-horizontal iframe,
53
+ body.is-resizing-vertical iframe { pointer-events: none; }
54
+
55
+ body.is-resizing-horizontal *,
56
+ body.is-resizing-vertical * { overflow-anchor: none; }
57
+
49
58
  .panel-resize-overlay {
50
59
  position: fixed;
51
60
  inset: 0;
@@ -19,6 +19,8 @@ type PreviewArgument =
19
19
  | {
20
20
  theme?: PreviewTheme | null;
21
21
  transport?: PreviewTransportPreference | null;
22
+ /** True when the preview renders inside the Electron desktop shell. */
23
+ desktop?: boolean | null;
22
24
  }
23
25
  | undefined;
24
26
 
@@ -35,17 +37,19 @@ function isPreviewTheme(value: PreviewArgument): value is PreviewTheme {
35
37
  return value === 'dark' || value === 'light';
36
38
  }
37
39
 
38
- function resolvePreviewArgument(value: PreviewArgument): { theme: PreviewTheme | null; transport: PreviewTransportPreference | null } {
40
+ function resolvePreviewArgument(value: PreviewArgument): { theme: PreviewTheme | null; transport: PreviewTransportPreference | null; desktop: boolean } {
39
41
  if (value && typeof value === 'object') {
40
42
  const theme = value.theme === 'dark' || value.theme === 'light' ? value.theme : null;
41
43
  return {
42
44
  theme,
43
45
  transport: value.transport === 'legacy-path' || value.transport === 'origin-port' ? value.transport : null,
46
+ desktop: value.desktop === true,
44
47
  };
45
48
  }
46
49
  return {
47
50
  theme: isPreviewTheme(value) ? value : null,
48
51
  transport: value === 'proxy' ? 'legacy-path' : null,
52
+ desktop: false,
49
53
  };
50
54
  }
51
55
 
@@ -73,6 +77,17 @@ export function appendPreviewTheme(src: string, theme: PreviewTheme | null | und
73
77
  return url.toString();
74
78
  }
75
79
 
80
+ /** Marks preview URLs loaded inside the desktop shell so the framed page can
81
+ * apply desktop chrome (titlebar-inset topbar height) without a preload. */
82
+ export function appendPreviewDesktop(src: string, desktop: boolean): string {
83
+ if (!desktop) return src;
84
+ const isRelative = src.startsWith('/');
85
+ const url = new URL(src, 'http://jaw.local');
86
+ url.searchParams.set('jawDesktop', '1');
87
+ if (isRelative) return `${url.pathname}${url.search}${url.hash}`;
88
+ return url.toString();
89
+ }
90
+
76
91
  export function buildPreviewState(
77
92
  instance: DashboardInstance | null,
78
93
  data: DashboardScanResult | null,
@@ -94,7 +109,7 @@ export function buildPreviewState(
94
109
  return { canPreview: false, src: null, reason: 'This port is outside the proxy allowlist.', transport: 'none', warning: null };
95
110
  }
96
111
  const originPreview = proxy.preview?.instances[String(instance.port)];
97
- const { theme, transport } = resolvePreviewArgument(previewArgument);
112
+ const { theme, transport, desktop } = resolvePreviewArgument(previewArgument);
98
113
  const useOriginPort = transport !== 'legacy-path'
99
114
  && proxy.preview?.enabled
100
115
  && originPreview?.status === 'ready'
@@ -105,7 +120,7 @@ export function buildPreviewState(
105
120
  previewUrl.pathname = `${previewUrl.pathname.replace(/\/?$/, '/')}0`;
106
121
  return {
107
122
  canPreview: true,
108
- src: appendPreviewTheme(previewUrl.toString(), theme),
123
+ src: appendPreviewDesktop(appendPreviewTheme(previewUrl.toString(), theme), desktop),
109
124
  reason: null,
110
125
  transport: 'origin-port',
111
126
  warning: 'origin proxy ready',
@@ -114,7 +129,7 @@ export function buildPreviewState(
114
129
  const basePath = proxy.basePath || '/i';
115
130
  return {
116
131
  canPreview: true,
117
- src: appendPreviewTheme(`${basePath}/${instance.port}/0`, theme),
132
+ src: appendPreviewDesktop(appendPreviewTheme(`${basePath}/${instance.port}/0`, theme), desktop),
118
133
  reason: null,
119
134
  transport: 'legacy-path',
120
135
  warning: 'legacy proxy fallback',
@@ -6,7 +6,8 @@
6
6
 
7
7
  import { useCallback, useEffect, useState } from 'react';
8
8
  import type { SettingsPageProps } from '../types';
9
- import { SettingsSection, PageError, PageLoading, PageOffline, usePageSnapshot } from './page-shell';
9
+ import { SettingsSection, SettingsActions, PageError, PageLoading, PageOffline, usePageSnapshot } from './page-shell';
10
+ import { ToggleField } from '../fields';
10
11
  import { describeError } from '../components/error-normalize';
11
12
 
12
13
  type ExportImportProps = SettingsPageProps & {
@@ -44,6 +45,7 @@ export function stripServerOwnedSettingsFields(settings: Record<string, unknown>
44
45
  multiSessionDefaultMigration: _sessionMigration,
45
46
  nativeTransportMigration: _nativeTransportMigration,
46
47
  maxConcurrentDefaultMigration: _maxConcurrentDefaultMigration,
48
+ claudeDefaultModelMigration: _claudeDefaultModelMigration,
47
49
  slackEnvironmentVariables: _slackEnvironmentVariables,
48
50
  telegramEnvironmentVariables: _telegramEnvironmentVariables,
49
51
  discordEnvironmentVariables: _discordEnvironmentVariables,
@@ -103,28 +105,27 @@ export default function AdvancedExport({ port, client, triggerDownload }: Export
103
105
  title="Export"
104
106
  hint={`Download the resolved /i/${port}/api/settings document as JSON.`}
105
107
  >
106
- <button
107
- type="button"
108
- className="settings-action settings-action-secondary"
109
- onClick={onExport}
110
- >
111
- Download settings JSON
112
- </button>
108
+ <SettingsActions>
109
+ <button
110
+ type="button"
111
+ className="settings-action"
112
+ onClick={onExport}
113
+ >
114
+ Download settings JSON
115
+ </button>
116
+ </SettingsActions>
113
117
  </SettingsSection>
114
118
 
115
119
  <SettingsSection
116
120
  title="Import (advanced)"
117
121
  hint="Replaces matching keys via PUT. Only enable when you understand the impact."
118
122
  >
119
- <label className="settings-field" htmlFor="advanced-toggle">
120
- <span className="settings-field-label">Show import controls</span>
121
- <input
122
- id="advanced-toggle"
123
- type="checkbox"
124
- checked={showAdvanced}
125
- onChange={(event) => setShowAdvanced(event.target.checked)}
126
- />
127
- </label>
123
+ <ToggleField
124
+ id="advanced-toggle"
125
+ label="Show import controls"
126
+ value={showAdvanced}
127
+ onChange={setShowAdvanced}
128
+ />
128
129
  {showAdvanced ? (
129
130
  <>
130
131
  <label className="settings-field" htmlFor="advanced-import">
@@ -142,20 +143,17 @@ export default function AdvancedExport({ port, client, triggerDownload }: Export
142
143
  {importError}
143
144
  </span>
144
145
  ) : null}
145
- {importResult ? (
146
- <span className="settings-field-description" role="status">
147
- {importResult}
148
- </span>
149
- ) : null}
150
146
  </label>
151
- <button
152
- type="button"
153
- className="settings-action settings-action-save"
154
- onClick={() => void onImport()}
155
- disabled={importBusy || importText.trim() === ''}
156
- >
157
- {importBusy ? 'Importing…' : 'Apply import'}
158
- </button>
147
+ <SettingsActions status={importResult ? <span role="status">{importResult}</span> : undefined}>
148
+ <button
149
+ type="button"
150
+ className="settings-action settings-action-save"
151
+ onClick={() => void onImport()}
152
+ disabled={importBusy || importText.trim() === ''}
153
+ >
154
+ {importBusy ? 'Importing…' : 'Apply import'}
155
+ </button>
156
+ </SettingsActions>
159
157
  </>
160
158
  ) : null}
161
159
  </SettingsSection>
@@ -11,8 +11,15 @@
11
11
  import { useCallback, useEffect, useRef, useState } from 'react';
12
12
  import type { SettingsPageProps } from '../types';
13
13
  import { SettingsRequestError } from '../settings-client';
14
- import { PageError, PageLoading, SettingsSection } from './page-shell';
15
- import { InlineWarn } from './components/InlineWarn';
14
+ import {
15
+ PageError,
16
+ PageLoading,
17
+ SettingsActions,
18
+ SettingsKeyValue,
19
+ SettingsNote,
20
+ SettingsSection,
21
+ StatusBadge,
22
+ } from './page-shell';
16
23
 
17
24
  export type BrowserStatus = {
18
25
  running: boolean;
@@ -185,28 +192,35 @@ export default function Browser({ port, client }: SettingsPageProps) {
185
192
  const { status, activeTab } = pollState;
186
193
  const actionPending = actionState.kind === 'pending';
187
194
 
195
+ const actionStatus =
196
+ actionState.kind === 'pending' ? (
197
+ <span role="status">{actionState.label}…</span>
198
+ ) : actionState.kind === 'success' ? (
199
+ <span role="status">{actionState.message}</span>
200
+ ) : null;
201
+
188
202
  return (
189
203
  <form className="settings-page-form" onSubmit={(event) => event.preventDefault()}>
190
204
  <SettingsSection
191
205
  title="Status"
192
206
  hint={`Polled every ${POLL_INTERVAL_MS / 1000}s while this page is open.`}
193
207
  >
194
- <dl className="settings-readonly-grid">
195
- <dt>Running</dt>
196
- <dd>{status.running ? '✅ yes' : '❌ no'}</dd>
197
- <dt>Tabs</dt>
198
- <dd>{status.tabs}</dd>
199
- <dt>CDP URL</dt>
200
- <dd>
201
- <code>{status.cdpUrl || '—'}</code>
202
- </dd>
203
- <dt>Instance port</dt>
204
- <dd>
205
- <code>{port}</code>
206
- </dd>
207
- </dl>
208
-
209
- <div className="browser-actions">
208
+ <SettingsKeyValue
209
+ items={[
210
+ {
211
+ label: 'Running',
212
+ value: status.running ? (
213
+ <StatusBadge tone="ok">Running</StatusBadge>
214
+ ) : (
215
+ <StatusBadge tone="neutral">Stopped</StatusBadge>
216
+ ),
217
+ },
218
+ { label: 'Tabs', value: status.tabs },
219
+ { label: 'CDP URL', value: status.cdpUrl || '—', mono: true },
220
+ { label: 'Instance port', value: port, mono: true },
221
+ ]}
222
+ />
223
+ <SettingsActions status={actionStatus}>
210
224
  <button
211
225
  type="button"
212
226
  className="settings-action settings-action-save"
@@ -233,26 +247,15 @@ export default function Browser({ port, client }: SettingsPageProps) {
233
247
  </button>
234
248
  <button
235
249
  type="button"
236
- className="settings-action settings-action-discard"
250
+ className="settings-action settings-action-danger"
237
251
  disabled={actionPending}
238
252
  onClick={onReset}
239
253
  >
240
254
  Reset profile
241
255
  </button>
242
- </div>
243
-
244
- {actionState.kind === 'pending' && (
245
- <p className="settings-section-hint" role="status">
246
- {actionState.label}…
247
- </p>
248
- )}
249
- {actionState.kind === 'success' && (
250
- <p className="settings-section-hint" role="status">
251
- ✅ {actionState.message}
252
- </p>
253
- )}
256
+ </SettingsActions>
254
257
  {actionState.kind === 'error' && (
255
- <InlineWarn role="alert">{actionState.message}</InlineWarn>
258
+ <SettingsNote tone="error" role="alert">{actionState.message}</SettingsNote>
256
259
  )}
257
260
  </SettingsSection>
258
261
 
@@ -261,24 +264,19 @@ export default function Browser({ port, client }: SettingsPageProps) {
261
264
  hint="Tab the agent currently targets. Empty when the browser is stopped."
262
265
  >
263
266
  {!status.running ? (
264
- <p className="settings-section-hint">Browser is not running.</p>
267
+ <SettingsNote>Browser is not running.</SettingsNote>
265
268
  ) : activeTab && activeTab.ok && activeTab.tab ? (
266
- <dl className="settings-readonly-grid">
267
- <dt>URL</dt>
268
- <dd>
269
- <code>{activeTab.tab.url || '—'}</code>
270
- </dd>
271
- <dt>Title</dt>
272
- <dd>{activeTab.tab.title || '—'}</dd>
273
- <dt>Target ID</dt>
274
- <dd>
275
- <code>{activeTab.tab.targetId || '—'}</code>
276
- </dd>
277
- </dl>
269
+ <SettingsKeyValue
270
+ items={[
271
+ { label: 'URL', value: activeTab.tab.url || '—', mono: true },
272
+ { label: 'Title', value: activeTab.tab.title || '—' },
273
+ { label: 'Target ID', value: activeTab.tab.targetId || '—', mono: true },
274
+ ]}
275
+ />
278
276
  ) : (
279
- <p className="settings-section-hint">
277
+ <SettingsNote>
280
278
  No verified active tab{activeTab?.reason ? ` (${activeTab.reason})` : ''}.
281
- </p>
279
+ </SettingsNote>
282
280
  )}
283
281
  </SettingsSection>
284
282
  </form>
@@ -20,6 +20,9 @@ import {
20
20
  PageLoading,
21
21
  PageOffline,
22
22
  usePageSnapshot,
23
+ SettingsActions,
24
+ SettingsKeyValue,
25
+ StatusBadge,
23
26
  } from './page-shell';
24
27
  import { expandPatch } from './path-utils';
25
28
  import { slackText } from './components/SlackSetup';
@@ -190,25 +193,37 @@ export default function ChannelsDiscord({ port, client, dirty, registerSave, man
190
193
  >
191
194
  <fieldset disabled={setupOpen} className="settings-slack-fields">
192
195
  <SettingsSection
193
- title="Channels"
194
- hint="Choose which channels receive inbound chat. Outbound send can still work on any configured channel."
196
+ title="Status"
197
+ hint="Live transport state plus a readiness probe for this channel."
195
198
  >
196
- <ChannelEnablementControl
197
- pageChannel="discord"
198
- snapshot={state.kind === 'ready' ? state.data : {}}
199
- enabledChannels={enabledChannels}
200
- homeChannel={homeChannel}
201
- setEnabledChannels={setEnabledChannels}
202
- setHomeChannel={setHomeChannel}
203
- dirty={dirty}
204
- idPrefix="di-channel"
199
+ <SettingsKeyValue
200
+ items={[
201
+ {
202
+ label: 'Discord',
203
+ value: enabled ? (
204
+ <StatusBadge tone="ok">Enabled</StatusBadge>
205
+ ) : (
206
+ <StatusBadge tone="neutral">Disabled</StatusBadge>
207
+ ),
208
+ },
209
+ ...(environmentManaged
210
+ ? [{ label: 'Managed by', value: environmentVariables.join(', '), mono: true }]
211
+ : []),
212
+ ]}
205
213
  />
206
214
  <TransportStatusChips client={client} channel="discord" />
215
+ <HealthBadge
216
+ client={client}
217
+ label="Discord"
218
+ endpoint="/api/health"
219
+ method="GET"
220
+ interpret={interpretDiscordHealth}
221
+ />
207
222
  </SettingsSection>
208
223
 
209
- <SettingsSection title="Discord" hint={environmentManaged
224
+ <SettingsSection title="Credentials" hint={environmentManaged
210
225
  ? t('settings.discord.managedByEnvironment', { variables: environmentVariables.join(', ') })
211
- : 'Bot token, guild + channels, forwarding rules.'}>
226
+ : 'Bot token, guild, and channel IDs.'}>
212
227
  <ToggleField
213
228
  id="dc-enabled"
214
229
  label="Discord enabled"
@@ -276,6 +291,22 @@ export default function ChannelsDiscord({ port, client, dirty, registerSave, man
276
291
  });
277
292
  }}
278
293
  />
294
+ </SettingsSection>
295
+
296
+ <SettingsSection
297
+ title="Routing"
298
+ hint="Choose which channels receive inbound chat and how replies are delivered. Outbound send can still work on any configured channel."
299
+ >
300
+ <ChannelEnablementControl
301
+ pageChannel="discord"
302
+ snapshot={state.kind === 'ready' ? state.data : {}}
303
+ enabledChannels={enabledChannels}
304
+ homeChannel={homeChannel}
305
+ setEnabledChannels={setEnabledChannels}
306
+ setHomeChannel={setHomeChannel}
307
+ dirty={dirty}
308
+ idPrefix="di-channel"
309
+ />
279
310
  <ToggleField
280
311
  id="dc-forwardAll"
281
312
  label="Forward all"
@@ -316,22 +347,16 @@ export default function ChannelsDiscord({ port, client, dirty, registerSave, man
316
347
  }}
317
348
  />
318
349
  </SettingsSection>
319
-
350
+ </fieldset>
320
351
  <SettingsSection
321
- title="Health"
322
- hint="Probes /api/health for Discord readiness. Degraded mode means the bot is missing the MESSAGE_CONTENT intent (slash commands only)."
352
+ title="Actions"
353
+ hint="Guided setup validates credentials with the issuer before saving."
323
354
  >
324
- <HealthBadge
325
- client={client}
326
- label="Discord"
327
- endpoint="/api/health"
328
- method="GET"
329
- interpret={interpretDiscordHealth}
330
- />
355
+ <SettingsActions>
356
+ <ChannelSetupEntry channel="discord" client={client} dirty={dirty} disabled={environmentManaged}
357
+ open={setupOpen} onOpenChange={setSetupOpen} onSaved={async () => setData(await client.get<DiscordSnapshot>('/api/settings'))} />
358
+ </SettingsActions>
331
359
  </SettingsSection>
332
- </fieldset>
333
- <ChannelSetupEntry channel="discord" client={client} dirty={dirty} disabled={environmentManaged}
334
- open={setupOpen} onOpenChange={setSetupOpen} onSaved={async () => setData(await client.get<DiscordSnapshot>('/api/settings'))} />
335
360
  </form>
336
361
  );
337
362
  }