@maudecode/talaria-web 1.17.2 → 1.19.0
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/_release.json +8 -8
- package/dist/api/auth-raw.d.ts +1 -1
- package/dist/api/auth-raw.js +20 -20
- package/dist/api/auth-raw.js.map +1 -1
- package/dist/api/automation-raw.d.ts +7 -1
- package/dist/api/automation-raw.js +74 -27
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +128 -23
- package/dist/api/automation-router.js +29 -13
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +1845 -40
- package/dist/api/chat-router.js +196 -114
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +37 -3
- package/dist/api/git-router.js +47 -48
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +9 -1
- package/dist/api/raw-routes.js +286 -73
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +16 -6
- package/dist/api/router.js +28 -26
- package/dist/api/router.js.map +1 -1
- package/dist/api/session-visibility.d.ts +4 -4
- package/dist/api/session-visibility.js +26 -16
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +3312 -131
- package/dist/api/sessions-router.js +287 -157
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +457 -8
- package/dist/api/settings-router.js +54 -33
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +7 -2
- package/dist/api/sse-routes.js +109 -62
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.d.ts +5 -0
- package/dist/api/tools-raw.js +63 -55
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +998 -85
- package/dist/api/tools-router.js +447 -61
- package/dist/api/tools-router.js.map +1 -1
- package/dist/api/transcribe-stream.d.ts +16 -0
- package/dist/api/transcribe-stream.js +172 -0
- package/dist/api/transcribe-stream.js.map +1 -0
- package/dist/app.d.ts +4 -1
- package/dist/app.js +98 -59
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +15 -11
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +5 -2
- package/dist/auth/oidc.js +8 -7
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/passkeys.d.ts +15 -14
- package/dist/auth/passkeys.js +89 -91
- package/dist/auth/passkeys.js.map +1 -1
- package/dist/auth/store.d.ts +17 -7
- package/dist/auth/store.js +93 -52
- package/dist/auth/store.js.map +1 -1
- package/dist/bin/talaria-web.js +12 -81
- package/dist/bin/talaria-web.js.map +1 -1
- package/dist/cli/ctl.js +2 -1
- package/dist/cli/ctl.js.map +1 -1
- package/dist/cli/dotenv.d.ts +5 -0
- package/dist/cli/dotenv.js +15 -2
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/cli/launcher.js +5 -5
- package/dist/cli/launcher.js.map +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +85 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/supervise.d.ts +2 -0
- package/dist/cli/supervise.js +67 -4
- package/dist/cli/supervise.js.map +1 -1
- package/dist/config/agent-config.d.ts +34 -11
- package/dist/config/agent-config.js +116 -60
- package/dist/config/agent-config.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +19 -6
- package/dist/config.js.map +1 -1
- package/dist/fs/atomic.d.ts +1 -0
- package/dist/fs/atomic.js +4 -1
- package/dist/fs/atomic.js.map +1 -1
- package/dist/fs/stat.d.ts +1 -0
- package/dist/fs/stat.js +11 -0
- package/dist/fs/stat.js.map +1 -0
- package/dist/http/context.d.ts +31 -12
- package/dist/http/context.js +60 -24
- package/dist/http/context.js.map +1 -1
- package/dist/http/csp.d.ts +2 -1
- package/dist/http/csp.js +3 -2
- package/dist/http/csp.js.map +1 -1
- package/dist/onboarding.d.ts +2 -2
- package/dist/onboarding.js +10 -8
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.d.ts +20 -4
- package/dist/profiles/profiles.js +115 -30
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/projects.d.ts +15 -6
- package/dist/projects.js +55 -47
- package/dist/projects.js.map +1 -1
- package/dist/providers/catalog.d.ts +84 -14
- package/dist/providers/catalog.js +474 -151
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/env-file.d.ts +10 -3
- package/dist/providers/env-file.js +24 -75
- package/dist/providers/env-file.js.map +1 -1
- package/dist/providers/runtime-env.d.ts +4 -2
- package/dist/providers/runtime-env.js +9 -6
- package/dist/providers/runtime-env.js.map +1 -1
- package/dist/providers/tables.d.ts +3 -1
- package/dist/providers/tables.js +4 -2
- package/dist/providers/tables.js.map +1 -1
- package/dist/raster-image.d.ts +7 -0
- package/dist/raster-image.js +267 -0
- package/dist/raster-image.js.map +1 -0
- package/dist/redact.js +342 -46
- package/dist/redact.js.map +1 -1
- package/dist/release.d.ts +7 -0
- package/dist/release.js +14 -0
- package/dist/release.js.map +1 -1
- package/dist/runtime.d.ts +5 -1
- package/dist/runtime.js +305 -96
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +15 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +9 -3
- package/dist/sessions/anchor.js +28 -36
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-events.d.ts +2 -0
- package/dist/sessions/background-events.js +10 -0
- package/dist/sessions/background-events.js.map +1 -0
- package/dist/sessions/background-tasks.d.ts +26 -27
- package/dist/sessions/background-tasks.js +89 -97
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/background-updates.d.ts +15 -8
- package/dist/sessions/background-updates.js +101 -25
- package/dist/sessions/background-updates.js.map +1 -1
- package/dist/sessions/cli-sessions.d.ts +27 -6
- package/dist/sessions/cli-sessions.js +152 -42
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +77 -9
- package/dist/sessions/completions.js +482 -45
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +8 -0
- package/dist/sessions/compress.js +2 -2
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/drafts.d.ts +14 -10
- package/dist/sessions/drafts.js +38 -43
- package/dist/sessions/drafts.js.map +1 -1
- package/dist/sessions/export.d.ts +5 -0
- package/dist/sessions/export.js +30 -0
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +46 -0
- package/dist/sessions/gateway-sessions.js +378 -0
- package/dist/sessions/gateway-sessions.js.map +1 -0
- package/dist/sessions/gateway-watcher.d.ts +7 -3
- package/dist/sessions/gateway-watcher.js +31 -19
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/goals.d.ts +31 -0
- package/dist/sessions/goals.js +75 -0
- package/dist/sessions/goals.js.map +1 -0
- package/dist/sessions/handoff.d.ts +32 -0
- package/dist/sessions/handoff.js +114 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/journal.d.ts +5 -79
- package/dist/sessions/journal.js +15 -606
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +31 -16
- package/dist/sessions/list.js +139 -129
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +69 -13
- package/dist/sessions/merge.js +265 -64
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/notices.d.ts +22 -0
- package/dist/sessions/notices.js +72 -0
- package/dist/sessions/notices.js.map +1 -0
- package/dist/sessions/pending.d.ts +10 -4
- package/dist/sessions/pending.js +83 -7
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +82 -0
- package/dist/sessions/prefix-index.js +232 -0
- package/dist/sessions/prefix-index.js.map +1 -0
- package/dist/sessions/recovery.d.ts +19 -0
- package/dist/sessions/recovery.js +322 -0
- package/dist/sessions/recovery.js.map +1 -0
- package/dist/sessions/relay.d.ts +38 -19
- package/dist/sessions/relay.js +302 -79
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +260 -55
- package/dist/sessions/service.js +1448 -462
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +24 -2
- package/dist/sessions/session.js +69 -7
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.d.ts +7 -6
- package/dist/sessions/shares.js +22 -45
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/source-kind.js +1 -0
- package/dist/sessions/source-kind.js.map +1 -1
- package/dist/sessions/state-db-identity.d.ts +18 -0
- package/dist/sessions/state-db-identity.js +67 -0
- package/dist/sessions/state-db-identity.js.map +1 -0
- package/dist/sessions/state-db-worker.d.ts +1 -0
- package/dist/sessions/state-db-worker.js +35 -0
- package/dist/sessions/state-db-worker.js.map +1 -0
- package/dist/sessions/state-db.d.ts +113 -7
- package/dist/sessions/state-db.js +861 -44
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/storage/backend.d.ts +162 -0
- package/dist/sessions/storage/backend.js +19 -0
- package/dist/sessions/storage/backend.js.map +1 -0
- package/dist/sessions/storage/conformance.d.ts +20 -0
- package/dist/sessions/storage/conformance.js +237 -0
- package/dist/sessions/storage/conformance.js.map +1 -0
- package/dist/sessions/storage/document.d.ts +16 -0
- package/dist/sessions/storage/document.js +44 -0
- package/dist/sessions/storage/document.js.map +1 -0
- package/dist/sessions/storage/json-documents.d.ts +23 -0
- package/dist/sessions/storage/json-documents.js +233 -0
- package/dist/sessions/storage/json-documents.js.map +1 -0
- package/dist/sessions/storage/json-files.d.ts +12 -0
- package/dist/sessions/storage/json-files.js +124 -0
- package/dist/sessions/storage/json-files.js.map +1 -0
- package/dist/sessions/storage/json-installation.d.ts +3 -0
- package/dist/sessions/storage/json-installation.js +31 -0
- package/dist/sessions/storage/json-installation.js.map +1 -0
- package/dist/sessions/storage/json-journal.d.ts +114 -0
- package/dist/sessions/storage/json-journal.js +686 -0
- package/dist/sessions/storage/json-journal.js.map +1 -0
- package/dist/sessions/storage/json-recovery.d.ts +4 -0
- package/dist/sessions/storage/json-recovery.js +195 -0
- package/dist/sessions/storage/json-recovery.js.map +1 -0
- package/dist/sessions/storage/json.d.ts +68 -0
- package/dist/sessions/storage/json.js +258 -0
- package/dist/sessions/storage/json.js.map +1 -0
- package/dist/sessions/storage/row.d.ts +6 -0
- package/dist/sessions/storage/row.js +49 -0
- package/dist/sessions/storage/row.js.map +1 -0
- package/dist/sessions/storage/search-text.d.ts +4 -0
- package/dist/sessions/storage/search-text.js +16 -0
- package/dist/sessions/storage/search-text.js.map +1 -0
- package/dist/sessions/store.d.ts +65 -68
- package/dist/sessions/store.js +305 -602
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +4 -0
- package/dist/sessions/streams.js +9 -1
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +2 -0
- package/dist/sessions/titles.js +5 -1
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/todo.d.ts +5 -0
- package/dist/sessions/todo.js +28 -21
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +5 -4
- package/dist/sessions/tool-display.js +30 -50
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +11 -2
- package/dist/sessions/turn-context.js +18 -11
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +122 -17
- package/dist/sessions/turn.js +939 -358
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sessions/wakeup-pause.d.ts +54 -0
- package/dist/sessions/wakeup-pause.js +163 -0
- package/dist/sessions/wakeup-pause.js.map +1 -0
- package/dist/sessions/window.js +13 -12
- package/dist/sessions/window.js.map +1 -1
- package/dist/settings.d.ts +19 -7
- package/dist/settings.js +178 -184
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/client.d.ts +17 -3
- package/dist/sidecar/client.js +78 -8
- package/dist/sidecar/client.js.map +1 -1
- package/dist/sidecar/discover.d.ts +2 -1
- package/dist/sidecar/discover.js +93 -10
- package/dist/sidecar/discover.js.map +1 -1
- package/dist/sidecar/env.d.ts +4 -0
- package/dist/sidecar/env.js +3 -0
- package/dist/sidecar/env.js.map +1 -0
- package/dist/sidecar/fake.d.ts +2 -2
- package/dist/sidecar/fake.js +19 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/startup.d.ts +13 -5
- package/dist/startup.js +48 -0
- package/dist/startup.js.map +1 -1
- package/dist/test/env-file.d.ts +5 -0
- package/dist/test/env-file.js +88 -0
- package/dist/test/env-file.js.map +1 -0
- package/dist/test/harness.d.ts +1 -0
- package/dist/test/harness.js +1 -1
- package/dist/test/harness.js.map +1 -1
- package/dist/test/passkeys.d.ts +22 -0
- package/dist/test/passkeys.js +62 -0
- package/dist/test/passkeys.js.map +1 -0
- package/dist/test/storage.d.ts +15 -0
- package/dist/test/storage.js +26 -0
- package/dist/test/storage.js.map +1 -0
- package/dist/test/ts-worker-hooks.d.ts +1 -0
- package/dist/test/ts-worker-hooks.js +24 -0
- package/dist/test/ts-worker-hooks.js.map +1 -0
- package/dist/text/diff.d.ts +9 -14
- package/dist/text/diff.js +74 -108
- package/dist/text/diff.js.map +1 -1
- package/dist/tools/commands.d.ts +6 -1
- package/dist/tools/commands.js +8 -2
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/connectors.d.ts +33 -0
- package/dist/tools/connectors.js +121 -0
- package/dist/tools/connectors.js.map +1 -0
- package/dist/tools/crons.d.ts +38 -1
- package/dist/tools/crons.js +122 -18
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +53 -0
- package/dist/tools/dashboard-plugins.js +188 -0
- package/dist/tools/dashboard-plugins.js.map +1 -0
- package/dist/tools/extensions.d.ts +18 -5
- package/dist/tools/extensions.js +344 -266
- package/dist/tools/extensions.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +62 -0
- package/dist/tools/gateway-restart.js +142 -0
- package/dist/tools/gateway-restart.js.map +1 -0
- package/dist/tools/health.d.ts +44 -0
- package/dist/tools/health.js +201 -46
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/hygiene.d.ts +4 -3
- package/dist/tools/hygiene.js +23 -9
- package/dist/tools/hygiene.js.map +1 -1
- package/dist/tools/kanban.d.ts +4 -2
- package/dist/tools/kanban.js +28 -19
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +13 -0
- package/dist/tools/mcp.js +88 -0
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/memory-masks.d.ts +5 -0
- package/dist/tools/memory-masks.js +256 -0
- package/dist/tools/memory-masks.js.map +1 -0
- package/dist/tools/memory.d.ts +29 -3
- package/dist/tools/memory.js +69 -27
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/plugin-settings.d.ts +15 -0
- package/dist/tools/plugin-settings.js +90 -0
- package/dist/tools/plugin-settings.js.map +1 -0
- package/dist/tools/project-os.d.ts +11 -0
- package/dist/tools/project-os.js +267 -0
- package/dist/tools/project-os.js.map +1 -0
- package/dist/tools/skills.d.ts +14 -5
- package/dist/tools/skills.js +49 -16
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +34 -15
- package/dist/tools/update-notifications.js +141 -57
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/update-rollback.d.ts +11 -0
- package/dist/tools/update-rollback.js +28 -0
- package/dist/tools/update-rollback.js.map +1 -0
- package/dist/tools/updates.d.ts +110 -32
- package/dist/tools/updates.js +1112 -294
- package/dist/tools/updates.js.map +1 -1
- package/dist/tools/wiki.d.ts +68 -0
- package/dist/tools/wiki.js +413 -0
- package/dist/tools/wiki.js.map +1 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.js +5 -0
- package/dist/util.js.map +1 -1
- package/dist/workspace/escape.d.ts +61 -0
- package/dist/workspace/escape.js +149 -0
- package/dist/workspace/escape.js.map +1 -0
- package/dist/workspace/extract.d.ts +22 -0
- package/dist/workspace/extract.js +308 -0
- package/dist/workspace/extract.js.map +1 -0
- package/dist/workspace/fs.d.ts +12 -0
- package/dist/workspace/fs.js +92 -23
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +34 -1
- package/dist/workspace/git.js +328 -35
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media.d.ts +16 -13
- package/dist/workspace/media.js +43 -61
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/rollback.d.ts +36 -22
- package/dist/workspace/rollback.js +178 -272
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/unzip.js +4 -1
- package/dist/workspace/unzip.js.map +1 -1
- package/dist/workspace/upload.d.ts +7 -4
- package/dist/workspace/upload.js +5 -2
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +15 -19
- package/dist/workspace/workspaces.js +55 -127
- package/dist/workspace/workspaces.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -1
- package/dist/workspace/worktrees.js +179 -42
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +7 -3
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/agent_support.json +26 -0
- package/sidecar/scripts/record-fixtures.py +12 -3
- package/sidecar/scripts/replay_sidecar.py +32 -0
- package/sidecar/scripts/suite_runner.py +302 -0
- package/sidecar/scripts/test.sh +12 -4
- package/sidecar/talaria_sidecar/__init__.py +6 -1
- package/sidecar/talaria_sidecar/__main__.py +4 -2
- package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
- package/sidecar/talaria_sidecar/agent_services.py +1053 -0
- package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
- package/sidecar/talaria_sidecar/home.py +56 -3
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +166 -24
- package/sidecar/talaria_sidecar/methods/chat.py +852 -135
- package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
- package/sidecar/talaria_sidecar/methods/commands.py +294 -4
- package/sidecar/talaria_sidecar/methods/config.py +123 -4
- package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
- package/sidecar/talaria_sidecar/methods/cron.py +395 -36
- package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +212 -55
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
- package/sidecar/talaria_sidecar/methods/goals.py +81 -41
- package/sidecar/talaria_sidecar/methods/kanban.py +108 -34
- package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
- package/sidecar/talaria_sidecar/methods/memory.py +84 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
- package/sidecar/talaria_sidecar/methods/process.py +218 -15
- package/sidecar/talaria_sidecar/methods/profiles.py +121 -13
- package/sidecar/talaria_sidecar/methods/providers.py +217 -28
- package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
- package/sidecar/talaria_sidecar/methods/skills.py +67 -4
- package/sidecar/talaria_sidecar/methods/state_db.py +316 -75
- package/sidecar/talaria_sidecar/methods/stt.py +159 -78
- package/sidecar/talaria_sidecar/methods/text.py +14 -1
- package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
- package/sidecar/talaria_sidecar/methods/usage.py +113 -14
- package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
- package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
- package/sidecar/talaria_sidecar/rpc.py +45 -4
- package/sidecar/talaria_sidecar/runtime.py +98 -13
- package/sidecar/talaria_sidecar/speed.py +35 -0
- package/static/dist/FILES.txt +126 -126
- package/static/dist/assets/AppShell-cey33v9s.js +8 -0
- package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
- package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
- package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
- package/static/dist/assets/Field-j8uqoigz.js +9 -0
- package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
- package/static/dist/assets/Markdown-lahuichm.js +598 -0
- package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
- package/static/dist/assets/Select-gqatm2e0.js +1 -0
- package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
- package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
- package/static/dist/assets/States-e7dkgtxf.js +1 -0
- package/static/dist/assets/Toaster-bfqqy786.js +1 -0
- package/static/dist/assets/_app-n1n6pfx1.js +1 -0
- package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-buxjxav3.js} +1 -1
- package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
- package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
- package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
- package/static/dist/assets/_app.logs-dm873z90.js +1 -0
- package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
- package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-g2vzghvc.js} +1 -1
- package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
- package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
- package/static/dist/assets/_app.skills-cii852yq.js +1 -0
- package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
- package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
- package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
- package/static/dist/assets/archive-b1j004vn.js +1 -0
- package/static/dist/assets/back-g74gkozu.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
- package/static/dist/assets/channel-es95o4y8.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
- package/static/dist/assets/copied-bli9tbcx.js +1 -0
- package/static/dist/assets/{copy-fw5b1pc6.js → copy-jamtd1pf.js} +1 -1
- package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
- package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
- package/static/dist/assets/host-hzm8n85n.js +1 -0
- package/static/dist/assets/index-drdcaqeq.css +2 -0
- package/static/dist/assets/index-jzm844he.js +11 -0
- package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
- package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
- package/static/dist/assets/{line-osxq6fq7.js → line-h0ojzsvs.js} +1 -1
- package/static/dist/assets/link-k01ryaf9.js +1 -0
- package/static/dist/assets/login-bsae49ew.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-bnre27u8.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
- package/static/dist/assets/onboarding-c65tysya.js +1 -0
- package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
- package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
- package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
- package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-mqbkv2a3.js} +1 -1
- package/static/dist/assets/refresh-l29ljp76.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
- package/static/dist/assets/saved-ndd4t2xb.js +1 -0
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
- package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
- package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
- package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
- package/static/dist/assets/toast-i3h34v6o.js +64 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
- package/static/dist/assets/untitled-oaoya4qj.js +1 -0
- package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
- package/static/dist/assets/{useParams-lhg566ew.js → useParams-gjc70qru.js} +1 -1
- package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-e6ae539u.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
- package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
- package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
- package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
- package/static/dist/assets/Markdown-mdwlvj3w.js +0 -598
- package/static/dist/assets/RightPanel-ftvrjlcp.js +0 -1
- package/static/dist/assets/Select-bilaypej.js +0 -1
- package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
- package/static/dist/assets/SettingsLayout-jonjefmj.js +0 -1
- package/static/dist/assets/States-nmejrwrm.js +0 -1
- package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
- package/static/dist/assets/_app-gdidzd94.js +0 -1
- package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
- package/static/dist/assets/_app.insights-luywlarz.js +0 -1
- package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
- package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
- package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
- package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
- package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
- package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
- package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
- package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
- package/static/dist/assets/back-bemaer09.js +0 -1
- package/static/dist/assets/cancel-drd0g6d9.js +0 -1
- package/static/dist/assets/channel-cpdgf867.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
- package/static/dist/assets/copied-ima3pysb.js +0 -1
- package/static/dist/assets/endpoints-d33siokx.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
- package/static/dist/assets/index-cxq58xb1.js +0 -11
- package/static/dist/assets/index-hgtx08n5.css +0 -2
- package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +0 -1
- package/static/dist/assets/link-jyxicdhg.js +0 -1
- package/static/dist/assets/login-ec21t39x.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
- package/static/dist/assets/onboarding-btnltvyz.js +0 -1
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
- package/static/dist/assets/refresh-b4uams1i.js +0 -1
- package/static/dist/assets/saved-kg52csy7.js +0 -1
- package/static/dist/assets/settings_section_extensions_title-ej0iapxe.js +0 -1
- package/static/dist/assets/share._token-f97e94r0.js +0 -2
- package/static/dist/assets/sliders-horizontal-fj18it47.js +0 -1
- package/static/dist/assets/sse-fwpqtzbg.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
- package/static/dist/assets/todoStore-eginf9h4.js +0 -1
- package/static/dist/assets/tts-lxdxnmjd.js +0 -1
- package/static/dist/assets/untitled-ovpfthg4.js +0 -1
- package/static/dist/assets/useForm-bcblv1rx.js +0 -1
- package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
package/dist/api/tools-router.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Skills, memory, prompts, commands, notes, insights, logs, health, MCP, plugins, updates, diagnostics (Python `api/routes.py` handlers of the same paths). */
|
|
2
1
|
import { implement } from '@orpc/server';
|
|
3
2
|
import { createHash } from 'node:crypto';
|
|
4
3
|
import { join } from 'node:path';
|
|
@@ -6,19 +5,32 @@ import { toolsContract } from '@maudecode/talaria-web-contracts';
|
|
|
6
5
|
import { HttpError, requireFields } from './router.js';
|
|
7
6
|
import { requestSessionIdGuard } from './session-visibility.js';
|
|
8
7
|
import { activeProfileName, ensureTrustedAuthSession, sessionCanManageServer } from '../auth/gate.js';
|
|
9
|
-
import { HttpFailure } from '../sessions/service.js';
|
|
8
|
+
import { currentChatReadiness, HttpFailure } from '../sessions/service.js';
|
|
10
9
|
import { SessionNotFound } from '../sessions/store.js';
|
|
11
10
|
import { insightsSessionRows } from '../sessions/state-db.js';
|
|
12
11
|
import { ConfigUnavailable } from '../config/agent-config.js';
|
|
13
12
|
import { SidecarError } from '../sidecar/client.js';
|
|
14
13
|
import { createPrompt, deletePrompt, externalNotesEnabled, loadPrompts, readMemory, writeMemory } from '../tools/memory.js';
|
|
15
|
-
import { notesSources } from '../tools/mcp.js';
|
|
14
|
+
import { JoplinError, joplinNote, joplinSearch, notesSources } from '../tools/mcp.js';
|
|
15
|
+
import { catalogNames, connectorOperation, connectorsPage, connectorTools, rememberCatalogNames } from '../tools/connectors.js';
|
|
16
|
+
import { resolveWikiLocation, wikiPages } from '../tools/wiki.js';
|
|
16
17
|
import { buildInsights } from '../tools/insights.js';
|
|
17
|
-
import { commandCatalog } from '../tools/commands.js';
|
|
18
|
-
import {
|
|
18
|
+
import { commandCatalog, SESSION_EXEC_COMMANDS } from '../tools/commands.js';
|
|
19
|
+
import { spokenText } from './tools-raw.js';
|
|
20
|
+
import { agentHealth, applyDashboardConfig, dashboardConfig, dashboardStatus, gatewayStatus, parseDashboardConfig, readLogTail, remoteGatewayBaseUrl, systemHealth } from '../tools/health.js';
|
|
21
|
+
import { restartGateway } from '../tools/gateway-restart.js';
|
|
22
|
+
import { projectOsDashboard } from '../tools/project-os.js';
|
|
23
|
+
import { PluginSettingsInvalid, planPluginSettings, pluginSettingsView, serializePluginSettingsSave } from '../tools/plugin-settings.js';
|
|
24
|
+
import { credentialShadowed, RuntimeCredentialError, writeRuntimeCredential } from '../providers/runtime-env.js';
|
|
25
|
+
import { EnvWriteError, loadEnvFile } from '../providers/env-file.js';
|
|
26
|
+
import { loadGatewaySessionIdentityMap } from '../sessions/list.js';
|
|
27
|
+
import { gitBadge } from '../workspace/git.js';
|
|
28
|
+
import { sanitizeError } from '../workspace/media.js';
|
|
19
29
|
import { normalizeChannel, updatesCheckView } from '../tools/updates.js';
|
|
20
30
|
import { pyBool } from '../settings.js';
|
|
21
31
|
import { str } from '../util.js';
|
|
32
|
+
import { redactString } from '../redact.js';
|
|
33
|
+
import { GATEWAY_RESTART_NOW } from '../tools/update-notifications.js';
|
|
22
34
|
const os = implement(toolsContract).$context().use(requestSessionIdGuard);
|
|
23
35
|
function failure(error) {
|
|
24
36
|
if (error instanceof HttpError)
|
|
@@ -43,6 +55,128 @@ async function run(fn) {
|
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
57
|
const home = (ctx) => ctx.deps.profileHome(activeProfileName(ctx));
|
|
58
|
+
/** Profile homes with an `stt.warm` in flight (TAL-916). */
|
|
59
|
+
const warmingHomes = new Set();
|
|
60
|
+
function runningSidecar(ctx) {
|
|
61
|
+
const sidecar = ctx.deps.sidecar();
|
|
62
|
+
if (!sidecar)
|
|
63
|
+
throw new HttpError(503, 'Hermes Agent sidecar is not running');
|
|
64
|
+
return sidecar;
|
|
65
|
+
}
|
|
66
|
+
/** A slash command's sidecar failure: `notFound` is 404, bad input 400, the rest as `failure` maps them. */
|
|
67
|
+
function commandFailure(error, notFound, message) {
|
|
68
|
+
if (error instanceof SidecarError && error.condition === notFound)
|
|
69
|
+
throw new HttpError(404, message);
|
|
70
|
+
if (error instanceof SidecarError && (error.condition === 'invalid_params' || error.code === -32602))
|
|
71
|
+
throw new HttpError(400, error.message);
|
|
72
|
+
return failure(error);
|
|
73
|
+
}
|
|
74
|
+
/** TAL-820: several profiles have third-party plugins and one of them loads its plugins into the shared sidecar process. */
|
|
75
|
+
async function pluginIsolationAdvisory(ctx) {
|
|
76
|
+
if (ctx.deps.isolatedProfileMode())
|
|
77
|
+
return false;
|
|
78
|
+
const { profiles } = await runningSidecar(ctx).call('plugins.isolation', { base_home: ctx.deps.profileHome('default') });
|
|
79
|
+
const withPlugins = profiles.filter((profile) => profile.third_party_plugins > 0);
|
|
80
|
+
return withPlugins.length > 1 && withPlugins.some((profile) => profile.isolation === 'in_process');
|
|
81
|
+
}
|
|
82
|
+
/** TAL-806: the active profile's plugins that declare settings; none on an Agent without the settings module. */
|
|
83
|
+
async function pluginSettingsList(ctx) {
|
|
84
|
+
const result = await runningSidecar(ctx).call('plugins.settings', { profile_home: home(ctx) });
|
|
85
|
+
return result.plugins.map((entry) => ({ key: entry.key, fields: pluginSettingsFieldsView(ctx, entry.fields) }));
|
|
86
|
+
}
|
|
87
|
+
const pluginSettingsFieldsView = (ctx, fields) => {
|
|
88
|
+
const rootProfile = ctx.deps.isRootProfile(activeProfileName(ctx));
|
|
89
|
+
return pluginSettingsView(fields, (envVar) => credentialShadowed(ctx.deps.config.env, rootProfile, envVar));
|
|
90
|
+
};
|
|
91
|
+
/** A refusal that proves nothing was written; a timeout or a sidecar exit leaves the outcome unknown. */
|
|
92
|
+
const definitiveRefusal = (error) => error instanceof SidecarError ? ['plugin_settings_managed', 'plugin_settings_changed', 'plugin_not_found'].includes(error.condition) || error.code === -32602
|
|
93
|
+
: error instanceof EnvWriteError ? error.condition !== 'sidecar_unavailable'
|
|
94
|
+
: error instanceof RuntimeCredentialError;
|
|
95
|
+
/** TAL-818: a sidecar `connectors.*` condition as the HTTP status the contract names; the body's `code` is the condition. */
|
|
96
|
+
const CONNECTOR_STATUS = {
|
|
97
|
+
connectors_unavailable: 404, connector_not_found: 404, connection_not_found: 404, operation_not_found: 404,
|
|
98
|
+
connectors_sign_in: 403, connectors_forbidden: 403, policy_invalid: 400, connectors_failed: 502,
|
|
99
|
+
policy_conflict: 409, connectors_org_required: 409, operation_settled: 409, operation_refused: 409,
|
|
100
|
+
};
|
|
101
|
+
async function connectorCall(ctx, method, params) {
|
|
102
|
+
try {
|
|
103
|
+
// A connect waits up to 31 s for its link; every portal request inside a call is bounded at 30 s.
|
|
104
|
+
return await runningSidecar(ctx).call(method, { ...params, profile_home: home(ctx) }, { timeoutMs: 90_000 });
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const status = error instanceof SidecarError ? CONNECTOR_STATUS[error.condition] : undefined;
|
|
108
|
+
if (status !== undefined)
|
|
109
|
+
throw new HttpError(status, error.message, { code: error.condition });
|
|
110
|
+
if (error instanceof SidecarError && error.code === -32602)
|
|
111
|
+
throw new HttpError(400, error.message);
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** The catalog's app names for the active profile: the last page read's, else one catalog read; none when it fails. */
|
|
116
|
+
async function connectorNames(ctx) {
|
|
117
|
+
return catalogNames(home(ctx)) ?? await connectorCall(ctx, 'connectors.catalog', {}).then((r) => rememberCatalogNames(home(ctx), r.connectors), () => ({}));
|
|
118
|
+
}
|
|
119
|
+
/** An operation as the contract shows it, with the apps' catalog names. */
|
|
120
|
+
const operationView = async (ctx, snapshot) => connectorOperation(snapshot, await connectorNames(ctx));
|
|
121
|
+
/** The rules, or why they cannot be read (a portal refusal or failure): the page then fails closed and says why. */
|
|
122
|
+
const connectorPolicy = (ctx) => connectorCall(ctx, 'connectors.policy.get', {}).then((policy) => ({ policy, error: null }), (error) => { if (error instanceof HttpError)
|
|
123
|
+
return { policy: null, error: error.message }; throw error; });
|
|
124
|
+
const health = (ctx) => agentHealth({ env: ctx.deps.config.env, hermesHome: ctx.deps.config.hermesHome, profileHome: () => home(ctx), fetch: () => ctx.deps.fetch, now: ctx.deps.nowSeconds });
|
|
125
|
+
/**
|
|
126
|
+
* TAL-805: the active profile's gateway mode from sidecar `gateway.mode`; null for a remote gateway. A named profile never
|
|
127
|
+
* borrows the root's health: when the sidecar cannot answer, it reads `stopped`, while the root profile reads null and keeps
|
|
128
|
+
* its health. The root profile's gateway in another container (`health` alive from its fresh runtime status) is invisible
|
|
129
|
+
* to the sidecar's process checks, so it stays `own`.
|
|
130
|
+
*/
|
|
131
|
+
async function gatewayMode(ctx, health) {
|
|
132
|
+
if (remoteGatewayBaseUrl(ctx.deps.config.env) !== null)
|
|
133
|
+
return null;
|
|
134
|
+
const sidecar = ctx.deps.sidecar();
|
|
135
|
+
const name = activeProfileName(ctx);
|
|
136
|
+
const isDefault = ctx.deps.isRootProfile(name);
|
|
137
|
+
let mode = null;
|
|
138
|
+
try {
|
|
139
|
+
if (sidecar)
|
|
140
|
+
mode = (await sidecar.call('gateway.mode', { profile_home: home(ctx), name, is_default: isDefault }, { timeoutMs: 10_000 })).gateway_mode;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
mode = null;
|
|
144
|
+
}
|
|
145
|
+
if (mode === null)
|
|
146
|
+
return isDefault ? null : 'stopped';
|
|
147
|
+
return mode === 'stopped' && isDefault && health.alive === true ? 'own' : mode;
|
|
148
|
+
}
|
|
149
|
+
/** Python `_gateway_status_payload` for the active profile. */
|
|
150
|
+
async function currentGatewayStatus(ctx) {
|
|
151
|
+
const sessionsPath = join(home(ctx), 'sessions', 'sessions.json');
|
|
152
|
+
const probe = await health(ctx);
|
|
153
|
+
return gatewayStatus(probe, loadGatewaySessionIdentityMap(sessionsPath), sessionsPath, await gatewayMode(ctx, probe));
|
|
154
|
+
}
|
|
155
|
+
const GATEWAY_ACTION_TIMEOUT_S = 60;
|
|
156
|
+
/** Python `_handle_gateway_lifecycle` through sidecar `gateway.control`: 409 busy, 504 timeout, 500 failure; only the Agent's first error line (`reason`) leaves the server, never its CLI output (TAL-884). */
|
|
157
|
+
async function gatewayAction(ctx, action) {
|
|
158
|
+
const sidecar = ctx.deps.sidecar();
|
|
159
|
+
if (!sidecar)
|
|
160
|
+
throw new HttpError(500, 'Hermes Agent sidecar is not running', { ok: false, action });
|
|
161
|
+
let outcome;
|
|
162
|
+
try {
|
|
163
|
+
outcome = await sidecar.call('gateway.control', { profile_home: home(ctx), action, background_wait_seconds: GATEWAY_ACTION_TIMEOUT_S }, { timeoutMs: 300_000 });
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw new HttpError(500, sanitizeError(error), { ok: false, action });
|
|
167
|
+
}
|
|
168
|
+
if (outcome.status === 'busy')
|
|
169
|
+
throw new HttpError(409, 'Another gateway action is already in progress; try again shortly.', { ok: false, action });
|
|
170
|
+
if (outcome.timed_out)
|
|
171
|
+
throw new HttpError(504, `Gateway ${action} timed out after ${String(GATEWAY_ACTION_TIMEOUT_S)} seconds`, { ok: false, action });
|
|
172
|
+
if (outcome.status === 'failed' && outcome.returncode !== undefined) {
|
|
173
|
+
const error = outcome.reason ? `Gateway ${action} failed: ${outcome.reason}` : `Gateway ${action} failed with exit code ${String(outcome.returncode)}`;
|
|
174
|
+
throw new HttpError(500, error, { ok: false, action, returncode: outcome.returncode });
|
|
175
|
+
}
|
|
176
|
+
if (outcome.status === 'failed')
|
|
177
|
+
throw new HttpError(500, outcome.message, { ok: false, action });
|
|
178
|
+
return { ok: true, action, message: `Gateway ${action} completed.`, status: await currentGatewayStatus(ctx) };
|
|
179
|
+
}
|
|
46
180
|
const principalHash = (...parts) => createHash('sha256').update(JSON.stringify(parts), 'utf8').digest('hex');
|
|
47
181
|
export function updateNotificationOwner(session) {
|
|
48
182
|
const authType = str(session?.auth_type).trim();
|
|
@@ -67,39 +201,54 @@ async function updateNotificationScope(ctx, tab) {
|
|
|
67
201
|
tab: tab ?? null,
|
|
68
202
|
};
|
|
69
203
|
}
|
|
70
|
-
async function applyWithNotification(ctx,
|
|
71
|
-
const
|
|
204
|
+
async function applyWithNotification(ctx, input, action) {
|
|
205
|
+
const target = updateTarget(input.target);
|
|
206
|
+
const confirmed = input.confirmed_agent_revision !== undefined || input.agent_refresh_token !== undefined;
|
|
207
|
+
const scope = await updateNotificationScope(ctx, input.tab_id);
|
|
72
208
|
const active = ctx.deps.updateNotifications.activeUpdate(scope, target);
|
|
73
209
|
if (active)
|
|
74
|
-
ctx.deps.updateNotifications.watch(scope, active.id);
|
|
210
|
+
(await ctx.deps.updateNotifications.watch(scope, active.id));
|
|
75
211
|
if (active && (active.phase === 'applying' || active.phase === 'restarting')) {
|
|
76
212
|
return { ok: false, status: 'already_in_progress', message: 'Update already in progress', notification_id: active.id };
|
|
77
213
|
}
|
|
78
|
-
const notification = active ?? ctx.deps.updateNotifications.begin(scope, target);
|
|
214
|
+
const notification = active ?? (await ctx.deps.updateNotifications.begin(scope, target));
|
|
79
215
|
if (active?.phase === 'awaiting_confirmation' && confirmed)
|
|
80
|
-
ctx.deps.updateNotifications.transition(notification.id, 'applying');
|
|
216
|
+
(await ctx.deps.updateNotifications.transition(notification.id, 'applying'));
|
|
81
217
|
try {
|
|
82
|
-
const
|
|
218
|
+
const options = { agentChannel: input.agent_channel, confirmedRevision: input.confirmed_agent_revision, version: input.version, refreshToken: input.agent_refresh_token, mutationIntent: principalHash(scope.owner, scope.profile, notification.id) };
|
|
219
|
+
const result = action === 'apply' ? await ctx.deps.updates.apply(target, bodyChannel(input.channel), () => true, options)
|
|
220
|
+
: action === 'force' ? await ctx.deps.updates.force(target, bodyChannel(input.channel), options)
|
|
221
|
+
: await ctx.deps.updates.clearLock(target, options);
|
|
83
222
|
const verifiedIdentity = typeof result.verified_revision === 'string'
|
|
84
223
|
? { revision: result.verified_revision, version: typeof result.verified_version === 'string' ? result.verified_version : null }
|
|
85
224
|
: undefined;
|
|
86
225
|
if (result.confirmation_required === true)
|
|
87
|
-
ctx.deps.updateNotifications.transition(notification.id, 'awaiting_confirmation', null, verifiedIdentity);
|
|
226
|
+
(await ctx.deps.updateNotifications.transition(notification.id, 'awaiting_confirmation', null, verifiedIdentity, result.message));
|
|
88
227
|
else if (result.restart_blocked === true)
|
|
89
|
-
ctx.deps.updateNotifications.transition(notification.id, 'blocked', null, verifiedIdentity, result.message);
|
|
228
|
+
(await ctx.deps.updateNotifications.transition(notification.id, 'blocked', null, verifiedIdentity, result.message));
|
|
90
229
|
else if (result.ok !== true)
|
|
91
|
-
ctx.deps.updateNotifications.transition(notification.id, 'failed', null, verifiedIdentity, result.message || result.error);
|
|
230
|
+
(await ctx.deps.updateNotifications.transition(notification.id, 'failed', null, verifiedIdentity, result.message || result.error));
|
|
92
231
|
else if (target === 'webui' && result.restart_scheduled === true) {
|
|
93
|
-
ctx.deps.updateNotifications.transition(notification.id, 'restarting', str(result.sourceRevision || result.candidate_revision), verifiedIdentity);
|
|
232
|
+
await ctx.deps.updateNotifications.transition(notification.id, 'restarting', str(result.sourceRevision || result.candidate_revision), verifiedIdentity);
|
|
233
|
+
}
|
|
234
|
+
else if (result.gateway_restart === 'waiting_for_idle' || (target === 'agent' && ctx.deps.gatewayRestarts.pendingId() !== null)) {
|
|
235
|
+
// TAL-953: the gateway restarts once its own work drains. A restart already waiting covers this update too, and a
|
|
236
|
+
// repeated request that found the Agent current follows that wait rather than reporting success before it.
|
|
237
|
+
const detail = result.stash_conflict === true ? str(result.message) : null;
|
|
238
|
+
await ctx.deps.updateNotifications.transition(notification.id, 'waiting_for_idle', null, verifiedIdentity, detail);
|
|
239
|
+
const pending = (await ctx.deps.gatewayRestarts.schedule(notification.id, scope.profile, detail));
|
|
240
|
+
if (pending !== notification.id)
|
|
241
|
+
(await ctx.deps.updateNotifications.watch(scope, pending));
|
|
242
|
+
return { ...result, notification_id: pending };
|
|
94
243
|
}
|
|
95
244
|
else {
|
|
96
245
|
// A kept Agent stash needs the user's attention; its recovery commands ride on the success record.
|
|
97
|
-
ctx.deps.updateNotifications.transition(notification.id, 'succeeded', null, verifiedIdentity, result.stash_conflict === true ? result.message : undefined);
|
|
246
|
+
await ctx.deps.updateNotifications.transition(notification.id, 'succeeded', null, verifiedIdentity, result.stash_conflict === true ? result.message : undefined);
|
|
98
247
|
}
|
|
99
248
|
return { ...result, notification_id: notification.id };
|
|
100
249
|
}
|
|
101
250
|
catch (error) {
|
|
102
|
-
ctx.deps.updateNotifications.transition(notification.id, 'failed', null, undefined, error instanceof Error ? error.message : null);
|
|
251
|
+
await ctx.deps.updateNotifications.transition(notification.id, 'failed', null, undefined, error instanceof Error ? error.message : null);
|
|
103
252
|
throw error;
|
|
104
253
|
}
|
|
105
254
|
}
|
|
@@ -177,10 +326,10 @@ export function sanitizeClientEvent(payload) {
|
|
|
177
326
|
out.event = 'unknown';
|
|
178
327
|
return out;
|
|
179
328
|
}
|
|
180
|
-
function memoryWorkspace(ctx, sessionId, workspace) {
|
|
329
|
+
async function memoryWorkspace(ctx, sessionId, workspace) {
|
|
181
330
|
if (sessionId) {
|
|
182
331
|
try {
|
|
183
|
-
const session = ctx.deps.sessionStore.get(sessionId, { metadataOnly: true });
|
|
332
|
+
const session = (await ctx.deps.sessionStore.get(sessionId, { metadataOnly: true }));
|
|
184
333
|
if (!ctx.deps.workspaces.profileSupportsLocalIo(session.profile))
|
|
185
334
|
return null;
|
|
186
335
|
const ws = str(session.workspace).trim();
|
|
@@ -193,17 +342,49 @@ function memoryWorkspace(ctx, sessionId, workspace) {
|
|
|
193
342
|
const profile = activeProfileName(ctx);
|
|
194
343
|
if (!ctx.deps.workspaces.profileSupportsLocalIo(profile))
|
|
195
344
|
return null;
|
|
196
|
-
const raw = workspace || (ctx.deps.config.env.TERMINAL_CWD ?? '') || ctx.deps.workspaces.lastWorkspace(profile);
|
|
345
|
+
const raw = workspace || (ctx.deps.config.env.TERMINAL_CWD ?? '') || (await ctx.deps.workspaces.lastWorkspace(profile));
|
|
197
346
|
if (!raw)
|
|
198
347
|
return null;
|
|
199
348
|
try {
|
|
200
|
-
return ctx.deps.workspaces.resolveTrusted(raw, profile);
|
|
349
|
+
return (await ctx.deps.workspaces.resolveTrusted(raw, profile));
|
|
201
350
|
}
|
|
202
351
|
catch {
|
|
203
352
|
return null;
|
|
204
353
|
}
|
|
205
354
|
}
|
|
355
|
+
/** The external notes drawer's Joplin access; 404 while the drawer is disabled. */
|
|
356
|
+
async function joplinDeps(ctx, disabled) {
|
|
357
|
+
const config = await ctx.deps.agentConfig.read(home(ctx));
|
|
358
|
+
if (!externalNotesEnabled(ctx.deps.config.env, config))
|
|
359
|
+
throw new HttpError(404, 'External notes sources are disabled.', { source: 'disabled', ...disabled });
|
|
360
|
+
return { config, env: ctx.deps.config.env, fetch: ctx.deps.fetch, redact: ctx.deps.sessions.deps.redactEnabled() };
|
|
361
|
+
}
|
|
362
|
+
/** A Joplin failure answers 502 with its fixed message. */
|
|
363
|
+
async function joplin(extra, fn) {
|
|
364
|
+
try {
|
|
365
|
+
return await fn();
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
if (error instanceof JoplinError)
|
|
369
|
+
throw new HttpError(502, error.message, { source: 'joplin', ...extra });
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/** Python `int(limit or 20)`, falling back to 20 for anything unparseable or zero. */
|
|
374
|
+
const notesLimit = (raw) => (/^\s*[+-]?\d+\s*$/.test(raw ?? '') ? Number.parseInt(String(raw).trim(), 10) : 0) || 20;
|
|
375
|
+
/** The wiki root for the active profile; an unreadable config.yaml falls through to the default. */
|
|
376
|
+
async function wikiLocation(ctx) {
|
|
377
|
+
const profileHome = home(ctx);
|
|
378
|
+
const config = await ctx.deps.agentConfig.read(profileHome).catch(() => ({}));
|
|
379
|
+
return resolveWikiLocation(ctx.deps.config.env, profileHome, config, ctx.deps.config.homeDir);
|
|
380
|
+
}
|
|
381
|
+
/** TAL-819: the Agent's review handler per write; its message can quote the entry text an approval replaced or removed. */
|
|
382
|
+
async function reviewPendingWrites(ctx, verb, input) {
|
|
383
|
+
const { results } = await runningSidecar(ctx).call(`write_approval.${verb}`, { profile_home: home(ctx), kind: input.kind, writes: input.writes });
|
|
384
|
+
return { results: results.map((r) => ({ ...r, message: redactString(r.message, ctx.deps.sessions.deps.redactEnabled()) })) };
|
|
385
|
+
}
|
|
206
386
|
export const toolsRouter = os.router({
|
|
387
|
+
toolsetsCatalog: os.toolsetsCatalog.handler(({ input, context: { ctx } }) => run(() => runningSidecar(ctx).call('toolsets.catalog', { profile_home: home(ctx), enabled_toolsets: input.toolsets }))),
|
|
207
388
|
skills: {
|
|
208
389
|
list: os.skills.list.handler(({ input, context: { ctx } }) => run(async () => ({ skills: await ctx.deps.skills.list(home(ctx), str(input.category).trim() || null) }))),
|
|
209
390
|
usage: os.skills.usage.handler(({ context: { ctx } }) => run(() => ctx.deps.skills.usage(home(ctx)))),
|
|
@@ -234,14 +415,31 @@ export const toolsRouter = os.router({
|
|
|
234
415
|
memory: {
|
|
235
416
|
get: os.memory.get.handler(({ input, context: { ctx } }) => run(async () => {
|
|
236
417
|
const config = await ctx.deps.agentConfig.read(home(ctx));
|
|
237
|
-
return readMemory(home(ctx), config, memoryWorkspace(ctx, str(input.session_id), str(input.workspace)), ctx.deps.config.env, ctx.deps.sessions.deps.redactEnabled());
|
|
418
|
+
return readMemory(home(ctx), config, (await memoryWorkspace(ctx, str(input.session_id), str(input.workspace))), ctx.deps.config.env, ctx.deps.sessions.deps.redactEnabled(), ctx.deps.auth.signingKey());
|
|
238
419
|
})),
|
|
239
420
|
write: os.memory.write.handler(({ input, context: { ctx } }) => run(async () => {
|
|
240
421
|
const section = input.section ?? input.target;
|
|
241
422
|
if (section === undefined || input.content === undefined)
|
|
242
423
|
throw new HttpError(400, 'Missing required field(s): section, content');
|
|
243
|
-
|
|
424
|
+
const profileHome = home(ctx);
|
|
425
|
+
return writeMemory(profileHome, await ctx.deps.agentConfig.read(profileHome), str(section), str(input.content), input.revision, {
|
|
426
|
+
key: ctx.deps.auth.signingKey(),
|
|
427
|
+
check: (target, content) => runningSidecar(ctx).call('memory.check', { profile_home: profileHome, target, content }),
|
|
428
|
+
write: (target, base, content) => runningSidecar(ctx).call('memory.write', { profile_home: profileHome, section: target, base, content }),
|
|
429
|
+
});
|
|
430
|
+
})),
|
|
431
|
+
},
|
|
432
|
+
pendingWrites: {
|
|
433
|
+
list: os.pendingWrites.list.handler(({ input, context: { ctx } }) => run(async () => {
|
|
434
|
+
// Without the Agent nothing can be reviewed, so the page shows no panel (the Agent's own status reports it down).
|
|
435
|
+
const sidecar = ctx.deps.sidecar();
|
|
436
|
+
const { enabled, items } = sidecar ? await sidecar.call('write_approval.pending', { profile_home: home(ctx), kind: input.kind }) : { enabled: false, items: [] };
|
|
437
|
+
const redact = (text) => redactString(text, ctx.deps.sessions.deps.redactEnabled());
|
|
438
|
+
// Display text is redacted like the memory page; `revision` stays the sidecar's hash of the raw diff it rechecks.
|
|
439
|
+
return { kind: input.kind, visible: items.length > 0, enabled, items: items.map((item) => ({ ...item, summary: redact(item.summary), diff: redact(item.diff) })) };
|
|
244
440
|
})),
|
|
441
|
+
approve: os.pendingWrites.approve.handler(({ input, context: { ctx } }) => run(() => reviewPendingWrites(ctx, 'approve', input))),
|
|
442
|
+
reject: os.pendingWrites.reject.handler(({ input, context: { ctx } }) => run(() => reviewPendingWrites(ctx, 'reject', input))),
|
|
245
443
|
},
|
|
246
444
|
prompts: {
|
|
247
445
|
list: os.prompts.list.handler(({ context: { ctx } }) => run(() => ({ prompts: loadPrompts(home(ctx)) }))),
|
|
@@ -263,20 +461,51 @@ export const toolsRouter = os.router({
|
|
|
263
461
|
const command = str(input.command).trim();
|
|
264
462
|
if (!command)
|
|
265
463
|
throw new HttpError(400, 'command is required');
|
|
464
|
+
const [, name = '', args = ''] = /^\/?(\S*)\s*([\s\S]*)$/.exec(command) ?? [];
|
|
465
|
+
const sessionId = str(input.session_id).trim();
|
|
466
|
+
if (sessionId)
|
|
467
|
+
(await ctx.deps.sessions.assertWritable(sessionId));
|
|
468
|
+
// TAL-902: a session command runs on the chat's own agent (the request guard already checked the chat's profile).
|
|
469
|
+
if (SESSION_EXEC_COMMANDS.has(name.toLowerCase())) {
|
|
470
|
+
return { output: await ctx.deps.turns.refine(sessionId ? (await ctx.deps.sessionStore.get(sessionId)) : null, args.trim()) };
|
|
471
|
+
}
|
|
472
|
+
// TAL-904: a chat's command runs under that chat's session and the workspace its next turn would use. An unknown
|
|
473
|
+
// chat (404) or a workspace that turn would refuse (400) refuses the command rather than run it half-bound.
|
|
474
|
+
const chat = sessionId ? { session_id: sessionId, workspace: (await ctx.deps.sessions.turnWorkspace((await ctx.deps.sessionStore.get(sessionId, { metadataOnly: true })))) } : {};
|
|
475
|
+
try {
|
|
476
|
+
return { output: (await runningSidecar(ctx).call('commands.exec', { profile_home: home(ctx), command, ...chat }, { timeoutMs: 120_000 })).output };
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
return commandFailure(error, 'command_not_found', 'Plugin command not found');
|
|
480
|
+
}
|
|
481
|
+
})),
|
|
482
|
+
bundles: os.commands.bundles.handler(({ context: { ctx } }) => run(async () => {
|
|
266
483
|
const sidecar = ctx.deps.sidecar();
|
|
267
|
-
if (!sidecar)
|
|
268
|
-
throw new HttpError(503, 'Hermes Agent sidecar is not running');
|
|
269
484
|
try {
|
|
270
|
-
return {
|
|
485
|
+
return { bundles: sidecar ? (await sidecar.call('commands.bundles', { profile_home: home(ctx) })).bundles : [] };
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
return { bundles: [] };
|
|
489
|
+
}
|
|
490
|
+
})),
|
|
491
|
+
resolveBundle: os.commands.resolveBundle.handler(({ input, context: { ctx } }) => run(async () => {
|
|
492
|
+
const command = str(input.command).trim();
|
|
493
|
+
if (!command)
|
|
494
|
+
throw new HttpError(400, 'command is required');
|
|
495
|
+
try {
|
|
496
|
+
return await runningSidecar(ctx).call('commands.bundle_resolve', { profile_home: home(ctx), command }, { timeoutMs: 120_000 });
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
return commandFailure(error, 'bundle_not_found', 'Bundle command not found');
|
|
500
|
+
}
|
|
501
|
+
})),
|
|
502
|
+
resolveMoa: os.commands.resolveMoa.handler(({ input, context: { ctx } }) => run(async () => {
|
|
503
|
+
try {
|
|
504
|
+
return (await runningSidecar(ctx).call('commands.moa_preset', { profile_home: home(ctx), preset: str(input.preset).trim() || null })).moa;
|
|
271
505
|
}
|
|
272
506
|
catch (error) {
|
|
273
|
-
if (error instanceof SidecarError)
|
|
274
|
-
|
|
275
|
-
throw new HttpError(404, 'Plugin command not found');
|
|
276
|
-
if (error.condition === 'invalid_params' || error.code === -32602)
|
|
277
|
-
throw new HttpError(400, error.message);
|
|
278
|
-
throw new HttpError(500, error.message);
|
|
279
|
-
}
|
|
507
|
+
if (error instanceof SidecarError && error.condition === 'moa_unavailable')
|
|
508
|
+
throw new HttpError(503, error.message);
|
|
280
509
|
throw error;
|
|
281
510
|
}
|
|
282
511
|
})),
|
|
@@ -287,17 +516,30 @@ export const toolsRouter = os.router({
|
|
|
287
516
|
return notesSources(config, externalNotesEnabled(ctx.deps.config.env, config));
|
|
288
517
|
})),
|
|
289
518
|
search: os.notes.search.handler(({ input, context: { ctx } }) => run(async () => {
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
519
|
+
const deps = await joplinDeps(ctx, { results: [] });
|
|
520
|
+
const source = str(input.source).trim().toLowerCase() || 'joplin';
|
|
521
|
+
const query = str(input.q).trim();
|
|
522
|
+
if (source !== 'joplin')
|
|
523
|
+
throw new HttpError(400, 'Search is currently implemented for Joplin sources only.', { source, results: [] });
|
|
524
|
+
return { source: 'joplin', query, results: await joplin({ query, results: [] }, () => joplinSearch(deps, query, notesLimit(input.limit))) };
|
|
525
|
+
})),
|
|
526
|
+
item: os.notes.item.handler(({ input, context: { ctx } }) => run(async () => {
|
|
527
|
+
const deps = await joplinDeps(ctx, {});
|
|
528
|
+
const source = str(input.source).trim().toLowerCase() || 'joplin';
|
|
529
|
+
if (source !== 'joplin')
|
|
530
|
+
throw new HttpError(400, 'Preview is currently implemented for Joplin sources only.', { source });
|
|
531
|
+
return { source: 'joplin', note: await joplin({}, () => joplinNote(deps, str(input.id))) };
|
|
295
532
|
})),
|
|
296
533
|
},
|
|
297
|
-
|
|
534
|
+
wiki: {
|
|
535
|
+
status: os.wiki.status.handler(({ context: { ctx } }) => run(async () => wikiPages.status(await wikiLocation(ctx)))),
|
|
536
|
+
browse: os.wiki.browse.handler(({ context: { ctx } }) => run(async () => wikiPages.browse(await wikiLocation(ctx)))),
|
|
537
|
+
page: os.wiki.page.handler(({ input, context: { ctx } }) => run(async () => wikiPages.page(await wikiLocation(ctx), str(input.path)))),
|
|
538
|
+
},
|
|
539
|
+
insights: os.insights.handler(({ input, context: { ctx } }) => run(async () => {
|
|
298
540
|
let entries = [];
|
|
299
541
|
try {
|
|
300
|
-
entries = ctx.deps.sessionStore.readIndexEntries();
|
|
542
|
+
entries = (await ctx.deps.sessionStore.readIndexEntries());
|
|
301
543
|
}
|
|
302
544
|
catch {
|
|
303
545
|
entries = [];
|
|
@@ -306,13 +548,13 @@ export const toolsRouter = os.router({
|
|
|
306
548
|
})),
|
|
307
549
|
logs: os.logs.handler(({ input, context: { ctx } }) => run(() => readLogTail(home(ctx), input.file, input.tail))),
|
|
308
550
|
ops: {
|
|
309
|
-
agent: os.ops.agent.handler(({ context: { ctx } }) => run(() =>
|
|
551
|
+
agent: os.ops.agent.handler(({ context: { ctx } }) => run(async () => { const [gateway, chat] = await Promise.all([health(ctx), currentChatReadiness(ctx.deps.sidecar())]); return { ...gateway, chat }; })),
|
|
310
552
|
system: os.ops.system.handler(({ context: { ctx } }) => run(() => systemHealth(ctx.deps.config.homeDir, ctx.deps.runtimeDiagnostics()))),
|
|
311
553
|
restart: os.ops.restart.handler(({ context: { ctx } }) => run(async () => {
|
|
312
554
|
const sidecar = ctx.deps.sidecar();
|
|
313
555
|
if (!sidecar)
|
|
314
556
|
throw new HttpError(500, 'Hermes Agent sidecar is not running');
|
|
315
|
-
const outcome = await sidecar
|
|
557
|
+
const outcome = await restartGateway(sidecar, home(ctx));
|
|
316
558
|
if (outcome.status === 'completed')
|
|
317
559
|
return { ok: true, message: 'Gateway service restarted successfully' };
|
|
318
560
|
if (outcome.status === 'busy')
|
|
@@ -320,12 +562,34 @@ export const toolsRouter = os.router({
|
|
|
320
562
|
throw new HttpError(500, outcome.message || 'Internal error running restart');
|
|
321
563
|
})),
|
|
322
564
|
dashboard: os.ops.dashboard.handler(({ context: { ctx } }) => run(async () => { const config = await ctx.deps.agentConfig.read(home(ctx)).catch(() => ({})); return dashboardStatus(config, ctx.deps.config.env, ctx.deps.fetch); })),
|
|
565
|
+
dashboardConfig: os.ops.dashboardConfig.handler(({ context: { ctx } }) => run(async () => dashboardConfig(await ctx.deps.agentConfig.read(home(ctx)).catch(() => ({}))))),
|
|
566
|
+
saveDashboardConfig: os.ops.saveDashboardConfig.handler(({ input, context: { ctx } }) => run(async () => {
|
|
567
|
+
const next = parseDashboardConfig(input);
|
|
568
|
+
await ctx.deps.agentConfig.update(home(ctx), (config) => { applyDashboardConfig(config, next); });
|
|
569
|
+
return next;
|
|
570
|
+
})),
|
|
571
|
+
projectOs: os.ops.projectOs.handler(({ input, context: { ctx } }) => run(async () => {
|
|
572
|
+
const profile = activeProfileName(ctx);
|
|
573
|
+
return projectOsDashboard(str(input.board), {
|
|
574
|
+
localIo: ctx.deps.workspaces.profileSupportsLocalIo(profile),
|
|
575
|
+
lastWorkspace: (await ctx.deps.workspaces.lastWorkspace(profile)),
|
|
576
|
+
boards: async () => (await runningSidecar(ctx).call('kanban.boards', { profile_home: home(ctx), include_archived: true })).boards,
|
|
577
|
+
git: async (repoRoot) => gitBadge(await ctx.deps.git.status(repoRoot, { useCache: true })),
|
|
578
|
+
cwd: process.cwd(),
|
|
579
|
+
});
|
|
580
|
+
})),
|
|
323
581
|
shutdown: os.ops.shutdown.handler(({ context: { ctx } }) => run(() => {
|
|
324
582
|
ctx.deps.log(`[shutdown-request] remote=${ctx.peer || 'unknown'} method=${ctx.method} path=${ctx.path.slice(0, 240)} ua=${(ctx.header('user-agent') ?? 'no-ua').replace(/[\x00-\x1f\x7f]+/g, '?').slice(0, 240)}`);
|
|
325
583
|
ctx.deps.requestShutdown();
|
|
326
584
|
return { status: 'shutting_down' };
|
|
327
585
|
})),
|
|
328
586
|
},
|
|
587
|
+
gateway: {
|
|
588
|
+
status: os.gateway.status.handler(({ context: { ctx } }) => run(() => currentGatewayStatus(ctx))),
|
|
589
|
+
start: os.gateway.start.handler(({ context: { ctx } }) => run(() => gatewayAction(ctx, 'start'))),
|
|
590
|
+
stop: os.gateway.stop.handler(({ context: { ctx } }) => run(() => gatewayAction(ctx, 'stop'))),
|
|
591
|
+
restart: os.gateway.restart.handler(({ context: { ctx } }) => run(() => gatewayAction(ctx, 'restart'))),
|
|
592
|
+
},
|
|
329
593
|
mcp: {
|
|
330
594
|
servers: os.mcp.servers.handler(({ context: { ctx } }) => run(() => ctx.deps.mcp.servers(home(ctx)))),
|
|
331
595
|
tools: os.mcp.tools.handler(({ input, context: { ctx } }) => run(() => ctx.deps.mcp.tools(home(ctx), input.q))),
|
|
@@ -342,9 +606,48 @@ export const toolsRouter = os.router({
|
|
|
342
606
|
update: os.mcp.update.handler(({ input, context: { ctx } }) => run(() => { const { name, ...body } = input; return ctx.deps.mcp.update(home(ctx), decodeURIComponent(name), body); })),
|
|
343
607
|
delete: os.mcp.delete.handler(({ input, context: { ctx } }) => run(() => ctx.deps.mcp.delete(home(ctx), decodeURIComponent(input.name)))),
|
|
344
608
|
},
|
|
609
|
+
connectors: {
|
|
610
|
+
// Fails closed: no sidecar, or one that cannot answer, hides the page.
|
|
611
|
+
available: os.connectors.available.handler(({ context: { ctx } }) => run(async () => ({ available: ctx.deps.sidecar() ? await connectorCall(ctx, 'connectors.available', {}).then((r) => r.available, () => false) : false }))),
|
|
612
|
+
page: os.connectors.page.handler(({ context: { ctx } }) => run(async () => {
|
|
613
|
+
if (!ctx.deps.sidecar() || !(await connectorCall(ctx, 'connectors.available', {})).available)
|
|
614
|
+
return { available: false, connectors: [], policy_revision: null, rules_error: null };
|
|
615
|
+
const [catalog, accounts, policy] = await Promise.all([connectorCall(ctx, 'connectors.catalog', {}), connectorCall(ctx, 'connectors.accounts', {}), connectorPolicy(ctx)]);
|
|
616
|
+
rememberCatalogNames(home(ctx), catalog.connectors);
|
|
617
|
+
return connectorsPage(catalog.connectors, accounts.accounts, policy.policy, policy.error);
|
|
618
|
+
})),
|
|
619
|
+
tools: os.connectors.tools.handler(({ input, context: { ctx } }) => run(async () => {
|
|
620
|
+
const [listing, policy] = await Promise.all([connectorCall(ctx, 'connectors.tools', { connector: input.connector }), connectorPolicy(ctx)]);
|
|
621
|
+
return connectorTools(listing, policy.policy);
|
|
622
|
+
})),
|
|
623
|
+
setPolicy: os.connectors.setPolicy.handler(({ input, context: { ctx } }) => run(async () => {
|
|
624
|
+
const change = input.tool === undefined ? (typeof input.enabled === 'boolean' ? { enabled: input.enabled } : null)
|
|
625
|
+
: typeof input.tool_enabled === 'boolean' && input.enabled === undefined ? { tool: input.tool, tool_enabled: input.tool_enabled } : null;
|
|
626
|
+
if (!change)
|
|
627
|
+
throw new HttpError(400, 'Send `enabled`, or `tool` with `tool_enabled`.', { code: 'policy_invalid' });
|
|
628
|
+
const { revision } = await connectorCall(ctx, 'connectors.policy.set', { connector: input.connector, expected_revision: input.revision, ...change });
|
|
629
|
+
return { ok: true, revision };
|
|
630
|
+
})),
|
|
631
|
+
connect: os.connectors.connect.handler(({ input, context: { ctx } }) => run(async () => operationView(ctx, await connectorCall(ctx, 'connectors.connect', { connector: input.connector })))),
|
|
632
|
+
removeAccount: os.connectors.removeAccount.handler(({ input, context: { ctx } }) => run(async () => {
|
|
633
|
+
await connectorCall(ctx, 'connectors.remove', { connection_id: input.connection_id });
|
|
634
|
+
return { ok: true };
|
|
635
|
+
})),
|
|
636
|
+
operation: os.connectors.operation.handler(({ input, context: { ctx } }) => run(async () => operationView(ctx, await connectorCall(ctx, 'connectors.operation', { op_id: input.op_id })))),
|
|
637
|
+
respond: os.connectors.respond.handler(({ input, context: { ctx } }) => run(async () => {
|
|
638
|
+
// Only a move the operation offers now reaches the Agent: the view decides, the sidecar applies.
|
|
639
|
+
const view = connectorOperation(await connectorCall(ctx, 'connectors.operation', { op_id: input.op_id }));
|
|
640
|
+
const { action } = input;
|
|
641
|
+
const offered = action === 'continue' ? view.can_continue : view.targets.some((t) => t.name === input.target && t.actions.includes(action));
|
|
642
|
+
if (!offered)
|
|
643
|
+
throw new HttpError(409, 'That move is not open on this connection.', { code: 'operation_refused' });
|
|
644
|
+
return operationView(ctx, await connectorCall(ctx, 'connectors.respond', { op_id: input.op_id, action, ...(input.target ? { target: input.target } : {}), ...(input.env ? { env: input.env } : {}) }));
|
|
645
|
+
})),
|
|
646
|
+
},
|
|
345
647
|
plugins: os.plugins.handler(({ context: { ctx } }) => run(async () => {
|
|
346
648
|
const sidecar = ctx.deps.sidecar();
|
|
347
649
|
const hooks = ['pre_tool_call', 'post_tool_call', 'pre_llm_call', 'post_llm_call'];
|
|
650
|
+
const editable = await sessionCanManageServer(ctx, await ensureTrustedAuthSession(ctx));
|
|
348
651
|
if (!sidecar)
|
|
349
652
|
return { plugins: [], empty: true, supported_hooks: hooks, read_only: true, unavailable: true };
|
|
350
653
|
try {
|
|
@@ -354,22 +657,80 @@ export const toolsRouter = os.router({
|
|
|
354
657
|
if (v && typeof v === 'object' && !Array.isArray(v) && typeof v.provider === 'string')
|
|
355
658
|
selected[k] = str(v.provider).trim().toLowerCase();
|
|
356
659
|
const result = await sidecar.call('plugins.list', { profile_home: home(ctx), selected_providers: selected });
|
|
357
|
-
|
|
660
|
+
// A settings failure leaves the list itself readable.
|
|
661
|
+
const declared = await pluginSettingsList(ctx).catch((error) => { ctx.deps.log(`[plugins] settings fields failed: ${str(error.message)}`); return []; });
|
|
662
|
+
const settings = new Map(declared.map((entry) => [entry.key, entry.fields]));
|
|
663
|
+
const plugins = result.plugins.map((plugin) => settings.has(plugin.key) ? { ...plugin, settings: settings.get(plugin.key) } : plugin);
|
|
664
|
+
// An advisory failure leaves the list itself readable.
|
|
665
|
+
const advisory = await pluginIsolationAdvisory(ctx).catch((error) => { ctx.deps.log(`[plugins] isolation advisory failed: ${str(error.message)}`); return false; });
|
|
666
|
+
return { plugins, empty: plugins.length === 0, supported_hooks: result.supported_hooks, read_only: !editable, plugin_isolation_advisory: advisory };
|
|
358
667
|
}
|
|
359
668
|
catch (error) {
|
|
360
669
|
ctx.deps.log(`[plugins] visibility payload failed: ${str(error.message)}`);
|
|
361
670
|
return { plugins: [], empty: true, supported_hooks: hooks, read_only: true, unavailable: true };
|
|
362
671
|
}
|
|
363
672
|
})),
|
|
673
|
+
pluginSettings: os.pluginSettings.handler(({ input, context: { ctx } }) => run(() => serializePluginSettingsSave(async () => {
|
|
674
|
+
const sidecar = runningSidecar(ctx);
|
|
675
|
+
const fields = (await pluginSettingsList(ctx)).find((entry) => entry.key === input.key)?.fields;
|
|
676
|
+
if (!fields)
|
|
677
|
+
throw new HttpError(404, `Plugin '${input.key}' declares no settings`);
|
|
678
|
+
let plan;
|
|
679
|
+
try {
|
|
680
|
+
plan = planPluginSettings(fields, input.values ?? {}, input.secrets ?? {});
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
if (error instanceof PluginSettingsInvalid)
|
|
684
|
+
throw new HttpError(400, error.message);
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
const secretFields = fields.filter((field) => field.env && field.env in plan.secrets);
|
|
688
|
+
// Secrets never reach config.yaml: each goes to the profile `.env` under the name the manifest field declares. They are
|
|
689
|
+
// written first and restored if a later write fails, so a refused save changes neither file. The save call always runs:
|
|
690
|
+
// it resolves the plugin again and refuses (before writing) when a secret's `.env` name no longer matches its manifest.
|
|
691
|
+
const credential = (envVar, value) => writeRuntimeCredential({ env: ctx.deps.config.env, sidecar: ctx.deps.sidecar, log: ctx.deps.log }, ctx.deps.isRootProfile(activeProfileName(ctx)), home(ctx), envVar, value);
|
|
692
|
+
const previous = loadEnvFile(join(home(ctx), '.env'));
|
|
693
|
+
const applied = [];
|
|
694
|
+
let result;
|
|
695
|
+
try {
|
|
696
|
+
for (const [envVar, value] of Object.entries(plan.secrets)) {
|
|
697
|
+
await credential(envVar, value);
|
|
698
|
+
applied.push(envVar);
|
|
699
|
+
}
|
|
700
|
+
result = await sidecar.call('plugins.settings_save', { profile_home: home(ctx), key: input.key, values: plan.values, secret_envs: Object.fromEntries(secretFields.map((field) => [field.key, field.env])) });
|
|
701
|
+
}
|
|
702
|
+
catch (error) {
|
|
703
|
+
if (!definitiveRefusal(error)) {
|
|
704
|
+
throw new HttpError(503, 'The Agent sidecar stopped before confirming the save, so it may be partly applied; reload Settings to see what was saved', { condition: 'plugin_settings_unconfirmed' });
|
|
705
|
+
}
|
|
706
|
+
for (const envVar of applied.reverse()) {
|
|
707
|
+
await credential(envVar, previous[envVar] ?? null).catch((restore) => { ctx.deps.log(`[plugins] could not restore ${envVar} after a failed settings save: ${str(restore.message)}`); });
|
|
708
|
+
}
|
|
709
|
+
if (error instanceof SidecarError && error.condition === 'plugin_settings_managed')
|
|
710
|
+
throw new HttpError(403, error.message, { condition: error.condition });
|
|
711
|
+
if (error instanceof SidecarError && error.condition === 'plugin_settings_changed')
|
|
712
|
+
throw new HttpError(409, `${error.message}; reload and try again`, { condition: error.condition });
|
|
713
|
+
if (error instanceof SidecarError && error.condition === 'plugin_not_found')
|
|
714
|
+
throw new HttpError(404, error.message);
|
|
715
|
+
if (error instanceof SidecarError && error.code === -32602)
|
|
716
|
+
throw new HttpError(400, error.message);
|
|
717
|
+
if (error instanceof RuntimeCredentialError)
|
|
718
|
+
throw new HttpError(503, error.message);
|
|
719
|
+
if (error instanceof EnvWriteError)
|
|
720
|
+
throw new HttpError(error.status, `Failed to save a secret: ${error.message}`, { condition: error.condition });
|
|
721
|
+
throw error;
|
|
722
|
+
}
|
|
723
|
+
return { ok: true, key: result.key, written: [...result.written, ...secretFields.map((field) => field.key)], settings: pluginSettingsFieldsView(ctx, result.fields) };
|
|
724
|
+
}))),
|
|
364
725
|
updates: {
|
|
365
|
-
check: os.updates.check.handler(({ context: { ctx } }) => run(() => {
|
|
366
|
-
const settings = ctx.deps.settings.load();
|
|
726
|
+
check: os.updates.check.handler(({ context: { ctx } }) => run(async () => {
|
|
727
|
+
const settings = (await ctx.deps.settings.load());
|
|
367
728
|
if (settings.check_for_updates === false)
|
|
368
729
|
return updatesCheckView({ disabled: true });
|
|
369
730
|
return updatesCheckView(ctx.deps.updates.cachedStatus(!pyBool(settings.ignore_agent_updates)));
|
|
370
731
|
})),
|
|
371
732
|
checkNow: os.updates.checkNow.handler(({ input, context: { ctx } }) => run(async () => {
|
|
372
|
-
const settings = ctx.deps.settings.load();
|
|
733
|
+
const settings = (await ctx.deps.settings.load());
|
|
373
734
|
const force = pyBool(input.force);
|
|
374
735
|
if (settings.check_for_updates === false && !force)
|
|
375
736
|
return updatesCheckView({ disabled: true });
|
|
@@ -378,58 +739,83 @@ export const toolsRouter = os.router({
|
|
|
378
739
|
ctx.deps.log(`[updates] checking for updates (force=${String(force)}, channel=${channel})`);
|
|
379
740
|
return updatesCheckView(await ctx.deps.updates.check(force, !pyBool(settings.ignore_agent_updates), channel, input.agent_channel));
|
|
380
741
|
})),
|
|
381
|
-
apply: os.updates.apply.handler(({ input, context: { ctx } }) => run(() =>
|
|
382
|
-
force: os.updates.force.handler(({ input, context: { ctx } }) => run(() =>
|
|
383
|
-
clearLock: os.updates.clearLock.handler(({ input, context: { ctx } }) => run(() =>
|
|
384
|
-
summary: os.updates.summary.handler(({ input, context: { ctx } }) => run(() => ctx.deps.updates.summarize(input.
|
|
742
|
+
apply: os.updates.apply.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'apply'))),
|
|
743
|
+
force: os.updates.force.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'force'))),
|
|
744
|
+
clearLock: os.updates.clearLock.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'clearLock'))),
|
|
745
|
+
summary: os.updates.summary.handler(({ input, context: { ctx } }) => run(async () => ctx.deps.updates.summarize(input.target, (await ctx.deps.settings.load()).check_for_updates === false))),
|
|
385
746
|
},
|
|
386
747
|
updateNotifications: {
|
|
387
748
|
list: os.updateNotifications.list.handler(({ input, context: { ctx } }) => run(async () => {
|
|
388
749
|
const scope = await updateNotificationScope(ctx, input.tab_id);
|
|
389
|
-
const frontendBuild = ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId());
|
|
390
|
-
return { ...ctx.deps.updateNotifications.list(scope), frontend_build: frontendBuild };
|
|
750
|
+
const frontendBuild = (await ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId()));
|
|
751
|
+
return { ...(await ctx.deps.updateNotifications.list(scope)), frontend_build: frontendBuild };
|
|
391
752
|
})),
|
|
392
753
|
read: os.updateNotifications.read.handler(({ input, context: { ctx } }) => run(async () => {
|
|
393
|
-
const notification = ctx.deps.updateNotifications.read(await updateNotificationScope(ctx, input.tab_id), input.id);
|
|
754
|
+
const notification = (await ctx.deps.updateNotifications.read(await updateNotificationScope(ctx, input.tab_id), input.id));
|
|
394
755
|
if (!notification)
|
|
395
756
|
throw new HttpError(404, 'Update notification not found');
|
|
396
757
|
return notification;
|
|
397
758
|
})),
|
|
398
759
|
dismiss: os.updateNotifications.dismiss.handler(({ input, context: { ctx } }) => run(async () => {
|
|
399
|
-
const result = ctx.deps.updateNotifications.dismiss(await updateNotificationScope(ctx, input.tab_id), input.id);
|
|
760
|
+
const result = (await ctx.deps.updateNotifications.dismiss(await updateNotificationScope(ctx, input.tab_id), input.id));
|
|
400
761
|
if (result === 'acknowledgement_required')
|
|
401
762
|
throw new HttpError(409, 'This notification requires acknowledgement before it can be dismissed');
|
|
402
763
|
return { ok: true };
|
|
403
764
|
})),
|
|
404
765
|
clear: os.updateNotifications.clear.handler(({ input, context: { ctx } }) => run(async () => {
|
|
405
766
|
const scope = await updateNotificationScope(ctx, input.tab_id);
|
|
406
|
-
const frontendBuild = ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId());
|
|
407
|
-
return { ...ctx.deps.updateNotifications.clear(scope), frontend_build: frontendBuild };
|
|
767
|
+
const frontendBuild = (await ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId()));
|
|
768
|
+
return { ...(await ctx.deps.updateNotifications.clear(scope)), frontend_build: frontendBuild };
|
|
408
769
|
})),
|
|
409
770
|
cancel: os.updateNotifications.cancel.handler(({ input, context: { ctx } }) => run(async () => {
|
|
410
|
-
const notification = ctx.deps.updateNotifications.cancelUpdate(await updateNotificationScope(ctx), input.id);
|
|
771
|
+
const notification = (await ctx.deps.updateNotifications.cancelUpdate(await updateNotificationScope(ctx), input.id));
|
|
411
772
|
if (!notification)
|
|
412
773
|
throw new HttpError(404, 'Awaiting update notification not found');
|
|
413
774
|
return notification;
|
|
414
775
|
})),
|
|
415
776
|
action: os.updateNotifications.action.handler(({ input, context: { ctx } }) => run(async () => {
|
|
416
|
-
const notification = ctx.deps.updateNotifications.action(await updateNotificationScope(ctx, input.tab_id), input.id, input.action_id);
|
|
777
|
+
const notification = (await ctx.deps.updateNotifications.action(await updateNotificationScope(ctx, input.tab_id), input.id, input.action_id));
|
|
417
778
|
if (!notification)
|
|
418
779
|
throw new HttpError(404, 'Notification action not found');
|
|
780
|
+
if (input.action_id === GATEWAY_RESTART_NOW)
|
|
781
|
+
ctx.deps.gatewayRestarts.restartNow(notification.id);
|
|
419
782
|
return notification;
|
|
420
783
|
})),
|
|
421
784
|
},
|
|
422
785
|
transcribeCapability: os.transcribeCapability.handler(({ context: { ctx } }) => run(async () => {
|
|
786
|
+
const unavailable = { ok: true, available: false, provider: 'none', streaming: false, warm_supported: false };
|
|
423
787
|
const sidecar = ctx.deps.sidecar();
|
|
424
788
|
if (!sidecar)
|
|
425
|
-
return
|
|
789
|
+
return unavailable;
|
|
426
790
|
try {
|
|
427
791
|
const cap = await sidecar.call('stt.capability', { profile_home: home(ctx) });
|
|
428
|
-
return { ok: true, available: cap.available, provider: cap.provider || 'none' };
|
|
792
|
+
return { ok: true, available: cap.available, provider: cap.provider || 'none', streaming: cap.available && cap.streaming, warm_supported: cap.available && cap.warm_supported };
|
|
429
793
|
}
|
|
430
794
|
catch {
|
|
431
|
-
return
|
|
795
|
+
return unavailable;
|
|
796
|
+
}
|
|
797
|
+
})),
|
|
798
|
+
speech: {
|
|
799
|
+
prepare: os.speech.prepare.handler(({ input, context: { ctx } }) => run(async () => ({ spoken_text: await spokenText(ctx, input.text.trim()) }))),
|
|
800
|
+
},
|
|
801
|
+
transcribeWarm: os.transcribeWarm.handler(({ context: { ctx } }) => run(() => {
|
|
802
|
+
const sidecar = ctx.deps.sidecar();
|
|
803
|
+
const profileHome = home(ctx);
|
|
804
|
+
// One load per profile at a time: a record start during a running load joins it rather than holding another sidecar slot.
|
|
805
|
+
if (sidecar && !warmingHomes.has(profileHome)) {
|
|
806
|
+
warmingHomes.add(profileHome);
|
|
807
|
+
// The load outlives this request's write lease: it is the profile's activity until it settles, so the profile
|
|
808
|
+
// cannot be deleted under it. Taken while the request's lease still refuses a deletion in progress.
|
|
809
|
+
const release = ctx.deps.profileActivity(activeProfileName(ctx));
|
|
810
|
+
// A first use downloads the model, and the Agent's load cannot be cancelled, so the call has no deadline: the entry
|
|
811
|
+
// lives exactly as long as the sidecar worker (a sidecar exit rejects it). Nobody waits on it.
|
|
812
|
+
void sidecar.call('stt.warm', { profile_home: profileHome }, { timeoutMs: 0 })
|
|
813
|
+
.then((result) => { if (result.action === 'error')
|
|
814
|
+
ctx.deps.log(`[stt] warm-up failed (${result.provider}): ${str(result.error)}`); })
|
|
815
|
+
.catch((error) => { ctx.deps.log(`[stt] warm-up failed: ${str(error.message)}`); })
|
|
816
|
+
.finally(() => { warmingHomes.delete(profileHome); release(); });
|
|
432
817
|
}
|
|
818
|
+
return { ok: true };
|
|
433
819
|
})),
|
|
434
820
|
clientEvents: os.clientEvents.handler(({ input, context: { ctx } }) => run(() => {
|
|
435
821
|
if (ctx.deps.clientEventLimiter.limited(ctx.peer || 'unknown'))
|