@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
|
@@ -14,9 +14,13 @@ import importlib
|
|
|
14
14
|
import logging
|
|
15
15
|
import multiprocessing
|
|
16
16
|
import queue
|
|
17
|
+
import os
|
|
17
18
|
import re
|
|
19
|
+
import signal
|
|
18
20
|
import threading
|
|
19
21
|
import time
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
from functools import wraps
|
|
20
24
|
from pathlib import Path
|
|
21
25
|
|
|
22
26
|
from ..errors import InvalidParams, RpcError
|
|
@@ -31,6 +35,47 @@ _PASSTHROUGH_FIELDS = ("script", "no_agent", "context_from", "reasoning_effort",
|
|
|
31
35
|
_RUNNING: dict[str, float] = {}
|
|
32
36
|
_RUNNING_LOCK = threading.Lock()
|
|
33
37
|
_SNAPSHOT_LOCK = threading.Lock()
|
|
38
|
+
# The Agent's fire claim lives FIRE_CLAIM_TTL_SECONDS (300); a run refreshes it well inside that, re-checks a missed
|
|
39
|
+
# refresh once before treating the claim as lost (as the Agent's own runs do), and gives up once no refresh has landed
|
|
40
|
+
# for most of the lease.
|
|
41
|
+
_CLAIM_HEARTBEAT_SECONDS = 60.0
|
|
42
|
+
_CLAIM_MISS_CONFIRM_SECONDS = 1.0
|
|
43
|
+
_CLAIM_HEARTBEAT_GRACE_SECONDS = 240.0
|
|
44
|
+
_CLAIM_LOST = "Another process took over this task's run claim, so this run stopped before saving or delivering anything"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class _ClaimLost(RuntimeError):
|
|
48
|
+
def __init__(self) -> None:
|
|
49
|
+
super().__init__(_CLAIM_LOST)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _main_model_pin() -> tuple[str | None, str | None]:
|
|
53
|
+
"""``(provider, model)`` the scoped profile's main agent runs on: the Agent's own ``cron.jobs._main_model_pin``.
|
|
54
|
+
|
|
55
|
+
Agent 0.21.3 predates that helper, so it is rebuilt from the readers 0.21.4 composes: the home's effective
|
|
56
|
+
``config.yaml`` model and the provider the runtime resolves for it. ``(None, None)`` when no model is configured.
|
|
57
|
+
"""
|
|
58
|
+
from cron import jobs
|
|
59
|
+
|
|
60
|
+
if hasattr(jobs, "_main_model_pin"):
|
|
61
|
+
return jobs._main_model_pin()
|
|
62
|
+
from hermes_cli.config_effective import load_user_config_effective
|
|
63
|
+
from hermes_constants import get_hermes_home
|
|
64
|
+
|
|
65
|
+
cfg_path = get_hermes_home() / "config.yaml"
|
|
66
|
+
cfg = load_user_config_effective(cfg_path) if cfg_path.exists() else {}
|
|
67
|
+
model_cfg = cfg.get("model") or {}
|
|
68
|
+
model = model_cfg.get("default") or model_cfg.get("model") if isinstance(model_cfg, dict) else model_cfg
|
|
69
|
+
model = model.strip() or None if isinstance(model, str) else None
|
|
70
|
+
if not model:
|
|
71
|
+
return None, None
|
|
72
|
+
provider = None
|
|
73
|
+
with contextlib.suppress(Exception):
|
|
74
|
+
from hermes_cli.runtime_provider import resolve_runtime_provider
|
|
75
|
+
|
|
76
|
+
resolved = resolve_runtime_provider(requested=None).get("provider")
|
|
77
|
+
provider = resolved.strip().lower() or None if isinstance(resolved, str) else None
|
|
78
|
+
return provider, model
|
|
34
79
|
|
|
35
80
|
|
|
36
81
|
class CronUnavailable(RpcError):
|
|
@@ -68,6 +113,25 @@ def _job_ref(params: dict, key: str = "job_id") -> str:
|
|
|
68
113
|
return ref
|
|
69
114
|
|
|
70
115
|
|
|
116
|
+
def _settled_mutation(method):
|
|
117
|
+
"""Fence schedule edits against manual execution, including its retained recovery obligation."""
|
|
118
|
+
@wraps(method)
|
|
119
|
+
def guarded(ctx, params):
|
|
120
|
+
from .cron_execution import ManualExecution, Unverified
|
|
121
|
+
home, jobs = profile_home_param(params), _jobs()
|
|
122
|
+
with _store(home):
|
|
123
|
+
job = getattr(jobs, "resolve_job_ref", jobs.get_job)(_job_ref(params))
|
|
124
|
+
if job is None:
|
|
125
|
+
return method(ctx, params)
|
|
126
|
+
job_id = _job_id({"job_id": job["id"]})
|
|
127
|
+
execution = ManualExecution(home, home, {"id": job_id}, None)
|
|
128
|
+
with execution.acquire():
|
|
129
|
+
if execution.file.exists():
|
|
130
|
+
raise Unverified("Schedule edits and deletion are blocked until the manual execution is reconciled.")
|
|
131
|
+
return method(ctx, dict(params, job_id=job_id))
|
|
132
|
+
return guarded
|
|
133
|
+
|
|
134
|
+
|
|
71
135
|
# ── job payload shaping ───────────────────────────────────────────────────
|
|
72
136
|
|
|
73
137
|
def _monitor_storage(monitor) -> dict:
|
|
@@ -115,6 +179,87 @@ def job_for_api(job: dict) -> dict:
|
|
|
115
179
|
return payload
|
|
116
180
|
|
|
117
181
|
|
|
182
|
+
# ── store health and foreign runs (TAL-810) ─────────────────────────────
|
|
183
|
+
|
|
184
|
+
def _store_health(cron_dir: Path) -> dict | None:
|
|
185
|
+
"""The Agent's cross-process write probe: ``None`` when the store accepts writes or the Agent predates it."""
|
|
186
|
+
try:
|
|
187
|
+
from cron.store_health import probe_report
|
|
188
|
+
except ImportError:
|
|
189
|
+
return None
|
|
190
|
+
return probe_report(cron_dir)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _live_executions(home: Path, job_ids: list[str], *, strict: bool = False) -> dict[str, dict]:
|
|
194
|
+
"""Jobs whose latest attempt is claimed or running under a live owner: the gateway scheduler or another process.
|
|
195
|
+
|
|
196
|
+
The executions ledger lives under ``get_hermes_home()``, not the cron store override, so it is read in the
|
|
197
|
+
profile's scope. A store without a ledger never ran anything, and is not created by this read. An unreadable
|
|
198
|
+
ledger reads idle for a listing; ``strict`` (run admission) refuses instead, since it cannot prove the job idle."""
|
|
199
|
+
try:
|
|
200
|
+
from cron.executions import live_inflight_execution
|
|
201
|
+
except ImportError:
|
|
202
|
+
return {}
|
|
203
|
+
if not job_ids or not (Path(home).expanduser() / "cron" / "executions.db").is_file():
|
|
204
|
+
return {}
|
|
205
|
+
try:
|
|
206
|
+
with scoped_home(home):
|
|
207
|
+
return {job_id: record for job_id in job_ids if job_id and (record := live_inflight_execution(job_id))}
|
|
208
|
+
except Exception as exc: # noqa: BLE001 - an unreadable ledger cannot prove a run; the list still loads
|
|
209
|
+
if strict:
|
|
210
|
+
raise RpcError("Cannot tell whether this task is already running: its executions ledger is unreadable", condition="cron_ledger_unreadable") from exc
|
|
211
|
+
log.warning("Cron executions ledger unreadable in %s", home, exc_info=True)
|
|
212
|
+
return {}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _claim_fire(store_home: Path, job: dict) -> dict | bool | None:
|
|
216
|
+
"""The Agent's own run-now lease (``claim_job_for_fire(manual=True)``), which a gateway tick must also win.
|
|
217
|
+
|
|
218
|
+
The exact record the claim took (the one to run), ``False`` when another process holds the job's claim, or
|
|
219
|
+
``None`` for a job the Agent does not claim (paused, disabled, or terminal), which no tick fires. ``mark_job_run``
|
|
220
|
+
releases a claim when the run ends; the run heartbeats it meanwhile."""
|
|
221
|
+
jobs = _jobs()
|
|
222
|
+
with _store(store_home):
|
|
223
|
+
if not jobs.is_job_runnable(job):
|
|
224
|
+
return None
|
|
225
|
+
claimed = jobs.claim_job_for_fire(job["id"], manual=True, return_job=True)
|
|
226
|
+
if not isinstance(claimed, dict):
|
|
227
|
+
# The claim only loses to a live owner's claim; any other refusal is a record the Agent never claims.
|
|
228
|
+
current = jobs.get_job(job["id"]) or {}
|
|
229
|
+
return False if isinstance(current.get("fire_claim"), dict) else None
|
|
230
|
+
return {key: value for key, value in claimed.items() if key != "_scheduled_instant"}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@contextlib.contextmanager
|
|
234
|
+
def _owner_fence(jobs, job_id: str, owner: str | None, *, protect_unclaimed=False):
|
|
235
|
+
"""Hold the Agent fire fence across side effects; canonical unclaimed runs also exclude a successor claim."""
|
|
236
|
+
if owner is None and protect_unclaimed:
|
|
237
|
+
with jobs._fire_job_lock(job_id) as locked:
|
|
238
|
+
current = jobs.get_job(job_id) if locked else None
|
|
239
|
+
yield bool(current) and not current.get("fire_claim")
|
|
240
|
+
else:
|
|
241
|
+
with jobs.fire_claim_fence(job_id, expected_owner=owner) if owner else contextlib.nullcontext(True) as owns:
|
|
242
|
+
yield owns
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _mark_run(jobs, job_id: str, success: bool, error, owner: str | None, delivery_error=None) -> None:
|
|
246
|
+
"""``mark_job_run`` fenced by the run's fire claim: a run that lost its claim records nothing over the new owner's."""
|
|
247
|
+
fence = {"expected_fire_owner": owner} if owner else {}
|
|
248
|
+
try:
|
|
249
|
+
jobs.mark_job_run(job_id, success, error, delivery_error=delivery_error, **fence)
|
|
250
|
+
except TypeError:
|
|
251
|
+
if owner:
|
|
252
|
+
raise
|
|
253
|
+
jobs.mark_job_run(job_id, success, error)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _elapsed(record: dict) -> float:
|
|
257
|
+
try:
|
|
258
|
+
return round(max(0.0, time.time() - datetime.fromisoformat(str(record.get("claimed_at"))).timestamp()), 1)
|
|
259
|
+
except ValueError:
|
|
260
|
+
return 0.0
|
|
261
|
+
|
|
262
|
+
|
|
118
263
|
# ── output files ──────────────────────────────────────────────────────────
|
|
119
264
|
|
|
120
265
|
def _response_marker_index(text: str) -> int:
|
|
@@ -199,12 +344,20 @@ def _snippet(text: str, limit: int = 600) -> str:
|
|
|
199
344
|
|
|
200
345
|
# ── manual runs ───────────────────────────────────────────────────────────
|
|
201
346
|
|
|
202
|
-
def _child_main(job, execution_home, result_queue):
|
|
347
|
+
def _child_main(job, execution_home, result_queue, cancel_event=None, execution_id=None, recovering=False):
|
|
203
348
|
try:
|
|
204
349
|
from cron.scheduler import run_job
|
|
205
350
|
|
|
351
|
+
def execute():
|
|
352
|
+
if recovering:
|
|
353
|
+
from .cron_execution import recover
|
|
354
|
+
return recover(job, execution_id, cancel_event)
|
|
355
|
+
if execution_id is not None:
|
|
356
|
+
return run_job(job, cancel_event=cancel_event, execution_id=execution_id)
|
|
357
|
+
return run_job(job)
|
|
358
|
+
|
|
206
359
|
if execution_home is None:
|
|
207
|
-
result =
|
|
360
|
+
result = execute()
|
|
208
361
|
else:
|
|
209
362
|
from talaria_sidecar.home import scoped_home as _scoped
|
|
210
363
|
|
|
@@ -212,12 +365,16 @@ def _child_main(job, execution_home, result_queue):
|
|
|
212
365
|
|
|
213
366
|
os.environ["HERMES_HOME"] = str(execution_home)
|
|
214
367
|
with _scoped(Path(execution_home)):
|
|
215
|
-
result =
|
|
216
|
-
result_queue.put(("ok", result))
|
|
368
|
+
result = execute()
|
|
369
|
+
result_queue.put(("ok", result, {key: job[key] for key in ("_model_unreachable", "_quota_hold_seconds") if key in job}))
|
|
217
370
|
except BaseException as exc: # noqa: BLE001 - surfaced in the parent
|
|
218
371
|
import traceback
|
|
372
|
+
from .cron_execution import Unverified
|
|
219
373
|
|
|
220
|
-
|
|
374
|
+
if isinstance(exc, Unverified):
|
|
375
|
+
result_queue.put(("unverified", exc.detail))
|
|
376
|
+
else:
|
|
377
|
+
result_queue.put(("error", f"{type(exc).__name__}: {exc}", traceback.format_exc()))
|
|
221
378
|
|
|
222
379
|
|
|
223
380
|
def _result_timeout(job) -> float:
|
|
@@ -234,44 +391,137 @@ def _result_timeout(job) -> float:
|
|
|
234
391
|
return 6 * 60 * 60.0
|
|
235
392
|
|
|
236
393
|
|
|
237
|
-
def
|
|
394
|
+
def _worker(main, *args) -> None:
|
|
395
|
+
"""A run's worker leads its own process group, so stopping the run also reaches every process it started."""
|
|
396
|
+
if hasattr(os, "setsid"):
|
|
397
|
+
os.setsid()
|
|
398
|
+
main(*args)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _signal_group(process, sig) -> None:
|
|
402
|
+
with contextlib.suppress(ProcessLookupError, PermissionError):
|
|
403
|
+
os.killpg(process.pid, sig)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _stop(process) -> None:
|
|
407
|
+
"""End a run's worker and everything it started, returning only once the worker has exited: SIGTERM to the
|
|
408
|
+
worker's process group, then SIGKILL to whatever is left, so nothing keeps running after the run gives up its
|
|
409
|
+
claim or its running guard. Without process groups (Windows) only the worker itself is stopped."""
|
|
410
|
+
if not hasattr(os, "killpg"):
|
|
411
|
+
process.terminate()
|
|
412
|
+
process.join(timeout=5)
|
|
413
|
+
if process.is_alive():
|
|
414
|
+
process.kill()
|
|
415
|
+
process.join()
|
|
416
|
+
return
|
|
417
|
+
_signal_group(process, signal.SIGTERM)
|
|
418
|
+
process.join(timeout=5)
|
|
419
|
+
_signal_group(process, signal.SIGKILL)
|
|
420
|
+
process.join()
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def _run_in_child(job, execution_home, ctx: CallContext, heartbeat=None, execution=None):
|
|
424
|
+
from .cron_execution import SETTLEMENT_SECONDS, Unverified
|
|
425
|
+
|
|
238
426
|
ctx_mp = multiprocessing.get_context("spawn")
|
|
239
427
|
result_queue = ctx_mp.Queue(maxsize=1)
|
|
240
|
-
|
|
241
|
-
|
|
428
|
+
cancel_event = ctx_mp.Event() if execution is not None else None
|
|
429
|
+
|
|
430
|
+
def start(recovering=False):
|
|
431
|
+
args = (job, str(execution_home) if execution_home else None, result_queue)
|
|
432
|
+
if execution is not None:
|
|
433
|
+
args += (cancel_event, execution.execution_id, recovering)
|
|
434
|
+
child = ctx_mp.Process(target=_worker, args=(_child_main, *args))
|
|
435
|
+
child.start()
|
|
436
|
+
return child
|
|
437
|
+
|
|
438
|
+
process = start(execution.recovering if execution else False)
|
|
242
439
|
deadline = time.monotonic() + _result_timeout(job)
|
|
440
|
+
next_beat = time.monotonic() + _CLAIM_HEARTBEAT_SECONDS
|
|
243
441
|
status, payload = "error", ["cron run subprocess failed before producing a result", ""]
|
|
442
|
+
settling = None
|
|
443
|
+
recovery_started = bool(execution and execution.recovering)
|
|
444
|
+
|
|
445
|
+
def cancel(reason):
|
|
446
|
+
nonlocal settling
|
|
447
|
+
if execution is None:
|
|
448
|
+
return
|
|
449
|
+
execution.cancel(reason)
|
|
450
|
+
cancel_event.set()
|
|
451
|
+
if settling is None:
|
|
452
|
+
settling = time.monotonic() + SETTLEMENT_SECONDS
|
|
453
|
+
|
|
454
|
+
def recover_child(detail):
|
|
455
|
+
nonlocal process, recovery_started, result_queue
|
|
456
|
+
process.join(timeout=5)
|
|
457
|
+
if process.is_alive():
|
|
458
|
+
_stop(process)
|
|
459
|
+
if recovery_started:
|
|
460
|
+
raise Unverified(detail)
|
|
461
|
+
recovery_started = True
|
|
462
|
+
cancel("submitter interrupted")
|
|
463
|
+
# A killed queue writer can leave a partial frame. Recovery gets a fresh pipe.
|
|
464
|
+
result_queue.close()
|
|
465
|
+
result_queue.join_thread()
|
|
466
|
+
result_queue = ctx_mp.Queue(maxsize=1)
|
|
467
|
+
process = start(True)
|
|
468
|
+
|
|
469
|
+
if execution and execution.record["cancel_reason"]:
|
|
470
|
+
cancel(execution.record["cancel_reason"])
|
|
244
471
|
try:
|
|
245
472
|
while True:
|
|
246
473
|
try:
|
|
247
474
|
status, *payload = result_queue.get(timeout=1.0)
|
|
248
|
-
|
|
475
|
+
if execution is not None and status == "unverified":
|
|
476
|
+
raise Unverified(payload[0])
|
|
477
|
+
if execution is None or status == "ok":
|
|
478
|
+
break
|
|
479
|
+
# A transport failure is not a failed task. Recover the original identity once.
|
|
480
|
+
recover_child(payload[0])
|
|
249
481
|
except queue.Empty:
|
|
482
|
+
if heartbeat is not None and time.monotonic() >= next_beat:
|
|
483
|
+
next_beat = time.monotonic() + _CLAIM_HEARTBEAT_SECONDS
|
|
484
|
+
if not heartbeat():
|
|
485
|
+
if execution is None:
|
|
486
|
+
_stop(process)
|
|
487
|
+
raise _ClaimLost()
|
|
488
|
+
cancel("claim_lost")
|
|
489
|
+
heartbeat = None
|
|
250
490
|
if ctx.cancelled:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
491
|
+
if execution is None:
|
|
492
|
+
_stop(process)
|
|
493
|
+
status, payload = "cancelled", ["cancelled", ""]
|
|
494
|
+
break
|
|
495
|
+
cancel("cancelled")
|
|
255
496
|
if not process.is_alive():
|
|
256
497
|
# The child may have put its result just before exiting; otherwise it died (OOM, signal) without one.
|
|
257
498
|
try:
|
|
258
499
|
status, *payload = result_queue.get_nowait()
|
|
259
500
|
except queue.Empty:
|
|
260
501
|
payload = [f"cron run subprocess exited with code {process.exitcode} without producing a result", ""]
|
|
502
|
+
if execution is not None and status != "ok":
|
|
503
|
+
recover_child(payload[0])
|
|
504
|
+
continue
|
|
261
505
|
break
|
|
262
506
|
if time.monotonic() >= deadline:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
507
|
+
if execution is None:
|
|
508
|
+
_stop(process)
|
|
509
|
+
payload = [f"cron run subprocess produced no result within {_result_timeout(job):g}s and was terminated", ""]
|
|
510
|
+
break
|
|
511
|
+
cancel("Manual task timed out")
|
|
512
|
+
if settling is not None and time.monotonic() >= settling:
|
|
513
|
+
raise Unverified("The owner has not provided a terminal receipt.")
|
|
267
514
|
process.join(timeout=5)
|
|
268
515
|
if process.is_alive():
|
|
269
|
-
process
|
|
270
|
-
process.join(timeout=5)
|
|
516
|
+
_stop(process)
|
|
271
517
|
finally:
|
|
518
|
+
if process.is_alive():
|
|
519
|
+
_stop(process)
|
|
272
520
|
result_queue.close()
|
|
273
521
|
result_queue.join_thread()
|
|
274
522
|
if status == "ok":
|
|
523
|
+
if execution is not None and len(payload) > 1:
|
|
524
|
+
execution.job.update(payload[1])
|
|
275
525
|
return payload[0]
|
|
276
526
|
if status == "cancelled":
|
|
277
527
|
raise RpcError("cancelled", condition="cancelled")
|
|
@@ -302,7 +552,32 @@ def _delivery_home(scheduler, home: Path):
|
|
|
302
552
|
pass
|
|
303
553
|
|
|
304
554
|
|
|
305
|
-
def
|
|
555
|
+
def _heartbeat(store_home, job_id, claim_owner):
|
|
556
|
+
jobs = _jobs()
|
|
557
|
+
last_beat = time.monotonic()
|
|
558
|
+
|
|
559
|
+
def heartbeat() -> bool:
|
|
560
|
+
"""Refresh only this fire's claim, giving transient store errors less than a lease to recover."""
|
|
561
|
+
nonlocal last_beat
|
|
562
|
+
try:
|
|
563
|
+
with _store(store_home):
|
|
564
|
+
owned = jobs.heartbeat_fire_claim(job_id, expected_owner=claim_owner) is not False
|
|
565
|
+
if not owned:
|
|
566
|
+
time.sleep(_CLAIM_MISS_CONFIRM_SECONDS)
|
|
567
|
+
owned = jobs.heartbeat_fire_claim(job_id, expected_owner=claim_owner) is not False
|
|
568
|
+
except Exception: # noqa: BLE001
|
|
569
|
+
log.warning("Fire claim heartbeat failed for job %s", job_id, exc_info=True)
|
|
570
|
+
return time.monotonic() - last_beat < _CLAIM_HEARTBEAT_GRACE_SECONDS
|
|
571
|
+
if owned:
|
|
572
|
+
last_beat = time.monotonic()
|
|
573
|
+
return owned
|
|
574
|
+
return heartbeat
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def run_tracked(job: dict, store_home: Path, execution_home: Path | None, ctx: CallContext, claim_owner: str | None = None, *, recovery_only=False) -> dict:
|
|
578
|
+
from . import cron_execution
|
|
579
|
+
if recovery_only or cron_execution.path(store_home, job["id"]).exists() or cron_execution.supported(job):
|
|
580
|
+
return cron_execution.run(job, store_home, execution_home, ctx, claim_owner, recovery_only=recovery_only)
|
|
306
581
|
jobs = _jobs()
|
|
307
582
|
scheduler = importlib.import_module("cron.scheduler")
|
|
308
583
|
silent_marker = getattr(scheduler, "SILENT_MARKER", "[SILENT]")
|
|
@@ -311,8 +586,12 @@ def run_tracked(job: dict, store_home: Path, execution_home: Path | None, ctx: C
|
|
|
311
586
|
execution_home = execution_home or store_home
|
|
312
587
|
outcome: dict = {"job_id": job_id, "status": "completed"}
|
|
313
588
|
try:
|
|
314
|
-
|
|
315
|
-
|
|
589
|
+
heartbeat = _heartbeat(store_home, job_id, claim_owner)
|
|
590
|
+
success, output, final_response, error = _run_in_child(job, execution_home, ctx, heartbeat if claim_owner else None)
|
|
591
|
+
with _store(store_home), _owner_fence(jobs, job_id, claim_owner) as owns, contextlib.ExitStack() as delivery:
|
|
592
|
+
if not owns:
|
|
593
|
+
raise _ClaimLost()
|
|
594
|
+
delivery.enter_context(_delivery_home(scheduler, store_home))
|
|
316
595
|
jobs.save_job_output(job_id, output)
|
|
317
596
|
content = final_response if success else f"⚠️ Cron job '{job.get('name', job_id)}' failed:\n{error}"
|
|
318
597
|
should_deliver = bool(content) and not (success and silent_marker in content.strip().upper())
|
|
@@ -324,15 +603,12 @@ def run_tracked(job: dict, store_home: Path, execution_home: Path | None, ctx: C
|
|
|
324
603
|
delivery_error = str(exc)
|
|
325
604
|
if success and not final_response:
|
|
326
605
|
success, error = False, "Agent completed but produced empty response (model error, timeout, or misconfiguration)"
|
|
327
|
-
|
|
328
|
-
jobs.mark_job_run(job_id, success, error, delivery_error=delivery_error)
|
|
329
|
-
except TypeError:
|
|
330
|
-
jobs.mark_job_run(job_id, success, error)
|
|
606
|
+
_mark_run(jobs, job_id, success, error, claim_owner, delivery_error)
|
|
331
607
|
outcome.update(success=bool(success), error=error, delivery_error=delivery_error)
|
|
332
608
|
except RpcError:
|
|
333
609
|
with _store(store_home):
|
|
334
610
|
try:
|
|
335
|
-
jobs
|
|
611
|
+
_mark_run(jobs, job_id, False, "cancelled", claim_owner)
|
|
336
612
|
except Exception: # noqa: BLE001
|
|
337
613
|
pass
|
|
338
614
|
raise
|
|
@@ -340,7 +616,7 @@ def run_tracked(job: dict, store_home: Path, execution_home: Path | None, ctx: C
|
|
|
340
616
|
log.exception("Manual cron run failed for job %s", job_id)
|
|
341
617
|
with _store(store_home):
|
|
342
618
|
try:
|
|
343
|
-
jobs
|
|
619
|
+
_mark_run(jobs, job_id, False, str(exc), claim_owner)
|
|
344
620
|
except Exception: # noqa: BLE001
|
|
345
621
|
pass
|
|
346
622
|
outcome.update(status="failed", success=False, error=str(exc))
|
|
@@ -353,17 +629,79 @@ def run_tracked(job: dict, store_home: Path, execution_home: Path | None, ctx: C
|
|
|
353
629
|
# ── methods ───────────────────────────────────────────────────────────────
|
|
354
630
|
|
|
355
631
|
def register(registry) -> None:
|
|
632
|
+
@registry.method("cron.blueprints")
|
|
633
|
+
def blueprints(ctx: CallContext, params: dict) -> dict:
|
|
634
|
+
try:
|
|
635
|
+
catalog = importlib.import_module("cron.blueprint_catalog")
|
|
636
|
+
except ModuleNotFoundError as exc:
|
|
637
|
+
if exc.name != "cron.blueprint_catalog":
|
|
638
|
+
raise
|
|
639
|
+
return {"blueprints": []}
|
|
640
|
+
with scoped_home(profile_home_param(params)):
|
|
641
|
+
rows = []
|
|
642
|
+
for blueprint in catalog.list_blueprints():
|
|
643
|
+
entry = catalog.blueprint_catalog_entry(blueprint)
|
|
644
|
+
schema = catalog.blueprint_form_schema(blueprint)
|
|
645
|
+
slots = [{**slot, "default": str(slot["default"]) if slot.get("default") is not None else None,
|
|
646
|
+
"options": [str(value) for value in slot.get("options", [])]} for slot in schema["fields"]]
|
|
647
|
+
rows.append({key: entry[key] for key in ("key", "title", "description", "category", "source", "plugin")})
|
|
648
|
+
rows[-1].update(schedule_label=entry["scheduleHuman"], slots=slots)
|
|
649
|
+
return {"blueprints": rows}
|
|
650
|
+
|
|
651
|
+
@registry.method("cron.blueprint_fill")
|
|
652
|
+
def blueprint_fill(ctx: CallContext, params: dict) -> dict:
|
|
653
|
+
key, values = params.get("key"), params.get("values")
|
|
654
|
+
if not isinstance(key, str) or not key.strip() or not isinstance(values, dict) or not all(isinstance(v, str) for v in values.values()):
|
|
655
|
+
raise InvalidParams("key and string slot values are required")
|
|
656
|
+
try:
|
|
657
|
+
catalog = importlib.import_module("cron.blueprint_catalog")
|
|
658
|
+
except ModuleNotFoundError as exc:
|
|
659
|
+
if exc.name != "cron.blueprint_catalog":
|
|
660
|
+
raise
|
|
661
|
+
raise InvalidParams("Automation blueprints are unavailable") from exc
|
|
662
|
+
with scoped_home(profile_home_param(params)):
|
|
663
|
+
blueprint = catalog.get_blueprint(key)
|
|
664
|
+
if blueprint is None:
|
|
665
|
+
raise InvalidParams("Unknown automation blueprint")
|
|
666
|
+
try:
|
|
667
|
+
draft = catalog.fill_blueprint(blueprint, values)
|
|
668
|
+
except catalog.BlueprintFillError as exc:
|
|
669
|
+
raise InvalidParams(str(exc)) from exc
|
|
670
|
+
draft.setdefault("skills", [])
|
|
671
|
+
return {"draft": draft}
|
|
672
|
+
|
|
356
673
|
@registry.method("cron.list")
|
|
357
674
|
def list_(ctx: CallContext, params: dict) -> dict:
|
|
358
|
-
"""Jobs of one store, shaped for the API; the server merges profiles."""
|
|
675
|
+
"""Jobs of one store, shaped for the API; the server merges profiles. ``probe_store`` adds the store's write health."""
|
|
359
676
|
jobs = _jobs()
|
|
360
|
-
|
|
361
|
-
|
|
677
|
+
home = profile_home_param(params)
|
|
678
|
+
with _store(home):
|
|
679
|
+
from .cron_execution import pending_jobs
|
|
680
|
+
pending = {job["id"]: job for job in pending_jobs(home)}
|
|
681
|
+
stored = jobs.list_jobs(include_disabled=True)
|
|
682
|
+
ids = {job["id"] for job in stored}
|
|
683
|
+
stored.extend(job for jid, job in pending.items() if jid not in ids)
|
|
684
|
+
listed = [job_for_api(job) for job in stored]
|
|
685
|
+
result: dict = {"jobs": listed}
|
|
686
|
+
if params.get("probe_store"):
|
|
687
|
+
result["store_health"] = _store_health(jobs.get_cron_output_dir().parent)
|
|
688
|
+
live = _live_executions(home, [str(job.get("id") or "") for job in listed])
|
|
689
|
+
with _RUNNING_LOCK:
|
|
690
|
+
active = set(_RUNNING)
|
|
691
|
+
for index, job in enumerate(listed):
|
|
692
|
+
jid = str(job.get("id") or "")
|
|
693
|
+
if jid in pending and jid not in live and jid not in active:
|
|
694
|
+
# Web preflight must use the accepted fire's profile, even after external job edits.
|
|
695
|
+
job = listed[index] = job_for_api(pending[jid])
|
|
696
|
+
job["running_elsewhere"] = jid in live
|
|
697
|
+
return result
|
|
362
698
|
|
|
363
699
|
@registry.method("cron.get")
|
|
364
700
|
def get(ctx: CallContext, params: dict) -> dict:
|
|
365
|
-
|
|
366
|
-
|
|
701
|
+
from .cron_execution import pending_job
|
|
702
|
+
home, job_id = profile_home_param(params), _job_id(params)
|
|
703
|
+
with _store(home):
|
|
704
|
+
job = pending_job(home, job_id) or _jobs().get_job(job_id)
|
|
367
705
|
return {"job": job_for_api(job) if job else None}
|
|
368
706
|
|
|
369
707
|
@registry.method("cron.create")
|
|
@@ -396,8 +734,6 @@ def register(registry) -> None:
|
|
|
396
734
|
# to the store home; owner_profile only preserves management from the creating Web profile.
|
|
397
735
|
if post.get("profile") and execution_home and not (model and provider) and not body.get("no_agent"):
|
|
398
736
|
try:
|
|
399
|
-
from cron.jobs import _main_model_pin
|
|
400
|
-
|
|
401
737
|
with _SNAPSHOT_LOCK, scoped_home(Path(execution_home)):
|
|
402
738
|
profile_provider, profile_model = _main_model_pin()
|
|
403
739
|
if not profile_model:
|
|
@@ -417,6 +753,7 @@ def register(registry) -> None:
|
|
|
417
753
|
return {"job": job_for_api(job)}
|
|
418
754
|
|
|
419
755
|
@registry.method("cron.update")
|
|
756
|
+
@_settled_mutation
|
|
420
757
|
def update(ctx: CallContext, params: dict) -> dict:
|
|
421
758
|
jobs = _jobs()
|
|
422
759
|
job_id = _job_ref(params)
|
|
@@ -445,6 +782,7 @@ def register(registry) -> None:
|
|
|
445
782
|
return {"job": job_for_api(job)}
|
|
446
783
|
|
|
447
784
|
@registry.method("cron.delete")
|
|
785
|
+
@_settled_mutation
|
|
448
786
|
def delete(ctx: CallContext, params: dict) -> dict:
|
|
449
787
|
job_id = _job_ref(params)
|
|
450
788
|
with _store(profile_home_param(params)):
|
|
@@ -462,6 +800,7 @@ def register(registry) -> None:
|
|
|
462
800
|
return {"job": dict(job)}
|
|
463
801
|
|
|
464
802
|
@registry.method("cron.resume")
|
|
803
|
+
@_settled_mutation
|
|
465
804
|
def resume(ctx: CallContext, params: dict) -> dict:
|
|
466
805
|
with _store(profile_home_param(params)):
|
|
467
806
|
try:
|
|
@@ -478,17 +817,37 @@ def register(registry) -> None:
|
|
|
478
817
|
store_home = profile_home_param(params)
|
|
479
818
|
execution_home = Path(params["execution_home"]).expanduser() if params.get("execution_home") else None
|
|
480
819
|
job_id = _job_id(params)
|
|
820
|
+
from .cron_execution import path
|
|
821
|
+
if path(store_home, job_id).exists():
|
|
822
|
+
return run_tracked({"id": job_id}, store_home, execution_home, ctx, recovery_only=True)
|
|
481
823
|
with _store(store_home):
|
|
482
824
|
job = _jobs().get_job(job_id)
|
|
483
825
|
if not job:
|
|
484
826
|
raise RpcError("Job not found", condition="not_found")
|
|
827
|
+
foreign = _live_executions(store_home, [job_id], strict=True).get(job_id)
|
|
828
|
+
if foreign is not None:
|
|
829
|
+
return {"job_id": job_id, "status": "already_running", "elapsed": _elapsed(foreign)}
|
|
485
830
|
with _RUNNING_LOCK:
|
|
486
831
|
started = _RUNNING.get(job_id)
|
|
487
832
|
if started is not None:
|
|
488
833
|
return {"job_id": job_id, "status": "already_running", "elapsed": round(time.time() - started, 1)}
|
|
489
834
|
_RUNNING[job_id] = time.time()
|
|
835
|
+
try:
|
|
836
|
+
claimed = _claim_fire(store_home, job)
|
|
837
|
+
except BaseException:
|
|
838
|
+
with _RUNNING_LOCK:
|
|
839
|
+
_RUNNING.pop(job_id, None)
|
|
840
|
+
raise
|
|
841
|
+
if claimed is False:
|
|
842
|
+
with _RUNNING_LOCK:
|
|
843
|
+
_RUNNING.pop(job_id, None)
|
|
844
|
+
return {"job_id": job_id, "status": "already_running", "elapsed": 0.0}
|
|
845
|
+
owner = None
|
|
846
|
+
if claimed:
|
|
847
|
+
job = claimed
|
|
848
|
+
owner = str((claimed.get("fire_claim") or {}).get("by") or "") or None
|
|
490
849
|
ctx.emit("started", {"job_id": job_id})
|
|
491
|
-
return run_tracked(job, store_home, execution_home, ctx)
|
|
850
|
+
return run_tracked(job, store_home, execution_home, ctx, owner)
|
|
492
851
|
|
|
493
852
|
@registry.method("cron.status", requires_agent=False)
|
|
494
853
|
def status(ctx: CallContext, params: dict) -> dict:
|