@clawpump/claw-agent 0.1.4 → 0.1.6

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 (1214) hide show
  1. package/agent/.dockerignore +67 -0
  2. package/agent/.envrc +1 -1
  3. package/agent/.gitattributes +8 -0
  4. package/agent/AGENTS.md +216 -4
  5. package/agent/CONTRIBUTING.md +46 -8
  6. package/agent/Dockerfile +78 -35
  7. package/agent/MANIFEST.in +2 -0
  8. package/agent/README.md +12 -5
  9. package/agent/README.ur-pk.md +261 -0
  10. package/agent/README.zh-CN.md +11 -8
  11. package/agent/SECURITY.md +5 -4
  12. package/agent/acp_adapter/provenance.py +127 -0
  13. package/agent/acp_adapter/server.py +112 -5
  14. package/agent/acp_adapter/session.py +1 -6
  15. package/agent/acp_registry/agent.json +2 -2
  16. package/agent/agent/account_usage.py +313 -1
  17. package/agent/agent/agent_init.py +140 -37
  18. package/agent/agent/agent_runtime_helpers.py +342 -83
  19. package/agent/agent/anthropic_adapter.py +320 -33
  20. package/agent/agent/auxiliary_client.py +525 -105
  21. package/agent/agent/background_review.py +157 -19
  22. package/agent/agent/bedrock_adapter.py +71 -6
  23. package/agent/agent/billing_view.py +295 -0
  24. package/agent/agent/chat_completion_helpers.py +229 -4
  25. package/agent/agent/codex_responses_adapter.py +86 -10
  26. package/agent/agent/codex_runtime.py +153 -1
  27. package/agent/agent/coding_context.py +738 -0
  28. package/agent/agent/context_compressor.py +392 -44
  29. package/agent/agent/context_references.py +34 -1
  30. package/agent/agent/conversation_compression.py +159 -22
  31. package/agent/agent/conversation_loop.py +643 -908
  32. package/agent/agent/copilot_acp_client.py +4 -11
  33. package/agent/agent/credential_pool.py +5 -3
  34. package/agent/agent/credits_tracker.py +794 -0
  35. package/agent/agent/curator.py +91 -18
  36. package/agent/agent/curator_backup.py +26 -10
  37. package/agent/agent/display.py +42 -1
  38. package/agent/agent/error_classifier.py +52 -3
  39. package/agent/agent/errors.py +3 -0
  40. package/agent/agent/file_safety.py +0 -17
  41. package/agent/agent/gemini_native_adapter.py +31 -1
  42. package/agent/agent/i18n.py +48 -4
  43. package/agent/agent/image_gen_provider.py +74 -5
  44. package/agent/agent/image_routing.py +29 -0
  45. package/agent/agent/insights.py +8 -17
  46. package/agent/agent/lsp/install.py +3 -0
  47. package/agent/agent/memory_manager.py +326 -31
  48. package/agent/agent/message_content.py +50 -0
  49. package/agent/agent/model_metadata.py +214 -3
  50. package/agent/agent/moonshot_schema.py +8 -1
  51. package/agent/agent/onboarding.py +60 -0
  52. package/agent/agent/prompt_builder.py +327 -37
  53. package/agent/agent/redact.py +1 -0
  54. package/agent/agent/runtime_cwd.py +34 -5
  55. package/agent/agent/secret_scope.py +205 -0
  56. package/agent/agent/secret_sources/bitwarden.py +34 -2
  57. package/agent/agent/skill_commands.py +90 -1
  58. package/agent/agent/skill_preprocessing.py +1 -0
  59. package/agent/agent/skill_utils.py +209 -36
  60. package/agent/agent/ssl_guard.py +94 -0
  61. package/agent/agent/system_prompt.py +133 -5
  62. package/agent/agent/tool_executor.py +496 -70
  63. package/agent/agent/transports/anthropic.py +83 -21
  64. package/agent/agent/transports/chat_completions.py +94 -5
  65. package/agent/agent/transports/codex.py +67 -2
  66. package/agent/agent/transports/codex_app_server.py +1 -0
  67. package/agent/agent/transports/codex_app_server_session.py +30 -0
  68. package/agent/agent/transports/types.py +12 -0
  69. package/agent/agent/turn_context.py +408 -0
  70. package/agent/agent/turn_finalizer.py +428 -0
  71. package/agent/agent/turn_retry_state.py +68 -0
  72. package/agent/agent/usage_pricing.py +3 -0
  73. package/agent/apps/bootstrap-installer/package.json +6 -5
  74. package/agent/apps/bootstrap-installer/src/routes/failure.tsx +12 -5
  75. package/agent/apps/bootstrap-installer/src/routes/progress.tsx +1 -3
  76. package/agent/apps/bootstrap-installer/src/store.ts +3 -2
  77. package/agent/apps/bootstrap-installer/src-tauri/src/bootstrap.rs +172 -7
  78. package/agent/apps/bootstrap-installer/src-tauri/src/events.rs +14 -1
  79. package/agent/apps/bootstrap-installer/src-tauri/src/paths.rs +29 -0
  80. package/agent/apps/bootstrap-installer/src-tauri/src/powershell.rs +93 -3
  81. package/agent/apps/bootstrap-installer/src-tauri/src/update.rs +695 -39
  82. package/agent/apps/bootstrap-installer/tsconfig.json +3 -4
  83. package/agent/apps/desktop/DESIGN.md +167 -0
  84. package/agent/apps/desktop/README.md +20 -16
  85. package/agent/apps/desktop/assets/icon.icns +0 -0
  86. package/agent/apps/desktop/assets/icon.ico +0 -0
  87. package/agent/apps/desktop/assets/icon.png +0 -0
  88. package/agent/apps/desktop/electron/backend-env.cjs +112 -0
  89. package/agent/apps/desktop/electron/backend-env.test.cjs +111 -0
  90. package/agent/apps/desktop/electron/backend-probes.test.cjs +3 -1
  91. package/agent/apps/desktop/electron/backend-ready.cjs +66 -0
  92. package/agent/apps/desktop/electron/bootstrap-platform.cjs +52 -0
  93. package/agent/apps/desktop/electron/bootstrap-platform.test.cjs +59 -1
  94. package/agent/apps/desktop/electron/bootstrap-runner.cjs +176 -38
  95. package/agent/apps/desktop/electron/bootstrap-runner.test.cjs +112 -1
  96. package/agent/apps/desktop/electron/connection-config.cjs +288 -0
  97. package/agent/apps/desktop/electron/connection-config.test.cjs +396 -0
  98. package/agent/apps/desktop/electron/dashboard-token.cjs +99 -0
  99. package/agent/apps/desktop/electron/dashboard-token.test.cjs +142 -0
  100. package/agent/apps/desktop/electron/desktop-uninstall.cjs +232 -0
  101. package/agent/apps/desktop/electron/desktop-uninstall.test.cjs +246 -0
  102. package/agent/apps/desktop/electron/entitlements.mac.inherit.plist +2 -0
  103. package/agent/apps/desktop/electron/fs-read-dir.cjs +109 -0
  104. package/agent/apps/desktop/electron/fs-read-dir.test.cjs +364 -0
  105. package/agent/apps/desktop/electron/gateway-ws-probe.cjs +188 -0
  106. package/agent/apps/desktop/electron/gateway-ws-probe.test.cjs +122 -0
  107. package/agent/apps/desktop/electron/git-root.cjs +54 -0
  108. package/agent/apps/desktop/electron/git-root.test.cjs +40 -0
  109. package/agent/apps/desktop/electron/git-worktrees.cjs +174 -0
  110. package/agent/apps/desktop/electron/hardening.cjs +123 -28
  111. package/agent/apps/desktop/electron/hardening.test.cjs +163 -0
  112. package/agent/apps/desktop/electron/main.cjs +3121 -331
  113. package/agent/apps/desktop/electron/oauth-net-request.cjs +20 -0
  114. package/agent/apps/desktop/electron/oauth-net-request.test.cjs +34 -0
  115. package/agent/apps/desktop/electron/preload.cjs +52 -2
  116. package/agent/apps/desktop/electron/session-windows.cjs +124 -0
  117. package/agent/apps/desktop/electron/session-windows.test.cjs +199 -0
  118. package/agent/apps/desktop/electron/update-rebuild.cjs +29 -0
  119. package/agent/apps/desktop/electron/update-rebuild.test.cjs +55 -0
  120. package/agent/apps/desktop/electron/update-remote.cjs +56 -0
  121. package/agent/apps/desktop/electron/update-remote.test.cjs +78 -0
  122. package/agent/apps/desktop/electron/vscode-marketplace.cjs +331 -0
  123. package/agent/apps/desktop/electron/vscode-marketplace.test.cjs +113 -0
  124. package/agent/apps/desktop/electron/windows-child-process.test.cjs +57 -0
  125. package/agent/apps/desktop/electron/windows-user-env.cjs +76 -0
  126. package/agent/apps/desktop/electron/windows-user-env.test.cjs +90 -0
  127. package/agent/apps/desktop/electron/workspace-cwd.cjs +38 -0
  128. package/agent/apps/desktop/electron/workspace-cwd.test.cjs +45 -0
  129. package/agent/apps/desktop/eslint.config.mjs +0 -3
  130. package/agent/apps/desktop/index.html +27 -2
  131. package/agent/apps/desktop/package.json +31 -11
  132. package/agent/apps/desktop/pr-assets/session-source-folders.png +0 -0
  133. package/agent/apps/desktop/public/apple-touch-icon.png +0 -0
  134. package/agent/apps/desktop/public/nous-girl.jpg +0 -0
  135. package/agent/apps/desktop/scripts/assert-dist-built.cjs +70 -0
  136. package/agent/apps/desktop/scripts/assert-dist-built.test.cjs +84 -0
  137. package/agent/apps/desktop/scripts/before-pack.cjs +78 -0
  138. package/agent/apps/desktop/scripts/before-pack.test.cjs +53 -0
  139. package/agent/apps/desktop/scripts/diag-scroll-reset.mjs +229 -0
  140. package/agent/apps/desktop/scripts/patch-electron-builder-mac-binary.cjs +64 -0
  141. package/agent/apps/desktop/scripts/run-electron-builder.cjs +57 -0
  142. package/agent/apps/desktop/src/app/agents/index.tsx +53 -45
  143. package/agent/apps/desktop/src/app/artifacts/index.tsx +102 -83
  144. package/agent/apps/desktop/src/app/chat/chat-drop-overlay.tsx +29 -8
  145. package/agent/apps/desktop/src/app/chat/chat-swap-overlay.tsx +47 -0
  146. package/agent/apps/desktop/src/app/chat/composer/attachments.tsx +81 -45
  147. package/agent/apps/desktop/src/app/chat/composer/completion-drawer.tsx +13 -24
  148. package/agent/apps/desktop/src/app/chat/composer/context-menu.tsx +138 -88
  149. package/agent/apps/desktop/src/app/chat/composer/controls.tsx +138 -90
  150. package/agent/apps/desktop/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
  151. package/agent/apps/desktop/src/app/chat/composer/focus.ts +32 -0
  152. package/agent/apps/desktop/src/app/chat/composer/help-hint.tsx +38 -25
  153. package/agent/apps/desktop/src/app/chat/composer/hooks/use-live-completion-adapter.ts +7 -0
  154. package/agent/apps/desktop/src/app/chat/composer/hooks/use-mic-recorder.ts +22 -12
  155. package/agent/apps/desktop/src/app/chat/composer/hooks/use-slash-completions.ts +142 -14
  156. package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts +14 -11
  157. package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-recorder.ts +9 -6
  158. package/agent/apps/desktop/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
  159. package/agent/apps/desktop/src/app/chat/composer/index.tsx +930 -180
  160. package/agent/apps/desktop/src/app/chat/composer/inline-refs.ts +136 -32
  161. package/agent/apps/desktop/src/app/chat/composer/model-pill.tsx +86 -0
  162. package/agent/apps/desktop/src/app/chat/composer/queue-panel.tsx +54 -75
  163. package/agent/apps/desktop/src/app/chat/composer/rich-editor.test.ts +117 -1
  164. package/agent/apps/desktop/src/app/chat/composer/rich-editor.ts +117 -6
  165. package/agent/apps/desktop/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
  166. package/agent/apps/desktop/src/app/chat/composer/status-stack/index.tsx +202 -0
  167. package/agent/apps/desktop/src/app/chat/composer/status-stack/status-row.tsx +155 -0
  168. package/agent/apps/desktop/src/app/chat/composer/text-utils.test.ts +104 -0
  169. package/agent/apps/desktop/src/app/chat/composer/text-utils.ts +37 -9
  170. package/agent/apps/desktop/src/app/chat/composer/trigger-popover.test.tsx +50 -0
  171. package/agent/apps/desktop/src/app/chat/composer/trigger-popover.tsx +105 -40
  172. package/agent/apps/desktop/src/app/chat/composer/types.ts +5 -0
  173. package/agent/apps/desktop/src/app/chat/composer/url-dialog.tsx +11 -15
  174. package/agent/apps/desktop/src/app/chat/composer/voice-activity.tsx +8 -4
  175. package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
  176. package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.ts +70 -16
  177. package/agent/apps/desktop/src/app/chat/hooks/use-file-drop-zone.ts +52 -16
  178. package/agent/apps/desktop/src/app/chat/index.tsx +234 -81
  179. package/agent/apps/desktop/src/app/chat/perf-probe.tsx +69 -21
  180. package/agent/apps/desktop/src/app/chat/right-rail/preview-console.tsx +44 -40
  181. package/agent/apps/desktop/src/app/chat/right-rail/preview-file.tsx +71 -25
  182. package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.test.tsx +40 -1
  183. package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.tsx +55 -53
  184. package/agent/apps/desktop/src/app/chat/right-rail/preview.tsx +35 -17
  185. package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
  186. package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.tsx +74 -0
  187. package/agent/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx +356 -0
  188. package/agent/apps/desktop/src/app/chat/sidebar/index.tsx +1189 -364
  189. package/agent/apps/desktop/src/app/chat/sidebar/load-more-row.tsx +30 -0
  190. package/agent/apps/desktop/src/app/chat/sidebar/order.test.ts +21 -0
  191. package/agent/apps/desktop/src/app/chat/sidebar/order.ts +17 -0
  192. package/agent/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx +524 -0
  193. package/agent/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx +80 -45
  194. package/agent/apps/desktop/src/app/chat/sidebar/session-row.tsx +120 -25
  195. package/agent/apps/desktop/src/app/chat/sidebar/virtual-session-list.tsx +7 -13
  196. package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
  197. package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.ts +326 -0
  198. package/agent/apps/desktop/src/app/chat/thread-loading.ts +7 -2
  199. package/agent/apps/desktop/src/app/command-center/index.tsx +320 -581
  200. package/agent/apps/desktop/src/app/command-palette/index.tsx +681 -0
  201. package/agent/apps/desktop/src/app/command-palette/marketplace-theme-page.tsx +157 -0
  202. package/agent/apps/desktop/src/app/cron/index.tsx +392 -324
  203. package/agent/apps/desktop/src/app/cron/job-state.ts +29 -0
  204. package/agent/apps/desktop/src/app/desktop-controller.tsx +618 -123
  205. package/agent/apps/desktop/src/app/floating-hud.ts +22 -0
  206. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
  207. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts +260 -14
  208. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-request.ts +48 -4
  209. package/agent/apps/desktop/src/app/hooks/use-keybinds.ts +270 -0
  210. package/agent/apps/desktop/src/app/hooks/use-refresh-hotkey.ts +45 -0
  211. package/agent/apps/desktop/src/app/layout-constants.ts +19 -0
  212. package/agent/apps/desktop/src/app/messaging/index.tsx +136 -241
  213. package/agent/apps/desktop/src/app/messaging/platform-icon.tsx +95 -0
  214. package/agent/apps/desktop/src/app/model-visibility-overlay.tsx +31 -0
  215. package/agent/apps/desktop/src/app/overlays/overlay-search-input.tsx +18 -62
  216. package/agent/apps/desktop/src/app/overlays/overlay-split-layout.tsx +59 -7
  217. package/agent/apps/desktop/src/app/overlays/overlay-view.tsx +9 -5
  218. package/agent/apps/desktop/src/app/page-search-shell.tsx +42 -20
  219. package/agent/apps/desktop/src/app/profiles/create-profile-dialog.tsx +165 -0
  220. package/agent/apps/desktop/src/app/profiles/delete-profile-dialog.tsx +65 -0
  221. package/agent/apps/desktop/src/app/profiles/index.tsx +174 -199
  222. package/agent/apps/desktop/src/app/profiles/rename-profile-dialog.tsx +125 -0
  223. package/agent/apps/desktop/src/app/right-sidebar/files/dnd-manager.ts +27 -0
  224. package/agent/apps/desktop/src/app/right-sidebar/files/ipc.test.ts +100 -0
  225. package/agent/apps/desktop/src/app/right-sidebar/files/ipc.ts +12 -18
  226. package/agent/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx +177 -0
  227. package/agent/apps/desktop/src/app/right-sidebar/files/tree.tsx +35 -21
  228. package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.test.ts +75 -3
  229. package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.ts +152 -5
  230. package/agent/apps/desktop/src/app/right-sidebar/index.test.tsx +75 -0
  231. package/agent/apps/desktop/src/app/right-sidebar/index.tsx +166 -129
  232. package/agent/apps/desktop/src/app/right-sidebar/store.ts +19 -4
  233. package/agent/apps/desktop/src/app/right-sidebar/terminal/buffer.ts +65 -0
  234. package/agent/apps/desktop/src/app/right-sidebar/terminal/index.tsx +29 -34
  235. package/agent/apps/desktop/src/app/right-sidebar/terminal/persistent.tsx +18 -6
  236. package/agent/apps/desktop/src/app/right-sidebar/terminal/selection.ts +93 -32
  237. package/agent/apps/desktop/src/app/right-sidebar/terminal/use-terminal-session.ts +381 -119
  238. package/agent/apps/desktop/src/app/routes.ts +9 -0
  239. package/agent/apps/desktop/src/app/session/hooks/use-cwd-actions.ts +17 -7
  240. package/agent/apps/desktop/src/app/session/hooks/use-message-stream.ts +365 -47
  241. package/agent/apps/desktop/src/app/session/hooks/use-model-controls.test.tsx +198 -0
  242. package/agent/apps/desktop/src/app/session/hooks/use-model-controls.ts +70 -34
  243. package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx +1061 -0
  244. package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.ts +1143 -165
  245. package/agent/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx +341 -2
  246. package/agent/apps/desktop/src/app/session/hooks/use-route-resume.ts +176 -5
  247. package/agent/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx +259 -0
  248. package/agent/apps/desktop/src/app/session/hooks/use-session-actions.ts +452 -149
  249. package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.test.tsx +327 -0
  250. package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.ts +133 -4
  251. package/agent/apps/desktop/src/app/session-picker-overlay.tsx +32 -0
  252. package/agent/apps/desktop/src/app/session-switcher.tsx +107 -0
  253. package/agent/apps/desktop/src/app/settings/about-settings.tsx +45 -36
  254. package/agent/apps/desktop/src/app/settings/appearance-settings.tsx +243 -162
  255. package/agent/apps/desktop/src/app/settings/config-settings.tsx +86 -66
  256. package/agent/apps/desktop/src/app/settings/constants.ts +459 -122
  257. package/agent/apps/desktop/src/app/settings/credential-key-ui.tsx +373 -0
  258. package/agent/apps/desktop/src/app/settings/env-credentials.tsx +198 -0
  259. package/agent/apps/desktop/src/app/settings/env-var-actions-menu.tsx +136 -0
  260. package/agent/apps/desktop/src/app/settings/field-copy.ts +56 -0
  261. package/agent/apps/desktop/src/app/settings/gateway-settings.tsx +385 -72
  262. package/agent/apps/desktop/src/app/settings/helpers.test.ts +156 -1
  263. package/agent/apps/desktop/src/app/settings/helpers.ts +30 -2
  264. package/agent/apps/desktop/src/app/settings/index.tsx +118 -84
  265. package/agent/apps/desktop/src/app/settings/keys-settings.tsx +62 -419
  266. package/agent/apps/desktop/src/app/settings/mcp-settings.tsx +65 -60
  267. package/agent/apps/desktop/src/app/settings/model-settings.test.tsx +129 -5
  268. package/agent/apps/desktop/src/app/settings/model-settings.tsx +370 -65
  269. package/agent/apps/desktop/src/app/settings/notifications-settings.tsx +150 -0
  270. package/agent/apps/desktop/src/app/settings/primitives.tsx +5 -11
  271. package/agent/apps/desktop/src/app/settings/provider-config-panel.test.tsx +142 -0
  272. package/agent/apps/desktop/src/app/settings/provider-config-panel.tsx +182 -0
  273. package/agent/apps/desktop/src/app/settings/providers-settings.test.tsx +171 -0
  274. package/agent/apps/desktop/src/app/settings/providers-settings.tsx +471 -0
  275. package/agent/apps/desktop/src/app/settings/sessions-settings.tsx +183 -71
  276. package/agent/apps/desktop/src/app/settings/toolset-config-panel.test.tsx +135 -1
  277. package/agent/apps/desktop/src/app/settings/toolset-config-panel.tsx +180 -57
  278. package/agent/apps/desktop/src/app/settings/types.ts +9 -6
  279. package/agent/apps/desktop/src/app/settings/uninstall-section.tsx +185 -0
  280. package/agent/apps/desktop/src/app/settings/use-deep-link-highlight.ts +60 -0
  281. package/agent/apps/desktop/src/app/shell/app-shell.tsx +59 -13
  282. package/agent/apps/desktop/src/app/shell/gateway-menu-panel.tsx +37 -32
  283. package/agent/apps/desktop/src/app/shell/hooks/use-overlay-routing.ts +6 -3
  284. package/agent/apps/desktop/src/app/shell/hooks/use-statusbar-items.tsx +212 -53
  285. package/agent/apps/desktop/src/app/shell/keybind-panel.tsx +215 -0
  286. package/agent/apps/desktop/src/app/shell/model-edit-submenu.test.tsx +84 -0
  287. package/agent/apps/desktop/src/app/shell/model-edit-submenu.tsx +244 -0
  288. package/agent/apps/desktop/src/app/shell/model-menu-panel.tsx +392 -0
  289. package/agent/apps/desktop/src/app/shell/statusbar-controls.tsx +23 -33
  290. package/agent/apps/desktop/src/app/shell/titlebar-controls.tsx +79 -95
  291. package/agent/apps/desktop/src/app/shell/titlebar.ts +8 -2
  292. package/agent/apps/desktop/src/app/skills/index.test.tsx +11 -0
  293. package/agent/apps/desktop/src/app/skills/index.tsx +79 -64
  294. package/agent/apps/desktop/src/app/types.ts +85 -0
  295. package/agent/apps/desktop/src/app/updates-overlay.tsx +110 -105
  296. package/agent/apps/desktop/src/components/assistant-ui/ansi-text.tsx +34 -0
  297. package/agent/apps/desktop/src/components/assistant-ui/block-direction.test.tsx +129 -0
  298. package/agent/apps/desktop/src/components/assistant-ui/clarify-tool.tsx +102 -81
  299. package/agent/apps/desktop/src/components/assistant-ui/directive-text.tsx +92 -15
  300. package/agent/apps/desktop/src/components/assistant-ui/markdown-text.test.ts +38 -0
  301. package/agent/apps/desktop/src/components/assistant-ui/markdown-text.tsx +304 -45
  302. package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
  303. package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.tsx +48 -0
  304. package/agent/apps/desktop/src/components/assistant-ui/streaming.test.tsx +142 -90
  305. package/agent/apps/desktop/src/components/assistant-ui/thread-list.tsx +337 -0
  306. package/agent/apps/desktop/src/components/assistant-ui/thread.tsx +667 -190
  307. package/agent/apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx +299 -0
  308. package/agent/apps/desktop/src/components/assistant-ui/tool-approval.test.tsx +133 -0
  309. package/agent/apps/desktop/src/components/assistant-ui/tool-approval.tsx +239 -0
  310. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts +31 -0
  311. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.ts +152 -134
  312. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback.tsx +142 -150
  313. package/agent/apps/desktop/src/components/assistant-ui/tooltip-icon-button.tsx +14 -12
  314. package/agent/apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
  315. package/agent/apps/desktop/src/components/assistant-ui/user-message-text.tsx +152 -0
  316. package/agent/apps/desktop/src/components/boot-failure-overlay.tsx +150 -33
  317. package/agent/apps/desktop/src/components/boot-failure-reauth.test.ts +100 -0
  318. package/agent/apps/desktop/src/components/boot-failure-reauth.ts +81 -0
  319. package/agent/apps/desktop/src/components/brand-mark.tsx +19 -0
  320. package/agent/apps/desktop/src/components/chat/code-card.tsx +1 -1
  321. package/agent/apps/desktop/src/components/chat/composer-dock.ts +31 -0
  322. package/agent/apps/desktop/src/components/chat/diff-lines.tsx +1 -1
  323. package/agent/apps/desktop/src/components/chat/disclosure-row.tsx +13 -3
  324. package/agent/apps/desktop/src/components/chat/expandable-block.tsx +52 -0
  325. package/agent/apps/desktop/src/components/chat/generated-image-result.tsx +174 -0
  326. package/agent/apps/desktop/src/components/chat/image-generation-placeholder.tsx +70 -37
  327. package/agent/apps/desktop/src/components/chat/intro.tsx +8 -7
  328. package/agent/apps/desktop/src/components/chat/preview-attachment.tsx +4 -2
  329. package/agent/apps/desktop/src/components/chat/shiki-highlighter.test.ts +37 -0
  330. package/agent/apps/desktop/src/components/chat/shiki-highlighter.tsx +96 -22
  331. package/agent/apps/desktop/src/components/chat/status-row.tsx +70 -0
  332. package/agent/apps/desktop/src/components/chat/status-section.tsx +42 -0
  333. package/agent/apps/desktop/src/components/chat/terminal-output.tsx +54 -0
  334. package/agent/apps/desktop/src/components/chat/zoomable-image.tsx +70 -109
  335. package/agent/apps/desktop/src/components/desktop-install-overlay.tsx +154 -84
  336. package/agent/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx +38 -8
  337. package/agent/apps/desktop/src/components/desktop-onboarding-overlay.tsx +789 -233
  338. package/agent/apps/desktop/src/components/error-boundary.tsx +77 -0
  339. package/agent/apps/desktop/src/components/gateway-connecting-overlay.test.tsx +144 -0
  340. package/agent/apps/desktop/src/components/gateway-connecting-overlay.tsx +7 -1
  341. package/agent/apps/desktop/src/components/haptics-provider.tsx +24 -0
  342. package/agent/apps/desktop/src/components/language-switcher.test.tsx +53 -0
  343. package/agent/apps/desktop/src/components/language-switcher.tsx +175 -0
  344. package/agent/apps/desktop/src/components/model-picker.tsx +42 -40
  345. package/agent/apps/desktop/src/components/model-visibility-dialog.tsx +166 -0
  346. package/agent/apps/desktop/src/components/notifications.tsx +48 -27
  347. package/agent/apps/desktop/src/components/pane-shell/index.ts +1 -1
  348. package/agent/apps/desktop/src/components/pane-shell/pane-shell.tsx +146 -9
  349. package/agent/apps/desktop/src/components/prompt-overlays.tsx +234 -0
  350. package/agent/apps/desktop/src/components/session-picker.tsx +108 -0
  351. package/agent/apps/desktop/src/components/ui/action-status.tsx +25 -0
  352. package/agent/apps/desktop/src/components/ui/badge.tsx +35 -0
  353. package/agent/apps/desktop/src/components/ui/button.tsx +37 -13
  354. package/agent/apps/desktop/src/components/ui/confirm-dialog.tsx +109 -0
  355. package/agent/apps/desktop/src/components/ui/control.ts +25 -0
  356. package/agent/apps/desktop/src/components/ui/copy-button.test.tsx +36 -0
  357. package/agent/apps/desktop/src/components/ui/copy-button.tsx +38 -27
  358. package/agent/apps/desktop/src/components/ui/dialog.tsx +39 -11
  359. package/agent/apps/desktop/src/components/ui/dropdown-menu.tsx +98 -24
  360. package/agent/apps/desktop/src/components/ui/error-state.tsx +50 -0
  361. package/agent/apps/desktop/src/components/ui/fade-text.tsx +9 -2
  362. package/agent/apps/desktop/src/components/ui/{braille-spinner.tsx → glyph-spinner.tsx} +15 -13
  363. package/agent/apps/desktop/src/components/ui/input.tsx +5 -2
  364. package/agent/apps/desktop/src/components/ui/kbd.tsx +83 -12
  365. package/agent/apps/desktop/src/components/ui/log-view.tsx +19 -0
  366. package/agent/apps/desktop/src/components/ui/pagination.tsx +12 -5
  367. package/agent/apps/desktop/src/components/ui/popover.tsx +44 -0
  368. package/agent/apps/desktop/src/components/ui/search-field.tsx +80 -0
  369. package/agent/apps/desktop/src/components/ui/segmented-control.tsx +51 -0
  370. package/agent/apps/desktop/src/components/ui/select.tsx +10 -3
  371. package/agent/apps/desktop/src/components/ui/sheet.tsx +8 -2
  372. package/agent/apps/desktop/src/components/ui/sidebar.tsx +18 -25
  373. package/agent/apps/desktop/src/components/ui/switch.tsx +38 -15
  374. package/agent/apps/desktop/src/components/ui/textarea.tsx +4 -11
  375. package/agent/apps/desktop/src/components/ui/tool-icon.tsx +65 -0
  376. package/agent/apps/desktop/src/components/ui/tooltip.tsx +31 -4
  377. package/agent/apps/desktop/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
  378. package/agent/apps/desktop/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
  379. package/agent/apps/desktop/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
  380. package/agent/apps/desktop/src/global.d.ts +181 -4
  381. package/agent/apps/desktop/src/hermes.test.ts +60 -0
  382. package/agent/apps/desktop/src/hermes.ts +190 -13
  383. package/agent/apps/desktop/src/hooks/use-image-download.ts +85 -0
  384. package/agent/apps/desktop/src/hooks/use-resize-observer.ts +13 -4
  385. package/agent/apps/desktop/src/hooks/use-worktree-info.ts +68 -0
  386. package/agent/apps/desktop/src/i18n/catalog.ts +12 -0
  387. package/agent/apps/desktop/src/i18n/context.test.tsx +232 -0
  388. package/agent/apps/desktop/src/i18n/context.tsx +183 -0
  389. package/agent/apps/desktop/src/i18n/define-locale.ts +41 -0
  390. package/agent/apps/desktop/src/i18n/en.ts +1921 -0
  391. package/agent/apps/desktop/src/i18n/index.ts +20 -0
  392. package/agent/apps/desktop/src/i18n/ja.ts +2053 -0
  393. package/agent/apps/desktop/src/i18n/languages.test.ts +43 -0
  394. package/agent/apps/desktop/src/i18n/languages.ts +86 -0
  395. package/agent/apps/desktop/src/i18n/runtime.test.ts +75 -0
  396. package/agent/apps/desktop/src/i18n/runtime.ts +53 -0
  397. package/agent/apps/desktop/src/i18n/types.ts +1559 -0
  398. package/agent/apps/desktop/src/i18n/zh-hant.ts +1992 -0
  399. package/agent/apps/desktop/src/i18n/zh.ts +2099 -0
  400. package/agent/apps/desktop/src/lib/ansi.test.ts +123 -0
  401. package/agent/apps/desktop/src/lib/ansi.ts +186 -0
  402. package/agent/apps/desktop/src/lib/chat-messages.test.ts +79 -0
  403. package/agent/apps/desktop/src/lib/chat-messages.ts +68 -29
  404. package/agent/apps/desktop/src/lib/chat-runtime.test.ts +65 -1
  405. package/agent/apps/desktop/src/lib/chat-runtime.ts +39 -3
  406. package/agent/apps/desktop/src/lib/completion-sound.ts +519 -0
  407. package/agent/apps/desktop/src/lib/desktop-fs.test.ts +116 -0
  408. package/agent/apps/desktop/src/lib/desktop-fs.ts +113 -0
  409. package/agent/apps/desktop/src/lib/desktop-slash-commands.test.ts +89 -6
  410. package/agent/apps/desktop/src/lib/desktop-slash-commands.ts +270 -131
  411. package/agent/apps/desktop/src/lib/external-link.test.tsx +27 -0
  412. package/agent/apps/desktop/src/lib/external-link.tsx +9 -2
  413. package/agent/apps/desktop/src/lib/gateway-events.test.ts +27 -0
  414. package/agent/apps/desktop/src/lib/gateway-events.ts +16 -0
  415. package/agent/apps/desktop/src/lib/gateway-ws-url.test.ts +78 -0
  416. package/agent/apps/desktop/src/lib/gateway-ws-url.ts +91 -0
  417. package/agent/apps/desktop/src/lib/generated-images.test.ts +97 -0
  418. package/agent/apps/desktop/src/lib/generated-images.ts +116 -0
  419. package/agent/apps/desktop/src/lib/haptics.ts +17 -0
  420. package/agent/apps/desktop/src/lib/icons.ts +10 -2
  421. package/agent/apps/desktop/src/lib/keybinds/actions.ts +137 -0
  422. package/agent/apps/desktop/src/lib/keybinds/combo.test.ts +86 -0
  423. package/agent/apps/desktop/src/lib/keybinds/combo.ts +195 -0
  424. package/agent/apps/desktop/src/lib/local-preview.ts +23 -2
  425. package/agent/apps/desktop/src/lib/markdown-preprocess.ts +20 -7
  426. package/agent/apps/desktop/src/lib/media.remote.test.ts +90 -0
  427. package/agent/apps/desktop/src/lib/media.ts +40 -1
  428. package/agent/apps/desktop/src/lib/model-status-label.test.ts +59 -0
  429. package/agent/apps/desktop/src/lib/model-status-label.ts +122 -0
  430. package/agent/apps/desktop/src/lib/mutable-ref.ts +6 -0
  431. package/agent/apps/desktop/src/lib/profile-color.ts +58 -0
  432. package/agent/apps/desktop/src/lib/query-client.ts +13 -0
  433. package/agent/apps/desktop/src/lib/remend-tail.test.ts +105 -0
  434. package/agent/apps/desktop/src/lib/remend-tail.ts +108 -0
  435. package/agent/apps/desktop/src/lib/session-export.ts +6 -3
  436. package/agent/apps/desktop/src/lib/session-ids.test.ts +44 -0
  437. package/agent/apps/desktop/src/lib/session-ids.ts +26 -0
  438. package/agent/apps/desktop/src/lib/session-search.test.ts +66 -0
  439. package/agent/apps/desktop/src/lib/session-search.ts +21 -0
  440. package/agent/apps/desktop/src/lib/session-source.ts +126 -0
  441. package/agent/apps/desktop/src/lib/storage.test.ts +25 -0
  442. package/agent/apps/desktop/src/lib/storage.ts +35 -1
  443. package/agent/apps/desktop/src/lib/todos.test.ts +46 -1
  444. package/agent/apps/desktop/src/lib/todos.ts +37 -0
  445. package/agent/apps/desktop/src/lib/tool-result-summary.ts +5 -1
  446. package/agent/apps/desktop/src/lib/update-copy.test.ts +38 -0
  447. package/agent/apps/desktop/src/lib/update-copy.ts +44 -0
  448. package/agent/apps/desktop/src/lib/use-enter-animation.ts +2 -2
  449. package/agent/apps/desktop/src/lib/yolo-session.ts +50 -0
  450. package/agent/apps/desktop/src/main.tsx +19 -19
  451. package/agent/apps/desktop/src/store/boot.ts +4 -3
  452. package/agent/apps/desktop/src/store/clarify.test.ts +81 -0
  453. package/agent/apps/desktop/src/store/clarify.ts +50 -13
  454. package/agent/apps/desktop/src/store/command-palette.ts +20 -0
  455. package/agent/apps/desktop/src/store/compaction.test.ts +53 -0
  456. package/agent/apps/desktop/src/store/compaction.ts +38 -0
  457. package/agent/apps/desktop/src/store/completion-sound.ts +32 -0
  458. package/agent/apps/desktop/src/store/composer-input-history.test.ts +147 -0
  459. package/agent/apps/desktop/src/store/composer-input-history.ts +158 -0
  460. package/agent/apps/desktop/src/store/composer-queue.test.ts +68 -0
  461. package/agent/apps/desktop/src/store/composer-queue.ts +76 -0
  462. package/agent/apps/desktop/src/store/composer-status.test.ts +99 -0
  463. package/agent/apps/desktop/src/store/composer-status.ts +277 -0
  464. package/agent/apps/desktop/src/store/composer.test.ts +106 -0
  465. package/agent/apps/desktop/src/store/composer.ts +116 -0
  466. package/agent/apps/desktop/src/store/cron.ts +19 -0
  467. package/agent/apps/desktop/src/store/gateway.ts +280 -6
  468. package/agent/apps/desktop/src/store/keybinds.ts +143 -0
  469. package/agent/apps/desktop/src/store/layout.ts +107 -9
  470. package/agent/apps/desktop/src/store/model-presets.test.ts +51 -0
  471. package/agent/apps/desktop/src/store/model-presets.ts +86 -0
  472. package/agent/apps/desktop/src/store/model-visibility.test.ts +99 -0
  473. package/agent/apps/desktop/src/store/model-visibility.ts +161 -0
  474. package/agent/apps/desktop/src/store/native-notifications.test.ts +192 -0
  475. package/agent/apps/desktop/src/store/native-notifications.ts +203 -0
  476. package/agent/apps/desktop/src/store/notifications.ts +10 -7
  477. package/agent/apps/desktop/src/store/onboarding.test.ts +271 -1
  478. package/agent/apps/desktop/src/store/onboarding.ts +268 -38
  479. package/agent/apps/desktop/src/store/preview.ts +10 -1
  480. package/agent/apps/desktop/src/store/profile.test.ts +89 -0
  481. package/agent/apps/desktop/src/store/profile.ts +395 -0
  482. package/agent/apps/desktop/src/store/prompts.test.ts +127 -0
  483. package/agent/apps/desktop/src/store/prompts.ts +117 -0
  484. package/agent/apps/desktop/src/store/session-switcher.test.ts +115 -0
  485. package/agent/apps/desktop/src/store/session-switcher.ts +128 -0
  486. package/agent/apps/desktop/src/store/session-sync.ts +25 -0
  487. package/agent/apps/desktop/src/store/session.test.ts +268 -2
  488. package/agent/apps/desktop/src/store/session.ts +392 -18
  489. package/agent/apps/desktop/src/store/subagents.ts +3 -0
  490. package/agent/apps/desktop/src/store/system-actions.ts +48 -0
  491. package/agent/apps/desktop/src/store/thread-scroll.ts +58 -5
  492. package/agent/apps/desktop/src/store/todos.test.ts +47 -0
  493. package/agent/apps/desktop/src/store/todos.ts +64 -0
  494. package/agent/apps/desktop/src/store/tool-dismiss.ts +45 -0
  495. package/agent/apps/desktop/src/store/translucency.ts +38 -0
  496. package/agent/apps/desktop/src/store/updates.test.ts +187 -2
  497. package/agent/apps/desktop/src/store/updates.ts +268 -18
  498. package/agent/apps/desktop/src/store/windows.test.ts +143 -0
  499. package/agent/apps/desktop/src/store/windows.ts +115 -0
  500. package/agent/apps/desktop/src/styles.css +510 -119
  501. package/agent/apps/desktop/src/themes/color.ts +142 -0
  502. package/agent/apps/desktop/src/themes/context.tsx +128 -75
  503. package/agent/apps/desktop/src/themes/install.test.ts +119 -0
  504. package/agent/apps/desktop/src/themes/install.ts +95 -0
  505. package/agent/apps/desktop/src/themes/presets.test.ts +33 -0
  506. package/agent/apps/desktop/src/themes/presets.ts +13 -4
  507. package/agent/apps/desktop/src/themes/profile-theme.test.ts +41 -0
  508. package/agent/apps/desktop/src/themes/types.ts +35 -0
  509. package/agent/apps/desktop/src/themes/user-themes.test.ts +63 -0
  510. package/agent/apps/desktop/src/themes/user-themes.ts +122 -0
  511. package/agent/apps/desktop/src/themes/vscode.test.ts +171 -0
  512. package/agent/apps/desktop/src/themes/vscode.ts +343 -0
  513. package/agent/apps/desktop/src/types/hermes.ts +138 -1
  514. package/agent/apps/desktop/tsconfig.json +2 -2
  515. package/agent/apps/desktop/vite.config.ts +18 -0
  516. package/agent/apps/shared/package.json +1 -1
  517. package/agent/apps/shared/src/json-rpc-gateway.ts +63 -2
  518. package/agent/apps/shared/tsconfig.json +2 -2
  519. package/agent/cli-config.yaml.example +78 -1
  520. package/agent/cli.py +2294 -3146
  521. package/agent/cron/blueprint_catalog.py +713 -0
  522. package/agent/cron/jobs.py +226 -110
  523. package/agent/cron/scheduler.py +468 -193
  524. package/agent/cron/scheduler_provider.py +177 -0
  525. package/agent/cron/scripts/__init__.py +1 -0
  526. package/agent/cron/scripts/classify_items.py +226 -0
  527. package/agent/cron/suggestion_catalog.py +154 -0
  528. package/agent/cron/suggestions.py +257 -0
  529. package/agent/docs/chronos-managed-cron-contract.md +196 -0
  530. package/agent/docs/design/profile-builder.md +146 -0
  531. package/agent/docs/middleware/README.md +260 -0
  532. package/agent/docs/observability/README.md +316 -0
  533. package/agent/docs/plans/2026-06-09-003-fix-telegram-stream-overflow-continuations-plan.md +240 -0
  534. package/agent/docs/rca-ssl-cacert-post-git-pull.md +54 -0
  535. package/agent/docs/relay-connector-contract.md +285 -0
  536. package/agent/gateway/authz_mixin.py +536 -0
  537. package/agent/gateway/channel_directory.py +65 -3
  538. package/agent/gateway/config.py +222 -12
  539. package/agent/gateway/display_config.py +10 -0
  540. package/agent/gateway/hooks.py +17 -0
  541. package/agent/gateway/kanban_watchers.py +1146 -0
  542. package/agent/gateway/message_timestamps.py +166 -0
  543. package/agent/gateway/platforms/ADDING_A_PLATFORM.md +29 -0
  544. package/agent/gateway/platforms/api_server.py +216 -38
  545. package/agent/gateway/platforms/base.py +210 -58
  546. package/agent/gateway/platforms/email.py +122 -12
  547. package/agent/gateway/platforms/feishu.py +80 -11
  548. package/agent/gateway/platforms/feishu_meeting_invite.py +212 -0
  549. package/agent/gateway/platforms/matrix.py +1498 -297
  550. package/agent/gateway/platforms/qqbot/adapter.py +6 -0
  551. package/agent/gateway/platforms/signal.py +8 -0
  552. package/agent/gateway/platforms/slack.py +308 -12
  553. package/agent/gateway/platforms/telegram.py +831 -24
  554. package/agent/gateway/platforms/webhook.py +109 -21
  555. package/agent/gateway/platforms/weixin.py +113 -2
  556. package/agent/gateway/platforms/whatsapp.py +94 -288
  557. package/agent/gateway/platforms/whatsapp_cloud.py +1956 -0
  558. package/agent/gateway/platforms/whatsapp_common.py +367 -0
  559. package/agent/gateway/platforms/yuanbao.py +608 -191
  560. package/agent/gateway/platforms/yuanbao_proto.py +232 -23
  561. package/agent/gateway/relay/__init__.py +375 -0
  562. package/agent/gateway/relay/adapter.py +222 -0
  563. package/agent/gateway/relay/auth.py +168 -0
  564. package/agent/gateway/relay/descriptor.py +118 -0
  565. package/agent/gateway/relay/transport.py +101 -0
  566. package/agent/gateway/relay/ws_transport.py +327 -0
  567. package/agent/gateway/response_filters.py +53 -0
  568. package/agent/gateway/rich_sent_store.py +80 -0
  569. package/agent/gateway/run.py +2940 -5001
  570. package/agent/gateway/session.py +109 -8
  571. package/agent/gateway/session_context.py +22 -4
  572. package/agent/gateway/slash_commands.py +3854 -0
  573. package/agent/gateway/status.py +141 -21
  574. package/agent/gateway/stream_consumer.py +288 -31
  575. package/agent/hermes-already-has-routines.md +1 -1
  576. package/agent/hermes_cli/__init__.py +62 -17
  577. package/agent/hermes_cli/_parser.py +30 -0
  578. package/agent/hermes_cli/_subprocess_compat.py +61 -0
  579. package/agent/hermes_cli/active_sessions.py +320 -0
  580. package/agent/hermes_cli/auth.py +707 -59
  581. package/agent/hermes_cli/auth_commands.py +39 -22
  582. package/agent/hermes_cli/backup.py +109 -7
  583. package/agent/hermes_cli/banner.py +88 -0
  584. package/agent/hermes_cli/blueprint_cmd.py +318 -0
  585. package/agent/hermes_cli/clawpump_cli.py +3 -3
  586. package/agent/hermes_cli/cli_agent_setup_mixin.py +684 -0
  587. package/agent/hermes_cli/cli_commands_mixin.py +2293 -0
  588. package/agent/hermes_cli/commands.py +216 -91
  589. package/agent/hermes_cli/config.py +967 -130
  590. package/agent/hermes_cli/container_boot.py +76 -11
  591. package/agent/hermes_cli/cron.py +5 -11
  592. package/agent/hermes_cli/curator.py +21 -0
  593. package/agent/hermes_cli/dashboard_auth/__init__.py +2 -0
  594. package/agent/hermes_cli/dashboard_auth/base.py +62 -0
  595. package/agent/hermes_cli/dashboard_auth/cookies.py +32 -19
  596. package/agent/hermes_cli/dashboard_auth/login_page.py +156 -6
  597. package/agent/hermes_cli/dashboard_auth/middleware.py +28 -4
  598. package/agent/hermes_cli/dashboard_auth/prefix.py +46 -2
  599. package/agent/hermes_cli/dashboard_auth/public_paths.py +6 -0
  600. package/agent/hermes_cli/dashboard_auth/routes.py +158 -2
  601. package/agent/hermes_cli/dashboard_auth/ws_tickets.py +85 -11
  602. package/agent/hermes_cli/dashboard_register.py +427 -0
  603. package/agent/hermes_cli/debug.py +155 -50
  604. package/agent/hermes_cli/distribution.py +227 -0
  605. package/agent/hermes_cli/doctor.py +255 -14
  606. package/agent/hermes_cli/dump.py +60 -6
  607. package/agent/hermes_cli/env_loader.py +33 -0
  608. package/agent/hermes_cli/gateway.py +755 -103
  609. package/agent/hermes_cli/gateway_enroll.py +250 -0
  610. package/agent/hermes_cli/gateway_windows.py +254 -11
  611. package/agent/hermes_cli/gui_uninstall.py +285 -0
  612. package/agent/hermes_cli/inventory.py +105 -4
  613. package/agent/hermes_cli/kanban.py +58 -71
  614. package/agent/hermes_cli/kanban_db.py +391 -14
  615. package/agent/hermes_cli/kanban_decompose.py +2 -2
  616. package/agent/hermes_cli/kanban_specify.py +3 -1
  617. package/agent/hermes_cli/logs.py +2 -0
  618. package/agent/hermes_cli/main.py +2889 -5287
  619. package/agent/hermes_cli/managed_scope.py +214 -0
  620. package/agent/hermes_cli/managed_uv.py +254 -0
  621. package/agent/hermes_cli/mcp_catalog.py +6 -3
  622. package/agent/hermes_cli/mcp_config.py +145 -21
  623. package/agent/hermes_cli/mcp_security.py +96 -0
  624. package/agent/hermes_cli/mcp_startup.py +32 -3
  625. package/agent/hermes_cli/memory_providers.py +149 -0
  626. package/agent/hermes_cli/memory_setup.py +97 -42
  627. package/agent/hermes_cli/middleware.py +313 -0
  628. package/agent/hermes_cli/model_catalog.py +31 -0
  629. package/agent/hermes_cli/model_cost_guard.py +134 -0
  630. package/agent/hermes_cli/model_normalize.py +2 -1
  631. package/agent/hermes_cli/model_setup_flows.py +2759 -0
  632. package/agent/hermes_cli/model_switch.py +242 -27
  633. package/agent/hermes_cli/models.py +284 -44
  634. package/agent/hermes_cli/nous_account.py +33 -6
  635. package/agent/hermes_cli/nous_billing.py +406 -0
  636. package/agent/hermes_cli/nous_subscription.py +202 -5
  637. package/agent/hermes_cli/platforms.py +1 -0
  638. package/agent/hermes_cli/plugins.py +218 -18
  639. package/agent/hermes_cli/plugins_cmd.py +249 -105
  640. package/agent/hermes_cli/portal_cli.py +56 -16
  641. package/agent/hermes_cli/profile_distribution.py +6 -1
  642. package/agent/hermes_cli/profiles.py +283 -32
  643. package/agent/hermes_cli/provider_catalog.py +170 -0
  644. package/agent/hermes_cli/providers.py +4 -1
  645. package/agent/hermes_cli/pty_bridge.py +53 -4
  646. package/agent/hermes_cli/runtime_provider.py +216 -34
  647. package/agent/hermes_cli/secret_prompt.py +4 -4
  648. package/agent/hermes_cli/secrets_cli.py +24 -0
  649. package/agent/hermes_cli/send_cmd.py +28 -2
  650. package/agent/hermes_cli/service_manager.py +166 -19
  651. package/agent/hermes_cli/session_listing.py +97 -0
  652. package/agent/hermes_cli/setup.py +158 -94
  653. package/agent/hermes_cli/setup_whatsapp_cloud.py +541 -0
  654. package/agent/hermes_cli/skills_config.py +8 -2
  655. package/agent/hermes_cli/skills_hub.py +149 -7
  656. package/agent/hermes_cli/status.py +2 -2
  657. package/agent/hermes_cli/subcommands/__init__.py +18 -0
  658. package/agent/hermes_cli/subcommands/_shared.py +29 -0
  659. package/agent/hermes_cli/subcommands/acp.py +52 -0
  660. package/agent/hermes_cli/subcommands/auth.py +109 -0
  661. package/agent/hermes_cli/subcommands/backup.py +38 -0
  662. package/agent/hermes_cli/subcommands/claw.py +92 -0
  663. package/agent/hermes_cli/subcommands/config.py +49 -0
  664. package/agent/hermes_cli/subcommands/cron.py +163 -0
  665. package/agent/hermes_cli/subcommands/dashboard.py +143 -0
  666. package/agent/hermes_cli/subcommands/debug.py +77 -0
  667. package/agent/hermes_cli/subcommands/doctor.py +35 -0
  668. package/agent/hermes_cli/subcommands/dump.py +28 -0
  669. package/agent/hermes_cli/subcommands/gateway.py +332 -0
  670. package/agent/hermes_cli/subcommands/gui.py +63 -0
  671. package/agent/hermes_cli/subcommands/hooks.py +77 -0
  672. package/agent/hermes_cli/subcommands/import_cmd.py +31 -0
  673. package/agent/hermes_cli/subcommands/insights.py +25 -0
  674. package/agent/hermes_cli/subcommands/login.py +78 -0
  675. package/agent/hermes_cli/subcommands/logout.py +28 -0
  676. package/agent/hermes_cli/subcommands/logs.py +78 -0
  677. package/agent/hermes_cli/subcommands/mcp.py +108 -0
  678. package/agent/hermes_cli/subcommands/memory.py +53 -0
  679. package/agent/hermes_cli/subcommands/model.py +72 -0
  680. package/agent/hermes_cli/subcommands/pairing.py +36 -0
  681. package/agent/hermes_cli/subcommands/plugins.py +94 -0
  682. package/agent/hermes_cli/subcommands/postinstall.py +23 -0
  683. package/agent/hermes_cli/subcommands/profile.py +203 -0
  684. package/agent/hermes_cli/subcommands/prompt_size.py +36 -0
  685. package/agent/hermes_cli/subcommands/security.py +62 -0
  686. package/agent/hermes_cli/subcommands/setup.py +58 -0
  687. package/agent/hermes_cli/subcommands/skills.py +298 -0
  688. package/agent/hermes_cli/subcommands/slack.py +60 -0
  689. package/agent/hermes_cli/subcommands/status.py +28 -0
  690. package/agent/hermes_cli/subcommands/tools.py +95 -0
  691. package/agent/hermes_cli/subcommands/uninstall.py +41 -0
  692. package/agent/hermes_cli/subcommands/update.py +70 -0
  693. package/agent/hermes_cli/subcommands/version.py +18 -0
  694. package/agent/hermes_cli/subcommands/webhook.py +76 -0
  695. package/agent/hermes_cli/subcommands/whatsapp.py +22 -0
  696. package/agent/hermes_cli/suggestions_cmd.py +153 -0
  697. package/agent/hermes_cli/telegram_managed_bot.py +358 -0
  698. package/agent/hermes_cli/tips.py +3 -4
  699. package/agent/hermes_cli/tools_config.py +155 -28
  700. package/agent/hermes_cli/uninstall.py +231 -35
  701. package/agent/hermes_cli/web_server.py +6188 -975
  702. package/agent/hermes_cli/win_pty_bridge.py +179 -0
  703. package/agent/hermes_cli/write_approval_commands.py +209 -0
  704. package/agent/hermes_constants.py +164 -33
  705. package/agent/hermes_logging.py +74 -2
  706. package/agent/hermes_state.py +919 -106
  707. package/agent/hermes_time.py +20 -0
  708. package/agent/locales/af.yaml +23 -0
  709. package/agent/locales/de.yaml +23 -0
  710. package/agent/locales/en.yaml +20 -0
  711. package/agent/locales/es.yaml +23 -0
  712. package/agent/locales/fr.yaml +23 -0
  713. package/agent/locales/ga.yaml +23 -0
  714. package/agent/locales/hu.yaml +23 -0
  715. package/agent/locales/it.yaml +23 -0
  716. package/agent/locales/ja.yaml +23 -0
  717. package/agent/locales/ko.yaml +23 -0
  718. package/agent/locales/pt.yaml +23 -0
  719. package/agent/locales/ru.yaml +23 -0
  720. package/agent/locales/tr.yaml +23 -0
  721. package/agent/locales/uk.yaml +23 -0
  722. package/agent/locales/zh-hant.yaml +23 -0
  723. package/agent/locales/zh.yaml +23 -0
  724. package/agent/model_tools.py +204 -40
  725. package/agent/optional-mcps/clawpump/manifest.yaml +15 -5
  726. package/agent/optional-mcps/clawpump-stdio/manifest.yaml +14 -4
  727. package/agent/optional-mcps/unreal-engine/manifest.yaml +54 -0
  728. package/agent/optional-skills/blockchain/hyperliquid/SKILL.md +2 -2
  729. package/agent/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1 -1
  730. package/agent/optional-skills/creative/kanban-video-orchestrator/SKILL.md +1 -1
  731. package/agent/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +4 -3
  732. package/agent/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +6 -4
  733. package/agent/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +2 -2
  734. package/agent/{skills/software-development → optional-skills/devops}/hermes-s6-container-supervision/SKILL.md +2 -0
  735. package/agent/optional-skills/devops/watchers/SKILL.md +1 -1
  736. package/agent/optional-skills/devops/watchers/scripts/watch_github.py +2 -1
  737. package/agent/optional-skills/payments/mpp-agent/SKILL.md +124 -0
  738. package/agent/optional-skills/payments/stripe-link-cli/SKILL.md +184 -0
  739. package/agent/optional-skills/payments/stripe-projects/SKILL.md +120 -0
  740. package/agent/optional-skills/productivity/canvas/SKILL.md +1 -1
  741. package/agent/optional-skills/productivity/canvas/scripts/canvas_api.py +4 -1
  742. package/agent/optional-skills/productivity/shop/SKILL.md +224 -0
  743. package/agent/optional-skills/productivity/shop/references/catalog-mcp.md +236 -0
  744. package/agent/optional-skills/productivity/shop/references/direct-api.md +278 -0
  745. package/agent/optional-skills/productivity/shop/references/legal.md +3 -0
  746. package/agent/optional-skills/productivity/shop/references/safety.md +36 -0
  747. package/agent/optional-skills/productivity/shopify/SKILL.md +1 -1
  748. package/agent/optional-skills/productivity/siyuan/SKILL.md +1 -1
  749. package/agent/optional-skills/productivity/telephony/SKILL.md +4 -4
  750. package/agent/optional-skills/productivity/telephony/scripts/telephony.py +15 -15
  751. package/agent/optional-skills/security/1password/SKILL.md +1 -1
  752. package/agent/{skills/red-teaming → optional-skills/security}/godmode/SKILL.md +3 -4
  753. package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/auto_jailbreak.py +3 -1
  754. package/agent/optional-skills/software-development/rest-graphql-debug/SKILL.md +1 -1
  755. package/agent/{skills → optional-skills}/software-development/subagent-driven-development/SKILL.md +5 -5
  756. package/agent/package-lock.json +4082 -7907
  757. package/agent/package.json +18 -3
  758. package/agent/plugins/browser/firecrawl/provider.py +4 -1
  759. package/agent/plugins/cron/__init__.py +344 -0
  760. package/agent/plugins/cron/chronos/__init__.py +241 -0
  761. package/agent/plugins/cron/chronos/_nas_client.py +123 -0
  762. package/agent/plugins/cron/chronos/plugin.yaml +9 -0
  763. package/agent/plugins/cron/chronos/verify.py +103 -0
  764. package/agent/plugins/dashboard_auth/basic/__init__.py +491 -0
  765. package/agent/plugins/dashboard_auth/basic/plugin.yaml +7 -0
  766. package/agent/plugins/dashboard_auth/nous/__init__.py +12 -14
  767. package/agent/plugins/dashboard_auth/self_hosted/__init__.py +736 -0
  768. package/agent/plugins/dashboard_auth/self_hosted/plugin.yaml +8 -0
  769. package/agent/plugins/disk-cleanup/disk_cleanup.py +100 -20
  770. package/agent/plugins/google_meet/audio_bridge.py +4 -0
  771. package/agent/plugins/google_meet/meet_bot.py +7 -1
  772. package/agent/plugins/hermes-achievements/dashboard/dist/index.js +9 -15
  773. package/agent/plugins/image_gen/fal/__init__.py +35 -6
  774. package/agent/plugins/image_gen/krea/__init__.py +56 -13
  775. package/agent/plugins/image_gen/openai/__init__.py +122 -24
  776. package/agent/plugins/image_gen/openai-codex/__init__.py +28 -2
  777. package/agent/plugins/image_gen/xai/__init__.py +92 -12
  778. package/agent/plugins/kanban/dashboard/dist/index.js +63 -48
  779. package/agent/plugins/kanban/dashboard/plugin_api.py +39 -35
  780. package/agent/plugins/memory/__init__.py +48 -5
  781. package/agent/plugins/memory/byterover/__init__.py +1 -0
  782. package/agent/plugins/memory/hindsight/README.md +1 -1
  783. package/agent/plugins/memory/hindsight/__init__.py +138 -24
  784. package/agent/plugins/memory/hindsight/plugin.yaml +1 -1
  785. package/agent/plugins/memory/honcho/README.md +13 -10
  786. package/agent/plugins/memory/honcho/cli.py +247 -122
  787. package/agent/plugins/memory/honcho/client.py +112 -102
  788. package/agent/plugins/memory/openviking/README.md +12 -1
  789. package/agent/plugins/memory/openviking/__init__.py +2281 -107
  790. package/agent/plugins/memory/openviking/plugin.yaml +1 -2
  791. package/agent/plugins/memory/supermemory/README.md +22 -10
  792. package/agent/plugins/memory/supermemory/__init__.py +142 -37
  793. package/agent/plugins/memory/supermemory/plugin.yaml +1 -1
  794. package/agent/plugins/model-providers/anthropic/__init__.py +1 -0
  795. package/agent/plugins/model-providers/bedrock/__init__.py +1 -0
  796. package/agent/plugins/model-providers/copilot-acp/__init__.py +1 -0
  797. package/agent/plugins/model-providers/custom/__init__.py +8 -2
  798. package/agent/plugins/model-providers/kimi-coding/__init__.py +16 -7
  799. package/agent/plugins/model-providers/minimax/__init__.py +60 -8
  800. package/agent/plugins/model-providers/opencode-zen/__init__.py +12 -3
  801. package/agent/plugins/model-providers/openrouter/__init__.py +75 -4
  802. package/agent/plugins/model-providers/xiaomi/__init__.py +2 -0
  803. package/agent/plugins/model-providers/zai/__init__.py +1 -0
  804. package/agent/plugins/observability/langfuse/__init__.py +147 -14
  805. package/agent/plugins/observability/nemo_relay/README.md +559 -0
  806. package/agent/plugins/observability/nemo_relay/__init__.py +962 -0
  807. package/agent/plugins/observability/nemo_relay/plugin.yaml +20 -0
  808. package/agent/plugins/platforms/discord/adapter.py +932 -61
  809. package/agent/plugins/platforms/discord/voice_mixer.py +379 -0
  810. package/agent/plugins/platforms/google_chat/adapter.py +9 -3
  811. package/agent/plugins/platforms/google_chat/oauth.py +1 -1
  812. package/agent/plugins/platforms/homeassistant/__init__.py +3 -0
  813. package/agent/{gateway/platforms/homeassistant.py → plugins/platforms/homeassistant/adapter.py} +128 -0
  814. package/agent/plugins/platforms/homeassistant/plugin.yaml +22 -0
  815. package/agent/plugins/platforms/irc/adapter.py +4 -1
  816. package/agent/plugins/platforms/line/adapter.py +16 -1
  817. package/agent/plugins/platforms/mattermost/adapter.py +100 -24
  818. package/agent/plugins/platforms/photon/README.md +179 -0
  819. package/agent/plugins/platforms/photon/__init__.py +4 -0
  820. package/agent/plugins/platforms/photon/adapter.py +1586 -0
  821. package/agent/plugins/platforms/photon/auth.py +1046 -0
  822. package/agent/plugins/platforms/photon/cli.py +439 -0
  823. package/agent/plugins/platforms/photon/plugin.yaml +88 -0
  824. package/agent/plugins/platforms/photon/sidecar/README.md +52 -0
  825. package/agent/plugins/platforms/photon/sidecar/index.mjs +720 -0
  826. package/agent/plugins/platforms/photon/sidecar/package-lock.json +1730 -0
  827. package/agent/plugins/platforms/photon/sidecar/package.json +25 -0
  828. package/agent/plugins/platforms/photon/sidecar/patch-spectrum-mixed-attachments.mjs +155 -0
  829. package/agent/plugins/platforms/raft/__init__.py +3 -0
  830. package/agent/plugins/platforms/raft/adapter.py +774 -0
  831. package/agent/plugins/platforms/raft/plugin.yaml +19 -0
  832. package/agent/plugins/platforms/simplex/adapter.py +777 -220
  833. package/agent/plugins/platforms/simplex/plugin.yaml +21 -2
  834. package/agent/plugins/platforms/teams/adapter.py +175 -5
  835. package/agent/plugins/plugin_utils.py +135 -0
  836. package/agent/plugins/video_gen/fal/__init__.py +10 -3
  837. package/agent/plugins/web/searxng/provider.py +15 -2
  838. package/agent/plugins/web/xai/provider.py +2 -2
  839. package/agent/providers/base.py +22 -3
  840. package/agent/pyproject.toml +115 -21
  841. package/agent/run_agent.py +733 -39
  842. package/agent/scripts/build_skills_index.py +51 -19
  843. package/agent/scripts/check_subprocess_stdin.py +177 -0
  844. package/agent/scripts/contributor_audit.py +2 -0
  845. package/agent/scripts/docker_config_migrate.py +67 -0
  846. package/agent/scripts/install.cmd +3 -3
  847. package/agent/scripts/install.ps1 +580 -154
  848. package/agent/scripts/install.sh +402 -185
  849. package/agent/scripts/lib/node-bootstrap.sh +39 -4
  850. package/agent/scripts/release.py +183 -0
  851. package/agent/scripts/run_tests.sh +1 -0
  852. package/agent/scripts/run_tests_parallel.py +18 -23
  853. package/agent/scripts/whatsapp-bridge/bridge.js +25 -4
  854. package/agent/setup.py +59 -0
  855. package/agent/skills/autonomous-ai-agents/codex/SKILL.md +19 -0
  856. package/agent/skills/autonomous-ai-agents/hermes-agent/SKILL.md +10 -3
  857. package/agent/skills/{mcp/native-mcp/SKILL.md → autonomous-ai-agents/hermes-agent/references/native-mcp.md} +0 -13
  858. package/agent/skills/{devops/webhook-subscriptions/SKILL.md → autonomous-ai-agents/hermes-agent/references/webhooks.md} +1 -11
  859. package/agent/skills/clawpump/SKILL.md +53 -5
  860. package/agent/skills/devops/kanban-orchestrator/SKILL.md +1 -0
  861. package/agent/skills/devops/kanban-worker/SKILL.md +1 -0
  862. package/agent/skills/github/github-auth/SKILL.md +2 -2
  863. package/agent/skills/github/github-auth/scripts/gh-env.sh +2 -2
  864. package/agent/skills/github/github-code-review/SKILL.md +2 -2
  865. package/agent/skills/github/github-issues/SKILL.md +2 -2
  866. package/agent/skills/github/github-pr-workflow/SKILL.md +2 -2
  867. package/agent/skills/github/github-repo-management/SKILL.md +2 -2
  868. package/agent/skills/media/gif-search/SKILL.md +1 -1
  869. package/agent/skills/media/youtube-content/SKILL.md +10 -7
  870. package/agent/skills/media/youtube-content/scripts/fetch_transcript.py +3 -3
  871. package/agent/skills/note-taking/obsidian/SKILL.md +1 -1
  872. package/agent/skills/productivity/airtable/SKILL.md +2 -2
  873. package/agent/skills/productivity/google-workspace/scripts/setup.py +33 -7
  874. package/agent/skills/productivity/notion/SKILL.md +2 -2
  875. package/agent/skills/productivity/teams-meeting-pipeline/SKILL.md +1 -1
  876. package/agent/skills/research/llm-wiki/SKILL.md +1 -1
  877. package/agent/skills/social-media/xurl/SKILL.md +9 -0
  878. package/agent/skills/software-development/hermes-agent-skill-authoring/SKILL.md +1 -1
  879. package/agent/skills/software-development/plan/SKILL.md +285 -5
  880. package/agent/skills/software-development/requesting-code-review/SKILL.md +2 -2
  881. package/agent/skills/software-development/simplify-code/SKILL.md +212 -0
  882. package/agent/skills/software-development/spike/SKILL.md +2 -2
  883. package/agent/skills/software-development/systematic-debugging/SKILL.md +1 -1
  884. package/agent/skills/software-development/test-driven-development/SKILL.md +1 -1
  885. package/agent/tools/approval.py +302 -4
  886. package/agent/tools/async_delegation.py +386 -0
  887. package/agent/tools/blueprints.py +325 -0
  888. package/agent/tools/browser_cdp_tool.py +3 -3
  889. package/agent/tools/browser_tool.py +34 -6
  890. package/agent/tools/checkpoint_manager.py +31 -1
  891. package/agent/tools/clarify_tool.py +55 -5
  892. package/agent/tools/code_execution_tool.py +31 -14
  893. package/agent/tools/computer_use/cua_backend.py +81 -3
  894. package/agent/tools/computer_use/tool.py +79 -5
  895. package/agent/tools/computer_use/vision_routing.py +55 -3
  896. package/agent/tools/credential_files.py +31 -12
  897. package/agent/tools/cronjob_tools.py +30 -20
  898. package/agent/tools/delegate_tool.py +356 -31
  899. package/agent/tools/env_probe.py +1 -0
  900. package/agent/tools/environments/docker.py +163 -8
  901. package/agent/tools/environments/file_sync.py +2 -1
  902. package/agent/tools/environments/local.py +74 -23
  903. package/agent/tools/environments/singularity.py +4 -1
  904. package/agent/tools/environments/ssh.py +78 -11
  905. package/agent/tools/file_operations.py +277 -41
  906. package/agent/tools/file_tools.py +166 -28
  907. package/agent/tools/image_generation_tool.py +515 -29
  908. package/agent/tools/kanban_tools.py +99 -0
  909. package/agent/tools/lazy_deps.py +33 -2
  910. package/agent/tools/mcp_oauth.py +5 -5
  911. package/agent/tools/mcp_oauth_manager.py +7 -5
  912. package/agent/tools/mcp_tool.py +840 -33
  913. package/agent/tools/memory_tool.py +335 -38
  914. package/agent/tools/osv_check.py +15 -1
  915. package/agent/tools/process_registry.py +155 -11
  916. package/agent/tools/read_extract.py +248 -0
  917. package/agent/tools/read_terminal_tool.py +93 -0
  918. package/agent/tools/schema_sanitizer.py +38 -0
  919. package/agent/tools/send_message_tool.py +163 -49
  920. package/agent/tools/session_search_tool.py +189 -7
  921. package/agent/tools/skill_manager_tool.py +202 -3
  922. package/agent/tools/skill_usage.py +52 -4
  923. package/agent/tools/skills_hub.py +184 -44
  924. package/agent/tools/skills_sync.py +232 -5
  925. package/agent/tools/skills_tool.py +125 -11
  926. package/agent/tools/terminal_tool.py +148 -26
  927. package/agent/tools/tirith_security.py +2 -0
  928. package/agent/tools/todo_tool.py +32 -1
  929. package/agent/tools/transcription_tools.py +13 -5
  930. package/agent/tools/tts_tool.py +332 -38
  931. package/agent/tools/url_safety.py +52 -1
  932. package/agent/tools/vision_tools.py +124 -39
  933. package/agent/tools/voice_mode.py +4 -3
  934. package/agent/tools/web_tools.py +45 -15
  935. package/agent/tools/write_approval.py +493 -0
  936. package/agent/toolsets.py +34 -10
  937. package/agent/trajectory_compressor.py +81 -10
  938. package/agent/tui_gateway/entry.py +43 -6
  939. package/agent/tui_gateway/server.py +3335 -330
  940. package/agent/tui_gateway/slash_worker.py +61 -0
  941. package/agent/tui_gateway/ws.py +67 -9
  942. package/agent/ui-tui/eslint.config.mjs +0 -4
  943. package/agent/ui-tui/package.json +6 -6
  944. package/agent/ui-tui/packages/hermes-ink/package.json +1 -1
  945. package/agent/ui-tui/packages/hermes-ink/src/ink/app-mouse.test.ts +34 -1
  946. package/agent/ui-tui/packages/hermes-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
  947. package/agent/ui-tui/packages/hermes-ink/src/ink/components/App.tsx +35 -2
  948. package/agent/ui-tui/packages/hermes-ink/src/ink/events/input-event.ts +4 -11
  949. package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.test.ts +23 -57
  950. package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.ts +11 -135
  951. package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.test.ts +185 -0
  952. package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.ts +37 -3
  953. package/agent/ui-tui/packages/hermes-ink/src/utils/execFileNoThrow.ts +5 -5
  954. package/agent/ui-tui/src/__tests__/appChromeStatusRule.test.tsx +217 -0
  955. package/agent/ui-tui/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
  956. package/agent/ui-tui/src/__tests__/approvalAction.test.ts +11 -0
  957. package/agent/ui-tui/src/__tests__/billingCommand.test.ts +301 -0
  958. package/agent/ui-tui/src/__tests__/blockLayout.test.ts +122 -0
  959. package/agent/ui-tui/src/__tests__/brandingMcpCount.test.ts +111 -0
  960. package/agent/ui-tui/src/__tests__/completionApply.test.ts +51 -0
  961. package/agent/ui-tui/src/__tests__/createGatewayEventHandler.test.ts +487 -2
  962. package/agent/ui-tui/src/__tests__/createSlashHandler.test.ts +54 -0
  963. package/agent/ui-tui/src/__tests__/creditsCommand.test.ts +144 -0
  964. package/agent/ui-tui/src/__tests__/gatewayClient.test.ts +120 -99
  965. package/agent/ui-tui/src/__tests__/gracefulExit.test.ts +11 -0
  966. package/agent/ui-tui/src/__tests__/memoryMonitor.test.ts +102 -0
  967. package/agent/ui-tui/src/__tests__/paths.test.ts +41 -1
  968. package/agent/ui-tui/src/__tests__/terminalModes.test.ts +22 -0
  969. package/agent/ui-tui/src/__tests__/text.test.ts +23 -0
  970. package/agent/ui-tui/src/__tests__/textInputFastEcho.test.ts +37 -0
  971. package/agent/ui-tui/src/__tests__/turnControllerNotice.test.ts +43 -0
  972. package/agent/ui-tui/src/__tests__/useInputHandlers.test.ts +38 -1
  973. package/agent/ui-tui/src/__tests__/virtualHeights.test.ts +8 -0
  974. package/agent/ui-tui/src/app/createGatewayEventHandler.ts +102 -7
  975. package/agent/ui-tui/src/app/interfaces.ts +64 -1
  976. package/agent/ui-tui/src/app/overlayStore.ts +18 -2
  977. package/agent/ui-tui/src/app/slash/commands/billing.ts +332 -0
  978. package/agent/ui-tui/src/app/slash/commands/core.ts +31 -2
  979. package/agent/ui-tui/src/app/slash/commands/credits.ts +57 -0
  980. package/agent/ui-tui/src/app/slash/commands/ops.ts +28 -0
  981. package/agent/ui-tui/src/app/slash/commands/session.ts +32 -4
  982. package/agent/ui-tui/src/app/slash/registry.ts +4 -0
  983. package/agent/ui-tui/src/app/turnController.ts +145 -2
  984. package/agent/ui-tui/src/app/uiStore.ts +2 -0
  985. package/agent/ui-tui/src/app/useInputHandlers.ts +42 -4
  986. package/agent/ui-tui/src/app/useMainApp.ts +54 -8
  987. package/agent/ui-tui/src/app/useSessionLifecycle.ts +40 -31
  988. package/agent/ui-tui/src/app/useSubmission.ts +23 -31
  989. package/agent/ui-tui/src/components/appChrome.tsx +112 -5
  990. package/agent/ui-tui/src/components/appLayout.tsx +9 -0
  991. package/agent/ui-tui/src/components/appOverlays.tsx +25 -1
  992. package/agent/ui-tui/src/components/billingOverlay.tsx +684 -0
  993. package/agent/ui-tui/src/components/branding.tsx +15 -3
  994. package/agent/ui-tui/src/components/messageLine.tsx +25 -3
  995. package/agent/ui-tui/src/components/pluginsHub.tsx +238 -0
  996. package/agent/ui-tui/src/components/prompts.tsx +31 -17
  997. package/agent/ui-tui/src/components/streamingAssistant.tsx +63 -55
  998. package/agent/ui-tui/src/components/textInput.tsx +16 -0
  999. package/agent/ui-tui/src/config/env.ts +12 -0
  1000. package/agent/ui-tui/src/config/limits.ts +13 -0
  1001. package/agent/ui-tui/src/domain/blockLayout.ts +146 -0
  1002. package/agent/ui-tui/src/domain/paths.ts +24 -0
  1003. package/agent/ui-tui/src/domain/slash.ts +40 -0
  1004. package/agent/ui-tui/src/entry.tsx +35 -4
  1005. package/agent/ui-tui/src/gatewayClient.ts +22 -10
  1006. package/agent/ui-tui/src/gatewayTypes.ts +130 -1
  1007. package/agent/ui-tui/src/lib/gracefulExit.ts +24 -4
  1008. package/agent/ui-tui/src/lib/memory.test.ts +162 -0
  1009. package/agent/ui-tui/src/lib/memory.ts +60 -1
  1010. package/agent/ui-tui/src/lib/memoryMonitor.ts +79 -4
  1011. package/agent/ui-tui/src/lib/osc52.ts +1 -1
  1012. package/agent/ui-tui/src/lib/text.test.ts +32 -1
  1013. package/agent/ui-tui/src/lib/text.ts +29 -2
  1014. package/agent/ui-tui/src/lib/virtualHeights.ts +13 -0
  1015. package/agent/ui-tui/src/types.ts +5 -0
  1016. package/agent/ui-tui/tsconfig.build.json +0 -1
  1017. package/agent/ui-tui/tsconfig.json +2 -1
  1018. package/agent/utils.py +66 -2
  1019. package/agent/uv.lock +308 -696
  1020. package/agent/web/index.html +2 -2
  1021. package/agent/web/package.json +11 -6
  1022. package/agent/web/public/claw-bg.webp +0 -0
  1023. package/agent/web/public/claw-logo.webp +0 -0
  1024. package/agent/web/src/App.tsx +138 -48
  1025. package/agent/web/src/components/AutomationBlueprints.tsx +225 -0
  1026. package/agent/web/src/components/Backdrop.tsx +15 -0
  1027. package/agent/web/src/components/ChatSessionList.tsx +260 -0
  1028. package/agent/web/src/components/ChatSidebar.tsx +262 -78
  1029. package/agent/web/src/components/ConfirmDialog.tsx +122 -0
  1030. package/agent/web/src/components/ModelPickerDialog.tsx +111 -16
  1031. package/agent/web/src/components/ModelReloadConfirm.tsx +40 -0
  1032. package/agent/web/src/components/ProfileScopeBanner.tsx +30 -0
  1033. package/agent/web/src/components/ProfileSwitcher.tsx +67 -0
  1034. package/agent/web/src/components/ReasoningPicker.tsx +167 -0
  1035. package/agent/web/src/components/SkillEditorDialog.tsx +215 -0
  1036. package/agent/web/src/components/ThemeSwitcher.tsx +119 -4
  1037. package/agent/web/src/components/ToolsetConfigDrawer.tsx +457 -0
  1038. package/agent/web/src/contexts/PageHeaderProvider.tsx +7 -4
  1039. package/agent/web/src/contexts/ProfileProvider.tsx +137 -0
  1040. package/agent/web/src/contexts/SystemActions.tsx +6 -8
  1041. package/agent/web/src/contexts/profile-context.ts +19 -0
  1042. package/agent/web/src/contexts/useProfileScope.ts +6 -0
  1043. package/agent/web/src/i18n/af.ts +5 -4
  1044. package/agent/web/src/i18n/de.ts +5 -4
  1045. package/agent/web/src/i18n/en.ts +58 -4
  1046. package/agent/web/src/i18n/es.ts +5 -3
  1047. package/agent/web/src/i18n/fr.ts +5 -3
  1048. package/agent/web/src/i18n/ga.ts +5 -4
  1049. package/agent/web/src/i18n/hu.ts +5 -4
  1050. package/agent/web/src/i18n/it.ts +5 -4
  1051. package/agent/web/src/i18n/ja.ts +5 -4
  1052. package/agent/web/src/i18n/ko.ts +5 -4
  1053. package/agent/web/src/i18n/pt.ts +5 -3
  1054. package/agent/web/src/i18n/ru.ts +5 -4
  1055. package/agent/web/src/i18n/tr.ts +5 -4
  1056. package/agent/web/src/i18n/types.ts +59 -1
  1057. package/agent/web/src/i18n/uk.ts +5 -3
  1058. package/agent/web/src/i18n/zh-hant.ts +5 -4
  1059. package/agent/web/src/i18n/zh.ts +5 -4
  1060. package/agent/web/src/index.css +2 -2
  1061. package/agent/web/src/lib/api.ts +819 -52
  1062. package/agent/web/src/lib/dashboard-flags.ts +16 -7
  1063. package/agent/web/src/lib/reasoning-effort.test.ts +48 -0
  1064. package/agent/web/src/lib/reasoning-effort.ts +36 -0
  1065. package/agent/web/src/lib/session-refresh.test.ts +21 -0
  1066. package/agent/web/src/lib/session-refresh.ts +26 -0
  1067. package/agent/web/src/pages/ChannelsPage.tsx +529 -68
  1068. package/agent/web/src/pages/ChatPage.tsx +249 -56
  1069. package/agent/web/src/pages/ConfigPage.tsx +11 -1
  1070. package/agent/web/src/pages/CronPage.tsx +219 -31
  1071. package/agent/web/src/pages/EnvPage.tsx +25 -6
  1072. package/agent/web/src/pages/FilesPage.tsx +525 -0
  1073. package/agent/web/src/pages/McpPage.tsx +80 -3
  1074. package/agent/web/src/pages/ModelsPage.tsx +97 -12
  1075. package/agent/web/src/pages/PluginsPage.tsx +1 -1
  1076. package/agent/web/src/pages/ProfileBuilderPage.tsx +611 -0
  1077. package/agent/web/src/pages/ProfilesPage.tsx +1038 -172
  1078. package/agent/web/src/pages/SessionsPage.tsx +144 -13
  1079. package/agent/web/src/pages/SkillsPage.tsx +851 -70
  1080. package/agent/web/src/pages/SystemPage.tsx +340 -4
  1081. package/agent/web/src/pages/WalletPage.tsx +401 -0
  1082. package/agent/web/src/pages/WebhooksPage.tsx +145 -15
  1083. package/agent/web/src/pages/X402Page.tsx +207 -0
  1084. package/agent/web/src/plugins/registry.ts +28 -11
  1085. package/agent/web/src/plugins/sdk.d.ts +160 -0
  1086. package/agent/web/src/themes/context.tsx +112 -5
  1087. package/agent/web/src/themes/fonts.ts +167 -0
  1088. package/agent/web/src/themes/index.ts +7 -0
  1089. package/agent/web/tsconfig.app.json +0 -1
  1090. package/agent/web/vite.config.ts +1 -8
  1091. package/agent/web/vitest.config.ts +16 -0
  1092. package/package.json +1 -1
  1093. package/agent/apps/desktop/package-lock.json +0 -18363
  1094. package/agent/apps/desktop/src/app/chat/composer/skin-slash-popover.tsx +0 -56
  1095. package/agent/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx +0 -382
  1096. package/agent/apps/desktop/src/components/assistant-ui/todo-tool.tsx +0 -109
  1097. package/agent/apps/desktop/src/components/chat/generated-image-context.tsx +0 -19
  1098. package/agent/optional-skills/productivity/shop-app/SKILL.md +0 -340
  1099. package/agent/skills/autonomous-ai-agents/kanban-codex-lane/SKILL.md +0 -277
  1100. package/agent/skills/autonomous-ai-agents/kanban-codex-lane/templates/pmb-codex-lane-prompt.md +0 -57
  1101. package/agent/skills/diagramming/DESCRIPTION.md +0 -3
  1102. package/agent/skills/domain/DESCRIPTION.md +0 -24
  1103. package/agent/skills/gifs/DESCRIPTION.md +0 -3
  1104. package/agent/skills/inference-sh/DESCRIPTION.md +0 -19
  1105. package/agent/skills/mcp/DESCRIPTION.md +0 -3
  1106. package/agent/skills/media/spotify/SKILL.md +0 -135
  1107. package/agent/skills/mlops/training/DESCRIPTION.md +0 -3
  1108. package/agent/skills/mlops/vector-databases/DESCRIPTION.md +0 -3
  1109. package/agent/skills/productivity/linear/SKILL.md +0 -380
  1110. package/agent/skills/productivity/linear/scripts/linear_api.py +0 -445
  1111. package/agent/skills/software-development/debugging-hermes-tui-commands/SKILL.md +0 -152
  1112. package/agent/skills/software-development/writing-plans/SKILL.md +0 -297
  1113. package/agent/ui-tui/package-lock.json +0 -7449
  1114. package/agent/ui-tui/packages/hermes-ink/package-lock.json +0 -1289
  1115. package/agent/web/package-lock.json +0 -8887
  1116. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/PORT_NOTES.md +0 -0
  1117. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/SKILL.md +0 -0
  1118. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/prompts/system.md +0 -0
  1119. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/macaron.md +0 -0
  1120. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/mono-ink.md +0 -0
  1121. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/neon.md +0 -0
  1122. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/warm.md +0 -0
  1123. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/prompt-construction.md +0 -0
  1124. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/style-presets.md +0 -0
  1125. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/blueprint.md +0 -0
  1126. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/chalkboard.md +0 -0
  1127. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/editorial.md +0 -0
  1128. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/elegant.md +0 -0
  1129. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/fantasy-animation.md +0 -0
  1130. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat-doodle.md +0 -0
  1131. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat.md +0 -0
  1132. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/ink-notes.md +0 -0
  1133. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/intuition-machine.md +0 -0
  1134. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/minimal.md +0 -0
  1135. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/nature.md +0 -0
  1136. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/notion.md +0 -0
  1137. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/pixel-art.md +0 -0
  1138. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/playful.md +0 -0
  1139. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/retro.md +0 -0
  1140. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/scientific.md +0 -0
  1141. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/screen-print.md +0 -0
  1142. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch-notes.md +0 -0
  1143. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch.md +0 -0
  1144. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vector-illustration.md +0 -0
  1145. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vintage.md +0 -0
  1146. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/warm.md +0 -0
  1147. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/watercolor.md +0 -0
  1148. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles.md +0 -0
  1149. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/usage.md +0 -0
  1150. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/workflow.md +0 -0
  1151. /package/agent/{skills → optional-skills}/creative/baoyu-comic/PORT_NOTES.md +0 -0
  1152. /package/agent/{skills → optional-skills}/creative/baoyu-comic/SKILL.md +0 -0
  1153. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/analysis-framework.md +0 -0
  1154. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/chalk.md +0 -0
  1155. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ink-brush.md +0 -0
  1156. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ligne-claire.md +0 -0
  1157. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/manga.md +0 -0
  1158. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/minimalist.md +0 -0
  1159. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/realistic.md +0 -0
  1160. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/auto-selection.md +0 -0
  1161. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/base-prompt.md +0 -0
  1162. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/character-template.md +0 -0
  1163. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/cinematic.md +0 -0
  1164. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/dense.md +0 -0
  1165. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/four-panel.md +0 -0
  1166. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/mixed.md +0 -0
  1167. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/splash.md +0 -0
  1168. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/standard.md +0 -0
  1169. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/webtoon.md +0 -0
  1170. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/ohmsha-guide.md +0 -0
  1171. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/partial-workflows.md +0 -0
  1172. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/concept-story.md +0 -0
  1173. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/four-panel.md +0 -0
  1174. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/ohmsha.md +0 -0
  1175. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/shoujo.md +0 -0
  1176. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/wuxia.md +0 -0
  1177. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/storyboard-template.md +0 -0
  1178. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/action.md +0 -0
  1179. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/dramatic.md +0 -0
  1180. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/energetic.md +0 -0
  1181. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/neutral.md +0 -0
  1182. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/romantic.md +0 -0
  1183. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/vintage.md +0 -0
  1184. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/warm.md +0 -0
  1185. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/workflow.md +0 -0
  1186. /package/agent/{skills → optional-skills}/creative/creative-ideation/SKILL.md +0 -0
  1187. /package/agent/{skills → optional-skills}/creative/creative-ideation/references/full-prompt-library.md +0 -0
  1188. /package/agent/{skills → optional-skills}/creative/pixel-art/ATTRIBUTION.md +0 -0
  1189. /package/agent/{skills → optional-skills}/creative/pixel-art/SKILL.md +0 -0
  1190. /package/agent/{skills → optional-skills}/creative/pixel-art/references/palettes.md +0 -0
  1191. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/__init__.py +0 -0
  1192. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/palettes.py +0 -0
  1193. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art.py +0 -0
  1194. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art_video.py +0 -0
  1195. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/SKILL.md +0 -0
  1196. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/analysis-modules.md +0 -0
  1197. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/methods-guide.md +0 -0
  1198. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/abliteration-config.yaml +0 -0
  1199. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/analysis-study.yaml +0 -0
  1200. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/batch-abliteration.yaml +0 -0
  1201. /package/agent/{skills → optional-skills}/mlops/research/DESCRIPTION.md +0 -0
  1202. /package/agent/{skills → optional-skills}/mlops/research/dspy/SKILL.md +0 -0
  1203. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/examples.md +0 -0
  1204. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/modules.md +0 -0
  1205. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/optimizers.md +0 -0
  1206. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/jailbreak-templates.md +0 -0
  1207. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/refusal-detection.md +0 -0
  1208. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/godmode_race.py +0 -0
  1209. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/load_godmode.py +0 -0
  1210. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/parseltongue.py +0 -0
  1211. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill-subtle.json +0 -0
  1212. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill.json +0 -0
  1213. /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/context-budget-discipline.md +0 -0
  1214. /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/gates-taxonomy.md +0 -0
