@gajae-code/coding-agent 0.17.2 → 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 +194 -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 +18 -0
- package/dist/types/config/file-lock.d.ts +9 -1
- package/dist/types/config/model-profile-activation.d.ts +45 -1
- package/dist/types/config/model-registry.d.ts +11 -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/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 +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/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/broker/broker.d.ts +13 -2
- 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 +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/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 +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/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.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 +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 +175 -117
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +14 -0
- package/src/config/file-lock.ts +147 -51
- package/src/config/model-profile-activation.ts +334 -43
- package/src/config/model-registry.ts +183 -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 +507 -81
- 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/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/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +20 -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 +408 -35
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- 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 +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/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 +27 -8
- package/src/sdk/broker/broker.ts +378 -52
- 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 +690 -80
- 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 +138 -2
- package/src/sdk/host/session-runtime.ts +311 -97
- 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 +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 +182 -7
- 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 +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/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/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.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
package/src/config/file-lock.ts
CHANGED
|
@@ -92,6 +92,15 @@ const DEFAULT_OPTIONS: Required<
|
|
|
92
92
|
retryDelayMs: 100,
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Windows can transiently deny a no-replace publication while another handle still
|
|
97
|
+
* has the staged or destination path open without delete sharing. The native result
|
|
98
|
+
* is explicitly pre-mutation in this case, so retrying the same source name cannot
|
|
99
|
+
* publish twice or clean up a committed namespace change.
|
|
100
|
+
*/
|
|
101
|
+
const PUBLICATION_SHARING_RETRY_ATTEMPTS = 3;
|
|
102
|
+
const PUBLICATION_SHARING_RETRY_DELAY_MS = 10;
|
|
103
|
+
|
|
95
104
|
/** Release retries cover transient handle denial and a competing exact-removal quarantine cleanup. */
|
|
96
105
|
export const FILE_LOCK_RELEASE_RETRY_ATTEMPTS = 20;
|
|
97
106
|
export const FILE_LOCK_RELEASE_RETRY_DELAY_MS = 25;
|
|
@@ -232,6 +241,7 @@ type LockInfoFileState = {
|
|
|
232
241
|
size: bigint;
|
|
233
242
|
mtimeNs: bigint;
|
|
234
243
|
ctimeNs: bigint;
|
|
244
|
+
birthtimeNs: bigint;
|
|
235
245
|
nlink: bigint;
|
|
236
246
|
};
|
|
237
247
|
|
|
@@ -246,6 +256,10 @@ type LockInfoPathState = {
|
|
|
246
256
|
|
|
247
257
|
function lockInfoFileState(stats: BigIntStats): LockInfoFileState | null {
|
|
248
258
|
if (stats.isSymbolicLink() || !stats.isFile()) return null;
|
|
259
|
+
// Some supported filesystems report creation time as missing or epoch zero. Keep
|
|
260
|
+
// the stable dev/inode identity and content evidence usable instead of wedging
|
|
261
|
+
// acquire/release/GC on a metadata field the filesystem cannot provide.
|
|
262
|
+
const birthtimeNs = typeof stats.birthtimeNs === "bigint" && stats.birthtimeNs > 0n ? stats.birthtimeNs : 0n;
|
|
249
263
|
return {
|
|
250
264
|
dev: stats.dev,
|
|
251
265
|
ino: stats.ino,
|
|
@@ -253,18 +267,21 @@ function lockInfoFileState(stats: BigIntStats): LockInfoFileState | null {
|
|
|
253
267
|
size: stats.size,
|
|
254
268
|
mtimeNs: stats.mtimeNs,
|
|
255
269
|
ctimeNs: stats.ctimeNs,
|
|
270
|
+
birthtimeNs,
|
|
256
271
|
nlink: stats.nlink,
|
|
257
272
|
};
|
|
258
273
|
}
|
|
259
274
|
|
|
260
275
|
function sameLockInfoFileState(left: LockInfoFileState, right: LockInfoFileState): boolean {
|
|
276
|
+
const birthtimeMatches =
|
|
277
|
+
left.birthtimeNs === 0n || right.birthtimeNs === 0n || left.birthtimeNs === right.birthtimeNs;
|
|
261
278
|
return (
|
|
262
279
|
left.dev === right.dev &&
|
|
263
280
|
left.ino === right.ino &&
|
|
264
281
|
left.mode === right.mode &&
|
|
265
282
|
left.size === right.size &&
|
|
266
283
|
left.mtimeNs === right.mtimeNs &&
|
|
267
|
-
|
|
284
|
+
birthtimeMatches &&
|
|
268
285
|
left.nlink === right.nlink
|
|
269
286
|
);
|
|
270
287
|
}
|
|
@@ -313,6 +330,7 @@ function fileLockDirIdentityFromPathState(state: LockInfoPathState, bytes: strin
|
|
|
313
330
|
infoSize: String(state.file.size),
|
|
314
331
|
infoMtimeNs: String(state.file.mtimeNs),
|
|
315
332
|
infoCtimeNs: String(state.file.ctimeNs),
|
|
333
|
+
infoBirthtimeNs: String(state.file.birthtimeNs),
|
|
316
334
|
infoSha256: crypto.createHash("sha256").update(bytes).digest("hex"),
|
|
317
335
|
};
|
|
318
336
|
}
|
|
@@ -680,6 +698,8 @@ function sameFileLockTreeAfterPublication(
|
|
|
680
698
|
staged: NativeDirectoryTreeSnapshot,
|
|
681
699
|
published: NativeDirectoryTreeSnapshot,
|
|
682
700
|
): boolean {
|
|
701
|
+
// ctime is intentionally omitted: native snapshots expose no birthtime, and a
|
|
702
|
+
// metadata-only change must not reject an otherwise identical published tree.
|
|
683
703
|
return (
|
|
684
704
|
staged.rootDev === published.rootDev &&
|
|
685
705
|
staged.rootIno === published.rootIno &&
|
|
@@ -695,7 +715,6 @@ function sameFileLockTreeAfterPublication(
|
|
|
695
715
|
entry.nlink === current.nlink &&
|
|
696
716
|
entry.size === current.size &&
|
|
697
717
|
entry.mtimeNs === current.mtimeNs &&
|
|
698
|
-
(entry.relativePath === "" || entry.ctimeNs === current.ctimeNs) &&
|
|
699
718
|
entry.sha256 === current.sha256
|
|
700
719
|
);
|
|
701
720
|
})
|
|
@@ -879,6 +898,7 @@ function isValidNativeNoReplaceResult(value: unknown): value is NativeNoReplaceR
|
|
|
879
898
|
"interrupted",
|
|
880
899
|
"identity_violation",
|
|
881
900
|
"durability_not_provable",
|
|
901
|
+
"sharing_violation",
|
|
882
902
|
"unknown",
|
|
883
903
|
] as const
|
|
884
904
|
).includes(value.reason as never) ||
|
|
@@ -954,25 +974,18 @@ function isValidNativeNoReplaceResult(value: unknown): value is NativeNoReplaceR
|
|
|
954
974
|
function isSuccessfulNativePublication(value: unknown, operation: "primary" | "directory"): boolean {
|
|
955
975
|
if (!isValidNativeNoReplaceResult(value) || !value.ok) return false;
|
|
956
976
|
if (operation === "directory") return value.primitive === "mkdirat_renameat_noreplace";
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
return false;
|
|
966
|
-
}
|
|
977
|
+
// Native code records the primitive it actually invoked in the receipt. That
|
|
978
|
+
// primitive is the producer-platform evidence; process.platform is only ambient
|
|
979
|
+
// capability metadata and may be overridden by a coordinator discovery test.
|
|
980
|
+
return (
|
|
981
|
+
value.primitive === "renameat2_noreplace" ||
|
|
982
|
+
value.primitive === "renameatx_np_excl" ||
|
|
983
|
+
value.primitive === "windows_rename_noreplace"
|
|
984
|
+
);
|
|
967
985
|
}
|
|
968
986
|
|
|
969
987
|
function isCommittedDirectoryVerificationFailure(value: unknown): value is NativeNoReplaceResult {
|
|
970
|
-
return (
|
|
971
|
-
process.platform === "linux" &&
|
|
972
|
-
isValidNativeNoReplaceResult(value) &&
|
|
973
|
-
!value.ok &&
|
|
974
|
-
value.mutationState === "committed"
|
|
975
|
-
);
|
|
988
|
+
return isValidNativeNoReplaceResult(value) && !value.ok && value.mutationState === "committed";
|
|
976
989
|
}
|
|
977
990
|
|
|
978
991
|
/**
|
|
@@ -996,6 +1009,35 @@ function isPreMutationUnsupportedRenameResult(value: unknown): value is NativeNo
|
|
|
996
1009
|
return true;
|
|
997
1010
|
}
|
|
998
1011
|
|
|
1012
|
+
function isPreMutationSharingViolation(value: unknown): value is NativeNoReplaceResult {
|
|
1013
|
+
return (
|
|
1014
|
+
isValidNativeNoReplaceResult(value) &&
|
|
1015
|
+
!value.ok &&
|
|
1016
|
+
value.code === "sharing_violation" &&
|
|
1017
|
+
value.mutationState === "not_committed" &&
|
|
1018
|
+
value.durabilityState === "not_attempted" &&
|
|
1019
|
+
value.reason === "sharing_violation" &&
|
|
1020
|
+
value.phase === "rename"
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
async function publishNoReplaceWithSharingRetry(
|
|
1025
|
+
publish: (sourcePath: string, destinationPath: string) => Promise<NativeNoReplaceResult>,
|
|
1026
|
+
sourcePath: string,
|
|
1027
|
+
destinationPath: string,
|
|
1028
|
+
): Promise<NativeNoReplaceResult> {
|
|
1029
|
+
let result = await publish(sourcePath, destinationPath);
|
|
1030
|
+
for (
|
|
1031
|
+
let attempt = 1;
|
|
1032
|
+
attempt < PUBLICATION_SHARING_RETRY_ATTEMPTS && isPreMutationSharingViolation(result);
|
|
1033
|
+
attempt++
|
|
1034
|
+
) {
|
|
1035
|
+
await Bun.sleep(PUBLICATION_SHARING_RETRY_DELAY_MS * attempt);
|
|
1036
|
+
result = await publish(sourcePath, destinationPath);
|
|
1037
|
+
}
|
|
1038
|
+
return result;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
999
1041
|
async function localLockKey(lockPath: string): Promise<string> {
|
|
1000
1042
|
try {
|
|
1001
1043
|
return normalizeLockKey(await fs.realpath(lockPath));
|
|
@@ -1034,7 +1076,14 @@ type LockStaleSnapshot =
|
|
|
1034
1076
|
| { stale: false }
|
|
1035
1077
|
| { stale: true; owner: FileLockOwnerToken; identity: GenericFileLockDirIdentity };
|
|
1036
1078
|
|
|
1037
|
-
/**
|
|
1079
|
+
/**
|
|
1080
|
+
* Identity evidence carried by the generic stale verdict into a later removal.
|
|
1081
|
+
*
|
|
1082
|
+
* `ctimeNs` is a mutable metadata-change time on every supported filesystem, so
|
|
1083
|
+
* it is retained for diagnostics/legacy consumers but is not part of the lock
|
|
1084
|
+
* identity predicate. `infoBirthtimeNs` is the creation time that stays bound
|
|
1085
|
+
* to the file object.
|
|
1086
|
+
*/
|
|
1038
1087
|
export interface GenericFileLockDirIdentity {
|
|
1039
1088
|
rootDev: string;
|
|
1040
1089
|
rootIno: string;
|
|
@@ -1044,23 +1093,34 @@ export interface GenericFileLockDirIdentity {
|
|
|
1044
1093
|
infoSize: string;
|
|
1045
1094
|
infoMtimeNs: string;
|
|
1046
1095
|
infoCtimeNs: string;
|
|
1096
|
+
infoBirthtimeNs: string;
|
|
1047
1097
|
infoSha256: string;
|
|
1048
1098
|
}
|
|
1049
1099
|
|
|
1050
|
-
function
|
|
1100
|
+
function sameStableFileLockIdentity(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1051
1101
|
return (
|
|
1052
1102
|
left.rootDev === right.rootDev &&
|
|
1053
1103
|
left.rootIno === right.rootIno &&
|
|
1054
1104
|
left.infoDev === right.infoDev &&
|
|
1055
1105
|
left.infoIno === right.infoIno &&
|
|
1106
|
+
left.infoBirthtimeNs === right.infoBirthtimeNs
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/** Content/topology evidence kept separate from the stable file identity. */
|
|
1111
|
+
function sameFileLockContentEvidence(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1112
|
+
return (
|
|
1056
1113
|
left.infoNlink === right.infoNlink &&
|
|
1057
1114
|
left.infoSize === right.infoSize &&
|
|
1058
1115
|
left.infoMtimeNs === right.infoMtimeNs &&
|
|
1059
|
-
left.infoCtimeNs === right.infoCtimeNs &&
|
|
1060
1116
|
left.infoSha256 === right.infoSha256
|
|
1061
1117
|
);
|
|
1062
1118
|
}
|
|
1063
1119
|
|
|
1120
|
+
function sameGenericFileLockDirIdentity(left: GenericFileLockDirIdentity, right: GenericFileLockDirIdentity): boolean {
|
|
1121
|
+
return sameStableFileLockIdentity(left, right) && sameFileLockContentEvidence(left, right);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1064
1124
|
let nativeExactRemovalUsable: boolean | undefined;
|
|
1065
1125
|
let nativeExactRemovalProbePromise: Promise<boolean> | undefined;
|
|
1066
1126
|
|
|
@@ -1171,26 +1231,54 @@ async function removeVerifiedOwnedLockDirWithoutNative(
|
|
|
1171
1231
|
return "cleanup_failed";
|
|
1172
1232
|
}
|
|
1173
1233
|
const current = await captureFileLockDirIdentity(lockDir);
|
|
1174
|
-
if (!current || !
|
|
1234
|
+
if (!current || !sameStableFileLockIdentity(current, expected)) return "owner_changed";
|
|
1175
1235
|
const captured = nativeFileLockBindings().snapshotDirectoryTree(lockDir);
|
|
1176
1236
|
if (!captured.ok || !captured.snapshot) return "owner_changed";
|
|
1177
1237
|
const infoEntry = captured.snapshot.entries.find(entry => entry.relativePath === "info");
|
|
1178
1238
|
if (
|
|
1179
|
-
captured.snapshot.rootDev !== expected.rootDev ||
|
|
1180
|
-
captured.snapshot.rootIno !== expected.rootIno ||
|
|
1181
1239
|
!infoEntry ||
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
infoEntry
|
|
1240
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1241
|
+
captured.snapshot.rootDev,
|
|
1242
|
+
captured.snapshot.rootIno,
|
|
1243
|
+
infoEntry,
|
|
1244
|
+
expected,
|
|
1245
|
+
) ||
|
|
1246
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expected)
|
|
1189
1247
|
)
|
|
1190
1248
|
return "owner_changed";
|
|
1191
1249
|
return await removeVerifiedLockDirWithoutNative(lockDir, captured.snapshot, owner);
|
|
1192
1250
|
}
|
|
1193
1251
|
|
|
1252
|
+
function nativeFileLockInfoMatchesStableIdentity(
|
|
1253
|
+
rootDev: string,
|
|
1254
|
+
rootIno: string,
|
|
1255
|
+
infoEntry: NativeDirectoryTreeSnapshot["entries"][number],
|
|
1256
|
+
expected: GenericFileLockDirIdentity,
|
|
1257
|
+
): boolean {
|
|
1258
|
+
return (
|
|
1259
|
+
rootDev === expected.rootDev &&
|
|
1260
|
+
rootIno === expected.rootIno &&
|
|
1261
|
+
infoEntry.dev === expected.infoDev &&
|
|
1262
|
+
infoEntry.ino === expected.infoIno
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function nativeFileLockInfoMatchesContentEvidence(
|
|
1267
|
+
infoEntry: NativeDirectoryTreeSnapshot["entries"][number],
|
|
1268
|
+
expected: GenericFileLockDirIdentity,
|
|
1269
|
+
): boolean {
|
|
1270
|
+
// Native snapshots expose a ctime-shaped field, but ctime is a mutable
|
|
1271
|
+
// metadata-change timestamp on every supported filesystem. The stable file
|
|
1272
|
+
// identity is checked separately; requiring ctime here would reject a
|
|
1273
|
+
// legitimate lock after chmod/ACL/indexer activity.
|
|
1274
|
+
return (
|
|
1275
|
+
infoEntry.nlink === expected.infoNlink &&
|
|
1276
|
+
infoEntry.size === expected.infoSize &&
|
|
1277
|
+
infoEntry.mtimeNs === expected.infoMtimeNs &&
|
|
1278
|
+
infoEntry.sha256 === expected.infoSha256
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1194
1282
|
export type GenericFileLockDirStaleVerdict = { stale: false } | { stale: true; identity: GenericFileLockDirIdentity };
|
|
1195
1283
|
|
|
1196
1284
|
/**
|
|
@@ -1254,17 +1342,17 @@ export async function removeFileLockDirForGc(
|
|
|
1254
1342
|
if (!infoEntry?.sha256) return "owner_changed";
|
|
1255
1343
|
const judgedDigest = crypto.createHash("sha256").update(onDiskBytes).digest("hex");
|
|
1256
1344
|
if (infoEntry.sha256 !== judgedDigest) return "owner_changed";
|
|
1345
|
+
const currentIdentity = await captureFileLockDirIdentity(nativeCapturePath);
|
|
1346
|
+
if (!currentIdentity || !sameStableFileLockIdentity(currentIdentity, expectedIdentity)) return "owner_changed";
|
|
1257
1347
|
if (
|
|
1258
1348
|
!captured.snapshot.rootDev ||
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
infoEntry
|
|
1266
|
-
infoEntry.ctimeNs !== expectedIdentity.infoCtimeNs ||
|
|
1267
|
-
infoEntry.sha256 !== expectedIdentity.infoSha256
|
|
1349
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1350
|
+
captured.snapshot.rootDev,
|
|
1351
|
+
captured.snapshot.rootIno,
|
|
1352
|
+
infoEntry,
|
|
1353
|
+
expectedIdentity,
|
|
1354
|
+
) ||
|
|
1355
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expectedIdentity)
|
|
1268
1356
|
)
|
|
1269
1357
|
return "owner_changed";
|
|
1270
1358
|
let removed: NativeExactUnlinkResult;
|
|
@@ -1636,12 +1724,20 @@ async function tryAcquireLock(
|
|
|
1636
1724
|
renameNoReplacePathAsync,
|
|
1637
1725
|
renameDirectoryNoReplacePathAsync,
|
|
1638
1726
|
};
|
|
1639
|
-
const published = await
|
|
1727
|
+
const published = await publishNoReplaceWithSharingRetry(
|
|
1728
|
+
publication.renameNoReplacePathAsync,
|
|
1729
|
+
canonicalPendingPath,
|
|
1730
|
+
destinationPath,
|
|
1731
|
+
);
|
|
1640
1732
|
let publishedSuccessfully = isSuccessfulNativePublication(published, "primary");
|
|
1641
1733
|
if (published.ok && !publishedSuccessfully)
|
|
1642
1734
|
throw new Error("Failed to publish file lock: invalid primary success receipt.");
|
|
1643
1735
|
if (!published.ok && isPreMutationUnsupportedRenameResult(published)) {
|
|
1644
|
-
const fallback = await
|
|
1736
|
+
const fallback = await publishNoReplaceWithSharingRetry(
|
|
1737
|
+
publication.renameDirectoryNoReplacePathAsync,
|
|
1738
|
+
canonicalPendingPath,
|
|
1739
|
+
destinationPath,
|
|
1740
|
+
);
|
|
1645
1741
|
const fallbackSuccessfully = isSuccessfulNativePublication(fallback, "directory");
|
|
1646
1742
|
if (fallback.ok && !fallbackSuccessfully)
|
|
1647
1743
|
throw new Error("Failed to publish file lock: invalid directory success receipt.");
|
|
@@ -1800,16 +1896,16 @@ async function quarantineReleasedLock(
|
|
|
1800
1896
|
if (!captured.ok || !captured.snapshot) return false;
|
|
1801
1897
|
const infoEntry = captured.snapshot.entries.find(entry => entry.relativePath === "info");
|
|
1802
1898
|
if (!infoEntry?.sha256) return false;
|
|
1899
|
+
const currentIdentity = await captureFileLockDirIdentity(nativeCapturePath);
|
|
1900
|
+
if (!currentIdentity || !sameStableFileLockIdentity(currentIdentity, expectedIdentity)) return false;
|
|
1803
1901
|
if (
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
infoEntry
|
|
1811
|
-
infoEntry.ctimeNs !== expectedIdentity.infoCtimeNs ||
|
|
1812
|
-
infoEntry.sha256 !== expectedIdentity.infoSha256
|
|
1902
|
+
!nativeFileLockInfoMatchesStableIdentity(
|
|
1903
|
+
captured.snapshot.rootDev,
|
|
1904
|
+
captured.snapshot.rootIno,
|
|
1905
|
+
infoEntry,
|
|
1906
|
+
expectedIdentity,
|
|
1907
|
+
) ||
|
|
1908
|
+
!nativeFileLockInfoMatchesContentEvidence(infoEntry, expectedIdentity)
|
|
1813
1909
|
)
|
|
1814
1910
|
return false;
|
|
1815
1911
|
// Bind the owner generation to the snapshot before exact removal. A successor
|