@gajae-code/coding-agent 0.17.2 → 0.17.5
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 +267 -0
- 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 +1049 -3
- package/dist/types/config/file-lock.d.ts +13 -3
- package/dist/types/config/model-profile-activation.d.ts +45 -1
- package/dist/types/config/model-registry.d.ts +14 -3
- package/dist/types/config/model-resolver.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/exec/bash-executor.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/gjc-plugins/runtime-adapters.d.ts +11 -2
- 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/gjc-runtime/state-writer.d.ts +14 -1
- package/dist/types/harness-control-plane/control-endpoint.d.ts +4 -1
- package/dist/types/harness-control-plane/finalize.d.ts +14 -3
- 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 +23 -1
- package/dist/types/modes/acp/acp-agent.d.ts +55 -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/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/loader.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +69 -6
- 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/broker/broker.d.ts +17 -4
- package/dist/types/sdk/broker/ensure.d.ts +3 -0
- package/dist/types/sdk/broker/identity.d.ts +5 -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/managed-task-dag.d.ts +1335 -0
- package/dist/types/sdk/broker/managed-task-verification.d.ts +37 -0
- 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 +12 -0
- package/dist/types/sdk/broker/startup-failure.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 +7 -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 +85 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +37 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session.d.ts +3 -3
- 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 +48 -4
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +175 -23
- 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/task/types.d.ts +2 -0
- package/dist/types/tools/bash-interactive.d.ts +1 -0
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/fetch.d.ts +10 -1
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/tools/subagent.d.ts +8 -1
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-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 +22 -1
- 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 +541 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +10 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli/stats-cli.ts +11 -1
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +175 -117
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +543 -3
- package/src/config/file-lock.ts +206 -65
- package/src/config/model-discovery-manager.ts +4 -4
- package/src/config/model-profile-activation.ts +417 -66
- package/src/config/model-registry.ts +254 -36
- package/src/config/model-resolver.ts +6 -1
- 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 +179 -9
- package/src/coordinator-mcp/server.ts +521 -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/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/exec/bash-executor.ts +3 -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/gjc-plugins/runtime-adapters.ts +46 -8
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/state-writer.ts +317 -6
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/harness-control-plane/control-endpoint.ts +24 -6
- package/src/harness-control-plane/finalize.ts +312 -25
- package/src/harness-control-plane/owner.ts +323 -89
- package/src/internal-urls/docs-index.generated.ts +23 -20
- 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 +192 -74
- package/src/modes/acp/acp-agent.ts +973 -56
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/gjc-bundle-settings.ts +21 -1
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/tool-status-header.ts +72 -6
- 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/runtime-mcp-command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +161 -15
- 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/loader.ts +6 -3
- package/src/runtime-mcp/manager.ts +845 -109
- 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 +27 -8
- package/src/sdk/broker/broker.ts +1431 -198
- package/src/sdk/broker/ensure.ts +21 -3
- package/src/sdk/broker/identity.ts +22 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/managed-task-dag.ts +1927 -0
- package/src/sdk/broker/managed-task-verification.ts +642 -0
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +175 -14
- package/src/sdk/broker/startup-failure.ts +80 -1
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/broker/transport.ts +1 -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 +707 -81
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +7 -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 +705 -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 +184 -2
- package/src/sdk/host/session-runtime.ts +322 -101
- 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/lifecycle/service.ts +2 -0
- package/src/sdk/prompt-deadline-flush.ts +356 -0
- package/src/sdk/prompt-deadline-manager.ts +133 -1
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/session-router.ts +9 -1
- package/src/sdk/session.ts +763 -116
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +397 -42
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2472 -407
- 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 +68 -18
- package/src/session/internal/managed-session-storage.ts +334 -12
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/setup/provider-presets.json +2 -1
- package/src/slash-commands/builtin-registry.ts +259 -15
- package/src/task/executor.ts +46 -17
- package/src/task/index.ts +14 -2
- package/src/task/types.ts +2 -0
- package/src/tools/bash-interactive.ts +2 -0
- package/src/tools/bash.ts +118 -78
- package/src/tools/fetch.ts +140 -25
- 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/subagent-render.ts +24 -1
- package/src/tools/subagent.ts +27 -1
- 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.ts +136 -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,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import type
|
|
2
|
+
import { constants as fsConstants, type Stats } from "node:fs";
|
|
3
|
+
import type { FileHandle } from "node:fs/promises";
|
|
3
4
|
import * as fs from "node:fs/promises";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
import { type FileLockOptions, withFileLock } from "../config/file-lock";
|
|
@@ -114,6 +115,12 @@ export function guardedStateWriteReceipt(result: GuardedWriteResult): GuardedSta
|
|
|
114
115
|
|
|
115
116
|
export interface StateWriterOptions {
|
|
116
117
|
cwd?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Linux-only private durable source publication. The supplied directory is
|
|
120
|
+
* the exact private subtree containing the target; existing paths are never
|
|
121
|
+
* chmodded or repaired.
|
|
122
|
+
*/
|
|
123
|
+
privateDurable?: { directory: string };
|
|
117
124
|
receipt?: StateWriterReceiptContext;
|
|
118
125
|
audit?: StateWriterAuditContext;
|
|
119
126
|
sourceRevision?: number;
|
|
@@ -149,6 +156,16 @@ export interface DeleteIfOwnedOptions extends StateWriterOptions {
|
|
|
149
156
|
predicate?: (current: unknown) => boolean | Promise<boolean>;
|
|
150
157
|
}
|
|
151
158
|
|
|
159
|
+
export class StatePublicationUncertainError extends Error {
|
|
160
|
+
constructor(
|
|
161
|
+
public readonly path: string,
|
|
162
|
+
public readonly cause: unknown,
|
|
163
|
+
) {
|
|
164
|
+
super(`state publication requires authoritative reload: ${path}`);
|
|
165
|
+
this.name = "StatePublicationUncertainError";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
152
169
|
export interface DeleteResult {
|
|
153
170
|
path: string;
|
|
154
171
|
deleted: boolean;
|
|
@@ -528,13 +545,293 @@ async function atomicWrite(filePath: string, content: string): Promise<string> {
|
|
|
528
545
|
return filePath;
|
|
529
546
|
}
|
|
530
547
|
|
|
548
|
+
function currentUid(): number {
|
|
549
|
+
const uid = process.getuid?.();
|
|
550
|
+
if (uid === undefined) throw new Error("private durable publication requires a POSIX uid");
|
|
551
|
+
return uid;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
interface PrivatePublicationDirectory {
|
|
555
|
+
handle: FileHandle;
|
|
556
|
+
parent?: PrivatePublicationDirectory;
|
|
557
|
+
name?: string;
|
|
558
|
+
dev: number;
|
|
559
|
+
ino: number;
|
|
560
|
+
privateSubtree: boolean;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
interface PrivatePublicationContext {
|
|
564
|
+
root: string;
|
|
565
|
+
directories: PrivatePublicationDirectory[];
|
|
566
|
+
targetParent: PrivatePublicationDirectory;
|
|
567
|
+
anchoredTarget: string;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function assertSafePublicationDirectory(stat: Stats, directory: string, privateSubtree: boolean): void {
|
|
571
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("unsafe publication directory");
|
|
572
|
+
if ((stat.mode & 0o022) !== 0 || stat.uid !== currentUid()) {
|
|
573
|
+
const mode = (stat.mode & 0o777).toString(8);
|
|
574
|
+
throw new Error(
|
|
575
|
+
`publication parent is not exclusively owned (uid=${stat.uid}, mode=${mode}, directory=${path.basename(directory)})`,
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
if (privateSubtree && (stat.mode & 0o777) !== 0o700)
|
|
579
|
+
throw new Error("private publication directory is not owned mode 0700");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function procPath(handle: FileHandle): string {
|
|
583
|
+
return `/proc/self/fd/${handle.fd}`;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function directoryPath(directory: PrivatePublicationDirectory): string {
|
|
587
|
+
return procPath(directory.handle);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const LINUX_O_PATH = 0o10000000;
|
|
591
|
+
|
|
592
|
+
async function readPrivateExistingStateForMutation(filePath: string): Promise<StrictMutationReadResult> {
|
|
593
|
+
let handle: FileHandle | undefined;
|
|
594
|
+
try {
|
|
595
|
+
handle = await fs.open(filePath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
|
|
596
|
+
const stat = await handle.stat();
|
|
597
|
+
if (!stat.isFile() || stat.nlink !== 1 || (stat.mode & 0o777) !== 0o600 || stat.uid !== currentUid())
|
|
598
|
+
throw new Error("unsafe private publication file");
|
|
599
|
+
const parsed = JSON.parse(await handle.readFile("utf-8"));
|
|
600
|
+
if (isPlainObject(parsed)) return { kind: "valid", value: parsed };
|
|
601
|
+
return { kind: "corrupt", error: "state file must contain a JSON object" };
|
|
602
|
+
} catch (error) {
|
|
603
|
+
if (isErrno(error, "ENOENT")) return { kind: "absent" };
|
|
604
|
+
return { kind: "corrupt", error: error instanceof Error ? error.message : String(error) };
|
|
605
|
+
} finally {
|
|
606
|
+
await handle?.close();
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
async function assertPrivatePublicationDirectories(context: PrivatePublicationContext): Promise<void> {
|
|
611
|
+
for (const expected of context.directories) {
|
|
612
|
+
const current = await expected.handle.stat();
|
|
613
|
+
const directory =
|
|
614
|
+
expected.parent && expected.name ? path.join(directoryPath(expected.parent), expected.name) : context.root;
|
|
615
|
+
assertSafePublicationDirectory(current, directory, expected.privateSubtree);
|
|
616
|
+
if (current.dev !== expected.dev || current.ino !== expected.ino)
|
|
617
|
+
throw new Error("private publication directory changed during publication");
|
|
618
|
+
if (expected.parent && expected.name) {
|
|
619
|
+
const linked = await fs.lstat(path.join(directoryPath(expected.parent), expected.name));
|
|
620
|
+
if (
|
|
621
|
+
!linked.isDirectory() ||
|
|
622
|
+
linked.isSymbolicLink() ||
|
|
623
|
+
linked.dev !== expected.dev ||
|
|
624
|
+
linked.ino !== expected.ino
|
|
625
|
+
)
|
|
626
|
+
throw new Error("private publication directory changed during publication");
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
const namedRoot = await fs.lstat(context.root);
|
|
630
|
+
const root = context.directories[0];
|
|
631
|
+
if (
|
|
632
|
+
!root ||
|
|
633
|
+
!namedRoot.isDirectory() ||
|
|
634
|
+
namedRoot.isSymbolicLink() ||
|
|
635
|
+
namedRoot.dev !== root.dev ||
|
|
636
|
+
namedRoot.ino !== root.ino
|
|
637
|
+
)
|
|
638
|
+
throw new Error("private publication root changed during publication");
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async function closePrivatePublicationContext(context: PrivatePublicationContext): Promise<void> {
|
|
642
|
+
await Promise.all(
|
|
643
|
+
context.directories
|
|
644
|
+
.splice(0)
|
|
645
|
+
.reverse()
|
|
646
|
+
.map(directory => directory.handle.close()),
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
async function preparePrivateDirectory(
|
|
651
|
+
filePath: string,
|
|
652
|
+
options: StateWriterOptions,
|
|
653
|
+
): Promise<PrivatePublicationContext> {
|
|
654
|
+
if (process.platform !== "linux") throw new Error("private durable publication requires Linux");
|
|
655
|
+
const boundary = resolveGjcTarget(options.privateDurable!.directory, cwdForOptions(options));
|
|
656
|
+
if (boundary !== path.dirname(filePath)) throw new Error("private publication directory must be the target parent");
|
|
657
|
+
const root = cwdForOptions(options);
|
|
658
|
+
if ((await fs.realpath(root)) !== root) throw new Error("private publication requires canonical cwd");
|
|
659
|
+
const directories: PrivatePublicationDirectory[] = [];
|
|
660
|
+
const openFlags = fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW;
|
|
661
|
+
try {
|
|
662
|
+
const rootHandle = await fs.open(root, openFlags);
|
|
663
|
+
let rootStat: Stats;
|
|
664
|
+
try {
|
|
665
|
+
rootStat = await rootHandle.stat();
|
|
666
|
+
} catch (error) {
|
|
667
|
+
await rootHandle.close();
|
|
668
|
+
throw error;
|
|
669
|
+
}
|
|
670
|
+
directories.push({
|
|
671
|
+
handle: rootHandle,
|
|
672
|
+
dev: rootStat.dev,
|
|
673
|
+
ino: rootStat.ino,
|
|
674
|
+
privateSubtree: false,
|
|
675
|
+
});
|
|
676
|
+
assertSafePublicationDirectory(rootStat, root, false);
|
|
677
|
+
const namedRoot = await fs.lstat(root);
|
|
678
|
+
if (namedRoot.isSymbolicLink() || namedRoot.dev !== rootStat.dev || namedRoot.ino !== rootStat.ino)
|
|
679
|
+
throw new Error("private publication root changed during publication");
|
|
680
|
+
|
|
681
|
+
let parent = directories[0];
|
|
682
|
+
if (!parent) throw new Error("private publication root was not opened");
|
|
683
|
+
let directory = root;
|
|
684
|
+
for (const segment of path.relative(root, path.dirname(filePath)).split(path.sep)) {
|
|
685
|
+
const childPath = path.join(directoryPath(parent), segment);
|
|
686
|
+
directory = path.join(directory, segment);
|
|
687
|
+
let created = false;
|
|
688
|
+
try {
|
|
689
|
+
await fs.mkdir(childPath, { mode: 0o700 });
|
|
690
|
+
created = true;
|
|
691
|
+
} catch (error) {
|
|
692
|
+
if (!isErrno(error, "EEXIST")) throw error;
|
|
693
|
+
}
|
|
694
|
+
let createdIdentity: { dev: number; ino: number } | undefined;
|
|
695
|
+
if (created) {
|
|
696
|
+
const pathHandle = await fs.open(
|
|
697
|
+
childPath,
|
|
698
|
+
LINUX_O_PATH | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW,
|
|
699
|
+
);
|
|
700
|
+
try {
|
|
701
|
+
const beforeChmod = await pathHandle.stat();
|
|
702
|
+
if (!beforeChmod.isDirectory() || beforeChmod.uid !== currentUid() || (beforeChmod.mode & 0o022) !== 0)
|
|
703
|
+
throw new Error("unsafe newly created private publication directory");
|
|
704
|
+
await fs.chmod(procPath(pathHandle), 0o700);
|
|
705
|
+
const afterChmod = await pathHandle.stat();
|
|
706
|
+
if ((afterChmod.mode & 0o777) !== 0o700)
|
|
707
|
+
throw new Error("private publication directory is not owned mode 0700");
|
|
708
|
+
createdIdentity = { dev: afterChmod.dev, ino: afterChmod.ino };
|
|
709
|
+
} finally {
|
|
710
|
+
await pathHandle.close();
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
const childHandle = await fs.open(childPath, openFlags);
|
|
714
|
+
let childStat: Stats;
|
|
715
|
+
try {
|
|
716
|
+
childStat = await childHandle.stat();
|
|
717
|
+
} catch (error) {
|
|
718
|
+
await childHandle.close();
|
|
719
|
+
throw error;
|
|
720
|
+
}
|
|
721
|
+
if (createdIdentity && (childStat.dev !== createdIdentity.dev || childStat.ino !== createdIdentity.ino)) {
|
|
722
|
+
await childHandle.close();
|
|
723
|
+
throw new Error("private publication directory changed during creation");
|
|
724
|
+
}
|
|
725
|
+
const privateSubtree = directory === boundary || directory.startsWith(`${boundary}${path.sep}`);
|
|
726
|
+
const child: PrivatePublicationDirectory = {
|
|
727
|
+
handle: childHandle,
|
|
728
|
+
parent,
|
|
729
|
+
name: segment,
|
|
730
|
+
dev: childStat.dev,
|
|
731
|
+
ino: childStat.ino,
|
|
732
|
+
privateSubtree,
|
|
733
|
+
};
|
|
734
|
+
directories.push(child);
|
|
735
|
+
assertSafePublicationDirectory(childStat, directory, privateSubtree);
|
|
736
|
+
if (created || directory === boundary) {
|
|
737
|
+
// The newly linked entry is durable only after both the child and its
|
|
738
|
+
// parent have been synced. Newly created directories are chmodded first
|
|
739
|
+
// so umask cannot weaken their required mode.
|
|
740
|
+
await childHandle.sync();
|
|
741
|
+
await parent.handle.sync();
|
|
742
|
+
}
|
|
743
|
+
parent = child;
|
|
744
|
+
}
|
|
745
|
+
const targetParent = directories[directories.length - 1];
|
|
746
|
+
if (!targetParent) throw new Error("private publication target parent was not opened");
|
|
747
|
+
const context: PrivatePublicationContext = {
|
|
748
|
+
root,
|
|
749
|
+
directories,
|
|
750
|
+
targetParent,
|
|
751
|
+
anchoredTarget: path.join(directoryPath(targetParent), path.basename(filePath)),
|
|
752
|
+
};
|
|
753
|
+
await assertPrivatePublicationDirectories(context);
|
|
754
|
+
try {
|
|
755
|
+
const stat = await fs.lstat(context.anchoredTarget);
|
|
756
|
+
if (
|
|
757
|
+
!stat.isFile() ||
|
|
758
|
+
stat.isSymbolicLink() ||
|
|
759
|
+
stat.nlink !== 1 ||
|
|
760
|
+
(stat.mode & 0o777) !== 0o600 ||
|
|
761
|
+
stat.uid !== currentUid()
|
|
762
|
+
)
|
|
763
|
+
throw new Error("unsafe private publication file");
|
|
764
|
+
} catch (error) {
|
|
765
|
+
if (!isErrno(error, "ENOENT")) throw error;
|
|
766
|
+
}
|
|
767
|
+
return context;
|
|
768
|
+
} catch (error) {
|
|
769
|
+
await Promise.all(directories.reverse().map(directory => directory.handle.close().catch(() => undefined)));
|
|
770
|
+
throw error;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async function privateAtomicWrite(
|
|
775
|
+
filePath: string,
|
|
776
|
+
content: string,
|
|
777
|
+
options: StateWriterOptions,
|
|
778
|
+
context: PrivatePublicationContext,
|
|
779
|
+
): Promise<void> {
|
|
780
|
+
await assertPrivatePublicationDirectories(context);
|
|
781
|
+
const temporary = tempPathFor(filePath);
|
|
782
|
+
const anchoredTemporary = path.join(directoryPath(context.targetParent), path.basename(temporary));
|
|
783
|
+
let renameAttempted = false;
|
|
784
|
+
try {
|
|
785
|
+
const handle = await fs.open(anchoredTemporary, "wx", 0o600);
|
|
786
|
+
try {
|
|
787
|
+
await handle.chmod(0o600);
|
|
788
|
+
const created = await handle.stat();
|
|
789
|
+
if (!created.isFile() || created.uid !== currentUid() || (created.mode & 0o777) !== 0o600)
|
|
790
|
+
throw new Error("unsafe private publication temporary file");
|
|
791
|
+
await handle.writeFile(content, "utf8");
|
|
792
|
+
await handle.sync();
|
|
793
|
+
} finally {
|
|
794
|
+
await handle.close();
|
|
795
|
+
}
|
|
796
|
+
await assertPrivatePublicationDirectories(context);
|
|
797
|
+
renameAttempted = true;
|
|
798
|
+
await fs.rename(anchoredTemporary, context.anchoredTarget);
|
|
799
|
+
await context.targetParent.handle.sync();
|
|
800
|
+
await assertPrivatePublicationDirectories(context);
|
|
801
|
+
await maybeAudit(filePath, options);
|
|
802
|
+
} catch (error) {
|
|
803
|
+
// A rename call or anything after it can have committed the replacement
|
|
804
|
+
// before returning an error. The caller must reload instead of retrying
|
|
805
|
+
// with a new authority record.
|
|
806
|
+
if (renameAttempted) throw new StatePublicationUncertainError(filePath, error);
|
|
807
|
+
await fs.rm(anchoredTemporary, { force: true }).catch(() => undefined);
|
|
808
|
+
throw error;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
531
812
|
async function writeGuardedResolvedJsonAtomic(
|
|
532
813
|
filePath: string,
|
|
533
814
|
value: unknown,
|
|
534
815
|
options: GuardedStateWriterOptions,
|
|
535
816
|
): Promise<GuardedWriteResult> {
|
|
817
|
+
let privateContext: PrivatePublicationContext | undefined;
|
|
818
|
+
if (options.privateDurable) {
|
|
819
|
+
if (options.policy !== "source" || options.expectedRevision === undefined)
|
|
820
|
+
throw new Error("private durable publication requires source CAS");
|
|
821
|
+
privateContext = await preparePrivateDirectory(filePath, options);
|
|
822
|
+
}
|
|
536
823
|
const write = async (): Promise<GuardedWriteResult> => {
|
|
537
|
-
|
|
824
|
+
if (privateContext) await assertPrivatePublicationDirectories(privateContext);
|
|
825
|
+
const strict = privateContext
|
|
826
|
+
? await readPrivateExistingStateForMutation(privateContext.anchoredTarget)
|
|
827
|
+
: undefined;
|
|
828
|
+
if (strict?.kind === "corrupt") throw new Error(strict.error);
|
|
829
|
+
if (strict?.kind === "absent" && options.expectedRevision !== 0) throw new Error("established state missing");
|
|
830
|
+
const current = strict
|
|
831
|
+
? strict.kind === "valid"
|
|
832
|
+
? strict.value
|
|
833
|
+
: undefined
|
|
834
|
+
: await readJsonIfPresentTolerant(filePath);
|
|
538
835
|
const currentRevision = persistedStateRevision(current);
|
|
539
836
|
|
|
540
837
|
if (options.policy === "source") {
|
|
@@ -542,8 +839,13 @@ async function writeGuardedResolvedJsonAtomic(
|
|
|
542
839
|
throw new StateWriteConflictError(filePath, options.expectedRevision, currentRevision);
|
|
543
840
|
}
|
|
544
841
|
const next = stampStateRevision(withWorkflowReceipt(value, buildReceipt(options)), currentRevision + 1);
|
|
545
|
-
|
|
546
|
-
|
|
842
|
+
if (options.privateDurable) {
|
|
843
|
+
if (!privateContext) throw new Error("private publication directories were not prepared");
|
|
844
|
+
await privateAtomicWrite(filePath, jsonText(next), options, privateContext);
|
|
845
|
+
} else {
|
|
846
|
+
await atomicWrite(filePath, jsonText(next));
|
|
847
|
+
await maybeAudit(filePath, options);
|
|
848
|
+
}
|
|
547
849
|
return { path: filePath, written: true, revision: currentRevision + 1, stamped: next };
|
|
548
850
|
}
|
|
549
851
|
|
|
@@ -567,7 +869,11 @@ async function writeGuardedResolvedJsonAtomic(
|
|
|
567
869
|
// that already holds this target's lock (via `withWorkflowStateLock`) must say
|
|
568
870
|
// so rather than deadlocking against itself — the same `lockHeld` contract the
|
|
569
871
|
// envelope writers already use.
|
|
570
|
-
|
|
872
|
+
try {
|
|
873
|
+
return options.lockHeld ? await write() : await lockResolvedWorkflowTarget(filePath, write, options.lock);
|
|
874
|
+
} finally {
|
|
875
|
+
if (privateContext) await closePrivatePublicationContext(privateContext);
|
|
876
|
+
}
|
|
571
877
|
}
|
|
572
878
|
|
|
573
879
|
export async function writeGuardedJsonAtomic(
|
|
@@ -798,7 +1104,12 @@ export async function withWorkflowStateLock<T>(
|
|
|
798
1104
|
options?: StateWriterOptions,
|
|
799
1105
|
): Promise<T> {
|
|
800
1106
|
const filePath = resolveGjcTarget(targetPath, cwdForOptions(options));
|
|
801
|
-
|
|
1107
|
+
const privateContext = options?.privateDurable ? await preparePrivateDirectory(filePath, options) : undefined;
|
|
1108
|
+
try {
|
|
1109
|
+
return await lockResolvedWorkflowTarget(filePath, fn, options?.lock);
|
|
1110
|
+
} finally {
|
|
1111
|
+
if (privateContext) await closePrivatePublicationContext(privateContext);
|
|
1112
|
+
}
|
|
802
1113
|
}
|
|
803
1114
|
|
|
804
1115
|
async function lockResolvedWorkflowTarget<T>(
|
|
@@ -382,6 +382,26 @@ function repositoryIdentity(binding: RepositoryBinding): Record<string, unknown>
|
|
|
382
382
|
};
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Self-transfer guards are narrower than repository identity guards: linked
|
|
387
|
+
* worktrees share a common dir but carry independent `.gjc` state, so they are
|
|
388
|
+
* valid succession peers. `captureRepositoryBinding` records a realpath for
|
|
389
|
+
* active roots, but persisted plan bindings are operator-controlled and may
|
|
390
|
+
* contain a symlink alias.
|
|
391
|
+
* Resolve both roots through the filesystem before comparing them; a failed
|
|
392
|
+
* resolution is a refusal, never a fallback to lexical path comparison.
|
|
393
|
+
*/
|
|
394
|
+
async function canonicalWorktreeRoot(binding: RepositoryBinding, side: "source" | "target"): Promise<string> {
|
|
395
|
+
try {
|
|
396
|
+
return await fs.realpath(binding.worktreeRoot);
|
|
397
|
+
} catch {
|
|
398
|
+
throw new UltragoalSuccessionError(
|
|
399
|
+
"unsafe_target",
|
|
400
|
+
`Cannot resolve the ${side} worktree root physically (${binding.worktreeRoot}); refusing succession.`,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
385
405
|
function successionOperationId(input: {
|
|
386
406
|
sourceRepository: RepositoryBinding;
|
|
387
407
|
sourceSessionId: string;
|
|
@@ -781,11 +801,15 @@ async function resolveTargetRepositoryBinding(
|
|
|
781
801
|
throw new UltragoalSuccessionError("unsafe_target", `--target-repo is not a directory: ${raw}`);
|
|
782
802
|
}
|
|
783
803
|
const target = publicRepositoryBinding(await captureRepositoryBinding(resolved, { displayPath: resolved }));
|
|
784
|
-
|
|
804
|
+
const [targetRoot, sourceRoot] = await Promise.all([
|
|
805
|
+
canonicalWorktreeRoot(target, "target"),
|
|
806
|
+
canonicalWorktreeRoot(sourceBinding, "source"),
|
|
807
|
+
]);
|
|
808
|
+
if (targetRoot === sourceRoot) {
|
|
785
809
|
throw new UltragoalSuccessionError(
|
|
786
810
|
"unsafe_target",
|
|
787
811
|
`--target-repo resolves to the source repository itself (${target.worktreeRoot}). ` +
|
|
788
|
-
"Succession
|
|
812
|
+
"Succession requires a distinct worktree or repository; it is not a rebind of the original run.",
|
|
789
813
|
);
|
|
790
814
|
}
|
|
791
815
|
return target;
|
|
@@ -1277,7 +1301,11 @@ export async function adoptUltragoalSuccession(
|
|
|
1277
1301
|
"adoption is pinned to the exact worktree the offer named.",
|
|
1278
1302
|
);
|
|
1279
1303
|
}
|
|
1280
|
-
|
|
1304
|
+
const [targetRoot, sourceRoot] = await Promise.all([
|
|
1305
|
+
canonicalWorktreeRoot(targetActual, "target"),
|
|
1306
|
+
canonicalWorktreeRoot(sourceRepository, "source"),
|
|
1307
|
+
]);
|
|
1308
|
+
if (targetRoot === sourceRoot) {
|
|
1281
1309
|
throw new UltragoalSuccessionError(
|
|
1282
1310
|
"unsafe_target",
|
|
1283
1311
|
"Refusing to adopt a succession offer into its own source repository.",
|
|
@@ -20,7 +20,11 @@ export interface EndpointRequest {
|
|
|
20
20
|
input: Record<string, unknown>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export
|
|
23
|
+
export interface EndpointHandlerRequest extends EndpointRequest {
|
|
24
|
+
signal: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type EndpointHandler = (req: EndpointHandlerRequest) => Promise<unknown>;
|
|
24
28
|
|
|
25
29
|
function frame(value: unknown): string {
|
|
26
30
|
return `${JSON.stringify(value)}\n`;
|
|
@@ -54,6 +58,14 @@ export class ControlServer {
|
|
|
54
58
|
socket.setEncoding("utf8");
|
|
55
59
|
let buffer = "";
|
|
56
60
|
let handled = false;
|
|
61
|
+
let responseSent = false;
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
socket.once("close", () => {
|
|
64
|
+
if (!responseSent) controller.abort(new Error("endpoint_client_disconnected"));
|
|
65
|
+
});
|
|
66
|
+
socket.on("error", () => {
|
|
67
|
+
if (!responseSent) controller.abort(new Error("endpoint_client_disconnected"));
|
|
68
|
+
});
|
|
57
69
|
socket.on("data", (chunk: string) => {
|
|
58
70
|
if (handled) return;
|
|
59
71
|
buffer += chunk;
|
|
@@ -61,20 +73,26 @@ export class ControlServer {
|
|
|
61
73
|
if (idx < 0) return;
|
|
62
74
|
handled = true;
|
|
63
75
|
const line = buffer.slice(0, idx).trim();
|
|
64
|
-
void this.#dispatch(line)
|
|
76
|
+
void this.#dispatch(line, controller.signal)
|
|
65
77
|
.then(response => {
|
|
66
|
-
socket.
|
|
78
|
+
if (!socket.destroyed && !controller.signal.aborted) {
|
|
79
|
+
responseSent = true;
|
|
80
|
+
socket.end(frame(response));
|
|
81
|
+
}
|
|
67
82
|
})
|
|
68
83
|
.catch((error: unknown) => {
|
|
69
|
-
socket.
|
|
84
|
+
if (!socket.destroyed && !controller.signal.aborted) {
|
|
85
|
+
responseSent = true;
|
|
86
|
+
socket.end(frame({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
87
|
+
}
|
|
70
88
|
});
|
|
71
89
|
});
|
|
72
90
|
}
|
|
73
91
|
|
|
74
|
-
async #dispatch(line: string): Promise<unknown> {
|
|
92
|
+
async #dispatch(line: string, signal: AbortSignal): Promise<unknown> {
|
|
75
93
|
const req = JSON.parse(line) as EndpointRequest;
|
|
76
94
|
if (!req || typeof req.verb !== "string") throw new Error("bad_request");
|
|
77
|
-
return this.handler({ verb: req.verb, input: req.input ?? {} });
|
|
95
|
+
return this.handler({ verb: req.verb, input: req.input ?? {}, signal });
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
async close(): Promise<void> {
|