@@ -1,5 +1,6 @@
1
+ import { useStore } from '@nanostores/react'
1
2
  import type * as React from 'react'
2
- import { useCallback, useEffect, useMemo, useState } from 'react'
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
3
4
 
4
5
  import { PageLoader } from '@/components/page-loader'
5
6
  import { Button } from '@/components/ui/button'
@@ -13,77 +14,46 @@ import {
13
14
  DialogTitle
14
15
  } from '@/components/ui/dialog'
15
16
  import { Input } from '@/components/ui/input'
17
+ import { SearchField } from '@/components/ui/search-field'
16
18
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
17
19
  import { Textarea } from '@/components/ui/textarea'
18
20
  import {
19
21
  createCronJob,
20
22
  type CronJob,
21
23
  deleteCronJob,
24
+ getCronJobRuns,
22
25
  getCronJobs,
23
26
  pauseCronJob,
24
27
  resumeCronJob,
28
+ type SessionInfo,
25
29
  triggerCronJob,
26
30
  updateCronJob
27
31
  } from '@/hermes'
28
- import { AlertTriangle, Clock, Pause, Pencil, Play, Trash2, Zap } from '@/lib/icons'
32
+ import { type Translations, useI18n } from '@/i18n'
33
+ import { AlertTriangle, Clock } from '@/lib/icons'
29
34
  import { cn } from '@/lib/utils'
