@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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""Suggested cron jobs — proposed automations the user accepts with one tap.
|
|
2
|
+
|
|
3
|
+
A *suggestion* is a ready-to-run cron job spec that Hermes surfaces to the
|
|
4
|
+
user, who accepts it (creates the real cron job) or dismisses it (latched so
|
|
5
|
+
it is never re-offered). This is the single surface every automation proposal
|
|
6
|
+
flows through, regardless of where it came from:
|
|
7
|
+
|
|
8
|
+
* ``catalog`` — a curated starter automation (daily briefing, important-mail
|
|
9
|
+
monitor, weekly digest, ...).
|
|
10
|
+
* ``blueprint`` — the user installed a skill that carries a ``blueprint:`` block
|
|
11
|
+
(see ``tools/blueprints.py``); installing it registers a
|
|
12
|
+
suggestion instead of auto-scheduling.
|
|
13
|
+
* ``usage`` — the background self-improvement review noticed a recurring
|
|
14
|
+
ask that a scheduled job would serve.
|
|
15
|
+
* ``integration`` — the user connected an account (Gmail, GitHub, ...) and
|
|
16
|
+
the obvious automations for that surface are offered.
|
|
17
|
+
|
|
18
|
+
Accepting a suggestion just calls the existing ``cron.jobs.create_job`` with
|
|
19
|
+
the stored ``job_spec`` — there is NO second job engine. Suggestions never
|
|
20
|
+
auto-create jobs; acceptance is always explicit (consent-first). Dismissed
|
|
21
|
+
suggestions latch by a stable ``dedup_key`` so the same proposal is not
|
|
22
|
+
re-offered after the user says no.
|
|
23
|
+
|
|
24
|
+
Storage mirrors ``cron/jobs.py``: ``~/.hermes/cron/suggestions.json``, atomic
|
|
25
|
+
writes, an in-process lock, and 0600 perms.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import json
|
|
31
|
+
import logging
|
|
32
|
+
import os
|
|
33
|
+
import tempfile
|
|
34
|
+
import threading
|
|
35
|
+
import uuid
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from typing import Any, Dict, List, Optional
|
|
38
|
+
|
|
39
|
+
from hermes_constants import get_hermes_home
|
|
40
|
+
from hermes_time import now as _hermes_now
|
|
41
|
+
from utils import atomic_replace
|
|
42
|
+
|
|
43
|
+
logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
CRON_DIR = get_hermes_home().resolve() / "cron"
|
|
46
|
+
SUGGESTIONS_FILE = CRON_DIR / "suggestions.json"
|
|
47
|
+
|
|
48
|
+
# In-process lock protecting load->modify->save cycles (the background review
|
|
49
|
+
# fork and the main agent can both write).
|
|
50
|
+
_suggestions_lock = threading.Lock()
|
|
51
|
+
|
|
52
|
+
# Cap pending suggestions so the list never becomes a nag wall. When full,
|
|
53
|
+
# new suggestions are dropped (the user should clear the backlog first).
|
|
54
|
+
MAX_PENDING = 5
|
|
55
|
+
|
|
56
|
+
VALID_SOURCES = frozenset({"catalog", "blueprint", "usage", "integration"})
|
|
57
|
+
_STATUS_PENDING = "pending"
|
|
58
|
+
_STATUS_ACCEPTED = "accepted"
|
|
59
|
+
_STATUS_DISMISSED = "dismissed"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _secure_file(path: Path) -> None:
|
|
63
|
+
try:
|
|
64
|
+
os.chmod(path, 0o600)
|
|
65
|
+
except OSError:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _ensure_dir() -> None:
|
|
70
|
+
CRON_DIR.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _load_raw() -> Dict[str, Any]:
|
|
74
|
+
if not SUGGESTIONS_FILE.exists():
|
|
75
|
+
return {"suggestions": []}
|
|
76
|
+
try:
|
|
77
|
+
with open(SUGGESTIONS_FILE, "r", encoding="utf-8") as f:
|
|
78
|
+
data = json.load(f)
|
|
79
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
80
|
+
logger.warning("suggestions.json unreadable (%s); starting empty", e)
|
|
81
|
+
return {"suggestions": []}
|
|
82
|
+
if isinstance(data, dict) and isinstance(data.get("suggestions"), list):
|
|
83
|
+
return data
|
|
84
|
+
if isinstance(data, list):
|
|
85
|
+
return {"suggestions": data}
|
|
86
|
+
logger.warning("suggestions.json malformed; starting empty")
|
|
87
|
+
return {"suggestions": []}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _save_raw(suggestions: List[Dict[str, Any]]) -> None:
|
|
91
|
+
_ensure_dir()
|
|
92
|
+
fd, tmp_path = tempfile.mkstemp(dir=str(SUGGESTIONS_FILE.parent), suffix=".tmp", prefix=".sugg_")
|
|
93
|
+
try:
|
|
94
|
+
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
|
95
|
+
json.dump(
|
|
96
|
+
{"suggestions": suggestions, "updated_at": _hermes_now().isoformat()},
|
|
97
|
+
f,
|
|
98
|
+
indent=2,
|
|
99
|
+
)
|
|
100
|
+
f.flush()
|
|
101
|
+
os.fsync(f.fileno())
|
|
102
|
+
atomic_replace(tmp_path, SUGGESTIONS_FILE)
|
|
103
|
+
_secure_file(SUGGESTIONS_FILE)
|
|
104
|
+
except BaseException:
|
|
105
|
+
try:
|
|
106
|
+
os.unlink(tmp_path)
|
|
107
|
+
except OSError:
|
|
108
|
+
pass
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def load_suggestions() -> List[Dict[str, Any]]:
|
|
113
|
+
"""Return all suggestion records (any status)."""
|
|
114
|
+
return _load_raw().get("suggestions", [])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def list_pending() -> List[Dict[str, Any]]:
|
|
118
|
+
"""Return pending suggestions in creation order (oldest first)."""
|
|
119
|
+
return [s for s in load_suggestions() if s.get("status") == _STATUS_PENDING]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def add_suggestion(
|
|
123
|
+
*,
|
|
124
|
+
title: str,
|
|
125
|
+
description: str,
|
|
126
|
+
source: str,
|
|
127
|
+
job_spec: Dict[str, Any],
|
|
128
|
+
dedup_key: str,
|
|
129
|
+
) -> Optional[Dict[str, Any]]:
|
|
130
|
+
"""Register a pending suggestion. Returns the record, or None if skipped.
|
|
131
|
+
|
|
132
|
+
Skipped when: the source is unknown, the same ``dedup_key`` was already
|
|
133
|
+
dismissed or accepted (never re-offer), an identical pending suggestion
|
|
134
|
+
exists, or the pending list is full (``MAX_PENDING``).
|
|
135
|
+
|
|
136
|
+
``job_spec`` is a dict of kwargs for ``cron.jobs.create_job`` — accepting
|
|
137
|
+
the suggestion passes it straight through, so there is no second schema to
|
|
138
|
+
keep in sync.
|
|
139
|
+
"""
|
|
140
|
+
if source not in VALID_SOURCES:
|
|
141
|
+
raise ValueError(f"unknown suggestion source: {source!r}")
|
|
142
|
+
if not title.strip() or not dedup_key.strip():
|
|
143
|
+
raise ValueError("title and dedup_key are required")
|
|
144
|
+
|
|
145
|
+
with _suggestions_lock:
|
|
146
|
+
suggestions = _load_raw().get("suggestions", [])
|
|
147
|
+
|
|
148
|
+
# Never re-offer something the user already saw and decided on, and
|
|
149
|
+
# never duplicate a still-pending proposal.
|
|
150
|
+
for existing in suggestions:
|
|
151
|
+
if existing.get("dedup_key") == dedup_key:
|
|
152
|
+
if existing.get("status") in (_STATUS_DISMISSED, _STATUS_ACCEPTED):
|
|
153
|
+
return None
|
|
154
|
+
if existing.get("status") == _STATUS_PENDING:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
pending_count = sum(1 for s in suggestions if s.get("status") == _STATUS_PENDING)
|
|
158
|
+
if pending_count >= MAX_PENDING:
|
|
159
|
+
logger.info("Suggestion backlog full (%d); dropping %r", MAX_PENDING, title)
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
record = {
|
|
163
|
+
"id": uuid.uuid4().hex[:12],
|
|
164
|
+
"title": title.strip(),
|
|
165
|
+
"description": description.strip(),
|
|
166
|
+
"source": source,
|
|
167
|
+
"job_spec": job_spec,
|
|
168
|
+
"dedup_key": dedup_key.strip(),
|
|
169
|
+
"status": _STATUS_PENDING,
|
|
170
|
+
"created_at": _hermes_now().isoformat(),
|
|
171
|
+
}
|
|
172
|
+
suggestions.append(record)
|
|
173
|
+
_save_raw(suggestions)
|
|
174
|
+
return record
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_suggestion(ref: str) -> Optional[Dict[str, Any]]:
|
|
178
|
+
"""Resolve a suggestion by id, 1-based pending index, or title (exact)."""
|
|
179
|
+
suggestions = load_suggestions()
|
|
180
|
+
# By id.
|
|
181
|
+
for s in suggestions:
|
|
182
|
+
if s.get("id") == ref:
|
|
183
|
+
return s
|
|
184
|
+
# By 1-based pending index.
|
|
185
|
+
if ref.isdigit():
|
|
186
|
+
pending = [s for s in suggestions if s.get("status") == _STATUS_PENDING]
|
|
187
|
+
idx = int(ref) - 1
|
|
188
|
+
if 0 <= idx < len(pending):
|
|
189
|
+
return pending[idx]
|
|
190
|
+
# By exact title (case-insensitive).
|
|
191
|
+
for s in suggestions:
|
|
192
|
+
if s.get("title", "").lower() == ref.lower():
|
|
193
|
+
return s
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _set_status(suggestion_id: str, status: str) -> bool:
|
|
198
|
+
with _suggestions_lock:
|
|
199
|
+
suggestions = _load_raw().get("suggestions", [])
|
|
200
|
+
changed = False
|
|
201
|
+
for s in suggestions:
|
|
202
|
+
if s.get("id") == suggestion_id:
|
|
203
|
+
s["status"] = status
|
|
204
|
+
s["resolved_at"] = _hermes_now().isoformat()
|
|
205
|
+
changed = True
|
|
206
|
+
break
|
|
207
|
+
if changed:
|
|
208
|
+
_save_raw(suggestions)
|
|
209
|
+
return changed
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def dismiss_suggestion(ref: str) -> bool:
|
|
213
|
+
"""Dismiss a suggestion (latched — never re-offered for its dedup_key)."""
|
|
214
|
+
s = get_suggestion(ref)
|
|
215
|
+
if not s:
|
|
216
|
+
return False
|
|
217
|
+
return _set_status(s["id"], _STATUS_DISMISSED)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def accept_suggestion(ref: str, *, origin: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
|
|
221
|
+
"""Accept a suggestion: create the real cron job from its ``job_spec``.
|
|
222
|
+
|
|
223
|
+
Returns the created cron job dict, or None if the suggestion isn't found /
|
|
224
|
+
not pending. The job_spec is passed straight to ``cron.jobs.create_job``;
|
|
225
|
+
an ``origin`` (platform/chat) is merged so "origin" delivery routes back to
|
|
226
|
+
the chat where the user accepted.
|
|
227
|
+
"""
|
|
228
|
+
s = get_suggestion(ref)
|
|
229
|
+
if not s or s.get("status") != _STATUS_PENDING:
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
from cron.jobs import create_job
|
|
233
|
+
|
|
234
|
+
spec = dict(s.get("job_spec") or {})
|
|
235
|
+
if origin is not None and "origin" not in spec:
|
|
236
|
+
spec["origin"] = origin
|
|
237
|
+
|
|
238
|
+
job = create_job(**spec)
|
|
239
|
+
_set_status(s["id"], _STATUS_ACCEPTED)
|
|
240
|
+
return job
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def clear_resolved() -> int:
|
|
244
|
+
"""Drop accepted/dismissed records from disk. Returns the count removed.
|
|
245
|
+
|
|
246
|
+
Pending suggestions and the dedup memory of dismissed ones are the only
|
|
247
|
+
things that matter long-term, but dismissed records must be RETAINED for
|
|
248
|
+
their dedup_key (so they aren't re-offered). This only prunes ACCEPTED
|
|
249
|
+
records, which have served their purpose once the job exists.
|
|
250
|
+
"""
|
|
251
|
+
with _suggestions_lock:
|
|
252
|
+
suggestions = _load_raw().get("suggestions", [])
|
|
253
|
+
kept = [s for s in suggestions if s.get("status") != _STATUS_ACCEPTED]
|
|
254
|
+
removed = len(suggestions) - len(kept)
|
|
255
|
+
if removed:
|
|
256
|
+
_save_raw(kept)
|
|
257
|
+
return removed
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Chronos managed-cron — agent ↔ NAS wire contract
|
|
2
|
+
|
|
3
|
+
**Status:** authoritative wire spec for the Chronos cron provider.
|
|
4
|
+
**Audience:** the NAS-side implementer of the `agent-cron` endpoints
|
|
5
|
+
(`nous-account-service`) and anyone debugging the managed-cron path.
|
|
6
|
+
|
|
7
|
+
Chronos lets a hosted Hermes gateway **scale to zero** while idle and still
|
|
8
|
+
fire cron jobs. Instead of an in-process 60-second ticker, the agent asks NAS
|
|
9
|
+
to arm exactly **one external one-shot per job at that job's real next-fire
|
|
10
|
+
time**. NAS calls the agent back at fire time over an authenticated webhook;
|
|
11
|
+
the agent runs the job and re-arms the next one-shot. Between fires the agent
|
|
12
|
+
process can be fully stopped — it wakes only on a genuine fire.
|
|
13
|
+
|
|
14
|
+
The external scheduler NAS uses to implement the one-shots is an **internal NAS
|
|
15
|
+
implementation detail**. The agent never talks to it, never holds its
|
|
16
|
+
credentials, and never names it. The agent only knows the three NAS endpoints
|
|
17
|
+
below.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
create/update/pause/resume/remove a cron job (agent side)
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
ChronosCronScheduler.reconcile() ── agent computes next_run_at
|
|
24
|
+
│ POST {portal}/api/agent-cron/provision (auth: agent's Nous access token)
|
|
25
|
+
▼
|
|
26
|
+
NAS arms a one-shot for fire_at ── NAS owns the scheduler + its creds
|
|
27
|
+
│
|
|
28
|
+
⏰ at fire_at
|
|
29
|
+
▼
|
|
30
|
+
scheduler → POST {portal}/api/agent-cron/relay (auth: scheduler signature, NAS-verified)
|
|
31
|
+
│
|
|
32
|
+
▼
|
|
33
|
+
NAS mints a short-lived agent-audience JWT (purpose=cron_fire)
|
|
34
|
+
│ POST {agent_callback_url}/api/cron/fire (auth: that JWT)
|
|
35
|
+
▼
|
|
36
|
+
agent verifies the NAS JWT → store CAS claim → run_one_job → re-arm next one-shot
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Trust model (read this first)
|
|
40
|
+
|
|
41
|
+
| Hop | Who calls whom | Auth mechanism | Verified by |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| 1 | agent → NAS (`provision`/`cancel`/`list`) | the agent's existing **Nous Portal access token** (Bearer) | NAS (its normal agent-token path) |
|
|
44
|
+
| 2 | scheduler → NAS (`relay`) | the scheduler's request **signature** | NAS (the signature path it already has) |
|
|
45
|
+
| 3 | NAS → agent (`/api/cron/fire`) | a **short-lived NAS-minted JWT** (`aud=agent:{instance_id}`, `purpose=cron_fire`) | agent (PyJWT against NAS JWKS) |
|
|
46
|
+
|
|
47
|
+
Why NAS-mediated rather than scheduler→agent direct: the scheduler signs with
|
|
48
|
+
**NAS's** keys, which the agent does not (and should not) hold. The agent can
|
|
49
|
+
only verify a **NAS-minted** token — a trust path it already has. This keeps
|
|
50
|
+
all scheduler credentials inside NAS. (Full rationale: the plan's DQ-4.)
|
|
51
|
+
|
|
52
|
+
No new secret is introduced on the agent: hop 1 reuses the token the agent
|
|
53
|
+
already uses for the portal, and hop 3 reuses the NAS-JWT verification the agent
|
|
54
|
+
already performs.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Endpoint 1 — `POST /api/agent-cron/provision` (agent → NAS)
|
|
59
|
+
|
|
60
|
+
Arm (or re-arm, idempotently) exactly one one-shot for a job.
|
|
61
|
+
|
|
62
|
+
- **Auth:** `Authorization: Bearer <agent Nous access token>`. NAS validates via
|
|
63
|
+
its normal agent-token path and scopes the row to the calling agent/org.
|
|
64
|
+
- **Request body:**
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"job_id": "ab12cd34",
|
|
68
|
+
"fire_at": "2026-06-18T12:34:56+00:00",
|
|
69
|
+
"agent_callback_url": "https://agent-xyz.fly.dev",
|
|
70
|
+
"dedup_key": "ab12cd34:2026-06-18T12:34:56+00:00"
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
- `fire_at` — ISO 8601, **agent-computed**. May be sub-minute in the future;
|
|
74
|
+
NAS must honor second-granularity (the agent owns the time, so there is no
|
|
75
|
+
1-minute scheduler floor).
|
|
76
|
+
- `agent_callback_url` — the agent's own publicly-reachable base URL. NAS
|
|
77
|
+
POSTs `{agent_callback_url}/api/cron/fire` at fire time.
|
|
78
|
+
- `dedup_key` — `"{job_id}:{fire_at}"`. NAS **upserts by `(agent_id, job_id)`**
|
|
79
|
+
so re-arming the same fire is idempotent (no duplicate one-shots). A new
|
|
80
|
+
`fire_at` for the same `job_id` replaces the prior arm.
|
|
81
|
+
- **Action:** arm one one-shot to fire at `fire_at`, destined for the NAS
|
|
82
|
+
**relay** route (Endpoint 3) — NOT the agent directly, so NAS stays in the
|
|
83
|
+
loop to mint the agent JWT. Persist `(agent_id, job_id, schedule_id,
|
|
84
|
+
agent_callback_url)`.
|
|
85
|
+
- **Response:** `200 {"schedule_id": "<opaque>"}`.
|
|
86
|
+
|
|
87
|
+
## Endpoint 2 — `POST /api/agent-cron/cancel` (agent → NAS)
|
|
88
|
+
|
|
89
|
+
- **Auth:** same as Endpoint 1.
|
|
90
|
+
- **Body:** `{"job_id": "ab12cd34"}`.
|
|
91
|
+
- **Action:** cancel the armed one-shot for `(agent_id, job_id)` and delete the
|
|
92
|
+
row. Idempotent — cancelling an unknown job is a 200 no-op.
|
|
93
|
+
- **Response:** `200 {"ok": true}`.
|
|
94
|
+
|
|
95
|
+
## Endpoint 3 — `POST /api/agent-cron/relay` (scheduler → NAS, the fire relay)
|
|
96
|
+
|
|
97
|
+
- **Auth:** the scheduler's request **signature**, verified by NAS with the
|
|
98
|
+
signature path it already has. This is the trust boundary for the fire — a
|
|
99
|
+
forged relay call must be rejected here.
|
|
100
|
+
- **Action:**
|
|
101
|
+
1. Look up `(agent_id, job_id) → agent_callback_url` from the persisted row.
|
|
102
|
+
2. Mint a **short-lived** JWT: `aud = "agent:{instance_id}"`,
|
|
103
|
+
`iss = {portal_url}`, `purpose = "cron_fire"`, small `exp` (≈60–120s),
|
|
104
|
+
signed with NAS's normal asymmetric signing key (published via JWKS).
|
|
105
|
+
3. `POST {agent_callback_url}/api/cron/fire` with
|
|
106
|
+
`Authorization: Bearer <that JWT>` and body `{"job_id": "...", "fire_at": "..."}`.
|
|
107
|
+
4. Treat a non-2xx agent response as a **retryable** failure (let the
|
|
108
|
+
scheduler retry the relay). The agent's store CAS de-dupes a double fire,
|
|
109
|
+
so retries are safe.
|
|
110
|
+
- **Response to the scheduler:** 2xx once the agent POST is accepted (202), so
|
|
111
|
+
the scheduler does not retry a delivered fire.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Inbound `POST /api/cron/fire` (NAS → agent) — agent side, already implemented
|
|
116
|
+
|
|
117
|
+
This is the agent endpoint NAS calls in Endpoint 3 step 3. Served by the
|
|
118
|
+
**dashboard app** (`hermes_cli/web_server.py`) — the agent's always-reachable
|
|
119
|
+
public HTTP surface on hosted deployments (the gateway may be idle/scaled down);
|
|
120
|
+
it is in `PUBLIC_API_PATHS` so the dashboard cookie gate lets the bearer-JWT
|
|
121
|
+
callback through to the verifier. (Also registered on the optional
|
|
122
|
+
`APIServerAdapter` for self-host API-server deployments.) The verifier is
|
|
123
|
+
`plugins/cron/chronos/verify.py`.
|
|
124
|
+
|
|
125
|
+
- **Auth:** `Authorization: Bearer <NAS-minted JWT>`. The agent verifies:
|
|
126
|
+
- signature against the NAS JWKS (`cron.chronos.nas_jwks_url`),
|
|
127
|
+
- `aud` == `cron.chronos.expected_audience` (this agent's
|
|
128
|
+
`agent:{instance_id}`),
|
|
129
|
+
- `iss` == `cron.chronos.portal_url`,
|
|
130
|
+
- `exp` / `nbf` (30s leeway),
|
|
131
|
+
- `purpose == "cron_fire"` — a general agent JWT (no/other purpose) is
|
|
132
|
+
rejected so it can't be replayed against this endpoint.
|
|
133
|
+
- **Body:** `{"job_id": "ab12cd34", "fire_at": "..."}` (only `job_id` is used).
|
|
134
|
+
- **Behavior:**
|
|
135
|
+
- invalid/missing/forged/expired/wrong-aud/wrong-purpose token → **401**, no
|
|
136
|
+
execution.
|
|
137
|
+
- missing `job_id` → **400**.
|
|
138
|
+
- valid → **202 `{"status": "accepted", "job_id": "..."}`** immediately, and
|
|
139
|
+
the job runs in the background. 202-before-run means a long agent turn never
|
|
140
|
+
trips the relay's HTTP timeout.
|
|
141
|
+
- **At-most-once:** the agent claims the job with a store-level compare-and-set
|
|
142
|
+
(`claim_job_for_fire`) before running. A relay/scheduler retry that arrives
|
|
143
|
+
while the first fire is in flight (or after it completed) loses the claim and
|
|
144
|
+
does not double-run.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## At-most-once & re-arm semantics
|
|
149
|
+
|
|
150
|
+
- **Recurring (cron/interval):** on fire, the agent advances `next_run_at`
|
|
151
|
+
(under its store lock) as part of the claim, runs the job, then re-provisions
|
|
152
|
+
a one-shot for the new `next_run_at`. A duplicate relay for the old `fire_at`
|
|
153
|
+
finds the claim taken / time advanced and is dropped.
|
|
154
|
+
- **One-shot (`30m`, `+90s`, etc.):** fires once; `mark_job_run` marks it
|
|
155
|
+
completed. No re-arm.
|
|
156
|
+
- **`repeat.times = N`:** `mark_job_run` deletes the job at the limit, so
|
|
157
|
+
`get_job` returns `None` after the final fire → the agent does **not** re-arm
|
|
158
|
+
→ the schedule stops cleanly with no orphaned one-shot.
|
|
159
|
+
- **Multi-replica agents:** the store CAS makes the fire at-most-once across N
|
|
160
|
+
gateway replicas sharing one `HERMES_HOME` — exactly one replica runs each
|
|
161
|
+
fire.
|
|
162
|
+
|
|
163
|
+
## Reconcile (self-healing)
|
|
164
|
+
|
|
165
|
+
The agent reconciles desired (`jobs.json`) vs armed on:
|
|
166
|
+
- `start()` (gateway boot / wake),
|
|
167
|
+
- every successful job mutation (`on_jobs_changed`),
|
|
168
|
+
- piggybacked after each fire (re-arm).
|
|
169
|
+
|
|
170
|
+
Reconcile arms missing/changed-time jobs and cancels orphans. A missed
|
|
171
|
+
provision (transient NAS error) self-heals on the next reconcile. There is **no
|
|
172
|
+
periodic wake** of a sleeping agent — that would negate scale-to-zero.
|
|
173
|
+
|
|
174
|
+
## Config (agent side)
|
|
175
|
+
|
|
176
|
+
All non-secret (`cron.chronos.*` in `config.yaml`); the agent holds no scheduler
|
|
177
|
+
credentials. For hosted agents NAS sets these at provision time:
|
|
178
|
+
|
|
179
|
+
| key | meaning |
|
|
180
|
+
|---|---|
|
|
181
|
+
| `cron.provider` | `"chronos"` to activate (empty = built-in ticker) |
|
|
182
|
+
| `cron.chronos.portal_url` | NAS base URL (also the expected JWT `iss`) |
|
|
183
|
+
| `cron.chronos.callback_url` | the agent's own public base URL for NAS→agent fires |
|
|
184
|
+
| `cron.chronos.expected_audience` | this agent's JWT `aud` (`agent:{instance_id}`) |
|
|
185
|
+
| `cron.chronos.nas_jwks_url` | NAS JWKS for verifying the fire JWT |
|
|
186
|
+
|
|
187
|
+
If `callback_url` / `portal_url` is blank or the agent has no Nous login,
|
|
188
|
+
`is_available()` returns False and the resolver falls back to the built-in
|
|
189
|
+
in-process ticker — cron never loses its trigger.
|
|
190
|
+
|
|
191
|
+
## Escape hatch (not default)
|
|
192
|
+
|
|
193
|
+
The inbound `/api/cron/fire` verifier is pluggable (`get_fire_verifier()`). If
|
|
194
|
+
relay volume through NAS ever saturates, a direct scheduler→agent mode with a
|
|
195
|
+
per-job NAS-minted cron-key can replace the NAS-JWT verifier with **no change to
|
|
196
|
+
the webhook handler**. NAS-mediated (this contract) is the default.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Profile Builder — Dashboard-Native, Full-Featured Profile Creation
|
|
2
|
+
|
|
3
|
+
Status: design proposal (not yet implemented)
|
|
4
|
+
Author: drafted for Teknium
|
|
5
|
+
Supersedes: PR #31781 (prompt_toolkit `hermes profile wizard`)
|
|
6
|
+
|
|
7
|
+
## Why this, not the CLI wizard
|
|
8
|
+
|
|
9
|
+
PR #31781 added a keyboard-driven `hermes profile wizard` in the terminal.
|
|
10
|
+
The decision is to **not** build the profile-creation experience in the CLI.
|
|
11
|
+
The dashboard already owns mature, separate pages for every element a profile
|
|
12
|
+
needs, and a profile is just a HERMES_HOME directory — so the dashboard is the
|
|
13
|
+
right home for a full-featured builder, and it can reuse everything that
|
|
14
|
+
already exists.
|
|
15
|
+
|
|
16
|
+
A profile = a full `~/.hermes/profiles/<name>/` directory with its own:
|
|
17
|
+
- `config.yaml` — holds `model`/`provider`, `mcp_servers`, enabled skills
|
|
18
|
+
- `skills/` — physical SKILL.md files (built-in seed + optional + hub installs)
|
|
19
|
+
- `.env` — secrets
|
|
20
|
+
- `SOUL.md` / `USER.md` — identity
|
|
21
|
+
|
|
22
|
+
So per-profile scoping of Model, MCPs, and Skills is **native** — no data-model
|
|
23
|
+
change needed. The gap is purely UX: creation today is a thin modal
|
|
24
|
+
(name + clone + model + description), and you can only compose skills/MCPs
|
|
25
|
+
*after* the profile exists, by visiting other pages and remembering to scope
|
|
26
|
+
them.
|
|
27
|
+
|
|
28
|
+
## What already exists (reuse, don't rebuild)
|
|
29
|
+
|
|
30
|
+
| Element | Existing page | Existing API | Profile-scopable? |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| Name / Description | ProfilesPage create modal | `POST /api/profiles` (`create_profile`) | yes (args) |
|
|
33
|
+
| Model + Provider | ModelsPage | `_write_profile_model(profile_dir, …)` | yes — HERMES_HOME override, already wired into create endpoint |
|
|
34
|
+
| MCPs | McpPage | `mcp_config._save_mcp_server` + `/api/mcp/catalog` | yes — wrap with HERMES_HOME override |
|
|
35
|
+
| Skills (built-in/optional) | SkillsPage | `GET /api/skills`, `/api/skills/toggle` | yes — config write |
|
|
36
|
+
| Skills (hub) | SkillsPage | `/api/skills/hub/search`, `/api/skills/hub/install` | **only via subprocess** — see seam #1 |
|
|
37
|
+
|
|
38
|
+
## Two architectural seams found while grounding this design
|
|
39
|
+
|
|
40
|
+
These are load-bearing — they change the implementation, not just the polish.
|
|
41
|
+
|
|
42
|
+
### Seam #1 — hub-skill install cannot use the HERMES_HOME override
|
|
43
|
+
|
|
44
|
+
`tools/skills_hub.py` binds `SKILLS_DIR = HERMES_HOME / "skills"` at **module
|
|
45
|
+
import time**. The context-local `set_hermes_home_override()` swap (which makes
|
|
46
|
+
`_write_profile_model` and the MCP write land in the target profile) does NOT
|
|
47
|
+
retroactively rebind that already-imported module global. So a data-layer wrap
|
|
48
|
+
of hub install would write into the dashboard's *own* active profile, not the
|
|
49
|
+
new one.
|
|
50
|
+
|
|
51
|
+
The correct mechanism is the existing subprocess path: `_spawn_hermes_action`
|
|
52
|
+
runs `python -m hermes_cli.main <subcommand>`, and `_apply_profile_override()`
|
|
53
|
+
re-reads `sys.argv` at import in the fresh child. Prepend `-p <profile>`:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
_spawn_hermes_action(["-p", profile, "skills", "install", identifier], "skills-install")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
A fresh subprocess re-imports `skills_hub` with the profile's HERMES_HOME bound
|
|
60
|
+
from the start, so `SKILLS_DIR` resolves to `<profile>/skills/`. Correct by
|
|
61
|
+
construction.
|
|
62
|
+
|
|
63
|
+
### Seam #2 — hub installs are async, so create cannot be fully atomic
|
|
64
|
+
|
|
65
|
+
Built-in/optional skill enabling and MCP writes are **synchronous config ops**
|
|
66
|
+
and can be part of the create call. Hub installs are long-running git fetches
|
|
67
|
+
spawned detached (`_spawn_hermes_action` returns a PID immediately). So the
|
|
68
|
+
create flow is:
|
|
69
|
+
|
|
70
|
+
1. `create_profile()` — make the dir (synchronous)
|
|
71
|
+
2. write model (synchronous, HERMES_HOME override)
|
|
72
|
+
3. write selected MCP servers (synchronous, HERMES_HOME override)
|
|
73
|
+
4. seed/enable selected built-in + optional skills (synchronous)
|
|
74
|
+
5. spawn `hermes -p <profile> skills install <id>` per hub skill (async, returns PIDs)
|
|
75
|
+
|
|
76
|
+
Steps 1–4 commit before the response; step 5 returns a list of action PIDs the
|
|
77
|
+
UI polls (same pattern as today's SkillsPage hub install). The builder's
|
|
78
|
+
"Review → Create" returns `{ok, name, path, hub_installs: [{id, pid}]}` and the
|
|
79
|
+
final screen shows live install progress for the hub skills.
|
|
80
|
+
|
|
81
|
+
## Proposed backend change (small, follows existing patterns)
|
|
82
|
+
|
|
83
|
+
Extend `ProfileCreate` and the create endpoint — no new endpoints, no rewrite:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
class ProfileCreate(BaseModel):
|
|
87
|
+
name: str
|
|
88
|
+
clone_from: Optional[str] = None
|
|
89
|
+
# Backward compatibility for older dashboard/desktop clients.
|
|
90
|
+
clone_from_default: bool = False
|
|
91
|
+
clone_all: bool = False
|
|
92
|
+
no_skills: bool = False
|
|
93
|
+
description: Optional[str] = None
|
|
94
|
+
provider: Optional[str] = None
|
|
95
|
+
model: Optional[str] = None
|
|
96
|
+
# NEW — all optional, all best-effort post-create (profile already exists)
|
|
97
|
+
mcp_servers: List[MCPServerCreate] = [] # synchronous, HERMES_HOME override
|
|
98
|
+
builtin_skills: List[str] = [] # synchronous enable/seed
|
|
99
|
+
hub_skills: List[str] = [] # async spawn, returns PIDs
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The endpoint already does best-effort post-create steps (`seed_profile_skills`,
|
|
103
|
+
`_write_profile_model`). Add two more best-effort blocks (MCP write, hub-skill
|
|
104
|
+
spawn) in the same style — a failure in any of them must not 500 the create,
|
|
105
|
+
since the profile dir already exists and the user can fix it from the relevant
|
|
106
|
+
page afterward. Mirror `_write_profile_model`'s HERMES_HOME-override helper for
|
|
107
|
+
the MCP write (`_write_profile_mcp_servers(profile_dir, servers)`).
|
|
108
|
+
|
|
109
|
+
## Proposed frontend — dedicated builder page `/profiles/new`
|
|
110
|
+
|
|
111
|
+
A full page (not the cramped modal), stepped, each step reusing the existing
|
|
112
|
+
page's component + API, targeted at the new profile:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
① Identity Name + Description (+ optional clone-from existing profile)
|
|
116
|
+
② Model Provider + model picker (reuse ModelsPage picker)
|
|
117
|
+
③ Skills Tabs: Built-in · Optional · Hub-search
|
|
118
|
+
multi-select; "Start from default bundle" preset button
|
|
119
|
+
④ MCPs Tabs: Catalog browse · Manual add (reuse McpPage form)
|
|
120
|
+
⑤ Review Blueprint preview → Create
|
|
121
|
+
→ progress screen for async hub installs
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Nothing writes to disk until ⑤.
|
|
125
|
+
|
|
126
|
+
## Open product decisions (need Teknium)
|
|
127
|
+
|
|
128
|
+
1. **Skills seeding default.** Fresh profiles auto-seed the default bundle
|
|
129
|
+
today. In the builder, should the skill step **replace** the bundle (pick
|
|
130
|
+
exactly what you want; offer a "start from default bundle" preset) or
|
|
131
|
+
**augment** it? Recommendation: replace + preset button.
|
|
132
|
+
|
|
133
|
+
2. **Page vs richer modal.** Dedicated `/profiles/new` page (room to grow:
|
|
134
|
+
SOUL editing, multi-agent fleets later) vs a bigger create modal on
|
|
135
|
+
ProfilesPage. Recommendation: dedicated page — matches "full-featured / way
|
|
136
|
+
more options."
|
|
137
|
+
|
|
138
|
+
## Verification plan (when built)
|
|
139
|
+
|
|
140
|
+
- Backend E2E with isolated HERMES_HOME: POST a full create body
|
|
141
|
+
(name + model + 2 MCPs + 3 builtin skills + 1 hub skill), assert the new
|
|
142
|
+
profile dir has the model in config.yaml, both MCP servers in config.yaml,
|
|
143
|
+
the builtin skills enabled, and a spawned PID for the hub skill. Negative:
|
|
144
|
+
a bad MCP entry must not 500 the create.
|
|
145
|
+
- `cd web && npm run build` (no JS test suite in web/).
|
|
146
|
+
- Targeted: `pytest tests/<web_server profile tests> -k profile_create`.
|