@clawpump/claw-agent 0.1.5 → 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.
- package/agent/.dockerignore +67 -0
- package/agent/.envrc +1 -1
- package/agent/.gitattributes +8 -0
- package/agent/AGENTS.md +216 -4
- package/agent/CONTRIBUTING.md +46 -8
- package/agent/Dockerfile +78 -35
- package/agent/MANIFEST.in +2 -0
- package/agent/README.md +12 -5
- package/agent/README.ur-pk.md +261 -0
- package/agent/README.zh-CN.md +11 -8
- package/agent/SECURITY.md +5 -4
- package/agent/acp_adapter/provenance.py +127 -0
- package/agent/acp_adapter/server.py +112 -5
- package/agent/acp_adapter/session.py +1 -6
- package/agent/acp_registry/agent.json +2 -2
- package/agent/agent/account_usage.py +313 -1
- package/agent/agent/agent_init.py +140 -37
- package/agent/agent/agent_runtime_helpers.py +342 -83
- package/agent/agent/anthropic_adapter.py +320 -33
- package/agent/agent/auxiliary_client.py +525 -105
- package/agent/agent/background_review.py +157 -19
- package/agent/agent/bedrock_adapter.py +71 -6
- package/agent/agent/billing_view.py +295 -0
- package/agent/agent/chat_completion_helpers.py +229 -4
- package/agent/agent/codex_responses_adapter.py +86 -10
- package/agent/agent/codex_runtime.py +153 -1
- package/agent/agent/coding_context.py +738 -0
- package/agent/agent/context_compressor.py +392 -44
- package/agent/agent/context_references.py +34 -1
- package/agent/agent/conversation_compression.py +159 -22
- package/agent/agent/conversation_loop.py +643 -908
- package/agent/agent/copilot_acp_client.py +4 -11
- package/agent/agent/credential_pool.py +5 -3
- package/agent/agent/credits_tracker.py +794 -0
- package/agent/agent/curator.py +91 -18
- package/agent/agent/curator_backup.py +26 -10
- package/agent/agent/display.py +42 -1
- package/agent/agent/error_classifier.py +52 -3
- package/agent/agent/errors.py +3 -0
- package/agent/agent/file_safety.py +0 -17
- package/agent/agent/gemini_native_adapter.py +31 -1
- package/agent/agent/i18n.py +48 -4
- package/agent/agent/image_gen_provider.py +74 -5
- package/agent/agent/image_routing.py +29 -0
- package/agent/agent/insights.py +8 -17
- package/agent/agent/lsp/install.py +3 -0
- package/agent/agent/memory_manager.py +326 -31
- package/agent/agent/message_content.py +50 -0
- package/agent/agent/model_metadata.py +214 -3
- package/agent/agent/moonshot_schema.py +8 -1
- package/agent/agent/onboarding.py +60 -0
- package/agent/agent/prompt_builder.py +327 -37
- package/agent/agent/redact.py +1 -0
- package/agent/agent/runtime_cwd.py +34 -5
- package/agent/agent/secret_scope.py +205 -0
- package/agent/agent/secret_sources/bitwarden.py +34 -2
- package/agent/agent/skill_commands.py +90 -1
- package/agent/agent/skill_preprocessing.py +1 -0
- package/agent/agent/skill_utils.py +209 -36
- package/agent/agent/ssl_guard.py +94 -0
- package/agent/agent/system_prompt.py +133 -5
- package/agent/agent/tool_executor.py +496 -70
- package/agent/agent/transports/anthropic.py +83 -21
- package/agent/agent/transports/chat_completions.py +94 -5
- package/agent/agent/transports/codex.py +67 -2
- package/agent/agent/transports/codex_app_server.py +1 -0
- package/agent/agent/transports/codex_app_server_session.py +30 -0
- package/agent/agent/transports/types.py +12 -0
- package/agent/agent/turn_context.py +408 -0
- package/agent/agent/turn_finalizer.py +428 -0
- package/agent/agent/turn_retry_state.py +68 -0
- package/agent/agent/usage_pricing.py +3 -0
- package/agent/apps/bootstrap-installer/package.json +6 -5
- package/agent/apps/bootstrap-installer/src/routes/failure.tsx +12 -5
- package/agent/apps/bootstrap-installer/src/routes/progress.tsx +1 -3
- package/agent/apps/bootstrap-installer/src/store.ts +3 -2
- package/agent/apps/bootstrap-installer/src-tauri/src/bootstrap.rs +172 -7
- package/agent/apps/bootstrap-installer/src-tauri/src/events.rs +14 -1
- package/agent/apps/bootstrap-installer/src-tauri/src/paths.rs +29 -0
- package/agent/apps/bootstrap-installer/src-tauri/src/powershell.rs +93 -3
- package/agent/apps/bootstrap-installer/src-tauri/src/update.rs +695 -39
- package/agent/apps/bootstrap-installer/tsconfig.json +3 -4
- package/agent/apps/desktop/DESIGN.md +167 -0
- package/agent/apps/desktop/README.md +20 -16
- package/agent/apps/desktop/assets/icon.icns +0 -0
- package/agent/apps/desktop/assets/icon.ico +0 -0
- package/agent/apps/desktop/assets/icon.png +0 -0
- package/agent/apps/desktop/electron/backend-env.cjs +112 -0
- package/agent/apps/desktop/electron/backend-env.test.cjs +111 -0
- package/agent/apps/desktop/electron/backend-probes.test.cjs +3 -1
- package/agent/apps/desktop/electron/backend-ready.cjs +66 -0
- package/agent/apps/desktop/electron/bootstrap-platform.cjs +52 -0
- package/agent/apps/desktop/electron/bootstrap-platform.test.cjs +59 -1
- package/agent/apps/desktop/electron/bootstrap-runner.cjs +176 -38
- package/agent/apps/desktop/electron/bootstrap-runner.test.cjs +112 -1
- package/agent/apps/desktop/electron/connection-config.cjs +288 -0
- package/agent/apps/desktop/electron/connection-config.test.cjs +396 -0
- package/agent/apps/desktop/electron/dashboard-token.cjs +99 -0
- package/agent/apps/desktop/electron/dashboard-token.test.cjs +142 -0
- package/agent/apps/desktop/electron/desktop-uninstall.cjs +232 -0
- package/agent/apps/desktop/electron/desktop-uninstall.test.cjs +246 -0
- package/agent/apps/desktop/electron/entitlements.mac.inherit.plist +2 -0
- package/agent/apps/desktop/electron/fs-read-dir.cjs +109 -0
- package/agent/apps/desktop/electron/fs-read-dir.test.cjs +364 -0
- package/agent/apps/desktop/electron/gateway-ws-probe.cjs +188 -0
- package/agent/apps/desktop/electron/gateway-ws-probe.test.cjs +122 -0
- package/agent/apps/desktop/electron/git-root.cjs +54 -0
- package/agent/apps/desktop/electron/git-root.test.cjs +40 -0
- package/agent/apps/desktop/electron/git-worktrees.cjs +174 -0
- package/agent/apps/desktop/electron/hardening.cjs +123 -28
- package/agent/apps/desktop/electron/hardening.test.cjs +163 -0
- package/agent/apps/desktop/electron/main.cjs +3121 -331
- package/agent/apps/desktop/electron/oauth-net-request.cjs +20 -0
- package/agent/apps/desktop/electron/oauth-net-request.test.cjs +34 -0
- package/agent/apps/desktop/electron/preload.cjs +52 -2
- package/agent/apps/desktop/electron/session-windows.cjs +124 -0
- package/agent/apps/desktop/electron/session-windows.test.cjs +199 -0
- package/agent/apps/desktop/electron/update-rebuild.cjs +29 -0
- package/agent/apps/desktop/electron/update-rebuild.test.cjs +55 -0
- package/agent/apps/desktop/electron/update-remote.cjs +56 -0
- package/agent/apps/desktop/electron/update-remote.test.cjs +78 -0
- package/agent/apps/desktop/electron/vscode-marketplace.cjs +331 -0
- package/agent/apps/desktop/electron/vscode-marketplace.test.cjs +113 -0
- package/agent/apps/desktop/electron/windows-child-process.test.cjs +57 -0
- package/agent/apps/desktop/electron/windows-user-env.cjs +76 -0
- package/agent/apps/desktop/electron/windows-user-env.test.cjs +90 -0
- package/agent/apps/desktop/electron/workspace-cwd.cjs +38 -0
- package/agent/apps/desktop/electron/workspace-cwd.test.cjs +45 -0
- package/agent/apps/desktop/eslint.config.mjs +0 -3
- package/agent/apps/desktop/index.html +27 -2
- package/agent/apps/desktop/package.json +31 -11
- package/agent/apps/desktop/pr-assets/session-source-folders.png +0 -0
- package/agent/apps/desktop/public/apple-touch-icon.png +0 -0
- package/agent/apps/desktop/public/nous-girl.jpg +0 -0
- package/agent/apps/desktop/scripts/assert-dist-built.cjs +70 -0
- package/agent/apps/desktop/scripts/assert-dist-built.test.cjs +84 -0
- package/agent/apps/desktop/scripts/before-pack.cjs +78 -0
- package/agent/apps/desktop/scripts/before-pack.test.cjs +53 -0
- package/agent/apps/desktop/scripts/diag-scroll-reset.mjs +229 -0
- package/agent/apps/desktop/scripts/patch-electron-builder-mac-binary.cjs +64 -0
- package/agent/apps/desktop/scripts/run-electron-builder.cjs +57 -0
- package/agent/apps/desktop/src/app/agents/index.tsx +53 -45
- package/agent/apps/desktop/src/app/artifacts/index.tsx +102 -83
- package/agent/apps/desktop/src/app/chat/chat-drop-overlay.tsx +29 -8
- package/agent/apps/desktop/src/app/chat/chat-swap-overlay.tsx +47 -0
- package/agent/apps/desktop/src/app/chat/composer/attachments.tsx +81 -45
- package/agent/apps/desktop/src/app/chat/composer/completion-drawer.tsx +13 -24
- package/agent/apps/desktop/src/app/chat/composer/context-menu.tsx +138 -88
- package/agent/apps/desktop/src/app/chat/composer/controls.tsx +138 -90
- package/agent/apps/desktop/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
- package/agent/apps/desktop/src/app/chat/composer/focus.ts +32 -0
- package/agent/apps/desktop/src/app/chat/composer/help-hint.tsx +38 -25
- package/agent/apps/desktop/src/app/chat/composer/hooks/use-live-completion-adapter.ts +7 -0
- package/agent/apps/desktop/src/app/chat/composer/hooks/use-mic-recorder.ts +22 -12
- package/agent/apps/desktop/src/app/chat/composer/hooks/use-slash-completions.ts +142 -14
- package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts +14 -11
- package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-recorder.ts +9 -6
- package/agent/apps/desktop/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
- package/agent/apps/desktop/src/app/chat/composer/index.tsx +930 -180
- package/agent/apps/desktop/src/app/chat/composer/inline-refs.ts +136 -32
- package/agent/apps/desktop/src/app/chat/composer/model-pill.tsx +86 -0
- package/agent/apps/desktop/src/app/chat/composer/queue-panel.tsx +54 -75
- package/agent/apps/desktop/src/app/chat/composer/rich-editor.test.ts +117 -1
- package/agent/apps/desktop/src/app/chat/composer/rich-editor.ts +117 -6
- package/agent/apps/desktop/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
- package/agent/apps/desktop/src/app/chat/composer/status-stack/index.tsx +202 -0
- package/agent/apps/desktop/src/app/chat/composer/status-stack/status-row.tsx +155 -0
- package/agent/apps/desktop/src/app/chat/composer/text-utils.test.ts +104 -0
- package/agent/apps/desktop/src/app/chat/composer/text-utils.ts +37 -9
- package/agent/apps/desktop/src/app/chat/composer/trigger-popover.test.tsx +50 -0
- package/agent/apps/desktop/src/app/chat/composer/trigger-popover.tsx +105 -40
- package/agent/apps/desktop/src/app/chat/composer/types.ts +5 -0
- package/agent/apps/desktop/src/app/chat/composer/url-dialog.tsx +11 -15
- package/agent/apps/desktop/src/app/chat/composer/voice-activity.tsx +8 -4
- package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
- package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.ts +70 -16
- package/agent/apps/desktop/src/app/chat/hooks/use-file-drop-zone.ts +52 -16
- package/agent/apps/desktop/src/app/chat/index.tsx +234 -81
- package/agent/apps/desktop/src/app/chat/perf-probe.tsx +69 -21
- package/agent/apps/desktop/src/app/chat/right-rail/preview-console.tsx +44 -40
- package/agent/apps/desktop/src/app/chat/right-rail/preview-file.tsx +71 -25
- package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.test.tsx +40 -1
- package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.tsx +55 -53
- package/agent/apps/desktop/src/app/chat/right-rail/preview.tsx +35 -17
- package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
- package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.tsx +74 -0
- package/agent/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx +356 -0
- package/agent/apps/desktop/src/app/chat/sidebar/index.tsx +1189 -364
- package/agent/apps/desktop/src/app/chat/sidebar/load-more-row.tsx +30 -0
- package/agent/apps/desktop/src/app/chat/sidebar/order.test.ts +21 -0
- package/agent/apps/desktop/src/app/chat/sidebar/order.ts +17 -0
- package/agent/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx +524 -0
- package/agent/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx +80 -45
- package/agent/apps/desktop/src/app/chat/sidebar/session-row.tsx +120 -25
- package/agent/apps/desktop/src/app/chat/sidebar/virtual-session-list.tsx +7 -13
- package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
- package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.ts +326 -0
- package/agent/apps/desktop/src/app/chat/thread-loading.ts +7 -2
- package/agent/apps/desktop/src/app/command-center/index.tsx +320 -581
- package/agent/apps/desktop/src/app/command-palette/index.tsx +681 -0
- package/agent/apps/desktop/src/app/command-palette/marketplace-theme-page.tsx +157 -0
- package/agent/apps/desktop/src/app/cron/index.tsx +392 -324
- package/agent/apps/desktop/src/app/cron/job-state.ts +29 -0
- package/agent/apps/desktop/src/app/desktop-controller.tsx +618 -123
- package/agent/apps/desktop/src/app/floating-hud.ts +22 -0
- package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
- package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts +260 -14
- package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-request.ts +48 -4
- package/agent/apps/desktop/src/app/hooks/use-keybinds.ts +270 -0
- package/agent/apps/desktop/src/app/hooks/use-refresh-hotkey.ts +45 -0
- package/agent/apps/desktop/src/app/layout-constants.ts +19 -0
- package/agent/apps/desktop/src/app/messaging/index.tsx +136 -241
- package/agent/apps/desktop/src/app/messaging/platform-icon.tsx +95 -0
- package/agent/apps/desktop/src/app/model-visibility-overlay.tsx +31 -0
- package/agent/apps/desktop/src/app/overlays/overlay-search-input.tsx +18 -62
- package/agent/apps/desktop/src/app/overlays/overlay-split-layout.tsx +59 -7
- package/agent/apps/desktop/src/app/overlays/overlay-view.tsx +9 -5
- package/agent/apps/desktop/src/app/page-search-shell.tsx +42 -20
- package/agent/apps/desktop/src/app/profiles/create-profile-dialog.tsx +165 -0
- package/agent/apps/desktop/src/app/profiles/delete-profile-dialog.tsx +65 -0
- package/agent/apps/desktop/src/app/profiles/index.tsx +174 -199
- package/agent/apps/desktop/src/app/profiles/rename-profile-dialog.tsx +125 -0
- package/agent/apps/desktop/src/app/right-sidebar/files/dnd-manager.ts +27 -0
- package/agent/apps/desktop/src/app/right-sidebar/files/ipc.test.ts +100 -0
- package/agent/apps/desktop/src/app/right-sidebar/files/ipc.ts +12 -18
- package/agent/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx +177 -0
- package/agent/apps/desktop/src/app/right-sidebar/files/tree.tsx +35 -21
- package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.test.ts +75 -3
- package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.ts +152 -5
- package/agent/apps/desktop/src/app/right-sidebar/index.test.tsx +75 -0
- package/agent/apps/desktop/src/app/right-sidebar/index.tsx +166 -129
- package/agent/apps/desktop/src/app/right-sidebar/store.ts +19 -4
- package/agent/apps/desktop/src/app/right-sidebar/terminal/buffer.ts +65 -0
- package/agent/apps/desktop/src/app/right-sidebar/terminal/index.tsx +29 -34
- package/agent/apps/desktop/src/app/right-sidebar/terminal/persistent.tsx +18 -6
- package/agent/apps/desktop/src/app/right-sidebar/terminal/selection.ts +93 -32
- package/agent/apps/desktop/src/app/right-sidebar/terminal/use-terminal-session.ts +381 -119
- package/agent/apps/desktop/src/app/routes.ts +9 -0
- package/agent/apps/desktop/src/app/session/hooks/use-cwd-actions.ts +17 -7
- package/agent/apps/desktop/src/app/session/hooks/use-message-stream.ts +365 -47
- package/agent/apps/desktop/src/app/session/hooks/use-model-controls.test.tsx +198 -0
- package/agent/apps/desktop/src/app/session/hooks/use-model-controls.ts +70 -34
- package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx +1061 -0
- package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.ts +1143 -165
- package/agent/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx +341 -2
- package/agent/apps/desktop/src/app/session/hooks/use-route-resume.ts +176 -5
- package/agent/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx +259 -0
- package/agent/apps/desktop/src/app/session/hooks/use-session-actions.ts +452 -149
- package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.test.tsx +327 -0
- package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.ts +133 -4
- package/agent/apps/desktop/src/app/session-picker-overlay.tsx +32 -0
- package/agent/apps/desktop/src/app/session-switcher.tsx +107 -0
- package/agent/apps/desktop/src/app/settings/about-settings.tsx +45 -36
- package/agent/apps/desktop/src/app/settings/appearance-settings.tsx +243 -162
- package/agent/apps/desktop/src/app/settings/config-settings.tsx +86 -66
- package/agent/apps/desktop/src/app/settings/constants.ts +459 -122
- package/agent/apps/desktop/src/app/settings/credential-key-ui.tsx +373 -0
- package/agent/apps/desktop/src/app/settings/env-credentials.tsx +198 -0
- package/agent/apps/desktop/src/app/settings/env-var-actions-menu.tsx +136 -0
- package/agent/apps/desktop/src/app/settings/field-copy.ts +56 -0
- package/agent/apps/desktop/src/app/settings/gateway-settings.tsx +385 -72
- package/agent/apps/desktop/src/app/settings/helpers.test.ts +156 -1
- package/agent/apps/desktop/src/app/settings/helpers.ts +30 -2
- package/agent/apps/desktop/src/app/settings/index.tsx +118 -84
- package/agent/apps/desktop/src/app/settings/keys-settings.tsx +62 -419
- package/agent/apps/desktop/src/app/settings/mcp-settings.tsx +65 -60
- package/agent/apps/desktop/src/app/settings/model-settings.test.tsx +129 -5
- package/agent/apps/desktop/src/app/settings/model-settings.tsx +370 -65
- package/agent/apps/desktop/src/app/settings/notifications-settings.tsx +150 -0
- package/agent/apps/desktop/src/app/settings/primitives.tsx +5 -11
- package/agent/apps/desktop/src/app/settings/provider-config-panel.test.tsx +142 -0
- package/agent/apps/desktop/src/app/settings/provider-config-panel.tsx +182 -0
- package/agent/apps/desktop/src/app/settings/providers-settings.test.tsx +171 -0
- package/agent/apps/desktop/src/app/settings/providers-settings.tsx +471 -0
- package/agent/apps/desktop/src/app/settings/sessions-settings.tsx +183 -71
- package/agent/apps/desktop/src/app/settings/toolset-config-panel.test.tsx +135 -1
- package/agent/apps/desktop/src/app/settings/toolset-config-panel.tsx +180 -57
- package/agent/apps/desktop/src/app/settings/types.ts +9 -6
- package/agent/apps/desktop/src/app/settings/uninstall-section.tsx +185 -0
- package/agent/apps/desktop/src/app/settings/use-deep-link-highlight.ts +60 -0
- package/agent/apps/desktop/src/app/shell/app-shell.tsx +59 -13
- package/agent/apps/desktop/src/app/shell/gateway-menu-panel.tsx +37 -32
- package/agent/apps/desktop/src/app/shell/hooks/use-overlay-routing.ts +6 -3
- package/agent/apps/desktop/src/app/shell/hooks/use-statusbar-items.tsx +212 -53
- package/agent/apps/desktop/src/app/shell/keybind-panel.tsx +215 -0
- package/agent/apps/desktop/src/app/shell/model-edit-submenu.test.tsx +84 -0
- package/agent/apps/desktop/src/app/shell/model-edit-submenu.tsx +244 -0
- package/agent/apps/desktop/src/app/shell/model-menu-panel.tsx +392 -0
- package/agent/apps/desktop/src/app/shell/statusbar-controls.tsx +23 -33
- package/agent/apps/desktop/src/app/shell/titlebar-controls.tsx +79 -95
- package/agent/apps/desktop/src/app/shell/titlebar.ts +8 -2
- package/agent/apps/desktop/src/app/skills/index.test.tsx +11 -0
- package/agent/apps/desktop/src/app/skills/index.tsx +79 -64
- package/agent/apps/desktop/src/app/types.ts +85 -0
- package/agent/apps/desktop/src/app/updates-overlay.tsx +110 -105
- package/agent/apps/desktop/src/components/assistant-ui/ansi-text.tsx +34 -0
- package/agent/apps/desktop/src/components/assistant-ui/block-direction.test.tsx +129 -0
- package/agent/apps/desktop/src/components/assistant-ui/clarify-tool.tsx +102 -81
- package/agent/apps/desktop/src/components/assistant-ui/directive-text.tsx +92 -15
- package/agent/apps/desktop/src/components/assistant-ui/markdown-text.test.ts +38 -0
- package/agent/apps/desktop/src/components/assistant-ui/markdown-text.tsx +304 -45
- package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
- package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.tsx +48 -0
- package/agent/apps/desktop/src/components/assistant-ui/streaming.test.tsx +142 -90
- package/agent/apps/desktop/src/components/assistant-ui/thread-list.tsx +337 -0
- package/agent/apps/desktop/src/components/assistant-ui/thread.tsx +667 -190
- package/agent/apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx +299 -0
- package/agent/apps/desktop/src/components/assistant-ui/tool-approval.test.tsx +133 -0
- package/agent/apps/desktop/src/components/assistant-ui/tool-approval.tsx +239 -0
- package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts +31 -0
- package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.ts +152 -134
- package/agent/apps/desktop/src/components/assistant-ui/tool-fallback.tsx +142 -150
- package/agent/apps/desktop/src/components/assistant-ui/tooltip-icon-button.tsx +14 -12
- package/agent/apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
- package/agent/apps/desktop/src/components/assistant-ui/user-message-text.tsx +152 -0
- package/agent/apps/desktop/src/components/boot-failure-overlay.tsx +150 -33
- package/agent/apps/desktop/src/components/boot-failure-reauth.test.ts +100 -0
- package/agent/apps/desktop/src/components/boot-failure-reauth.ts +81 -0
- package/agent/apps/desktop/src/components/brand-mark.tsx +19 -0
- package/agent/apps/desktop/src/components/chat/code-card.tsx +1 -1
- package/agent/apps/desktop/src/components/chat/composer-dock.ts +31 -0
- package/agent/apps/desktop/src/components/chat/diff-lines.tsx +1 -1
- package/agent/apps/desktop/src/components/chat/disclosure-row.tsx +13 -3
- package/agent/apps/desktop/src/components/chat/expandable-block.tsx +52 -0
- package/agent/apps/desktop/src/components/chat/generated-image-result.tsx +174 -0
- package/agent/apps/desktop/src/components/chat/image-generation-placeholder.tsx +70 -37
- package/agent/apps/desktop/src/components/chat/intro.tsx +8 -7
- package/agent/apps/desktop/src/components/chat/preview-attachment.tsx +4 -2
- package/agent/apps/desktop/src/components/chat/shiki-highlighter.test.ts +37 -0
- package/agent/apps/desktop/src/components/chat/shiki-highlighter.tsx +96 -22
- package/agent/apps/desktop/src/components/chat/status-row.tsx +70 -0
- package/agent/apps/desktop/src/components/chat/status-section.tsx +42 -0
- package/agent/apps/desktop/src/components/chat/terminal-output.tsx +54 -0
- package/agent/apps/desktop/src/components/chat/zoomable-image.tsx +70 -109
- package/agent/apps/desktop/src/components/desktop-install-overlay.tsx +154 -84
- package/agent/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx +38 -8
- package/agent/apps/desktop/src/components/desktop-onboarding-overlay.tsx +789 -233
- package/agent/apps/desktop/src/components/error-boundary.tsx +77 -0
- package/agent/apps/desktop/src/components/gateway-connecting-overlay.test.tsx +144 -0
- package/agent/apps/desktop/src/components/gateway-connecting-overlay.tsx +7 -1
- package/agent/apps/desktop/src/components/haptics-provider.tsx +24 -0
- package/agent/apps/desktop/src/components/language-switcher.test.tsx +53 -0
- package/agent/apps/desktop/src/components/language-switcher.tsx +175 -0
- package/agent/apps/desktop/src/components/model-picker.tsx +42 -40
- package/agent/apps/desktop/src/components/model-visibility-dialog.tsx +166 -0
- package/agent/apps/desktop/src/components/notifications.tsx +48 -27
- package/agent/apps/desktop/src/components/pane-shell/index.ts +1 -1
- package/agent/apps/desktop/src/components/pane-shell/pane-shell.tsx +146 -9
- package/agent/apps/desktop/src/components/prompt-overlays.tsx +234 -0
- package/agent/apps/desktop/src/components/session-picker.tsx +108 -0
- package/agent/apps/desktop/src/components/ui/action-status.tsx +25 -0
- package/agent/apps/desktop/src/components/ui/badge.tsx +35 -0
- package/agent/apps/desktop/src/components/ui/button.tsx +37 -13
- package/agent/apps/desktop/src/components/ui/confirm-dialog.tsx +109 -0
- package/agent/apps/desktop/src/components/ui/control.ts +25 -0
- package/agent/apps/desktop/src/components/ui/copy-button.test.tsx +36 -0
- package/agent/apps/desktop/src/components/ui/copy-button.tsx +38 -27
- package/agent/apps/desktop/src/components/ui/dialog.tsx +39 -11
- package/agent/apps/desktop/src/components/ui/dropdown-menu.tsx +98 -24
- package/agent/apps/desktop/src/components/ui/error-state.tsx +50 -0
- package/agent/apps/desktop/src/components/ui/fade-text.tsx +9 -2
- package/agent/apps/desktop/src/components/ui/{braille-spinner.tsx → glyph-spinner.tsx} +15 -13
- package/agent/apps/desktop/src/components/ui/input.tsx +5 -2
- package/agent/apps/desktop/src/components/ui/kbd.tsx +83 -12
- package/agent/apps/desktop/src/components/ui/log-view.tsx +19 -0
- package/agent/apps/desktop/src/components/ui/pagination.tsx +12 -5
- package/agent/apps/desktop/src/components/ui/popover.tsx +44 -0
- package/agent/apps/desktop/src/components/ui/search-field.tsx +80 -0
- package/agent/apps/desktop/src/components/ui/segmented-control.tsx +51 -0
- package/agent/apps/desktop/src/components/ui/select.tsx +10 -3
- package/agent/apps/desktop/src/components/ui/sheet.tsx +8 -2
- package/agent/apps/desktop/src/components/ui/sidebar.tsx +18 -25
- package/agent/apps/desktop/src/components/ui/switch.tsx +38 -15
- package/agent/apps/desktop/src/components/ui/textarea.tsx +4 -11
- package/agent/apps/desktop/src/components/ui/tool-icon.tsx +65 -0
- package/agent/apps/desktop/src/components/ui/tooltip.tsx +31 -4
- package/agent/apps/desktop/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
- package/agent/apps/desktop/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
- package/agent/apps/desktop/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
- package/agent/apps/desktop/src/global.d.ts +181 -4
- package/agent/apps/desktop/src/hermes.test.ts +60 -0
- package/agent/apps/desktop/src/hermes.ts +190 -13
- package/agent/apps/desktop/src/hooks/use-image-download.ts +85 -0
- package/agent/apps/desktop/src/hooks/use-resize-observer.ts +13 -4
- package/agent/apps/desktop/src/hooks/use-worktree-info.ts +68 -0
- package/agent/apps/desktop/src/i18n/catalog.ts +12 -0
- package/agent/apps/desktop/src/i18n/context.test.tsx +232 -0
- package/agent/apps/desktop/src/i18n/context.tsx +183 -0
- package/agent/apps/desktop/src/i18n/define-locale.ts +41 -0
- package/agent/apps/desktop/src/i18n/en.ts +1921 -0
- package/agent/apps/desktop/src/i18n/index.ts +20 -0
- package/agent/apps/desktop/src/i18n/ja.ts +2053 -0
- package/agent/apps/desktop/src/i18n/languages.test.ts +43 -0
- package/agent/apps/desktop/src/i18n/languages.ts +86 -0
- package/agent/apps/desktop/src/i18n/runtime.test.ts +75 -0
- package/agent/apps/desktop/src/i18n/runtime.ts +53 -0
- package/agent/apps/desktop/src/i18n/types.ts +1559 -0
- package/agent/apps/desktop/src/i18n/zh-hant.ts +1992 -0
- package/agent/apps/desktop/src/i18n/zh.ts +2099 -0
- package/agent/apps/desktop/src/lib/ansi.test.ts +123 -0
- package/agent/apps/desktop/src/lib/ansi.ts +186 -0
- package/agent/apps/desktop/src/lib/chat-messages.test.ts +79 -0
- package/agent/apps/desktop/src/lib/chat-messages.ts +68 -29
- package/agent/apps/desktop/src/lib/chat-runtime.test.ts +65 -1
- package/agent/apps/desktop/src/lib/chat-runtime.ts +39 -3
- package/agent/apps/desktop/src/lib/completion-sound.ts +519 -0
- package/agent/apps/desktop/src/lib/desktop-fs.test.ts +116 -0
- package/agent/apps/desktop/src/lib/desktop-fs.ts +113 -0
- package/agent/apps/desktop/src/lib/desktop-slash-commands.test.ts +89 -6
- package/agent/apps/desktop/src/lib/desktop-slash-commands.ts +270 -131
- package/agent/apps/desktop/src/lib/external-link.test.tsx +27 -0
- package/agent/apps/desktop/src/lib/external-link.tsx +9 -2
- package/agent/apps/desktop/src/lib/gateway-events.test.ts +27 -0
- package/agent/apps/desktop/src/lib/gateway-events.ts +16 -0
- package/agent/apps/desktop/src/lib/gateway-ws-url.test.ts +78 -0
- package/agent/apps/desktop/src/lib/gateway-ws-url.ts +91 -0
- package/agent/apps/desktop/src/lib/generated-images.test.ts +97 -0
- package/agent/apps/desktop/src/lib/generated-images.ts +116 -0
- package/agent/apps/desktop/src/lib/haptics.ts +17 -0
- package/agent/apps/desktop/src/lib/icons.ts +10 -2
- package/agent/apps/desktop/src/lib/keybinds/actions.ts +137 -0
- package/agent/apps/desktop/src/lib/keybinds/combo.test.ts +86 -0
- package/agent/apps/desktop/src/lib/keybinds/combo.ts +195 -0
- package/agent/apps/desktop/src/lib/local-preview.ts +23 -2
- package/agent/apps/desktop/src/lib/markdown-preprocess.ts +20 -7
- package/agent/apps/desktop/src/lib/media.remote.test.ts +90 -0
- package/agent/apps/desktop/src/lib/media.ts +40 -1
- package/agent/apps/desktop/src/lib/model-status-label.test.ts +59 -0
- package/agent/apps/desktop/src/lib/model-status-label.ts +122 -0
- package/agent/apps/desktop/src/lib/mutable-ref.ts +6 -0
- package/agent/apps/desktop/src/lib/profile-color.ts +58 -0
- package/agent/apps/desktop/src/lib/query-client.ts +13 -0
- package/agent/apps/desktop/src/lib/remend-tail.test.ts +105 -0
- package/agent/apps/desktop/src/lib/remend-tail.ts +108 -0
- package/agent/apps/desktop/src/lib/session-export.ts +6 -3
- package/agent/apps/desktop/src/lib/session-ids.test.ts +44 -0
- package/agent/apps/desktop/src/lib/session-ids.ts +26 -0
- package/agent/apps/desktop/src/lib/session-search.test.ts +66 -0
- package/agent/apps/desktop/src/lib/session-search.ts +21 -0
- package/agent/apps/desktop/src/lib/session-source.ts +126 -0
- package/agent/apps/desktop/src/lib/storage.test.ts +25 -0
- package/agent/apps/desktop/src/lib/storage.ts +35 -1
- package/agent/apps/desktop/src/lib/todos.test.ts +46 -1
- package/agent/apps/desktop/src/lib/todos.ts +37 -0
- package/agent/apps/desktop/src/lib/tool-result-summary.ts +5 -1
- package/agent/apps/desktop/src/lib/update-copy.test.ts +38 -0
- package/agent/apps/desktop/src/lib/update-copy.ts +44 -0
- package/agent/apps/desktop/src/lib/use-enter-animation.ts +2 -2
- package/agent/apps/desktop/src/lib/yolo-session.ts +50 -0
- package/agent/apps/desktop/src/main.tsx +19 -19
- package/agent/apps/desktop/src/store/boot.ts +4 -3
- package/agent/apps/desktop/src/store/clarify.test.ts +81 -0
- package/agent/apps/desktop/src/store/clarify.ts +50 -13
- package/agent/apps/desktop/src/store/command-palette.ts +20 -0
- package/agent/apps/desktop/src/store/compaction.test.ts +53 -0
- package/agent/apps/desktop/src/store/compaction.ts +38 -0
- package/agent/apps/desktop/src/store/completion-sound.ts +32 -0
- package/agent/apps/desktop/src/store/composer-input-history.test.ts +147 -0
- package/agent/apps/desktop/src/store/composer-input-history.ts +158 -0
- package/agent/apps/desktop/src/store/composer-queue.test.ts +68 -0
- package/agent/apps/desktop/src/store/composer-queue.ts +76 -0
- package/agent/apps/desktop/src/store/composer-status.test.ts +99 -0
- package/agent/apps/desktop/src/store/composer-status.ts +277 -0
- package/agent/apps/desktop/src/store/composer.test.ts +106 -0
- package/agent/apps/desktop/src/store/composer.ts +116 -0
- package/agent/apps/desktop/src/store/cron.ts +19 -0
- package/agent/apps/desktop/src/store/gateway.ts +280 -6
- package/agent/apps/desktop/src/store/keybinds.ts +143 -0
- package/agent/apps/desktop/src/store/layout.ts +107 -9
- package/agent/apps/desktop/src/store/model-presets.test.ts +51 -0
- package/agent/apps/desktop/src/store/model-presets.ts +86 -0
- package/agent/apps/desktop/src/store/model-visibility.test.ts +99 -0
- package/agent/apps/desktop/src/store/model-visibility.ts +161 -0
- package/agent/apps/desktop/src/store/native-notifications.test.ts +192 -0
- package/agent/apps/desktop/src/store/native-notifications.ts +203 -0
- package/agent/apps/desktop/src/store/notifications.ts +10 -7
- package/agent/apps/desktop/src/store/onboarding.test.ts +271 -1
- package/agent/apps/desktop/src/store/onboarding.ts +268 -38
- package/agent/apps/desktop/src/store/preview.ts +10 -1
- package/agent/apps/desktop/src/store/profile.test.ts +89 -0
- package/agent/apps/desktop/src/store/profile.ts +395 -0
- package/agent/apps/desktop/src/store/prompts.test.ts +127 -0
- package/agent/apps/desktop/src/store/prompts.ts +117 -0
- package/agent/apps/desktop/src/store/session-switcher.test.ts +115 -0
- package/agent/apps/desktop/src/store/session-switcher.ts +128 -0
- package/agent/apps/desktop/src/store/session-sync.ts +25 -0
- package/agent/apps/desktop/src/store/session.test.ts +268 -2
- package/agent/apps/desktop/src/store/session.ts +392 -18
- package/agent/apps/desktop/src/store/subagents.ts +3 -0
- package/agent/apps/desktop/src/store/system-actions.ts +48 -0
- package/agent/apps/desktop/src/store/thread-scroll.ts +58 -5
- package/agent/apps/desktop/src/store/todos.test.ts +47 -0
- package/agent/apps/desktop/src/store/todos.ts +64 -0
- package/agent/apps/desktop/src/store/tool-dismiss.ts +45 -0
- package/agent/apps/desktop/src/store/translucency.ts +38 -0
- package/agent/apps/desktop/src/store/updates.test.ts +187 -2
- package/agent/apps/desktop/src/store/updates.ts +268 -18
- package/agent/apps/desktop/src/store/windows.test.ts +143 -0
- package/agent/apps/desktop/src/store/windows.ts +115 -0
- package/agent/apps/desktop/src/styles.css +510 -119
- package/agent/apps/desktop/src/themes/color.ts +142 -0
- package/agent/apps/desktop/src/themes/context.tsx +128 -75
- package/agent/apps/desktop/src/themes/install.test.ts +119 -0
- package/agent/apps/desktop/src/themes/install.ts +95 -0
- package/agent/apps/desktop/src/themes/presets.test.ts +33 -0
- package/agent/apps/desktop/src/themes/presets.ts +13 -4
- package/agent/apps/desktop/src/themes/profile-theme.test.ts +41 -0
- package/agent/apps/desktop/src/themes/types.ts +35 -0
- package/agent/apps/desktop/src/themes/user-themes.test.ts +63 -0
- package/agent/apps/desktop/src/themes/user-themes.ts +122 -0
- package/agent/apps/desktop/src/themes/vscode.test.ts +171 -0
- package/agent/apps/desktop/src/themes/vscode.ts +343 -0
- package/agent/apps/desktop/src/types/hermes.ts +138 -1
- package/agent/apps/desktop/tsconfig.json +2 -2
- package/agent/apps/desktop/vite.config.ts +18 -0
- package/agent/apps/shared/package.json +1 -1
- package/agent/apps/shared/src/json-rpc-gateway.ts +63 -2
- package/agent/apps/shared/tsconfig.json +2 -2
- package/agent/cli-config.yaml.example +78 -1
- package/agent/cli.py +2177 -3162
- package/agent/cron/blueprint_catalog.py +713 -0
- package/agent/cron/jobs.py +226 -110
- package/agent/cron/scheduler.py +468 -193
- package/agent/cron/scheduler_provider.py +177 -0
- package/agent/cron/scripts/__init__.py +1 -0
- package/agent/cron/scripts/classify_items.py +226 -0
- package/agent/cron/suggestion_catalog.py +154 -0
- package/agent/cron/suggestions.py +257 -0
- package/agent/docs/chronos-managed-cron-contract.md +196 -0
- package/agent/docs/design/profile-builder.md +146 -0
- package/agent/docs/middleware/README.md +260 -0
- package/agent/docs/observability/README.md +316 -0
- package/agent/docs/plans/2026-06-09-003-fix-telegram-stream-overflow-continuations-plan.md +240 -0
- package/agent/docs/rca-ssl-cacert-post-git-pull.md +54 -0
- package/agent/docs/relay-connector-contract.md +285 -0
- package/agent/gateway/authz_mixin.py +536 -0
- package/agent/gateway/channel_directory.py +65 -3
- package/agent/gateway/config.py +222 -12
- package/agent/gateway/display_config.py +10 -0
- package/agent/gateway/hooks.py +17 -0
- package/agent/gateway/kanban_watchers.py +1146 -0
- package/agent/gateway/message_timestamps.py +166 -0
- package/agent/gateway/platforms/ADDING_A_PLATFORM.md +29 -0
- package/agent/gateway/platforms/api_server.py +216 -38
- package/agent/gateway/platforms/base.py +210 -58
- package/agent/gateway/platforms/email.py +122 -12
- package/agent/gateway/platforms/feishu.py +80 -11
- package/agent/gateway/platforms/feishu_meeting_invite.py +212 -0
- package/agent/gateway/platforms/matrix.py +1498 -297
- package/agent/gateway/platforms/qqbot/adapter.py +6 -0
- package/agent/gateway/platforms/signal.py +8 -0
- package/agent/gateway/platforms/slack.py +308 -12
- package/agent/gateway/platforms/telegram.py +831 -24
- package/agent/gateway/platforms/webhook.py +109 -21
- package/agent/gateway/platforms/weixin.py +113 -2
- package/agent/gateway/platforms/whatsapp.py +94 -288
- package/agent/gateway/platforms/whatsapp_cloud.py +1956 -0
- package/agent/gateway/platforms/whatsapp_common.py +367 -0
- package/agent/gateway/platforms/yuanbao.py +608 -191
- package/agent/gateway/platforms/yuanbao_proto.py +232 -23
- package/agent/gateway/relay/__init__.py +375 -0
- package/agent/gateway/relay/adapter.py +222 -0
- package/agent/gateway/relay/auth.py +168 -0
- package/agent/gateway/relay/descriptor.py +118 -0
- package/agent/gateway/relay/transport.py +101 -0
- package/agent/gateway/relay/ws_transport.py +327 -0
- package/agent/gateway/response_filters.py +53 -0
- package/agent/gateway/rich_sent_store.py +80 -0
- package/agent/gateway/run.py +2940 -5001
- package/agent/gateway/session.py +109 -8
- package/agent/gateway/session_context.py +22 -4
- package/agent/gateway/slash_commands.py +3854 -0
- package/agent/gateway/status.py +141 -21
- package/agent/gateway/stream_consumer.py +288 -31
- package/agent/hermes-already-has-routines.md +1 -1
- package/agent/hermes_cli/__init__.py +62 -17
- package/agent/hermes_cli/_parser.py +30 -0
- package/agent/hermes_cli/_subprocess_compat.py +61 -0
- package/agent/hermes_cli/active_sessions.py +320 -0
- package/agent/hermes_cli/auth.py +707 -59
- package/agent/hermes_cli/auth_commands.py +39 -22
- package/agent/hermes_cli/backup.py +109 -7
- package/agent/hermes_cli/banner.py +88 -0
- package/agent/hermes_cli/blueprint_cmd.py +318 -0
- package/agent/hermes_cli/cli_agent_setup_mixin.py +684 -0
- package/agent/hermes_cli/cli_commands_mixin.py +2293 -0
- package/agent/hermes_cli/commands.py +215 -91
- package/agent/hermes_cli/config.py +967 -130
- package/agent/hermes_cli/container_boot.py +76 -11
- package/agent/hermes_cli/cron.py +5 -11
- package/agent/hermes_cli/curator.py +21 -0
- package/agent/hermes_cli/dashboard_auth/__init__.py +2 -0
- package/agent/hermes_cli/dashboard_auth/base.py +62 -0
- package/agent/hermes_cli/dashboard_auth/cookies.py +32 -19
- package/agent/hermes_cli/dashboard_auth/login_page.py +156 -6
- package/agent/hermes_cli/dashboard_auth/middleware.py +28 -4
- package/agent/hermes_cli/dashboard_auth/prefix.py +46 -2
- package/agent/hermes_cli/dashboard_auth/public_paths.py +6 -0
- package/agent/hermes_cli/dashboard_auth/routes.py +158 -2
- package/agent/hermes_cli/dashboard_auth/ws_tickets.py +85 -11
- package/agent/hermes_cli/dashboard_register.py +427 -0
- package/agent/hermes_cli/debug.py +155 -50
- package/agent/hermes_cli/doctor.py +255 -14
- package/agent/hermes_cli/dump.py +60 -6
- package/agent/hermes_cli/env_loader.py +33 -0
- package/agent/hermes_cli/gateway.py +755 -103
- package/agent/hermes_cli/gateway_enroll.py +250 -0
- package/agent/hermes_cli/gateway_windows.py +254 -11
- package/agent/hermes_cli/gui_uninstall.py +285 -0
- package/agent/hermes_cli/inventory.py +105 -4
- package/agent/hermes_cli/kanban.py +58 -71
- package/agent/hermes_cli/kanban_db.py +391 -14
- package/agent/hermes_cli/kanban_decompose.py +2 -2
- package/agent/hermes_cli/kanban_specify.py +3 -1
- package/agent/hermes_cli/logs.py +2 -0
- package/agent/hermes_cli/main.py +2889 -5287
- package/agent/hermes_cli/managed_scope.py +214 -0
- package/agent/hermes_cli/managed_uv.py +254 -0
- package/agent/hermes_cli/mcp_catalog.py +6 -3
- package/agent/hermes_cli/mcp_config.py +145 -21
- package/agent/hermes_cli/mcp_security.py +96 -0
- package/agent/hermes_cli/mcp_startup.py +32 -3
- package/agent/hermes_cli/memory_providers.py +149 -0
- package/agent/hermes_cli/memory_setup.py +97 -42
- package/agent/hermes_cli/middleware.py +313 -0
- package/agent/hermes_cli/model_catalog.py +31 -0
- package/agent/hermes_cli/model_cost_guard.py +134 -0
- package/agent/hermes_cli/model_normalize.py +2 -1
- package/agent/hermes_cli/model_setup_flows.py +2759 -0
- package/agent/hermes_cli/model_switch.py +242 -27
- package/agent/hermes_cli/models.py +284 -44
- package/agent/hermes_cli/nous_account.py +33 -6
- package/agent/hermes_cli/nous_billing.py +406 -0
- package/agent/hermes_cli/nous_subscription.py +202 -5
- package/agent/hermes_cli/platforms.py +1 -0
- package/agent/hermes_cli/plugins.py +218 -18
- package/agent/hermes_cli/plugins_cmd.py +249 -105
- package/agent/hermes_cli/portal_cli.py +56 -16
- package/agent/hermes_cli/profile_distribution.py +6 -1
- package/agent/hermes_cli/profiles.py +283 -32
- package/agent/hermes_cli/provider_catalog.py +170 -0
- package/agent/hermes_cli/providers.py +4 -1
- package/agent/hermes_cli/pty_bridge.py +53 -4
- package/agent/hermes_cli/runtime_provider.py +216 -34
- package/agent/hermes_cli/secret_prompt.py +4 -4
- package/agent/hermes_cli/secrets_cli.py +24 -0
- package/agent/hermes_cli/send_cmd.py +28 -2
- package/agent/hermes_cli/service_manager.py +166 -19
- package/agent/hermes_cli/session_listing.py +97 -0
- package/agent/hermes_cli/setup.py +158 -94
- package/agent/hermes_cli/setup_whatsapp_cloud.py +541 -0
- package/agent/hermes_cli/skills_config.py +8 -2
- package/agent/hermes_cli/skills_hub.py +149 -7
- package/agent/hermes_cli/status.py +2 -2
- package/agent/hermes_cli/subcommands/__init__.py +18 -0
- package/agent/hermes_cli/subcommands/_shared.py +29 -0
- package/agent/hermes_cli/subcommands/acp.py +52 -0
- package/agent/hermes_cli/subcommands/auth.py +109 -0
- package/agent/hermes_cli/subcommands/backup.py +38 -0
- package/agent/hermes_cli/subcommands/claw.py +92 -0
- package/agent/hermes_cli/subcommands/config.py +49 -0
- package/agent/hermes_cli/subcommands/cron.py +163 -0
- package/agent/hermes_cli/subcommands/dashboard.py +143 -0
- package/agent/hermes_cli/subcommands/debug.py +77 -0
- package/agent/hermes_cli/subcommands/doctor.py +35 -0
- package/agent/hermes_cli/subcommands/dump.py +28 -0
- package/agent/hermes_cli/subcommands/gateway.py +332 -0
- package/agent/hermes_cli/subcommands/gui.py +63 -0
- package/agent/hermes_cli/subcommands/hooks.py +77 -0
- package/agent/hermes_cli/subcommands/import_cmd.py +31 -0
- package/agent/hermes_cli/subcommands/insights.py +25 -0
- package/agent/hermes_cli/subcommands/login.py +78 -0
- package/agent/hermes_cli/subcommands/logout.py +28 -0
- package/agent/hermes_cli/subcommands/logs.py +78 -0
- package/agent/hermes_cli/subcommands/mcp.py +108 -0
- package/agent/hermes_cli/subcommands/memory.py +53 -0
- package/agent/hermes_cli/subcommands/model.py +72 -0
- package/agent/hermes_cli/subcommands/pairing.py +36 -0
- package/agent/hermes_cli/subcommands/plugins.py +94 -0
- package/agent/hermes_cli/subcommands/postinstall.py +23 -0
- package/agent/hermes_cli/subcommands/profile.py +203 -0
- package/agent/hermes_cli/subcommands/prompt_size.py +36 -0
- package/agent/hermes_cli/subcommands/security.py +62 -0
- package/agent/hermes_cli/subcommands/setup.py +58 -0
- package/agent/hermes_cli/subcommands/skills.py +298 -0
- package/agent/hermes_cli/subcommands/slack.py +60 -0
- package/agent/hermes_cli/subcommands/status.py +28 -0
- package/agent/hermes_cli/subcommands/tools.py +95 -0
- package/agent/hermes_cli/subcommands/uninstall.py +41 -0
- package/agent/hermes_cli/subcommands/update.py +70 -0
- package/agent/hermes_cli/subcommands/version.py +18 -0
- package/agent/hermes_cli/subcommands/webhook.py +76 -0
- package/agent/hermes_cli/subcommands/whatsapp.py +22 -0
- package/agent/hermes_cli/suggestions_cmd.py +153 -0
- package/agent/hermes_cli/telegram_managed_bot.py +358 -0
- package/agent/hermes_cli/tips.py +3 -4
- package/agent/hermes_cli/tools_config.py +155 -28
- package/agent/hermes_cli/uninstall.py +231 -35
- package/agent/hermes_cli/web_server.py +6188 -975
- package/agent/hermes_cli/win_pty_bridge.py +179 -0
- package/agent/hermes_cli/write_approval_commands.py +209 -0
- package/agent/hermes_constants.py +164 -33
- package/agent/hermes_logging.py +74 -2
- package/agent/hermes_state.py +919 -106
- package/agent/hermes_time.py +20 -0
- package/agent/locales/af.yaml +23 -0
- package/agent/locales/de.yaml +23 -0
- package/agent/locales/en.yaml +20 -0
- package/agent/locales/es.yaml +23 -0
- package/agent/locales/fr.yaml +23 -0
- package/agent/locales/ga.yaml +23 -0
- package/agent/locales/hu.yaml +23 -0
- package/agent/locales/it.yaml +23 -0
- package/agent/locales/ja.yaml +23 -0
- package/agent/locales/ko.yaml +23 -0
- package/agent/locales/pt.yaml +23 -0
- package/agent/locales/ru.yaml +23 -0
- package/agent/locales/tr.yaml +23 -0
- package/agent/locales/uk.yaml +23 -0
- package/agent/locales/zh-hant.yaml +23 -0
- package/agent/locales/zh.yaml +23 -0
- package/agent/model_tools.py +204 -40
- package/agent/optional-mcps/clawpump/manifest.yaml +4 -2
- package/agent/optional-mcps/clawpump-stdio/manifest.yaml +2 -0
- package/agent/optional-mcps/unreal-engine/manifest.yaml +54 -0
- package/agent/optional-skills/blockchain/hyperliquid/SKILL.md +2 -2
- package/agent/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1 -1
- package/agent/optional-skills/creative/kanban-video-orchestrator/SKILL.md +1 -1
- package/agent/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +4 -3
- package/agent/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +6 -4
- package/agent/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +2 -2
- package/agent/{skills/software-development → optional-skills/devops}/hermes-s6-container-supervision/SKILL.md +2 -0
- package/agent/optional-skills/devops/watchers/SKILL.md +1 -1
- package/agent/optional-skills/devops/watchers/scripts/watch_github.py +2 -1
- package/agent/optional-skills/payments/mpp-agent/SKILL.md +124 -0
- package/agent/optional-skills/payments/stripe-link-cli/SKILL.md +184 -0
- package/agent/optional-skills/payments/stripe-projects/SKILL.md +120 -0
- package/agent/optional-skills/productivity/canvas/SKILL.md +1 -1
- package/agent/optional-skills/productivity/canvas/scripts/canvas_api.py +4 -1
- package/agent/optional-skills/productivity/shop/SKILL.md +224 -0
- package/agent/optional-skills/productivity/shop/references/catalog-mcp.md +236 -0
- package/agent/optional-skills/productivity/shop/references/direct-api.md +278 -0
- package/agent/optional-skills/productivity/shop/references/legal.md +3 -0
- package/agent/optional-skills/productivity/shop/references/safety.md +36 -0
- package/agent/optional-skills/productivity/shopify/SKILL.md +1 -1
- package/agent/optional-skills/productivity/siyuan/SKILL.md +1 -1
- package/agent/optional-skills/productivity/telephony/SKILL.md +4 -4
- package/agent/optional-skills/productivity/telephony/scripts/telephony.py +15 -15
- package/agent/optional-skills/security/1password/SKILL.md +1 -1
- package/agent/{skills/red-teaming → optional-skills/security}/godmode/SKILL.md +3 -4
- package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/auto_jailbreak.py +3 -1
- package/agent/optional-skills/software-development/rest-graphql-debug/SKILL.md +1 -1
- package/agent/{skills → optional-skills}/software-development/subagent-driven-development/SKILL.md +5 -5
- package/agent/package-lock.json +4082 -7907
- package/agent/package.json +18 -3
- package/agent/plugins/browser/firecrawl/provider.py +4 -1
- package/agent/plugins/cron/__init__.py +344 -0
- package/agent/plugins/cron/chronos/__init__.py +241 -0
- package/agent/plugins/cron/chronos/_nas_client.py +123 -0
- package/agent/plugins/cron/chronos/plugin.yaml +9 -0
- package/agent/plugins/cron/chronos/verify.py +103 -0
- package/agent/plugins/dashboard_auth/basic/__init__.py +491 -0
- package/agent/plugins/dashboard_auth/basic/plugin.yaml +7 -0
- package/agent/plugins/dashboard_auth/nous/__init__.py +12 -14
- package/agent/plugins/dashboard_auth/self_hosted/__init__.py +736 -0
- package/agent/plugins/dashboard_auth/self_hosted/plugin.yaml +8 -0
- package/agent/plugins/disk-cleanup/disk_cleanup.py +100 -20
- package/agent/plugins/google_meet/audio_bridge.py +4 -0
- package/agent/plugins/google_meet/meet_bot.py +7 -1
- package/agent/plugins/hermes-achievements/dashboard/dist/index.js +9 -15
- package/agent/plugins/image_gen/fal/__init__.py +35 -6
- package/agent/plugins/image_gen/krea/__init__.py +56 -13
- package/agent/plugins/image_gen/openai/__init__.py +122 -24
- package/agent/plugins/image_gen/openai-codex/__init__.py +28 -2
- package/agent/plugins/image_gen/xai/__init__.py +92 -12
- package/agent/plugins/kanban/dashboard/dist/index.js +63 -48
- package/agent/plugins/kanban/dashboard/plugin_api.py +39 -35
- package/agent/plugins/memory/__init__.py +48 -5
- package/agent/plugins/memory/byterover/__init__.py +1 -0
- package/agent/plugins/memory/hindsight/README.md +1 -1
- package/agent/plugins/memory/hindsight/__init__.py +138 -24
- package/agent/plugins/memory/hindsight/plugin.yaml +1 -1
- package/agent/plugins/memory/honcho/README.md +13 -10
- package/agent/plugins/memory/honcho/cli.py +247 -122
- package/agent/plugins/memory/honcho/client.py +112 -102
- package/agent/plugins/memory/openviking/README.md +12 -1
- package/agent/plugins/memory/openviking/__init__.py +2281 -107
- package/agent/plugins/memory/openviking/plugin.yaml +1 -2
- package/agent/plugins/memory/supermemory/README.md +22 -10
- package/agent/plugins/memory/supermemory/__init__.py +142 -37
- package/agent/plugins/memory/supermemory/plugin.yaml +1 -1
- package/agent/plugins/model-providers/anthropic/__init__.py +1 -0
- package/agent/plugins/model-providers/bedrock/__init__.py +1 -0
- package/agent/plugins/model-providers/copilot-acp/__init__.py +1 -0
- package/agent/plugins/model-providers/custom/__init__.py +8 -2
- package/agent/plugins/model-providers/kimi-coding/__init__.py +16 -7
- package/agent/plugins/model-providers/minimax/__init__.py +60 -8
- package/agent/plugins/model-providers/opencode-zen/__init__.py +12 -3
- package/agent/plugins/model-providers/openrouter/__init__.py +75 -4
- package/agent/plugins/model-providers/xiaomi/__init__.py +2 -0
- package/agent/plugins/model-providers/zai/__init__.py +1 -0
- package/agent/plugins/observability/langfuse/__init__.py +147 -14
- package/agent/plugins/observability/nemo_relay/README.md +559 -0
- package/agent/plugins/observability/nemo_relay/__init__.py +962 -0
- package/agent/plugins/observability/nemo_relay/plugin.yaml +20 -0
- package/agent/plugins/platforms/discord/adapter.py +932 -61
- package/agent/plugins/platforms/discord/voice_mixer.py +379 -0
- package/agent/plugins/platforms/google_chat/adapter.py +9 -3
- package/agent/plugins/platforms/google_chat/oauth.py +1 -1
- package/agent/plugins/platforms/homeassistant/__init__.py +3 -0
- package/agent/{gateway/platforms/homeassistant.py → plugins/platforms/homeassistant/adapter.py} +128 -0
- package/agent/plugins/platforms/homeassistant/plugin.yaml +22 -0
- package/agent/plugins/platforms/irc/adapter.py +4 -1
- package/agent/plugins/platforms/line/adapter.py +16 -1
- package/agent/plugins/platforms/mattermost/adapter.py +100 -24
- package/agent/plugins/platforms/photon/README.md +179 -0
- package/agent/plugins/platforms/photon/__init__.py +4 -0
- package/agent/plugins/platforms/photon/adapter.py +1586 -0
- package/agent/plugins/platforms/photon/auth.py +1046 -0
- package/agent/plugins/platforms/photon/cli.py +439 -0
- package/agent/plugins/platforms/photon/plugin.yaml +88 -0
- package/agent/plugins/platforms/photon/sidecar/README.md +52 -0
- package/agent/plugins/platforms/photon/sidecar/index.mjs +720 -0
- package/agent/plugins/platforms/photon/sidecar/package-lock.json +1730 -0
- package/agent/plugins/platforms/photon/sidecar/package.json +25 -0
- package/agent/plugins/platforms/photon/sidecar/patch-spectrum-mixed-attachments.mjs +155 -0
- package/agent/plugins/platforms/raft/__init__.py +3 -0
- package/agent/plugins/platforms/raft/adapter.py +774 -0
- package/agent/plugins/platforms/raft/plugin.yaml +19 -0
- package/agent/plugins/platforms/simplex/adapter.py +777 -220
- package/agent/plugins/platforms/simplex/plugin.yaml +21 -2
- package/agent/plugins/platforms/teams/adapter.py +175 -5
- package/agent/plugins/plugin_utils.py +135 -0
- package/agent/plugins/video_gen/fal/__init__.py +10 -3
- package/agent/plugins/web/searxng/provider.py +15 -2
- package/agent/plugins/web/xai/provider.py +2 -2
- package/agent/providers/base.py +22 -3
- package/agent/pyproject.toml +115 -21
- package/agent/run_agent.py +733 -39
- package/agent/scripts/build_skills_index.py +51 -19
- package/agent/scripts/check_subprocess_stdin.py +177 -0
- package/agent/scripts/contributor_audit.py +2 -0
- package/agent/scripts/docker_config_migrate.py +67 -0
- package/agent/scripts/install.cmd +3 -3
- package/agent/scripts/install.ps1 +580 -154
- package/agent/scripts/install.sh +402 -185
- package/agent/scripts/lib/node-bootstrap.sh +39 -4
- package/agent/scripts/release.py +183 -0
- package/agent/scripts/run_tests.sh +1 -0
- package/agent/scripts/run_tests_parallel.py +18 -23
- package/agent/scripts/whatsapp-bridge/bridge.js +25 -4
- package/agent/setup.py +59 -0
- package/agent/skills/autonomous-ai-agents/codex/SKILL.md +19 -0
- package/agent/skills/autonomous-ai-agents/hermes-agent/SKILL.md +10 -3
- package/agent/skills/{mcp/native-mcp/SKILL.md → autonomous-ai-agents/hermes-agent/references/native-mcp.md} +0 -13
- package/agent/skills/{devops/webhook-subscriptions/SKILL.md → autonomous-ai-agents/hermes-agent/references/webhooks.md} +1 -11
- package/agent/skills/clawpump/SKILL.md +3 -1
- package/agent/skills/devops/kanban-orchestrator/SKILL.md +1 -0
- package/agent/skills/devops/kanban-worker/SKILL.md +1 -0
- package/agent/skills/github/github-auth/SKILL.md +2 -2
- package/agent/skills/github/github-auth/scripts/gh-env.sh +2 -2
- package/agent/skills/github/github-code-review/SKILL.md +2 -2
- package/agent/skills/github/github-issues/SKILL.md +2 -2
- package/agent/skills/github/github-pr-workflow/SKILL.md +2 -2
- package/agent/skills/github/github-repo-management/SKILL.md +2 -2
- package/agent/skills/media/gif-search/SKILL.md +1 -1
- package/agent/skills/media/youtube-content/SKILL.md +10 -7
- package/agent/skills/media/youtube-content/scripts/fetch_transcript.py +3 -3
- package/agent/skills/note-taking/obsidian/SKILL.md +1 -1
- package/agent/skills/productivity/airtable/SKILL.md +2 -2
- package/agent/skills/productivity/google-workspace/scripts/setup.py +33 -7
- package/agent/skills/productivity/notion/SKILL.md +2 -2
- package/agent/skills/productivity/teams-meeting-pipeline/SKILL.md +1 -1
- package/agent/skills/research/llm-wiki/SKILL.md +1 -1
- package/agent/skills/social-media/xurl/SKILL.md +9 -0
- package/agent/skills/software-development/hermes-agent-skill-authoring/SKILL.md +1 -1
- package/agent/skills/software-development/plan/SKILL.md +285 -5
- package/agent/skills/software-development/requesting-code-review/SKILL.md +2 -2
- package/agent/skills/software-development/simplify-code/SKILL.md +212 -0
- package/agent/skills/software-development/spike/SKILL.md +2 -2
- package/agent/skills/software-development/systematic-debugging/SKILL.md +1 -1
- package/agent/skills/software-development/test-driven-development/SKILL.md +1 -1
- package/agent/tools/approval.py +302 -4
- package/agent/tools/async_delegation.py +386 -0
- package/agent/tools/blueprints.py +325 -0
- package/agent/tools/browser_cdp_tool.py +3 -3
- package/agent/tools/browser_tool.py +34 -6
- package/agent/tools/checkpoint_manager.py +31 -1
- package/agent/tools/clarify_tool.py +55 -5
- package/agent/tools/code_execution_tool.py +31 -14
- package/agent/tools/computer_use/cua_backend.py +81 -3
- package/agent/tools/computer_use/tool.py +79 -5
- package/agent/tools/computer_use/vision_routing.py +55 -3
- package/agent/tools/credential_files.py +31 -12
- package/agent/tools/cronjob_tools.py +30 -20
- package/agent/tools/delegate_tool.py +356 -31
- package/agent/tools/env_probe.py +1 -0
- package/agent/tools/environments/docker.py +163 -8
- package/agent/tools/environments/file_sync.py +2 -1
- package/agent/tools/environments/local.py +74 -23
- package/agent/tools/environments/singularity.py +4 -1
- package/agent/tools/environments/ssh.py +78 -11
- package/agent/tools/file_operations.py +277 -41
- package/agent/tools/file_tools.py +166 -28
- package/agent/tools/image_generation_tool.py +515 -29
- package/agent/tools/kanban_tools.py +99 -0
- package/agent/tools/lazy_deps.py +33 -2
- package/agent/tools/mcp_oauth.py +5 -5
- package/agent/tools/mcp_oauth_manager.py +7 -5
- package/agent/tools/mcp_tool.py +840 -33
- package/agent/tools/memory_tool.py +335 -38
- package/agent/tools/osv_check.py +15 -1
- package/agent/tools/process_registry.py +155 -11
- package/agent/tools/read_extract.py +248 -0
- package/agent/tools/read_terminal_tool.py +93 -0
- package/agent/tools/schema_sanitizer.py +38 -0
- package/agent/tools/send_message_tool.py +163 -49
- package/agent/tools/session_search_tool.py +189 -7
- package/agent/tools/skill_manager_tool.py +202 -3
- package/agent/tools/skill_usage.py +52 -4
- package/agent/tools/skills_hub.py +184 -44
- package/agent/tools/skills_sync.py +232 -5
- package/agent/tools/skills_tool.py +125 -11
- package/agent/tools/terminal_tool.py +148 -26
- package/agent/tools/tirith_security.py +2 -0
- package/agent/tools/todo_tool.py +32 -1
- package/agent/tools/transcription_tools.py +13 -5
- package/agent/tools/tts_tool.py +332 -38
- package/agent/tools/url_safety.py +52 -1
- package/agent/tools/vision_tools.py +124 -39
- package/agent/tools/voice_mode.py +4 -3
- package/agent/tools/web_tools.py +45 -15
- package/agent/tools/write_approval.py +493 -0
- package/agent/toolsets.py +34 -10
- package/agent/trajectory_compressor.py +81 -10
- package/agent/tui_gateway/entry.py +43 -6
- package/agent/tui_gateway/server.py +3335 -330
- package/agent/tui_gateway/slash_worker.py +61 -0
- package/agent/tui_gateway/ws.py +67 -9
- package/agent/ui-tui/eslint.config.mjs +0 -4
- package/agent/ui-tui/package.json +6 -6
- package/agent/ui-tui/packages/hermes-ink/package.json +1 -1
- package/agent/ui-tui/packages/hermes-ink/src/ink/app-mouse.test.ts +34 -1
- package/agent/ui-tui/packages/hermes-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
- package/agent/ui-tui/packages/hermes-ink/src/ink/components/App.tsx +35 -2
- package/agent/ui-tui/packages/hermes-ink/src/ink/events/input-event.ts +4 -11
- package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.test.ts +23 -57
- package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.ts +11 -135
- package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.test.ts +185 -0
- package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.ts +37 -3
- package/agent/ui-tui/packages/hermes-ink/src/utils/execFileNoThrow.ts +5 -5
- package/agent/ui-tui/src/__tests__/appChromeStatusRule.test.tsx +217 -0
- package/agent/ui-tui/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
- package/agent/ui-tui/src/__tests__/approvalAction.test.ts +11 -0
- package/agent/ui-tui/src/__tests__/billingCommand.test.ts +301 -0
- package/agent/ui-tui/src/__tests__/blockLayout.test.ts +122 -0
- package/agent/ui-tui/src/__tests__/brandingMcpCount.test.ts +111 -0
- package/agent/ui-tui/src/__tests__/completionApply.test.ts +51 -0
- package/agent/ui-tui/src/__tests__/createGatewayEventHandler.test.ts +487 -2
- package/agent/ui-tui/src/__tests__/createSlashHandler.test.ts +54 -0
- package/agent/ui-tui/src/__tests__/creditsCommand.test.ts +144 -0
- package/agent/ui-tui/src/__tests__/gatewayClient.test.ts +120 -99
- package/agent/ui-tui/src/__tests__/gracefulExit.test.ts +11 -0
- package/agent/ui-tui/src/__tests__/memoryMonitor.test.ts +102 -0
- package/agent/ui-tui/src/__tests__/paths.test.ts +41 -1
- package/agent/ui-tui/src/__tests__/terminalModes.test.ts +22 -0
- package/agent/ui-tui/src/__tests__/text.test.ts +23 -0
- package/agent/ui-tui/src/__tests__/textInputFastEcho.test.ts +37 -0
- package/agent/ui-tui/src/__tests__/turnControllerNotice.test.ts +43 -0
- package/agent/ui-tui/src/__tests__/useInputHandlers.test.ts +38 -1
- package/agent/ui-tui/src/__tests__/virtualHeights.test.ts +8 -0
- package/agent/ui-tui/src/app/createGatewayEventHandler.ts +102 -7
- package/agent/ui-tui/src/app/interfaces.ts +64 -1
- package/agent/ui-tui/src/app/overlayStore.ts +18 -2
- package/agent/ui-tui/src/app/slash/commands/billing.ts +332 -0
- package/agent/ui-tui/src/app/slash/commands/core.ts +31 -2
- package/agent/ui-tui/src/app/slash/commands/credits.ts +57 -0
- package/agent/ui-tui/src/app/slash/commands/ops.ts +28 -0
- package/agent/ui-tui/src/app/slash/commands/session.ts +32 -4
- package/agent/ui-tui/src/app/slash/registry.ts +4 -0
- package/agent/ui-tui/src/app/turnController.ts +145 -2
- package/agent/ui-tui/src/app/uiStore.ts +2 -0
- package/agent/ui-tui/src/app/useInputHandlers.ts +42 -4
- package/agent/ui-tui/src/app/useMainApp.ts +54 -8
- package/agent/ui-tui/src/app/useSessionLifecycle.ts +40 -31
- package/agent/ui-tui/src/app/useSubmission.ts +23 -31
- package/agent/ui-tui/src/components/appChrome.tsx +112 -5
- package/agent/ui-tui/src/components/appLayout.tsx +9 -0
- package/agent/ui-tui/src/components/appOverlays.tsx +25 -1
- package/agent/ui-tui/src/components/billingOverlay.tsx +684 -0
- package/agent/ui-tui/src/components/branding.tsx +15 -3
- package/agent/ui-tui/src/components/messageLine.tsx +25 -3
- package/agent/ui-tui/src/components/pluginsHub.tsx +238 -0
- package/agent/ui-tui/src/components/prompts.tsx +31 -17
- package/agent/ui-tui/src/components/streamingAssistant.tsx +63 -55
- package/agent/ui-tui/src/components/textInput.tsx +16 -0
- package/agent/ui-tui/src/config/env.ts +12 -0
- package/agent/ui-tui/src/config/limits.ts +13 -0
- package/agent/ui-tui/src/domain/blockLayout.ts +146 -0
- package/agent/ui-tui/src/domain/paths.ts +24 -0
- package/agent/ui-tui/src/domain/slash.ts +40 -0
- package/agent/ui-tui/src/entry.tsx +35 -4
- package/agent/ui-tui/src/gatewayClient.ts +22 -10
- package/agent/ui-tui/src/gatewayTypes.ts +130 -1
- package/agent/ui-tui/src/lib/gracefulExit.ts +24 -4
- package/agent/ui-tui/src/lib/memory.test.ts +162 -0
- package/agent/ui-tui/src/lib/memory.ts +60 -1
- package/agent/ui-tui/src/lib/memoryMonitor.ts +79 -4
- package/agent/ui-tui/src/lib/osc52.ts +1 -1
- package/agent/ui-tui/src/lib/text.test.ts +32 -1
- package/agent/ui-tui/src/lib/text.ts +29 -2
- package/agent/ui-tui/src/lib/virtualHeights.ts +13 -0
- package/agent/ui-tui/src/types.ts +5 -0
- package/agent/ui-tui/tsconfig.build.json +0 -1
- package/agent/ui-tui/tsconfig.json +2 -1
- package/agent/utils.py +66 -2
- package/agent/uv.lock +300 -684
- package/agent/web/index.html +2 -2
- package/agent/web/package.json +11 -6
- package/agent/web/public/claw-bg.webp +0 -0
- package/agent/web/public/claw-logo.webp +0 -0
- package/agent/web/src/App.tsx +138 -48
- package/agent/web/src/components/AutomationBlueprints.tsx +225 -0
- package/agent/web/src/components/Backdrop.tsx +15 -0
- package/agent/web/src/components/ChatSessionList.tsx +260 -0
- package/agent/web/src/components/ChatSidebar.tsx +262 -78
- package/agent/web/src/components/ConfirmDialog.tsx +122 -0
- package/agent/web/src/components/ModelPickerDialog.tsx +111 -16
- package/agent/web/src/components/ModelReloadConfirm.tsx +40 -0
- package/agent/web/src/components/ProfileScopeBanner.tsx +30 -0
- package/agent/web/src/components/ProfileSwitcher.tsx +67 -0
- package/agent/web/src/components/ReasoningPicker.tsx +167 -0
- package/agent/web/src/components/SkillEditorDialog.tsx +215 -0
- package/agent/web/src/components/ThemeSwitcher.tsx +119 -4
- package/agent/web/src/components/ToolsetConfigDrawer.tsx +457 -0
- package/agent/web/src/contexts/PageHeaderProvider.tsx +7 -4
- package/agent/web/src/contexts/ProfileProvider.tsx +137 -0
- package/agent/web/src/contexts/SystemActions.tsx +6 -8
- package/agent/web/src/contexts/profile-context.ts +19 -0
- package/agent/web/src/contexts/useProfileScope.ts +6 -0
- package/agent/web/src/i18n/af.ts +5 -4
- package/agent/web/src/i18n/de.ts +5 -4
- package/agent/web/src/i18n/en.ts +58 -4
- package/agent/web/src/i18n/es.ts +5 -3
- package/agent/web/src/i18n/fr.ts +5 -3
- package/agent/web/src/i18n/ga.ts +5 -4
- package/agent/web/src/i18n/hu.ts +5 -4
- package/agent/web/src/i18n/it.ts +5 -4
- package/agent/web/src/i18n/ja.ts +5 -4
- package/agent/web/src/i18n/ko.ts +5 -4
- package/agent/web/src/i18n/pt.ts +5 -3
- package/agent/web/src/i18n/ru.ts +5 -4
- package/agent/web/src/i18n/tr.ts +5 -4
- package/agent/web/src/i18n/types.ts +59 -1
- package/agent/web/src/i18n/uk.ts +5 -3
- package/agent/web/src/i18n/zh-hant.ts +5 -4
- package/agent/web/src/i18n/zh.ts +5 -4
- package/agent/web/src/index.css +2 -2
- package/agent/web/src/lib/api.ts +819 -52
- package/agent/web/src/lib/dashboard-flags.ts +16 -7
- package/agent/web/src/lib/reasoning-effort.test.ts +48 -0
- package/agent/web/src/lib/reasoning-effort.ts +36 -0
- package/agent/web/src/lib/session-refresh.test.ts +21 -0
- package/agent/web/src/lib/session-refresh.ts +26 -0
- package/agent/web/src/pages/ChannelsPage.tsx +529 -68
- package/agent/web/src/pages/ChatPage.tsx +249 -56
- package/agent/web/src/pages/ConfigPage.tsx +11 -1
- package/agent/web/src/pages/CronPage.tsx +219 -31
- package/agent/web/src/pages/EnvPage.tsx +25 -6
- package/agent/web/src/pages/FilesPage.tsx +525 -0
- package/agent/web/src/pages/McpPage.tsx +80 -3
- package/agent/web/src/pages/ModelsPage.tsx +97 -12
- package/agent/web/src/pages/PluginsPage.tsx +1 -1
- package/agent/web/src/pages/ProfileBuilderPage.tsx +611 -0
- package/agent/web/src/pages/ProfilesPage.tsx +1038 -172
- package/agent/web/src/pages/SessionsPage.tsx +144 -13
- package/agent/web/src/pages/SkillsPage.tsx +851 -70
- package/agent/web/src/pages/SystemPage.tsx +340 -4
- package/agent/web/src/pages/WalletPage.tsx +401 -0
- package/agent/web/src/pages/WebhooksPage.tsx +145 -15
- package/agent/web/src/pages/X402Page.tsx +207 -0
- package/agent/web/src/plugins/registry.ts +28 -11
- package/agent/web/src/plugins/sdk.d.ts +160 -0
- package/agent/web/src/themes/context.tsx +112 -5
- package/agent/web/src/themes/fonts.ts +167 -0
- package/agent/web/src/themes/index.ts +7 -0
- package/agent/web/tsconfig.app.json +0 -1
- package/agent/web/vite.config.ts +1 -8
- package/agent/web/vitest.config.ts +16 -0
- package/package.json +1 -1
- package/agent/apps/desktop/package-lock.json +0 -18363
- package/agent/apps/desktop/src/app/chat/composer/skin-slash-popover.tsx +0 -56
- package/agent/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx +0 -382
- package/agent/apps/desktop/src/components/assistant-ui/todo-tool.tsx +0 -109
- package/agent/apps/desktop/src/components/chat/generated-image-context.tsx +0 -19
- package/agent/optional-skills/productivity/shop-app/SKILL.md +0 -340
- package/agent/skills/autonomous-ai-agents/kanban-codex-lane/SKILL.md +0 -277
- package/agent/skills/autonomous-ai-agents/kanban-codex-lane/templates/pmb-codex-lane-prompt.md +0 -57
- package/agent/skills/diagramming/DESCRIPTION.md +0 -3
- package/agent/skills/domain/DESCRIPTION.md +0 -24
- package/agent/skills/gifs/DESCRIPTION.md +0 -3
- package/agent/skills/inference-sh/DESCRIPTION.md +0 -19
- package/agent/skills/mcp/DESCRIPTION.md +0 -3
- package/agent/skills/media/spotify/SKILL.md +0 -135
- package/agent/skills/mlops/training/DESCRIPTION.md +0 -3
- package/agent/skills/mlops/vector-databases/DESCRIPTION.md +0 -3
- package/agent/skills/productivity/linear/SKILL.md +0 -380
- package/agent/skills/productivity/linear/scripts/linear_api.py +0 -445
- package/agent/skills/software-development/debugging-hermes-tui-commands/SKILL.md +0 -152
- package/agent/skills/software-development/writing-plans/SKILL.md +0 -297
- package/agent/ui-tui/package-lock.json +0 -7449
- package/agent/ui-tui/packages/hermes-ink/package-lock.json +0 -1289
- package/agent/web/package-lock.json +0 -8887
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/PORT_NOTES.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/SKILL.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/prompts/system.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/macaron.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/mono-ink.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/neon.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/warm.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/prompt-construction.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/style-presets.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/blueprint.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/chalkboard.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/editorial.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/elegant.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/fantasy-animation.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat-doodle.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/ink-notes.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/intuition-machine.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/minimal.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/nature.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/notion.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/pixel-art.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/playful.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/retro.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/scientific.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/screen-print.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch-notes.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vector-illustration.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vintage.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/warm.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/watercolor.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/usage.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/workflow.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/PORT_NOTES.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/SKILL.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/analysis-framework.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/chalk.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ink-brush.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ligne-claire.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/manga.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/minimalist.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/realistic.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/auto-selection.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/base-prompt.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/character-template.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/cinematic.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/dense.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/four-panel.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/mixed.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/splash.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/standard.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/webtoon.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/ohmsha-guide.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/partial-workflows.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/concept-story.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/four-panel.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/ohmsha.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/shoujo.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/wuxia.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/storyboard-template.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/action.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/dramatic.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/energetic.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/neutral.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/romantic.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/vintage.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/warm.md +0 -0
- /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/workflow.md +0 -0
- /package/agent/{skills → optional-skills}/creative/creative-ideation/SKILL.md +0 -0
- /package/agent/{skills → optional-skills}/creative/creative-ideation/references/full-prompt-library.md +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/ATTRIBUTION.md +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/SKILL.md +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/references/palettes.md +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/__init__.py +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/palettes.py +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art.py +0 -0
- /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art_video.py +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/SKILL.md +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/analysis-modules.md +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/methods-guide.md +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/abliteration-config.yaml +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/analysis-study.yaml +0 -0
- /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/batch-abliteration.yaml +0 -0
- /package/agent/{skills → optional-skills}/mlops/research/DESCRIPTION.md +0 -0
- /package/agent/{skills → optional-skills}/mlops/research/dspy/SKILL.md +0 -0
- /package/agent/{skills → optional-skills}/mlops/research/dspy/references/examples.md +0 -0
- /package/agent/{skills → optional-skills}/mlops/research/dspy/references/modules.md +0 -0
- /package/agent/{skills → optional-skills}/mlops/research/dspy/references/optimizers.md +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/jailbreak-templates.md +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/refusal-detection.md +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/godmode_race.py +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/load_godmode.py +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/parseltongue.py +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill-subtle.json +0 -0
- /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill.json +0 -0
- /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/context-budget-discipline.md +0 -0
- /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/gates-taxonomy.md +0 -0
|
@@ -2,19 +2,27 @@ import type { MutableRefObject } from 'react'
|
|
|
2
2
|
import { useCallback, useRef } from 'react'
|
|
3
3
|
import type { NavigateFunction } from 'react-router-dom'
|
|
4
4
|
|
|
5
|
-
import { deleteSession, getSessionMessages, setSessionArchived } from '@/hermes'
|
|
5
|
+
import { deleteSession, getSession, getSessionMessages, setSessionArchived } from '@/hermes'
|
|
6
|
+
import { useI18n } from '@/i18n'
|
|
6
7
|
import { type ChatMessage, chatMessageText, preserveLocalAssistantErrors, toChatMessages } from '@/lib/chat-messages'
|
|
7
8
|
import { normalizePersonalityValue } from '@/lib/chat-runtime'
|
|
8
9
|
import { embeddedImageUrls, textWithoutEmbeddedImages } from '@/lib/embedded-images'
|
|
9
|
-
import {
|
|
10
|
+
import { setSessionYolo } from '@/lib/yolo-session'
|
|
10
11
|
import { clearQueuedPrompts } from '@/store/composer-queue'
|
|
11
12
|
import { $pinnedSessionIds } from '@/store/layout'
|
|
12
13
|
import { clearNotifications, notify, notifyError } from '@/store/notifications'
|
|
13
14
|
import { requestDesktopOnboarding } from '@/store/onboarding'
|
|
15
|
+
import { $activeGatewayProfile, $newChatProfile, $profiles, ensureGatewayProfile, normalizeProfileKey } from '@/store/profile'
|
|
14
16
|
import {
|
|
15
17
|
$currentCwd,
|
|
18
|
+
$currentFastMode,
|
|
19
|
+
$currentModel,
|
|
20
|
+
$currentProvider,
|
|
21
|
+
$currentReasoningEffort,
|
|
16
22
|
$messages,
|
|
17
23
|
$sessions,
|
|
24
|
+
$yoloActive,
|
|
25
|
+
sessionPinId,
|
|
18
26
|
setActiveSessionId,
|
|
19
27
|
setAwaitingResponse,
|
|
20
28
|
setBusy,
|
|
@@ -30,13 +38,20 @@ import {
|
|
|
30
38
|
setFreshDraftReady,
|
|
31
39
|
setIntroSeed,
|
|
32
40
|
setMessages,
|
|
41
|
+
setResumeExhaustedSessionId,
|
|
42
|
+
setResumeFailedSessionId,
|
|
33
43
|
setSelectedStoredSessionId,
|
|
34
44
|
setSessions,
|
|
35
45
|
setSessionStartedAt,
|
|
36
|
-
|
|
46
|
+
setSessionsTotal,
|
|
47
|
+
setTurnStartedAt,
|
|
48
|
+
setYoloActive,
|
|
49
|
+
workspaceCwdForNewSession
|
|
37
50
|
} from '@/store/session'
|
|
51
|
+
import { broadcastSessionsChanged } from '@/store/session-sync'
|
|
38
52
|
import { reportBackendContract } from '@/store/updates'
|
|
39
|
-
import
|
|
53
|
+
import { isWatchWindow } from '@/store/windows'
|
|
54
|
+
import type { SessionCreateResponse, SessionInfo, SessionResumeResponse, SessionRuntimeInfo, UsageStats } from '@/types/hermes'
|
|
40
55
|
|
|
41
56
|
import { NEW_CHAT_ROUTE, sessionRoute, SETTINGS_ROUTE } from '../../routes'
|
|
42
57
|
import type { ClientSessionState, SidebarNavItem } from '../../types'
|
|
@@ -167,6 +182,10 @@ function upsertOptimisticSession(
|
|
|
167
182
|
preview: string | null = null
|
|
168
183
|
) {
|
|
169
184
|
const now = Date.now() / 1000
|
|
185
|
+
// Stamp the profile the session was just created on (= the live gateway's
|
|
186
|
+
// profile) so the scoped sidebar shows the new row immediately instead of
|
|
187
|
+
// filtering it out as "default" until the aggregator re-fetches.
|
|
188
|
+
const profileKey = normalizeProfileKey($activeGatewayProfile.get())
|
|
170
189
|
|
|
171
190
|
const session: SessionInfo = {
|
|
172
191
|
cwd: created.info?.cwd ?? null,
|
|
@@ -174,11 +193,13 @@ function upsertOptimisticSession(
|
|
|
174
193
|
id,
|
|
175
194
|
input_tokens: 0,
|
|
176
195
|
is_active: true,
|
|
196
|
+
is_default_profile: profileKey === 'default',
|
|
177
197
|
last_active: now,
|
|
178
198
|
message_count: created.message_count ?? created.messages?.length ?? 0,
|
|
179
199
|
model: created.info?.model ?? null,
|
|
180
200
|
output_tokens: 0,
|
|
181
201
|
preview,
|
|
202
|
+
profile: profileKey,
|
|
182
203
|
source: 'tui',
|
|
183
204
|
started_at: now,
|
|
184
205
|
title,
|
|
@@ -196,14 +217,91 @@ function patchSessionWorkspace(sessionId: string, cwd: string | undefined) {
|
|
|
196
217
|
setSessions(prev => prev.map(session => (session.id === sessionId ? { ...session, cwd } : session)))
|
|
197
218
|
}
|
|
198
219
|
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
|
|
220
|
+
function sessionMatchesStoredId(session: SessionInfo, storedSessionId: string): boolean {
|
|
221
|
+
return session.id === storedSessionId || session._lineage_root_id === storedSessionId
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function upsertResolvedSession(session: SessionInfo, storedSessionId: string) {
|
|
225
|
+
const lineage = session._lineage_root_id ?? session.id
|
|
226
|
+
|
|
227
|
+
setSessions(prev => [
|
|
228
|
+
session,
|
|
229
|
+
...prev.filter(existing => {
|
|
230
|
+
if (sessionMatchesStoredId(existing, storedSessionId)) {
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return (existing._lineage_root_id ?? existing.id) !== lineage
|
|
235
|
+
})
|
|
236
|
+
])
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function resolveStoredSession(storedSessionId: string): Promise<SessionInfo | undefined> {
|
|
240
|
+
const cached = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId))
|
|
241
|
+
|
|
242
|
+
if (cached) {
|
|
243
|
+
return cached
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Direct by-id on the live backend — one row lookup, no list scan. Covers
|
|
247
|
+
// single-profile users and any id on the active profile (e.g. an old session
|
|
248
|
+
// past the sidebar's recent window). 404 just means it's not on this profile.
|
|
249
|
+
try {
|
|
250
|
+
const session = await getSession(storedSessionId)
|
|
251
|
+
|
|
252
|
+
upsertResolvedSession(session, storedSessionId)
|
|
253
|
+
|
|
254
|
+
return session
|
|
255
|
+
} catch {
|
|
256
|
+
// Not on the active profile — fall through to the cross-profile probe.
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Multi-profile only: probe each other profile by id (still one cheap lookup
|
|
260
|
+
// each) rather than pulling every profile's recent sessions. The first hit
|
|
261
|
+
// carries its owning `profile`, which routes the resume to the right backend.
|
|
262
|
+
const activeKey = normalizeProfileKey($activeGatewayProfile.get())
|
|
263
|
+
|
|
264
|
+
const otherProfiles = $profiles
|
|
265
|
+
.get()
|
|
266
|
+
.map(profile => normalizeProfileKey(profile.name))
|
|
267
|
+
.filter(key => key !== activeKey)
|
|
268
|
+
|
|
269
|
+
for (const profile of otherProfiles) {
|
|
270
|
+
try {
|
|
271
|
+
const session = await getSession(storedSessionId, profile)
|
|
272
|
+
|
|
273
|
+
upsertResolvedSession(session, storedSessionId)
|
|
274
|
+
|
|
275
|
+
return session
|
|
276
|
+
} catch {
|
|
277
|
+
// Not on this profile; try the next.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return undefined
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
type SessionRuntimeStatePatch = Partial<
|
|
285
|
+
Pick<
|
|
286
|
+
ClientSessionState,
|
|
287
|
+
| 'branch'
|
|
288
|
+
| 'cwd'
|
|
289
|
+
| 'fast'
|
|
290
|
+
| 'model'
|
|
291
|
+
| 'personality'
|
|
292
|
+
| 'provider'
|
|
293
|
+
| 'reasoningEffort'
|
|
294
|
+
| 'serviceTier'
|
|
295
|
+
| 'yolo'
|
|
296
|
+
>
|
|
297
|
+
>
|
|
298
|
+
|
|
299
|
+
function applyRuntimeInfo(info: SessionRuntimeInfo | undefined): SessionRuntimeStatePatch | null {
|
|
202
300
|
if (!info) {
|
|
203
301
|
return null
|
|
204
302
|
}
|
|
205
303
|
|
|
206
|
-
const sessionState:
|
|
304
|
+
const sessionState: SessionRuntimeStatePatch = {}
|
|
207
305
|
|
|
208
306
|
reportBackendContract(info.desktop_contract)
|
|
209
307
|
|
|
@@ -211,12 +309,14 @@ function applyRuntimeInfo(
|
|
|
211
309
|
requestDesktopOnboarding(info.credential_warning)
|
|
212
310
|
}
|
|
213
311
|
|
|
214
|
-
if (info.model) {
|
|
312
|
+
if (typeof info.model === 'string') {
|
|
215
313
|
setCurrentModel(info.model)
|
|
314
|
+
sessionState.model = info.model
|
|
216
315
|
}
|
|
217
316
|
|
|
218
|
-
if (info.provider) {
|
|
317
|
+
if (typeof info.provider === 'string') {
|
|
219
318
|
setCurrentProvider(info.provider)
|
|
319
|
+
sessionState.provider = info.provider
|
|
220
320
|
}
|
|
221
321
|
|
|
222
322
|
if (info.cwd) {
|
|
@@ -230,19 +330,29 @@ function applyRuntimeInfo(
|
|
|
230
330
|
}
|
|
231
331
|
|
|
232
332
|
if (typeof info.personality === 'string') {
|
|
233
|
-
|
|
333
|
+
const personality = normalizePersonalityValue(info.personality)
|
|
334
|
+
setCurrentPersonality(personality)
|
|
335
|
+
sessionState.personality = personality
|
|
234
336
|
}
|
|
235
337
|
|
|
236
338
|
if (typeof info.reasoning_effort === 'string') {
|
|
237
339
|
setCurrentReasoningEffort(info.reasoning_effort)
|
|
340
|
+
sessionState.reasoningEffort = info.reasoning_effort
|
|
238
341
|
}
|
|
239
342
|
|
|
240
343
|
if (typeof info.service_tier === 'string') {
|
|
241
344
|
setCurrentServiceTier(info.service_tier)
|
|
345
|
+
sessionState.serviceTier = info.service_tier
|
|
242
346
|
}
|
|
243
347
|
|
|
244
348
|
if (typeof info.fast === 'boolean') {
|
|
245
349
|
setCurrentFastMode(info.fast)
|
|
350
|
+
sessionState.fast = info.fast
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (typeof info.yolo === 'boolean') {
|
|
354
|
+
setYoloActive(info.yolo)
|
|
355
|
+
sessionState.yolo = info.yolo
|
|
246
356
|
}
|
|
247
357
|
|
|
248
358
|
if (info.usage) {
|
|
@@ -252,6 +362,16 @@ function applyRuntimeInfo(
|
|
|
252
362
|
return sessionState
|
|
253
363
|
}
|
|
254
364
|
|
|
365
|
+
function applyStoredSessionPreviewRuntimeInfo(stored: { model?: null | string } | undefined) {
|
|
366
|
+
setCurrentModel(stored?.model || '')
|
|
367
|
+
setCurrentProvider('')
|
|
368
|
+
setCurrentReasoningEffort('')
|
|
369
|
+
setCurrentServiceTier('')
|
|
370
|
+
setCurrentFastMode(false)
|
|
371
|
+
setYoloActive(false)
|
|
372
|
+
setCurrentPersonality('')
|
|
373
|
+
}
|
|
374
|
+
|
|
255
375
|
export function useSessionActions({
|
|
256
376
|
activeSessionId,
|
|
257
377
|
activeSessionIdRef,
|
|
@@ -268,6 +388,8 @@ export function useSessionActions({
|
|
|
268
388
|
syncSessionStateToView,
|
|
269
389
|
updateSessionState
|
|
270
390
|
}: SessionActionsOptions) {
|
|
391
|
+
const { t } = useI18n()
|
|
392
|
+
const copy = t.desktop
|
|
271
393
|
const resumeRequestRef = useRef(0)
|
|
272
394
|
|
|
273
395
|
const startFreshSessionDraft = useCallback(
|
|
@@ -291,72 +413,124 @@ export function useSessionActions({
|
|
|
291
413
|
})
|
|
292
414
|
setSessionStartedAt(null)
|
|
293
415
|
setTurnStartedAt(null)
|
|
294
|
-
|
|
416
|
+
// The composer's model/effort/fast is sticky UI state (persisted in
|
|
417
|
+
// localStorage) — a new chat FOLLOWS your last pick instead of snapping
|
|
418
|
+
// back to the profile default, so we deliberately don't reset it here. The
|
|
419
|
+
// profile default still owns first-run seeding and profile switches (see
|
|
420
|
+
// refreshCurrentModel). Only $currentServiceTier (a live-session mirror)
|
|
421
|
+
// is cleared.
|
|
422
|
+
setCurrentServiceTier('')
|
|
423
|
+
setYoloActive(false)
|
|
424
|
+
setCurrentCwd(workspaceCwdForNewSession())
|
|
295
425
|
setCurrentBranch('')
|
|
296
|
-
|
|
297
|
-
clearComposerAttachments()
|
|
426
|
+
// Never clear the composer here — ChatBar's per-thread draft swap owns it.
|
|
298
427
|
setFreshDraftReady(true)
|
|
299
428
|
},
|
|
300
429
|
[activeSessionIdRef, busyRef, navigate, selectedStoredSessionIdRef]
|
|
301
430
|
)
|
|
302
431
|
|
|
303
|
-
const createBackendSessionForSend = useCallback(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
432
|
+
const createBackendSessionForSend = useCallback(
|
|
433
|
+
async (preview: string | null = null): Promise<string | null> => {
|
|
434
|
+
const startingActiveSessionId = activeSessionIdRef.current
|
|
435
|
+
const startingStoredSessionId = selectedStoredSessionIdRef.current
|
|
436
|
+
const startingRouteToken = getRouteToken()
|
|
307
437
|
|
|
308
|
-
|
|
438
|
+
creatingSessionRef.current = true
|
|
309
439
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
await
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
440
|
+
try {
|
|
441
|
+
// A plain new session (top "New Session", /new, keybind) leaves
|
|
442
|
+
// $newChatProfile null to mean "use the live context"; the per-profile
|
|
443
|
+
// "+" sets it explicitly. Resolve null to the active gateway profile so
|
|
444
|
+
// session.create always carries it: in global-remote mode one backend
|
|
445
|
+
// serves every profile, so an omitted profile param silently lands the
|
|
446
|
+
// chat on the launch (default) profile — the "rubberbands back to
|
|
447
|
+
// default" bug. This is a no-op for single-profile/local-pooled users:
|
|
448
|
+
// a backend resolves its own launch profile to None (_profile_home).
|
|
449
|
+
const newChatProfile = $newChatProfile.get() ?? normalizeProfileKey($activeGatewayProfile.get())
|
|
450
|
+
await ensureGatewayProfile(newChatProfile)
|
|
451
|
+
const cwd = $currentCwd.get().trim() || workspaceCwdForNewSession()
|
|
452
|
+
// The composer's model/effort/fast is sticky UI state ($currentModel,
|
|
453
|
+
// $currentProvider, $currentReasoningEffort, $currentFastMode). Ship it
|
|
454
|
+
// with every session.create so the new chat opens on whatever the picker
|
|
455
|
+
// shows — applied as per-session overrides, never written to the profile
|
|
456
|
+
// default (that lives in Settings → Model).
|
|
457
|
+
const uiModel = $currentModel.get().trim()
|
|
458
|
+
const uiProvider = $currentProvider.get().trim()
|
|
459
|
+
const uiEffort = $currentReasoningEffort.get().trim()
|
|
460
|
+
const uiFast = $currentFastMode.get()
|
|
461
|
+
|
|
462
|
+
const created = await requestGateway<SessionCreateResponse>('session.create', {
|
|
463
|
+
cols: 96,
|
|
464
|
+
...(cwd && { cwd }),
|
|
465
|
+
...(newChatProfile ? { profile: newChatProfile } : {}),
|
|
466
|
+
...(uiModel ? { model: uiModel, ...(uiProvider ? { provider: uiProvider } : {}) } : {}),
|
|
467
|
+
...(uiEffort ? { reasoning_effort: uiEffort } : {}),
|
|
468
|
+
...(uiFast ? { fast: true } : {})
|
|
469
|
+
})
|
|
324
470
|
|
|
325
|
-
|
|
326
|
-
selectedStoredSessionIdRef.current = stored
|
|
327
|
-
ensureSessionState(created.session_id, stored)
|
|
471
|
+
const stored = created.stored_session_id ?? null
|
|
328
472
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
473
|
+
if (
|
|
474
|
+
activeSessionIdRef.current !== startingActiveSessionId ||
|
|
475
|
+
selectedStoredSessionIdRef.current !== startingStoredSessionId ||
|
|
476
|
+
getRouteToken() !== startingRouteToken
|
|
477
|
+
) {
|
|
478
|
+
await requestGateway('session.close', { session_id: created.session_id }).catch(() => undefined)
|
|
333
479
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
setSelectedStoredSessionId(stored)
|
|
337
|
-
setSessionStartedAt(Date.now())
|
|
338
|
-
const runtimeInfo = applyRuntimeInfo(created.info)
|
|
480
|
+
return null
|
|
481
|
+
}
|
|
339
482
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
483
|
+
activeSessionIdRef.current = created.session_id
|
|
484
|
+
selectedStoredSessionIdRef.current = stored
|
|
485
|
+
ensureSessionState(created.session_id, stored)
|
|
486
|
+
|
|
487
|
+
if (stored) {
|
|
488
|
+
// Seed the sidebar preview with the user's first message so the row
|
|
489
|
+
// reads meaningfully while the turn is in flight, instead of flashing
|
|
490
|
+
// "Untitled session" until the turn persists and auto-title runs. The
|
|
491
|
+
// server later returns its own preview/title and supersedes this.
|
|
492
|
+
upsertOptimisticSession(created, stored, null, preview?.trim() || null)
|
|
493
|
+
navigate(sessionRoute(stored), { replace: true })
|
|
494
|
+
// Other windows (e.g. the main window when this is the pop-out) can't
|
|
495
|
+
// see this session until they re-pull the shared list.
|
|
496
|
+
broadcastSessionsChanged()
|
|
497
|
+
}
|
|
343
498
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
499
|
+
setFreshDraftReady(false)
|
|
500
|
+
setActiveSessionId(created.session_id)
|
|
501
|
+
setSelectedStoredSessionId(stored)
|
|
502
|
+
setSessionStartedAt(Date.now())
|
|
503
|
+
const yoloArmed = $yoloActive.get()
|
|
504
|
+
const runtimeInfo = applyRuntimeInfo(created.info)
|
|
505
|
+
|
|
506
|
+
if (runtimeInfo) {
|
|
507
|
+
updateSessionState(created.session_id, state => ({ ...state, ...runtimeInfo }), stored)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// User may have armed YOLO on the new-chat draft before the runtime
|
|
511
|
+
// session existed — apply it to the freshly created session.
|
|
512
|
+
if (yoloArmed) {
|
|
513
|
+
await setSessionYolo(requestGateway, created.session_id, true).catch(() => undefined)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return created.session_id
|
|
517
|
+
} finally {
|
|
518
|
+
window.setTimeout(() => {
|
|
519
|
+
creatingSessionRef.current = false
|
|
520
|
+
}, 0)
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
[
|
|
524
|
+
activeSessionIdRef,
|
|
525
|
+
creatingSessionRef,
|
|
526
|
+
ensureSessionState,
|
|
527
|
+
getRouteToken,
|
|
528
|
+
navigate,
|
|
529
|
+
requestGateway,
|
|
530
|
+
selectedStoredSessionIdRef,
|
|
531
|
+
updateSessionState
|
|
532
|
+
]
|
|
533
|
+
)
|
|
360
534
|
|
|
361
535
|
const selectSidebarItem = useCallback(
|
|
362
536
|
(item: SidebarNavItem) => {
|
|
@@ -395,32 +569,103 @@ export function useSessionActions({
|
|
|
395
569
|
const isCurrentResume = () =>
|
|
396
570
|
resumeRequestRef.current === requestId && selectedStoredSessionIdRef.current === storedSessionId
|
|
397
571
|
|
|
572
|
+
// Paint the click before the profile-resolve / gateway-swap awaits below,
|
|
573
|
+
// so there's zero dead air: highlight the row instantly (the sidebar reads
|
|
574
|
+
// $selectedStoredSessionId) and, for a cold target, drop the previous
|
|
575
|
+
// transcript so the thread shows its loader instead of the old session
|
|
576
|
+
// lingering until resume lands. A warm-cached target keeps its transcript —
|
|
577
|
+
// the cached fast-path repaints it this same tick. Setting the ref here is
|
|
578
|
+
// also what use-route-resume's self-heal assumes ("set synchronously at
|
|
579
|
+
// resume entry").
|
|
580
|
+
setFreshDraftReady(false)
|
|
581
|
+
clearNotifications()
|
|
582
|
+
setSelectedStoredSessionId(storedSessionId)
|
|
583
|
+
selectedStoredSessionIdRef.current = storedSessionId
|
|
584
|
+
// Optimistically clear any prior resume-failure latch for this session:
|
|
585
|
+
// we're attempting a fresh resume, so the self-heal in use-route-resume
|
|
586
|
+
// must not keep treating it as stranded. It's re-armed below only if THIS
|
|
587
|
+
// attempt fails terminally (RPC reject + REST fallback failure).
|
|
588
|
+
setResumeFailedSessionId(current => (current === storedSessionId ? null : current))
|
|
589
|
+
// Also clear the exhausted-latch: a fresh attempt (manual Retry, reconnect,
|
|
590
|
+
// reselect) gives the bounded auto-retry counter a clean cycle, so the
|
|
591
|
+
// chat view drops the error state and shows the loader again.
|
|
592
|
+
setResumeExhaustedSessionId(current => (current === storedSessionId ? null : current))
|
|
593
|
+
|
|
594
|
+
const warmRuntimeId = runtimeIdByStoredSessionIdRef.current.get(storedSessionId)
|
|
595
|
+
|
|
596
|
+
if (!warmRuntimeId || !sessionStateByRuntimeIdRef.current.get(warmRuntimeId)) {
|
|
597
|
+
setActiveSessionId(null)
|
|
598
|
+
activeSessionIdRef.current = null
|
|
599
|
+
setMessages([])
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Swap the single live gateway to this session's profile before any
|
|
603
|
+
// gateway call (no-op when it's already on that profile / single-profile).
|
|
604
|
+
// resolveStoredSession finds the row by id (cheap), so an uncached pasted
|
|
605
|
+
// id loads as fast as a sidebar click instead of hanging on a list scan.
|
|
606
|
+
const storedForProfile = await resolveStoredSession(storedSessionId)
|
|
607
|
+
const sessionProfile = storedForProfile?.profile
|
|
608
|
+
|
|
609
|
+
if (resumeRequestRef.current !== requestId) {
|
|
610
|
+
return
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
await ensureGatewayProfile(sessionProfile)
|
|
614
|
+
|
|
398
615
|
const cachedRuntimeId = runtimeIdByStoredSessionIdRef.current.get(storedSessionId)
|
|
399
616
|
const cachedState = cachedRuntimeId && sessionStateByRuntimeIdRef.current.get(cachedRuntimeId)
|
|
400
617
|
|
|
401
618
|
if (cachedRuntimeId && cachedState) {
|
|
619
|
+
const stored = $sessions.get().find(session => session.id === storedSessionId)
|
|
620
|
+
|
|
621
|
+
const cachedViewState =
|
|
622
|
+
!cachedState.model && stored?.model != null
|
|
623
|
+
? {
|
|
624
|
+
...cachedState,
|
|
625
|
+
model: stored.model || ''
|
|
626
|
+
}
|
|
627
|
+
: cachedState
|
|
628
|
+
|
|
629
|
+
if (cachedViewState !== cachedState) {
|
|
630
|
+
sessionStateByRuntimeIdRef.current.set(cachedRuntimeId, cachedViewState)
|
|
631
|
+
}
|
|
632
|
+
|
|
402
633
|
setFreshDraftReady(false)
|
|
403
634
|
clearNotifications()
|
|
404
635
|
setSelectedStoredSessionId(storedSessionId)
|
|
405
636
|
selectedStoredSessionIdRef.current = storedSessionId
|
|
406
637
|
setActiveSessionId(cachedRuntimeId)
|
|
407
638
|
activeSessionIdRef.current = cachedRuntimeId
|
|
408
|
-
syncSessionStateToView(cachedRuntimeId,
|
|
409
|
-
setCurrentCwd(
|
|
410
|
-
setCurrentBranch(
|
|
639
|
+
syncSessionStateToView(cachedRuntimeId, cachedViewState)
|
|
640
|
+
setCurrentCwd(cachedViewState.cwd)
|
|
641
|
+
setCurrentBranch(cachedViewState.branch)
|
|
411
642
|
setSessionStartedAt(Date.now())
|
|
412
|
-
clearComposerDraft()
|
|
413
|
-
clearComposerAttachments()
|
|
414
643
|
|
|
415
|
-
|
|
416
|
-
.
|
|
417
|
-
if (isCurrentResume() && usage) {
|
|
418
|
-
setCurrentUsage(current => ({ ...current, ...usage }))
|
|
419
|
-
}
|
|
420
|
-
})
|
|
421
|
-
.catch(() => undefined)
|
|
644
|
+
try {
|
|
645
|
+
const usage = await requestGateway<UsageStats>('session.usage', { session_id: cachedRuntimeId })
|
|
422
646
|
|
|
423
|
-
|
|
647
|
+
if (!isCurrentResume()) {
|
|
648
|
+
return
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (usage) {
|
|
652
|
+
setCurrentUsage(current => ({ ...current, ...usage }))
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return
|
|
656
|
+
} catch {
|
|
657
|
+
// The cached runtime id was minted by a prior backend instance. A
|
|
658
|
+
// pooled profile backend that gets idle-reaped (pruneSecondaryGateways)
|
|
659
|
+
// and respawned across a profile swap mints fresh ids, so this mapping
|
|
660
|
+
// now 404s ("session not found"). Drop it and fall through to a full
|
|
661
|
+
// resume that rebinds a live runtime id.
|
|
662
|
+
if (!isCurrentResume()) {
|
|
663
|
+
return
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
runtimeIdByStoredSessionIdRef.current.delete(storedSessionId)
|
|
667
|
+
sessionStateByRuntimeIdRef.current.delete(cachedRuntimeId)
|
|
668
|
+
}
|
|
424
669
|
}
|
|
425
670
|
|
|
426
671
|
setFreshDraftReady(false)
|
|
@@ -433,7 +678,8 @@ export function useSessionActions({
|
|
|
433
678
|
setSelectedStoredSessionId(storedSessionId)
|
|
434
679
|
selectedStoredSessionIdRef.current = storedSessionId
|
|
435
680
|
setSessionStartedAt(Date.now())
|
|
436
|
-
const stored = $sessions.get().find(session => session
|
|
681
|
+
const stored = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId))
|
|
682
|
+
applyStoredSessionPreviewRuntimeInfo(stored)
|
|
437
683
|
|
|
438
684
|
if (stored) {
|
|
439
685
|
setCurrentUsage(current => ({
|
|
@@ -444,36 +690,46 @@ export function useSessionActions({
|
|
|
444
690
|
}))
|
|
445
691
|
}
|
|
446
692
|
|
|
693
|
+
let resumedRunning = false
|
|
694
|
+
|
|
447
695
|
try {
|
|
448
|
-
|
|
449
|
-
// Previously these raced:
|
|
450
|
-
// 1. clear messages to []
|
|
451
|
-
// 2. local getSessionMessages -> 45 msgs
|
|
452
|
-
// 3. a second resume path cleared [] again
|
|
453
|
-
// 4. gateway resume -> 43 msgs
|
|
454
|
-
// That is the ctrl+R flash chain. Avoid showing an empty thread
|
|
455
|
-
// while we already have a route-scoped session id, and don't race the
|
|
456
|
-
// local snapshot against gateway resume.
|
|
696
|
+
const watchWindow = isWatchWindow()
|
|
457
697
|
let localSnapshot = $messages.get()
|
|
458
698
|
|
|
699
|
+
// REST transcript prefetch and the gateway resume RPC are independent
|
|
700
|
+
// — run them concurrently so a big session's wall time is
|
|
701
|
+
// max(prefetch, resume) instead of their sum. The prefetch paints the
|
|
702
|
+
// transcript as soon as it lands; the RPC binds the runtime id.
|
|
703
|
+
// Watch windows skip the prefetch — lazy resume attaches the live mirror.
|
|
704
|
+
const prefetchPromise = watchWindow ? null : getSessionMessages(storedSessionId, sessionProfile)
|
|
705
|
+
|
|
706
|
+
const resumePromise = requestGateway<SessionResumeResponse>('session.resume', {
|
|
707
|
+
session_id: storedSessionId,
|
|
708
|
+
cols: 96,
|
|
709
|
+
...(watchWindow ? { lazy: true } : {}),
|
|
710
|
+
...(sessionProfile ? { profile: sessionProfile } : {})
|
|
711
|
+
})
|
|
712
|
+
// The rejection is consumed by the `await` below; this guard only
|
|
713
|
+
// keeps it from surfacing as unhandled while the prefetch settles.
|
|
714
|
+
resumePromise.catch(() => undefined)
|
|
715
|
+
|
|
459
716
|
try {
|
|
460
|
-
|
|
717
|
+
if (prefetchPromise) {
|
|
718
|
+
const storedMessages = await prefetchPromise
|
|
461
719
|
|
|
462
|
-
|
|
463
|
-
|
|
720
|
+
if (isCurrentResume()) {
|
|
721
|
+
localSnapshot = preserveLocalAssistantErrors(toChatMessages(storedMessages.messages), $messages.get())
|
|
464
722
|
|
|
465
|
-
|
|
466
|
-
|
|
723
|
+
if (!chatMessageArraysEquivalent($messages.get(), localSnapshot)) {
|
|
724
|
+
setMessages(localSnapshot)
|
|
725
|
+
}
|
|
467
726
|
}
|
|
468
727
|
}
|
|
469
728
|
} catch {
|
|
470
729
|
// Non-fatal: gateway resume below can still hydrate the session.
|
|
471
730
|
}
|
|
472
731
|
|
|
473
|
-
const resumed = await
|
|
474
|
-
session_id: storedSessionId,
|
|
475
|
-
cols: 96
|
|
476
|
-
})
|
|
732
|
+
const resumed = await resumePromise
|
|
477
733
|
|
|
478
734
|
if (!isCurrentResume()) {
|
|
479
735
|
return
|
|
@@ -481,25 +737,22 @@ export function useSessionActions({
|
|
|
481
737
|
|
|
482
738
|
const currentMessages = $messages.get()
|
|
483
739
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
//
|
|
489
|
-
// `getSessionMessages()` is the stable stored transcript snapshot and
|
|
490
|
-
// paints first; `session.resume` can return a slightly different
|
|
491
|
-
// runtime-shaped projection (e.g. tool/system coalescing), which was
|
|
492
|
-
// causing a second full message-list replacement a second later.
|
|
493
|
-
// Keep the already-painted local snapshot for the view/cache when it
|
|
494
|
-
// exists; use gateway messages only as a fallback when no local
|
|
495
|
-
// snapshot was available.
|
|
496
|
-
|
|
740
|
+
// Keep the local snapshot when resume would only reshuffle runtime
|
|
741
|
+
// projection. When the REST prefetch already hydrated the transcript,
|
|
742
|
+
// skip converting/reconciling the resume payload entirely — on a
|
|
743
|
+
// 1000+-message session that second conversion plus the deep
|
|
744
|
+
// equivalence compare costs over a second of main-thread time.
|
|
497
745
|
const preferredMessages =
|
|
498
746
|
localSnapshot.length > 0
|
|
499
747
|
? localSnapshot
|
|
500
|
-
:
|
|
501
|
-
|
|
502
|
-
|
|
748
|
+
: (() => {
|
|
749
|
+
const resumedMessages = preserveLocalAssistantErrors(
|
|
750
|
+
reconcileResumeMessages(toChatMessages(resumed.messages), currentMessages),
|
|
751
|
+
currentMessages
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
return chatMessageArraysEquivalent(currentMessages, resumedMessages) ? currentMessages : resumedMessages
|
|
755
|
+
})()
|
|
503
756
|
|
|
504
757
|
const messagesForView = preserveLocalAssistantErrors(preferredMessages, currentMessages)
|
|
505
758
|
|
|
@@ -509,43 +762,72 @@ export function useSessionActions({
|
|
|
509
762
|
|
|
510
763
|
patchSessionWorkspace(storedSessionId, runtimeInfo?.cwd)
|
|
511
764
|
|
|
765
|
+
resumedRunning = Boolean((resumed as { running?: boolean }).running)
|
|
766
|
+
|
|
512
767
|
updateSessionState(
|
|
513
768
|
resumed.session_id,
|
|
514
769
|
state => ({
|
|
515
770
|
...state,
|
|
516
771
|
...(runtimeInfo ?? {}),
|
|
517
772
|
messages: messagesForView,
|
|
518
|
-
busy:
|
|
519
|
-
awaitingResponse:
|
|
773
|
+
busy: resumedRunning,
|
|
774
|
+
awaitingResponse: resumedRunning
|
|
520
775
|
}),
|
|
521
776
|
storedSessionId
|
|
522
777
|
)
|
|
523
|
-
clearComposerDraft()
|
|
524
|
-
clearComposerAttachments()
|
|
525
778
|
} catch (err) {
|
|
526
779
|
if (!isCurrentResume()) {
|
|
527
780
|
return
|
|
528
781
|
}
|
|
529
782
|
|
|
530
|
-
|
|
783
|
+
// The gateway resume RPC failed. Try the REST transcript as a fallback
|
|
784
|
+
// so the window at least shows history. CRITICAL: this fallback must be
|
|
785
|
+
// wrapped in its own try — if it ALSO throws (wedged/unreachable backend,
|
|
786
|
+
// the common case when resume failed in the first place), an unguarded
|
|
787
|
+
// throw here skips setMessages AND leaves activeSessionId null with an
|
|
788
|
+
// empty transcript. That is the exact state the thread loader latches on
|
|
789
|
+
// forever (messagesEmpty && !activeSessionId) with no recovery path —
|
|
790
|
+
// the "open in new window stays stuck loading, even after a nap" bug.
|
|
791
|
+
try {
|
|
792
|
+
const fallback = await getSessionMessages(storedSessionId, sessionProfile)
|
|
793
|
+
|
|
794
|
+
if (!isCurrentResume()) {
|
|
795
|
+
return
|
|
796
|
+
}
|
|
531
797
|
|
|
532
|
-
|
|
533
|
-
|
|
798
|
+
setMessages(preserveLocalAssistantErrors(toChatMessages(fallback.messages), $messages.get()))
|
|
799
|
+
} catch {
|
|
800
|
+
// Fallback also failed: nothing to paint. Leave whatever messages are
|
|
801
|
+
// already shown and fall through to arm the resume-failure latch so
|
|
802
|
+
// use-route-resume re-attempts the resume on the next render / window
|
|
803
|
+
// focus / gateway reconnect instead of stranding the loader.
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (isCurrentResume() && $messages.get().length === 0) {
|
|
807
|
+
// Arm the self-heal ONLY when the window is still empty: the gateway
|
|
808
|
+
// resume rejected AND the REST fallback failed to paint a transcript.
|
|
809
|
+
// That is the exact stranded state the loader latches on
|
|
810
|
+
// (messagesEmpty && !activeSessionId), and matches $resumeFailedSessionId's
|
|
811
|
+
// documented contract. If the REST fallback DID paint history, the
|
|
812
|
+
// window is readable — arming here would needlessly auto-retry and,
|
|
813
|
+
// once retries exhaust, blank that visible transcript behind the
|
|
814
|
+
// exhausted-state error overlay (a regression vs. plain fallback success).
|
|
815
|
+
setResumeFailedSessionId(storedSessionId)
|
|
534
816
|
}
|
|
535
817
|
|
|
536
|
-
|
|
537
|
-
notifyError(err, 'Resume failed')
|
|
818
|
+
notifyError(err, copy.resumeFailed)
|
|
538
819
|
} finally {
|
|
539
820
|
if (isCurrentResume()) {
|
|
540
|
-
busyRef.current =
|
|
541
|
-
setBusy(
|
|
542
|
-
setAwaitingResponse(
|
|
821
|
+
busyRef.current = resumedRunning
|
|
822
|
+
setBusy(resumedRunning)
|
|
823
|
+
setAwaitingResponse(resumedRunning)
|
|
543
824
|
}
|
|
544
825
|
}
|
|
545
826
|
},
|
|
546
827
|
[
|
|
547
828
|
activeSessionIdRef,
|
|
548
829
|
busyRef,
|
|
830
|
+
copy,
|
|
549
831
|
requestGateway,
|
|
550
832
|
runtimeIdByStoredSessionIdRef,
|
|
551
833
|
selectedStoredSessionIdRef,
|
|
@@ -562,8 +844,8 @@ export function useSessionActions({
|
|
|
562
844
|
if (!sourceSessionId) {
|
|
563
845
|
notify({
|
|
564
846
|
kind: 'warning',
|
|
565
|
-
title:
|
|
566
|
-
message:
|
|
847
|
+
title: copy.nothingToBranch,
|
|
848
|
+
message: copy.branchNeedsChat
|
|
567
849
|
})
|
|
568
850
|
|
|
569
851
|
return false
|
|
@@ -572,8 +854,8 @@ export function useSessionActions({
|
|
|
572
854
|
if (busyRef.current) {
|
|
573
855
|
notify({
|
|
574
856
|
kind: 'warning',
|
|
575
|
-
title:
|
|
576
|
-
message:
|
|
857
|
+
title: copy.sessionBusy,
|
|
858
|
+
message: copy.branchStopCurrent
|
|
577
859
|
})
|
|
578
860
|
|
|
579
861
|
return false
|
|
@@ -603,8 +885,8 @@ export function useSessionActions({
|
|
|
603
885
|
if (!branchMessages.length) {
|
|
604
886
|
notify({
|
|
605
887
|
kind: 'warning',
|
|
606
|
-
title:
|
|
607
|
-
message:
|
|
888
|
+
title: copy.nothingToBranch,
|
|
889
|
+
message: copy.branchNoText
|
|
608
890
|
})
|
|
609
891
|
|
|
610
892
|
return false
|
|
@@ -618,14 +900,14 @@ export function useSessionActions({
|
|
|
618
900
|
cols: 96,
|
|
619
901
|
...(cwd && { cwd }),
|
|
620
902
|
messages: branchMessages.map(({ content, role }) => ({ content, role })),
|
|
621
|
-
title:
|
|
903
|
+
title: copy.branchTitle
|
|
622
904
|
})
|
|
623
905
|
|
|
624
906
|
const routedSessionId = branched.stored_session_id ?? branched.session_id
|
|
625
907
|
const preview = branchMessages.map(({ content }) => content).find(Boolean) ?? null
|
|
626
908
|
|
|
627
909
|
setFreshDraftReady(false)
|
|
628
|
-
upsertOptimisticSession(branched, routedSessionId,
|
|
910
|
+
upsertOptimisticSession(branched, routedSessionId, copy.branchTitle, preview)
|
|
629
911
|
ensureSessionState(branched.session_id, routedSessionId)
|
|
630
912
|
setActiveSessionId(branched.session_id)
|
|
631
913
|
activeSessionIdRef.current = branched.session_id
|
|
@@ -643,8 +925,6 @@ export function useSessionActions({
|
|
|
643
925
|
selectedStoredSessionIdRef.current = routedSessionId
|
|
644
926
|
navigate(sessionRoute(routedSessionId))
|
|
645
927
|
|
|
646
|
-
clearComposerDraft()
|
|
647
|
-
clearComposerAttachments()
|
|
648
928
|
const runtimeInfo = applyRuntimeInfo(branched.info)
|
|
649
929
|
|
|
650
930
|
patchSessionWorkspace(routedSessionId, runtimeInfo?.cwd)
|
|
@@ -655,7 +935,7 @@ export function useSessionActions({
|
|
|
655
935
|
|
|
656
936
|
return true
|
|
657
937
|
} catch (err) {
|
|
658
|
-
notifyError(err,
|
|
938
|
+
notifyError(err, copy.branchFailed)
|
|
659
939
|
|
|
660
940
|
return false
|
|
661
941
|
} finally {
|
|
@@ -667,6 +947,7 @@ export function useSessionActions({
|
|
|
667
947
|
[
|
|
668
948
|
activeSessionIdRef,
|
|
669
949
|
busyRef,
|
|
950
|
+
copy,
|
|
670
951
|
creatingSessionRef,
|
|
671
952
|
ensureSessionState,
|
|
672
953
|
navigate,
|
|
@@ -680,14 +961,20 @@ export function useSessionActions({
|
|
|
680
961
|
async (storedSessionId: string) => {
|
|
681
962
|
clearNotifications()
|
|
682
963
|
|
|
683
|
-
const removed = $sessions.get().find(
|
|
964
|
+
const removed = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId))
|
|
684
965
|
const wasSelected = selectedStoredSessionId === storedSessionId
|
|
685
966
|
const closingRuntimeId = wasSelected ? activeSessionId : null
|
|
686
967
|
const previousMessages = $messages.get()
|
|
687
968
|
const previousPinned = $pinnedSessionIds.get()
|
|
969
|
+
// Pins are keyed on the durable lineage-root id; the stored id may be the
|
|
970
|
+
// live tip after compression. Drop both so the pin can't linger.
|
|
971
|
+
const removedPinId = removed ? sessionPinId(removed) : storedSessionId
|
|
688
972
|
|
|
689
|
-
setSessions(prev => prev.filter(
|
|
690
|
-
$
|
|
973
|
+
setSessions(prev => prev.filter(session => !sessionMatchesStoredId(session, storedSessionId)))
|
|
974
|
+
// Keep $sessionsTotal in sync so the sidebar's "Load N more" footer
|
|
975
|
+
// doesn't keep claiming the removed row is still on the server.
|
|
976
|
+
setSessionsTotal(prev => Math.max(0, prev - 1))
|
|
977
|
+
$pinnedSessionIds.set(previousPinned.filter(id => id !== storedSessionId && id !== removedPinId))
|
|
691
978
|
|
|
692
979
|
// Tear down before awaiting so the route effect can't resume the
|
|
693
980
|
// doomed session via the stale /<sid> URL.
|
|
@@ -700,7 +987,7 @@ export function useSessionActions({
|
|
|
700
987
|
await requestGateway('session.close', { session_id: closingRuntimeId }).catch(() => undefined)
|
|
701
988
|
}
|
|
702
989
|
|
|
703
|
-
await deleteSession(storedSessionId)
|
|
990
|
+
await deleteSession(storedSessionId, removed?.profile)
|
|
704
991
|
clearQueuedPrompts(storedSessionId)
|
|
705
992
|
|
|
706
993
|
if (closingRuntimeId) {
|
|
@@ -709,6 +996,7 @@ export function useSessionActions({
|
|
|
709
996
|
} catch (err) {
|
|
710
997
|
if (removed) {
|
|
711
998
|
setSessions(prev => [removed, ...prev])
|
|
999
|
+
setSessionsTotal(prev => prev + 1)
|
|
712
1000
|
}
|
|
713
1001
|
|
|
714
1002
|
$pinnedSessionIds.set(previousPinned)
|
|
@@ -717,7 +1005,7 @@ export function useSessionActions({
|
|
|
717
1005
|
setFreshDraftReady(false)
|
|
718
1006
|
setSelectedStoredSessionId(storedSessionId)
|
|
719
1007
|
selectedStoredSessionIdRef.current = storedSessionId
|
|
720
|
-
const stored = $sessions.get().find(session => session
|
|
1008
|
+
const stored = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId))
|
|
721
1009
|
|
|
722
1010
|
if (stored) {
|
|
723
1011
|
setCurrentUsage(current => ({
|
|
@@ -737,12 +1025,13 @@ export function useSessionActions({
|
|
|
737
1025
|
}
|
|
738
1026
|
}
|
|
739
1027
|
|
|
740
|
-
notifyError(err,
|
|
1028
|
+
notifyError(err, copy.deleteFailed)
|
|
741
1029
|
}
|
|
742
1030
|
},
|
|
743
1031
|
[
|
|
744
1032
|
activeSessionId,
|
|
745
1033
|
activeSessionIdRef,
|
|
1034
|
+
copy,
|
|
746
1035
|
navigate,
|
|
747
1036
|
requestGateway,
|
|
748
1037
|
selectedStoredSessionId,
|
|
@@ -755,31 +1044,45 @@ export function useSessionActions({
|
|
|
755
1044
|
async (storedSessionId: string) => {
|
|
756
1045
|
clearNotifications()
|
|
757
1046
|
|
|
758
|
-
const archived = $sessions.get().find(
|
|
1047
|
+
const archived = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId))
|
|
759
1048
|
const wasSelected = selectedStoredSessionId === storedSessionId
|
|
760
1049
|
const previousPinned = $pinnedSessionIds.get()
|
|
1050
|
+
// Pins are keyed on the durable lineage-root id; the stored id may be the
|
|
1051
|
+
// live tip after compression. Drop both so the pin can't linger.
|
|
1052
|
+
const archivedPinId = archived ? sessionPinId(archived) : storedSessionId
|
|
761
1053
|
|
|
762
1054
|
// Soft-hide: drop from the sidebar immediately, keep the data.
|
|
763
|
-
setSessions(prev => prev.filter(
|
|
764
|
-
|
|
1055
|
+
setSessions(prev => prev.filter(session => !sessionMatchesStoredId(session, storedSessionId)))
|
|
1056
|
+
// Archived sessions are hidden by the listSessions(min_messages=1) query
|
|
1057
|
+
// on the next refresh, so they count as "removed" for the load-more
|
|
1058
|
+
// footer math.
|
|
1059
|
+
setSessionsTotal(prev => Math.max(0, prev - 1))
|
|
1060
|
+
$pinnedSessionIds.set(previousPinned.filter(id => id !== storedSessionId && id !== archivedPinId))
|
|
765
1061
|
|
|
766
1062
|
if (wasSelected) {
|
|
767
1063
|
startFreshSessionDraft(true)
|
|
768
1064
|
}
|
|
769
1065
|
|
|
770
1066
|
try {
|
|
771
|
-
await setSessionArchived(storedSessionId, true)
|
|
772
|
-
|
|
1067
|
+
await setSessionArchived(storedSessionId, true, archived?.profile)
|
|
1068
|
+
// A sidebar refresh can race the optimistic removal while the PATCH is
|
|
1069
|
+
// in flight and briefly reinsert the still-unarchived backend row. Win
|
|
1070
|
+
// that race after the mutation succeeds so right-click → Archive does
|
|
1071
|
+
// not appear to do nothing until the next full refresh.
|
|
1072
|
+
setSessions(prev => prev.filter(session => !sessionMatchesStoredId(session, storedSessionId)))
|
|
1073
|
+
$pinnedSessionIds.set($pinnedSessionIds.get().filter(id => id !== storedSessionId && id !== archivedPinId))
|
|
1074
|
+
notify({ durationMs: 2_000, kind: 'success', message: copy.archived })
|
|
773
1075
|
} catch (err) {
|
|
774
1076
|
if (archived) {
|
|
775
|
-
setSessions(prev => [archived, ...prev.filter(
|
|
1077
|
+
setSessions(prev => [archived, ...prev.filter(session => !sessionMatchesStoredId(session, storedSessionId))])
|
|
1078
|
+
setSessionsTotal(prev => prev + 1)
|
|
776
1079
|
}
|
|
777
1080
|
|
|
778
1081
|
$pinnedSessionIds.set(previousPinned)
|
|
779
|
-
notifyError(err,
|
|
1082
|
+
notifyError(err, copy.archiveFailed)
|
|
780
1083
|
}
|
|
781
1084
|
},
|
|
782
|
-
[selectedStoredSessionId, startFreshSessionDraft]
|
|
1085
|
+
[copy, selectedStoredSessionId, startFreshSessionDraft]
|
|
783
1086
|
)
|
|
784
1087
|
|
|
785
1088
|
return {
|