35
+ import { $cronFocusJobId, $cronJobs, setCronFocusJobId, setCronJobs, updateCronJobs } from '@/store/cron'
30
36
  import { notify, notifyError } from '@/store/notifications'
31
37
 
32
- import { PageSearchShell } from '../page-search-shell'
38
+ import { useRefreshHotkey } from '../hooks/use-refresh-hotkey'
39
+ import { OverlayMain, OverlayNewButton, OverlaySidebar, OverlaySplitLayout } from '../overlays/overlay-split-layout'
40
+ import { OverlayView } from '../overlays/overlay-view'
33
41
  import type { SetStatusbarItemGroup } from '../shell/statusbar-controls'
34
42
 
43
+ import { jobState, jobTitle, STATE_DOT } from './job-state'
44
+
35
45
  const DEFAULT_DELIVER = 'local'
36
46
 
37
- const DELIVERY_OPTIONS: ReadonlyArray<{ label: string; value: string }> = [
38
- { label: 'This desktop', value: 'local' },
39
- { label: 'Telegram', value: 'telegram' },
40
- { label: 'Discord', value: 'discord' },
41
- { label: 'Slack', value: 'slack' },
42
- { label: 'Email', value: 'email' }
43
- ]
47
+ const DELIVERY_VALUES: readonly string[] = ['local', 'telegram', 'discord', 'slack', 'email']
44
48
 
