@gajae-code/coding-agent 0.11.1 → 0.11.2
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 +54 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/cli/session-picker.d.ts +2 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/mcp-serve.d.ts +33 -0
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/commands/notify.d.ts +0 -2
- package/dist/types/commands/sdk.d.ts +1 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +14 -4
- package/dist/types/config/keybindings.d.ts +42 -1
- package/dist/types/config/model-auth.d.ts +3 -0
- package/dist/types/config/model-bindings-applier.d.ts +13 -0
- package/dist/types/config/model-discovery-manager.d.ts +49 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-registry.d.ts +16 -15
- package/dist/types/config/model-resolver.d.ts +28 -18
- package/dist/types/config/models-config-schema.d.ts +11 -0
- package/dist/types/config/settings-schema.d.ts +56 -1
- package/dist/types/config/settings.d.ts +14 -11
- package/dist/types/coordinator-mcp/policy.d.ts +5 -0
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/discovery/helpers.d.ts +0 -6
- package/dist/types/edit/index.d.ts +3 -0
- package/dist/types/eval/py/env.d.ts +9 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -3
- package/dist/types/extensibility/hooks/runner.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
- package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
- package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
- package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
- package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
- package/dist/types/gjc-runtime/team-store.d.ts +160 -0
- package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
- package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
- package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/goals/state.d.ts +8 -0
- package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
- package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
- package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/state.d.ts +11 -4
- package/dist/types/lsp/lspmux.d.ts +5 -3
- package/dist/types/lsp/path-trust.d.ts +1 -0
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memories/storage.d.ts +1 -0
- package/dist/types/modes/action-registry.d.ts +29 -0
- package/dist/types/modes/components/chrome.d.ts +14 -0
- package/dist/types/modes/components/command-palette.d.ts +27 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
- package/dist/types/modes/components/queue-pane.d.ts +12 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
- package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/show-images-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +1 -1
- package/dist/types/modes/components/status-line.d.ts +1 -94
- package/dist/types/modes/components/tasks-pane.d.ts +15 -0
- package/dist/types/modes/components/theme-selector.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/tool-status-header.d.ts +111 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
- package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -1
- package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
- package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
- package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
- package/dist/types/modes/interactive-mode.d.ts +19 -17
- package/dist/types/modes/jobs-observer.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
- package/dist/types/modes/tasks-aggregator.d.ts +39 -0
- package/dist/types/modes/transcript-item-registry.d.ts +60 -0
- package/dist/types/modes/types.d.ts +20 -13
- package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +78 -12
- package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
- package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
- package/dist/types/sdk/broker/session-index.d.ts +0 -1
- package/dist/types/sdk/broker/state-version.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
- package/dist/types/sdk/bus/config-commands.d.ts +1 -1
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/html-format.d.ts +3 -2
- package/dist/types/sdk/bus/index.d.ts +27 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/notification-service.d.ts +20 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
- package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
- package/dist/types/sdk/bus/rich-document.d.ts +7 -0
- package/dist/types/sdk/bus/rich-render.d.ts +18 -41
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
- package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/session-directory.d.ts +56 -0
- package/dist/types/session/agent-session.d.ts +82 -47
- package/dist/types/session/agent-storage.d.ts +7 -0
- package/dist/types/session/fallback-chain-controller.d.ts +10 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
- package/dist/types/session/messages.d.ts +16 -0
- package/dist/types/session/session-manager-internal.d.ts +14 -0
- package/dist/types/session/session-manager.d.ts +82 -12
- package/dist/types/session/session-storage.d.ts +43 -3
- package/dist/types/session/volatile-context-pruning.d.ts +15 -0
- package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
- package/dist/types/system-prompt.d.ts +2 -11
- package/dist/types/task/executor.d.ts +3 -1
- package/dist/types/thinking.d.ts +7 -0
- package/dist/types/tool-discovery/tool-index.d.ts +1 -50
- package/dist/types/tools/ask.d.ts +64 -2
- package/dist/types/tools/bash.d.ts +3 -0
- package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
- package/dist/types/tools/cron.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/index.d.ts +30 -15
- package/dist/types/tools/output-meta.d.ts +1 -0
- package/dist/types/tools/read.d.ts +3 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/web/search/index.d.ts +3 -1
- package/package.json +21 -9
- package/scripts/build-sdk-package-smoke.ts +34 -1
- package/scripts/generate-hotkeys-docs.ts +74 -0
- package/scripts/generate-sdk-operation-inventory.ts +64 -20
- package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
- package/src/async/job-manager.ts +49 -6
- package/src/cli/config-cli.ts +75 -2
- package/src/cli/notify-cli.ts +92 -26
- package/src/cli/session-picker.ts +20 -3
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/harness.ts +34 -106
- package/src/commands/launch.ts +6 -4
- package/src/commands/mcp-serve.ts +85 -8
- package/src/commands/mcp.ts +2 -2
- package/src/commands/notify.ts +8 -4
- package/src/commands/sdk.ts +61 -40
- package/src/commands/ultragoal.ts +4 -1
- package/src/config/atomic-yaml-patch.ts +80 -13
- package/src/config/file-lock.ts +105 -43
- package/src/config/keybindings.ts +64 -20
- package/src/config/model-auth.ts +9 -0
- package/src/config/model-bindings-applier.ts +139 -0
- package/src/config/model-discovery-manager.ts +224 -0
- package/src/config/model-equivalence.ts +66 -0
- package/src/config/model-registry.ts +169 -302
- package/src/config/model-resolver.ts +361 -369
- package/src/config/models-config-schema.ts +5 -4
- package/src/config/settings-schema.ts +159 -2
- package/src/config/settings.ts +458 -482
- package/src/coordinator-mcp/policy.ts +76 -11
- package/src/coordinator-mcp/question-gate-codec.ts +274 -0
- package/src/coordinator-mcp/question-state.ts +778 -0
- package/src/coordinator-mcp/server.ts +1702 -238
- package/src/debug/index.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
- package/src/defaults/gjc/skills/team/SKILL.md +16 -0
- package/src/discovery/helpers.ts +1 -50
- package/src/edit/index.ts +64 -0
- package/src/eval/py/env.ts +26 -0
- package/src/eval/py/kernel.ts +5 -3
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +12 -3
- package/src/extensibility/extensions/types.ts +39 -1
- package/src/extensibility/gjc-plugins/installer.ts +16 -16
- package/src/extensibility/hooks/runner.ts +2 -2
- package/src/extensibility/runtime-skill-discovery.ts +33 -13
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
- package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
- package/src/gjc-runtime/deep-interview-state.ts +317 -5
- package/src/gjc-runtime/goal-mode-request.ts +55 -8
- package/src/gjc-runtime/launch-tmux.ts +2 -5
- package/src/gjc-runtime/launch-worktree.ts +5 -5
- package/src/gjc-runtime/linux-proc.ts +71 -0
- package/src/gjc-runtime/ralplan-runtime.ts +74 -90
- package/src/gjc-runtime/session-resolution.ts +18 -3
- package/src/gjc-runtime/session-state-sidecar.ts +6 -107
- package/src/gjc-runtime/state-migrations.ts +1 -1
- package/src/gjc-runtime/state-runtime.ts +320 -249
- package/src/gjc-runtime/state-writer.ts +36 -40
- package/src/gjc-runtime/team-launch.ts +319 -0
- package/src/gjc-runtime/team-notify.ts +326 -0
- package/src/gjc-runtime/team-runtime.ts +1099 -1482
- package/src/gjc-runtime/team-store.ts +828 -0
- package/src/gjc-runtime/team-workers.ts +962 -0
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
- package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
- package/src/gjc-runtime/tmux-sessions.ts +4 -21
- package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
- package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
- package/src/gjc-runtime/ultragoal-guard.ts +29 -5
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
- package/src/gjc-runtime/workflow-cli-common.ts +30 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +18 -0
- package/src/goals/continuation-timeout-guard.ts +79 -0
- package/src/goals/runtime.ts +7 -5
- package/src/goals/state.ts +18 -0
- package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
- package/src/harness-control-plane/phase-rollup.ts +4 -7
- package/src/harness-control-plane/receipt-ingest.ts +5 -0
- package/src/harness-control-plane/receipt-spool.ts +51 -7
- package/src/harness-control-plane/session-lease.ts +12 -130
- package/src/hindsight/backend.ts +26 -27
- package/src/hindsight/state.ts +101 -32
- package/src/hooks/skill-state.ts +17 -11
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/lsp/client.ts +1 -1
- package/src/lsp/config.ts +145 -26
- package/src/lsp/index.ts +1 -1
- package/src/lsp/lspmux.ts +39 -10
- package/src/lsp/path-trust.ts +81 -0
- package/src/main.ts +28 -8
- package/src/memories/index.ts +1 -0
- package/src/memories/storage.ts +6 -2
- package/src/modes/action-registry.ts +165 -0
- package/src/modes/components/chrome.ts +40 -0
- package/src/modes/components/command-palette.ts +168 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/custom-provider-wizard.ts +51 -14
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/pet-selector.ts +11 -17
- package/src/modes/components/plan-preview-overlay.ts +295 -0
- package/src/modes/components/queue-mode-selector.ts +10 -27
- package/src/modes/components/queue-pane.ts +79 -0
- package/src/modes/components/read-tool-group.ts +13 -0
- package/src/modes/components/session-observer-overlay.ts +207 -772
- package/src/modes/components/sessions-dashboard.ts +181 -0
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +10 -24
- package/src/modes/components/status-line/types.ts +1 -1
- package/src/modes/components/status-line.ts +1 -969
- package/src/modes/components/tasks-pane.ts +73 -0
- package/src/modes/components/theme-selector.ts +11 -31
- package/src/modes/components/tool-execution.ts +22 -0
- package/src/modes/components/tool-status-header.ts +1056 -0
- package/src/modes/components/transcript-viewer-overlay.ts +384 -0
- package/src/modes/controllers/btw-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +24 -1
- package/src/modes/controllers/goal-mode-controller.ts +474 -0
- package/src/modes/controllers/input-controller.ts +764 -229
- package/src/modes/controllers/mode-gate.ts +24 -0
- package/src/modes/controllers/plan-mode-controller.ts +517 -0
- package/src/modes/controllers/selector-controller.ts +225 -10
- package/src/modes/controllers/stt-controller.ts +125 -0
- package/src/modes/interactive-mode.ts +289 -1150
- package/src/modes/jobs-observer.ts +3 -0
- package/src/modes/runtime-init.ts +8 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
- package/src/modes/tasks-aggregator.ts +199 -0
- package/src/modes/transcript-item-registry.ts +229 -0
- package/src/modes/types.ts +45 -18
- package/src/modes/utils/ui-helpers.ts +17 -9
- package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
- package/src/prompts/agent-fragments/restricted-bash.md +1 -0
- package/src/prompts/agents/architect.md +2 -8
- package/src/prompts/agents/critic.md +2 -8
- package/src/prompts/agents/executor.md +3 -0
- package/src/prompts/agents/planner.md +4 -12
- package/src/prompts/system/custom-system-prompt.md +1 -23
- package/src/prompts/system/plan-mode-approved.md +8 -0
- package/src/prompts/system/system-prompt.md +17 -96
- package/src/prompts/tools/bash.md +4 -4
- package/src/prompts/tools/browser.md +15 -52
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/hashline.md +13 -55
- package/src/prompts/tools/read.md +3 -6
- package/src/prompts/tools/search-tool-bm25.md +0 -2
- package/src/prompts/tools/search.md +2 -4
- package/src/prompts/tools/skill-discovery.md +1 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-mcp/manager.ts +1 -1
- package/src/sdk/broker/broker.ts +206 -78
- package/src/sdk/broker/discovery.ts +1 -1
- package/src/sdk/broker/ensure.ts +3 -1
- package/src/sdk/broker/lifecycle-codec.ts +11 -0
- package/src/sdk/broker/lifecycle-ledger.ts +371 -74
- package/src/sdk/broker/lifecycle.ts +1399 -142
- package/src/sdk/broker/process-incarnation.ts +5 -13
- package/src/sdk/broker/session-index.ts +145 -56
- package/src/sdk/broker/state-version.ts +21 -0
- package/src/sdk/broker/transport.ts +1 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -28
- package/src/sdk/bus/chat-effect-journal.ts +10 -2
- package/src/sdk/bus/config-commands.ts +5 -4
- package/src/sdk/bus/config.ts +98 -0
- package/src/sdk/bus/conversation-store.ts +5 -29
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +778 -93
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/natives-augment.d.ts +26 -1
- package/src/sdk/bus/notification-service.ts +168 -20
- package/src/sdk/bus/rate-limit-pool.ts +58 -14
- package/src/sdk/bus/recent-activity.ts +188 -74
- package/src/sdk/bus/rich-document.ts +258 -0
- package/src/sdk/bus/rich-render.ts +62 -70
- package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
- package/src/sdk/bus/telegram-daemon.ts +1389 -237
- package/src/sdk/bus/threaded-inbound.ts +8 -3
- package/src/sdk/bus/threaded-render.ts +57 -1
- package/src/sdk/bus/topic-registry.ts +120 -13
- package/src/sdk/host/control/dispatch.ts +14 -2
- package/src/sdk/host/control/operations.ts +6 -1
- package/src/sdk/host/host.ts +31 -1
- package/src/sdk/host/query/handlers.ts +20 -22
- package/src/sdk/host/query/revision-store.ts +80 -57
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
- package/src/sdk/session-directory.ts +141 -0
- package/src/sdk/session.ts +458 -479
- package/src/session/agent-session.ts +1700 -583
- package/src/session/agent-storage.ts +18 -0
- package/src/session/cache-economics.ts +25 -8
- package/src/session/fallback-chain-controller.ts +53 -3
- package/src/session/internal/managed-session-scope.ts +2226 -0
- package/src/session/internal/managed-session-storage.ts +453 -0
- package/src/session/messages.ts +91 -2
- package/src/session/session-manager-internal.ts +33 -0
- package/src/session/session-manager.ts +1112 -333
- package/src/session/session-storage.ts +444 -39
- package/src/session/volatile-context-pruning.ts +78 -0
- package/src/setup/credential-auto-import.ts +2 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
- package/src/setup/provider-onboarding.ts +36 -61
- package/src/setup/provider-presets.json +5 -0
- package/src/skill-state/active-state.ts +3 -13
- package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
- package/src/skill-state/workflow-state-contract.ts +6 -41
- package/src/slash-commands/builtin-registry.ts +46 -11
- package/src/system-prompt.ts +37 -44
- package/src/task/agents.ts +19 -1
- package/src/task/executor.ts +90 -6
- package/src/task/index.ts +36 -21
- package/src/thinking.ts +21 -6
- package/src/tool-discovery/tool-index.ts +2 -134
- package/src/tools/ask.ts +157 -21
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/bash.ts +38 -0
- package/src/tools/browser/dead-tab-recovery.ts +78 -0
- package/src/tools/browser/tab-supervisor.ts +282 -36
- package/src/tools/computer.ts +10 -3
- package/src/tools/cron.ts +30 -16
- package/src/tools/eval.ts +1 -2
- package/src/tools/fetch.ts +11 -4
- package/src/tools/index.ts +76 -24
- package/src/tools/output-meta.ts +13 -5
- package/src/tools/read.ts +37 -1
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/utils/event-bus.ts +9 -4
- package/src/web/search/index.ts +3 -3
- package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
- package/src/discovery/plugin-dir-roots.ts +0 -28
- package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
defaultClipboardPasteImageKeysForPlatform,
|
|
5
|
+
defaultMessageQueueKeysForPlatform,
|
|
6
|
+
KEYBINDINGS,
|
|
7
|
+
} from "../src/config/keybindings";
|
|
8
|
+
|
|
9
|
+
import { APP_ACTION_METADATA } from "../src/modes/action-registry";
|
|
10
|
+
|
|
11
|
+
const DOC_PATH = path.resolve(import.meta.dir, "../../../docs/keybindings.md");
|
|
12
|
+
const SECTION_START = "### Application context (`app.*`)";
|
|
13
|
+
const SECTION_END = "### Global engine context (`tui.global.*`)";
|
|
14
|
+
|
|
15
|
+
const DOCUMENTATION_PLATFORMS = ["darwin", "win32", "linux"] as const;
|
|
16
|
+
|
|
17
|
+
function defaultKeys(
|
|
18
|
+
value: (typeof KEYBINDINGS)[keyof typeof KEYBINDINGS],
|
|
19
|
+
bindingId: keyof typeof KEYBINDINGS,
|
|
20
|
+
): string {
|
|
21
|
+
const defaultsByPlatform = DOCUMENTATION_PLATFORMS.map(platform => {
|
|
22
|
+
switch (bindingId) {
|
|
23
|
+
case "app.message.queue":
|
|
24
|
+
return defaultMessageQueueKeysForPlatform(platform);
|
|
25
|
+
case "app.clipboard.pasteImage":
|
|
26
|
+
return defaultClipboardPasteImageKeysForPlatform(platform);
|
|
27
|
+
default: {
|
|
28
|
+
const keys = value.defaultKeys;
|
|
29
|
+
return (Array.isArray(keys) ? keys : [keys]).join(", ") || "_(none)_";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const groups = new Map<string, string[]>();
|
|
34
|
+
for (const [index, keys] of defaultsByPlatform.entries()) {
|
|
35
|
+
const platform = DOCUMENTATION_PLATFORMS[index]!;
|
|
36
|
+
groups.set(keys, [...(groups.get(keys) ?? []), platform]);
|
|
37
|
+
}
|
|
38
|
+
return groups.size === 1
|
|
39
|
+
? defaultsByPlatform[0]!
|
|
40
|
+
: [...groups].map(([keys, platforms]) => `${keys} (${platforms.join("/")})`).join(" / ");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Canonical application-action table shared by docs and drift tests. */
|
|
44
|
+
export function generateHotkeysDocsTable(): string {
|
|
45
|
+
return [
|
|
46
|
+
"| Action ID | Default | Domains |",
|
|
47
|
+
"| --- | --- | --- |",
|
|
48
|
+
...APP_ACTION_METADATA.map(action => {
|
|
49
|
+
const binding = KEYBINDINGS[action.bindingId ?? action.id];
|
|
50
|
+
return `| \`${action.id}\` | ${defaultKeys(binding, action.bindingId ?? action.id)} | ${action.domains.join(", ")} |`;
|
|
51
|
+
}),
|
|
52
|
+
].join("\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function generateKeybindingsDocument(source = readFileSync(DOC_PATH, "utf8")): string {
|
|
56
|
+
const start = source.indexOf(SECTION_START);
|
|
57
|
+
const end = source.indexOf(SECTION_END);
|
|
58
|
+
if (start < 0 || end < 0 || end <= start) throw new Error("Application keybinding section not found");
|
|
59
|
+
return `${source.slice(0, start)}${SECTION_START}\n\n${generateHotkeysDocsTable()}\n\n${source.slice(end)}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (import.meta.main) {
|
|
63
|
+
const expected = generateKeybindingsDocument();
|
|
64
|
+
if (process.argv.includes("--check")) {
|
|
65
|
+
if (readFileSync(DOC_PATH, "utf8") !== expected) {
|
|
66
|
+
console.error(
|
|
67
|
+
`${path.relative(process.cwd(), DOC_PATH)} is out of date; run bun scripts/generate-hotkeys-docs.ts`,
|
|
68
|
+
);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
writeFileSync(DOC_PATH, expected);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -32,6 +32,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
32
32
|
"slash_command:notify":
|
|
33
33
|
"interactive diagnostics command; session on/off delegate to the notifications extension, not an SDK ingress seam",
|
|
34
34
|
"slash_command:pet": "visual/local-only command, not a user-facing SDK control seam",
|
|
35
|
+
"slash_command:transcript": "visual/local-only transcript viewer, not a user-facing SDK control seam",
|
|
36
|
+
"slash_command:sessions": "visual/local-only sessions dashboard, not a user-facing SDK control seam",
|
|
35
37
|
"agent_session:constructor": "internal accessor/plumbing, not a user-facing control seam",
|
|
36
38
|
"agent_session:nextToolChoice": "internal accessor/plumbing, not a user-facing control seam",
|
|
37
39
|
"agent_session:setForcedToolChoice": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -50,6 +52,9 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
50
52
|
"agent_session:estimateMidRunContextTokensForTests": "test-only estimator seam, not a user-facing SDK control seam",
|
|
51
53
|
"agent_session:activeMidRunBarrierCountForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
52
54
|
"agent_session:activeMidRunMaintenanceCountForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
55
|
+
"agent_session:getPendingNextTurnMessagesForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
56
|
+
"agent_session:setCancelAndSubmitAbortOutcomeProviderForTests":
|
|
57
|
+
"test-only cancellation seam, not a user-facing SDK control seam",
|
|
53
58
|
"agent_session:getAgentId": "internal accessor/plumbing, not a user-facing control seam",
|
|
54
59
|
"agent_session:emitNotice": "internal accessor/plumbing, not a user-facing control seam",
|
|
55
60
|
"agent_session:subscribe": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -57,6 +62,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
57
62
|
"agent_session:closeWriterStrict": "internal ACP lifecycle teardown plumbing, not a user-facing control seam",
|
|
58
63
|
"agent_session:disposeChildSubprocesses": "internal accessor/plumbing, not a user-facing control seam",
|
|
59
64
|
"agent_session:waitForIdle": "internal accessor/plumbing, not a user-facing control seam",
|
|
65
|
+
"agent_session:awaitPendingContextTransformations":
|
|
66
|
+
"internal context-transformation lifecycle barrier, not a user-facing SDK control seam",
|
|
60
67
|
"agent_session:drainAsyncJobDeliveriesForAcp": "internal accessor/plumbing, not a user-facing control seam",
|
|
61
68
|
"agent_session:getAsyncDeliveryStateForAcp":
|
|
62
69
|
"internal ACP lifecycle quiescence plumbing, not a user-facing control seam",
|
|
@@ -66,10 +73,7 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
66
73
|
"agent_session:hasForegroundBashBackgroundRequestHandler":
|
|
67
74
|
"internal accessor/plumbing, not a user-facing control seam",
|
|
68
75
|
"agent_session:requestForegroundBashBackground": "internal accessor/plumbing, not a user-facing control seam",
|
|
69
|
-
"agent_session:isMCPDiscoveryEnabled": "internal accessor/plumbing, not a user-facing control seam",
|
|
70
|
-
"agent_session:getDiscoverableMCPSearchIndex": "internal accessor/plumbing, not a user-facing control seam",
|
|
71
76
|
"agent_session:getSelectedMCPToolNames": "internal accessor/plumbing, not a user-facing control seam",
|
|
72
|
-
"agent_session:activateDiscoveredMCPTools": "internal accessor/plumbing, not a user-facing control seam",
|
|
73
77
|
"agent_session:isToolDiscoveryEnabled": "internal accessor/plumbing, not a user-facing control seam",
|
|
74
78
|
"agent_session:getDiscoverableToolSearchIndex": "internal accessor/plumbing, not a user-facing control seam",
|
|
75
79
|
"agent_session:getSelectedDiscoveredToolNames": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -85,6 +89,7 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
85
89
|
"agent_session:setPlanModeState": "internal accessor/plumbing, not a user-facing control seam",
|
|
86
90
|
"agent_session:getGoalModeState": "internal accessor/plumbing, not a user-facing control seam",
|
|
87
91
|
"agent_session:setGoalModeState": "internal accessor/plumbing, not a user-facing control seam",
|
|
92
|
+
"agent_session:setSdkPlanModeHandler": "internal host lifecycle plumbing for mode.plan.set",
|
|
88
93
|
"agent_session:getWorkflowGateEmitter": "internal accessor/plumbing, not a user-facing control seam",
|
|
89
94
|
"agent_session:getAskAnswerSource": "internal accessor/plumbing, not a user-facing control seam",
|
|
90
95
|
"agent_session:setWorkflowGateEmitter": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -105,6 +110,7 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
105
110
|
"agent_session:purgeQueuedCustomMessages": "internal accessor/plumbing, not a user-facing control seam",
|
|
106
111
|
"agent_session:clearQueue": "internal accessor/plumbing, not a user-facing control seam",
|
|
107
112
|
"agent_session:popLastQueuedMessage": "internal accessor/plumbing, not a user-facing control seam",
|
|
113
|
+
"agent_session:cancelAndSubmit": "interactive queue transaction plumbing, not an independent SDK control seam",
|
|
108
114
|
"agent_session:applyCompactionPostAppendForTests": "internal accessor/plumbing, not a user-facing control seam",
|
|
109
115
|
"agent_session:continuePersistedHistory": "internal startup lifecycle plumbing, not a user-facing control seam",
|
|
110
116
|
"agent_session:setActiveModelProfile": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -126,6 +132,7 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
126
132
|
"agent_session:fetchUsageReportsForControl":
|
|
127
133
|
"internal Telegram control wrapper over the reviewed usage.get seam, not an independent public SDK operation",
|
|
128
134
|
"agent_session:cycleRoleModels": "internal accessor/plumbing, not a user-facing control seam",
|
|
135
|
+
"agent_session:getRoleModelCycleCandidateCount": "internal role-model display accessor, not a user-facing SDK seam",
|
|
129
136
|
"agent_session:isFastModeEnabled": "internal accessor/plumbing, not a user-facing control seam",
|
|
130
137
|
"agent_session:isFastForProvider": "internal accessor/plumbing, not a user-facing control seam",
|
|
131
138
|
"agent_session:isFastForSubagentProvider": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -221,7 +228,6 @@ const SEAM_TO_SDK: Readonly<Record<string, string>> = {
|
|
|
221
228
|
"agent_session:setTodoPhases": "todo.replace",
|
|
222
229
|
"agent_session:getQueuedMessageEntries": "queue.messages.list",
|
|
223
230
|
"agent_session:getAllToolNames": "tools.list",
|
|
224
|
-
"agent_session:getDiscoverableMCPTools": "tools.list",
|
|
225
231
|
"agent_session:getDiscoverableTools": "tools.list",
|
|
226
232
|
"agent_session:sendUserMessage": "turn.steer",
|
|
227
233
|
"agent_session:reload": "runtime.reload",
|
|
@@ -270,17 +276,30 @@ export interface SourceSeam {
|
|
|
270
276
|
sourceFile: string;
|
|
271
277
|
sourceKind: SourceKind;
|
|
272
278
|
}
|
|
273
|
-
interface
|
|
279
|
+
interface IncludedInventoryRecord {
|
|
274
280
|
sourceId: string;
|
|
275
281
|
sourceFile: string;
|
|
276
282
|
sourceKind: SourceKind;
|
|
277
|
-
decision: "include"
|
|
278
|
-
|
|
279
|
-
sdkId?: string;
|
|
283
|
+
decision: "include";
|
|
284
|
+
sdkId: string;
|
|
280
285
|
adapterMappings: Operation["adapterDispositions"];
|
|
281
286
|
testIds: string[];
|
|
282
287
|
}
|
|
283
288
|
|
|
289
|
+
interface ExcludedInventoryRecord {
|
|
290
|
+
sourceId: string;
|
|
291
|
+
sourceFile: string;
|
|
292
|
+
sourceKind: SourceKind;
|
|
293
|
+
decision: "exclude";
|
|
294
|
+
rationale: string;
|
|
295
|
+
exclusionMetadata: {
|
|
296
|
+
adapterMappings: "not_applicable";
|
|
297
|
+
testIds: "not_applicable";
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
type InventoryRecord = IncludedInventoryRecord | ExcludedInventoryRecord;
|
|
302
|
+
|
|
284
303
|
function repoPath(file: string): string {
|
|
285
304
|
return path.relative(repoRoot, file).split(path.sep).join("/");
|
|
286
305
|
}
|
|
@@ -291,7 +310,10 @@ function collectCaseSeams(source: string, prefix: string): string[] {
|
|
|
291
310
|
}
|
|
292
311
|
|
|
293
312
|
export function scanSlashCommands(sourceText: string): string[] {
|
|
294
|
-
const
|
|
313
|
+
const anchor = "const BUILTIN_SLASH_COMMAND_REGISTRY";
|
|
314
|
+
const anchorIndex = sourceText.indexOf(anchor);
|
|
315
|
+
if (anchorIndex === -1) throw new Error(`SDK operation inventory scanner: required anchor ${anchor} was not found.`);
|
|
316
|
+
const builtinRegistry = sourceText.slice(anchorIndex);
|
|
295
317
|
return [...builtinRegistry.matchAll(/^\t\tname:\s*["']([^"']+)["']/gm)].map(match => `slash_command:${match[1]}`);
|
|
296
318
|
}
|
|
297
319
|
|
|
@@ -664,14 +686,17 @@ export function scanAgentSessionMethods(sourceText: string): string[] {
|
|
|
664
686
|
for (let bodyIndex = index + 2; bodyIndex < tokens.length; bodyIndex++) {
|
|
665
687
|
if (tokens[bodyIndex]!.text === "<") angleDepth++;
|
|
666
688
|
else if (tokens[bodyIndex]!.text === ">" && angleDepth > 0) angleDepth--;
|
|
689
|
+
else if (tokens[bodyIndex]!.text === ";" && angleDepth === 0) break;
|
|
667
690
|
else if (tokens[bodyIndex]!.text === "{" && angleDepth === 0) {
|
|
668
691
|
bodyStart = bodyIndex;
|
|
669
692
|
break;
|
|
670
693
|
}
|
|
671
694
|
}
|
|
672
|
-
if (bodyStart === undefined)
|
|
695
|
+
if (bodyStart === undefined)
|
|
696
|
+
throw new Error("SDK operation inventory scanner: AgentSession class is missing its opening body delimiter.");
|
|
673
697
|
const bodyEnd = matchingToken(tokens, bodyStart, "{", "}");
|
|
674
|
-
if (bodyEnd === undefined)
|
|
698
|
+
if (bodyEnd === undefined)
|
|
699
|
+
throw new Error("SDK operation inventory scanner: AgentSession class body is unbalanced.");
|
|
675
700
|
|
|
676
701
|
const methods: string[] = [];
|
|
677
702
|
for (let memberStart = bodyStart + 1; memberStart < bodyEnd; ) {
|
|
@@ -685,7 +710,7 @@ export function scanAgentSessionMethods(sourceText: string): string[] {
|
|
|
685
710
|
}
|
|
686
711
|
return methods;
|
|
687
712
|
}
|
|
688
|
-
|
|
713
|
+
throw new Error("SDK operation inventory scanner: required AgentSession class declaration was not found.");
|
|
689
714
|
}
|
|
690
715
|
|
|
691
716
|
export function scanAcpMethods(sourceText: string): string[] {
|
|
@@ -776,14 +801,24 @@ function generatedRecords(seams: Awaited<ReturnType<typeof scanSeams>>): Invento
|
|
|
776
801
|
const sdkId = SEAM_TO_SDK[seam.sourceId];
|
|
777
802
|
const rationale = lockedExclusion(seam.sourceId);
|
|
778
803
|
if (!sdkId && !rationale) continue;
|
|
779
|
-
|
|
780
|
-
|
|
804
|
+
if (!sdkId) {
|
|
805
|
+
if (!rationale) continue;
|
|
806
|
+
records.push({
|
|
807
|
+
...seam,
|
|
808
|
+
decision: "exclude",
|
|
809
|
+
rationale,
|
|
810
|
+
exclusionMetadata: { adapterMappings: "not_applicable", testIds: "not_applicable" },
|
|
811
|
+
});
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const operation = OPERATIONS.find(candidate => candidate.sdkId === sdkId);
|
|
815
|
+
if (!operation) throw new Error(`SEAM_TO_SDK maps ${seam.sourceId} to unknown SDK ID: ${sdkId}`);
|
|
781
816
|
records.push({
|
|
782
817
|
...seam,
|
|
783
|
-
decision:
|
|
784
|
-
|
|
785
|
-
adapterMappings: operation
|
|
786
|
-
testIds: operation
|
|
818
|
+
decision: "include",
|
|
819
|
+
sdkId,
|
|
820
|
+
adapterMappings: operation.adapterDispositions,
|
|
821
|
+
testIds: operation.testIds,
|
|
787
822
|
});
|
|
788
823
|
}
|
|
789
824
|
return records;
|
|
@@ -804,8 +839,17 @@ function validateRegistry(records: InventoryRecord[]): string[] {
|
|
|
804
839
|
if (operation.testIds.length === 0) errors.push(`${operation.id} is missing test IDs.`);
|
|
805
840
|
}
|
|
806
841
|
for (const record of records) {
|
|
807
|
-
if (record.decision === "exclude"
|
|
808
|
-
errors.push(`${record.sourceId} exclusion lacks a locked rationale.`);
|
|
842
|
+
if (record.decision === "exclude") {
|
|
843
|
+
if (!record.rationale) errors.push(`${record.sourceId} exclusion lacks a locked rationale.`);
|
|
844
|
+
if (
|
|
845
|
+
record.exclusionMetadata.adapterMappings !== "not_applicable" ||
|
|
846
|
+
record.exclusionMetadata.testIds !== "not_applicable"
|
|
847
|
+
)
|
|
848
|
+
errors.push(
|
|
849
|
+
`${record.sourceId} exclusion metadata must mark adapter mappings and test IDs as not applicable.`,
|
|
850
|
+
);
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
809
853
|
if (ADAPTERS.some(adapter => !record.adapterMappings[adapter]))
|
|
810
854
|
errors.push(`${record.sourceId} is missing adapter mappings.`);
|
|
811
855
|
if (record.testIds.length === 0) errors.push(`${record.sourceId} is missing test IDs.`);
|
|
@@ -981,6 +981,7 @@ function isSource(file: string): boolean {
|
|
|
981
981
|
}
|
|
982
982
|
|
|
983
983
|
const teamRuntimeTmuxPath = "packages/coding-agent/src/gjc-runtime/team-runtime.ts";
|
|
984
|
+
const teamWorkersTmuxPath = "packages/coding-agent/src/gjc-runtime/team-workers.ts";
|
|
984
985
|
|
|
985
986
|
const coordinatorMcpRoot = "packages/coding-agent/src/coordinator-mcp/server.ts";
|
|
986
987
|
function isPublishedGjcSessionShellHelper(file: string): boolean {
|
|
@@ -1427,6 +1428,16 @@ function exactTeamRuntimeSendKeysRanges(contents: string): ShellRange[] {
|
|
|
1427
1428
|
/Bun\.spawnSync\(\s*\[\s*config\.tmux_command\s*,\s*["']send-keys["']\s*,\s*["']-l["']\s*,\s*["']-t["']\s*,\s*paneId\s*,\s*workerCommand\s*\]\s*,\s*\{[\s\S]{0,200}?stdout\s*:\s*["']ignore["'][\s\S]{0,200}?stderr\s*:\s*["']ignore["'][\s\S]{0,100}?\}\s*\)\s*;/g,
|
|
1428
1429
|
),
|
|
1429
1430
|
];
|
|
1431
|
+
const continuationPromptMatches = [
|
|
1432
|
+
...contents.matchAll(
|
|
1433
|
+
/(?:const\s+GJC_TEAM_CONTINUATION_PROMPT\s*=\s*["']Continue only your current claimed GJC team task\. Re-read current GJC team state; do not replay prior output; report status\.["']\s*;|import\s*\{[\s\S]{0,1000}?\bGJC_TEAM_CONTINUATION_PROMPT\b[\s\S]{0,1000}?\}\s*from\s*["']\.\/team-workers["']\s*;)/g,
|
|
1434
|
+
),
|
|
1435
|
+
];
|
|
1436
|
+
const continuationMatches = [
|
|
1437
|
+
...contents.matchAll(
|
|
1438
|
+
/const\s+args\s*=\s*Object\.freeze\(\s*\[\s*["']send-keys["']\s*,\s*["']-l["']\s*,\s*["']-t["']\s*,\s*worker\.pane_id\s*,\s*GJC_TEAM_CONTINUATION_PROMPT\s*,\s*["'];["']\s*,\s*["']send-keys["']\s*,\s*["']-t["']\s*,\s*worker\.pane_id\s*,\s*["']Enter["']\s*,?\s*\]\s*\)\s*;\s*const\s+dispatch\s*=\s*gjcTeamRuntimeTestSeams\?\.continuationTmuxDispatch\s*\?\s*gjcTeamRuntimeTestSeams\.continuationTmuxDispatch\(config\.tmux_command\s*,\s*args\)\s*:\s*Bun\.spawnSync\(\[config\.tmux_command\s*,\s*\.\.\.args\]\s*,\s*\{\s*stdout\s*:\s*["']ignore["']\s*,\s*stderr\s*:\s*["']ignore["']\s*,\s*timeout\s*:\s*GJC_TEAM_CONTINUATION_DISPATCH_TIMEOUT_MS\s*,?\s*\}\s*\)\s*;/g,
|
|
1439
|
+
),
|
|
1440
|
+
];
|
|
1430
1441
|
const enterMatches = [
|
|
1431
1442
|
...contents.matchAll(
|
|
1432
1443
|
/const\s+sendKeys\s*=\s*Bun\.spawnSync\(\s*\[\s*config\.tmux_command\s*,\s*["']send-keys["']\s*,\s*["']-t["']\s*,\s*paneId\s*,\s*["']Enter["']\s*\]\s*,\s*\{[\s\S]{0,200}?stdout\s*:\s*["']ignore["'][\s\S]{0,200}?stderr\s*:\s*["']ignore["'][\s\S]{0,100}?\}\s*\)\s*;/g,
|
|
@@ -1449,6 +1460,8 @@ function exactTeamRuntimeSendKeysRanges(contents: string): ShellRange[] {
|
|
|
1449
1460
|
guardMatches.length !== 1 ||
|
|
1450
1461
|
payloadMatches.length !== 1 ||
|
|
1451
1462
|
enterMatches.length !== 1 ||
|
|
1463
|
+
continuationPromptMatches.length !== 1 ||
|
|
1464
|
+
continuationMatches.length !== 1 ||
|
|
1452
1465
|
fallbackPredicateMatches.length !== 1 ||
|
|
1453
1466
|
useFallbackMatches.length !== 1 ||
|
|
1454
1467
|
splitWorkerCommandMatches.length !== 1
|
|
@@ -1468,18 +1481,43 @@ function exactTeamRuntimeSendKeysRanges(contents: string): ShellRange[] {
|
|
|
1468
1481
|
const guard = guardMatches[0];
|
|
1469
1482
|
const openingBrace = (guard.index ?? 0) + guard[0].lastIndexOf("{");
|
|
1470
1483
|
const range = braceBlockRange(contents, openingBrace);
|
|
1471
|
-
|
|
1484
|
+
const continuationFunction =
|
|
1485
|
+
/async\s+function\s+continueStalledGjcTeamWorkers\s*\([^)]*\)\s*:\s*Promise<void>\s*\{/.exec(contents);
|
|
1486
|
+
const monitorFence = /await\s+withGjcTeamTaskMutation\([\s\S]{0,500}?async\s+capability\s*=>\s*\{/.exec(contents);
|
|
1487
|
+
if (!range || !continuationFunction || !monitorFence) return [];
|
|
1488
|
+
const continuationOpeningBrace = (continuationFunction.index ?? 0) + continuationFunction[0].lastIndexOf("{");
|
|
1489
|
+
const continuationRange = braceBlockRange(contents, continuationOpeningBrace);
|
|
1490
|
+
const monitorOpeningBrace = (monitorFence.index ?? 0) + monitorFence[0].lastIndexOf("{");
|
|
1491
|
+
const monitorRange = braceBlockRange(contents, monitorOpeningBrace);
|
|
1492
|
+
if (!continuationRange || !monitorRange) return [];
|
|
1493
|
+
const monitorBody = contents.slice(monitorRange.start, monitorRange.end);
|
|
1494
|
+
const continuationCall = /await\s+continueStalledGjcTeamWorkers\s*\(/.exec(monitorBody);
|
|
1495
|
+
const reconciliationCall = /await\s+reconcileGjcTeamStaleClaimsUnlocked\s*\(/.exec(monitorBody);
|
|
1496
|
+
const continuationStart = continuationMatches[0].index ?? 0;
|
|
1497
|
+
const finalValidationStart = contents.lastIndexOf("const revalidationReason =", continuationStart);
|
|
1498
|
+
const skippedBranch = finalValidationStart === -1 ? "" : contents.slice(finalValidationStart, continuationStart);
|
|
1472
1499
|
if (
|
|
1473
1500
|
payloadStart < range.start ||
|
|
1474
1501
|
payloadStart >= range.end ||
|
|
1475
1502
|
enterStart < range.start ||
|
|
1476
1503
|
enterStart >= range.end ||
|
|
1477
|
-
contents.indexOf("void sendKeys.exitCode;", enterStart) >= range.end
|
|
1504
|
+
contents.indexOf("void sendKeys.exitCode;", enterStart) >= range.end ||
|
|
1505
|
+
continuationStart < continuationRange.start ||
|
|
1506
|
+
continuationStart >= continuationRange.end ||
|
|
1507
|
+
finalValidationStart < continuationRange.start ||
|
|
1508
|
+
!continuationCall ||
|
|
1509
|
+
!reconciliationCall ||
|
|
1510
|
+
(continuationCall.index ?? 0) >= (reconciliationCall.index ?? 0) ||
|
|
1511
|
+
!/if\s*\(\s*revalidationReason\s*\)[\s\S]*?return\s*;/.test(skippedBranch)
|
|
1478
1512
|
)
|
|
1479
1513
|
return [];
|
|
1480
1514
|
return [
|
|
1481
1515
|
{ start: payloadStart, end: payloadStart + payloadMatches[0][0].length },
|
|
1482
1516
|
{ start: enterStart, end: enterStart + enterMatches[0][0].length },
|
|
1517
|
+
{
|
|
1518
|
+
start: continuationMatches[0].index ?? 0,
|
|
1519
|
+
end: (continuationMatches[0].index ?? 0) + continuationMatches[0][0].length,
|
|
1520
|
+
},
|
|
1483
1521
|
];
|
|
1484
1522
|
}
|
|
1485
1523
|
|
|
@@ -1504,6 +1542,7 @@ function isTypeOnlyTmuxPrimitiveOccurrence(contents: string, occurrence: TmuxPri
|
|
|
1504
1542
|
}
|
|
1505
1543
|
|
|
1506
1544
|
function tmuxMachineBusViolations(file: string, contents: string): string[] {
|
|
1545
|
+
if (isGeneratedDocumentationIndex(file)) return [];
|
|
1507
1546
|
const allowedTeamFallbackRanges = file === teamRuntimeTmuxPath ? exactTeamRuntimeSendKeysRanges(contents) : [];
|
|
1508
1547
|
const violations: string[] = [];
|
|
1509
1548
|
for (const occurrence of tmuxPrimitiveOccurrences(contents)) {
|
|
@@ -1890,6 +1929,15 @@ async function scan(): Promise<string[]> {
|
|
|
1890
1929
|
} else {
|
|
1891
1930
|
violations.push(...tmuxMachineBusViolations(file, contents));
|
|
1892
1931
|
}
|
|
1932
|
+
if (
|
|
1933
|
+
file === teamWorkersTmuxPath &&
|
|
1934
|
+
!/^export const GJC_TEAM_CONTINUATION_PROMPT =\n\t"Continue only your current claimed GJC team task\. Re-read current GJC team state; do not replay prior output; report status\.";$/m.test(
|
|
1935
|
+
contents,
|
|
1936
|
+
)
|
|
1937
|
+
)
|
|
1938
|
+
violations.push(
|
|
1939
|
+
`${file}: stalled-worker continuation prompt must remain the exact source-controlled literal`,
|
|
1940
|
+
);
|
|
1893
1941
|
}
|
|
1894
1942
|
if (file === coordinatorMcpRoot) {
|
|
1895
1943
|
for (const pattern of coordinatorDirectAuthorityPatterns) {
|
|
@@ -3067,6 +3115,9 @@ fi
|
|
|
3067
3115
|
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3068
3116
|
);
|
|
3069
3117
|
const canonicalTeamRuntimeSendKeysFixture = `
|
|
3118
|
+
async function continueStalledGjcTeamWorkers(): Promise<void> {
|
|
3119
|
+
const revalidationReason = null;
|
|
3120
|
+
if (revalidationReason) return;
|
|
3070
3121
|
function shouldDispatchWorkerWithSendKeys(tmuxCommand: string, platform: NodeJS.Platform = process.platform): boolean {
|
|
3071
3122
|
return platform === "win32" || path.basename(tmuxCommand).toLowerCase() === "psmux";
|
|
3072
3123
|
}
|
|
@@ -3083,11 +3134,100 @@ if (useSendKeysFallback) {
|
|
|
3083
3134
|
});
|
|
3084
3135
|
void sendKeys.exitCode;
|
|
3085
3136
|
}
|
|
3137
|
+
const GJC_TEAM_CONTINUATION_PROMPT = "Continue only your current claimed GJC team task. Re-read current GJC team state; do not replay prior output; report status.";
|
|
3138
|
+
const GJC_TEAM_CONTINUATION_DISPATCH_TIMEOUT_MS = 5_000;
|
|
3139
|
+
const args = Object.freeze([
|
|
3140
|
+
"send-keys",
|
|
3141
|
+
"-l",
|
|
3142
|
+
"-t",
|
|
3143
|
+
worker.pane_id,
|
|
3144
|
+
GJC_TEAM_CONTINUATION_PROMPT,
|
|
3145
|
+
";",
|
|
3146
|
+
"send-keys",
|
|
3147
|
+
"-t",
|
|
3148
|
+
worker.pane_id,
|
|
3149
|
+
"Enter",
|
|
3150
|
+
]);
|
|
3151
|
+
|
|
3152
|
+
const dispatch = gjcTeamRuntimeTestSeams?.continuationTmuxDispatch
|
|
3153
|
+
? gjcTeamRuntimeTestSeams.continuationTmuxDispatch(config.tmux_command, args)
|
|
3154
|
+
: Bun.spawnSync([config.tmux_command, ...args], {
|
|
3155
|
+
stdout: "ignore",
|
|
3156
|
+
stderr: "ignore",
|
|
3157
|
+
timeout: GJC_TEAM_CONTINUATION_DISPATCH_TIMEOUT_MS,
|
|
3158
|
+
});
|
|
3159
|
+
}
|
|
3160
|
+
async function monitorGjcTeam(): Promise<void> {
|
|
3161
|
+
await withGjcTeamTaskMutation(taskStore(dir), async capability => {
|
|
3162
|
+
await continueStalledGjcTeamWorkers();
|
|
3163
|
+
await reconcileGjcTeamStaleClaimsUnlocked(workerOrchestrationRuntime, teamName, dir, config, env, capability);
|
|
3164
|
+
});
|
|
3165
|
+
}
|
|
3086
3166
|
`;
|
|
3087
3167
|
await runSelfTestFixture(
|
|
3088
3168
|
{ "packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture },
|
|
3089
3169
|
0,
|
|
3090
3170
|
);
|
|
3171
|
+
await runSelfTestFixture(
|
|
3172
|
+
{
|
|
3173
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3174
|
+
"async function continueStalledGjcTeamWorkers(): Promise<void>",
|
|
3175
|
+
"async function relocatedContinuation(): Promise<void>",
|
|
3176
|
+
),
|
|
3177
|
+
},
|
|
3178
|
+
1,
|
|
3179
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3180
|
+
);
|
|
3181
|
+
await runSelfTestFixture(
|
|
3182
|
+
{
|
|
3183
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3184
|
+
"if (revalidationReason) return;",
|
|
3185
|
+
"if (revalidationReason) {}",
|
|
3186
|
+
),
|
|
3187
|
+
},
|
|
3188
|
+
1,
|
|
3189
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3190
|
+
);
|
|
3191
|
+
await runSelfTestFixture(
|
|
3192
|
+
{
|
|
3193
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3194
|
+
"await continueStalledGjcTeamWorkers();",
|
|
3195
|
+
"",
|
|
3196
|
+
),
|
|
3197
|
+
},
|
|
3198
|
+
1,
|
|
3199
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3200
|
+
);
|
|
3201
|
+
await runSelfTestFixture(
|
|
3202
|
+
{
|
|
3203
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3204
|
+
"await continueStalledGjcTeamWorkers();\n\t\tawait reconcileGjcTeamStaleClaimsUnlocked(workerOrchestrationRuntime, teamName, dir, config, env, capability);",
|
|
3205
|
+
"await reconcileGjcTeamStaleClaimsUnlocked(workerOrchestrationRuntime, teamName, dir, config, env, capability);\n\t\tawait continueStalledGjcTeamWorkers();",
|
|
3206
|
+
),
|
|
3207
|
+
},
|
|
3208
|
+
1,
|
|
3209
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3210
|
+
);
|
|
3211
|
+
await runSelfTestFixture(
|
|
3212
|
+
{
|
|
3213
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3214
|
+
"const dispatch =",
|
|
3215
|
+
'args.push("forged");\nconst dispatch =',
|
|
3216
|
+
),
|
|
3217
|
+
},
|
|
3218
|
+
1,
|
|
3219
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3220
|
+
);
|
|
3221
|
+
await runSelfTestFixture(
|
|
3222
|
+
{
|
|
3223
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3224
|
+
"report status.",
|
|
3225
|
+
"report injected status.",
|
|
3226
|
+
),
|
|
3227
|
+
},
|
|
3228
|
+
1,
|
|
3229
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3230
|
+
);
|
|
3091
3231
|
await runSelfTestFixture(
|
|
3092
3232
|
{
|
|
3093
3233
|
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
@@ -3115,6 +3255,46 @@ if (useSendKeysFallback) {
|
|
|
3115
3255
|
1,
|
|
3116
3256
|
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3117
3257
|
);
|
|
3258
|
+
await runSelfTestFixture(
|
|
3259
|
+
{
|
|
3260
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replaceAll(
|
|
3261
|
+
"worker.pane_id",
|
|
3262
|
+
'"%99"',
|
|
3263
|
+
),
|
|
3264
|
+
},
|
|
3265
|
+
1,
|
|
3266
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3267
|
+
);
|
|
3268
|
+
await runSelfTestFixture(
|
|
3269
|
+
{
|
|
3270
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3271
|
+
'GJC_TEAM_CONTINUATION_PROMPT,\n\t";",',
|
|
3272
|
+
"`$" + "{GJC_TEAM_CONTINUATION_PROMPT}" + '`,\n\t";",',
|
|
3273
|
+
),
|
|
3274
|
+
},
|
|
3275
|
+
1,
|
|
3276
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3277
|
+
);
|
|
3278
|
+
await runSelfTestFixture(
|
|
3279
|
+
{
|
|
3280
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3281
|
+
'"send-keys",\n\t"-l",\n\t"-t",\n\tworker.pane_id,\n\tGJC_TEAM_CONTINUATION_PROMPT,\n\t";",\n\t"send-keys",\n\t"-t",\n\tworker.pane_id,\n\t"Enter",',
|
|
3282
|
+
'"send-keys", "-t", worker.pane_id, "Enter", ";", "send-keys", "-l", "-t", worker.pane_id, GJC_TEAM_CONTINUATION_PROMPT,',
|
|
3283
|
+
),
|
|
3284
|
+
},
|
|
3285
|
+
1,
|
|
3286
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3287
|
+
);
|
|
3288
|
+
await runSelfTestFixture(
|
|
3289
|
+
{
|
|
3290
|
+
"packages/coding-agent/src/gjc-runtime/team-runtime.ts": canonicalTeamRuntimeSendKeysFixture.replace(
|
|
3291
|
+
"Bun.spawnSync([config.tmux_command, ...args]",
|
|
3292
|
+
'Bun.spawnSync([config.tmux_command, "run-shell", ...args]',
|
|
3293
|
+
),
|
|
3294
|
+
},
|
|
3295
|
+
1,
|
|
3296
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3297
|
+
);
|
|
3118
3298
|
await runSelfTestFixture(
|
|
3119
3299
|
{
|
|
3120
3300
|
"packages/coding-agent/src/coordinator-mcp/server.ts":
|
package/src/async/job-manager.ts
CHANGED
|
@@ -12,6 +12,7 @@ const DELIVERY_MAX_TEXT_BYTES = 64 * 1024;
|
|
|
12
12
|
const DELIVERY_PREVIEW_HEAD_BYTES = 32 * 1024;
|
|
13
13
|
const DELIVERY_PREVIEW_TAIL_BYTES = 32 * 1024;
|
|
14
14
|
const DELIVERY_MAX_ATTEMPTS = 3;
|
|
15
|
+
const MAX_DEAD_LETTERED_DELIVERIES = 50;
|
|
15
16
|
|
|
16
17
|
export interface AsyncJob {
|
|
17
18
|
id: string;
|
|
@@ -207,6 +208,12 @@ interface AsyncJobDelivery {
|
|
|
207
208
|
promise?: Promise<void>;
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
interface DeadLetteredDelivery {
|
|
212
|
+
jobId: string;
|
|
213
|
+
attempt: number;
|
|
214
|
+
lastError?: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
210
217
|
export interface AsyncJobDeliveryState {
|
|
211
218
|
queued: number;
|
|
212
219
|
delivering: boolean;
|
|
@@ -381,7 +388,8 @@ export class AsyncJobManager {
|
|
|
381
388
|
* resume fails closed with reason "no_runner".
|
|
382
389
|
*/
|
|
383
390
|
readonly #descriptorResumeRunners = new Map<string, ResumeRunner>();
|
|
384
|
-
readonly #deadLetteredDeliveries = new Map<string,
|
|
391
|
+
readonly #deadLetteredDeliveries = new Map<string, DeadLetteredDelivery>();
|
|
392
|
+
readonly #deadLetteredDeliveryOwners = new Map<string, string | undefined>();
|
|
385
393
|
readonly #ownerSubagentShutdownLeases = new Map<string, OwnerSubagentShutdownLeaseState>();
|
|
386
394
|
#ownerSubagentShutdownSeq = 0;
|
|
387
395
|
#lastDisposeDiagnostics: AsyncJobDisposeDiagnostics = { stuckJobIds: [], deliveriesDrained: true };
|
|
@@ -1333,12 +1341,16 @@ export class AsyncJobManager {
|
|
|
1333
1341
|
}
|
|
1334
1342
|
|
|
1335
1343
|
getDeliveryState(filter?: AsyncJobFilter): AsyncJobDeliveryState {
|
|
1344
|
+
this.#expireMonitorTombstones();
|
|
1345
|
+
this.#pruneEvictedDeadLetters();
|
|
1336
1346
|
const deliveries = this.#filterDeliveries(filter);
|
|
1337
1347
|
const inFlightDeliveries = this.#filterInFlightDeliveries(filter);
|
|
1338
1348
|
const ownerId = filter?.ownerId;
|
|
1339
|
-
const deadLettered =
|
|
1340
|
-
|
|
1341
|
-
|
|
1349
|
+
const deadLettered = ownerId
|
|
1350
|
+
? Array.from(this.#deadLetteredDeliveries.keys()).filter(
|
|
1351
|
+
jobId => this.#deadLetteredDeliveryOwners.get(jobId) === ownerId,
|
|
1352
|
+
).length
|
|
1353
|
+
: this.#deadLetteredDeliveries.size;
|
|
1342
1354
|
const nextRetryAt = deliveries.reduce<number | undefined>((next, delivery) => {
|
|
1343
1355
|
if (next === undefined) return delivery.nextAttemptAt;
|
|
1344
1356
|
return Math.min(next, delivery.nextAttemptAt);
|
|
@@ -1553,6 +1565,7 @@ export class AsyncJobManager {
|
|
|
1553
1565
|
this.#deliveries.length = 0;
|
|
1554
1566
|
this.#inFlightDeliveries.length = 0;
|
|
1555
1567
|
this.#deadLetteredDeliveries.clear();
|
|
1568
|
+
this.#deadLetteredDeliveryOwners.clear();
|
|
1556
1569
|
this.#suppressedDeliveries.clear();
|
|
1557
1570
|
this.#watchedJobs.clear();
|
|
1558
1571
|
this.#outputState.clear();
|
|
@@ -1615,12 +1628,15 @@ export class AsyncJobManager {
|
|
|
1615
1628
|
}
|
|
1616
1629
|
|
|
1617
1630
|
#evictJob(jobId: string): void {
|
|
1631
|
+
this.#expireMonitorTombstones();
|
|
1618
1632
|
this.#recordMonitorTombstone(jobId);
|
|
1619
1633
|
this.#runLifecycle(jobId, "evict");
|
|
1620
1634
|
this.#purgeTerminalSubagentStateForJob(jobId);
|
|
1621
1635
|
this.#jobs.delete(jobId);
|
|
1622
1636
|
this.#lifecycles.delete(jobId);
|
|
1623
1637
|
this.#lifecyclePhases.delete(jobId);
|
|
1638
|
+
this.#deadLetteredDeliveries.delete(jobId);
|
|
1639
|
+
this.#deadLetteredDeliveryOwners.delete(jobId);
|
|
1624
1640
|
this.#suppressedDeliveries.delete(jobId);
|
|
1625
1641
|
this.#watchedJobs.delete(jobId);
|
|
1626
1642
|
this.#outputState.delete(jobId);
|
|
@@ -1700,6 +1716,33 @@ export class AsyncJobManager {
|
|
|
1700
1716
|
return this.#isDeliveryAcknowledged(jobId) || this.#watchedJobs.has(jobId);
|
|
1701
1717
|
}
|
|
1702
1718
|
|
|
1719
|
+
#pruneEvictedDeadLetters(): void {
|
|
1720
|
+
for (const jobId of this.#deadLetteredDeliveries.keys()) {
|
|
1721
|
+
if (this.#jobs.has(jobId)) continue;
|
|
1722
|
+
this.#deadLetteredDeliveries.delete(jobId);
|
|
1723
|
+
this.#deadLetteredDeliveryOwners.delete(jobId);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
#recordDeadLetter(delivery: AsyncJobDelivery): void {
|
|
1728
|
+
this.#pruneEvictedDeadLetters();
|
|
1729
|
+
if (!this.#jobs.has(delivery.jobId)) return;
|
|
1730
|
+
this.#deadLetteredDeliveries.delete(delivery.jobId);
|
|
1731
|
+
this.#deadLetteredDeliveryOwners.delete(delivery.jobId);
|
|
1732
|
+
this.#deadLetteredDeliveries.set(delivery.jobId, {
|
|
1733
|
+
jobId: delivery.jobId,
|
|
1734
|
+
attempt: delivery.attempt,
|
|
1735
|
+
lastError: delivery.lastError,
|
|
1736
|
+
});
|
|
1737
|
+
this.#deadLetteredDeliveryOwners.set(delivery.jobId, delivery.ownerId);
|
|
1738
|
+
while (this.#deadLetteredDeliveries.size > MAX_DEAD_LETTERED_DELIVERIES) {
|
|
1739
|
+
const oldestJobId = this.#deadLetteredDeliveries.keys().next().value;
|
|
1740
|
+
if (oldestJobId === undefined) return;
|
|
1741
|
+
this.#deadLetteredDeliveries.delete(oldestJobId);
|
|
1742
|
+
this.#deadLetteredDeliveryOwners.delete(oldestJobId);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1703
1746
|
#enqueueDelivery(jobId: string, text: string): void {
|
|
1704
1747
|
// Skip delivery if already acknowledged
|
|
1705
1748
|
if (this.#isDeliveryAcknowledged(jobId)) {
|
|
@@ -1717,7 +1760,7 @@ export class AsyncJobManager {
|
|
|
1717
1760
|
});
|
|
1718
1761
|
while (this.#deliveries.length > DEFAULT_MAX_DELIVERY_QUEUE) {
|
|
1719
1762
|
const dropped = this.#deliveries.shift();
|
|
1720
|
-
if (dropped) this.#
|
|
1763
|
+
if (dropped) this.#recordDeadLetter(dropped);
|
|
1721
1764
|
}
|
|
1722
1765
|
this.#ensureDeliveryLoop();
|
|
1723
1766
|
}
|
|
@@ -1781,7 +1824,7 @@ export class AsyncJobManager {
|
|
|
1781
1824
|
delivery.attempt += 1;
|
|
1782
1825
|
delivery.lastError = error instanceof Error ? error.message : String(error);
|
|
1783
1826
|
if (delivery.attempt >= DELIVERY_MAX_ATTEMPTS) {
|
|
1784
|
-
this.#
|
|
1827
|
+
this.#recordDeadLetter(delivery);
|
|
1785
1828
|
logger.warn("Async job completion delivery reached retry cap", {
|
|
1786
1829
|
jobId: delivery.jobId,
|
|
1787
1830
|
attempt: delivery.attempt,
|