@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
|
@@ -8,12 +8,13 @@ import json
|
|
|
8
8
|
import logging
|
|
9
9
|
import queue
|
|
10
10
|
import sqlite3
|
|
11
|
+
import threading
|
|
11
12
|
import time
|
|
12
13
|
from contextlib import closing
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
|
|
15
16
|
from ..errors import InvalidParams, RpcError
|
|
16
|
-
from ..home import profile_home_param, scoped_home
|
|
17
|
+
from ..home import _PROCESS_HOME, _is_named_profile, profile_home_param, scoped_home
|
|
17
18
|
from ..rpc import CallContext
|
|
18
19
|
|
|
19
20
|
log = logging.getLogger("talaria_sidecar.process")
|
|
@@ -27,11 +28,23 @@ def _registry():
|
|
|
27
28
|
return process_registry
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
def _is_child_process(row: dict) -> bool:
|
|
32
|
+
"""TAL-933: a subagent's own process notice, which the server surfaces only when the owning profile opts in."""
|
|
33
|
+
try:
|
|
34
|
+
from tools.process_registry_notifications import is_child_process_notification
|
|
35
|
+
except Exception: # noqa: BLE001 - before Agent 0.21.7, the same rule inline
|
|
36
|
+
if row.get("type") in ("async_delegation", "async_delegation_work_closeout"):
|
|
37
|
+
return False
|
|
38
|
+
return str(row.get("owner_task_id") or row.get("task_id") or "").startswith("sa-")
|
|
39
|
+
return bool(is_child_process_notification(row))
|
|
40
|
+
|
|
41
|
+
|
|
30
42
|
def _event_row(evt: dict) -> dict:
|
|
31
43
|
registry = _registry()
|
|
32
44
|
row = {str(k): v for k, v in evt.items()} if isinstance(evt, dict) else {}
|
|
33
45
|
process_id = str(row.get("delegation_id") or row.get("session_id") or row.get("task_id") or "") if row.get("type") == "async_delegation" else str(row.get("session_id") or "")
|
|
34
46
|
row["process_id"] = process_id
|
|
47
|
+
row["child_process"] = _is_child_process(row)
|
|
35
48
|
if registry is not None and process_id and (not row.get("session_key") or not row.get("origin_ui_session_id")):
|
|
36
49
|
try:
|
|
37
50
|
proc = registry.get(process_id)
|
|
@@ -42,26 +55,186 @@ def _event_row(evt: dict) -> dict:
|
|
|
42
55
|
if not row.get("origin_ui_session_id"):
|
|
43
56
|
row["origin_ui_session_id"] = str(getattr(proc, "origin_ui_session_id", "") or "") or str(getattr(proc, "spawn_session_id", "") or "")
|
|
44
57
|
try:
|
|
45
|
-
|
|
58
|
+
# Only the exit is consumed by the agent's wait or poll; a watch notice from the same process still wakes (TAL-724).
|
|
59
|
+
row["consumed"] = bool(registry is not None and process_id and row.get("type") in (None, "completion") and registry.is_completion_consumed(process_id))
|
|
46
60
|
except Exception: # noqa: BLE001
|
|
47
61
|
row["consumed"] = False
|
|
48
62
|
return row
|
|
49
63
|
|
|
50
64
|
|
|
65
|
+
# Recovered sessions, held so their exit is seen even when an Agent call other than drain prunes them first.
|
|
66
|
+
_RECOVERED: dict[str, object] = {}
|
|
67
|
+
_RECOVERED_LOCK = threading.Lock()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _reports_recovered_exits(registry) -> bool:
|
|
71
|
+
"""Agent 0.21.6 (hermes-agent 7550800d) closes or prunes a recovered session whose PID is gone without queuing a
|
|
72
|
+
completion, since it never collected an exit status. Talaria still wakes the session with an unknown exit code."""
|
|
73
|
+
return callable(getattr(registry, "_detached_host_fate", None)) and callable(getattr(registry, "_publish_finished", None))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def track_recovered(registry) -> None:
|
|
77
|
+
if not _reports_recovered_exits(registry):
|
|
78
|
+
return
|
|
79
|
+
try:
|
|
80
|
+
with registry._lock:
|
|
81
|
+
detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
|
|
82
|
+
except Exception: # noqa: BLE001 - recovery itself succeeded; only the exit report is lost
|
|
83
|
+
log.warning("Failed to track recovered processes", exc_info=True)
|
|
84
|
+
return
|
|
85
|
+
with _RECOVERED_LOCK:
|
|
86
|
+
_RECOVERED.update((s.id, s) for s in detached)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _publish_recovered_exits(registry) -> None:
|
|
90
|
+
with _RECOVERED_LOCK:
|
|
91
|
+
exited = [s for s in _RECOVERED.values() if s.exited]
|
|
92
|
+
for session in exited:
|
|
93
|
+
del _RECOVERED[session.id]
|
|
94
|
+
for session in exited:
|
|
95
|
+
# A kill (or any path that collected a status) already queued its own completion through _move_to_finished.
|
|
96
|
+
if session.exit_code is not None or getattr(session, "_finish_claimed", False):
|
|
97
|
+
continue
|
|
98
|
+
try:
|
|
99
|
+
# Best effort, as in the Agent: a durable result must not block the live completion.
|
|
100
|
+
from tools.process_registry_results import save_completed_result
|
|
101
|
+
|
|
102
|
+
save_completed_result(session)
|
|
103
|
+
except Exception: # noqa: BLE001
|
|
104
|
+
log.debug("Failed to retain the result of recovered process %s", session.id, exc_info=True)
|
|
105
|
+
try:
|
|
106
|
+
with registry._lock:
|
|
107
|
+
registry._running.pop(session.id, None)
|
|
108
|
+
session.exited_at = session.exited_at or time.time()
|
|
109
|
+
registry._finished[session.id] = session
|
|
110
|
+
registry._publish_finished(session, True)
|
|
111
|
+
except Exception: # noqa: BLE001 - retried on the next drain
|
|
112
|
+
log.warning("Failed to report the exit of recovered process %s", session.id, exc_info=True)
|
|
113
|
+
with _RECOVERED_LOCK:
|
|
114
|
+
_RECOVERED.setdefault(session.id, session)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
_COMPLETION_BASE_HOME: Path | None = None
|
|
118
|
+
_RESTORED_COMPLETION_HOMES: set[Path] = set()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _completion_homes() -> list[Path]:
|
|
122
|
+
from hermes_constants import get_hermes_home
|
|
123
|
+
from .profiles import named_profile_homes
|
|
124
|
+
|
|
125
|
+
homes = [_PROCESS_HOME, Path(get_hermes_home())]
|
|
126
|
+
if _COMPLETION_BASE_HOME is not None:
|
|
127
|
+
# The server drains one global queue. Re-enumerate so new profiles join and removed/escaped ones leave.
|
|
128
|
+
homes += [_COMPLETION_BASE_HOME, *(home for _, home in named_profile_homes(_COMPLETION_BASE_HOME))]
|
|
129
|
+
return list(dict.fromkeys(home.resolve() for home in homes))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _restore_and_sweep_completions(registry) -> None:
|
|
133
|
+
from tools import async_delegation
|
|
134
|
+
|
|
135
|
+
restore = getattr(registry, "restore_completions", None)
|
|
136
|
+
if not callable(restore):
|
|
137
|
+
return # Older Agents already restore at registry import and have no orphan sweep.
|
|
138
|
+
# The Agent binds the launch home itself, even when the first drain is in a named profile.
|
|
139
|
+
restore()
|
|
140
|
+
for home in _completion_homes():
|
|
141
|
+
try:
|
|
142
|
+
with scoped_home(home):
|
|
143
|
+
if _is_named_profile(home) and home not in _RESTORED_COMPLETION_HOMES:
|
|
144
|
+
async_delegation.restore_undelivered_completions(registry.completion_queue)
|
|
145
|
+
_RESTORED_COMPLETION_HOMES.add(home)
|
|
146
|
+
sweep = getattr(async_delegation, "maybe_sweep_orphaned_completions", None)
|
|
147
|
+
if callable(sweep):
|
|
148
|
+
sweep(registry.completion_queue)
|
|
149
|
+
except Exception: # noqa: BLE001 - retry this home without blocking other profiles or queued events
|
|
150
|
+
log.debug("Failed to restore or sweep delegation completions for %s", home, exc_info=True)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
_DELIVERY_RECONCILE_INTERVAL_S = 30
|
|
154
|
+
_LAST_DELIVERY_RECONCILE: dict[Path, float] = {}
|
|
155
|
+
_DELIVERY_RECONCILE_CURSOR: dict[Path, str] = {}
|
|
156
|
+
_DELIVERY_RECONCILE_PAGE_SIZE = 200
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _delivered_notifications(home: Path, delegation_id: str | None = None, after: str = "") -> tuple[list[dict], str]:
|
|
160
|
+
"""Only typed transcript deliveries, never every delivered ledger row. No Agent state is changed."""
|
|
161
|
+
db_path = home / "state.db"
|
|
162
|
+
if not db_path.exists():
|
|
163
|
+
return [], ""
|
|
164
|
+
with closing(sqlite3.connect(f"{db_path.resolve().as_uri()}?mode=ro", uri=True, timeout=5)) as conn:
|
|
165
|
+
tables = {r[0] for r in conn.execute("SELECT name FROM sqlite_master WHERE type='table'")}
|
|
166
|
+
if not {"async_delegations", "messages", "sessions"} <= tables:
|
|
167
|
+
return [], ""
|
|
168
|
+
rows = conn.execute("""WITH RECURSIVE candidates AS (
|
|
169
|
+
SELECT delegation_id, origin_ui_session_id, parent_session_id, origin_session_id, event_json
|
|
170
|
+
FROM async_delegations WHERE delivery_state='delivered' AND state NOT IN ('running','finalizing')
|
|
171
|
+
AND event_json IS NOT NULL AND origin_ui_session_id != '' AND delivered_at >= ?
|
|
172
|
+
AND (? IS NULL OR delegation_id=?) AND delegation_id > ?
|
|
173
|
+
), lineage(delegation_id, id) AS (
|
|
174
|
+
SELECT delegation_id, parent_session_id FROM candidates WHERE parent_session_id != ''
|
|
175
|
+
UNION SELECT delegation_id, origin_session_id FROM candidates WHERE origin_session_id != ''
|
|
176
|
+
UNION SELECT l.delegation_id, s.id FROM lineage l
|
|
177
|
+
JOIN sessions parent ON parent.id=l.id AND parent.end_reason='compression'
|
|
178
|
+
JOIN sessions s ON s.parent_session_id=l.id
|
|
179
|
+
) SELECT DISTINCT c.delegation_id, c.origin_ui_session_id, c.event_json
|
|
180
|
+
FROM candidates c JOIN lineage l ON l.delegation_id=c.delegation_id
|
|
181
|
+
JOIN messages m ON m.session_id=l.id
|
|
182
|
+
WHERE m.role='user' AND m.display_kind='async_delegation_complete'
|
|
183
|
+
AND json_valid(m.display_metadata)
|
|
184
|
+
AND json_extract(m.display_metadata, '$.delegation_id')=c.delegation_id
|
|
185
|
+
AND coalesce(json_extract(m.display_metadata, '$.delivery_notice'), '')=''
|
|
186
|
+
AND coalesce(json_extract(m.display_metadata, '$.presentation_suppressed'), 0)=0
|
|
187
|
+
ORDER BY c.delegation_id LIMIT ?""", (time.time() - 48 * 3600, delegation_id, delegation_id, after, _DELIVERY_RECONCILE_PAGE_SIZE)).fetchall()
|
|
188
|
+
events = []
|
|
189
|
+
for did, owner, payload in rows:
|
|
190
|
+
event = _json(payload)
|
|
191
|
+
if event.get("type") != "async_delegation" or event.get("delegation_id") != did or event.get("origin_ui_session_id") != owner or event.get("task_failure_notice"):
|
|
192
|
+
continue
|
|
193
|
+
events.append({**event, "reconciliation_profile_home": str(home.resolve())})
|
|
194
|
+
return events, rows[-1][0] if len(rows) == _DELIVERY_RECONCILE_PAGE_SIZE else ""
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _reconcile_delivered_notifications() -> list[dict]:
|
|
198
|
+
out = []
|
|
199
|
+
for home in _completion_homes():
|
|
200
|
+
now = time.monotonic()
|
|
201
|
+
if now - _LAST_DELIVERY_RECONCILE.get(home, -float("inf")) < _DELIVERY_RECONCILE_INTERVAL_S:
|
|
202
|
+
continue
|
|
203
|
+
try:
|
|
204
|
+
events, cursor = _delivered_notifications(home, after=_DELIVERY_RECONCILE_CURSOR.get(home, ""))
|
|
205
|
+
out.extend(events)
|
|
206
|
+
_DELIVERY_RECONCILE_CURSOR[home] = cursor
|
|
207
|
+
_LAST_DELIVERY_RECONCILE[home] = now
|
|
208
|
+
except Exception: # retry unreadable homes; never block live queue delivery
|
|
209
|
+
log.warning("Failed to reconcile typed delegation deliveries for %s", home, exc_info=True)
|
|
210
|
+
return out
|
|
211
|
+
|
|
212
|
+
|
|
51
213
|
def drain(max_events: int) -> list[dict]:
|
|
52
214
|
"""Pop every queued completion event; the server requeues what it does not own."""
|
|
53
215
|
registry = _registry()
|
|
54
216
|
completion_queue = getattr(registry, "completion_queue", None) if registry is not None else None
|
|
55
217
|
if completion_queue is None:
|
|
56
218
|
return []
|
|
219
|
+
try:
|
|
220
|
+
_restore_and_sweep_completions(registry)
|
|
221
|
+
except Exception: # noqa: BLE001 - maintenance must not prevent delivery of live queued events
|
|
222
|
+
log.debug("Failed to reconcile delegation completions", exc_info=True)
|
|
57
223
|
try:
|
|
58
224
|
# A recovered process has no reader thread; only this probe notices its exit and queues its completion (TAL-533).
|
|
59
225
|
with registry._lock:
|
|
60
226
|
detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
|
|
61
227
|
for session in detached:
|
|
62
228
|
registry._refresh_detached_session(session)
|
|
229
|
+
_publish_recovered_exits(registry)
|
|
63
230
|
except Exception: # noqa: BLE001
|
|
64
231
|
log.debug("Failed to reconcile recovered processes", exc_info=True)
|
|
232
|
+
# Use the existing queue and its bound, so reconciliation cannot starve live or foreign events.
|
|
233
|
+
try:
|
|
234
|
+
for event in _reconcile_delivered_notifications():
|
|
235
|
+
completion_queue.put_nowait(event)
|
|
236
|
+
except Exception:
|
|
237
|
+
log.warning("Failed to offer typed delegation deliveries", exc_info=True)
|
|
65
238
|
out = []
|
|
66
239
|
while len(out) < max_events:
|
|
67
240
|
try:
|
|
@@ -83,7 +256,7 @@ def requeue(events: list[dict]) -> int:
|
|
|
83
256
|
count = 0
|
|
84
257
|
for evt in events:
|
|
85
258
|
try:
|
|
86
|
-
completion_queue.put_nowait({k: v for k, v in evt.items() if k not in ("process_id", "consumed")})
|
|
259
|
+
completion_queue.put_nowait({k: v for k, v in evt.items() if k not in ("process_id", "consumed", "child_process")})
|
|
87
260
|
count += 1
|
|
88
261
|
except Exception: # noqa: BLE001
|
|
89
262
|
log.debug("Failed to requeue process completion", exc_info=True)
|
|
@@ -141,6 +314,15 @@ def claim_delivery(evt: dict, consumer: str) -> str | None:
|
|
|
141
314
|
if api is None:
|
|
142
315
|
return ""
|
|
143
316
|
claim_id = api.claim_event_delivery(_ledger_event(evt), consumer)
|
|
317
|
+
if claim_id is None and consumer == "webui" and evt.get("origin_ui_session_id"):
|
|
318
|
+
from hermes_constants import get_hermes_home
|
|
319
|
+
home = Path(get_hermes_home()).resolve()
|
|
320
|
+
if evt.get("reconciliation_profile_home", str(home)) == str(home):
|
|
321
|
+
# A live queue copy can race the transcript-only consumer too. Recheck the same proof here.
|
|
322
|
+
transport = {"process_id", "consumed", "child_process", "restored", "reconciliation_profile_home"}
|
|
323
|
+
for candidate in _delivered_notifications(home, str(evt.get("delegation_id") or ""))[0]:
|
|
324
|
+
if {k: v for k, v in candidate.items() if k not in transport} == {k: v for k, v in evt.items() if k not in transport}:
|
|
325
|
+
return "" # Web's session receipt acknowledges this admission, not the Agent ledger.
|
|
144
326
|
return None if claim_id is None else str(claim_id)
|
|
145
327
|
|
|
146
328
|
|
|
@@ -175,11 +357,14 @@ def defer_delivery(evt: dict, claim_id: str) -> bool:
|
|
|
175
357
|
|
|
176
358
|
|
|
177
359
|
def format_notification(evt: dict) -> str:
|
|
178
|
-
if evt.get("type")
|
|
360
|
+
if evt.get("type") in ("async_delegation", "heartbeat", "watch_match", "watch_disabled", "watch_overflow_tripped", "watch_overflow_released"):
|
|
179
361
|
try:
|
|
180
|
-
from tools
|
|
362
|
+
from tools import process_registry
|
|
181
363
|
|
|
182
|
-
|
|
364
|
+
# Older formatters fall through unknown events to an exit notification.
|
|
365
|
+
if evt.get("type") == "heartbeat" and not callable(getattr(getattr(process_registry, "ProcessRegistry", None), "_emit_heartbeat", None)):
|
|
366
|
+
return ""
|
|
367
|
+
return process_registry.format_process_notification(evt) or ""
|
|
183
368
|
except Exception: # noqa: BLE001
|
|
184
369
|
return ""
|
|
185
370
|
if evt.get("type") != "completion":
|
|
@@ -349,12 +534,21 @@ def _goal_text(content) -> str:
|
|
|
349
534
|
return ""
|
|
350
535
|
if content.startswith(_CONTENT_JSON_PREFIX):
|
|
351
536
|
try:
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
537
|
+
from hermes_state import SessionDB
|
|
538
|
+
decode = getattr(SessionDB, "_decode_content", None)
|
|
539
|
+
except ImportError:
|
|
540
|
+
decode = None
|
|
541
|
+
if callable(decode):
|
|
542
|
+
content = decode(content)
|
|
543
|
+
else:
|
|
544
|
+
try:
|
|
545
|
+
content = json.loads(content[len(_CONTENT_JSON_PREFIX):])
|
|
546
|
+
except ValueError:
|
|
547
|
+
pass # Legacy malformed marker rows remain literal text, as in the Agent.
|
|
548
|
+
if isinstance(content, list):
|
|
549
|
+
texts = [p.get("text") for p in content if isinstance(p, dict) and p.get("type") == "text"]
|
|
356
550
|
return str(texts[0]) if texts and texts[0] else ""
|
|
357
|
-
return content.split(_IMAGE_HINTS, 1)[0]
|
|
551
|
+
return content.split(_IMAGE_HINTS, 1)[0] if isinstance(content, str) else ""
|
|
358
552
|
|
|
359
553
|
|
|
360
554
|
def unit_children(unit: dict, owner: str, live: list[dict], finished: list[dict], now: float) -> list[dict]:
|
|
@@ -415,10 +609,11 @@ def recover(base_home: Path) -> int:
|
|
|
415
609
|
"""TAL-533: re-adopt every profile's checkpointed processes when a sidecar starts, so a process in a profile nobody
|
|
416
610
|
uses yet is watched (and its exit reported) from the start. Entering a home's scope recovers it once; a failed
|
|
417
611
|
recovery fails the call, so the server retries."""
|
|
418
|
-
from
|
|
612
|
+
from .profiles import named_profile_homes
|
|
419
613
|
|
|
420
|
-
|
|
421
|
-
|
|
614
|
+
global _COMPLETION_BASE_HOME
|
|
615
|
+
_COMPLETION_BASE_HOME = base_home
|
|
616
|
+
named = [home for _, home in named_profile_homes(base_home)]
|
|
422
617
|
failed = []
|
|
423
618
|
for home in [base_home, *named]:
|
|
424
619
|
try:
|
|
@@ -479,7 +674,15 @@ def register(registry_) -> None:
|
|
|
479
674
|
if not consumer:
|
|
480
675
|
raise InvalidParams("consumer is required")
|
|
481
676
|
with scoped_home(profile_home_param(params)):
|
|
482
|
-
|
|
677
|
+
claim = claim_delivery(evt, consumer)
|
|
678
|
+
result = {"claim_id": claim}
|
|
679
|
+
if claim is None:
|
|
680
|
+
api = _delivery_api()
|
|
681
|
+
lookup = getattr(api, "get_durable_delegation", None)
|
|
682
|
+
row = lookup(str(evt.get("delegation_id") or "")) if callable(lookup) else None
|
|
683
|
+
if row and row.get("delivery_state") == "pending":
|
|
684
|
+
result["retryable"] = True
|
|
685
|
+
return result
|
|
483
686
|
|
|
484
687
|
@registry_.method("process.complete_delivery")
|
|
485
688
|
def complete_(ctx: CallContext, params: dict) -> dict:
|
|
@@ -24,6 +24,9 @@ log = logging.getLogger("talaria_sidecar.profiles")
|
|
|
24
24
|
_PROFILE_ID_RE = re.compile(r"[a-z0-9][a-z0-9_-]{0,63}")
|
|
25
25
|
_PROFILE_DIRS = ("skills", "memories", "sessions", "logs", "cron")
|
|
26
26
|
_CLONE_CONFIG_FILES = ("config.yaml", ".env", "SOUL.md")
|
|
27
|
+
_AVATAR_EXTS = ("png", "jpg", "webp")
|
|
28
|
+
# The Agent's ``INTERNAL_LISTING_SOURCES``: worker sessions are never a profile's conversation.
|
|
29
|
+
_INTERNAL_SOURCES = ("kanban", "tool", "oneshot")
|
|
27
30
|
_TERMINAL_ENV = {
|
|
28
31
|
"backend": "TERMINAL_ENV", "env_type": "TERMINAL_ENV", "cwd": "TERMINAL_CWD", "timeout": "TERMINAL_TIMEOUT", "lifetime_seconds": "TERMINAL_LIFETIME_SECONDS",
|
|
29
32
|
"modal_mode": "TERMINAL_MODAL_MODE", "docker_image": "TERMINAL_DOCKER_IMAGE", "docker_forward_env": "TERMINAL_DOCKER_FORWARD_ENV", "docker_env": "TERMINAL_DOCKER_ENV",
|
|
@@ -96,36 +99,141 @@ def _visible(profile_dir: Path) -> bool:
|
|
|
96
99
|
return not (isinstance(data, dict) and data.get("visible") is False)
|
|
97
100
|
|
|
98
101
|
|
|
102
|
+
def _bounded(value, limit: int) -> str:
|
|
103
|
+
"""One printable line of at most ``limit`` characters; anything but a string reads as empty."""
|
|
104
|
+
if not isinstance(value, str):
|
|
105
|
+
return ""
|
|
106
|
+
text = " ".join("".join(c if c.isprintable() else " " for c in value).split())
|
|
107
|
+
return text if len(text) <= limit else text[: limit - 1].rstrip() + "\u2026"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def bot_identity(home: Path) -> dict:
|
|
111
|
+
"""The presentation-only Bot Mode identity from ``profile.yaml`` and ``assets/``; never the raw ``ui_meta``."""
|
|
112
|
+
meta = _yaml_load(home / "profile.yaml") or {}
|
|
113
|
+
ui_meta = meta.get("ui_meta") if isinstance(meta.get("ui_meta"), dict) else {}
|
|
114
|
+
bots = ui_meta.get("hermes-bots") if isinstance(ui_meta.get("hermes-bots"), dict) else {}
|
|
115
|
+
return {
|
|
116
|
+
# Bot Mode's roster name (``ui_meta['hermes-bots'].title``) wins over the profile's own display name.
|
|
117
|
+
"display_name": _bounded(bots.get("title"), 80) or _bounded(meta.get("display_name"), 80),
|
|
118
|
+
"description": _bounded(meta.get("description"), 280), "has_avatar": any((home / "assets" / f"avatar.{ext}").is_file() for ext in _AVATAR_EXTS),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def canonical_bot_chat(home: Path) -> dict | None:
|
|
123
|
+
"""The profile's canonical Bot Chat: its session titled exactly ``Bot Chat`` (Bot Mode's registry) and live
|
|
124
|
+
compression tip, read through a read-only handle. Missing, unreadable, archived, worker-owned, or an Agent
|
|
125
|
+
without Bot Mode answers None; the gateway's resurrection of accidental archives is a write and stays there."""
|
|
126
|
+
db_path = home / "state.db"
|
|
127
|
+
if not db_path.is_file():
|
|
128
|
+
return None
|
|
129
|
+
try:
|
|
130
|
+
from hermes_state import SessionDB
|
|
131
|
+
|
|
132
|
+
title = getattr(SessionDB, "CANONICAL_BOT_CHAT_TITLE", None)
|
|
133
|
+
if not title:
|
|
134
|
+
return None
|
|
135
|
+
db = SessionDB(db_path=db_path, read_only=True)
|
|
136
|
+
except Exception: # noqa: BLE001
|
|
137
|
+
return None
|
|
138
|
+
try:
|
|
139
|
+
row = db.get_session_by_title(title)
|
|
140
|
+
if not row or row.get("title") != title or row.get("archived") or str(row.get("source") or "").strip().lower() in _INTERNAL_SOURCES:
|
|
141
|
+
return None
|
|
142
|
+
session_id = str(row["id"])
|
|
143
|
+
return {"session_id": session_id, "tip_session_id": str(db.get_compression_tip(session_id) or session_id)}
|
|
144
|
+
except Exception: # noqa: BLE001
|
|
145
|
+
log.debug("canonical Bot Chat lookup failed for %s", db_path, exc_info=True)
|
|
146
|
+
return None
|
|
147
|
+
finally:
|
|
148
|
+
try:
|
|
149
|
+
db.close()
|
|
150
|
+
except Exception: # noqa: BLE001
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
GATEWAY_RUNNING_MODES = ("own", "served")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def gateway_mode(home: Path, name: str, is_default: bool) -> str:
|
|
158
|
+
"""The profile's gateway under the host multiplexer (TAL-805): ``served`` by the live host gateway, ``own`` gateway
|
|
159
|
+
process, ``parked`` (``hermes -p X gateway stop`` left its marker and nothing runs; the marker records intent, so a
|
|
160
|
+
live ``--force`` gateway still counts, as in ``hermes -p X gateway status``), ``standalone`` (opted out of the host and
|
|
161
|
+
not running), else ``stopped``. The default profile is the host itself.
|
|
162
|
+
A helper the installed Agent lacks answers no, so an Agent without the multiplexer helpers reports ``own`` or
|
|
163
|
+
``stopped``; a helper that fails answers no too, except the parked check, which fails closed to ``stopped``."""
|
|
164
|
+
from hermes_cli import profiles as agent
|
|
165
|
+
|
|
166
|
+
def probe(helper: str, arg) -> bool | None:
|
|
167
|
+
check = getattr(agent, helper, None)
|
|
168
|
+
if check is None:
|
|
169
|
+
return False
|
|
170
|
+
try:
|
|
171
|
+
return bool(check(arg))
|
|
172
|
+
except Exception: # noqa: BLE001
|
|
173
|
+
log.debug("gateway mode probe %s failed for %s", helper, home, exc_info=True)
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
def asks(helper: str, arg) -> bool:
|
|
177
|
+
return probe(helper, arg) is True
|
|
178
|
+
|
|
179
|
+
named = not is_default
|
|
180
|
+
parked = probe("profile_is_parked", home) if named else False
|
|
181
|
+
if parked is None:
|
|
182
|
+
return "stopped"
|
|
183
|
+
if named and asks("_served_by_running_multiplexer", name):
|
|
184
|
+
return "served"
|
|
185
|
+
if asks("_check_gateway_running", home):
|
|
186
|
+
return "own"
|
|
187
|
+
if parked:
|
|
188
|
+
return "parked"
|
|
189
|
+
if named and asks("profile_is_standalone", home):
|
|
190
|
+
return "standalone"
|
|
191
|
+
return "stopped"
|
|
192
|
+
|
|
193
|
+
|
|
99
194
|
def _row(home: Path, name: str, is_default: bool) -> dict:
|
|
100
|
-
from hermes_cli.profiles import
|
|
195
|
+
from hermes_cli.profiles import _read_config_model
|
|
101
196
|
|
|
102
197
|
try:
|
|
103
198
|
model, provider = _read_config_model(home)
|
|
104
199
|
except Exception: # noqa: BLE001
|
|
105
200
|
model, provider = None, None
|
|
106
|
-
|
|
107
|
-
gateway_running = bool(_check_gateway_running(home))
|
|
108
|
-
except Exception: # noqa: BLE001
|
|
109
|
-
gateway_running = False
|
|
201
|
+
mode = gateway_mode(home, name, is_default)
|
|
110
202
|
enabled, total = skills_stats(home)
|
|
111
203
|
return {
|
|
112
|
-
"name": name, "path": str(home), "is_default": is_default, "gateway_running":
|
|
204
|
+
"name": name, "path": str(home), "is_default": is_default, "gateway_running": mode in GATEWAY_RUNNING_MODES, "gateway_mode": mode,
|
|
205
|
+
"model": model, "provider": provider,
|
|
113
206
|
"has_env": (home / ".env").exists(), "visible": _visible(home), "skill_count": enabled, "enabled_skills": enabled, "total_skills": total,
|
|
207
|
+
**bot_identity(home), "canonical_session": canonical_bot_chat(home),
|
|
114
208
|
}
|
|
115
209
|
|
|
116
210
|
|
|
117
|
-
def
|
|
118
|
-
"""
|
|
211
|
+
def named_profile_homes(base_home: Path) -> list[tuple[str, Path]]:
|
|
212
|
+
"""(name, home) for the ``profiles/*`` directories named like profiles, skipping any that resolve outside the resolved
|
|
213
|
+
profiles root (a symlink leading elsewhere is never read as a profile; TAL-579). A contained symlink answers the
|
|
214
|
+
target it was checked against, so retargeting the link afterwards cannot redirect the caller."""
|
|
119
215
|
from hermes_cli.profiles import _PROFILE_ID_RE as UPSTREAM_ID_RE
|
|
120
216
|
|
|
217
|
+
profiles_root = base_home / "profiles"
|
|
218
|
+
if not profiles_root.is_dir():
|
|
219
|
+
return []
|
|
220
|
+
root = profiles_root.resolve()
|
|
221
|
+
homes = []
|
|
222
|
+
for entry in sorted(profiles_root.iterdir()):
|
|
223
|
+
if not (entry.is_dir() and UPSTREAM_ID_RE.match(entry.name)):
|
|
224
|
+
continue
|
|
225
|
+
real = entry.resolve()
|
|
226
|
+
if real.is_relative_to(root):
|
|
227
|
+
homes.append((entry.name, real if entry.is_symlink() else entry))
|
|
228
|
+
return homes
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def list_profiles(base_home: Path) -> list[dict]:
|
|
232
|
+
"""Profile rows for the base Hermes home: the root profile plus ``profiles/*``."""
|
|
121
233
|
rows = []
|
|
122
234
|
if base_home.is_dir():
|
|
123
235
|
rows.append(_row(base_home, "default", True))
|
|
124
|
-
|
|
125
|
-
if profiles_root.is_dir():
|
|
126
|
-
for entry in sorted(profiles_root.iterdir()):
|
|
127
|
-
if entry.is_dir() and UPSTREAM_ID_RE.match(entry.name):
|
|
128
|
-
rows.append(_row(entry, entry.name, False))
|
|
236
|
+
rows.extend(_row(home, name, False) for name, home in named_profile_homes(base_home))
|
|
129
237
|
return rows
|
|
130
238
|
|
|
131
239
|
|