45
49
  const SCHEDULE_OPTIONS: ReadonlyArray<ScheduleOption> = [
46
- {
47
- expr: '0 9 * * *',
48
- hint: 'Every day at 9:00 AM',
49
- label: 'Daily',
50
- value: 'daily'
51
- },
52
- {
53
- expr: '0 9 * * 1-5',
54
- hint: 'Monday through Friday at 9:00 AM',
55
- label: 'Weekdays',
56
- value: 'weekdays'
57
- },
58
- {
59
- expr: '0 9 * * 1',
60
- hint: 'Every Monday at 9:00 AM',
61
- label: 'Weekly',
62
- value: 'weekly'
63
- },
64
- {
65
- expr: '0 9 1 * *',
66
- hint: 'The first day of each month at 9:00 AM',
67
- label: 'Monthly',
68
- value: 'monthly'
69
- },
70
- {
71
- expr: '0 * * * *',
72
- hint: 'At the top of every hour',
73
- label: 'Hourly',
74
- value: 'hourly'
75
- },
76
- {
77
- expr: '*/15 * * * *',
78
- hint: 'Every 15 minutes',
79
- label: 'Every 15 minutes',
80
- value: 'every-15-minutes'
81
- },
82
- {
83
- hint: 'Cron syntax or natural language',
84
- label: 'Custom',
85
- value: 'custom'
86
- }
50
+ { expr: '0 9 * * *', value: 'daily' },
51
+ { expr: '0 9 * * 1-5', value: 'weekdays' },
52
+ { expr: '0 9 * * 1', value: 'weekly' },
53
+ { expr: '0 9 1 * *', value: 'monthly' },
54
+ { expr: '0 * * * *', value: 'hourly' },
55
+ { expr: '*/15 * * * *', value: 'every-15-minutes' },
56
+ { value: 'custom' }
87
57
  ]
