@gajae-code/coding-agent 0.13.3 → 0.14.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/CHANGELOG.md +184 -2
- package/README.md +2 -0
- package/bin/gajaessi.js +4 -0
- package/dist/types/async/job-manager.d.ts +55 -2
- package/dist/types/async/support.d.ts +14 -0
- package/dist/types/capability/mcp.d.ts +6 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/accounts-cli.d.ts +19 -0
- package/dist/types/cli/args.d.ts +3 -0
- package/dist/types/cli/config-cli.d.ts +6 -0
- package/dist/types/cli/crash-cli.d.ts +10 -0
- package/dist/types/cli/customize-doctor.d.ts +145 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/mcp-cli.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/root-flags.d.ts +12 -0
- package/dist/types/cli/setup-cli.d.ts +3 -1
- package/dist/types/cli/skills-cli.d.ts +2 -1
- package/dist/types/cli/update-cli.d.ts +19 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/accounts.d.ts +40 -0
- package/dist/types/commands/crash.d.ts +24 -0
- package/dist/types/commands/customize.d.ts +22 -0
- package/dist/types/commands/daemon.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/commands/setup.d.ts +6 -0
- package/dist/types/commands/skills.d.ts +6 -1
- package/dist/types/commands/update.d.ts +7 -0
- package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
- package/dist/types/config/config-schema-version.d.ts +10 -0
- package/dist/types/config/file-lock.d.ts +18 -0
- package/dist/types/config/model-profile-activation.d.ts +3 -1
- package/dist/types/config/model-registry.d.ts +9 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +70 -6
- package/dist/types/config/settings.d.ts +63 -0
- package/dist/types/config/skill-settings-defaults.d.ts +26 -0
- package/dist/types/config/task-delegation.d.ts +39 -0
- package/dist/types/config/update-channel.d.ts +10 -0
- package/dist/types/coordinator-mcp/server.d.ts +5 -1
- package/dist/types/crash/index-store.d.ts +87 -0
- package/dist/types/crash/nudge.d.ts +50 -0
- package/dist/types/crash/record-loader.d.ts +17 -0
- package/dist/types/crash/report.d.ts +134 -0
- package/dist/types/crash/sanitize.d.ts +25 -0
- package/dist/types/cursor.d.ts +13 -2
- package/dist/types/customization/import.d.ts +37 -0
- package/dist/types/customization/index.d.ts +4 -0
- package/dist/types/customization/inventory.d.ts +25 -0
- package/dist/types/customization/mutations.d.ts +32 -0
- package/dist/types/customization/types.d.ts +115 -0
- package/dist/types/daemon/control-types.d.ts +8 -1
- package/dist/types/daemon/operator-contract.d.ts +4 -4
- package/dist/types/discovery/claude.d.ts +39 -1
- package/dist/types/discovery/codex.d.ts +39 -1
- package/dist/types/discovery/index.d.ts +2 -0
- package/dist/types/discovery/mcp-compat.d.ts +30 -0
- package/dist/types/edit/renderer.d.ts +23 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +21 -4
- package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
- package/dist/types/extensibility/hooks/loader.d.ts +19 -5
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
- package/dist/types/extensibility/skill-management.d.ts +107 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
- package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
- package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
- package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
- package/dist/types/hooks/events.d.ts +60 -0
- package/dist/types/hooks/normalize.d.ts +83 -0
- package/dist/types/hooks/skill-state.d.ts +9 -2
- package/dist/types/main.d.ts +1 -1
- package/dist/types/modes/acp/abort-scope.d.ts +13 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -4
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
- package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
- package/dist/types/modes/components/customization/index.d.ts +1 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +8 -30
- package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
- package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
- package/dist/types/modes/components/oauth-selector.d.ts +10 -4
- package/dist/types/modes/components/pet-capability.d.ts +11 -25
- package/dist/types/modes/components/status-line/gh.d.ts +6 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
- package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
- package/dist/types/runtime-mcp/config.d.ts +9 -0
- package/dist/types/runtime-mcp/manager.d.ts +26 -1
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
- package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
- package/dist/types/runtime-mcp/protocol.d.ts +278 -0
- package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
- package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
- package/dist/types/runtime-mcp/types.d.ts +102 -10
- package/dist/types/sdk/acp/adapter.d.ts +26 -5
- package/dist/types/sdk/broker/broker.d.ts +3 -55
- package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
- package/dist/types/sdk/broker/session-index.d.ts +14 -5
- package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
- package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
- package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
- package/dist/types/sdk/bus/index.d.ts +85 -99
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
- package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
- package/dist/types/sdk/bus/notification-service.d.ts +52 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
- package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
- package/dist/types/sdk/bus/session-control.d.ts +25 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
- package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
- package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
- package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
- package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
- package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
- package/dist/types/sdk/cli/rows.d.ts +2 -11
- package/dist/types/sdk/cli/session-cli.d.ts +15 -25
- package/dist/types/sdk/client/client.d.ts +97 -1
- package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +18 -5
- package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
- package/dist/types/sdk/host/host.d.ts +15 -1
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/host/session-runtime.d.ts +127 -7
- package/dist/types/sdk/host/types.d.ts +1 -1
- package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
- package/dist/types/sdk/index.d.ts +2 -1
- package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
- package/dist/types/sdk/lifecycle/client.d.ts +59 -0
- package/dist/types/sdk/lifecycle/index.d.ts +3 -0
- package/dist/types/sdk/lifecycle/service.d.ts +232 -0
- package/dist/types/sdk/mcp/server.d.ts +9 -6
- package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
- package/dist/types/sdk/prompt-status.d.ts +10 -3
- package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
- package/dist/types/sdk/receipt-state.d.ts +17 -0
- package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
- package/dist/types/sdk/router/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +152 -0
- package/dist/types/sdk/session-list.d.ts +22 -0
- package/dist/types/sdk/session-reconnect.d.ts +43 -1
- package/dist/types/sdk/session.d.ts +34 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
- package/dist/types/session/account-inventory.d.ts +86 -0
- package/dist/types/session/agent-session.d.ts +145 -6
- package/dist/types/session/agent-storage.d.ts +10 -0
- package/dist/types/session/coordinator-tool-label.d.ts +28 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/secure-token-file.d.ts +3 -0
- package/dist/types/session/session-manager.d.ts +40 -1
- package/dist/types/session/startup-auth-config.d.ts +44 -0
- package/dist/types/session/terminal-abort.d.ts +378 -0
- package/dist/types/session/yield-queue.d.ts +7 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +88 -0
- package/dist/types/session-import/command.d.ts +35 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/provider-codex.d.ts +22 -0
- package/dist/types/session-import/provider-service.d.ts +38 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +47 -0
- package/dist/types/session-import/types.d.ts +120 -0
- package/dist/types/setup/paseo/check.d.ts +16 -0
- package/dist/types/setup/paseo/install-saga.d.ts +115 -0
- package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
- package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
- package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
- package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
- package/dist/types/setup/paseo/provider-config.d.ts +35 -0
- package/dist/types/setup/paseo/remove.d.ts +14 -0
- package/dist/types/setup/paseo/result-types.d.ts +59 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
- package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
- package/dist/types/skill-state/active-state.d.ts +5 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
- package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
- package/dist/types/slash-commands/types.d.ts +7 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/tools/ask-answer-registry.d.ts +6 -3
- package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
- package/dist/types/tools/bash.d.ts +2 -6
- package/dist/types/tools/browser/attach.d.ts +11 -0
- package/dist/types/tools/browser/launch.d.ts +20 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +9 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/monitor.d.ts +1 -1
- package/dist/types/tools/skill-discovery.d.ts +8 -1
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
- package/dist/types/utils/herdr-pane.d.ts +76 -0
- package/package.json +19 -9
- package/scripts/build-binary.ts +2 -1
- package/scripts/build-sdk-package-smoke.ts +2 -13
- package/scripts/capture-sticky-viewport-showcase.ts +0 -1
- package/scripts/compile-args.ts +2 -0
- package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
- package/scripts/generate-sdk-operation-inventory.ts +28 -0
- package/scripts/generate-telegram-baseline-manifest.ts +1 -0
- package/scripts/generate-tool-catalog.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
- package/src/async/job-manager.ts +352 -17
- package/src/async/support.ts +25 -0
- package/src/autoresearch/dashboard.ts +28 -13
- package/src/capability/index.ts +3 -1
- package/src/capability/mcp.ts +6 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/accounts-cli.ts +395 -0
- package/src/cli/args.ts +23 -0
- package/src/cli/auth-broker-cli.ts +136 -66
- package/src/cli/auth-gateway-cli.ts +94 -70
- package/src/cli/config-cli.ts +27 -2
- package/src/cli/crash-cli.ts +78 -0
- package/src/cli/customize-doctor.ts +1605 -0
- package/src/cli/daemon-cli.ts +12 -3
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/mcp-cli.ts +128 -60
- package/src/cli/notify-cli.ts +8 -14
- package/src/cli/root-flags.ts +8 -0
- package/src/cli/setup-cli.ts +145 -0
- package/src/cli/skills-cli.ts +38 -2
- package/src/cli/update-cli.ts +167 -12
- package/src/cli.ts +4 -0
- package/src/commands/accounts.ts +71 -0
- package/src/commands/crash.ts +35 -0
- package/src/commands/customize.ts +84 -0
- package/src/commands/daemon.ts +2 -2
- package/src/commands/deep-interview.ts +2 -0
- package/src/commands/launch.ts +1 -0
- package/src/commands/mcp.ts +12 -7
- package/src/commands/ralplan.ts +2 -0
- package/src/commands/sdk.ts +65 -32
- package/src/commands/setup.ts +5 -0
- package/src/commands/skills.ts +14 -4
- package/src/commands/ultragoal.ts +10 -1
- package/src/commands/update.ts +26 -15
- package/src/config/atomic-yaml-patch-worker.ts +57 -0
- package/src/config/atomic-yaml-patch.ts +769 -29
- package/src/config/config-schema-version.ts +10 -0
- package/src/config/file-lock.ts +70 -1
- package/src/config/mcp-schema.json +52 -14
- package/src/config/model-profile-activation.ts +20 -1
- package/src/config/model-profiles.ts +29 -19
- package/src/config/model-registry.ts +132 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +76 -6
- package/src/config/settings.ts +4038 -199
- package/src/config/skill-settings-defaults.ts +41 -3
- package/src/config/task-delegation.ts +87 -0
- package/src/config/update-channel.ts +23 -0
- package/src/coordinator-mcp/server.ts +377 -308
- package/src/crash/index-store.ts +723 -0
- package/src/crash/nudge.ts +89 -0
- package/src/crash/record-loader.ts +149 -0
- package/src/crash/report.ts +551 -0
- package/src/crash/sanitize.ts +129 -0
- package/src/cursor.ts +36 -10
- package/src/customization/import.ts +946 -0
- package/src/customization/index.ts +4 -0
- package/src/customization/inventory.ts +335 -0
- package/src/customization/mutations.ts +141 -0
- package/src/customization/types.ts +223 -0
- package/src/daemon/control-types.ts +8 -1
- package/src/daemon/operator-contract.ts +6 -6
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
- package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/discovery/claude-hooks.ts +38 -0
- package/src/discovery/claude.ts +142 -209
- package/src/discovery/codex-hooks.ts +38 -0
- package/src/discovery/codex.ts +132 -198
- package/src/discovery/helpers.ts +8 -1
- package/src/discovery/index.ts +2 -0
- package/src/discovery/mcp-compat.ts +234 -0
- package/src/discovery/mcp-json.ts +6 -0
- package/src/edit/renderer.ts +40 -0
- package/src/edit/streaming.ts +4 -2
- package/src/exec/bash-executor.ts +24 -20
- package/src/export/html/index.ts +51 -2
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +17 -4
- package/src/extensibility/extensions/types.ts +31 -6
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
- package/src/extensibility/gjc-plugins/installer.ts +9 -5
- package/src/extensibility/gjc-plugins/observability.ts +8 -2
- package/src/extensibility/gjc-plugins/registry.ts +13 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
- package/src/extensibility/gjc-plugins/schema.ts +222 -39
- package/src/extensibility/hooks/loader.ts +154 -10
- package/src/extensibility/runtime-skill-discovery.ts +257 -60
- package/src/extensibility/skill-management.ts +368 -0
- package/src/extensibility/skills.ts +52 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
- package/src/gjc-runtime/launch-worktree.ts +56 -2
- package/src/gjc-runtime/linux-proc.ts +7 -1
- package/src/gjc-runtime/ralplan-runtime.ts +100 -164
- package/src/gjc-runtime/session-state-lock.ts +992 -0
- package/src/gjc-runtime/session-state-sidecar.ts +644 -142
- package/src/gjc-runtime/state-writer.ts +39 -14
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
- package/src/gjc-runtime/ultragoal-guard.ts +11 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
- package/src/gjc-runtime/workflow-settings.ts +596 -0
- package/src/goals/tools/goal-tool.ts +6 -1
- package/src/hooks/events.ts +291 -0
- package/src/hooks/native-skill-hook.ts +4 -0
- package/src/hooks/normalize.ts +369 -0
- package/src/hooks/skill-state.ts +165 -46
- package/src/internal-urls/docs-index.generated.ts +40 -32
- package/src/main.ts +32 -5
- package/src/migrate/mcp-mapper.ts +25 -2
- package/src/modes/acp/abort-scope.ts +29 -0
- package/src/modes/acp/acp-agent.ts +423 -98
- package/src/modes/components/assistant-message.ts +6 -1
- package/src/modes/components/customization/customization-dashboard.ts +443 -0
- package/src/modes/components/customization/import-wizard.ts +372 -0
- package/src/modes/components/customization/index.ts +1 -0
- package/src/modes/components/gajae-pet-widget.ts +539 -213
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +39 -40
- package/src/modes/components/settings-selector.ts +9 -0
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +16 -1
- package/src/modes/components/tool-status-header.ts +13 -3
- package/src/modes/controllers/command-controller.ts +20 -8
- package/src/modes/controllers/extension-ui-controller.ts +56 -257
- package/src/modes/controllers/input-controller.ts +10 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
- package/src/modes/controllers/selector-controller.ts +177 -72
- package/src/modes/controllers/stt-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +88 -16
- package/src/modes/print-mode.ts +35 -6
- package/src/modes/runtime-init.ts +21 -68
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/injected-user-submission.ts +25 -0
- package/src/modes/utils/terminal-bell.ts +15 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/critic.md +1 -1
- package/src/prompts/system/rlm-research.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -2
- package/src/prompts/tools/bash.md +7 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +6 -6
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/skill-discovery.md +4 -2
- package/src/runtime-mcp/client.ts +427 -23
- package/src/runtime-mcp/config.ts +37 -5
- package/src/runtime-mcp/manager-pool.test.ts +56 -0
- package/src/runtime-mcp/manager.ts +52 -2
- package/src/runtime-mcp/oauth-discovery.ts +13 -0
- package/src/runtime-mcp/oauth-flow.ts +46 -1
- package/src/runtime-mcp/pool-key.ts +5 -1
- package/src/runtime-mcp/pool.test.ts +9 -0
- package/src/runtime-mcp/protocol.test.ts +353 -0
- package/src/runtime-mcp/protocol.ts +624 -0
- package/src/runtime-mcp/scope-config.ts +78 -0
- package/src/runtime-mcp/tool-bridge.ts +44 -10
- package/src/runtime-mcp/transports/http.ts +84 -13
- package/src/runtime-mcp/types.ts +123 -12
- package/src/sdk/acp/adapter.ts +328 -97
- package/src/sdk/broker/broker.ts +160 -741
- package/src/sdk/broker/ensure.ts +9 -1
- package/src/sdk/broker/lifecycle.ts +510 -116
- package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
- package/src/sdk/broker/process-incarnation.ts +19 -0
- package/src/sdk/broker/session-index.ts +516 -117
- package/src/sdk/broker/startup-failure.ts +28 -5
- package/src/sdk/broker/transport.ts +1 -13
- package/src/sdk/bus/chat-daemon-cli.ts +4 -2
- package/src/sdk/bus/chat-daemon-control.ts +67 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
- package/src/sdk/bus/config.ts +13 -0
- package/src/sdk/bus/conversation-store.ts +59 -171
- package/src/sdk/bus/daemon-paths.ts +20 -0
- package/src/sdk/bus/discord-conversation.ts +2 -0
- package/src/sdk/bus/discord-daemon.ts +524 -126
- package/src/sdk/bus/discord-live-provider.ts +206 -79
- package/src/sdk/bus/existing-thread-readiness.ts +4 -97
- package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
- package/src/sdk/bus/index.ts +2480 -456
- package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
- package/src/sdk/bus/lifecycle-commands.ts +2 -2
- package/src/sdk/bus/managed-daemon.ts +2 -145
- package/src/sdk/bus/notification-service.ts +196 -0
- package/src/sdk/bus/operator-runtime.ts +1 -1
- package/src/sdk/bus/prompt-reconciliation.ts +24 -15
- package/src/sdk/bus/reconciliation-store.ts +553 -24
- package/src/sdk/bus/session-control.ts +49 -3
- package/src/sdk/bus/slack-conversation.ts +4 -0
- package/src/sdk/bus/slack-daemon.ts +733 -134
- package/src/sdk/bus/slack-live-provider.ts +65 -15
- package/src/sdk/bus/slack-provider.ts +4 -0
- package/src/sdk/bus/slack-thread-binding.ts +9 -104
- package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
- package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
- package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
- package/src/sdk/bus/telegram-daemon-control.ts +3 -13
- package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
- package/src/sdk/bus/telegram-daemon.ts +2552 -2280
- package/src/sdk/bus/telegram-reference.ts +1 -226
- package/src/sdk/bus/telegram-setup.ts +2 -2
- package/src/sdk/bus/threaded-render.ts +1 -0
- package/src/sdk/bus/topic-registry.ts +279 -146
- package/src/sdk/cli/rows.ts +2 -35
- package/src/sdk/cli/session-cli.ts +776 -700
- package/src/sdk/client/client.ts +892 -1
- package/src/sdk/host/control/dispatch.ts +93 -58
- package/src/sdk/host/control/index.ts +1 -1
- package/src/sdk/host/control/operations.ts +18 -10
- package/src/sdk/host/control/runtime-gate.ts +40 -0
- package/src/sdk/host/host.ts +63 -12
- package/src/sdk/host/query/handlers.ts +66 -7
- package/src/sdk/host/reverse-leases.ts +2 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
- package/src/sdk/host/session-runtime.test.ts +2787 -34
- package/src/sdk/host/session-runtime.ts +1489 -101
- package/src/sdk/host/surface-policy.ts +12 -8
- package/src/sdk/host/types.ts +1 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
- package/src/sdk/host/websocket-transport.ts +85 -50
- package/src/sdk/index.ts +2 -1
- package/src/sdk/lifecycle/broker-client.ts +53 -0
- package/src/sdk/lifecycle/client.ts +234 -0
- package/src/sdk/lifecycle/index.ts +3 -0
- package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
- package/src/sdk/lifecycle/service.ts +720 -0
- package/src/sdk/mcp/server.ts +226 -188
- package/src/sdk/prompt-deadline-lease.ts +55 -0
- package/src/sdk/prompt-deadline-manager.ts +148 -0
- package/src/sdk/prompt-status.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +272 -129
- package/src/sdk/protocol/operation-registry.ts +71 -8
- package/src/sdk/receipt-state.ts +43 -0
- package/src/sdk/reconciliation-extensions.ts +14 -0
- package/src/sdk/router/index.ts +1 -0
- package/src/sdk/router/session-router.ts +1658 -0
- package/src/sdk/session-list.ts +93 -0
- package/src/sdk/session-reconnect.ts +45 -1
- package/src/sdk/session.ts +716 -120
- package/src/sdk/transport/serve-cli.ts +18 -34
- package/src/session/account-inventory.ts +603 -0
- package/src/session/agent-session.ts +2857 -582
- package/src/session/agent-storage.ts +35 -0
- package/src/session/blob-store.ts +32 -1
- package/src/session/coordinator-tool-label.ts +40 -0
- package/src/session/internal/managed-session-scope.ts +4 -0
- package/src/session/internal/managed-session-storage.ts +173 -12
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +730 -58
- package/src/session/session-storage.ts +25 -16
- package/src/session/startup-auth-config.ts +297 -0
- package/src/session/terminal-abort.ts +1253 -0
- package/src/session/yield-queue.ts +57 -15
- package/src/session-import/claude.ts +334 -0
- package/src/session-import/codex.ts +1033 -0
- package/src/session-import/command.ts +77 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +7 -0
- package/src/session-import/provider-codex.ts +327 -0
- package/src/session-import/provider-service.ts +457 -0
- package/src/session-import/redact.ts +128 -0
- package/src/session-import/service.ts +1264 -0
- package/src/session-import/types.ts +148 -0
- package/src/setup/paseo/check.ts +213 -0
- package/src/setup/paseo/install-saga.ts +293 -0
- package/src/setup/paseo/json-publisher.ts +263 -0
- package/src/setup/paseo/orchestration-preferences.ts +86 -0
- package/src/setup/paseo/paseo-ownership.ts +224 -0
- package/src/setup/paseo/paseo-setup.ts +253 -0
- package/src/setup/paseo/provider-config.ts +139 -0
- package/src/setup/paseo/remove.ts +183 -0
- package/src/setup/paseo/result-types.ts +79 -0
- package/src/setup/paseo/setup-deps.ts +175 -0
- package/src/setup/paseo/skills-bridge.ts +260 -0
- package/src/skill-state/active-state.ts +21 -11
- package/src/slash-commands/acp-builtins.ts +9 -1
- package/src/slash-commands/builtin-registry.ts +98 -16
- package/src/slash-commands/helpers/credential-switch.ts +143 -0
- package/src/slash-commands/helpers/mcp.ts +9 -3
- package/src/slash-commands/helpers/usage-report.ts +61 -56
- package/src/slash-commands/types.ts +7 -2
- package/src/task/executor.ts +30 -11
- package/src/task/index.ts +66 -7
- package/src/task/render.ts +23 -9
- package/src/tools/ask-answer-registry.ts +23 -7
- package/src/tools/ask.ts +8 -4
- package/src/tools/bash-sleep-advisory.ts +115 -0
- package/src/tools/bash.ts +98 -18
- package/src/tools/browser/attach.ts +71 -3
- package/src/tools/browser/launch.ts +86 -13
- package/src/tools/browser/profile-discovery.ts +57 -7
- package/src/tools/browser/render.ts +8 -1
- package/src/tools/browser.ts +130 -21
- package/src/tools/computer.enforcement.test.ts +1 -1
- package/src/tools/computer.ts +3 -2
- package/src/tools/cron.ts +12 -1
- package/src/tools/image-gen.ts +27 -16
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +33 -6
- package/src/tools/monitor.ts +41 -2
- package/src/tools/skill-discovery.ts +21 -29
- package/src/tools/subagent.ts +142 -24
- package/src/tools/tool-catalog.generated.ts +6 -6
- package/src/tools/ultragoal-ask-guard.ts +10 -3
- package/src/utils/herdr-pane.ts +345 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/scrapers/index.ts +6 -4
- package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
- package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
- package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
- package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
- package/dist/types/runtime/lazy-service.test.d.ts +0 -1
- package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
- package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
- package/dist/types/runtime-mcp/config.test.d.ts +0 -1
- package/dist/types/runtime-mcp/http.test.d.ts +0 -1
- package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
- package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
- package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
- package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
- package/dist/types/sdk/elevation/audit.d.ts +0 -93
- package/dist/types/sdk/elevation/capability.d.ts +0 -3
- package/dist/types/sdk/elevation/digest.d.ts +0 -72
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
- package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
- package/dist/types/sdk/elevation/owner.d.ts +0 -48
- package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
- package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
- package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
- package/dist/types/session/auth-broker-config.d.ts +0 -13
- package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
- package/dist/types/skills/skills.test.d.ts +0 -1
- package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
- package/dist/types/task/token-log.test.d.ts +0 -1
- package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
- package/dist/types/tools/descriptors.test.d.ts +0 -1
- package/scripts/g005-daemon-smoke.ts +0 -180
- package/scripts/g011-daemon-path-smoke.ts +0 -153
- package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
- package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
- package/src/sdk/bus/telegram-cli.ts +0 -212
- package/src/sdk/elevation/allowlist.ts +0 -54
- package/src/sdk/elevation/audit.ts +0 -208
- package/src/sdk/elevation/capability.ts +0 -41
- package/src/sdk/elevation/digest.ts +0 -129
- package/src/sdk/elevation/dispatch-receipt.ts +0 -184
- package/src/sdk/elevation/grant-ledger.ts +0 -1142
- package/src/sdk/elevation/owner.ts +0 -109
- package/src/session/auth-broker-config.ts +0 -109
- /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
- /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
- /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
package/src/async/job-manager.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { logger } from "@gajae-code/utils";
|
|
2
|
+
import {
|
|
3
|
+
lookupOwnedRegistration,
|
|
4
|
+
registerOwnedRegistration,
|
|
5
|
+
resolveToolLineage,
|
|
6
|
+
retireOwnedRegistrationForDeadLetter,
|
|
7
|
+
unregisterOwnedRegistration,
|
|
8
|
+
} from "../session/terminal-abort";
|
|
2
9
|
import type { AgentProgress, AgentSource } from "../task/types";
|
|
3
10
|
|
|
4
11
|
const DELIVERY_RETRY_BASE_MS = 500;
|
|
@@ -160,7 +167,13 @@ export interface SubagentRecord {
|
|
|
160
167
|
* file, followed by a separately available runner (`no_runner` otherwise).
|
|
161
168
|
*/
|
|
162
169
|
resumable: boolean;
|
|
163
|
-
queued?: { ownerId?: string; seq: number; message?: string; createdAt: number };
|
|
170
|
+
queued?: { ownerId?: string; seq: number; message?: string; resumeToolCallId?: string; createdAt: number };
|
|
171
|
+
/** Last queued-resume seq for a CANCELLED queued resume (rec.queued is
|
|
172
|
+
* cleared on cancel): retained on the record so owned settlement's second
|
|
173
|
+
* proof can still see the generation as provably cancelled, without a
|
|
174
|
+
* separate FIFO-capped evidence set that could evict an in-flight
|
|
175
|
+
* settlement's generation (review thread P2). */
|
|
176
|
+
terminalQueuedSeq?: number;
|
|
164
177
|
/** Resolved model the subagent was asked to use, e.g. "openai-codex/gpt-5.5". */
|
|
165
178
|
requestedModel?: string;
|
|
166
179
|
/** Model actually used after auth fallback (#985); equals requestedModel when no fallback. */
|
|
@@ -187,7 +200,12 @@ export interface ResumeDescriptor {
|
|
|
187
200
|
* In-memory resume runner bound to the session that originally launched a
|
|
188
201
|
* subagent. Never serialized: process restart drops it so resume fails closed.
|
|
189
202
|
*/
|
|
190
|
-
export type ResumeRunner = (
|
|
203
|
+
export type ResumeRunner = (
|
|
204
|
+
subagentId: string,
|
|
205
|
+
message?: string,
|
|
206
|
+
descriptor?: ResumeDescriptor,
|
|
207
|
+
resumeToolCallId?: string,
|
|
208
|
+
) => string | undefined;
|
|
191
209
|
|
|
192
210
|
function sessionFileFromResumeDescriptorData(data: unknown): string | null {
|
|
193
211
|
if (typeof data !== "object" || data === null) return null;
|
|
@@ -326,6 +344,10 @@ export interface AsyncJobWaitHandle {
|
|
|
326
344
|
close(): void;
|
|
327
345
|
}
|
|
328
346
|
|
|
347
|
+
export interface AsyncJobWatchHandle {
|
|
348
|
+
close(): number;
|
|
349
|
+
}
|
|
350
|
+
|
|
329
351
|
interface TerminalEvent {
|
|
330
352
|
generation: string;
|
|
331
353
|
jobId: string | null;
|
|
@@ -429,6 +451,82 @@ export class AsyncJobManager {
|
|
|
429
451
|
return AsyncJobManager.#instance;
|
|
430
452
|
}
|
|
431
453
|
|
|
454
|
+
static readonly #byEndpoint = new Map<string, AsyncJobManager>();
|
|
455
|
+
|
|
456
|
+
/** Register a manager for a top-level session endpoint so concurrent
|
|
457
|
+
* sessions' owned work can be settled in the ABORTING endpoint's manager
|
|
458
|
+
* instead of the last-created process-global instance (review thread P1).
|
|
459
|
+
* Returns TRUE when the mapping was installed (or already held by this
|
|
460
|
+
* manager); returns FALSE when the endpoint id is already held by a
|
|
461
|
+
* FOREIGN live manager — a second top-level session constructed or
|
|
462
|
+
* resumed under that endpoint must then fail construction instead of
|
|
463
|
+
* silently replacing the first manager, which would make the first
|
|
464
|
+
* session's tools resolve the second manager and let same-id jobs be
|
|
465
|
+
* queried, registered, or cancelled across sessions (review thread P1). */
|
|
466
|
+
static registerForEndpoint(endpointId: string, manager: AsyncJobManager): boolean {
|
|
467
|
+
const holder = AsyncJobManager.#byEndpoint.get(endpointId);
|
|
468
|
+
if (holder !== undefined && holder !== manager) return false;
|
|
469
|
+
AsyncJobManager.#byEndpoint.set(endpointId, manager);
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
static forEndpoint(endpointId: string | undefined): AsyncJobManager | undefined {
|
|
474
|
+
if (endpointId === undefined) return undefined;
|
|
475
|
+
return AsyncJobManager.#byEndpoint.get(endpointId);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
static unregisterForEndpoint(endpointId: string): void {
|
|
479
|
+
AsyncJobManager.#byEndpoint.delete(endpointId);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Reverse lookup: the endpoint this manager is registered under, if any
|
|
483
|
+
* (review thread P1 — endpoint-scoped lineage resolution). */
|
|
484
|
+
static endpointIdOf(manager: AsyncJobManager | undefined): string | undefined {
|
|
485
|
+
if (!manager) return undefined;
|
|
486
|
+
for (const [endpointId, candidate] of AsyncJobManager.#byEndpoint) {
|
|
487
|
+
if (candidate === manager) return endpointId;
|
|
488
|
+
}
|
|
489
|
+
return undefined;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** Re-register a manager under a successor endpoint id after a committed
|
|
493
|
+
* session-identity transition (newSession / switchSession / handoff).
|
|
494
|
+
* Lineage bindings made after the transition use the successor id, so the
|
|
495
|
+
* process-global endpoint registry must follow — otherwise
|
|
496
|
+
* `endpointIdOf()` keeps resolving the predecessor and a queued subagent
|
|
497
|
+
* resume can neither resolve its lineage nor register its owned tuple
|
|
498
|
+
* (review thread P1). Returns TRUE when the mapping was moved (or no move
|
|
499
|
+
* was needed); returns FALSE when the successor endpoint is owned by a
|
|
500
|
+
* FOREIGN live manager — the transition must then abort or roll back
|
|
501
|
+
* BEFORE retiring predecessor state, because leaving this manager under
|
|
502
|
+
* the predecessor while tools resolve the successor to the foreign
|
|
503
|
+
* manager sends jobs to the wrong session and owned aborts lose their
|
|
504
|
+
* causal set (review thread P1). */
|
|
505
|
+
static rekeyForEndpoint(
|
|
506
|
+
predecessorEndpointId: string,
|
|
507
|
+
successorEndpointId: string,
|
|
508
|
+
manager: AsyncJobManager | undefined,
|
|
509
|
+
): boolean {
|
|
510
|
+
if (!manager || predecessorEndpointId === successorEndpointId) return true;
|
|
511
|
+
if (AsyncJobManager.#byEndpoint.get(predecessorEndpointId) !== manager) return true;
|
|
512
|
+
const successorOwner = AsyncJobManager.#byEndpoint.get(successorEndpointId);
|
|
513
|
+
if (successorOwner !== undefined && successorOwner !== manager) return false;
|
|
514
|
+
AsyncJobManager.#byEndpoint.delete(predecessorEndpointId);
|
|
515
|
+
AsyncJobManager.#byEndpoint.set(successorEndpointId, manager);
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** Remove every endpoint registration owned by the manager. Disposal-safe:
|
|
520
|
+
* covers registrations whose key drifted from the session's current id
|
|
521
|
+
* (provider session ids, mid-transition teardown) and stale predecessor
|
|
522
|
+
* keys, so teardown cannot leave a dead manager behind. */
|
|
523
|
+
static unregisterManager(manager: AsyncJobManager | undefined): void {
|
|
524
|
+
if (!manager) return;
|
|
525
|
+
for (const [endpointId, candidate] of [...AsyncJobManager.#byEndpoint]) {
|
|
526
|
+
if (candidate === manager) AsyncJobManager.#byEndpoint.delete(endpointId);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
432
530
|
/** Install or clear the process-global instance. */
|
|
433
531
|
static setInstance(value: AsyncJobManager | undefined): void {
|
|
434
532
|
AsyncJobManager.#instance = value;
|
|
@@ -437,6 +535,7 @@ export class AsyncJobManager {
|
|
|
437
535
|
/** Reset the process-global instance. Test-only. */
|
|
438
536
|
static resetForTests(): void {
|
|
439
537
|
AsyncJobManager.#instance = undefined;
|
|
538
|
+
AsyncJobManager.#byEndpoint.clear();
|
|
440
539
|
}
|
|
441
540
|
|
|
442
541
|
readonly #jobs = new Map<string, AsyncJob>();
|
|
@@ -444,7 +543,8 @@ export class AsyncJobManager {
|
|
|
444
543
|
readonly #inFlightDeliveries: AsyncJobDelivery[] = [];
|
|
445
544
|
readonly #suppressedDeliveries = new Set<string>();
|
|
446
545
|
readonly #deliveryAckOwners = new Map<string, string>();
|
|
447
|
-
readonly #watchedJobs = new
|
|
546
|
+
readonly #watchedJobs = new Map<string, number>();
|
|
547
|
+
readonly #watchedGenerations = new Map<string, number>();
|
|
448
548
|
readonly #evictionTimers = new Map<string, NodeJS.Timeout>();
|
|
449
549
|
readonly #outputState = new Map<string, AsyncJobOutputState>();
|
|
450
550
|
readonly #ownerCleanups = new Map<string, Set<() => void>>();
|
|
@@ -863,6 +963,11 @@ export class AsyncJobManager {
|
|
|
863
963
|
this.#runLifecycle(id, "terminal", job);
|
|
864
964
|
this.#scheduleEviction(id);
|
|
865
965
|
this.#drainResumeQueue();
|
|
966
|
+
// The run has now actually unwound: retire the owned tuple so a
|
|
967
|
+
// later scope:"owned" abort of the same turn does not report
|
|
968
|
+
// stopped/stopped_owned while this job is still executing
|
|
969
|
+
// (review thread P1).
|
|
970
|
+
this.#retireCancelledJobOwned(id, job.generation);
|
|
866
971
|
return;
|
|
867
972
|
}
|
|
868
973
|
if (outcome.kind === "paused") {
|
|
@@ -908,6 +1013,7 @@ export class AsyncJobManager {
|
|
|
908
1013
|
this.#runLifecycle(id, "terminal", job);
|
|
909
1014
|
this.#scheduleEviction(id);
|
|
910
1015
|
this.#drainResumeQueue();
|
|
1016
|
+
this.#retireCancelledJobOwned(id, job.generation);
|
|
911
1017
|
return;
|
|
912
1018
|
}
|
|
913
1019
|
const errorText = error instanceof Error ? error.message : String(error);
|
|
@@ -936,6 +1042,17 @@ export class AsyncJobManager {
|
|
|
936
1042
|
* so cross-agent cancellation is rejected at the manager level.
|
|
937
1043
|
*/
|
|
938
1044
|
cancel(id: string, filter?: AsyncJobFilter): boolean {
|
|
1045
|
+
if (id.startsWith("queued:")) {
|
|
1046
|
+
// A queued resume (no real job yet): owned settlement cancels it by
|
|
1047
|
+
// removing the queued subagent record and publishing the terminal
|
|
1048
|
+
// (review thread P1).
|
|
1049
|
+
const colon = id.lastIndexOf(":");
|
|
1050
|
+
const subagentId = colon > "queued:".length ? id.slice("queued:".length, colon) : undefined;
|
|
1051
|
+
if (!subagentId) return false;
|
|
1052
|
+
const rec = this.getSubagentRecord(subagentId);
|
|
1053
|
+
if (rec?.status !== "queued") return false;
|
|
1054
|
+
return this.cancelSubagent(subagentId, filter);
|
|
1055
|
+
}
|
|
939
1056
|
const job = this.#jobs.get(id);
|
|
940
1057
|
if (!job) return false;
|
|
941
1058
|
if (filter?.ownerId && job.ownerId !== filter.ownerId) return false;
|
|
@@ -949,6 +1066,10 @@ export class AsyncJobManager {
|
|
|
949
1066
|
this.#runLifecycle(id, "cancel");
|
|
950
1067
|
this.#scheduleEviction(id);
|
|
951
1068
|
this.#drainResumeQueue();
|
|
1069
|
+
// A PAUSED job's run has already unwound (it returned "paused"), so
|
|
1070
|
+
// its owned tuple is retired here; a RUNNING job's tuple is retired
|
|
1071
|
+
// from the settlement path once the run actually unwinds below.
|
|
1072
|
+
this.#retireCancelledJobOwned(id, job.generation);
|
|
952
1073
|
return true;
|
|
953
1074
|
}
|
|
954
1075
|
if (job.status !== "running") return false;
|
|
@@ -1463,6 +1584,7 @@ export class AsyncJobManager {
|
|
|
1463
1584
|
subagentId: string,
|
|
1464
1585
|
filter?: AsyncJobFilter,
|
|
1465
1586
|
message?: string,
|
|
1587
|
+
resumeToolCallId?: string,
|
|
1466
1588
|
): { ok: boolean; status?: SubagentLifecycle; jobId?: string; queued?: boolean; reason?: string } {
|
|
1467
1589
|
const rec = this.getSubagentRecord(subagentId, filter);
|
|
1468
1590
|
if (!rec) return { ok: false, reason: "not_found" };
|
|
@@ -1487,24 +1609,81 @@ export class AsyncJobManager {
|
|
|
1487
1609
|
if (this.getRunningJobs().length >= this.#maxRunningJobs) {
|
|
1488
1610
|
const seq = ++this.#resumeSeq;
|
|
1489
1611
|
rec.status = "queued";
|
|
1490
|
-
rec.queued = {
|
|
1612
|
+
rec.queued = {
|
|
1613
|
+
ownerId: rec.ownerId,
|
|
1614
|
+
seq,
|
|
1615
|
+
message,
|
|
1616
|
+
...(resumeToolCallId ? { resumeToolCallId } : {}),
|
|
1617
|
+
createdAt: Date.now(),
|
|
1618
|
+
};
|
|
1491
1619
|
this.#resumeQueue.push({
|
|
1492
1620
|
subagentId: rec.subagentId,
|
|
1493
1621
|
ownerId: rec.ownerId,
|
|
1494
1622
|
seq,
|
|
1495
1623
|
message,
|
|
1624
|
+
...(resumeToolCallId ? { resumeToolCallId } : {}),
|
|
1496
1625
|
createdAt: rec.queued.createdAt,
|
|
1497
1626
|
});
|
|
1627
|
+
// Register the QUEUED generation as owned work of the resume request's
|
|
1628
|
+
// turn: no real job exists until #startResume drains it, so without a
|
|
1629
|
+
// registration a scope:"owned" abort of the requesting turn would see
|
|
1630
|
+
// an empty causal set, report stopped_owned, and then the queue would
|
|
1631
|
+
// drain and launch the resumed subagent anyway (review thread P1).
|
|
1632
|
+
if (resumeToolCallId) {
|
|
1633
|
+
const lineage = resolveToolLineage(resumeToolCallId, AsyncJobManager.endpointIdOf(this));
|
|
1634
|
+
if (lineage) {
|
|
1635
|
+
const queuedGeneration = `queued:${rec.subagentId}:${seq}`;
|
|
1636
|
+
registerOwnedRegistration({
|
|
1637
|
+
...(lineage.endpointId ? { endpointId: lineage.endpointId } : {}),
|
|
1638
|
+
lineageIdHash: lineage.lineageIdHash,
|
|
1639
|
+
promptAttemptEpoch: lineage.promptAttemptEpoch,
|
|
1640
|
+
endpointGeneration: lineage.endpointGeneration,
|
|
1641
|
+
jobId: queuedGeneration,
|
|
1642
|
+
jobGeneration: queuedGeneration,
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1498
1646
|
this.#notifyChange();
|
|
1499
1647
|
return { ok: true, queued: true, status: "queued" };
|
|
1500
1648
|
}
|
|
1501
|
-
return this.#startResume(rec, message, descriptor);
|
|
1649
|
+
return this.#startResume(rec, message, descriptor, resumeToolCallId);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/** Retire the owned registration of a job that settles WITHOUT a delivery
|
|
1653
|
+
* (explicit cancellation): the cancelled-job completion path deliberately
|
|
1654
|
+
* enqueues no delivery, so the tuple would otherwise persist until
|
|
1655
|
+
* eviction — an owned abort of the same turn then reports owned_unsettled
|
|
1656
|
+
* with no work remaining, and repeated cancellations exhaust the bounded
|
|
1657
|
+
* ownership registries (review thread P2). */
|
|
1658
|
+
#retireCancelledJobOwned(jobId: string, jobGeneration: string): void {
|
|
1659
|
+
const registration = lookupOwnedRegistration(jobId, jobGeneration, AsyncJobManager.endpointIdOf(this));
|
|
1660
|
+
if (registration) unregisterOwnedRegistration(registration);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
#retireQueuedOwned(rec: SubagentRecord): void {
|
|
1664
|
+
const seq = rec.queued?.seq ?? rec.terminalQueuedSeq;
|
|
1665
|
+
if (seq === undefined) return;
|
|
1666
|
+
const queuedGeneration = `queued:${rec.subagentId}:${seq}`;
|
|
1667
|
+
// Resolve the registration with the resume lineage's ENDPOINT identity:
|
|
1668
|
+
// task ids are session-scoped and each manager's resume sequence starts
|
|
1669
|
+
// locally, so concurrent sessions can both register an identical
|
|
1670
|
+
// queued:<subagent>:<seq> generation — an endpoint-less lookup could
|
|
1671
|
+
// retrieve and unregister the OTHER session's tuple (review thread P1).
|
|
1672
|
+
const endpointId = rec.queued?.resumeToolCallId
|
|
1673
|
+
? (resolveToolLineage(rec.queued.resumeToolCallId, AsyncJobManager.endpointIdOf(this))?.endpointId ??
|
|
1674
|
+
// Fall back to the manager's own registered endpoint when the
|
|
1675
|
+
// binding itself predates endpoint keying or is not found.
|
|
1676
|
+
AsyncJobManager.endpointIdOf(this))
|
|
1677
|
+
: AsyncJobManager.endpointIdOf(this);
|
|
1678
|
+
const registration = lookupOwnedRegistration(queuedGeneration, queuedGeneration, endpointId);
|
|
1679
|
+
if (registration) unregisterOwnedRegistration(registration);
|
|
1502
1680
|
}
|
|
1503
1681
|
|
|
1504
1682
|
#startResume(
|
|
1505
1683
|
rec: SubagentRecord,
|
|
1506
1684
|
message: string | undefined,
|
|
1507
1685
|
descriptor: ResumeDescriptor | undefined,
|
|
1686
|
+
resumeToolCallId?: string,
|
|
1508
1687
|
): { ok: boolean; status?: SubagentLifecycle; jobId?: string; reason?: string } {
|
|
1509
1688
|
if (this.#isOwnerSubagentShutdownFenced(rec.ownerId)) {
|
|
1510
1689
|
return { ok: false, status: rec.status, reason: "owner_shutdown_in_progress" };
|
|
@@ -1515,16 +1694,40 @@ export class AsyncJobManager {
|
|
|
1515
1694
|
// never renders the prior run's tool/output as live before it emits again.
|
|
1516
1695
|
this.#subagentProgress.delete(rec.subagentId);
|
|
1517
1696
|
const runner = this.#resolveResumeRunner(rec, descriptor);
|
|
1518
|
-
const newJobId = runner?.(rec.subagentId, message, descriptor);
|
|
1519
|
-
if (!newJobId)
|
|
1697
|
+
const newJobId = runner?.(rec.subagentId, message, descriptor, resumeToolCallId);
|
|
1698
|
+
if (!newJobId) {
|
|
1699
|
+
// The queued resume FAILED to start: retire its owned registration
|
|
1700
|
+
// so the tuple does not accumulate indefinitely (review thread P2).
|
|
1701
|
+
this.#retireQueuedOwned(rec);
|
|
1702
|
+
return { ok: false, reason: "resume_failed" };
|
|
1703
|
+
}
|
|
1520
1704
|
if (prevJobId && prevJobId !== newJobId) rec.historicalJobIds.push(prevJobId);
|
|
1521
1705
|
rec.terminalGeneration = undefined;
|
|
1522
1706
|
rec.currentJobId = newJobId;
|
|
1523
1707
|
rec.currentJobGeneration = this.#jobs.get(newJobId)?.generation;
|
|
1524
1708
|
rec.status = this.#jobs.get(newJobId)?.status ?? "running";
|
|
1525
1709
|
rec.queued = undefined;
|
|
1526
|
-
if (queuedGeneration)
|
|
1710
|
+
if (queuedGeneration) {
|
|
1527
1711
|
this.#waitGenerationAliases.set(queuedGeneration, this.#jobs.get(newJobId)?.generation ?? newJobId);
|
|
1712
|
+
// The queued resume's owned registration is superseded by the real
|
|
1713
|
+
// job's registration (bound by the task tool): remove it so the
|
|
1714
|
+
// causal set has exactly one tuple per job. The EXACT stored tuple
|
|
1715
|
+
// is looked up first — unregisterOwnedRegistration now verifies the
|
|
1716
|
+
// full five-tuple before deleting (review thread P1). The lookup is
|
|
1717
|
+
// ENDPOINT-qualified via the resume lineage: concurrent sessions
|
|
1718
|
+
// mint the same queued:<subagent>:<seq> generation, and the
|
|
1719
|
+
// remaining endpoint-less fallback scan could retrieve and
|
|
1720
|
+
// unregister the OTHER session's tuple (review thread P1).
|
|
1721
|
+
const resumeEndpoint = resumeToolCallId
|
|
1722
|
+
? (resolveToolLineage(resumeToolCallId, AsyncJobManager.endpointIdOf(this))?.endpointId ??
|
|
1723
|
+
// The binding may have been evicted (8192-cap FIFO): fall back
|
|
1724
|
+
// to the manager's own endpoint so the lookup never degrades
|
|
1725
|
+
// into the cross-endpoint scan (review thread P2).
|
|
1726
|
+
AsyncJobManager.endpointIdOf(this))
|
|
1727
|
+
: undefined;
|
|
1728
|
+
const queuedReg = lookupOwnedRegistration(queuedGeneration, queuedGeneration, resumeEndpoint);
|
|
1729
|
+
if (queuedReg) unregisterOwnedRegistration(queuedReg);
|
|
1730
|
+
}
|
|
1528
1731
|
this.#notifyChange();
|
|
1529
1732
|
return { ok: true, status: rec.status, jobId: newJobId };
|
|
1530
1733
|
}
|
|
@@ -1546,15 +1749,22 @@ export class AsyncJobManager {
|
|
|
1546
1749
|
continue;
|
|
1547
1750
|
}
|
|
1548
1751
|
try {
|
|
1549
|
-
const result = this.#startResume(
|
|
1752
|
+
const result = this.#startResume(
|
|
1753
|
+
rec,
|
|
1754
|
+
entry.message,
|
|
1755
|
+
this.#descriptorForRecord(rec),
|
|
1756
|
+
rec.queued?.resumeToolCallId,
|
|
1757
|
+
);
|
|
1550
1758
|
if (!result.ok) {
|
|
1551
1759
|
if (result.reason === "owner_shutdown_in_progress") {
|
|
1552
1760
|
index += 1;
|
|
1553
1761
|
continue;
|
|
1554
1762
|
}
|
|
1555
1763
|
const queuedSeq = rec.queued?.seq;
|
|
1556
|
-
if (queuedSeq !== undefined)
|
|
1764
|
+
if (queuedSeq !== undefined) {
|
|
1765
|
+
this.#retireQueuedOwned(rec);
|
|
1557
1766
|
this.#publishQueuedTerminal(rec.subagentId, `queued:${rec.subagentId}:${queuedSeq}`, "failed");
|
|
1767
|
+
}
|
|
1558
1768
|
}
|
|
1559
1769
|
this.#resumeQueue.splice(index, 1);
|
|
1560
1770
|
} catch (error) {
|
|
@@ -1563,8 +1773,10 @@ export class AsyncJobManager {
|
|
|
1563
1773
|
continue;
|
|
1564
1774
|
}
|
|
1565
1775
|
const queuedSeq = rec.queued?.seq;
|
|
1566
|
-
if (queuedSeq !== undefined)
|
|
1776
|
+
if (queuedSeq !== undefined) {
|
|
1777
|
+
this.#retireQueuedOwned(rec);
|
|
1567
1778
|
this.#publishQueuedTerminal(rec.subagentId, `queued:${rec.subagentId}:${queuedSeq}`, "failed");
|
|
1779
|
+
}
|
|
1568
1780
|
this.#resumeQueue.splice(index, 1);
|
|
1569
1781
|
}
|
|
1570
1782
|
}
|
|
@@ -1587,6 +1799,13 @@ export class AsyncJobManager {
|
|
|
1587
1799
|
if (shouldScheduleEviction && currentJobId) this.#scheduleEviction(currentJobId);
|
|
1588
1800
|
else this.#notifyChange();
|
|
1589
1801
|
this.#drainResumeQueue();
|
|
1802
|
+
// A paused run has already unwound (it returned "paused") and this
|
|
1803
|
+
// direct branch never reaches cancel(), so retire the owned tuple
|
|
1804
|
+
// here — the cancellation emits no completion delivery, and without
|
|
1805
|
+
// this the tuple survives job eviction and a later scope:"owned"
|
|
1806
|
+
// abort of the attempt reports owned_unsettled with no work left
|
|
1807
|
+
// (review thread P2).
|
|
1808
|
+
if (shouldScheduleEviction && currentJobId && job) this.#retireCancelledJobOwned(currentJobId, job.generation);
|
|
1590
1809
|
return true;
|
|
1591
1810
|
}
|
|
1592
1811
|
if (rec.status === "queued") {
|
|
@@ -1594,8 +1813,16 @@ export class AsyncJobManager {
|
|
|
1594
1813
|
const queuedSeq = rec.queued?.seq;
|
|
1595
1814
|
if (idx !== -1) this.#resumeQueue.splice(idx, 1);
|
|
1596
1815
|
rec.status = "cancelled";
|
|
1597
|
-
if (queuedSeq !== undefined)
|
|
1816
|
+
if (queuedSeq !== undefined) {
|
|
1598
1817
|
this.#publishQueuedTerminal(rec.subagentId, `queued:${rec.subagentId}:${queuedSeq}`, "cancelled");
|
|
1818
|
+
// rec.queued is cleared below; retain terminal evidence ON THE
|
|
1819
|
+
// RECORD so owned settlement can prove the queued generation was
|
|
1820
|
+
// cancelled even when an in-flight settlement outlives any
|
|
1821
|
+
// bounded evidence set (review thread P2). The owned tuple is
|
|
1822
|
+
// retired at this terminal state too.
|
|
1823
|
+
rec.terminalQueuedSeq = queuedSeq;
|
|
1824
|
+
this.#retireQueuedOwned(rec);
|
|
1825
|
+
}
|
|
1599
1826
|
rec.queued = undefined;
|
|
1600
1827
|
this.#subagentProgress.delete(rec.subagentId);
|
|
1601
1828
|
this.#notifyChange();
|
|
@@ -1610,6 +1837,13 @@ export class AsyncJobManager {
|
|
|
1610
1837
|
}
|
|
1611
1838
|
for (const [sid, rec] of this.#subagentRecords) {
|
|
1612
1839
|
if (!ownerId || rec.ownerId === ownerId) {
|
|
1840
|
+
// Retire the queued resume's owned registration BEFORE deleting the
|
|
1841
|
+
// record: the purge removes the resume-queue entry and record with
|
|
1842
|
+
// no start, cancellation, or delivery boundary, so the registration
|
|
1843
|
+
// would otherwise leak into the global ownership registries and
|
|
1844
|
+
// eventually make later owned aborts fail closed (review thread
|
|
1845
|
+
// P2). #retireQueuedOwned is a no-op for non-queued records.
|
|
1846
|
+
this.#retireQueuedOwned(rec);
|
|
1613
1847
|
this.#liveHandles.delete(sid);
|
|
1614
1848
|
this.#resumeDescriptors.delete(sid);
|
|
1615
1849
|
this.#descriptorResumeRunners.delete(sid);
|
|
@@ -1620,9 +1854,69 @@ export class AsyncJobManager {
|
|
|
1620
1854
|
}
|
|
1621
1855
|
|
|
1622
1856
|
getJob(id: string): AsyncJob | undefined {
|
|
1857
|
+
if (id.startsWith("queued:")) {
|
|
1858
|
+
const colon = id.lastIndexOf(":");
|
|
1859
|
+
const subagentId = colon > "queued:".length ? id.slice("queued:".length, colon) : undefined;
|
|
1860
|
+
if (!subagentId) return undefined;
|
|
1861
|
+
const rec = this.getSubagentRecord(subagentId);
|
|
1862
|
+
if (!rec) return undefined;
|
|
1863
|
+
const liveSeq = rec.queued?.seq;
|
|
1864
|
+
const terminalSeq = rec.terminalQueuedSeq;
|
|
1865
|
+
// A failed queued resume publishes its terminalGeneration (the
|
|
1866
|
+
// queued id) via #publishQueuedTerminal — that is retained
|
|
1867
|
+
// failed-generation evidence for the settlement proof.
|
|
1868
|
+
const terminalQueuedId = terminalSeq !== undefined ? `queued:${subagentId}:${terminalSeq}` : undefined;
|
|
1869
|
+
const publishedQueuedId = rec.terminalGeneration?.startsWith("queued:") ? rec.terminalGeneration : undefined;
|
|
1870
|
+
if (liveSeq === undefined && terminalQueuedId === undefined && publishedQueuedId === undefined)
|
|
1871
|
+
return undefined;
|
|
1872
|
+
const resolvedQueuedId =
|
|
1873
|
+
liveSeq !== undefined ? `queued:${subagentId}:${liveSeq}` : (terminalQueuedId ?? publishedQueuedId);
|
|
1874
|
+
if (resolvedQueuedId === undefined || id !== resolvedQueuedId) return undefined;
|
|
1875
|
+
if (liveSeq === undefined) {
|
|
1876
|
+
// The queued resume reached a TERMINAL state (cancelled or
|
|
1877
|
+
// failed, rec.queued cleared): the generation is provably
|
|
1878
|
+
// terminal so owned settlement's second proof succeeds
|
|
1879
|
+
// (review thread P2).
|
|
1880
|
+
return {
|
|
1881
|
+
id,
|
|
1882
|
+
generation: id,
|
|
1883
|
+
type: "task",
|
|
1884
|
+
status: rec.status === "failed" ? "failed" : "cancelled",
|
|
1885
|
+
startTime: Date.now(),
|
|
1886
|
+
label: `terminal queued resume ${subagentId}`,
|
|
1887
|
+
abortController: new AbortController(),
|
|
1888
|
+
promise: Promise.resolve(),
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
if (id !== `queued:${subagentId}:${liveSeq}`) return undefined;
|
|
1892
|
+
return {
|
|
1893
|
+
id,
|
|
1894
|
+
generation: id,
|
|
1895
|
+
type: "task",
|
|
1896
|
+
// A still-queued resume is NOT quiescent ("paused" fails the owned
|
|
1897
|
+
// settlement's second proof); once cancelled it is terminal.
|
|
1898
|
+
status: rec.status === "cancelled" ? "cancelled" : "paused",
|
|
1899
|
+
startTime: rec.queued?.createdAt ?? Date.now(),
|
|
1900
|
+
label: `queued resume ${subagentId}`,
|
|
1901
|
+
abortController: new AbortController(),
|
|
1902
|
+
promise: Promise.resolve(),
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1623
1905
|
return this.#jobs.get(id);
|
|
1624
1906
|
}
|
|
1625
1907
|
|
|
1908
|
+
/**
|
|
1909
|
+
* The EXECUTION promise of the job record whose generation matches the
|
|
1910
|
+
* captured generation, or undefined when the record is gone or rebound.
|
|
1911
|
+
* The promise settles only when the job's function actually unwinds — the
|
|
1912
|
+
* eagerly-updated cancel status is not proof of quiescence (review P1).
|
|
1913
|
+
*/
|
|
1914
|
+
getJobPromise(id: string, generation: string): Promise<void> | undefined {
|
|
1915
|
+
const job = this.#jobs.get(id);
|
|
1916
|
+
if (!job || job.generation !== generation) return undefined;
|
|
1917
|
+
return job.promise;
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1626
1920
|
getRunningJobs(filter?: AsyncJobFilter): AsyncJob[] {
|
|
1627
1921
|
return this.#filterJobs(this.#jobs.values(), filter).filter(job => job.status === "running");
|
|
1628
1922
|
}
|
|
@@ -1805,10 +2099,38 @@ export class AsyncJobManager {
|
|
|
1805
2099
|
return this.getDeliveryState(filter).queued > 0;
|
|
1806
2100
|
}
|
|
1807
2101
|
|
|
2102
|
+
watchJobGenerations(jobIds: string[]): AsyncJobWatchHandle {
|
|
2103
|
+
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
2104
|
+
const generations: string[] = [];
|
|
2105
|
+
for (const jobId of uniqueJobIds) {
|
|
2106
|
+
const generation = this.#jobs.get(jobId)?.generation;
|
|
2107
|
+
if (!generation) continue;
|
|
2108
|
+
generations.push(generation);
|
|
2109
|
+
this.#watchedGenerations.set(generation, (this.#watchedGenerations.get(generation) ?? 0) + 1);
|
|
2110
|
+
}
|
|
2111
|
+
let closed = false;
|
|
2112
|
+
return {
|
|
2113
|
+
close: () => {
|
|
2114
|
+
if (closed) return 0;
|
|
2115
|
+
closed = true;
|
|
2116
|
+
let removed = 0;
|
|
2117
|
+
for (const generation of generations) {
|
|
2118
|
+
const watchers = this.#watchedGenerations.get(generation) ?? 0;
|
|
2119
|
+
if (watchers === 1) {
|
|
2120
|
+
this.#watchedGenerations.delete(generation);
|
|
2121
|
+
removed += 1;
|
|
2122
|
+
} else if (watchers > 1) this.#watchedGenerations.set(generation, watchers - 1);
|
|
2123
|
+
}
|
|
2124
|
+
if (removed > 0) this.#ensureDeliveryLoop();
|
|
2125
|
+
return removed;
|
|
2126
|
+
},
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
|
|
1808
2130
|
watchJobs(jobIds: string[]): number {
|
|
1809
2131
|
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
1810
2132
|
for (const jobId of uniqueJobIds) {
|
|
1811
|
-
this.#watchedJobs.
|
|
2133
|
+
this.#watchedJobs.set(jobId, (this.#watchedJobs.get(jobId) ?? 0) + 1);
|
|
1812
2134
|
}
|
|
1813
2135
|
return uniqueJobIds.length;
|
|
1814
2136
|
}
|
|
@@ -1817,9 +2139,11 @@ export class AsyncJobManager {
|
|
|
1817
2139
|
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
1818
2140
|
let removed = 0;
|
|
1819
2141
|
for (const jobId of uniqueJobIds) {
|
|
1820
|
-
|
|
2142
|
+
const watchers = this.#watchedJobs.get(jobId) ?? 0;
|
|
2143
|
+
if (watchers === 1) {
|
|
2144
|
+
this.#watchedJobs.delete(jobId);
|
|
1821
2145
|
removed += 1;
|
|
1822
|
-
}
|
|
2146
|
+
} else if (watchers > 1) this.#watchedJobs.set(jobId, watchers - 1);
|
|
1823
2147
|
}
|
|
1824
2148
|
if (removed > 0) this.#ensureDeliveryLoop();
|
|
1825
2149
|
return removed;
|
|
@@ -2004,6 +2328,7 @@ export class AsyncJobManager {
|
|
|
2004
2328
|
this.#deliveryAckOwners.clear();
|
|
2005
2329
|
this.#waitGenerationAliases.clear();
|
|
2006
2330
|
this.#watchedJobs.clear();
|
|
2331
|
+
this.#watchedGenerations.clear();
|
|
2007
2332
|
this.#outputState.clear();
|
|
2008
2333
|
this.#ownerCleanups.clear();
|
|
2009
2334
|
this.#subagentRecords.clear();
|
|
@@ -2077,7 +2402,6 @@ export class AsyncJobManager {
|
|
|
2077
2402
|
this.#deadLetteredDeliveryOwners.delete(jobId);
|
|
2078
2403
|
this.#suppressedDeliveries.delete(jobId);
|
|
2079
2404
|
if (job) this.#publishedTerminalGenerations.delete(job.generation);
|
|
2080
|
-
this.#watchedJobs.delete(jobId);
|
|
2081
2405
|
this.#outputState.delete(jobId);
|
|
2082
2406
|
}
|
|
2083
2407
|
|
|
@@ -2161,7 +2485,12 @@ export class AsyncJobManager {
|
|
|
2161
2485
|
}
|
|
2162
2486
|
|
|
2163
2487
|
isDeliverySuppressed(jobId: string, generation?: string): boolean {
|
|
2164
|
-
|
|
2488
|
+
const watchedGeneration = generation ?? this.#jobs.get(jobId)?.generation;
|
|
2489
|
+
return (
|
|
2490
|
+
this.#isDeliveryAcknowledged(jobId, generation) ||
|
|
2491
|
+
(this.#watchedJobs.get(jobId) ?? 0) > 0 ||
|
|
2492
|
+
(watchedGeneration !== undefined && (this.#watchedGenerations.get(watchedGeneration) ?? 0) > 0)
|
|
2493
|
+
);
|
|
2165
2494
|
}
|
|
2166
2495
|
|
|
2167
2496
|
#pruneEvictedDeadLetters(): void {
|
|
@@ -2185,6 +2514,12 @@ export class AsyncJobManager {
|
|
|
2185
2514
|
lastError: delivery.lastError,
|
|
2186
2515
|
});
|
|
2187
2516
|
this.#deadLetteredDeliveryOwners.set(delivery.jobId, delivery.ownerId);
|
|
2517
|
+
// The dead-lettered delivery never injects a message and has no later
|
|
2518
|
+
// consumption boundary: retire the exact owned registration so the
|
|
2519
|
+
// terminal tuple does not occupy the global registries until a future
|
|
2520
|
+
// job-record eviction makes it invisible to settlement scans (review
|
|
2521
|
+
// thread P2).
|
|
2522
|
+
retireOwnedRegistrationForDeadLetter(AsyncJobManager.endpointIdOf(this), delivery.jobId, delivery.generation);
|
|
2188
2523
|
while (this.#deadLetteredDeliveries.size > MAX_DEAD_LETTERED_DELIVERIES) {
|
|
2189
2524
|
const oldestJobId = this.#deadLetteredDeliveries.keys().next().value;
|
|
2190
2525
|
if (oldestJobId === undefined) return;
|
package/src/async/support.ts
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { resolveEquivalentPath } from "@gajae-code/utils";
|
|
1
3
|
import type { Settings } from "../config/settings";
|
|
2
4
|
|
|
3
5
|
export function isBackgroundJobSupportEnabled(settings: Pick<Settings, "get">): boolean {
|
|
4
6
|
void settings;
|
|
5
7
|
return true;
|
|
6
8
|
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Single source of truth for the AsyncJobManager endpoint key.
|
|
12
|
+
*
|
|
13
|
+
* A session with an explicit provider session id is keyed by (provider id,
|
|
14
|
+
* transcript path); everything else is keyed by its logical session id. The
|
|
15
|
+
* transcript component is canonicalized so a path alias — symlink, `..`
|
|
16
|
+
* segment, or unresolved relative path — cannot register the manager under one
|
|
17
|
+
* key at construction and look it up under another across a session-identity
|
|
18
|
+
* transition, stranding ownership.
|
|
19
|
+
*
|
|
20
|
+
* Both the SDK constructor and AgentSession's transition rekeying must derive
|
|
21
|
+
* the key here; duplicating the shape lets the two drift apart silently.
|
|
22
|
+
*/
|
|
23
|
+
export function asyncJobEndpointId(
|
|
24
|
+
providerSessionId: string | undefined,
|
|
25
|
+
sessionId: string,
|
|
26
|
+
sessionFile: string | undefined,
|
|
27
|
+
): string {
|
|
28
|
+
return providerSessionId !== undefined && sessionFile !== undefined
|
|
29
|
+
? JSON.stringify(["async-job-endpoint", providerSessionId, resolveEquivalentPath(path.resolve(sessionFile))])
|
|
30
|
+
: sessionId;
|
|
31
|
+
}
|
|
@@ -5,20 +5,39 @@ import { currentResults, findBaselineMetric, findBaselineRunNumber, findBaseline
|
|
|
5
5
|
import type { AutoresearchRuntime, DashboardController, ExperimentResult, ExperimentState } from "./types";
|
|
6
6
|
|
|
7
7
|
export function createDashboardController(): DashboardController {
|
|
8
|
-
let overlayTui: {
|
|
8
|
+
let overlayTui: { requestLayoutRender(source?: string): void } | null = null;
|
|
9
9
|
let spinnerTimer: NodeJS.Timeout | undefined;
|
|
10
10
|
let spinnerFrame = 0;
|
|
11
11
|
|
|
12
12
|
const requestRender = (): void => {
|
|
13
|
-
overlayTui?.
|
|
13
|
+
overlayTui?.requestLayoutRender("autoresearch-overlay");
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const stopSpinner = (): void => {
|
|
17
|
+
if (!spinnerTimer) return;
|
|
18
|
+
clearInterval(spinnerTimer);
|
|
19
|
+
spinnerTimer = undefined;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const syncSpinner = (runtime: AutoresearchRuntime): void => {
|
|
23
|
+
if (!overlayTui || !runtime.runningExperiment) {
|
|
24
|
+
stopSpinner();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (spinnerTimer) return;
|
|
28
|
+
spinnerTimer = setInterval(() => {
|
|
29
|
+
if (!runtime.runningExperiment) {
|
|
30
|
+
stopSpinner();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
spinnerFrame += 1;
|
|
34
|
+
requestRender();
|
|
35
|
+
}, 80);
|
|
14
36
|
};
|
|
15
37
|
|
|
16
38
|
const clear = (): void => {
|
|
17
39
|
overlayTui = null;
|
|
18
|
-
|
|
19
|
-
clearInterval(spinnerTimer);
|
|
20
|
-
spinnerTimer = undefined;
|
|
21
|
-
}
|
|
40
|
+
stopSpinner();
|
|
22
41
|
};
|
|
23
42
|
|
|
24
43
|
return {
|
|
@@ -31,6 +50,7 @@ export function createDashboardController(): DashboardController {
|
|
|
31
50
|
requestRender,
|
|
32
51
|
updateWidget(ctx, runtime): void {
|
|
33
52
|
if (!ctx.hasUI) return;
|
|
53
|
+
syncSpinner(runtime);
|
|
34
54
|
const state = runtime.state;
|
|
35
55
|
if (!shouldShowDashboard(runtime, state)) {
|
|
36
56
|
ctx.ui.setWidget("autoresearch", undefined);
|
|
@@ -57,12 +77,7 @@ export function createDashboardController(): DashboardController {
|
|
|
57
77
|
await ctx.ui.custom<void>(
|
|
58
78
|
(tui, theme, _keybindings, done) => {
|
|
59
79
|
overlayTui = tui;
|
|
60
|
-
|
|
61
|
-
spinnerTimer = setInterval(() => {
|
|
62
|
-
spinnerFrame += 1;
|
|
63
|
-
requestRender();
|
|
64
|
-
}, 80);
|
|
65
|
-
}
|
|
80
|
+
syncSpinner(runtime);
|
|
66
81
|
|
|
67
82
|
let scrollOffset = 0;
|
|
68
83
|
return {
|
|
@@ -108,7 +123,7 @@ export function createDashboardController(): DashboardController {
|
|
|
108
123
|
} else if (data === "G") {
|
|
109
124
|
scrollOffset = maxScroll;
|
|
110
125
|
}
|
|
111
|
-
tui.
|
|
126
|
+
tui.requestLayoutRender("autoresearch-overlay-input");
|
|
112
127
|
},
|
|
113
128
|
invalidate(): void {},
|
|
114
129
|
dispose(): void {
|