@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
|
@@ -4,27 +4,34 @@ import * as fs from "node:fs/promises";
|
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { getAgentDir, isKnownSinkPeerClosedError } from "@gajae-code/utils";
|
|
6
6
|
import { normalizePathForComparison, VERSION } from "@gajae-code/utils/dirs";
|
|
7
|
-
|
|
8
|
-
import { withFileLock } from "../config/file-lock";
|
|
9
7
|
import {
|
|
10
8
|
COORDINATOR_MCP_PROTOCOL_VERSION,
|
|
11
9
|
COORDINATOR_MCP_SERVER_NAME,
|
|
12
10
|
COORDINATOR_MCP_TOOL_NAMES,
|
|
13
11
|
type CoordinatorToolName,
|
|
14
12
|
} from "../coordinator/contract";
|
|
13
|
+
import { SessionStateLockUnavailableError, withSessionStateFileLock } from "../gjc-runtime/session-state-lock";
|
|
14
|
+
import {
|
|
15
|
+
classifyRuntimeToolActivity,
|
|
16
|
+
publicRuntimeToolActivity,
|
|
17
|
+
terminallySettledRuntimeToolActivity,
|
|
18
|
+
} from "../gjc-runtime/session-state-sidecar";
|
|
15
19
|
import { listMcpDelegateHostContexts } from "../hooks/mcp-delegate-host-context";
|
|
16
20
|
import type { WorkflowGate, WorkflowGateQueryRecord } from "../modes/shared/agent-wire/workflow-gate-types";
|
|
17
21
|
import type { BrokerDiscovery } from "../sdk/broker/discovery";
|
|
18
22
|
import { type EnsureBrokerSettings, ensureBroker } from "../sdk/broker/ensure";
|
|
19
23
|
import { lifecycleRequestTimeoutMs } from "../sdk/broker/startup-budget";
|
|
20
24
|
import { UnsupportedStateVersionError } from "../sdk/broker/state-version";
|
|
21
|
-
import { SdkClient, SdkClientError
|
|
25
|
+
import { SdkClient, SdkClientError } from "../sdk/client/client";
|
|
22
26
|
import { readSdkBrokerDiscovery } from "../sdk/client/discovery";
|
|
27
|
+
import { reduceTerminalReceiptState } from "../sdk/receipt-state";
|
|
28
|
+
import { type SessionAttachment, SessionRouter, type SessionRouterDeps, SessionRouterError } from "../sdk/router";
|
|
23
29
|
import {
|
|
24
30
|
type ActivatedPreparedSession,
|
|
25
31
|
requestPreparedSessionActivation,
|
|
26
32
|
SessionActivationError,
|
|
27
33
|
} from "../sdk/session-activation";
|
|
34
|
+
import { SessionListTraversalError, sessionListPageFromResponse, traverseSessionList } from "../sdk/session-list";
|
|
28
35
|
import {
|
|
29
36
|
ackCodexWakeEvent,
|
|
30
37
|
bindDelegateCodexHandoff,
|
|
@@ -111,16 +118,6 @@ interface JsonRpcResponse {
|
|
|
111
118
|
error?: { code: number; message: string; data?: unknown };
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
function isLifecycleOperation(operation: string): boolean {
|
|
115
|
-
return (
|
|
116
|
-
operation === "session.create" ||
|
|
117
|
-
operation === "session.fork" ||
|
|
118
|
-
operation === "session.resume" ||
|
|
119
|
-
operation === "session.close" ||
|
|
120
|
-
operation === "session.delete"
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
121
|
function sinkErrorCode(error: unknown): string | undefined {
|
|
125
122
|
if (error === null || (typeof error !== "object" && typeof error !== "function")) return undefined;
|
|
126
123
|
try {
|
|
@@ -173,10 +170,11 @@ interface CoordinatorFinalResponse {
|
|
|
173
170
|
truncated: boolean;
|
|
174
171
|
}
|
|
175
172
|
|
|
176
|
-
function reportableFinalResponse(response: CoordinatorFinalResponse): boolean {
|
|
177
|
-
return (
|
|
178
|
-
|
|
179
|
-
|
|
173
|
+
function reportableFinalResponse(response: CoordinatorFinalResponse | undefined): boolean {
|
|
174
|
+
return Boolean(
|
|
175
|
+
response &&
|
|
176
|
+
((typeof response.text === "string" && response.text.trim().length > 0) ||
|
|
177
|
+
(typeof response.artifact_path === "string" && response.artifact_path.trim().length > 0)),
|
|
180
178
|
);
|
|
181
179
|
}
|
|
182
180
|
|
|
@@ -186,7 +184,8 @@ interface RuntimeSessionStatePayload extends CoordinatorSessionState {
|
|
|
186
184
|
}
|
|
187
185
|
|
|
188
186
|
interface CoordinatorServices {
|
|
189
|
-
|
|
187
|
+
connectBroker?: (url: string, token: string) => Promise<SdkClient>;
|
|
188
|
+
routerDeps?: SessionRouterDeps;
|
|
190
189
|
ensureBroker?: (settings: EnsureBrokerSettings) => Promise<BrokerDiscovery>;
|
|
191
190
|
readSdkBrokerDiscovery?: (agentDir: string) => Promise<BrokerDiscovery | null>;
|
|
192
191
|
getAgentDir?: () => string;
|
|
@@ -277,13 +276,15 @@ interface CoordinatorSessionState {
|
|
|
277
276
|
current_turn_id: string | null;
|
|
278
277
|
last_turn_id: string | null;
|
|
279
278
|
updated_at: string;
|
|
279
|
+
ended_at?: string;
|
|
280
280
|
source: "coordinator" | "agent_session_event";
|
|
281
281
|
live: boolean | null;
|
|
282
282
|
reason: string | null;
|
|
283
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Tool-activity snapshot owned by the runtime sidecar; never lifecycle state. It is
|
|
285
|
+
* carried opaquely because only the sidecar's validator decides what is publishable.
|
|
286
|
+
*/
|
|
284
287
|
activity?: unknown;
|
|
285
|
-
active_tools?: unknown;
|
|
286
|
-
active_tool_calls?: unknown;
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
type CoordinatorEventKind =
|
|
@@ -338,8 +339,15 @@ const UNOBSERVED_COMPENSATION_CODE = "broker_compensation_unobserved";
|
|
|
338
339
|
const MISSING_FINAL_RESPONSE_ADVISORY = "completion_missing_final_response";
|
|
339
340
|
const PROMPT_ACK_TIMEOUT_REASON = "runtime_prompt_ack_timeout";
|
|
340
341
|
const DEFAULT_RUNTIME_PROMPT_ACK_TIMEOUT_MS = 10_000;
|
|
342
|
+
/**
|
|
343
|
+
* Pagination window for `readCompleteQ12Snapshot`: it stops starting pages once
|
|
344
|
+
* this much time has passed and gives each page only the remainder as its reply
|
|
345
|
+
* budget. It bounds pagination, not the whole call — attachment resolution runs
|
|
346
|
+
* before the window opens, and a page's budget is a post-connect reply deadline,
|
|
347
|
+
* so transport reconnect time sits outside it.
|
|
348
|
+
*/
|
|
349
|
+
const Q12_SNAPSHOT_BUDGET_MS = 5_000;
|
|
341
350
|
const MAX_RUNTIME_PROMPT_ACK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
342
|
-
const MAX_COORDINATOR_SESSION_LIST_PAGES = 10_000;
|
|
343
351
|
const ACTIVE_TURN_STATUSES = new Set<TurnStatus>(["delivering", "active", "waiting_for_answer", "completing"]);
|
|
344
352
|
const TERMINAL_TURN_STATUSES = new Set<TurnStatus>(["completed", "failed", "cancelled", "superseded"]);
|
|
345
353
|
const TURN_ID_PATTERN = /^turn-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1241,7 +1249,10 @@ function publicLifecycleReceipt(result: Record<string, unknown>, sessionId: stri
|
|
|
1241
1249
|
|
|
1242
1250
|
function publicCoordinatorSessionState(state: CoordinatorSessionState | null): Record<string, unknown> | null {
|
|
1243
1251
|
if (!state) return null;
|
|
1244
|
-
|
|
1252
|
+
// The sidecar owns the one projection that strips its private correlation state and
|
|
1253
|
+
// withholds any snapshot that contradicts the lifecycle state published beside it.
|
|
1254
|
+
const activity = publicRuntimeToolActivity(state.activity, state.state);
|
|
1255
|
+
return {
|
|
1245
1256
|
session_id: state.session_id,
|
|
1246
1257
|
state: state.state,
|
|
1247
1258
|
ready_for_input: state.ready_for_input,
|
|
@@ -1249,56 +1260,11 @@ function publicCoordinatorSessionState(state: CoordinatorSessionState | null): R
|
|
|
1249
1260
|
last_turn_id: state.last_turn_id,
|
|
1250
1261
|
updated_at: state.updated_at,
|
|
1251
1262
|
...(typeof state.live === "boolean" ? { live: state.live } : {}),
|
|
1263
|
+
...(activity ? { activity } : {}),
|
|
1264
|
+
...(typeof state.ended_at === "string" && Number.isFinite(Date.parse(state.ended_at))
|
|
1265
|
+
? { ended_at: state.ended_at }
|
|
1266
|
+
: {}),
|
|
1252
1267
|
};
|
|
1253
|
-
const activity = asRecord(state.activity);
|
|
1254
|
-
if (
|
|
1255
|
-
typeof state.last_activity_at === "string" &&
|
|
1256
|
-
Number.isFinite(Date.parse(state.last_activity_at)) &&
|
|
1257
|
-
activity &&
|
|
1258
|
-
typeof activity.sequence === "number" &&
|
|
1259
|
-
Number.isSafeInteger(activity.sequence) &&
|
|
1260
|
-
activity.sequence > 0 &&
|
|
1261
|
-
activity.kind === "tool_execution" &&
|
|
1262
|
-
(activity.phase === "started" || activity.phase === "finished") &&
|
|
1263
|
-
typeof activity.tool_name === "string" &&
|
|
1264
|
-
/^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(activity.tool_name) &&
|
|
1265
|
-
typeof activity.observed_at === "string" &&
|
|
1266
|
-
Number.isFinite(Date.parse(activity.observed_at)) &&
|
|
1267
|
-
typeof activity.active_tool_count === "number" &&
|
|
1268
|
-
Number.isSafeInteger(activity.active_tool_count) &&
|
|
1269
|
-
activity.active_tool_count >= 0
|
|
1270
|
-
) {
|
|
1271
|
-
result.last_activity_at = state.last_activity_at;
|
|
1272
|
-
result.activity = {
|
|
1273
|
-
sequence: activity.sequence,
|
|
1274
|
-
kind: activity.kind,
|
|
1275
|
-
phase: activity.phase,
|
|
1276
|
-
tool_name: activity.tool_name,
|
|
1277
|
-
observed_at: activity.observed_at,
|
|
1278
|
-
...(typeof activity.started_at === "string" && Number.isFinite(Date.parse(activity.started_at))
|
|
1279
|
-
? { started_at: activity.started_at }
|
|
1280
|
-
: {}),
|
|
1281
|
-
...(typeof activity.elapsed_ms === "number" &&
|
|
1282
|
-
Number.isSafeInteger(activity.elapsed_ms) &&
|
|
1283
|
-
activity.elapsed_ms >= 0
|
|
1284
|
-
? { elapsed_ms: activity.elapsed_ms }
|
|
1285
|
-
: {}),
|
|
1286
|
-
...(activity.outcome === "succeeded" || activity.outcome === "failed" ? { outcome: activity.outcome } : {}),
|
|
1287
|
-
active_tool_count: activity.active_tool_count,
|
|
1288
|
-
};
|
|
1289
|
-
if (Array.isArray(state.active_tools))
|
|
1290
|
-
result.active_tools = state.active_tools.slice(0, 8).flatMap(value => {
|
|
1291
|
-
const tool = asRecord(value);
|
|
1292
|
-
return tool &&
|
|
1293
|
-
typeof tool.tool_name === "string" &&
|
|
1294
|
-
/^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(tool.tool_name) &&
|
|
1295
|
-
typeof tool.started_at === "string" &&
|
|
1296
|
-
Number.isFinite(Date.parse(tool.started_at))
|
|
1297
|
-
? [{ tool_name: tool.tool_name, started_at: tool.started_at }]
|
|
1298
|
-
: [];
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
return result;
|
|
1302
1268
|
}
|
|
1303
1269
|
|
|
1304
1270
|
function eventTimestamp(record: Record<string, unknown>): string | null {
|
|
@@ -1888,35 +1854,52 @@ async function writeSessionStateUnlocked(
|
|
|
1888
1854
|
live?: boolean | null;
|
|
1889
1855
|
reason?: string | null;
|
|
1890
1856
|
source?: CoordinatorSessionState["source"];
|
|
1857
|
+
/** Rebuild the lifecycle fields from canonical state instead of the previous projection. */
|
|
1891
1858
|
overwrite?: boolean;
|
|
1892
1859
|
} = {},
|
|
1893
1860
|
): Promise<CoordinatorSessionState> {
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1861
|
+
const persisted = await readSessionState(namespaceDir, sessionId);
|
|
1862
|
+
// An overwrite is a canonical lifecycle repair, not proof that tool activity ended.
|
|
1863
|
+
const previous = options.overwrite ? null : persisted;
|
|
1896
1864
|
const hasCurrentTurn = Object.hasOwn(options, "currentTurnId");
|
|
1897
1865
|
const hasLastTurn = Object.hasOwn(options, "lastTurnId");
|
|
1898
1866
|
const hasLive = Object.hasOwn(options, "live");
|
|
1867
|
+
const updatedAt = new Date().toISOString();
|
|
1868
|
+
// A coordinator write says nothing about tool activity, so every lifecycle path —
|
|
1869
|
+
// including canonical repair — carries the sidecar's snapshot and its sequence
|
|
1870
|
+
// forward. A TERMINAL lifecycle state is the one exception: it is authority that
|
|
1871
|
+
// nothing can still be running, so it settles orphaned in-flight calls through the
|
|
1872
|
+
// exact helper the runtime uses. A malformed snapshot is preserved verbatim rather
|
|
1873
|
+
// than reset to a lower sequence; the public projection refuses to publish it either way.
|
|
1874
|
+
const terminal = state === "completed" || state === "errored";
|
|
1875
|
+
const activity = terminal
|
|
1876
|
+
? terminallySettledRuntimeToolActivity(persisted?.activity, updatedAt)
|
|
1877
|
+
: classifyRuntimeToolActivity(persisted?.activity);
|
|
1878
|
+
const isTerminalState = state === "completed" || state === "errored" || state === "stale";
|
|
1879
|
+
const endedAt = isTerminalState
|
|
1880
|
+
? updatedAt
|
|
1881
|
+
: typeof persisted?.ended_at === "string" && Number.isFinite(Date.parse(persisted.ended_at))
|
|
1882
|
+
? persisted.ended_at
|
|
1883
|
+
: undefined;
|
|
1899
1884
|
const payload: CoordinatorSessionState = {
|
|
1900
1885
|
schema_version: 1,
|
|
1901
1886
|
session_id: sessionId,
|
|
1902
1887
|
state,
|
|
1903
|
-
ready_for_input: state === "ready_for_input"
|
|
1888
|
+
ready_for_input: state === "ready_for_input",
|
|
1904
1889
|
current_turn_id: hasCurrentTurn
|
|
1905
1890
|
? (options.currentTurnId ?? null)
|
|
1906
1891
|
: state === "running"
|
|
1907
1892
|
? (previous?.current_turn_id ?? null)
|
|
1908
1893
|
: null,
|
|
1909
1894
|
last_turn_id: hasLastTurn ? (options.lastTurnId ?? null) : (previous?.last_turn_id ?? null),
|
|
1910
|
-
updated_at:
|
|
1895
|
+
updated_at: updatedAt,
|
|
1911
1896
|
source: options.source ?? "coordinator",
|
|
1912
1897
|
live: hasLive ? (options.live ?? null) : (previous?.live ?? null),
|
|
1913
1898
|
reason: options.reason ?? null,
|
|
1914
|
-
...(
|
|
1915
|
-
...(
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
? { active_tool_calls: existing.active_tool_calls }
|
|
1919
|
-
: {}),
|
|
1899
|
+
...(endedAt !== undefined ? { ended_at: endedAt } : {}),
|
|
1900
|
+
...(activity.kind === "absent"
|
|
1901
|
+
? {}
|
|
1902
|
+
: { activity: activity.kind === "valid" ? activity.activity : persisted?.activity }),
|
|
1920
1903
|
};
|
|
1921
1904
|
await writeJsonFile(sessionStateFile(namespaceDir, sessionId), payload);
|
|
1922
1905
|
if (
|
|
@@ -1944,8 +1927,24 @@ async function writeSessionStateUnlocked(
|
|
|
1944
1927
|
return payload;
|
|
1945
1928
|
}
|
|
1946
1929
|
|
|
1930
|
+
/**
|
|
1931
|
+
* Serialize a coordinator state mutation on the same lock the runtime sidecar takes.
|
|
1932
|
+
*
|
|
1933
|
+
* Both writers contend for `<file>.lock`, so they must use one implementation and one
|
|
1934
|
+
* on-disk owner format. That format is the base Coordinator's regular-file owner JSON,
|
|
1935
|
+
* now shared: a directory-style lock here would make a base-version `<file>.lock` regular
|
|
1936
|
+
* file permanently unusable (`ENOTDIR` on `<file>.lock/info`), stranding the session. The
|
|
1937
|
+
* base runtime did use a directory at this path, so the shared implementation reclaims
|
|
1938
|
+
* that shape too. Live owners are waited for; dead and malformed ones are reclaimed by
|
|
1939
|
+
* that implementation's own liveness and staleness checks.
|
|
1940
|
+
*/
|
|
1947
1941
|
async function withSessionStateLock<T>(stateFile: string, operation: () => Promise<T>): Promise<T> {
|
|
1948
|
-
|
|
1942
|
+
try {
|
|
1943
|
+
return await withSessionStateFileLock(stateFile, operation);
|
|
1944
|
+
} catch (error) {
|
|
1945
|
+
if (error instanceof SessionStateLockUnavailableError) throw new Error("coordinator_state_unreadable");
|
|
1946
|
+
throw error;
|
|
1947
|
+
}
|
|
1949
1948
|
}
|
|
1950
1949
|
|
|
1951
1950
|
async function writeSessionState(
|
|
@@ -1993,7 +1992,12 @@ async function markTurnTerminalFromSessionState(
|
|
|
1993
1992
|
turn: TurnRecord,
|
|
1994
1993
|
sessionState: CoordinatorSessionState,
|
|
1995
1994
|
): Promise<TurnRecord> {
|
|
1996
|
-
const
|
|
1995
|
+
const receiptState = reduceTerminalReceiptState({
|
|
1996
|
+
execution: sessionState.state === "errored" ? "failed" : "completed",
|
|
1997
|
+
reportable: reportableFinalResponse((sessionState as RuntimeSessionStatePayload).final_response),
|
|
1998
|
+
});
|
|
1999
|
+
const terminalStatus: TurnStatus =
|
|
2000
|
+
receiptState.receipt === "missing" ? "failed" : sessionState.state === "errored" ? "failed" : "completed";
|
|
1997
2001
|
const runtimeState = sessionState as RuntimeSessionStatePayload;
|
|
1998
2002
|
const finalResponse = runtimeState.final_response ?? {
|
|
1999
2003
|
text: null,
|
|
@@ -2012,24 +2016,21 @@ async function markTurnTerminalFromSessionState(
|
|
|
2012
2016
|
state: "acknowledged",
|
|
2013
2017
|
},
|
|
2014
2018
|
final_response: finalResponse,
|
|
2015
|
-
evidence:
|
|
2016
|
-
? turn.evidence
|
|
2017
|
-
: [
|
|
2018
|
-
...turn.evidence,
|
|
2019
|
-
{
|
|
2020
|
-
type: MISSING_FINAL_RESPONSE_ADVISORY,
|
|
2021
|
-
message: "Runtime completed without reportable final_response text or artifact_path.",
|
|
2022
|
-
created_at: timestamp,
|
|
2023
|
-
},
|
|
2024
|
-
],
|
|
2019
|
+
evidence: turn.evidence,
|
|
2025
2020
|
error:
|
|
2026
|
-
|
|
2027
|
-
?
|
|
2028
|
-
code: "
|
|
2029
|
-
message:
|
|
2021
|
+
receiptState.receipt === "missing"
|
|
2022
|
+
? {
|
|
2023
|
+
code: "receipt_missing",
|
|
2024
|
+
message: "Runtime completed without reportable final_response text or artifact_path.",
|
|
2030
2025
|
recoverable: true,
|
|
2031
|
-
}
|
|
2032
|
-
:
|
|
2026
|
+
}
|
|
2027
|
+
: terminalStatus === "failed"
|
|
2028
|
+
? (runtimeState.error ?? {
|
|
2029
|
+
code: "runtime_errored",
|
|
2030
|
+
message: sessionState.reason ?? "runtime_errored",
|
|
2031
|
+
recoverable: true,
|
|
2032
|
+
})
|
|
2033
|
+
: null,
|
|
2033
2034
|
updated_at: timestamp,
|
|
2034
2035
|
completed_at: timestamp,
|
|
2035
2036
|
};
|
|
@@ -2363,6 +2364,16 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2363
2364
|
const config = buildCoordinatorMcpConfig(env);
|
|
2364
2365
|
const promptAckTimeoutMs = boundedRuntimePromptAckTimeoutMs(env.GJC_COORDINATOR_MCP_PROMPT_ACK_TIMEOUT_MS);
|
|
2365
2366
|
const services = options.services ?? {};
|
|
2367
|
+
const routerAgentDir = services.getAgentDir?.() ?? getAgentDir();
|
|
2368
|
+
const router = new SessionRouter({ agentDir: routerAgentDir, deps: services.routerDeps });
|
|
2369
|
+
let routerReady: Promise<void> | null = null;
|
|
2370
|
+
async function ensureRouterReady(): Promise<void> {
|
|
2371
|
+
routerReady ??= router.start().catch(error => {
|
|
2372
|
+
routerReady = null;
|
|
2373
|
+
throw error;
|
|
2374
|
+
});
|
|
2375
|
+
await routerReady;
|
|
2376
|
+
}
|
|
2366
2377
|
const platform = options.platform ?? process.platform;
|
|
2367
2378
|
const loadModelProfiles = services.resolveModelProfiles ?? loadCoordinatorModelProfiles;
|
|
2368
2379
|
const namespaceDir = path.join(
|
|
@@ -2832,27 +2843,111 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2832
2843
|
}
|
|
2833
2844
|
}
|
|
2834
2845
|
|
|
2846
|
+
type CoordinatorSessionAttachment = {
|
|
2847
|
+
sessionId: string;
|
|
2848
|
+
generation: number;
|
|
2849
|
+
attachment: SessionAttachment;
|
|
2850
|
+
};
|
|
2851
|
+
|
|
2852
|
+
async function resolveSessionAttachment(session: Record<string, unknown>): Promise<CoordinatorSessionAttachment> {
|
|
2853
|
+
const sessionId = optionalString(session.session_id) ?? optionalString(session.sessionId);
|
|
2854
|
+
const generation =
|
|
2855
|
+
typeof session.endpoint_generation === "number" &&
|
|
2856
|
+
Number.isSafeInteger(session.endpoint_generation) &&
|
|
2857
|
+
session.endpoint_generation > 0
|
|
2858
|
+
? session.endpoint_generation
|
|
2859
|
+
: null;
|
|
2860
|
+
const workspace = optionalString(session.broker_workspace);
|
|
2861
|
+
const incarnation = optionalString(session.endpoint_incarnation);
|
|
2862
|
+
if (!sessionId || generation === null)
|
|
2863
|
+
throw new SdkClientError("not_found", "Coordinator session has no usable endpoint generation.");
|
|
2864
|
+
if (!workspace || !incarnation)
|
|
2865
|
+
throw new SdkClientError("endpoint_stale", "Coordinator session has no exact endpoint authority.");
|
|
2866
|
+
let persistedWorkspace: string;
|
|
2867
|
+
try {
|
|
2868
|
+
persistedWorkspace = await canonicalBrokerWorkspace(workspace);
|
|
2869
|
+
} catch {
|
|
2870
|
+
throw new SdkClientError("endpoint_stale", "Coordinator session workspace authority is unavailable.");
|
|
2871
|
+
}
|
|
2872
|
+
await ensureRouterReady();
|
|
2873
|
+
await router.reconcile();
|
|
2874
|
+
const attachment = router.attachment(sessionId, generation);
|
|
2875
|
+
if (!attachment?.isCurrent())
|
|
2876
|
+
throw new SdkClientError("endpoint_stale", "Coordinator session attachment is unavailable or stale.");
|
|
2877
|
+
let authority: BrokerSessionAuthority;
|
|
2878
|
+
try {
|
|
2879
|
+
authority = await exactBrokerSessionAuthority(sessionId, persistedWorkspace);
|
|
2880
|
+
} catch (error) {
|
|
2881
|
+
if (error instanceof SdkClientError && (error.code === "not_found" || error.code === "endpoint_stale"))
|
|
2882
|
+
throw new SdkClientError(
|
|
2883
|
+
"endpoint_stale",
|
|
2884
|
+
"Coordinator session endpoint authority is unavailable or stale.",
|
|
2885
|
+
);
|
|
2886
|
+
throw error;
|
|
2887
|
+
}
|
|
2888
|
+
if (
|
|
2889
|
+
!sameCanonicalPath(authority.workspace, persistedWorkspace, platform) ||
|
|
2890
|
+
authority.endpointGeneration !== generation ||
|
|
2891
|
+
authority.endpointIncarnation !== incarnation
|
|
2892
|
+
)
|
|
2893
|
+
throw new SdkClientError("endpoint_stale", "Coordinator session endpoint authority changed.");
|
|
2894
|
+
return { sessionId, generation, attachment };
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
function sdkResponse(response: Record<string, unknown>, operation: string): Record<string, unknown> {
|
|
2898
|
+
if (response.ok !== true) {
|
|
2899
|
+
const error = asRecord(response.error);
|
|
2900
|
+
throw new SdkClientError(
|
|
2901
|
+
typeof error?.code === "string" ? error.code : "unavailable",
|
|
2902
|
+
typeof error?.message === "string" ? error.message : `SDK ${operation} request failed.`,
|
|
2903
|
+
);
|
|
2904
|
+
}
|
|
2905
|
+
return response;
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
async function requestSessionFrame(
|
|
2909
|
+
target: CoordinatorSessionAttachment,
|
|
2910
|
+
frame: Record<string, unknown>,
|
|
2911
|
+
options?: { timeoutMs?: number },
|
|
2912
|
+
): Promise<Record<string, unknown>> {
|
|
2913
|
+
try {
|
|
2914
|
+
return await router.request(target.sessionId, frame, target.generation, target.attachment, options);
|
|
2915
|
+
} catch (error) {
|
|
2916
|
+
if (error instanceof SessionRouterError)
|
|
2917
|
+
throw new SdkClientError(
|
|
2918
|
+
error.phase === "ambiguous" ? "ambiguous" : "endpoint_stale",
|
|
2919
|
+
error.phase === "ambiguous"
|
|
2920
|
+
? "Coordinator session request may have been accepted before attachment changed."
|
|
2921
|
+
: "Coordinator session attachment changed before request dispatch.",
|
|
2922
|
+
error,
|
|
2923
|
+
);
|
|
2924
|
+
throw error;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2835
2928
|
async function controlSession(
|
|
2836
2929
|
session: Record<string, unknown>,
|
|
2837
2930
|
operation: string,
|
|
2838
2931
|
input: Record<string, unknown>,
|
|
2839
2932
|
idempotencyKey: string,
|
|
2840
2933
|
): Promise<unknown> {
|
|
2841
|
-
const
|
|
2842
|
-
const
|
|
2843
|
-
endpoint.url,
|
|
2844
|
-
endpoint.token,
|
|
2845
|
-
);
|
|
2846
|
-
const isPromptOperation =
|
|
2934
|
+
const target = await resolveSessionAttachment(session);
|
|
2935
|
+
const promptOperation =
|
|
2847
2936
|
operation === "turn.prompt" || operation === "turn.follow_up" || operation === "turn.abort_and_prompt";
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2937
|
+
const response = asRecord(
|
|
2938
|
+
await requestSessionFrame(
|
|
2939
|
+
target,
|
|
2940
|
+
{
|
|
2941
|
+
type: "control_request",
|
|
2942
|
+
operation,
|
|
2943
|
+
input,
|
|
2944
|
+
idempotencyKey,
|
|
2945
|
+
},
|
|
2946
|
+
promptOperation ? { timeoutMs: promptAckTimeoutMs } : undefined,
|
|
2947
|
+
),
|
|
2948
|
+
);
|
|
2949
|
+
if (response?.ok === false) sdkResponse(response, operation);
|
|
2950
|
+
return response;
|
|
2856
2951
|
}
|
|
2857
2952
|
|
|
2858
2953
|
async function querySession(
|
|
@@ -2861,24 +2956,17 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2861
2956
|
input: Record<string, unknown> = {},
|
|
2862
2957
|
cursor?: string,
|
|
2863
2958
|
): Promise<Record<string, unknown>> {
|
|
2864
|
-
const
|
|
2865
|
-
const
|
|
2866
|
-
|
|
2867
|
-
|
|
2959
|
+
const target = await resolveSessionAttachment(session);
|
|
2960
|
+
const response = asRecord(
|
|
2961
|
+
await requestSessionFrame(target, {
|
|
2962
|
+
type: "query_request",
|
|
2963
|
+
query,
|
|
2964
|
+
input,
|
|
2965
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
2966
|
+
}),
|
|
2868
2967
|
);
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
if (response?.ok !== true) {
|
|
2872
|
-
const error = asRecord(response?.error);
|
|
2873
|
-
throw new SdkClientError(
|
|
2874
|
-
typeof error?.code === "string" ? error.code : "unavailable",
|
|
2875
|
-
typeof error?.message === "string" ? error.message : `SDK ${query} query failed.`,
|
|
2876
|
-
);
|
|
2877
|
-
}
|
|
2878
|
-
return response;
|
|
2879
|
-
} finally {
|
|
2880
|
-
await client.close();
|
|
2881
|
-
}
|
|
2968
|
+
if (!response) throw new SdkClientError("unavailable", `SDK ${query} query returned an invalid response.`);
|
|
2969
|
+
return sdkResponse(response, query);
|
|
2882
2970
|
}
|
|
2883
2971
|
|
|
2884
2972
|
async function readCompleteQ12Snapshot(session: Record<string, unknown>): Promise<{
|
|
@@ -2887,25 +2975,36 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2887
2975
|
complete: boolean;
|
|
2888
2976
|
reason: "pagination_malformed" | "query_unavailable" | null;
|
|
2889
2977
|
}> {
|
|
2890
|
-
const deadline = Date.now() +
|
|
2978
|
+
const deadline = Date.now() + Q12_SNAPSHOT_BUDGET_MS;
|
|
2891
2979
|
const items: unknown[] = [];
|
|
2892
2980
|
const cursors = new Set<string>();
|
|
2893
2981
|
let cursor: string | undefined;
|
|
2894
2982
|
let revision: string | null = null;
|
|
2895
2983
|
let bytes = 0;
|
|
2896
|
-
let
|
|
2984
|
+
let target: CoordinatorSessionAttachment;
|
|
2897
2985
|
try {
|
|
2898
|
-
|
|
2899
|
-
client = await (services.connectSdk ?? ((url, token) => SdkClient.connect(url, token)))(
|
|
2900
|
-
endpoint.url,
|
|
2901
|
-
endpoint.token,
|
|
2902
|
-
);
|
|
2986
|
+
target = await resolveSessionAttachment(session);
|
|
2903
2987
|
} catch {
|
|
2904
2988
|
return { items: [], revision, complete: false, reason: "query_unavailable" };
|
|
2905
2989
|
}
|
|
2906
2990
|
try {
|
|
2907
2991
|
for (let pageCount = 0; pageCount < 8 && Date.now() <= deadline; pageCount++) {
|
|
2908
|
-
|
|
2992
|
+
// The snapshot deadline is only checked between pages, so each page has to
|
|
2993
|
+
// carry what is left of it. Without that budget the page inherits the
|
|
2994
|
+
// Router's session reply budget and one wedged page outlives the whole
|
|
2995
|
+
// snapshot bound this function promises its callers.
|
|
2996
|
+
const response = asRecord(
|
|
2997
|
+
await requestSessionFrame(
|
|
2998
|
+
target,
|
|
2999
|
+
{
|
|
3000
|
+
type: "query_request",
|
|
3001
|
+
query: "Q12",
|
|
3002
|
+
input: {},
|
|
3003
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
3004
|
+
},
|
|
3005
|
+
{ timeoutMs: Math.max(1, deadline - Date.now()) },
|
|
3006
|
+
),
|
|
3007
|
+
);
|
|
2909
3008
|
if (response?.ok !== true) return { items: [], revision, complete: false, reason: "query_unavailable" };
|
|
2910
3009
|
const page = asRecord(response.page);
|
|
2911
3010
|
const pageItems = page?.items;
|
|
@@ -2946,8 +3045,6 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2946
3045
|
return { items: [], revision, complete: false, reason: "pagination_malformed" };
|
|
2947
3046
|
} catch {
|
|
2948
3047
|
return { items: [], revision, complete: false, reason: "query_unavailable" };
|
|
2949
|
-
} finally {
|
|
2950
|
-
await client.close().catch(() => undefined);
|
|
2951
3048
|
}
|
|
2952
3049
|
}
|
|
2953
3050
|
|
|
@@ -2992,6 +3089,11 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2992
3089
|
return error?.code === UNOBSERVED_COMPENSATION_CODE;
|
|
2993
3090
|
}
|
|
2994
3091
|
|
|
3092
|
+
function isRouterRequestAmbiguous(response: Record<string, unknown>): boolean {
|
|
3093
|
+
if (response.ok !== false) return false;
|
|
3094
|
+
return asRecord(response.error)?.code === "ambiguous";
|
|
3095
|
+
}
|
|
3096
|
+
|
|
2995
3097
|
function sdkError(error: unknown): Record<string, unknown> {
|
|
2996
3098
|
if (error instanceof SdkClientError) return { ok: false, error: { code: error.code, message: error.message } };
|
|
2997
3099
|
return {
|
|
@@ -3006,6 +3108,20 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3006
3108
|
return key;
|
|
3007
3109
|
}
|
|
3008
3110
|
|
|
3111
|
+
/**
|
|
3112
|
+
* Path for the lock owner file that serializes idempotency mutations.
|
|
3113
|
+
*
|
|
3114
|
+
* Lock artifacts (owner records, transition markers, quarantine placeholders) are
|
|
3115
|
+
* created as siblings of the locked path by {@link withSessionStateFileLock}.
|
|
3116
|
+
* The record directory must enumerate as parseable records only, so the lock
|
|
3117
|
+
* path lives in a sibling `idempotency-locks` directory: its artifacts can never
|
|
3118
|
+
* appear inside `idempotency/`, which would surface as
|
|
3119
|
+
* `JSON Parse error: Unexpected EOF` during replay or enumeration.
|
|
3120
|
+
*/
|
|
3121
|
+
function idempotencyLockFile(idempotencyKey: string): string {
|
|
3122
|
+
const keyDigest = createHash("sha256").update(idempotencyKey).digest("hex");
|
|
3123
|
+
return path.join(namespaceDir, "idempotency-locks", `${keyDigest}.json`);
|
|
3124
|
+
}
|
|
3009
3125
|
function idempotencyFile(idempotencyKey: string): string {
|
|
3010
3126
|
const keyDigest = createHash("sha256").update(idempotencyKey).digest("hex");
|
|
3011
3127
|
return path.join(namespaceDir, "idempotency", `${keyDigest}.json`);
|
|
@@ -3021,8 +3137,8 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3021
3137
|
* the remote effect settled. A tool may declare such a response nonterminal,
|
|
3022
3138
|
* which returns it to this caller while the receipt stays `in_progress`, so
|
|
3023
3139
|
* an exact same-key retry re-runs the observation under the same request
|
|
3024
|
-
* digest.
|
|
3025
|
-
*
|
|
3140
|
+
* digest. Router post-send ambiguity is nonterminal by default; every other
|
|
3141
|
+
* tool-specific exception is supplied by its handler.
|
|
3026
3142
|
*/
|
|
3027
3143
|
async function withToolIdempotency(
|
|
3028
3144
|
tool: string,
|
|
@@ -3030,14 +3146,15 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3030
3146
|
canonicalArgs: Record<string, unknown>,
|
|
3031
3147
|
operation: () => Promise<Record<string, unknown>>,
|
|
3032
3148
|
recoverInProgress = false,
|
|
3033
|
-
isNonterminal: (response: Record<string, unknown>) => boolean =
|
|
3149
|
+
isNonterminal: (response: Record<string, unknown>) => boolean = isRouterRequestAmbiguous,
|
|
3034
3150
|
): Promise<Record<string, unknown>> {
|
|
3035
3151
|
const keyDigest = createHash("sha256").update(idempotencyKey).digest("hex");
|
|
3036
3152
|
const requestDigest = createHash("sha256")
|
|
3037
3153
|
.update(canonicalJson({ tool, args: canonicalArgs }))
|
|
3038
3154
|
.digest("hex");
|
|
3039
3155
|
const file = idempotencyFile(idempotencyKey);
|
|
3040
|
-
|
|
3156
|
+
const lockFile = idempotencyLockFile(idempotencyKey);
|
|
3157
|
+
return await withSessionStateLock(lockFile, async () => {
|
|
3041
3158
|
const existingFile = await readCoordinatorIdempotencyFile(file);
|
|
3042
3159
|
if (existingFile.kind === "corrupt")
|
|
3043
3160
|
return {
|
|
@@ -3144,7 +3261,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3144
3261
|
|
|
3145
3262
|
let client: SdkClient;
|
|
3146
3263
|
try {
|
|
3147
|
-
client = await (services.
|
|
3264
|
+
client = await (services.connectBroker ?? ((url, token) => SdkClient.connect(url, token)))(
|
|
3148
3265
|
discovery.url,
|
|
3149
3266
|
discovery.token,
|
|
3150
3267
|
);
|
|
@@ -3161,15 +3278,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3161
3278
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
3162
3279
|
});
|
|
3163
3280
|
} catch (error) {
|
|
3164
|
-
|
|
3165
|
-
if (
|
|
3166
|
-
isLifecycleOperation(operation) &&
|
|
3167
|
-
mapped.code === "uncertain_after_send" &&
|
|
3168
|
-
mapped.details &&
|
|
3169
|
-
typeof mapped.details === "object"
|
|
3170
|
-
)
|
|
3171
|
-
result = await client.lookupLifecycle(mapped.details as SdkSentRecord);
|
|
3172
|
-
else requestError = mapped;
|
|
3281
|
+
requestError = toCoordinatorBrokerError("request", error);
|
|
3173
3282
|
}
|
|
3174
3283
|
try {
|
|
3175
3284
|
await client.close();
|
|
@@ -3196,28 +3305,29 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3196
3305
|
cwd: string,
|
|
3197
3306
|
input: Record<string, unknown>,
|
|
3198
3307
|
): Promise<Record<string, unknown>> {
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3308
|
+
try {
|
|
3309
|
+
const pages = await traverseSessionList(
|
|
3310
|
+
input,
|
|
3311
|
+
async pageInput => {
|
|
3312
|
+
const response = await brokerSession(cwd, "session.list", pageInput);
|
|
3313
|
+
if (asRecord(response)?.ok === false) brokerResult(response);
|
|
3314
|
+
return response;
|
|
3315
|
+
},
|
|
3316
|
+
response => sessionListPageFromResponse(response),
|
|
3208
3317
|
);
|
|
3209
|
-
|
|
3210
|
-
|
|
3318
|
+
const aggregate: Record<string, unknown> = {};
|
|
3319
|
+
const sessions: unknown[] = [];
|
|
3320
|
+
for (const { page } of pages) {
|
|
3321
|
+
for (const [key, value] of Object.entries(page)) {
|
|
3322
|
+
if (key !== "sessions" && key !== "continuationCursor") aggregate[key] = value;
|
|
3323
|
+
}
|
|
3324
|
+
sessions.push(...page.sessions);
|
|
3211
3325
|
}
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
: undefined;
|
|
3217
|
-
if (!nextCursor) return { ...aggregate, sessions };
|
|
3218
|
-
cursor = nextCursor;
|
|
3326
|
+
return { ...aggregate, sessions };
|
|
3327
|
+
} catch (error) {
|
|
3328
|
+
if (error instanceof SessionListTraversalError) throw new SdkClientError("protocol_error", error.message);
|
|
3329
|
+
throw error;
|
|
3219
3330
|
}
|
|
3220
|
-
throw new SdkClientError("protocol_error", "session.list exceeded the page budget.");
|
|
3221
3331
|
}
|
|
3222
3332
|
|
|
3223
3333
|
async function canonicalBrokerWorkspace(cwd: string): Promise<string> {
|
|
@@ -3295,123 +3405,29 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3295
3405
|
return { workspace: match.workspace, endpointGeneration, endpointIncarnation };
|
|
3296
3406
|
}
|
|
3297
3407
|
|
|
3298
|
-
async function exactBrokerSessionBinding(
|
|
3299
|
-
sessionId
|
|
3300
|
-
workspace: string,
|
|
3301
|
-
idempotencyKey?: string,
|
|
3302
|
-
): Promise<BrokerSessionAuthority & { endpoint: { url: string; token: string } }> {
|
|
3303
|
-
const authority = await exactBrokerSessionAuthority(sessionId, workspace);
|
|
3304
|
-
const endpointRecord = brokerResult(
|
|
3305
|
-
await brokerSession(
|
|
3306
|
-
workspace,
|
|
3307
|
-
"session.get_endpoint",
|
|
3308
|
-
{
|
|
3309
|
-
sessionId,
|
|
3310
|
-
endpointGeneration: authority.endpointGeneration,
|
|
3311
|
-
endpointIncarnation: authority.endpointIncarnation,
|
|
3312
|
-
},
|
|
3313
|
-
idempotencyKey,
|
|
3314
|
-
),
|
|
3315
|
-
);
|
|
3316
|
-
const url = optionalString(endpointRecord.url);
|
|
3317
|
-
const token = optionalString(endpointRecord.token);
|
|
3318
|
-
if (!url || !token)
|
|
3319
|
-
throw new SdkClientError("endpoint_stale", "Broker returned an invalid incarnation-bound endpoint.");
|
|
3320
|
-
return { ...authority, endpoint: { url, token } };
|
|
3321
|
-
}
|
|
3322
|
-
|
|
3323
|
-
async function resolveSessionEndpoint(
|
|
3324
|
-
session: Record<string, unknown>,
|
|
3325
|
-
idempotencyKey?: string,
|
|
3326
|
-
): Promise<{ url: string; token: string }> {
|
|
3327
|
-
const sessionId = optionalString(session.session_id) ?? optionalString(session.sessionId);
|
|
3328
|
-
const cwd = optionalString(session.cwd);
|
|
3329
|
-
const persistedWorkspace = optionalString(session.broker_workspace);
|
|
3330
|
-
const persistedGeneration =
|
|
3331
|
-
typeof session.endpoint_generation === "number" &&
|
|
3332
|
-
Number.isSafeInteger(session.endpoint_generation) &&
|
|
3333
|
-
session.endpoint_generation > 0
|
|
3334
|
-
? session.endpoint_generation
|
|
3335
|
-
: null;
|
|
3336
|
-
const persistedIncarnation = optionalString(session.endpoint_incarnation);
|
|
3337
|
-
if (!sessionId || !cwd || !persistedWorkspace || persistedGeneration === null || !persistedIncarnation)
|
|
3338
|
-
throw new SdkClientError("not_found", "Coordinator session has no incarnation-bound broker identity.");
|
|
3339
|
-
const workspace = await canonicalBrokerWorkspace(cwd);
|
|
3340
|
-
if (!sameCanonicalPath(workspace, persistedWorkspace, platform))
|
|
3341
|
-
throw new SdkClientError("endpoint_stale", "Coordinator session workspace binding is stale.");
|
|
3342
|
-
const binding = await exactBrokerSessionBinding(sessionId, workspace, idempotencyKey);
|
|
3343
|
-
if (binding.endpointGeneration !== persistedGeneration || binding.endpointIncarnation !== persistedIncarnation)
|
|
3344
|
-
throw new SdkClientError("endpoint_stale", "Coordinator session endpoint incarnation is stale.");
|
|
3345
|
-
return binding.endpoint;
|
|
3346
|
-
}
|
|
3347
|
-
|
|
3348
|
-
/**
|
|
3349
|
-
* The same incarnation-bound authority `resolveSessionEndpoint` requires,
|
|
3350
|
-
* plus the exact endpoint generation the activation frame has to name. A
|
|
3351
|
-
* session whose endpoint rolled or whose workspace binding drifted is refused
|
|
3352
|
-
* here, before any activation is attempted.
|
|
3353
|
-
*/
|
|
3354
|
-
async function resolveSessionActivationTarget(
|
|
3355
|
-
session: Record<string, unknown>,
|
|
3356
|
-
idempotencyKey?: string,
|
|
3357
|
-
): Promise<{ endpoint: { url: string; token: string }; endpointGeneration: number }> {
|
|
3358
|
-
const sessionId = optionalString(session.session_id) ?? optionalString(session.sessionId);
|
|
3359
|
-
const cwd = optionalString(session.cwd);
|
|
3360
|
-
const persistedWorkspace = optionalString(session.broker_workspace);
|
|
3361
|
-
const persistedGeneration =
|
|
3362
|
-
typeof session.endpoint_generation === "number" &&
|
|
3363
|
-
Number.isSafeInteger(session.endpoint_generation) &&
|
|
3364
|
-
session.endpoint_generation > 0
|
|
3365
|
-
? session.endpoint_generation
|
|
3366
|
-
: null;
|
|
3367
|
-
const persistedIncarnation = optionalString(session.endpoint_incarnation);
|
|
3368
|
-
if (!sessionId || !cwd || !persistedWorkspace || persistedGeneration === null || !persistedIncarnation)
|
|
3369
|
-
throw new SdkClientError("not_found", "Coordinator session has no incarnation-bound broker identity.");
|
|
3370
|
-
const workspace = await canonicalBrokerWorkspace(cwd);
|
|
3371
|
-
if (!sameCanonicalPath(workspace, persistedWorkspace, platform))
|
|
3372
|
-
throw new SdkClientError("endpoint_stale", "Coordinator session workspace binding is stale.");
|
|
3373
|
-
const binding = await exactBrokerSessionBinding(sessionId, workspace, idempotencyKey);
|
|
3374
|
-
if (binding.endpointGeneration !== persistedGeneration || binding.endpointIncarnation !== persistedIncarnation)
|
|
3375
|
-
throw new SdkClientError("endpoint_stale", "Coordinator session endpoint incarnation is stale.");
|
|
3376
|
-
return { endpoint: binding.endpoint, endpointGeneration: binding.endpointGeneration };
|
|
3408
|
+
async function exactBrokerSessionBinding(sessionId: string, workspace: string): Promise<BrokerSessionAuthority> {
|
|
3409
|
+
return await exactBrokerSessionAuthority(sessionId, workspace);
|
|
3377
3410
|
}
|
|
3378
3411
|
|
|
3379
3412
|
/**
|
|
3380
|
-
* Ask a prepared session to publish its withheld readiness
|
|
3381
|
-
*
|
|
3382
|
-
*
|
|
3383
|
-
* signal: it proves exact endpoint authority, then delegates to the same
|
|
3384
|
-
* activation exchange the `gjc notify activate-thread` CLI uses. The session's
|
|
3385
|
-
* own activation gate remains the authority on whether a binding exists.
|
|
3413
|
+
* Ask a prepared session to publish its withheld readiness through the
|
|
3414
|
+
* Router-owned attachment. Endpoint credentials and SDK clients never leave
|
|
3415
|
+
* SessionRouter.
|
|
3386
3416
|
*/
|
|
3387
3417
|
async function activatePreparedCoordinatorSession(
|
|
3388
3418
|
session: Record<string, unknown>,
|
|
3389
3419
|
sessionId: string,
|
|
3390
|
-
|
|
3420
|
+
_idempotencyKey: string,
|
|
3391
3421
|
): Promise<ActivatedPreparedSession> {
|
|
3392
|
-
const target = await
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
throw new SessionActivationError("activation_unavailable", "The session endpoint could not be reached.");
|
|
3402
|
-
}
|
|
3403
|
-
try {
|
|
3404
|
-
return await requestPreparedSessionActivation(
|
|
3405
|
-
{
|
|
3406
|
-
request: async frame => (await client.request(frame)) as Record<string, unknown>,
|
|
3407
|
-
close: async () => await client.close(),
|
|
3408
|
-
},
|
|
3409
|
-
sessionId,
|
|
3410
|
-
target.endpointGeneration,
|
|
3411
|
-
);
|
|
3412
|
-
} finally {
|
|
3413
|
-
await client.close().catch(() => undefined);
|
|
3414
|
-
}
|
|
3422
|
+
const target = await resolveSessionAttachment(session);
|
|
3423
|
+
return await requestPreparedSessionActivation(
|
|
3424
|
+
{
|
|
3425
|
+
request: async frame => await requestSessionFrame(target, frame),
|
|
3426
|
+
close: async () => {},
|
|
3427
|
+
},
|
|
3428
|
+
sessionId,
|
|
3429
|
+
target.generation,
|
|
3430
|
+
);
|
|
3415
3431
|
}
|
|
3416
3432
|
|
|
3417
3433
|
async function listSessions(cwd?: string): Promise<Array<Record<string, unknown>>> {
|
|
@@ -3528,16 +3544,49 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3528
3544
|
await advanceDeletion(questionPaths, deletionId, "broker_closed");
|
|
3529
3545
|
|
|
3530
3546
|
try {
|
|
3531
|
-
await
|
|
3532
|
-
|
|
3547
|
+
const listing = await paginatedBrokerSessionList(workspace, { cwd: workspace });
|
|
3548
|
+
const rows = jsonRecords(
|
|
3549
|
+
Array.isArray((listing as Record<string, unknown>).sessions)
|
|
3550
|
+
? ((listing as Record<string, unknown>).sessions as unknown[])
|
|
3551
|
+
: [],
|
|
3552
|
+
);
|
|
3553
|
+
const candidates: Array<Record<string, unknown>> = [];
|
|
3554
|
+
for (const row of rows) {
|
|
3555
|
+
if (brokerSessionId(row) !== id) continue;
|
|
3556
|
+
const declaredWorkspace = brokerSessionScope(row);
|
|
3557
|
+
if (!declaredWorkspace) continue;
|
|
3558
|
+
let canonicalDeclared: string;
|
|
3559
|
+
try {
|
|
3560
|
+
canonicalDeclared = await canonicalBrokerWorkspace(declaredWorkspace);
|
|
3561
|
+
} catch {
|
|
3562
|
+
continue;
|
|
3563
|
+
}
|
|
3564
|
+
if (sameCanonicalPath(canonicalDeclared, workspace, platform)) candidates.push(row);
|
|
3565
|
+
}
|
|
3566
|
+
if (candidates.length === 0) {
|
|
3567
|
+
// No retained row: proven deletion (session_deleted) after successful close.
|
|
3568
|
+
} else if (candidates.length !== 1) {
|
|
3569
|
+
return { ok: false, reason: "close_failed", detail: "endpoint_stale", closed: false };
|
|
3570
|
+
} else {
|
|
3571
|
+
const row = candidates[0]!;
|
|
3572
|
+
const gen = brokerEndpointGeneration(row);
|
|
3573
|
+
const inc = brokerEndpointIncarnation(row, id);
|
|
3574
|
+
const genMatches = gen === persistedGeneration;
|
|
3575
|
+
const incMatches = inc === persistedIncarnation;
|
|
3576
|
+
if (!genMatches || !incMatches) return { ok: false, reason: "endpoint_stale", closed: false };
|
|
3577
|
+
const isAmbiguous = row.ambiguous === true;
|
|
3578
|
+
const isTerminalUncertain =
|
|
3579
|
+
row.terminalUncertain === true || (row as Record<string, unknown>).terminal_uncertain === true;
|
|
3580
|
+
const isTerminal = row.terminal === true;
|
|
3581
|
+
const isLive = row.live === true;
|
|
3582
|
+
if (isAmbiguous || isTerminalUncertain)
|
|
3583
|
+
return { ok: false, reason: "close_failed", detail: "endpoint_stale", closed: false };
|
|
3584
|
+
if (!isTerminal || isLive) return { ok: false, reason: "endpoint_stale", closed: false };
|
|
3585
|
+
}
|
|
3533
3586
|
} catch (error) {
|
|
3534
|
-
if (
|
|
3535
|
-
return {
|
|
3536
|
-
|
|
3537
|
-
reason: "close_failed",
|
|
3538
|
-
detail: error instanceof SdkClientError ? error.code : "unavailable",
|
|
3539
|
-
closed: false,
|
|
3540
|
-
};
|
|
3587
|
+
if (error instanceof SdkClientError)
|
|
3588
|
+
return { ok: false, reason: "close_failed", detail: error.code, closed: false };
|
|
3589
|
+
return { ok: false, reason: "close_failed", detail: "unavailable", closed: false };
|
|
3541
3590
|
}
|
|
3542
3591
|
await fs.rm(sessionFile(id), { force: true });
|
|
3543
3592
|
await fs.rm(sessionStateFile(namespaceDir, id), { force: true });
|
|
@@ -3771,9 +3820,12 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
3771
3820
|
const existing = transaction.requests.prompts[keyDigest];
|
|
3772
3821
|
if (existing) {
|
|
3773
3822
|
if (existing.request_digest !== requestDigest) throw new Error("idempotency_conflict");
|
|
3774
|
-
if (existing.phase === "
|
|
3775
|
-
|
|
3776
|
-
|
|
3823
|
+
if (existing.phase === "uncertain") throw new Error("terminal_uncertain");
|
|
3824
|
+
// The host deduplicates this key, so a post-send Router ambiguity may re-dispatch it to recover the receipt.
|
|
3825
|
+
if (existing.phase === "remote_started") {
|
|
3826
|
+
existing.updated_at = new Date().toISOString();
|
|
3827
|
+
return;
|
|
3828
|
+
}
|
|
3777
3829
|
}
|
|
3778
3830
|
const now = new Date().toISOString();
|
|
3779
3831
|
transaction.requests.prompts[keyDigest] = {
|
|
@@ -4170,7 +4222,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4170
4222
|
const creation = await claimProductionCreation(name, idempotencyKey, canonicalArgs);
|
|
4171
4223
|
if (creation.request.phase === "completed" && creation.request.safe_response)
|
|
4172
4224
|
return creation.request.safe_response;
|
|
4173
|
-
const binding = await exactBrokerSessionBinding(sessionId, cwd
|
|
4225
|
+
const binding = await exactBrokerSessionBinding(sessionId, cwd);
|
|
4174
4226
|
const session = normalizeSession({
|
|
4175
4227
|
session_id: sessionId,
|
|
4176
4228
|
cwd,
|
|
@@ -4555,7 +4607,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4555
4607
|
message: "Coordinator session is bound to another workspace.",
|
|
4556
4608
|
},
|
|
4557
4609
|
};
|
|
4558
|
-
const binding = await exactBrokerSessionBinding(sessionId, canonicalCwd
|
|
4610
|
+
const binding = await exactBrokerSessionBinding(sessionId, canonicalCwd);
|
|
4559
4611
|
if (
|
|
4560
4612
|
!sameCanonicalPath(
|
|
4561
4613
|
optionalString(existing.broker_workspace) ?? "",
|
|
@@ -4619,7 +4671,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4619
4671
|
const createdCwd = await canonicalBrokerWorkspace(
|
|
4620
4672
|
optionalString(created.cwd) ?? canonicalCwd,
|
|
4621
4673
|
);
|
|
4622
|
-
const binding = await exactBrokerSessionBinding(sessionId, createdCwd
|
|
4674
|
+
const binding = await exactBrokerSessionBinding(sessionId, createdCwd);
|
|
4623
4675
|
session = normalizeSession({
|
|
4624
4676
|
session_id: sessionId,
|
|
4625
4677
|
cwd: createdCwd,
|
|
@@ -4875,7 +4927,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4875
4927
|
}
|
|
4876
4928
|
sessionId = safeExternalId("session", created.sessionId ?? created.session_id);
|
|
4877
4929
|
const sessionCwd = await canonicalBrokerWorkspace(optionalString(created.cwd) ?? cwd);
|
|
4878
|
-
const binding = await exactBrokerSessionBinding(sessionId, sessionCwd
|
|
4930
|
+
const binding = await exactBrokerSessionBinding(sessionId, sessionCwd);
|
|
4879
4931
|
session = normalizeSession({
|
|
4880
4932
|
session_id: sessionId,
|
|
4881
4933
|
cwd: sessionCwd,
|
|
@@ -4956,7 +5008,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4956
5008
|
return response;
|
|
4957
5009
|
},
|
|
4958
5010
|
true,
|
|
4959
|
-
isUnobservedCompensation,
|
|
5011
|
+
response => isUnobservedCompensation(response) || isRouterRequestAmbiguous(response),
|
|
4960
5012
|
);
|
|
4961
5013
|
}
|
|
4962
5014
|
if (name === "gjc_coordinator_activate_session") {
|
|
@@ -5055,7 +5107,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
5055
5107
|
* `already` rather than publishing readiness twice.
|
|
5056
5108
|
*/
|
|
5057
5109
|
true,
|
|
5058
|
-
isUnknownActivationOutcome,
|
|
5110
|
+
response => isUnknownActivationOutcome(response) || isRouterRequestAmbiguous(response),
|
|
5059
5111
|
);
|
|
5060
5112
|
}
|
|
5061
5113
|
if (name === "gjc_coordinator_send_prompt") {
|
|
@@ -5145,6 +5197,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
5145
5197
|
session_state: publicCoordinatorSessionState(await readSessionState(namespaceDir, sessionId)),
|
|
5146
5198
|
};
|
|
5147
5199
|
}),
|
|
5200
|
+
true,
|
|
5148
5201
|
);
|
|
5149
5202
|
}
|
|
5150
5203
|
if (name === "gjc_coordinator_read_turn") {
|
|
@@ -5713,7 +5766,19 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
5713
5766
|
return { jsonrpc: "2.0", id, error: { code: -32601, message: `unknown_method:${request.method}` } };
|
|
5714
5767
|
}
|
|
5715
5768
|
|
|
5716
|
-
return {
|
|
5769
|
+
return {
|
|
5770
|
+
config,
|
|
5771
|
+
callTool,
|
|
5772
|
+
handleJsonRpc,
|
|
5773
|
+
handle: handleJsonRpc,
|
|
5774
|
+
reapSession,
|
|
5775
|
+
sessionReaper,
|
|
5776
|
+
router,
|
|
5777
|
+
close: async () => {
|
|
5778
|
+
sessionReaper.stop();
|
|
5779
|
+
await router.stop();
|
|
5780
|
+
},
|
|
5781
|
+
};
|
|
5717
5782
|
}
|
|
5718
5783
|
|
|
5719
5784
|
function legacyToolResult(payload: unknown): { content: Array<{ type: "text"; text: string }>; isError: boolean } {
|
|
@@ -5754,11 +5819,15 @@ export async function handleCoordinatorMcpRequest(
|
|
|
5754
5819
|
const params = (request.params ?? {}) as { name?: string; arguments?: Record<string, unknown> };
|
|
5755
5820
|
const args = params.arguments ?? {};
|
|
5756
5821
|
const server = createCoordinatorMcpServer({ env: options.env ?? process.env });
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5822
|
+
try {
|
|
5823
|
+
return {
|
|
5824
|
+
jsonrpc: "2.0",
|
|
5825
|
+
id: request.id ?? null,
|
|
5826
|
+
result: legacyToolResult(await server.callTool(params.name ?? "", args)),
|
|
5827
|
+
};
|
|
5828
|
+
} finally {
|
|
5829
|
+
await server.close();
|
|
5830
|
+
}
|
|
5762
5831
|
}
|
|
5763
5832
|
|
|
5764
5833
|
export interface PumpCoordinatorOptions {
|
|
@@ -5982,6 +6051,6 @@ export async function runCoordinatorMcpStdio(options: CoordinatorMcpServerOption
|
|
|
5982
6051
|
},
|
|
5983
6052
|
);
|
|
5984
6053
|
} finally {
|
|
5985
|
-
server.
|
|
6054
|
+
await server.close();
|
|
5986
6055
|
}
|
|
5987
6056
|
}
|