88
58
 
89
59
  const STATE_TONE: Record<string, 'good' | 'muted' | 'warn' | 'bad'> = {
@@ -115,28 +85,6 @@ function jobPrompt(job: CronJob): string {
115
85
  return asText(job.prompt)
116
86
  }
117
87
 
118
- function jobTitle(job: CronJob): string {
119
- const name = jobName(job)
120
-
121
- if (name) {
122
- return name
123
- }
124
-
125
- const prompt = jobPrompt(job)
126
-
127
- if (prompt) {
128
- return truncate(prompt, 60)
129
- }
130
-
131
- const script = asText(job.script)
132
-
133
- if (script) {
134
- return truncate(script, 60)
135
- }
136
-
137
- return job.id || 'Cron job'
138
- }
139
-
140
88
  function jobScheduleDisplay(job: CronJob): string {
141
89
  return asText(job.schedule_display) || asText(job.schedule?.display) || asText(job.schedule?.expr) || '—'
142
90
  }
@@ -145,10 +93,6 @@ function jobScheduleExpr(job: CronJob): string {
145
93
  return asText(job.schedule?.expr) || asText(job.schedule_display) || ''
146
94
  }
147
95
 
148
- function jobState(job: CronJob): string {
149
- return asText(job.state) || (job.enabled === false ? 'disabled' : 'scheduled')
150
- }
151
-
152
96
  function jobDeliver(job: CronJob): string {
153
97
  return asText(job.deliver) || DEFAULT_DELIVER
154
98
  }
@@ -159,19 +103,8 @@ function cronParts(expr: string): null | string[] {
159
103
  return parts.length === 5 ? parts : null
160
104
  }
161
105
 
162
- function dayName(value: string): string {
163
- const names: Record<string, string> = {
164
- '0': 'Sunday',
165
- '1': 'Monday',
166
- '2': 'Tuesday',
167
- '3': 'Wednesday',
168
- '4': 'Thursday',
169
- '5': 'Friday',
170
- '6': 'Saturday',
171
- '7': 'Sunday'
172
- }
173
-
174
- return names[value] ?? `day ${value}`
106
+ function dayName(value: string, c: Translations['cron']): string {
107
+ return c.days[value] ?? c.dayFallback(value)
175
108
  }
176
109
 
177
110
  function formatCronTime(minute: string, hour: string): string {
@@ -247,36 +180,36 @@ function scheduleOptionForExpr(expr: string): ScheduleOption {
247
180
  return SCHEDULE_OPTIONS[SCHEDULE_OPTIONS.length - 1]
248
181
  }
249
182
 
250
- function scheduleSummary(option: ScheduleOption, expr: string): string {
183
+ function scheduleSummary(option: ScheduleOption, expr: string, c: Translations['cron']): string {
251
184
  const parts = cronParts(expr)
252
185
 
253
186
  if (!parts) {
254
- return option.hint
187
+ return c.scheduleHints[option.value] ?? ''
255
188
  }
256
189
 
257
190
  const [minute, hour, dayOfMonth, , dayOfWeek] = parts
258
191
 
259
192
  if (option.value === 'daily') {
260
- return `Every day at ${formatCronTime(minute, hour)}`
193
+ return c.everyDayAt(formatCronTime(minute, hour))
261
194
  }
262
195
 
263
196
  if (option.value === 'weekdays') {
264
- return `Weekdays at ${formatCronTime(minute, hour)}`
197
+ return c.weekdaysAt(formatCronTime(minute, hour))
265
198
  }
266
199
 
267
200
  if (option.value === 'weekly') {
268
- return `Every ${dayName(dayOfWeek)} at ${formatCronTime(minute, hour)}`
201
+ return c.everyDayOfWeekAt(dayName(dayOfWeek, c), formatCronTime(minute, hour))
269
202
  }
270
203
 
271
204
  if (option.value === 'monthly') {
272
- return `Monthly on day ${dayOfMonth} at ${formatCronTime(minute, hour)}`
205
+ return c.monthlyOnDayAt(dayOfMonth, formatCronTime(minute, hour))
273
206
  }
274
207
 
275
208
  if (option.value === 'hourly') {
276
- return minute === '0' ? 'At the top of every hour' : `Every hour at :${minute.padStart(2, '0')}`
209
+ return minute === '0' ? c.topOfHour : c.everyHourAt(minute.padStart(2, '0'))
277
210
  }
278
211
 
279
- return option.hint
212
+ return c.scheduleHints[option.value] ?? ''
280
213
  }
281
214
 
282
215
  function formatTime(iso?: null | string): string {
@@ -306,46 +239,89 @@ function matchesQuery(job: CronJob, q: string): boolean {
306
239
  }
307
240
 
308
241
  interface CronViewProps extends React.ComponentProps<'section'> {
242
+ onClose: () => void
243
+ onOpenSession?: (sessionId: string) => void
309
244
  setStatusbarItemGroup?: SetStatusbarItemGroup
310
245
  }
311
246
 
312
- export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...props }: CronViewProps) {
313
- const [jobs, setJobs] = useState<CronJob[] | null>(null)
247
+ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setStatusbarItemGroup }: CronViewProps) {
248
+ const { t } = useI18n()
249
+ const c = t.cron
250
+ // Source of truth is the shared atom (also fed by the controller poll), so the
251
+ // sidebar and this overlay never drift — a delete here clears the sidebar row
252
+ // immediately. `loading` only gates the first paint before the atom is filled.
253
+ const jobs = useStore($cronJobs)
254
+ const [loading, setLoading] = useState(jobs.length === 0)
314
255
  const [query, setQuery] = useState('')
315
- const [refreshing, setRefreshing] = useState(false)
316
256
  const [busyJobId, setBusyJobId] = useState<null | string>(null)
257
+ // Master/detail: the job whose schedule + run history fill the right pane.
258
+ const [selectedJobId, setSelectedJobId] = useState<null | string>(null)
259
+ // Set when a job is opened from the sidebar so we scroll it into view once the
260
+ // row exists. Cleared after the scroll fires.
261
+ const pendingScrollRef = useRef<null | string>(null)
262
+ const focusJobId = useStore($cronFocusJobId)
317
263
 
318
264
  const [editor, setEditor] = useState<EditorState>({ mode: 'closed' })
319
265
  const [pendingDelete, setPendingDelete] = useState<CronJob | null>(null)
320
266
  const [deleting, setDeleting] = useState(false)
321
267
 
322
268
  const refresh = useCallback(async () => {
323
- setRefreshing(true)
324
-
325
269
  try {
326
- const result = await getCronJobs()
327
- setJobs(result)
270
+ setCronJobs(await getCronJobs())
328
271
  } catch (err) {
329
- notifyError(err, 'Failed to load cron jobs')
272
+ notifyError(err, c.failedLoad)
330
273
  } finally {
331
- setRefreshing(false)
274
+ setLoading(false)
332
275
  }
333
- }, [])
276
+ }, [c])
277
+
278
+ useRefreshHotkey(refresh)
334
279
 
335
280
  useEffect(() => {
336
281
  void refresh()
337
282
  }, [refresh])
338
283
 
339
- const visibleJobs = useMemo(() => {
340
- if (!jobs) {
341
- return []
284
+ // Sidebar "open this job": resolve the focus id (or name) to a job, select
285
+ // it, queue a scroll, then clear the one-shot focus so re-opening cron
286
+ // normally doesn't re-trigger it.
287
+ useEffect(() => {
288
+ if (!focusJobId) {return}
289
+
290
+ const match = jobs.find(job => job.id === focusJobId || jobName(job) === focusJobId)
291
+
292
+ if (match) {
293
+ setSelectedJobId(match.id)
294
+ pendingScrollRef.current = match.id
342
295
  }
343
296
 
344
- return jobs.filter(job => matchesQuery(job, query.trim())).sort((a, b) => jobTitle(a).localeCompare(jobTitle(b)))
345
- }, [jobs, query])
297
+ setCronFocusJobId(null)
298
+ }, [focusJobId, jobs])
299
+
300
+ const visibleJobs = useMemo(
301
+ () => jobs.filter(job => matchesQuery(job, query.trim())).sort((a, b) => jobTitle(a).localeCompare(jobTitle(b))),
302
+ [jobs, query]
303
+ )
304
+
305
+ // Detail always reflects a concrete job: the explicitly selected one, else the
306
+ // first visible row, so the right pane is never empty while jobs exist.
307
+ const selectedJob = useMemo(
308
+ () => visibleJobs.find(job => job.id === selectedJobId) ?? visibleJobs[0] ?? null,
309
+ [visibleJobs, selectedJobId]
310
+ )
311
+
312
+ // Scroll a sidebar-opened job into view once its list row is mounted.
313
+ useEffect(() => {
314
+ const target = pendingScrollRef.current
315
+
316
+ if (!target || selectedJob?.id !== target) {return}
317
+
318
+ pendingScrollRef.current = null
319
+ requestAnimationFrame(() => {
320
+ document.querySelector(`[data-cron-row="${CSS.escape(target)}"]`)?.scrollIntoView({ block: 'nearest' })
321
+ })
322
+ }, [selectedJob])
346
323
 
347
- const enabledCount = jobs?.filter(job => job.enabled).length ?? 0
348
- const totalCount = jobs?.length ?? 0
324
+ const totalCount = jobs.length
349
325
 
350
326
  async function handlePauseResume(job: CronJob) {
351
327
  setBusyJobId(job.id)
@@ -353,14 +329,14 @@ export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...pro
353
329
  try {
354
330
  const isPaused = jobState(job) === 'paused'
355
331
  const updated = isPaused ? await resumeCronJob(job.id) : await pauseCronJob(job.id)
356
- setJobs(current => (current ? current.map(row => (row.id === job.id ? updated : row)) : current))
332
+ updateCronJobs(rows => rows.map(row => (row.id === job.id ? updated : row)))
357
333
  notify({
358
334
  kind: 'success',
359
- title: isPaused ? 'Cron resumed' : 'Cron paused',
335
+ title: isPaused ? c.resumed : c.paused,
360
336
  message: truncate(jobTitle(job), 60)
361
337
  })
362
338
  } catch (err) {
363
- notifyError(err, 'Failed to update cron job')
339
+ notifyError(err, c.failedUpdate)
364
340
  } finally {
365
341
  setBusyJobId(null)
366
342
  }
@@ -371,10 +347,10 @@ export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...pro
371
347
 
372
348
  try {
373
349
  const updated = await triggerCronJob(job.id)
374
- setJobs(current => (current ? current.map(row => (row.id === job.id ? updated : row)) : current))
375
- notify({ kind: 'success', title: 'Cron triggered', message: truncate(jobTitle(job), 60) })
350
+ updateCronJobs(rows => rows.map(row => (row.id === job.id ? updated : row)))
351
+ notify({ kind: 'success', title: c.triggered, message: truncate(jobTitle(job), 60) })
376
352
  } catch (err) {
377
- notifyError(err, 'Failed to trigger cron job')
353
+ notifyError(err, c.failedTrigger)
378
354
  } finally {
379
355
  setBusyJobId(null)
380
356
  }
@@ -389,11 +365,11 @@ export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...pro
389
365
 
390
366
  try {
391
367
  await deleteCronJob(pendingDelete.id)
392
- setJobs(current => (current ? current.filter(row => row.id !== pendingDelete.id) : current))
393
- notify({ kind: 'success', title: 'Cron deleted', message: truncate(jobTitle(pendingDelete), 60) })
368
+ updateCronJobs(rows => rows.filter(row => row.id !== pendingDelete.id))
369
+ notify({ kind: 'success', title: c.deleted, message: truncate(jobTitle(pendingDelete), 60) })
394
370
  setPendingDelete(null)
395
371
  } catch (err) {
396
- notifyError(err, 'Failed to delete cron job')
372
+ notifyError(err, c.failedDelete)
397
373
  } finally {
398
374
  setDeleting(false)
399
375
  }
@@ -408,8 +384,8 @@ export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...pro
408
384
  deliver: values.deliver || DEFAULT_DELIVER
409
385
  })
410
386
 
411
- setJobs(current => (current ? [...current, created] : [created]))
412
- notify({ kind: 'success', title: 'Cron created', message: truncate(jobTitle(created), 60) })
387
+ updateCronJobs(rows => [...rows, created])
388
+ notify({ kind: 'success', title: c.created, message: truncate(jobTitle(created), 60) })
413
389
  } else if (editor.mode === 'edit') {
414
390
  const updated = await updateCronJob(editor.job.id, {
415
391
  prompt: values.prompt,
@@ -418,192 +394,313 @@ export function CronView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...pro
418
394
  deliver: values.deliver
419
395
  })
420
396
 
421
- setJobs(current => (current ? current.map(row => (row.id === updated.id ? updated : row)) : current))
422
- notify({ kind: 'success', title: 'Cron updated', message: truncate(jobTitle(updated), 60) })
397
+ updateCronJobs(rows => rows.map(row => (row.id === updated.id ? updated : row)))
398
+ notify({ kind: 'success', title: c.updated, message: truncate(jobTitle(updated), 60) })
423
399
  }
