@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
package/src/config/file-lock.ts
CHANGED
|
@@ -44,12 +44,14 @@ export type FileLockAcquireReason = "acquire_timeout" | "orphan_transition";
|
|
|
44
44
|
* generation); this records the cause that exhaustion must report.
|
|
45
45
|
*/
|
|
46
46
|
export interface FileLockStaleRemovalFailure {
|
|
47
|
-
/** Guarded-removal outcome
|
|
48
|
-
outcome: "cleanup_failed" | "error";
|
|
47
|
+
/** Guarded-removal outcome; refusals are surfaced only after exhaustion revalidates the dead generation. */
|
|
48
|
+
outcome: "cleanup_failed" | "owner_changed" | "missing" | "error";
|
|
49
49
|
/** Native/errno code carried by the refusal, when one was present. */
|
|
50
50
|
code?: string;
|
|
51
51
|
/** Human-readable cause surfaced to the operator at exhaustion. */
|
|
52
52
|
message: string;
|
|
53
|
+
/** Platform-specific manual cleanup command, set only when the same dead owner persists at exhaustion. */
|
|
54
|
+
manualCleanupCommand?: string;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
export class FileLockAcquireError extends Error {
|
|
@@ -70,10 +72,12 @@ export class FileLockAcquireError extends Error {
|
|
|
70
72
|
removalFailure.code ? ` [${removalFailure.code}]` : ""
|
|
71
73
|
})`
|
|
72
74
|
: "";
|
|
75
|
+
const cleanupDetail = removalFailure?.manualCleanupCommand
|
|
76
|
+
? `; manual cleanup is appropriate only after independently verifying this exact directory still belongs to the dead owner and no successor has taken it: ${removalFailure.manualCleanupCommand}`
|
|
77
|
+
: "";
|
|
73
78
|
super(
|
|
74
79
|
`Failed to acquire lock for ${filePath} after ${attempts} attempts: ${detail}${removalDetail} (${lockPath}); ` +
|
|
75
|
-
`a live owner is never displaced — if this is an SDK broker (gjc sdk session list), it must finish or be stopped before retrying
|
|
76
|
-
`the lock is a directory, remove it only by deleting the directory (${lockPath}) once no live owner remains`,
|
|
80
|
+
`a live owner is never displaced — if this is an SDK broker (gjc sdk session list), it must finish or be stopped before retrying${cleanupDetail}`,
|
|
77
81
|
);
|
|
78
82
|
this.code = reason;
|
|
79
83
|
this.name = "FileLockAcquireError";
|
|
@@ -92,6 +96,15 @@ const DEFAULT_OPTIONS: Required<
|
|
|
92
96
|
retryDelayMs: 100,
|
|
93
97
|
};
|
|
94
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Windows can transiently deny a no-replace publication while another handle still
|
|
101
|
+
* has the staged or destination path open without delete sharing. The native result
|
|
102
|
+
* is explicitly pre-mutation in this case, so retrying the same source name cannot
|
|
103
|
+
* publish twice or clean up a committed namespace change.
|
|
104
|
+
*/
|
|
105
|
+
const PUBLICATION_SHARING_RETRY_ATTEMPTS = 3;
|
|
106
|
+
const PUBLICATION_SHARING_RETRY_DELAY_MS = 10;
|
|
107
|
+
|
|
95
108
|
/** Release retries cover transient handle denial and a competing exact-removal quarantine cleanup. */
|
|
96
109
|
export const FILE_LOCK_RELEASE_RETRY_ATTEMPTS = 20;
|
|
97
110
|
export const FILE_LOCK_RELEASE_RETRY_DELAY_MS = 25;
|
|
@@ -232,6 +245,7 @@ type LockInfoFileState = {
|
|
|
232
245
|
size: bigint;
|
|
233
246
|
mtimeNs: bigint;
|
|
234
247
|
ctimeNs: bigint;
|
|
248
|
+
birthtimeNs: bigint;
|
|
235
249
|
nlink: bigint;
|
|
236
250
|
};
|
|
237
251
|
|
|
@@ -246,6 +260,10 @@ type LockInfoPathState = {
|
|
|
246
260
|
|
|
247
261
|
function lockInfoFileState(stats: BigIntStats): LockInfoFileState | null {
|
|
248
262
|
if (stats.isSymbolicLink() || !stats.isFile()) return null;
|
|
263
|
+
// Some supported filesystems report creation time as missing or epoch zero. Keep
|
|
264
|
+
// the stable dev/inode identity and content evidence usable instead of wedging
|
|
265
|
+
// acquire/release/GC on a metadata field the filesystem cannot provide.
|
|
266
|
+
const birthtimeNs = typeof stats.birthtimeNs === "bigint" && stats.birthtimeNs > 0n ? stats.birthtimeNs : 0n;
|
|
249
267
|
return {
|
|
250
268
|
dev: stats.dev,
|
|
251
269
|
ino: stats.ino,
|
|
@@ -253,18 +271,21 @@ function lockInfoFileState(stats: BigIntStats): LockInfoFileState | null {
|
|
|
253
271
|
size: stats.size,
|
|
254
272
|
mtimeNs: stats.mtimeNs,
|
|
255
273
|
ctimeNs: stats.ctimeNs,
|
|
274
|
+
birthtimeNs,
|
|
256
275
|
nlink: stats.nlink,
|
|
257
276
|
};
|
|
258
277
|
}
|
|
259
278
|
|
|
260
279
|
function sameLockInfoFileState(left: LockInfoFileState, right: LockInfoFileState): boolean {
|
|
280
|
+
const birthtimeMatches =
|
|
281
|
+
left.birthtimeNs === 0n || right.birthtimeNs === 0n || left.birthtimeNs === right.birthtimeNs;
|
|
261
282
|
return (
|
|
262
283
|
left.dev === right.dev &&
|
|
263
284
|
left.ino === right.ino &&
|
|
264
285
|
left.mode === right.mode &&
|
|
265
286
|
left.size === right.size &&
|
|
266
287
|
left.mtimeNs === right.mtimeNs &&
|
|
267
|
-
|
|
288
|
+
birthtimeMatches &&
|
|
268
289
|
left.nlink === right.nlink
|
|
269
290
|
);
|
|
270
291
|
}
|
|
@@ -313,6 +334,7 @@ function fileLockDirIdentityFromPathState(state: LockInfoPathState, bytes: strin
|
|
|
313
334
|
infoSize: String(state.file.size),
|
|
314
335
|
infoMtimeNs: String(state.file.mtimeNs),
|
|
315
336
|
infoCtimeNs: String(state.file.ctimeNs),
|
|
337
|
+
infoBirthtimeNs: String(state.file.birthtimeNs),
|
|
316
338
|
infoSha256: crypto.createHash("sha256").update(bytes).digest("hex"),
|
|
317
339
|
};
|
|
318
340
|
}
|
|
@@ -680,6 +702,8 @@ function sameFileLockTreeAfterPublication(
|
|
|
680
702
|
staged: NativeDirectoryTreeSnapshot,
|
|
681
703
|
published: NativeDirectoryTreeSnapshot,
|
|
682
704
|
): boolean {
|
|
705
|
+
// ctime is intentionally omitted: native snapshots expose no birthtime, and a
|
|
706
|
+
// metadata-only change must not reject an otherwise identical published tree.
|
|
683
707
|
return (
|
|
684
708
|
staged.rootDev === published.rootDev &&
|
|
685
709
|
staged.rootIno === published.rootIno &&
|
|
@@ -695,7 +719,6 @@ function sameFileLockTreeAfterPublication(
|
|
|
695
719
|
entry.nlink === current.nlink &&
|
|
696
720
|
entry.size === current.size &&
|
|
697
721
|
entry.mtimeNs === current.mtimeNs &&
|
|
698
|
-
(entry.relativePath === "" || entry.ctimeNs === current.ctimeNs) &&
|
|
699
722
|
entry.sha256 === current.sha256
|
|
700
723
|
);
|
|
701
724
|
})
|
|
@@ -879,6 +902,7 @@ function isValidNativeNoReplaceResult(value: unknown): value is NativeNoReplaceR
|
|
|
879
902
|
"interrupted",
|
|
880
903
|
"identity_violation",
|
|
881
904
|
"durability_not_provable",
|
|
905
|
+
"sharing_violation",
|
|
882
906
|
"unknown",
|
|
883
907
|
] as const
|
|
884
908
|
).includes(value.reason as never) ||
|
|
@@ -954,25 +978,18 @@ function isValidNativeNoReplaceResult(value: unknown): value is NativeNoReplaceR
|
|
|
954
978
|
function isSuccessfulNativePublication(value: unknown, operation: "primary" | "directory"): boolean {
|
|
955
979
|
if (!isValidNativeNoReplaceResult(value) || !value.ok) return false;
|
|
956
980
|
if (operation === "directory") return value.primitive === "mkdirat_renameat_noreplace";
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
return false;
|
|
966
|
-
}
|
|
981
|
+
// Native code records the primitive it actually invoked in the receipt. That
|
|
982
|
+
// primitive is the producer-platform evidence; process.platform is only ambient
|
|
983
|
+
// capability metadata and may be overridden by a coordinator discovery test.
|
|
984
|
+
return (
|
|
985
|
+
value.primitive === "renameat2_noreplace" ||
|
|
986
|
+
value.primitive === "renameatx_np_excl" ||
|
|
987
|
+
value.primitive === "windows_rename_noreplace"
|
|
988
|
+
);
|
|
967
989
|
}
|
|
968
990
|
|
|
969
991
|
function isCommittedDirectoryVerificationFailure(value: unknown): value is NativeNoReplaceResult {
|
|
970
|
-
return (
|
|
971
|
-
process.platform === "linux" &&
|
|
972
|
-
isValidNativeNoReplaceResult(value) &&
|
|
973
|
-
!value.ok &&
|
|
974
|
-
value.mutationState === "committed"
|
|
975
|
-
);
|
|
992
|
+
return isValidNativeNoReplaceResult(value) && !value.ok && value.mutationState === "committed";
|
|
976
993
|
}
|
|
977
994
|
|
|
978
995
|
/**
|
|
@@ -996,6 +1013,35 @@ function isPreMutationUnsupportedRenameResult(value: unknown): value is NativeNo
|
|
|
996
1013
|
return true;
|
|
997
1014
|
}
|
|
998
1015
|
|
|
1016
|
+
function isPreMutationSharingViolation(value: unknown): value is NativeNoReplaceResult {
|
|
1017
|
+
return (
|
|
1018
|
+
isValidNativeNoReplaceResult(value) &&
|
|
1019
|
+
!value.ok &&
|
|
1020
|
+
value.code === "sharing_violation" &&
|
|
1021
|
+
value.mutationState === "not_committed" &&
|
|
1022
|
+
value.durabilityState === "not_attempted" &&
|
|
1023
|
+
value.reason === "sharing_violation" &&
|
|
1024
|
+
value.phase === "rename"
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
async function publishNoReplaceWithSharingRetry(
|
|
1029
|
+
publish: (sourcePath: string, destinationPath: string) => Promise<NativeNoReplaceResult>,
|
|
1030
|
+
sourcePath: string,
|
|
1031
|
+
destinationPath: string,
|
|
1032
|
+
): Promise<NativeNoReplaceResult> {
|
|
1033
|
+
let result = await publish(sourcePath, destinationPath);
|
|
1034
|
+
for (
|
|
1035
|
+
let attempt = 1;
|
|
1036
|
+
attempt < PUBLICATION_SHARING_RETRY_ATTEMPTS && isPreMutationSharingViolation(result);
|
|
1037
|
+
attempt++
|
|
1038
|
+
) {
|
|
1039
|
+
await Bun.sleep(PUBLICATION_SHARING_RETRY_DELAY_MS * attempt);
|
|
1040
|
+
result = await publish(sourcePath, destinationPath);
|
|
1041
|
+
}
|
|
1042
|
+
return result;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
999
1045
|
async function localLockKey(lockPath: string): Promise<string> {
|
|
1000
1046
|
try {
|
|
1001
1047
|
return normalizeLockKey(await fs.realpath(lockPath));
|
|
@@ -1027,6 +1073,10 @@ function ownerIncarnationChanged(owner: FileLockOwnerToken, startTimeCache?: Map
|
|
|
1027
1073
|
return currentStartTime !== null && currentStartTime !== owner.start_time;
|
|
1028
1074
|
}
|
|
1029
1075
|
|
|
1076
|
+
function ownerGenerationIsDead(owner: FileLockOwnerToken): boolean {
|
|
1077
|
+
return ownerLiveness(owner.pid) === "dead" || ownerIncarnationChanged(owner);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1030
1080
|
/** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */
|
|
1031
1081
|
export type FileLockGcRemoval = "removed" | "owner_changed" | "missing" | "cleanup_failed";
|
|
1032
1082
|
|
|
@@ -1034,7 +1084,14 @@ type LockStaleSnapshot =
|
|
|
1034
1084
|
| { stale: false }
|
|
1035
1085
|
| { stale: true; owner: FileLockOwnerToken; identity: GenericFileLockDirIdentity };
|
|
1036
1086
|
|
|
1037
|
-
/**
|
|
1087
|
+
/**
|
|
1088
|
+
* Identity evidence carried by the generic stale verdict into a later removal.
|
|
1089
|
+
*
|
|
1090
|
+
* `ctimeNs` is a mutable metadata-change time on every supported filesystem, so
|
|
1091
|
+
* it is retained for diagnostics/legacy consumers but is not part of the lock
|
|
1092
|
+
* identity predicate. `infoBirthtimeNs` is the creation time that stays bound
|
|
1093
|
+
* to the file object.
|
|
1094
|
+
*/
|
|
1038
1095
|
export interface GenericFileLockDirIdentity {
|
|
1039
1096
|
rootDev: string;
|
|
1040
1097
|
rootIno: string;
|
|
@@ -1044,23 +1101,34 @@ export interface GenericFileLockDirIdentity {
|
|
|
1044
1101
|
infoSize: string;
|
|
1045
1102
|
infoMtimeNs: string;
|
|
1046
1103
|
infoCtimeNs: string;
|
|
1104
|
+
infoBirthtimeNs: string;
|
|
1047
1105
|
infoSha256: string;
|
|
1048
1106
|
}
|
|
1049
1107
|
|
|
1050
|
-
function
|
|
1108
|
+
function sameStableFileLockIdentity(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1051
1109
|
return (
|
|
1052
1110
|
left.rootDev === right.rootDev &&
|
|
1053
1111
|
left.rootIno === right.rootIno &&
|
|
1054
1112
|
left.infoDev === right.infoDev &&
|
|
1055
1113
|
left.infoIno === right.infoIno &&
|
|
1114
|
+
left.infoBirthtimeNs === right.infoBirthtimeNs
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/** Content/topology evidence kept separate from the stable file identity. */
|
|
1119
|
+
function sameFileLockContentEvidence(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1120
|
+
return (
|
|
1056
1121
|
left.infoNlink === right.infoNlink &&
|
|
1057
1122
|
left.infoSize === right.infoSize &&
|
|
1058
1123
|
left.infoMtimeNs === right.infoMtimeNs &&
|
|
1059
|
-
left.infoCtimeNs === right.infoCtimeNs &&
|
|
1060
1124
|
left.infoSha256 === right.infoSha256
|
|
1061
1125
|
);
|
|
1062
1126
|
}
|
|
1063
1127
|
|
|
1128
|
+
function sameGenericFileLockDirIdentity(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1129
|
+
return sameStableFileLockIdentity(left, right) && sameFileLockContentEvidence(left, right);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1064
1132
|
let nativeExactRemovalUsable: boolean | undefined;
|
|
1065
1133
|
let nativeExactRemovalProbePromise: Promise<boolean> | undefined;
|
|
1066
1134
|
|
|
@@ -1171,26 +1239,54 @@ async function removeVerifiedOwnedLockDirWithoutNative(
|
|
|
1171
1239
|
return "cleanup_failed";
|
|
1172
1240
|
}
|
|
1173
1241
|
const current = await captureFileLockDirIdentity(lockDir);
|
|
1174
|
-
if (!current || !
|
|
1242
|
+
if (!current || !sameStableFileLockIdentity(current, expected)) return "owner_changed";
|
|
1175
1243
|
const captured = nativeFileLockBindings().snapshotDirectoryTree(lockDir);
|
|
1176
1244
|
if (!captured.ok || !captured.snapshot) return "owner_changed";
|
|
1177
1245
|
const infoEntry = captured.snapshot.entries.find(entry => entry.relativePath === "info");
|
|
1178
1246
|
if (
|
|
1179
|
-
captured.snapshot.rootDev !== expected.rootDev ||
|
|
1180
|
-
captured.snapshot.rootIno !== expected.rootIno ||
|
|
1181
1247
|
!infoEntry ||
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
infoEntry
|
|
1248
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1249
|
+
captured.snapshot.rootDev,
|
|
1250
|
+
captured.snapshot.rootIno,
|
|
1251
|
+
infoEntry,
|
|
1252
|
+
expected,
|
|
1253
|
+
) ||
|
|
1254
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expected)
|
|
1189
1255
|
)
|
|
1190
1256
|
return "owner_changed";
|
|
1191
1257
|
return await removeVerifiedLockDirWithoutNative(lockDir, captured.snapshot, owner);
|
|
1192
1258
|
}
|
|
1193
1259
|
|
|
1260
|
+
function nativeFileLockInfoMatchesStableIdentity(
|
|
1261
|
+
rootDev: string,
|
|
1262
|
+
rootIno: string,
|
|
1263
|
+
infoEntry: NativeDirectoryTreeSnapshot["entries"][number],
|
|
1264
|
+
expected: GenericFileLockDirIdentity,
|
|
1265
|
+
): boolean {
|
|
1266
|
+
return (
|
|
1267
|
+
rootDev === expected.rootDev &&
|
|
1268
|
+
rootIno === expected.rootIno &&
|
|
1269
|
+
infoEntry.dev === expected.infoDev &&
|
|
1270
|
+
infoEntry.ino === expected.infoIno
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
function nativeFileLockInfoMatchesContentEvidence(
|
|
1275
|
+
infoEntry: NativeDirectoryTreeSnapshot["entries"][number],
|
|
1276
|
+
expected: GenericFileLockDirIdentity,
|
|
1277
|
+
): boolean {
|
|
1278
|
+
// Native snapshots expose a ctime-shaped field, but ctime is a mutable
|
|
1279
|
+
// metadata-change timestamp on every supported filesystem. The stable file
|
|
1280
|
+
// identity is checked separately; requiring ctime here would reject a
|
|
1281
|
+
// legitimate lock after chmod/ACL/indexer activity.
|
|
1282
|
+
return (
|
|
1283
|
+
infoEntry.nlink === expected.infoNlink &&
|
|
1284
|
+
infoEntry.size === expected.infoSize &&
|
|
1285
|
+
infoEntry.mtimeNs === expected.infoMtimeNs &&
|
|
1286
|
+
infoEntry.sha256 === expected.infoSha256
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1194
1290
|
export type GenericFileLockDirStaleVerdict = { stale: false } | { stale: true; identity: GenericFileLockDirIdentity };
|
|
1195
1291
|
|
|
1196
1292
|
/**
|
|
@@ -1254,17 +1350,17 @@ export async function removeFileLockDirForGc(
|
|
|
1254
1350
|
if (!infoEntry?.sha256) return "owner_changed";
|
|
1255
1351
|
const judgedDigest = crypto.createHash("sha256").update(onDiskBytes).digest("hex");
|
|
1256
1352
|
if (infoEntry.sha256 !== judgedDigest) return "owner_changed";
|
|
1353
|
+
const currentIdentity = await captureFileLockDirIdentity(nativeCapturePath);
|
|
1354
|
+
if (!currentIdentity || !sameStableFileLockIdentity(currentIdentity, expectedIdentity)) return "owner_changed";
|
|
1257
1355
|
if (
|
|
1258
1356
|
!captured.snapshot.rootDev ||
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
infoEntry
|
|
1266
|
-
infoEntry.ctimeNs !== expectedIdentity.infoCtimeNs ||
|
|
1267
|
-
infoEntry.sha256 !== expectedIdentity.infoSha256
|
|
1357
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1358
|
+
captured.snapshot.rootDev,
|
|
1359
|
+
captured.snapshot.rootIno,
|
|
1360
|
+
infoEntry,
|
|
1361
|
+
expectedIdentity,
|
|
1362
|
+
) ||
|
|
1363
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expectedIdentity)
|
|
1268
1364
|
)
|
|
1269
1365
|
return "owner_changed";
|
|
1270
1366
|
let removed: NativeExactUnlinkResult;
|
|
@@ -1462,13 +1558,17 @@ async function staleLockSnapshot(
|
|
|
1462
1558
|
|
|
1463
1559
|
type StaleLockRemovalAttempt = { removed: true } | { removed: false; failure?: FileLockStaleRemovalFailure };
|
|
1464
1560
|
|
|
1465
|
-
type RecordedStaleRemovalFailure = {
|
|
1561
|
+
type RecordedStaleRemovalFailure = {
|
|
1562
|
+
owner: FileLockOwnerToken;
|
|
1563
|
+
identity: GenericFileLockDirIdentity;
|
|
1564
|
+
failure: FileLockStaleRemovalFailure;
|
|
1565
|
+
};
|
|
1466
1566
|
|
|
1467
1567
|
/**
|
|
1468
|
-
* A recorded refusal describes exactly one dead owner generation
|
|
1469
|
-
* exhaustion and report it only while
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1568
|
+
* A recorded refusal describes exactly one dead owner generation and directory identity.
|
|
1569
|
+
* Re-read the pathname at exhaustion and report it only while both still match, so a refusal
|
|
1570
|
+
* recorded for a dead generation is never pinned onto a successor that took the pathname over
|
|
1571
|
+
* before the budget ran out, even if its legacy owner bytes are identical.
|
|
1472
1572
|
*/
|
|
1473
1573
|
async function staleRemovalFailureForCurrentGeneration(
|
|
1474
1574
|
lockPath: string,
|
|
@@ -1476,13 +1576,31 @@ async function staleRemovalFailureForCurrentGeneration(
|
|
|
1476
1576
|
): Promise<FileLockStaleRemovalFailure | undefined> {
|
|
1477
1577
|
if (!recorded) return undefined;
|
|
1478
1578
|
try {
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1579
|
+
const observation = await readLockInfoObservation(lockPath);
|
|
1580
|
+
if (!observation) return undefined;
|
|
1581
|
+
const current = parseLockInfoBytes(observation.bytes);
|
|
1582
|
+
if (!current || !sameFileLockOwnerToken(current, recorded.owner) || !ownerGenerationIsDead(current))
|
|
1583
|
+
return undefined;
|
|
1584
|
+
const currentIdentity = fileLockDirIdentityFromPathState(observation.state, observation.bytes);
|
|
1585
|
+
if (!sameGenericFileLockDirIdentity(recorded.identity, currentIdentity)) return undefined;
|
|
1586
|
+
return {
|
|
1587
|
+
...recorded.failure,
|
|
1588
|
+
manualCleanupCommand: manualLockCleanupCommand(lockPath),
|
|
1589
|
+
};
|
|
1481
1590
|
} catch {
|
|
1482
1591
|
return undefined;
|
|
1483
1592
|
}
|
|
1484
1593
|
}
|
|
1485
1594
|
|
|
1595
|
+
function manualLockCleanupCommand(lockPath: string): string {
|
|
1596
|
+
if (process.platform === "win32") {
|
|
1597
|
+
const quotedPath = lockPath.replace(/'/g, "''");
|
|
1598
|
+
return `Remove-Item -LiteralPath '${quotedPath}' -Recurse -Force`;
|
|
1599
|
+
}
|
|
1600
|
+
const quotedPath = lockPath.replace(/'/g, "'\\''");
|
|
1601
|
+
return `rm -rf -- '${quotedPath}'`;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1486
1604
|
async function removeStaleLockForAcquire(
|
|
1487
1605
|
lockPath: string,
|
|
1488
1606
|
snapshot: LockStaleSnapshot,
|
|
@@ -1491,8 +1609,21 @@ async function removeStaleLockForAcquire(
|
|
|
1491
1609
|
try {
|
|
1492
1610
|
const outcome = await removeFileLockDirForGc(lockPath, snapshot.owner, snapshot.identity);
|
|
1493
1611
|
if (outcome === "removed") return { removed: true };
|
|
1494
|
-
//
|
|
1495
|
-
//
|
|
1612
|
+
// Either refusal can mean a successor or an incomplete publication owns the path;
|
|
1613
|
+
// keep it only as a diagnostic candidate and expose it at exhaustion if the same
|
|
1614
|
+
// dead owner still persists. Never fall back to path-only deletion.
|
|
1615
|
+
if (outcome === "owner_changed" || outcome === "missing") {
|
|
1616
|
+
return {
|
|
1617
|
+
removed: false,
|
|
1618
|
+
failure: {
|
|
1619
|
+
outcome,
|
|
1620
|
+
message:
|
|
1621
|
+
outcome === "owner_changed"
|
|
1622
|
+
? "the identity-bound removal guard returned owner_changed; no path-only fallback was attempted"
|
|
1623
|
+
: "the guarded removal could not read the owner record; no path-only fallback was attempted",
|
|
1624
|
+
},
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1496
1627
|
if (outcome !== "cleanup_failed") return { removed: false };
|
|
1497
1628
|
return {
|
|
1498
1629
|
removed: false,
|
|
@@ -1636,12 +1767,20 @@ async function tryAcquireLock(
|
|
|
1636
1767
|
renameNoReplacePathAsync,
|
|
1637
1768
|
renameDirectoryNoReplacePathAsync,
|
|
1638
1769
|
};
|
|
1639
|
-
const published = await
|
|
1770
|
+
const published = await publishNoReplaceWithSharingRetry(
|
|
1771
|
+
publication.renameNoReplacePathAsync,
|
|
1772
|
+
canonicalPendingPath,
|
|
1773
|
+
destinationPath,
|
|
1774
|
+
);
|
|
1640
1775
|
let publishedSuccessfully = isSuccessfulNativePublication(published, "primary");
|
|
1641
1776
|
if (published.ok && !publishedSuccessfully)
|
|
1642
1777
|
throw new Error("Failed to publish file lock: invalid primary success receipt.");
|
|
1643
1778
|
if (!published.ok && isPreMutationUnsupportedRenameResult(published)) {
|
|
1644
|
-
const fallback = await
|
|
1779
|
+
const fallback = await publishNoReplaceWithSharingRetry(
|
|
1780
|
+
publication.renameDirectoryNoReplacePathAsync,
|
|
1781
|
+
canonicalPendingPath,
|
|
1782
|
+
destinationPath,
|
|
1783
|
+
);
|
|
1645
1784
|
const fallbackSuccessfully = isSuccessfulNativePublication(fallback, "directory");
|
|
1646
1785
|
if (fallback.ok && !fallbackSuccessfully)
|
|
1647
1786
|
throw new Error("Failed to publish file lock: invalid directory success receipt.");
|
|
@@ -1800,16 +1939,16 @@ async function quarantineReleasedLock(
|
|
|
1800
1939
|
if (!captured.ok || !captured.snapshot) return false;
|
|
1801
1940
|
const infoEntry = captured.snapshot.entries.find(entry => entry.relativePath === "info");
|
|
1802
1941
|
if (!infoEntry?.sha256) return false;
|
|
1942
|
+
const currentIdentity = await captureFileLockDirIdentity(nativeCapturePath);
|
|
1943
|
+
if (!currentIdentity || !sameStableFileLockIdentity(currentIdentity, expectedIdentity)) return false;
|
|
1803
1944
|
if (
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
infoEntry
|
|
1811
|
-
infoEntry.ctimeNs !== expectedIdentity.infoCtimeNs ||
|
|
1812
|
-
infoEntry.sha256 !== expectedIdentity.infoSha256
|
|
1945
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1946
|
+
captured.snapshot.rootDev,
|
|
1947
|
+
captured.snapshot.rootIno,
|
|
1948
|
+
infoEntry,
|
|
1949
|
+
expectedIdentity,
|
|
1950
|
+
) ||
|
|
1951
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expectedIdentity)
|
|
1813
1952
|
)
|
|
1814
1953
|
return false;
|
|
1815
1954
|
// Bind the owner generation to the snapshot before exact removal. A successor
|
|
@@ -2111,7 +2250,9 @@ export async function acquireFileLock(filePath: string, options: FileLockOptions
|
|
|
2111
2250
|
continue;
|
|
2112
2251
|
}
|
|
2113
2252
|
staleRemovalFailure =
|
|
2114
|
-
stale.stale && staleRemoval.failure
|
|
2253
|
+
stale.stale && staleRemoval.failure
|
|
2254
|
+
? { owner: stale.owner, identity: stale.identity, failure: staleRemoval.failure }
|
|
2255
|
+
: undefined;
|
|
2115
2256
|
if (!opts.signal) {
|
|
2116
2257
|
await Bun.sleep(opts.retryDelayMs);
|
|
2117
2258
|
continue;
|
|
@@ -222,11 +222,11 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
222
222
|
? result.stale
|
|
223
223
|
? "cached"
|
|
224
224
|
: "ok"
|
|
225
|
-
: result.fetched
|
|
225
|
+
: result.fetched ||
|
|
226
|
+
(result.cacheFresh && result.cacheAuthoritative && result.dynamicModelIds?.length === 0)
|
|
226
227
|
? "empty"
|
|
227
|
-
: // No fetch happened
|
|
228
|
-
//
|
|
229
|
-
// provider is unvalidated, not authoritatively empty.
|
|
228
|
+
: // No fetch happened and no fresh authoritative empty row
|
|
229
|
+
// attested to this result, so the provider is unvalidated.
|
|
230
230
|
"unavailable";
|
|
231
231
|
const state: ProviderDiscoveryState = {
|
|
232
232
|
provider: provider.provider,
|