@gajae-code/coding-agent 0.17.1 → 0.17.4
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 +266 -0
- package/dist/types/async/job-manager.d.ts +7 -6
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/github-release.d.ts +17 -0
- package/dist/types/cli/public-command-entry.d.ts +56 -0
- package/dist/types/cli/public-command-errors.d.ts +126 -0
- package/dist/types/cli/public-command-evidence.d.ts +99 -0
- package/dist/types/cli/public-command-help.d.ts +65 -0
- package/dist/types/cli/public-command-registry.d.ts +69 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -0
- package/dist/types/cli/skills-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +4 -50
- package/dist/types/commands/sdk.d.ts +20 -37
- package/dist/types/commands/setup.d.ts +3 -0
- package/dist/types/commands/skills.d.ts +9 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/file-lock.d.ts +10 -1
- package/dist/types/config/model-profile-activation.d.ts +63 -4
- package/dist/types/config/model-registry.d.ts +20 -2
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/coordinator-mcp/server.d.ts +3 -0
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +12 -0
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
- package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/parse.d.ts +9 -1
- package/dist/types/main.d.ts +22 -0
- package/dist/types/modes/acp/acp-agent.d.ts +94 -1
- package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
- package/dist/types/modes/components/session-selector.d.ts +5 -2
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
- package/dist/types/modes/types.d.ts +2 -2
- package/dist/types/runtime/process-lifecycle.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +56 -0
- package/dist/types/runtime-mcp/pool.d.ts +17 -0
- package/dist/types/runtime-mcp/redaction.d.ts +20 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
- package/dist/types/sdk/acp/adapter.d.ts +27 -0
- package/dist/types/sdk/acp/final-text.d.ts +8 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/ensure.d.ts +46 -1
- package/dist/types/sdk/broker/identity.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
- package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
- package/dist/types/sdk/broker/runtime.d.ts +1 -1
- package/dist/types/sdk/broker/session-index.d.ts +22 -3
- package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
- package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
- package/dist/types/sdk/bus/index.d.ts +19 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
- package/dist/types/sdk/cli/master-cli.d.ts +6 -10
- package/dist/types/sdk/cli/rows.d.ts +19 -1
- package/dist/types/sdk/cli/session-cli.d.ts +22 -5
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/guides/cli.d.ts +3 -4
- package/dist/types/sdk/guides/verify.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +9 -0
- package/dist/types/sdk/host/session-runtime.d.ts +31 -0
- package/dist/types/sdk/host/types.d.ts +10 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
- package/dist/types/sdk/prompt-failure.d.ts +30 -1
- package/dist/types/sdk/prompt-status.d.ts +8 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +168 -21
- package/dist/types/session/fallback-chain-controller.d.ts +6 -6
- package/dist/types/session/fold-coordinator.d.ts +17 -3
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
- package/dist/types/session/session-manager.d.ts +64 -1
- package/dist/types/session/session-work-lease.d.ts +14 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
- package/dist/types/setup/provider-onboarding.d.ts +81 -1
- package/dist/types/thinking.d.ts +3 -1
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf.d.ts +4 -0
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/dist/types/web/scrapers/types.d.ts +3 -0
- package/package.json +18 -10
- package/scripts/build-binary.ts +9 -3
- package/scripts/compile-args.ts +0 -9
- package/scripts/embed-mupdf.ts +52 -0
- package/scripts/generate-sdk-operation-inventory.ts +31 -1
- package/scripts/vendor-markit.ts +196 -0
- package/src/async/job-manager.ts +60 -9
- package/src/cli/daemon-cli.ts +53 -18
- package/src/cli/github-release.ts +87 -5
- package/src/cli/mcp-cli.ts +38 -4
- package/src/cli/public-command-entry.ts +450 -0
- package/src/cli/public-command-errors.ts +581 -0
- package/src/cli/public-command-evidence.ts +717 -0
- package/src/cli/public-command-help.ts +360 -0
- package/src/cli/public-command-registry.ts +535 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +9 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +232 -100
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +16 -0
- package/src/config/file-lock.ts +199 -68
- package/src/config/model-profile-activation.ts +406 -53
- package/src/config/model-registry.ts +204 -25
- package/src/config/settings-schema.ts +26 -2
- package/src/coordinator-mcp/policy.ts +10 -5
- package/src/coordinator-mcp/question-gate-codec.ts +17 -0
- package/src/coordinator-mcp/question-state.ts +175 -8
- package/src/coordinator-mcp/server.ts +528 -87
- package/src/coordinator-mcp/session-reaper.ts +6 -4
- package/src/crash/record-loader.ts +6 -2
- package/src/daemon/operator-contract.ts +26 -12
- package/src/debug/report-bundle.ts +114 -24
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
- package/src/eval/js/context-manager.ts +8 -8
- package/src/eval/js/worker-core.ts +9 -4
- package/src/eval/js/worker-protocol.ts +2 -0
- package/src/extensibility/extensions/runner.ts +52 -4
- package/src/extensibility/extensions/types.ts +10 -0
- package/src/extensibility/gjc-plugins/registry.ts +196 -37
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/managed-owner-admission.ts +67 -50
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +21 -19
- package/src/internal-urls/embedded-protocol.ts +83 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/parse.ts +21 -1
- package/src/internal-urls/router.ts +4 -2
- package/src/main.ts +123 -55
- package/src/modes/acp/acp-agent.ts +593 -47
- package/src/modes/acp/acp-event-mapper.ts +9 -0
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/model-selector.ts +31 -15
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/components/thinking-selector.ts +7 -3
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/controllers/command-controller.ts +58 -32
- package/src/modes/controllers/extension-ui-controller.ts +33 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +177 -18
- package/src/modes/interactive-mode.ts +21 -7
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
- package/src/modes/types.ts +2 -2
- package/src/prompts/agent-fragments/browser-aside.md +1 -0
- package/src/prompts/system/title-system.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/read.md +2 -0
- package/src/runtime/network-prewarm-service.test.ts +36 -1
- package/src/runtime/network-prewarm-service.ts +28 -3
- package/src/runtime/process-lifecycle.ts +22 -11
- package/src/runtime-mcp/config.ts +16 -1
- package/src/runtime-mcp/manager.ts +689 -55
- package/src/runtime-mcp/pool.test.ts +31 -0
- package/src/runtime-mcp/pool.ts +304 -28
- package/src/runtime-mcp/redaction.ts +42 -0
- package/src/runtime-mcp/startup-policy.ts +7 -0
- package/src/runtime-mcp/tool-bridge.ts +71 -0
- package/src/runtime-mcp/transports/http.ts +108 -25
- package/src/sdk/acp/adapter.ts +90 -9
- package/src/sdk/acp/final-text.ts +19 -2
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/ensure.ts +97 -19
- package/src/sdk/broker/identity.ts +9 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +35 -7
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
- package/src/sdk/bus/index.ts +721 -84
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -3
- package/src/sdk/cli/master-cli.ts +47 -36
- package/src/sdk/cli/rows.ts +30 -7
- package/src/sdk/cli/session-cli.ts +687 -184
- package/src/sdk/client/client.ts +18 -0
- package/src/sdk/guides/catalog.ts +2 -2
- package/src/sdk/guides/cli.ts +20 -62
- package/src/sdk/guides/verify.ts +14 -0
- package/src/sdk/host/host.ts +49 -5
- package/src/sdk/host/session-runtime.test.ts +636 -9
- package/src/sdk/host/session-runtime.ts +499 -118
- package/src/sdk/host/types.ts +12 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
- package/src/sdk/host/websocket-transport.ts +40 -6
- package/src/sdk/index.ts +11 -0
- package/src/sdk/prompt-deadline-flush.ts +334 -0
- package/src/sdk/prompt-deadline-manager.ts +136 -4
- package/src/sdk/prompt-failure.ts +43 -1
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
- package/src/sdk/router/session-router.ts +31 -4
- package/src/sdk/session.ts +194 -16
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +494 -49
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2437 -400
- package/src/session/fallback-chain-controller.ts +6 -7
- package/src/session/fold-coordinator.ts +24 -5
- package/src/session/internal/managed-session-scope.ts +58 -18
- package/src/session/internal/managed-session-storage.ts +304 -11
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/session-import/codex.ts +12 -3
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/slash-commands/builtin-registry.ts +258 -14
- package/src/task/index.ts +14 -2
- package/src/thinking.ts +21 -2
- package/src/tools/bash.ts +98 -78
- package/src/tools/fetch.ts +119 -20
- package/src/tools/job.ts +151 -25
- package/src/tools/output-meta.ts +15 -2
- package/src/tools/path-utils.ts +27 -3
- package/src/tools/read.ts +3 -3
- package/src/tools/steer-fold.ts +107 -0
- package/src/tools/tool-catalog.generated.ts +29 -2
- package/src/tools/tool-errors.ts +4 -0
- package/src/utils/git.ts +53 -3
- package/src/utils/markit.ts +55 -41
- package/src/utils/mupdf-assets.d.ts +4 -0
- package/src/utils/mupdf-embedded.ts +4 -0
- package/src/utils/mupdf-wasm-embedded.ts +3 -0
- package/src/utils/mupdf-wasm.ts +24 -2
- package/src/utils/mupdf.ts +129 -0
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
- package/src/web/scrapers/types.ts +24 -3
- package/vendor/markit-ai/LICENSE +21 -0
- package/vendor/markit-ai/MANIFEST.json +412 -0
- package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/config.js +139 -0
- package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
- package/vendor/markit-ai/dist/commands/convert.js +113 -0
- package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/formats.js +92 -0
- package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/init.js +29 -0
- package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/onboard.js +61 -0
- package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/plugin.js +58 -0
- package/vendor/markit-ai/dist/config.d.ts +26 -0
- package/vendor/markit-ai/dist/config.js +42 -0
- package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/audio.js +104 -0
- package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/csv.js +83 -0
- package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/docx.js +57 -0
- package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/epub.js +128 -0
- package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
- package/vendor/markit-ai/dist/converters/github.js +148 -0
- package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/html.js +30 -0
- package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/image.js +124 -0
- package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
- package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
- package/vendor/markit-ai/dist/converters/iwork.js +391 -0
- package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/json.js +21 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
- package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
- package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
- package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
- package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
- package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
- package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
- package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/pptx.js +289 -0
- package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
- package/vendor/markit-ai/dist/converters/rss.js +138 -0
- package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
- package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
- package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/xml.js +18 -0
- package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/yaml.js +17 -0
- package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/zip.js +57 -0
- package/vendor/markit-ai/dist/index.d.ts +30 -0
- package/vendor/markit-ai/dist/index.js +26 -0
- package/vendor/markit-ai/dist/main.d.ts +2 -0
- package/vendor/markit-ai/dist/main.js +191 -0
- package/vendor/markit-ai/dist/markit.d.ts +45 -0
- package/vendor/markit-ai/dist/markit.js +267 -0
- package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
- package/vendor/markit-ai/dist/plugins/api.js +42 -0
- package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
- package/vendor/markit-ai/dist/plugins/index.js +3 -0
- package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/installer.js +176 -0
- package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
- package/vendor/markit-ai/dist/plugins/loader.js +61 -0
- package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/types.js +1 -0
- package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
- package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
- package/vendor/markit-ai/dist/providers/index.js +56 -0
- package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/openai.js +76 -0
- package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
- package/vendor/markit-ai/dist/providers/types.js +1 -0
- package/vendor/markit-ai/dist/types.d.ts +36 -0
- package/vendor/markit-ai/dist/types.js +1 -0
- package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
- package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
- package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
- package/vendor/markit-ai/dist/utils/output.js +31 -0
- package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
- package/vendor/markit-ai/dist/utils/turndown.js +70 -0
- package/vendor/markit-ai/package.json +74 -0
- package/vendor/markit-ai.patch +49 -0
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
1
2
|
import { getAgentDir } from "@gajae-code/utils";
|
|
2
3
|
import { CliParseError } from "@gajae-code/utils/cli";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
normalizePublicCommandFailure,
|
|
6
|
+
type PublicCommandDiagnosticCode,
|
|
7
|
+
PublicCommandFailure,
|
|
8
|
+
} from "../../cli/public-command-errors";
|
|
9
|
+
import { normalizeBrokerInput } from "../broker/broker";
|
|
10
|
+
import type { BrokerDiscovery } from "../broker/discovery";
|
|
11
|
+
import { lifecycleRequestTimeoutMs } from "../broker/startup-budget";
|
|
12
|
+
import { readSdkBrokerDiscovery, SdkClient, SdkClientError, SdkDiscoveryError } from "../client";
|
|
4
13
|
import { SessionListTraversalError, sessionListPageFromResponse, traverseSessionList } from "../session-list";
|
|
14
|
+
import type { ServeHandle } from "./index";
|
|
5
15
|
import { DEFAULT_PENDING_CEILING_BYTES, MIN_PENDING_CEILING_BYTES, startSocketServe, startStdioServe } from "./index";
|
|
6
16
|
|
|
7
17
|
type ServeMode = { kind: "stdio" } | { kind: "socket"; socketPath: string };
|
|
@@ -12,13 +22,160 @@ interface ServeArguments {
|
|
|
12
22
|
pendingCeiling?: string;
|
|
13
23
|
}
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Usage failures keep a static, allowlisted reason instead of the parser's raw text:
|
|
27
|
+
* the concrete diagnostic is what makes an unknown flag or a missing operand
|
|
28
|
+
* actionable, and it never echoes caller argv back into output or the evidence store.
|
|
29
|
+
*/
|
|
30
|
+
function usageError(diagnostic: PublicCommandDiagnosticCode): never {
|
|
31
|
+
throw new PublicCommandFailure({ kind: "usage", proof: "pre-effect", diagnostics: [diagnostic] });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A `gjc sdk serve` operational failure with a stable machine-readable code and a
|
|
36
|
+
* documented exit code, mirroring `SdkSessionCliError`. Usage errors keep their own
|
|
37
|
+
* public failure envelope; this type covers only failures an embedder must branch on.
|
|
38
|
+
*/
|
|
39
|
+
export class SdkServeError extends PublicCommandFailure {
|
|
40
|
+
/**
|
|
41
|
+
* Diagnostics for a broker-teardown failure that happened alongside this primary
|
|
42
|
+
* failure. It rides beside `details` rather than inside it because `details`
|
|
43
|
+
* carries the broker's own error payload verbatim and embedders already read it.
|
|
44
|
+
*/
|
|
45
|
+
cleanupError?: { code: string; message: string };
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
readonly code: string,
|
|
49
|
+
message: string,
|
|
50
|
+
readonly exitCode: 1,
|
|
51
|
+
readonly details?: unknown,
|
|
52
|
+
) {
|
|
53
|
+
super(sdkServeFailureInput(code));
|
|
54
|
+
this.name = "SdkServeError";
|
|
55
|
+
this.message = message;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sdkServeFailureInput(code: string): {
|
|
60
|
+
kind:
|
|
61
|
+
| "usage"
|
|
62
|
+
| "invalid_json"
|
|
63
|
+
| "unavailable"
|
|
64
|
+
| "broker_unavailable"
|
|
65
|
+
| "endpoint_stale"
|
|
66
|
+
| "broker_restarting"
|
|
67
|
+
| "authorization_denied"
|
|
68
|
+
| "timeout"
|
|
69
|
+
| "wait_timeout"
|
|
70
|
+
| "uncertain_after_send"
|
|
71
|
+
| "daemon_unhealthy"
|
|
72
|
+
| "daemon_stale"
|
|
73
|
+
| "daemon_mixed"
|
|
74
|
+
| "operation_failed"
|
|
75
|
+
| "internal";
|
|
76
|
+
proof?: "pre-send" | "pre-effect" | "accepted" | "completed" | "sent" | "unknown";
|
|
77
|
+
} {
|
|
78
|
+
switch (code) {
|
|
79
|
+
case "broker_restarting":
|
|
80
|
+
return { kind: "broker_restarting", proof: "pre-effect" };
|
|
81
|
+
case "broker_unavailable":
|
|
82
|
+
case "broker_discovery_unreadable":
|
|
83
|
+
return { kind: "broker_unavailable", proof: "pre-effect" };
|
|
84
|
+
case "endpoint_stale":
|
|
85
|
+
return { kind: "endpoint_stale", proof: "pre-effect" };
|
|
86
|
+
case "authorization_denied":
|
|
87
|
+
case "unauthorized":
|
|
88
|
+
case "forbidden":
|
|
89
|
+
case "master_context_required":
|
|
90
|
+
case "adapter_operation_prohibited":
|
|
91
|
+
case "endpoint_credential_forbidden":
|
|
92
|
+
return { kind: "authorization_denied", proof: "pre-effect" };
|
|
93
|
+
case "timeout":
|
|
94
|
+
return { kind: "timeout", proof: "unknown" };
|
|
95
|
+
case "uncertain_after_send":
|
|
96
|
+
return { kind: "uncertain_after_send", proof: "sent" };
|
|
97
|
+
case "usage":
|
|
98
|
+
case "invalid_input":
|
|
99
|
+
case "invalid_json":
|
|
100
|
+
return { kind: "usage", proof: "pre-effect" };
|
|
101
|
+
case "unavailable":
|
|
102
|
+
case "unsupported_platform":
|
|
103
|
+
case "not_found":
|
|
104
|
+
case "ambiguous_session":
|
|
105
|
+
return { kind: "unavailable", proof: "pre-effect" };
|
|
106
|
+
case "no_live_endpoint":
|
|
107
|
+
return { kind: "endpoint_stale", proof: "pre-effect" };
|
|
108
|
+
case "multiple_live_endpoints":
|
|
109
|
+
return { kind: "usage", proof: "pre-effect" };
|
|
110
|
+
default:
|
|
111
|
+
return { kind: "operation_failed" };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Normalizes a serve-path failure into a typed error so nothing escapes untyped. */
|
|
116
|
+
function toServeError(error: unknown): Error {
|
|
117
|
+
if (error instanceof SdkServeError || error instanceof CliParseError) return error;
|
|
118
|
+
if (error instanceof SdkClientError) return new SdkServeError(error.code, error.message, 1, error.details);
|
|
119
|
+
return new SdkServeError("serve_failed", error instanceof Error ? error.message : "SDK serve failed.", 1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Reads the broker discovery record so an unreadable one — a permission or file-kind
|
|
124
|
+
* failure, or a record from a newer state version — fails as a typed serve error
|
|
125
|
+
* instead of escaping the command boundary untyped. A missing record still reads as
|
|
126
|
+
* `null`, which the caller reports as `broker_unavailable`.
|
|
127
|
+
*/
|
|
128
|
+
async function readServeDiscovery(agentDir: string): Promise<BrokerDiscovery | null> {
|
|
129
|
+
try {
|
|
130
|
+
return await readSdkBrokerDiscovery(agentDir);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// The path is a local file inside the agent dir, already named by this
|
|
133
|
+
// command's other diagnostics; the broker token is never surfaced.
|
|
134
|
+
const details =
|
|
135
|
+
error instanceof SdkDiscoveryError
|
|
136
|
+
? { code: error.code, message: error.message, path: error.path }
|
|
137
|
+
: { code: "discovery_error", message: error instanceof Error ? error.message : String(error) };
|
|
138
|
+
throw new SdkServeError("broker_discovery_unreadable", "SDK broker discovery record is unreadable", 1, details);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Reduces a teardown failure to the code and message an embedder can branch on. */
|
|
143
|
+
function cleanupDiagnostics(error: Error): { code: string; message: string } {
|
|
144
|
+
return { code: error instanceof SdkClientError ? error.code : "serve_cleanup_failed", message: error.message };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Runs broker teardown to completion, handing back its failure instead of throwing it. */
|
|
148
|
+
async function brokerCloseFailure(broker: SdkClient): Promise<Error | undefined> {
|
|
149
|
+
try {
|
|
150
|
+
await broker.close();
|
|
151
|
+
return undefined;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Combines the serve body's failure with the broker-teardown failure. The primary
|
|
159
|
+
* failure always wins — a rejected teardown only ever rides along as diagnostics, it
|
|
160
|
+
* never replaces the error an embedder branches on — and a teardown that fails on its
|
|
161
|
+
* own still leaves typed. Exported for tests.
|
|
162
|
+
*/
|
|
163
|
+
export function resolveServeOutcome(primary: Error | undefined, cleanup: Error | undefined): Error | undefined {
|
|
164
|
+
if (primary) {
|
|
165
|
+
if (cleanup && primary instanceof SdkServeError) {
|
|
166
|
+
primary.cleanupError = cleanupDiagnostics(cleanup);
|
|
167
|
+
primary.input.diagnostics = [...(primary.input.diagnostics ?? []), "broker_cleanup_failed"];
|
|
168
|
+
}
|
|
169
|
+
return primary;
|
|
170
|
+
}
|
|
171
|
+
if (!cleanup) return undefined;
|
|
172
|
+
const diagnostics = cleanupDiagnostics(cleanup);
|
|
173
|
+
return new SdkServeError("serve_cleanup_failed", `SDK broker cleanup failed: ${cleanup.message}`, 1, diagnostics);
|
|
17
174
|
}
|
|
18
175
|
|
|
19
|
-
function readFlagValue(argv: string[], index: number
|
|
176
|
+
function readFlagValue(argv: string[], index: number): string {
|
|
20
177
|
const value = argv[index + 1];
|
|
21
|
-
if (value === undefined || value.startsWith("-")) usageError(
|
|
178
|
+
if (value === undefined || value.startsWith("-")) usageError("usage_missing_value");
|
|
22
179
|
return value;
|
|
23
180
|
}
|
|
24
181
|
|
|
@@ -30,29 +187,29 @@ function parseServeArguments(argv: string[]): ServeArguments {
|
|
|
30
187
|
for (let index = 0; index < argv.length; index++) {
|
|
31
188
|
switch (argv[index]) {
|
|
32
189
|
case "--stdio":
|
|
33
|
-
if (stdio) usageError("
|
|
190
|
+
if (stdio) usageError("usage_duplicate_option");
|
|
34
191
|
stdio = true;
|
|
35
192
|
break;
|
|
36
193
|
case "--socket":
|
|
37
|
-
if (socketPath !== undefined) usageError("
|
|
38
|
-
socketPath = readFlagValue(argv, index
|
|
194
|
+
if (socketPath !== undefined) usageError("usage_duplicate_option");
|
|
195
|
+
socketPath = readFlagValue(argv, index);
|
|
39
196
|
index++;
|
|
40
197
|
break;
|
|
41
198
|
case "--session":
|
|
42
|
-
if (sessionId !== undefined) usageError("
|
|
43
|
-
sessionId = readFlagValue(argv, index
|
|
199
|
+
if (sessionId !== undefined) usageError("usage_duplicate_option");
|
|
200
|
+
sessionId = readFlagValue(argv, index);
|
|
44
201
|
index++;
|
|
45
202
|
break;
|
|
46
203
|
case "--pending-ceiling":
|
|
47
|
-
if (pendingCeiling !== undefined) usageError("
|
|
48
|
-
pendingCeiling = readFlagValue(argv, index
|
|
204
|
+
if (pendingCeiling !== undefined) usageError("usage_duplicate_option");
|
|
205
|
+
pendingCeiling = readFlagValue(argv, index);
|
|
49
206
|
index++;
|
|
50
207
|
break;
|
|
51
208
|
default:
|
|
52
|
-
usageError(
|
|
209
|
+
usageError("usage_unknown_argument");
|
|
53
210
|
}
|
|
54
211
|
}
|
|
55
|
-
if (stdio === (socketPath !== undefined)) usageError("
|
|
212
|
+
if (stdio === (socketPath !== undefined)) usageError("usage_transport_exclusive");
|
|
56
213
|
return { mode: stdio ? { kind: "stdio" } : { kind: "socket", socketPath: socketPath! }, sessionId, pendingCeiling };
|
|
57
214
|
}
|
|
58
215
|
|
|
@@ -60,14 +217,32 @@ function parseServeArguments(argv: string[]): ServeArguments {
|
|
|
60
217
|
export function resolveServePendingCeiling(flagValue: string | undefined, envValue: string | undefined): number {
|
|
61
218
|
const value = flagValue ?? envValue;
|
|
62
219
|
if (value === undefined) return DEFAULT_PENDING_CEILING_BYTES;
|
|
63
|
-
if (!/^\d+$/.test(value)) usageError("
|
|
220
|
+
if (!/^\d+$/.test(value)) usageError("usage_invalid_option_value");
|
|
64
221
|
const ceiling = Number(value);
|
|
65
|
-
if (!Number.isSafeInteger(ceiling) || ceiling < MIN_PENDING_CEILING_BYTES)
|
|
66
|
-
usageError(`--pending-ceiling must be an integer of at least ${MIN_PENDING_CEILING_BYTES}`);
|
|
222
|
+
if (!Number.isSafeInteger(ceiling) || ceiling < MIN_PENDING_CEILING_BYTES) usageError("usage_invalid_option_value");
|
|
67
223
|
return ceiling;
|
|
68
224
|
}
|
|
69
225
|
|
|
70
|
-
type
|
|
226
|
+
type BrokerTranscriptIdentity = {
|
|
227
|
+
dev: string;
|
|
228
|
+
ino: string;
|
|
229
|
+
size: number;
|
|
230
|
+
mtimeMs: number;
|
|
231
|
+
mtimeNs: string;
|
|
232
|
+
sha256: string;
|
|
233
|
+
};
|
|
234
|
+
type BrokerSavedSession = { id: string; path: string; identity: BrokerTranscriptIdentity };
|
|
235
|
+
type BrokerSessionLocator = { cwd: string; worktreeRoot: string | null; stateRoot: string };
|
|
236
|
+
type BrokerSessionRow = {
|
|
237
|
+
sessionId: string;
|
|
238
|
+
live: boolean;
|
|
239
|
+
ambiguous: boolean;
|
|
240
|
+
terminal?: boolean;
|
|
241
|
+
hostUnregisteredReason?: "process_exited" | "detached_idle";
|
|
242
|
+
terminalUncertain?: boolean;
|
|
243
|
+
locator?: BrokerSessionLocator;
|
|
244
|
+
savedSession?: BrokerSavedSession;
|
|
245
|
+
};
|
|
71
246
|
|
|
72
247
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
73
248
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -84,93 +259,363 @@ function brokerResult(value: unknown): Record<string, unknown> {
|
|
|
84
259
|
return isRecord(value) && isRecord(value.result) ? value.result : {};
|
|
85
260
|
}
|
|
86
261
|
|
|
87
|
-
function
|
|
262
|
+
function brokerSessionLocator(value: unknown): BrokerSessionLocator | undefined {
|
|
263
|
+
if (!isRecord(value)) return undefined;
|
|
264
|
+
const { cwd, worktreeRoot, stateRoot } = value;
|
|
265
|
+
return typeof cwd === "string" &&
|
|
266
|
+
cwd.length > 0 &&
|
|
267
|
+
(worktreeRoot === null || typeof worktreeRoot === "string") &&
|
|
268
|
+
typeof stateRoot === "string" &&
|
|
269
|
+
stateRoot.length > 0
|
|
270
|
+
? { cwd, worktreeRoot, stateRoot }
|
|
271
|
+
: undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function brokerSavedSession(value: unknown): BrokerSavedSession | undefined {
|
|
275
|
+
if (!isRecord(value) || typeof value.id !== "string" || !value.id || typeof value.path !== "string" || !value.path)
|
|
276
|
+
return undefined;
|
|
277
|
+
if (!isRecord(value.identity)) return undefined;
|
|
278
|
+
const { dev, ino, size, mtimeMs, mtimeNs, sha256 } = value.identity;
|
|
279
|
+
if (
|
|
280
|
+
typeof dev !== "string" ||
|
|
281
|
+
!/^[0-9]+$/.test(dev) ||
|
|
282
|
+
typeof ino !== "string" ||
|
|
283
|
+
!/^[0-9]+$/.test(ino) ||
|
|
284
|
+
typeof size !== "number" ||
|
|
285
|
+
!Number.isSafeInteger(size) ||
|
|
286
|
+
size < 0 ||
|
|
287
|
+
typeof mtimeMs !== "number" ||
|
|
288
|
+
!Number.isFinite(mtimeMs) ||
|
|
289
|
+
mtimeMs < 0 ||
|
|
290
|
+
typeof mtimeNs !== "string" ||
|
|
291
|
+
!/^[0-9]+$/.test(mtimeNs) ||
|
|
292
|
+
typeof sha256 !== "string" ||
|
|
293
|
+
!/^[a-f0-9]{64}$/.test(sha256)
|
|
294
|
+
)
|
|
295
|
+
return undefined;
|
|
296
|
+
return { id: value.id, path: value.path, identity: { dev, ino, size, mtimeMs, mtimeNs, sha256 } };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function brokerSessionRows(sessions: readonly unknown[], savedSession?: unknown): BrokerSessionRow[] {
|
|
300
|
+
const pageSavedSession = brokerSavedSession(savedSession);
|
|
88
301
|
return sessions.flatMap(item => {
|
|
89
302
|
if (!isRecord(item) || typeof item.sessionId !== "string" || !item.sessionId) return [];
|
|
90
|
-
|
|
303
|
+
const locator = brokerSessionLocator(item.locator);
|
|
304
|
+
const saved = pageSavedSession?.id === item.sessionId ? pageSavedSession : brokerSavedSession(item.savedSession);
|
|
305
|
+
const hostUnregisteredReason =
|
|
306
|
+
item.hostUnregisteredReason === "process_exited" || item.hostUnregisteredReason === "detached_idle"
|
|
307
|
+
? item.hostUnregisteredReason
|
|
308
|
+
: undefined;
|
|
309
|
+
const terminalUncertain = item.terminalUncertain === true || item.terminal_uncertain === true;
|
|
310
|
+
return [
|
|
311
|
+
{
|
|
312
|
+
sessionId: item.sessionId,
|
|
313
|
+
live: item.live === true,
|
|
314
|
+
ambiguous: item.ambiguous === true,
|
|
315
|
+
...(item.terminal === true ? { terminal: true } : {}),
|
|
316
|
+
...(hostUnregisteredReason === undefined ? {} : { hostUnregisteredReason }),
|
|
317
|
+
...(terminalUncertain ? { terminalUncertain: true } : {}),
|
|
318
|
+
...(locator === undefined ? {} : { locator }),
|
|
319
|
+
...(saved === undefined ? {} : { savedSession: saved }),
|
|
320
|
+
},
|
|
321
|
+
];
|
|
91
322
|
});
|
|
92
323
|
}
|
|
93
324
|
|
|
94
325
|
/** Exhausts strict broker `session.list` pages into one full session snapshot. */
|
|
95
|
-
export async function listBrokerSessions(
|
|
326
|
+
export async function listBrokerSessions(
|
|
327
|
+
broker: Pick<SdkClient, "global">,
|
|
328
|
+
explicitSessionId?: string,
|
|
329
|
+
cwd?: string,
|
|
330
|
+
): Promise<BrokerSessionRow[]> {
|
|
96
331
|
try {
|
|
97
332
|
const pages = await traverseSessionList(
|
|
98
|
-
{
|
|
333
|
+
{
|
|
334
|
+
...(explicitSessionId ? { resolveSessionId: explicitSessionId } : {}),
|
|
335
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
336
|
+
},
|
|
99
337
|
async input => await broker.global("session.list", input),
|
|
100
338
|
response => {
|
|
101
339
|
brokerResult(response);
|
|
102
340
|
return sessionListPageFromResponse(response);
|
|
103
341
|
},
|
|
104
342
|
);
|
|
105
|
-
return pages.flatMap(page =>
|
|
343
|
+
return pages.flatMap(page =>
|
|
344
|
+
brokerSessionRows(page.sessions, isRecord(page.page) ? page.page.savedSession : undefined),
|
|
345
|
+
);
|
|
106
346
|
} catch (error) {
|
|
107
347
|
if (error instanceof SessionListTraversalError) throw new SdkClientError("protocol_error", error.message);
|
|
108
348
|
throw error;
|
|
109
349
|
}
|
|
110
350
|
}
|
|
111
351
|
|
|
352
|
+
function endpointStaleError(sessionId: string): Error {
|
|
353
|
+
// A typed error, because `toServeError` only passes `SdkServeError` through: a plain
|
|
354
|
+
// Error here is rewritten to `serve_failed`, which hides the one code that tells a
|
|
355
|
+
// caller recovery was attempted and the endpoint is still not live.
|
|
356
|
+
return new SdkServeError("endpoint_stale", `session ${sessionId} endpoint is not live`, 1);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function recoverBrokerSession(broker: SdkClient, row: BrokerSessionRow, sessionId: string): Promise<void> {
|
|
360
|
+
const locator = row.locator;
|
|
361
|
+
const authority =
|
|
362
|
+
row.savedSession?.id === sessionId
|
|
363
|
+
? row.savedSession
|
|
364
|
+
: locator === undefined
|
|
365
|
+
? undefined
|
|
366
|
+
: (await listBrokerSessions(broker, sessionId, locator.cwd)).find(
|
|
367
|
+
candidate => candidate.sessionId === sessionId,
|
|
368
|
+
)?.savedSession;
|
|
369
|
+
if (locator === undefined || authority?.id !== sessionId) throw endpointStaleError(sessionId);
|
|
370
|
+
const normalized = normalizeBrokerInput("session.resume", { sessionId, cwd: locator.cwd });
|
|
371
|
+
if (!("input" in normalized)) {
|
|
372
|
+
brokerResult(normalized);
|
|
373
|
+
throw endpointStaleError(sessionId);
|
|
374
|
+
}
|
|
375
|
+
const input = {
|
|
376
|
+
...normalized.input,
|
|
377
|
+
sessionPath: authority.path,
|
|
378
|
+
sessionIdentity: authority.identity,
|
|
379
|
+
};
|
|
380
|
+
const timeoutMs = lifecycleRequestTimeoutMs("session.resume", input);
|
|
381
|
+
brokerResult(
|
|
382
|
+
await broker.global("session.resume", input, {
|
|
383
|
+
idempotencyKey: crypto.randomUUID(),
|
|
384
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
385
|
+
}),
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Resolves an explicit or automatic serve target, reattaching one stale explicit session at most once. */
|
|
390
|
+
export async function resolveServeSession(broker: SdkClient, explicitSessionId?: string): Promise<string> {
|
|
391
|
+
const sessions = await listBrokerSessions(broker, explicitSessionId);
|
|
392
|
+
if (explicitSessionId !== undefined) {
|
|
393
|
+
const row = sessions.find(session => session.sessionId === explicitSessionId);
|
|
394
|
+
// An indexed, unambiguous row that is not live is the recoverable
|
|
395
|
+
// self-reap case (#5633). Every other targeting outcome — unindexed,
|
|
396
|
+
// ambiguous, no explicit id — stays the selector's to report, so this
|
|
397
|
+
// decision does not depend on the selector's error text.
|
|
398
|
+
// Recovery requires durable retirement provenance. A non-live row without a terminal
|
|
399
|
+
// retirement event may only have stale heartbeat evidence, which does not prove that the
|
|
400
|
+
// previous host exited and must not authorize a second host for the same transcript.
|
|
401
|
+
if (
|
|
402
|
+
row !== undefined &&
|
|
403
|
+
!row.ambiguous &&
|
|
404
|
+
!row.terminalUncertain &&
|
|
405
|
+
!row.live &&
|
|
406
|
+
row.terminal === true &&
|
|
407
|
+
(row.hostUnregisteredReason === "process_exited" || row.hostUnregisteredReason === "detached_idle")
|
|
408
|
+
) {
|
|
409
|
+
await recoverBrokerSession(broker, row, explicitSessionId);
|
|
410
|
+
return selectBrokerSession(await listBrokerSessions(broker, explicitSessionId), explicitSessionId);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return selectBrokerSession(sessions, explicitSessionId);
|
|
414
|
+
}
|
|
415
|
+
|
|
112
416
|
/** Selects the session to serve through broker `session.list` truth (C10); exported for tests. */
|
|
113
417
|
export function selectBrokerSession(sessions: BrokerSessionRow[], explicitSessionId: string | undefined): string {
|
|
114
418
|
if (explicitSessionId !== undefined) {
|
|
115
419
|
const row = sessions.find(session => session.sessionId === explicitSessionId);
|
|
116
|
-
if (!row) throw new
|
|
117
|
-
if (row.ambiguous) throw new
|
|
118
|
-
if (
|
|
420
|
+
if (!row) throw new SdkServeError("not_found", `session ${explicitSessionId} is not indexed by the broker`, 1);
|
|
421
|
+
if (row.ambiguous) throw new SdkServeError("ambiguous_session", "session id maps to more than one state root", 1);
|
|
422
|
+
if (row.terminalUncertain)
|
|
423
|
+
throw new SdkServeError("terminal_uncertain", `session ${explicitSessionId} ownership is uncertain`, 1);
|
|
424
|
+
if (!row.live) throw new SdkServeError("endpoint_stale", `session ${explicitSessionId} endpoint is not live`, 1);
|
|
119
425
|
return row.sessionId;
|
|
120
426
|
}
|
|
121
|
-
const live = sessions.filter(session => session.live && !session.ambiguous);
|
|
122
|
-
if (live.length === 0) throw new
|
|
123
|
-
if (live.length > 1)
|
|
427
|
+
const live = sessions.filter(session => session.live && !session.ambiguous && !session.terminalUncertain);
|
|
428
|
+
if (live.length === 0) throw new SdkServeError("no_live_endpoint", "no live session endpoint", 1);
|
|
429
|
+
if (live.length > 1)
|
|
430
|
+
throw new SdkServeError("multiple_live_endpoints", "more than one live session; specify --session <id>", 1);
|
|
124
431
|
return live[0]!.sessionId;
|
|
125
432
|
}
|
|
126
433
|
|
|
434
|
+
/** Only SDK-owned error codes carry classification authority at preflight. */
|
|
435
|
+
function servePreflightFailure(error: unknown): PublicCommandFailure {
|
|
436
|
+
if (!(error instanceof SdkClientError)) return normalizePublicCommandFailure(error);
|
|
437
|
+
switch (error.code) {
|
|
438
|
+
case "broker_restarting":
|
|
439
|
+
return new PublicCommandFailure({ kind: "broker_restarting", proof: "pre-effect" });
|
|
440
|
+
case "broker_unavailable":
|
|
441
|
+
return new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
|
|
442
|
+
case "endpoint_stale":
|
|
443
|
+
return new PublicCommandFailure({ kind: "endpoint_stale", proof: "pre-effect" });
|
|
444
|
+
case "authorization_denied":
|
|
445
|
+
case "unauthorized":
|
|
446
|
+
case "forbidden":
|
|
447
|
+
case "master_context_required":
|
|
448
|
+
case "adapter_operation_prohibited":
|
|
449
|
+
case "endpoint_credential_forbidden":
|
|
450
|
+
return new PublicCommandFailure({ kind: "authorization_denied", proof: "pre-effect" });
|
|
451
|
+
case "timeout":
|
|
452
|
+
return new PublicCommandFailure({ kind: "timeout", proof: "unknown" });
|
|
453
|
+
case "unavailable":
|
|
454
|
+
return new PublicCommandFailure({ kind: "unavailable", proof: "unknown" });
|
|
455
|
+
case "uncertain_after_send":
|
|
456
|
+
return new PublicCommandFailure({ kind: "uncertain_after_send", proof: "sent" });
|
|
457
|
+
default:
|
|
458
|
+
return normalizePublicCommandFailure(error);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Bounded dependency seam for preflight tests; production keeps the same transport factories. */
|
|
463
|
+
export interface SdkServeDependencies {
|
|
464
|
+
readDiscovery: (agentDir: string) => Promise<{ url: string; token: string } | null>;
|
|
465
|
+
connect: (url: string, token: string) => Promise<Pick<SdkClient, "global" | "close">>;
|
|
466
|
+
startStdio: typeof startStdioServe;
|
|
467
|
+
startSocket: typeof startSocketServe;
|
|
468
|
+
}
|
|
469
|
+
|
|
127
470
|
/**
|
|
128
471
|
* Attaches a stdio or Unix-socket relay to one live SDK session endpoint.
|
|
129
472
|
* Session targeting is broker-bound (C10): `session.list` resolves the session
|
|
130
473
|
* and `session.get_endpoint` mints the exact credential — never a direct
|
|
131
474
|
* endpoint-file read. A missing or unreachable broker fails closed.
|
|
132
475
|
*/
|
|
133
|
-
export async function runSdkServe(argv: string[]): Promise<void> {
|
|
476
|
+
export async function runSdkServe(argv: string[], dependencies?: SdkServeDependencies): Promise<void> {
|
|
477
|
+
if (dependencies !== undefined) {
|
|
478
|
+
await runSdkServePublic(argv, dependencies);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
await runSdkServeTyped(argv);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Public-boundary adapter used by dependency-injected preflight tests and the CLI scanner. */
|
|
485
|
+
async function runSdkServePublic(argv: string[], dependencies: SdkServeDependencies): Promise<void> {
|
|
486
|
+
let broker: Pick<SdkClient, "global" | "close"> | undefined;
|
|
487
|
+
let transport: ServeHandle | undefined;
|
|
488
|
+
try {
|
|
489
|
+
const parsed = parseServeArguments(argv);
|
|
490
|
+
if (parsed.mode.kind === "socket" && process.platform === "win32")
|
|
491
|
+
throw new PublicCommandFailure({ kind: "unavailable", proof: "pre-effect" });
|
|
492
|
+
const pendingCeilingBytes = resolveServePendingCeiling(
|
|
493
|
+
parsed.pendingCeiling,
|
|
494
|
+
process.env.GJC_SDK_SERVE_PENDING_CEILING_BYTES,
|
|
495
|
+
);
|
|
496
|
+
const discovery = await dependencies.readDiscovery(getAgentDir());
|
|
497
|
+
if (!discovery) throw new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
|
|
498
|
+
try {
|
|
499
|
+
broker = await dependencies.connect(discovery.url, discovery.token);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
if (error instanceof SdkClientError || error instanceof PublicCommandFailure) throw error;
|
|
502
|
+
throw new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
|
|
503
|
+
}
|
|
504
|
+
const sessionId = selectBrokerSession(await listBrokerSessions(broker, parsed.sessionId), parsed.sessionId);
|
|
505
|
+
const endpoint = brokerResult(await broker.global("session.get_endpoint", { sessionId }));
|
|
506
|
+
const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
|
|
507
|
+
const token = typeof endpoint.token === "string" ? endpoint.token : "";
|
|
508
|
+
// An endpoint without its minted credential cannot authenticate any relayed
|
|
509
|
+
// client, so starting the listener would advertise a serve that always fails.
|
|
510
|
+
if (!url || !token) throw new PublicCommandFailure({ kind: "unavailable", proof: "pre-effect" });
|
|
511
|
+
const options = { url, token, pendingCeilingBytes };
|
|
512
|
+
transport =
|
|
513
|
+
parsed.mode.kind === "stdio"
|
|
514
|
+
? await dependencies.startStdio(options)
|
|
515
|
+
: await dependencies.startSocket({ ...options, socketPath: parsed.mode.socketPath });
|
|
516
|
+
} catch (error) {
|
|
517
|
+
// No transport handle has transferred ownership. Cleanup diagnostics are
|
|
518
|
+
// attached to the original failure instance, never substituted for it, and
|
|
519
|
+
// broker credentials never reach a raw error.
|
|
520
|
+
const failure = servePreflightFailure(error);
|
|
521
|
+
try {
|
|
522
|
+
await broker?.close();
|
|
523
|
+
} catch {
|
|
524
|
+
failure.input.diagnostics = [...(failure.input.diagnostics ?? []), "broker_cleanup_failed"];
|
|
525
|
+
}
|
|
526
|
+
throw failure;
|
|
527
|
+
}
|
|
528
|
+
await ownSdkServeTransport(transport!, () => broker!.close());
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/** Native serve path: operational failures remain typed for direct SDK embedders. */
|
|
532
|
+
async function runSdkServeTyped(argv: string[]): Promise<void> {
|
|
134
533
|
const parsed = parseServeArguments(argv);
|
|
135
534
|
if (parsed.mode.kind === "socket" && process.platform === "win32")
|
|
136
|
-
throw new
|
|
535
|
+
throw new SdkServeError("unsupported_platform", "--socket is unavailable on Windows.", 1);
|
|
137
536
|
const pendingCeilingBytes = resolveServePendingCeiling(
|
|
138
537
|
parsed.pendingCeiling,
|
|
139
538
|
process.env.GJC_SDK_SERVE_PENDING_CEILING_BYTES,
|
|
140
539
|
);
|
|
141
|
-
const discovery = await
|
|
142
|
-
if (!discovery) throw new
|
|
540
|
+
const discovery = await readServeDiscovery(getAgentDir());
|
|
541
|
+
if (!discovery) throw new SdkServeError("broker_unavailable", "SDK broker is not running", 1);
|
|
143
542
|
let broker: SdkClient;
|
|
144
543
|
try {
|
|
145
544
|
broker = await SdkClient.connect(discovery.url, discovery.token);
|
|
146
545
|
} catch {
|
|
147
|
-
throw new
|
|
546
|
+
throw new SdkServeError("broker_unavailable", "SDK broker is not reachable", 1);
|
|
148
547
|
}
|
|
548
|
+
let primary: Error | undefined;
|
|
549
|
+
let transport: ServeHandle | undefined;
|
|
149
550
|
try {
|
|
150
|
-
const sessionId =
|
|
551
|
+
const sessionId = await resolveServeSession(broker, parsed.sessionId);
|
|
151
552
|
const endpoint = brokerResult(await broker.global("session.get_endpoint", { sessionId }));
|
|
152
553
|
const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
|
|
153
|
-
const token = typeof endpoint.token === "string" ? endpoint.token :
|
|
154
|
-
|
|
554
|
+
const token = typeof endpoint.token === "string" && endpoint.token ? endpoint.token : undefined;
|
|
555
|
+
// An empty credential has to die here rather than at the transport: the relay
|
|
556
|
+
// writes it straight into the upstream URL, where it resurfaces as a generic
|
|
557
|
+
// connection failure and this stable malformed-endpoint code is lost.
|
|
558
|
+
if (!url || !token) throw new SdkServeError("unavailable", "broker returned an invalid endpoint record", 1);
|
|
155
559
|
const options = { url, token, pendingCeilingBytes };
|
|
156
|
-
|
|
560
|
+
transport =
|
|
157
561
|
parsed.mode.kind === "stdio"
|
|
158
562
|
? await startStdioServe(options)
|
|
159
563
|
: await startSocketServe({ ...options, socketPath: parsed.mode.socketPath });
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
564
|
+
} catch (error) {
|
|
565
|
+
primary = toServeError(error);
|
|
566
|
+
}
|
|
567
|
+
if (transport) {
|
|
568
|
+
// Once the relay owns stdout, post-start failures must never cross back into
|
|
569
|
+
// the public command renderer. That boundary writes JSON to stdout, which is
|
|
570
|
+
// the stdio frame channel; the transport owner reports only a fixed stderr
|
|
571
|
+
// diagnostic and exit status instead.
|
|
572
|
+
await ownSdkServeTransport(transport, () => broker.close());
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
// Teardown always runs, but never through a `finally` throw: a rejected
|
|
576
|
+
// broker.close() there would replace the typed failure with its own.
|
|
577
|
+
const failure = resolveServeOutcome(primary, await brokerCloseFailure(broker));
|
|
578
|
+
if (failure) throw failure;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Acquiring a ServeHandle transfers output/termination ownership to transport.
|
|
583
|
+
* This boundary never rejects into the ordinary public command writer, even
|
|
584
|
+
* when no frame has been written. Raw relay framing remains transport-owned.
|
|
585
|
+
*/
|
|
586
|
+
export async function ownSdkServeTransport(handle: ServeHandle, closeBroker: () => Promise<void>): Promise<void> {
|
|
587
|
+
let failed = false;
|
|
588
|
+
const reportFailure = (): void => {
|
|
589
|
+
process.exitCode = 1;
|
|
590
|
+
if (failed) return;
|
|
591
|
+
failed = true;
|
|
592
|
+
try {
|
|
593
|
+
process.stderr.write(`${JSON.stringify({ type: "transport_error", code: "serve_failed" })}\n`);
|
|
594
|
+
} catch {
|
|
595
|
+
// A broken diagnostic stream cannot transfer ownership back to the CLI.
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
const stop = (): void => {
|
|
599
|
+
void handle.close().catch(reportFailure);
|
|
600
|
+
};
|
|
601
|
+
try {
|
|
163
602
|
process.once("SIGINT", stop);
|
|
164
603
|
process.once("SIGTERM", stop);
|
|
604
|
+
await handle.done;
|
|
605
|
+
} catch {
|
|
606
|
+
reportFailure();
|
|
607
|
+
} finally {
|
|
608
|
+
process.removeListener("SIGINT", stop);
|
|
609
|
+
process.removeListener("SIGTERM", stop);
|
|
165
610
|
try {
|
|
166
|
-
await handle.
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
611
|
+
await handle.close();
|
|
612
|
+
} catch {
|
|
613
|
+
reportFailure();
|
|
614
|
+
}
|
|
615
|
+
try {
|
|
616
|
+
await closeBroker();
|
|
617
|
+
} catch {
|
|
618
|
+
reportFailure();
|
|
170
619
|
}
|
|
171
|
-
} catch (error) {
|
|
172
|
-
throw error instanceof SdkClientError ? new Error(`${error.code}: ${error.message}`) : error;
|
|
173
|
-
} finally {
|
|
174
|
-
await broker.close();
|
|
175
620
|
}
|
|
176
621
|
}
|