424
400
 
425
401
  setEditor({ mode: 'closed' })
426
402
  }
427
403
 
428
404
  return (
429
- <PageSearchShell
430
- {...props}
431
- filters={
432
- <div className="flex flex-wrap items-center justify-center gap-2">
433
- <Button onClick={() => setEditor({ mode: 'create' })} size="sm">
434
- <Codicon name="add" />
435
- New cron
436
- </Button>
437
- </div>
438
- }
439
- onSearchChange={setQuery}
440
- searchPlaceholder="Search cron jobs..."
441
- searchTrailingAction={
442
- <Button
443
- aria-label={refreshing ? 'Refreshing cron jobs' : 'Refresh cron jobs'}
444
- className="text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground"
445
- disabled={refreshing}
446
- onClick={() => void refresh()}
447
- size="icon-xs"
448
- title={refreshing ? 'Refreshing cron jobs' : 'Refresh cron jobs'}
449
- type="button"
450
- variant="ghost"
451
- >
452
- <Codicon name="refresh" size="0.875rem" spinning={refreshing} />
453
- </Button>
454
- }
455
- searchValue={query}
456
- >
457
- {!jobs ? (
458
- <PageLoader label="Loading cron jobs..." />
459
- ) : visibleJobs.length === 0 ? (
460
- <EmptyState
461
- actionLabel={totalCount === 0 ? 'Create first cron' : undefined}
462
- description={
463
- totalCount === 0
464
- ? 'Schedule a prompt to run on a cron expression. Hermes will run it and deliver results to the destination you pick.'
465
- : 'Try a broader search query.'
466
- }
467
- onAction={totalCount === 0 ? () => setEditor({ mode: 'create' }) : undefined}
468
- title={totalCount === 0 ? 'No scheduled jobs yet' : 'No matches'}
469
- />
405
+ <OverlayView closeLabel={c.close} onClose={onClose}>
406
+ {loading && jobs.length === 0 ? (
407
+ <PageLoader label={c.loading} />
470
408
  ) : (
471
- <div className="h-full overflow-y-auto px-4 py-3">
472
- <div className="divide-y divide-border/40 rounded-lg border border-border/40 bg-background/70">
409
+ <OverlaySplitLayout>
410
+ <OverlaySidebar>
411
+ <OverlayNewButton label={c.newCron} onClick={() => setEditor({ mode: 'create' })} />
412
+ {totalCount > 0 && (
413
+ <SearchField
414
+ aria-label={c.search}
415
+ containerClassName="mb-1 w-full px-2"
416
+ onChange={setQuery}
417
+ placeholder={c.search}
418
+ value={query}
419
+ />
420
+ )}
473
421
  {visibleJobs.map(job => (
474
- <CronJobRow
475
- busy={busyJobId === job.id}
422
+ <CronJobListRow
423
+ active={selectedJob?.id === job.id}
424
+ c={c}
476
425
  job={job}
477
426
  key={job.id}
478
- onDelete={() => setPendingDelete(job)}
479
- onEdit={() => setEditor({ mode: 'edit', job })}
480
- onPauseResume={() => void handlePauseResume(job)}
481
- onTrigger={() => void handleTrigger(job)}
427
+ onSelect={() => setSelectedJobId(job.id)}
482
428
  />
483
429
  ))}
484
- </div>
485
- </div>
430
+ {visibleJobs.length === 0 && (
431
+ <p className="px-2 py-4 text-center text-xs text-muted-foreground">
432
+ {totalCount === 0 ? c.emptyTitleNew : c.emptyTitleSearch}
433
+ </p>
434
+ )}
435
+ </OverlaySidebar>
436
+
437
+ <OverlayMain className="px-0">
438
+ {selectedJob ? (
439
+ <CronJobDetail
440
+ busy={busyJobId === selectedJob.id}
441
+ c={c}
442
+ job={selectedJob}
443
+ onDelete={() => setPendingDelete(selectedJob)}
444
+ onEdit={() => setEditor({ mode: 'edit', job: selectedJob })}
445
+ onOpenSession={onOpenSession}
446
+ onPauseResume={() => void handlePauseResume(selectedJob)}
447
+ onTrigger={() => void handleTrigger(selectedJob)}
448
+ />
449
+ ) : (
450
+ <div className="grid h-full place-items-center px-6 py-12 text-center text-sm text-muted-foreground">
451
+ <div>
452
+ <Clock className="mx-auto size-6 text-muted-foreground/60" />
453
+ <p className="mt-3">{totalCount === 0 ? c.emptyDescNew : c.emptyDescSearch}</p>
454
+ </div>
455
+ </div>
456
+ )}
457
+ </OverlayMain>
458
+ </OverlaySplitLayout>
486
459
  )}
487
- <div className="hidden">{totalCount === 0 ? 'No scheduled jobs' : `${enabledCount}/${totalCount} active`}</div>
488
460
 
489
461
  <CronEditorDialog editor={editor} onClose={() => setEditor({ mode: 'closed' })} onSave={handleEditorSave} />
490
462
 
491
- <Dialog onOpenChange={open => !open && !deleting && setPendingDelete(null)} open={pendingDelete !== null}>
492
- <DialogContent className="max-w-md">
493
- <DialogHeader>
494
- <DialogTitle>Delete cron job?</DialogTitle>
495
- <DialogDescription>
496
- {pendingDelete ? (
497
- <>
498
- This will remove{' '}
499
- <span className="font-medium text-foreground">{truncate(jobTitle(pendingDelete), 60)}</span>{' '}
500
- permanently. It will stop firing immediately.
501
- </>
502
- ) : null}
503
- </DialogDescription>
504
- </DialogHeader>
505
- <DialogFooter>
506
- <Button disabled={deleting} onClick={() => setPendingDelete(null)} variant="outline">
507
- Cancel
508
- </Button>
509
- <Button disabled={deleting} onClick={() => void handleConfirmDelete()} variant="destructive">
510
- {deleting ? 'Deleting...' : 'Delete'}
511
- </Button>
512
- </DialogFooter>
513
- </DialogContent>
514
- </Dialog>
515
- </PageSearchShell>
463
+ <Dialog onOpenChange={open => !open && !deleting && setPendingDelete(null)} open={pendingDelete !== null}>
464
+ <DialogContent className="max-w-md">
465
+ <DialogHeader>
466
+ <DialogTitle>{c.deleteTitle}</DialogTitle>
467
+ <DialogDescription>
468
+ {pendingDelete ? (
469
+ <>
470
+ {c.deleteDescPrefix}
471
+ <span className="font-medium text-foreground">{truncate(jobTitle(pendingDelete), 60)}</span>
472
+ {c.deleteDescSuffix}
473
+ </>
474
+ ) : null}
475
+ </DialogDescription>
476
+ </DialogHeader>
477
+ <DialogFooter>
478
+ <Button disabled={deleting} onClick={() => setPendingDelete(null)} variant="outline">
479
+ {t.common.cancel}
480
+ </Button>
481
+ <Button disabled={deleting} onClick={() => void handleConfirmDelete()} variant="destructive">
482
+ {deleting ? c.deleting : t.common.delete}
483
+ </Button>
484
+ </DialogFooter>
485
+ </DialogContent>
486
+ </Dialog>
487
+ </OverlayView>
488
+ )
489
+ }
490
+
491
+ function CronJobListRow({
492
+ active,
493
+ c,
494
+ job,
495
+ onSelect
496
+ }: {
497
+ active: boolean
498
+ c: Translations['cron']
499
+ job: CronJob
500
+ onSelect: () => void
501
+ }) {
502
+ const state = jobState(job)
503
+
504
+ return (
505
+ <button
506
+ className={cn(
507
+ 'flex w-full flex-col items-start gap-0.5 rounded-md px-2 py-1.5 text-left transition-colors',
508
+ active ? 'bg-accent text-foreground' : 'text-foreground/85 hover:bg-accent/60'
509
+ )}
510
+ data-cron-row={job.id}
511
+ onClick={onSelect}
512
+ type="button"
513
+ >
514
+ <span className="flex w-full items-center gap-2">
515
+ <span
516
+ aria-hidden="true"
517
+ className={cn('size-1.5 shrink-0 rounded-full', STATE_DOT[state] ?? 'bg-muted-foreground')}
518
+ />
519
+ <span className="min-w-0 flex-1 truncate text-sm font-medium">{jobTitle(job)}</span>
520
+ </span>
521
+ <span className="truncate pl-3.5 text-[0.66rem] text-muted-foreground">{jobScheduleDisplay(job)}</span>
522
+ </button>
516
523
  )
517
524
  }
518
525
 
519
- function CronJobRow({
526
+ function CronJobDetail({
520
527
  busy,
528
+ c,
521
529
  job,
522
530
  onDelete,
523
531
  onEdit,
532
+ onOpenSession,
524
533
  onPauseResume,
525
534
  onTrigger
526
535
  }: {
527
536
  busy: boolean
537
+ c: Translations['cron']
528
538
  job: CronJob
529
539
  onDelete: () => void
530
540
  onEdit: () => void
541
+ onOpenSession?: (sessionId: string) => void
531
542
  onPauseResume: () => void
532
543
  onTrigger: () => void
533
544
  }) {
534
545
  const state = jobState(job)
535
546
  const isPaused = state === 'paused'
536
- const hasName = Boolean(jobName(job))
537
- const prompt = jobPrompt(job)
538
547
  const deliver = jobDeliver(job)
548
+ const prompt = jobPrompt(job)
539
549
 
540
550
  return (
541
- <div className="grid gap-3 px-3 py-2.5 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-start">
542
- <button
543
- className="min-w-0 cursor-pointer rounded-md text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40"
544
- onClick={onEdit}
545
- type="button"
546
- >
547
- <div className="flex flex-wrap items-center gap-2">
548
- <span className="truncate text-sm font-medium">{jobTitle(job)}</span>
549
- <StatePill tone={STATE_TONE[state] ?? 'muted'}>{state}</StatePill>
550
- {deliver && deliver !== DEFAULT_DELIVER && <StatePill tone="muted">{deliver}</StatePill>}
551
- </div>
552
- {hasName && prompt && <p className="mt-1 truncate text-xs text-muted-foreground">{truncate(prompt, 120)}</p>}
553
- <div className="mt-1 flex flex-wrap items-center gap-x-4 gap-y-1 text-[0.68rem] text-muted-foreground">
554
- <span className="inline-flex items-center gap-1 font-mono">
555
- <Clock className="size-3" />
556
- {jobScheduleDisplay(job)}
557
- </span>
558
- <span>Last: {formatTime(job.last_run_at)}</span>
559
- <span>Next: {formatTime(job.next_run_at)}</span>
551
+ <div className="flex h-full min-h-0 flex-col">
552
+ <div className="min-h-0 flex-1 overflow-y-auto">
553
+ <div className="mx-auto max-w-2xl space-y-6 px-6 py-6">
554
+ <header className="space-y-3">
555
+ <div className="flex flex-wrap items-start justify-between gap-3">
556
+ <div className="min-w-0 space-y-1">
557
+ <div className="flex flex-wrap items-center gap-2">
558
+ <h3 className="text-xl font-semibold tracking-tight">{jobTitle(job)}</h3>
559
+ <StatePill tone={STATE_TONE[state] ?? 'muted'}>{c.states[state] ?? state}</StatePill>
560
+ {deliver && deliver !== DEFAULT_DELIVER && (
561
+ <StatePill tone="muted">{c.deliveryLabels[deliver] ?? deliver}</StatePill>
562
+ )}
563
+ </div>
564
+ <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-[0.7rem] text-muted-foreground">
565
+ <span className="inline-flex items-center gap-1">
566
+ <Clock className="size-3" />
567
+ {jobScheduleDisplay(job)}
568
+ </span>
569
+ <span>
570
+ {c.last} {formatTime(job.last_run_at)}
571
+ </span>
572
+ <span>
573
+ {c.next} {formatTime(job.next_run_at)}
574
+ </span>
575
+ </div>
576
+ </div>
577
+ <div className="flex shrink-0 items-center gap-1">
578
+ <Button disabled={busy} onClick={onPauseResume} size="sm" variant="outline">
579
+ <Codicon name={isPaused ? 'play' : 'debug-pause'} size="0.875rem" />
580
+ {isPaused ? c.resumeTitle : c.pauseTitle}
581
+ </Button>
582
+ <Button disabled={busy} onClick={onTrigger} size="sm" variant="outline">
583
+ <Codicon name="zap" size="0.875rem" />
584
+ {c.triggerNow}
585
+ </Button>
586
+ <Button onClick={onEdit} size="sm" variant="outline">
587
+ <Codicon name="edit" size="0.875rem" />
588
+ {c.edit}
589
+ </Button>
590
+ <Button
591
+ className="text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
592
+ onClick={onDelete}
593
+ size="sm"
594
+ variant="ghost"
595
+ >
596
+ <Codicon name="trash" size="0.875rem" />
597
+ </Button>
598
+ </div>
599
+ </div>
600
+
601
+ {prompt && <p className="line-clamp-3 text-xs text-muted-foreground">{prompt}</p>}
602
+ {job.last_error && (
603
+ <p className="inline-flex items-start gap-1 text-[0.7rem] text-destructive">
604
+ <AlertTriangle className="mt-px size-3 shrink-0" />
605
+ <span className="line-clamp-2">{job.last_error}</span>
606
+ </p>
607
+ )}
608
+ </header>
609
+
610
+ <CronJobRuns c={c} jobId={job.id} onOpenSession={onOpenSession} />
560
611
  </div>
561
- {job.last_error && (
562
- <p className="mt-1 inline-flex items-start gap-1 text-[0.68rem] text-destructive">
563
- <AlertTriangle className="mt-px size-3 shrink-0" />
564
- <span className="line-clamp-2">{job.last_error}</span>
565
- </p>
566
- )}
567
- </button>
568
-
569
- <div className="flex shrink-0 items-center gap-0.5">
570
- <IconAction
571
- aria-label={isPaused ? 'Resume cron' : 'Pause cron'}
572
- disabled={busy}
573
- onClick={onPauseResume}
574
- title={isPaused ? 'Resume' : 'Pause'}
575
- >
576
- {isPaused ? <Play className="size-3.5" /> : <Pause className="size-3.5" />}
577
- </IconAction>
578
- <IconAction aria-label="Trigger now" disabled={busy} onClick={onTrigger} title="Trigger now">
579
- <Zap className="size-3.5" />
580
- </IconAction>
581
- <IconAction aria-label="Edit cron" onClick={onEdit} title="Edit">
582
- <Pencil className="size-3.5" />
583
- </IconAction>
584
- <IconAction
585
- aria-label="Delete cron"
586
- className="text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
587
- onClick={onDelete}
588
- title="Delete"
589
- >
590
- <Trash2 className="size-3.5" />
591
- </IconAction>
592
612
  </div>
593
613
  </div>
594
614
  )
595
615
  }
596
616
 
597
- function IconAction({ children, className, ...props }: Omit<React.ComponentProps<typeof Button>, 'size' | 'variant'>) {
617
+ function formatRunTime(seconds?: null | number): string {
618
+ if (!seconds) {
619
+ return '—'
620
+ }
621
+
622
+ const date = new Date(seconds * 1000)
623
+
624
+ return Number.isNaN(date.valueOf()) ? '—' : date.toLocaleString()
625
+ }
626
+
627
+ // Runs are produced by the background scheduler tick (no UI signal), so poll
628
+ // while the panel is open + on tab re-focus so a fired run shows up within a few
629
+ // seconds instead of waiting for a reload.
630
+ const RUNS_POLL_INTERVAL_MS = 8000
631
+
632
+ function CronJobRuns({
633
+ c,
634
+ jobId,
635
+ onOpenSession
636
+ }: {
637
+ c: Translations['cron']
638
+ jobId: string
639
+ onOpenSession?: (sessionId: string) => void
640
+ }) {
641
+ const [runs, setRuns] = useState<null | SessionInfo[]>(null)
642
+
643
+ useEffect(() => {
644
+ let cancelled = false
645
+
646
+ const load = () =>
647
+ getCronJobRuns(jobId)
648
+ .then(result => {
649
+ if (!cancelled) {setRuns(result)}
650
+ })
651
+ .catch(() => {
652
+ if (!cancelled) {setRuns(prev => prev ?? [])}
653
+ })
654
+
655
+ void load()
656
+
657
+ const intervalId = window.setInterval(() => {
658
+ if (document.visibilityState === 'visible') {void load()}
659
+ }, RUNS_POLL_INTERVAL_MS)
660
+
661
+ const onVisible = () => {
662
+ if (document.visibilityState === 'visible') {void load()}
663
+ }
664
+
665
+ document.addEventListener('visibilitychange', onVisible)
666
+
667
+ return () => {
668
+ cancelled = true
669
+ window.clearInterval(intervalId)
670
+ document.removeEventListener('visibilitychange', onVisible)
671
+ }
672
+ }, [jobId])
673
+
598
674
  return (
599
- <Button
600
- className={cn('size-7 text-muted-foreground hover:text-foreground', className)}
601
- size="icon"
602
- variant="ghost"
603
- {...props}
604
- >
605
- {children}
606
- </Button>
675
+ <div>
676
+ <div className="mb-1.5 text-[0.62rem] font-medium uppercase tracking-wide text-muted-foreground">
677
+ {c.runHistory}
678
+ {runs && runs.length > 0 ? ` · ${runs.length}` : ''}
679
+ </div>
680
+ {runs === null ? (
681
+ <div className="flex items-center gap-1.5 py-1 text-xs text-muted-foreground">
682
+ <Codicon name="loading" size="0.75rem" spinning />
683
+ </div>
684
+ ) : runs.length === 0 ? (
685
+ <div className="py-1 text-xs text-muted-foreground">{c.noRuns}</div>
686
+ ) : (
687
+ <div className="flex flex-col gap-px">
688
+ {runs.map(run => (
689
+ <button
690
+ className="flex items-center justify-between gap-3 rounded-md px-2 py-1 text-left text-xs hover:bg-(--chrome-action-hover) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40"
691
+ key={run.id}
692
+ onClick={() => onOpenSession?.(run.id)}
693
+ type="button"
694
+ >
695
+ <span className="truncate text-foreground">{run.title?.trim() || run.preview?.trim() || run.id}</span>
696
+ <span className="shrink-0 text-[0.62rem] text-muted-foreground tabular-nums">
697
+ {formatRunTime(run.last_active || run.started_at)}
698
+ </span>
699
+ </button>
700
+ ))}
701
+ </div>
702
+ )}
703
+ </div>
607
704
  )
608
705
  }
609
706
 
@@ -617,33 +714,6 @@ function StatePill({ children, tone }: { children: string; tone: keyof typeof PI
617
714
  )
618
715
  }
619
716
 
620
- function EmptyState({
621
- actionLabel,
622
- description,
623
- onAction,
624
- title
625
- }: {
626
- actionLabel?: string
627
- description: string
628
- onAction?: () => void
629
- title: string
630
- }) {
631
- return (
632
- <div className="grid h-full place-items-center px-6 py-12 text-center">
633
- <div className="max-w-sm space-y-2">
634
- <div className="text-sm font-medium">{title}</div>
635
- <p className="text-xs text-muted-foreground">{description}</p>
636
- {actionLabel && onAction && (
637
- <Button className="mt-2" onClick={onAction} size="sm">
638
- <Codicon name="add" />
639
- {actionLabel}
640
- </Button>
641
- )}
642
- </div>
643
- </div>
644
- )
645
- }
646
-
647
717
  function CronEditorDialog({
648
718
  editor,
649
719
  onClose,
@@ -653,6 +723,8 @@ function CronEditorDialog({
653
723
  onClose: () => void
654
724
  onSave: (values: EditorValues) => Promise<void>
655
725
  }) {
726
+ const { t } = useI18n()
727
+ const c = t.cron
656
728
  const open = editor.mode !== 'closed'
657
729
  const isEdit = editor.mode === 'edit'
658
730
  const initial = isEdit ? editor.job : null
@@ -695,7 +767,7 @@ function CronEditorDialog({
695
767
  }
696
768
  }
697
769
 
698
- const scheduleHint = scheduleSummary(selectedScheduleOption, schedule)
770
+ const scheduleHint = scheduleSummary(selectedScheduleOption, schedule, c)
699
771
 
700
772
  async function handleSubmit(event: React.FormEvent) {
701
773
  event.preventDefault()
@@ -703,7 +775,7 @@ function CronEditorDialog({
703
775
  const trimmedSchedule = schedule.trim()
704
776
 
705
777
  if (!trimmedPrompt || !trimmedSchedule) {
706
- setError('Prompt and schedule are required.')
778
+ setError(c.promptScheduleRequired)
707
779
 
708
780
  return
709
781
  }
@@ -719,7 +791,7 @@ function CronEditorDialog({
719
791
  schedule: trimmedSchedule
720
792
  })
721
793
  } catch (err) {
722
- setError(err instanceof Error ? err.message : 'Failed to save cron job')
794
+ setError(err instanceof Error ? err.message : c.failedSave)
723
795
  } finally {
724
796
  setSaving(false)
725
797
  }
@@ -729,37 +801,33 @@ function CronEditorDialog({
729
801
  <Dialog onOpenChange={value => !value && !saving && onClose()} open={open}>
730
802
  <DialogContent className="max-w-lg">
731
803
  <DialogHeader>
732
- <DialogTitle>{isEdit ? 'Edit cron job' : 'New cron job'}</DialogTitle>
733
- <DialogDescription>
734
- {isEdit
735
- ? 'Update the schedule, prompt, or delivery target. Changes apply on next run.'
736
- : 'Schedule a prompt to run automatically. Use cron syntax or a natural phrase like "every 15 minutes".'}
737
- </DialogDescription>
804
+ <DialogTitle>{isEdit ? c.editTitle : c.createTitle}</DialogTitle>
805
+ <DialogDescription>{isEdit ? c.editDesc : c.createDesc}</DialogDescription>
738
806
  </DialogHeader>
739
807
 
740
808
  <form className="grid gap-4" onSubmit={handleSubmit}>
741
- <Field htmlFor="cron-name" label="Name" optional>
809
+ <Field htmlFor="cron-name" label={c.nameLabel} optional optionalLabel={c.optional}>
742
810
  <Input
743
811
  autoFocus
744
812
  id="cron-name"
745
813
  onChange={event => setName(event.target.value)}
746
- placeholder="Morning briefing"
814
+ placeholder={c.namePlaceholder}
747
815
  value={name}
748
816
  />
749
817
  </Field>
750
818
 
751
- <Field htmlFor="cron-prompt" label="Prompt">
819
+ <Field htmlFor="cron-prompt" label={c.promptLabel}>
752
820
  <Textarea
753
821
  className="min-h-24 font-mono"
754
822
  id="cron-prompt"
755
823
  onChange={event => setPrompt(event.target.value)}
756
- placeholder="Summarize my unread Slack threads and email me the top 5..."
824
+ placeholder={c.promptPlaceholder}
757
825
  value={prompt}
758
826
  />
759
827
  </Field>
760
828
 
761
829
  <div className="grid items-start gap-4 sm:grid-cols-2">
762
- <Field htmlFor="cron-frequency" label="Frequency">
830
+ <Field htmlFor="cron-frequency" label={c.frequencyLabel}>
763
831
  <Select onValueChange={handleSchedulePresetChange} value={schedulePreset}>
764
832
  <SelectTrigger className="h-9 rounded-md" id="cron-frequency">
765
833
  <SelectValue />
@@ -767,22 +835,22 @@ function CronEditorDialog({
767
835
  <SelectContent>
768
836
  {SCHEDULE_OPTIONS.map(option => (
769
837
  <SelectItem key={option.value} value={option.value}>
770
- {option.label}
838
+ {c.scheduleLabels[option.value]}
771
839
  </SelectItem>
772
840
  ))}
773
841
  </SelectContent>
774
842
  </Select>
775
843
  </Field>
776
844
 
777
- <Field htmlFor="cron-deliver" label="Deliver to">
845
+ <Field htmlFor="cron-deliver" label={c.deliverLabel}>
778
846
  <Select onValueChange={setDeliver} value={deliver}>
779
847
  <SelectTrigger className="h-9 rounded-md" id="cron-deliver">
780
848
  <SelectValue />
781
849
  </SelectTrigger>
782
850
  <SelectContent>
783
- {DELIVERY_OPTIONS.map(option => (
784
- <SelectItem key={option.value} value={option.value}>
785
- {option.label}
851
+ {DELIVERY_VALUES.map(value => (
852
+ <SelectItem key={value} value={value}>
853
+ {c.deliveryLabels[value]}
786
854
  </SelectItem>
787
855
  ))}
788
856
  </SelectContent>
@@ -791,18 +859,18 @@ function CronEditorDialog({
791
859
  </div>
792
860
 
793
861
  {schedulePreset === 'custom' ? (
794
- <Field htmlFor="cron-schedule" label="Custom schedule">
862
+ <Field htmlFor="cron-schedule" label={c.customScheduleLabel}>
795
863
  <Input
796
864
  className="font-mono"
797
865
  id="cron-schedule"
798
866
  onChange={event => setSchedule(event.target.value)}
799
- placeholder="0 9 * * * or weekdays at 9am"
867
+ placeholder={c.customPlaceholder}
800
868
  value={schedule}
801
869
  />
802
- <FieldHint>Cron expression, or phrases like "every hour" or "weekdays at 9am".</FieldHint>
870
+ <FieldHint>{c.customHint}</FieldHint>
803
871
  </Field>
804
872
  ) : (
805
- <div className="rounded-md border border-border/60 bg-muted/30 px-3 py-2">
873
+ <div className="rounded-md bg-(--ui-bg-quinary) px-3 py-2">
806
874
  <div className="flex flex-wrap items-center justify-between gap-2 text-xs">
807
875
  <span className="font-medium text-foreground">{scheduleHint}</span>
808
876
  <span className="font-mono text-muted-foreground">{schedule}</span>
@@ -811,7 +879,7 @@ function CronEditorDialog({
811
879
  )}
812
880
 
813
881
  {error && (
814
- <div className="flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
882
+ <div className="flex items-start gap-2 rounded-md bg-destructive/10 px-3 py-2 text-xs text-destructive">
815
883
  <AlertTriangle className="mt-0.5 size-3.5 shrink-0" />
816
884
  <span>{error}</span>
817
885
  </div>
@@ -819,10 +887,10 @@ function CronEditorDialog({
819
887
 
820
888
  <DialogFooter>
821
889
  <Button disabled={saving} onClick={onClose} type="button" variant="outline">
822
- Cancel
890
+ {t.common.cancel}
823
891
  </Button>
824
892
  <Button disabled={saving} type="submit">
825
- {saving ? 'Saving...' : isEdit ? 'Save changes' : 'Create cron'}
893
+ {saving ? t.common.saving : isEdit ? c.saveChanges : c.createAction}
826
894
  </Button>
827
895
  </DialogFooter>
828
896
  </form>
@@ -835,18 +903,20 @@ function Field({
835
903
  children,
836
904
  htmlFor,
837
905
  label,
838
- optional
906
+ optional,
907
+ optionalLabel
839
908
  }: {
840
909
  children: React.ReactNode
841
910
  htmlFor: string
842
911
  label: string
843
912
  optional?: boolean
913
+ optionalLabel?: string
844
914
  }) {
845
915
  return (
846
916
  <div className="grid gap-1.5">
847
917
  <label className="flex items-baseline gap-2 text-xs font-medium text-foreground" htmlFor={htmlFor}>
848
918
  {label}
849
- {optional && <span className="text-[0.65rem] font-normal text-muted-foreground">Optional</span>}
919
+ {optional && <span className="text-[0.65rem] font-normal text-muted-foreground">{optionalLabel}</span>}
850
920
  </label>
851
921
  {children}
852
922
  </div>
@@ -868,7 +938,5 @@ interface EditorValues {
868
938
 
869
939
  interface ScheduleOption {
870
940
  expr?: string
871
- hint: string
872
- label: string
873
941
  value: string
874
942
  }