@animalabs/agent-framework 0.22.1 → 0.22.3
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/README.md +4 -2
- package/dist/src/agent.d.ts +266 -28
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +539 -104
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts +41 -0
- package/dist/src/api/mcp-server-core.d.ts.map +1 -0
- package/dist/src/api/mcp-server-core.js +593 -0
- package/dist/src/api/mcp-server-core.js.map +1 -0
- package/dist/src/api/mcp-server.d.ts +2 -36
- package/dist/src/api/mcp-server.d.ts.map +1 -1
- package/dist/src/api/mcp-server.js +15 -595
- package/dist/src/api/mcp-server.js.map +1 -1
- package/dist/src/api/server.d.ts +9 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +55 -27
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/api/types.d.ts +10 -2
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/branch-names.d.ts +14 -0
- package/dist/src/branch-names.d.ts.map +1 -0
- package/dist/src/branch-names.js +22 -0
- package/dist/src/branch-names.js.map +1 -0
- package/dist/src/closest-names.d.ts +28 -0
- package/dist/src/closest-names.d.ts.map +1 -0
- package/dist/src/closest-names.js +98 -0
- package/dist/src/closest-names.js.map +1 -0
- package/dist/src/code-execution/py-runner.d.ts +16 -5
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +186 -74
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +49 -3
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts +12 -1
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +21 -3
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/config-checks.d.ts +28 -0
- package/dist/src/config-checks.d.ts.map +1 -0
- package/dist/src/config-checks.js +52 -0
- package/dist/src/config-checks.js.map +1 -0
- package/dist/src/deadline-timer.d.ts +21 -0
- package/dist/src/deadline-timer.d.ts.map +1 -0
- package/dist/src/deadline-timer.js +43 -0
- package/dist/src/deadline-timer.js.map +1 -0
- package/dist/src/error-message.d.ts +30 -0
- package/dist/src/error-message.d.ts.map +1 -0
- package/dist/src/error-message.js +50 -0
- package/dist/src/error-message.js.map +1 -0
- package/dist/src/framework.d.ts +1212 -192
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +6686 -1835
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +8 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +27 -3
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/gate-script.d.ts.map +1 -1
- package/dist/src/gate/gate-script.js.map +1 -1
- package/dist/src/index.d.ts +5 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +170 -13
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +499 -258
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js +91 -30
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +19 -3
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +23 -8
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +20 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -0
- package/dist/src/mcpl/convert-block.js +89 -0
- package/dist/src/mcpl/convert-block.js.map +1 -0
- package/dist/src/mcpl/errors.d.ts +13 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -1
- package/dist/src/mcpl/errors.js +28 -0
- package/dist/src/mcpl/errors.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js +4 -3
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +83 -72
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +114 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
- package/dist/src/mcpl/inbound-source.js +83 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -0
- package/dist/src/mcpl/index.d.ts +3 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +15 -11
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +153 -84
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +54 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -0
- package/dist/src/mcpl/log-value.js +109 -0
- package/dist/src/mcpl/log-value.js.map +1 -0
- package/dist/src/mcpl/prose-stream-router.d.ts +6 -6
- package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
- package/dist/src/mcpl/prose-stream-router.js +4 -4
- package/dist/src/mcpl/prose-stream-router.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +64 -7
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +121 -24
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +38 -8
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +77 -78
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +72 -30
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +49 -14
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +74 -21
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/refusal-lines.d.ts +37 -0
- package/dist/src/mcpl/refusal-lines.d.ts.map +1 -0
- package/dist/src/mcpl/refusal-lines.js +61 -0
- package/dist/src/mcpl/refusal-lines.js.map +1 -0
- package/dist/src/mcpl/scope-manager.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +107 -12
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +470 -139
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts +10 -1
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +14 -3
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
- package/dist/src/mcpl/skip-reply-wake.js +55 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
- package/dist/src/mcpl/tool-classes.d.ts +1 -1
- package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
- package/dist/src/mcpl/tool-classes.js +3 -2
- package/dist/src/mcpl/tool-classes.js.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +74 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +209 -22
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +43 -28
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/mcpl/visible-content.d.ts +15 -0
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +25 -0
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +19 -1
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +54 -25
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +1 -1
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
- package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
- package/dist/src/modules/discord/discord-js-client.js +25 -9
- package/dist/src/modules/discord/discord-js-client.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +29 -3
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +383 -145
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/discord/types.d.ts +14 -1
- package/dist/src/modules/discord/types.d.ts.map +1 -1
- package/dist/src/modules/health/index.d.ts.map +1 -1
- package/dist/src/modules/health/index.js +2 -1
- package/dist/src/modules/health/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +3 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +359 -127
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +28 -1
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +177 -32
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +10 -0
- package/dist/src/modules/unknown-tool.d.ts.map +1 -0
- package/dist/src/modules/unknown-tool.js +17 -0
- package/dist/src/modules/unknown-tool.js.map +1 -0
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +54 -6
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +93 -27
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +64 -6
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +291 -44
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +127 -27
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +821 -248
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +117 -15
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +436 -51
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +75 -8
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +576 -68
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +42 -3
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +7 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js +28 -4
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/prose-drafts.d.ts +240 -0
- package/dist/src/prose-drafts.d.ts.map +1 -0
- package/dist/src/prose-drafts.js +362 -0
- package/dist/src/prose-drafts.js.map +1 -0
- package/dist/src/prose-segments.d.ts +21 -2
- package/dist/src/prose-segments.d.ts.map +1 -1
- package/dist/src/prose-segments.js +46 -9
- package/dist/src/prose-segments.js.map +1 -1
- package/dist/src/provider-waits.d.ts.map +1 -1
- package/dist/src/provider-waits.js.map +1 -1
- package/dist/src/queue.d.ts.map +1 -1
- package/dist/src/record-journal.d.ts.map +1 -1
- package/dist/src/record-journal.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +1 -0
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +32 -25
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -1
- package/dist/src/runtime/liveness-watchdog.js.map +1 -1
- package/dist/src/safe-slice.d.ts +5 -1
- package/dist/src/safe-slice.d.ts.map +1 -1
- package/dist/src/safe-slice.js +9 -1
- package/dist/src/safe-slice.js.map +1 -1
- package/dist/src/shutdown.d.ts.map +1 -1
- package/dist/src/shutdown.js.map +1 -1
- package/dist/src/stored-removal.d.ts +73 -0
- package/dist/src/stored-removal.d.ts.map +1 -0
- package/dist/src/stored-removal.js +100 -0
- package/dist/src/stored-removal.js.map +1 -0
- package/dist/src/thinking-token-stamp.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts +87 -19
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +135 -32
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts +9 -0
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +257 -60
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +7 -10
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +32 -3
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +106 -19
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +25 -1
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +260 -65
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +1 -1
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/types/agent.d.ts +59 -11
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +17 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +31 -5
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/inference-log.d.ts +1 -1
- package/dist/src/types/inference-log.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +30 -7
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +151 -11
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +5 -0
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +35 -8
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +10 -9
- package/src/agent.ts +572 -105
- package/src/api/mcp-server-core.ts +681 -0
- package/src/api/mcp-server.ts +16 -685
- package/src/api/server.ts +55 -30
- package/src/api/types.ts +10 -2
- package/src/branch-names.ts +19 -0
- package/src/closest-names.ts +94 -0
- package/src/code-execution/py-runner.ts +200 -76
- package/src/code-execution/runtime-py.ts +49 -3
- package/src/code-execution/tool-definition.ts +28 -4
- package/src/config-checks.ts +48 -0
- package/src/deadline-timer.ts +44 -0
- package/src/error-message.ts +48 -0
- package/src/framework.ts +7158 -1936
- package/src/gate/event-gate.ts +28 -3
- package/src/index.ts +12 -3
- package/src/mcpl/channel-registry.ts +615 -289
- package/src/mcpl/checkpoint-manager.ts +104 -29
- package/src/mcpl/conversation-router.ts +28 -8
- package/src/mcpl/convert-block.ts +97 -0
- package/src/mcpl/errors.ts +28 -0
- package/src/mcpl/feature-set-manager.ts +4 -3
- package/src/mcpl/hook-orchestrator.ts +84 -77
- package/src/mcpl/inbound-source.ts +156 -0
- package/src/mcpl/index.ts +10 -1
- package/src/mcpl/inference-router.ts +174 -99
- package/src/mcpl/log-value.ts +116 -0
- package/src/mcpl/prose-stream-router.ts +6 -6
- package/src/mcpl/push-coalescer.ts +124 -24
- package/src/mcpl/push-handler.ts +86 -84
- package/src/mcpl/reference-fetcher.ts +71 -26
- package/src/mcpl/references.ts +81 -22
- package/src/mcpl/refusal-lines.ts +59 -0
- package/src/mcpl/server-connection.ts +496 -142
- package/src/mcpl/server-registry.ts +15 -4
- package/src/mcpl/skip-reply-wake.ts +73 -0
- package/src/mcpl/tool-classes.ts +3 -2
- package/src/mcpl/transport.ts +219 -26
- package/src/mcpl/types.ts +18 -3
- package/src/mcpl/visible-content.ts +27 -0
- package/src/module-registry.ts +58 -23
- package/src/modules/api/index.ts +1 -1
- package/src/modules/discord/discord-js-client.ts +26 -10
- package/src/modules/discord/index.ts +395 -160
- package/src/modules/discord/types.ts +15 -2
- package/src/modules/health/index.ts +2 -1
- package/src/modules/history/index.ts +410 -120
- package/src/modules/history/semantic.ts +189 -32
- package/src/modules/unknown-tool.ts +16 -0
- package/src/modules/workspace/disk-agreement.ts +125 -21
- package/src/modules/workspace/effects.ts +279 -35
- package/src/modules/workspace/index.ts +841 -261
- package/src/modules/workspace/observe.ts +456 -56
- package/src/modules/workspace/reconcile.ts +688 -76
- package/src/modules/workspace/types.ts +41 -2
- package/src/modules/workspace/watcher.ts +27 -4
- package/src/prose-drafts.ts +481 -0
- package/src/prose-segments.ts +51 -8
- package/src/recovery/offline-branch.ts +36 -29
- package/src/safe-slice.ts +9 -1
- package/src/stored-removal.ts +126 -0
- package/src/tool-image-ledger.ts +153 -34
- package/src/tool-presentation.ts +224 -40
- package/src/tool-result-guard.ts +7 -8
- package/src/tool-result-history.ts +124 -20
- package/src/tune-out/coordinator.ts +259 -65
- package/src/types/agent.ts +59 -13
- package/src/types/events.ts +17 -0
- package/src/types/framework.ts +31 -5
- package/src/types/inference-log.ts +1 -1
- package/src/types/module.ts +31 -7
- package/src/types/trace.ts +158 -12
- package/src/usage/usage-tracker.ts +32 -8
- package/dist/test/activation-request-sanitize.test.d.ts +0 -2
- package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
- package/dist/test/activation-request-sanitize.test.js +0 -89
- package/dist/test/activation-request-sanitize.test.js.map +0 -1
- package/dist/test/agent-cache-ttl.test.d.ts +0 -2
- package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
- package/dist/test/agent-cache-ttl.test.js +0 -41
- package/dist/test/agent-cache-ttl.test.js.map +0 -1
- package/dist/test/agent-runtime-settings.test.d.ts +0 -2
- package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
- package/dist/test/agent-runtime-settings.test.js +0 -462
- package/dist/test/agent-runtime-settings.test.js.map +0 -1
- package/dist/test/api-admin-gate.test.d.ts +0 -2
- package/dist/test/api-admin-gate.test.d.ts.map +0 -1
- package/dist/test/api-admin-gate.test.js +0 -116
- package/dist/test/api-admin-gate.test.js.map +0 -1
- package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
- package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
- package/dist/test/assistant-persist-refusal.test.js +0 -63
- package/dist/test/assistant-persist-refusal.test.js.map +0 -1
- package/dist/test/batched-wake-locus.test.d.ts +0 -2
- package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
- package/dist/test/batched-wake-locus.test.js +0 -166
- package/dist/test/batched-wake-locus.test.js.map +0 -1
- package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
- package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
- package/dist/test/busy-agent-scheduler.test.js +0 -92
- package/dist/test/busy-agent-scheduler.test.js.map +0 -1
- package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
- package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
- package/dist/test/channel-incoming-targeting.test.js +0 -81
- package/dist/test/channel-incoming-targeting.test.js.map +0 -1
- package/dist/test/channel-label-history.test.d.ts +0 -2
- package/dist/test/channel-label-history.test.d.ts.map +0 -1
- package/dist/test/channel-label-history.test.js +0 -424
- package/dist/test/channel-label-history.test.js.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
- package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.js +0 -47
- package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
- package/dist/test/channel-registry-routing.test.d.ts +0 -2
- package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-routing.test.js +0 -446
- package/dist/test/channel-registry-routing.test.js.map +0 -1
- package/dist/test/channel-registry-typing.test.d.ts +0 -2
- package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-typing.test.js +0 -91
- package/dist/test/channel-registry-typing.test.js.map +0 -1
- package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
- package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
- package/dist/test/channels-changed-respond-first.test.js +0 -74
- package/dist/test/channels-changed-respond-first.test.js.map +0 -1
- package/dist/test/checkpoint-attribution.test.d.ts +0 -2
- package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
- package/dist/test/checkpoint-attribution.test.js +0 -200
- package/dist/test/checkpoint-attribution.test.js.map +0 -1
- package/dist/test/code-execution.test.d.ts +0 -11
- package/dist/test/code-execution.test.d.ts.map +0 -1
- package/dist/test/code-execution.test.js +0 -1272
- package/dist/test/code-execution.test.js.map +0 -1
- package/dist/test/component-defaults.test.d.ts +0 -2
- package/dist/test/component-defaults.test.d.ts.map +0 -1
- package/dist/test/component-defaults.test.js +0 -54
- package/dist/test/component-defaults.test.js.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
- package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
- package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
- package/dist/test/conversation-router.test.d.ts +0 -2
- package/dist/test/conversation-router.test.d.ts.map +0 -1
- package/dist/test/conversation-router.test.js +0 -174
- package/dist/test/conversation-router.test.js.map +0 -1
- package/dist/test/conversation-routing.test.d.ts +0 -7
- package/dist/test/conversation-routing.test.d.ts.map +0 -1
- package/dist/test/conversation-routing.test.js +0 -387
- package/dist/test/conversation-routing.test.js.map +0 -1
- package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
- package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
- package/dist/test/deferred-wake-integrity.test.js +0 -320
- package/dist/test/deferred-wake-integrity.test.js.map +0 -1
- package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
- package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
- package/dist/test/discord-awareness-outbox.test.js +0 -267
- package/dist/test/discord-awareness-outbox.test.js.map +0 -1
- package/dist/test/discord-history-delete-window.test.d.ts +0 -2
- package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
- package/dist/test/discord-history-delete-window.test.js +0 -81
- package/dist/test/discord-history-delete-window.test.js.map +0 -1
- package/dist/test/discord-history-sync.test.d.ts +0 -2
- package/dist/test/discord-history-sync.test.d.ts.map +0 -1
- package/dist/test/discord-history-sync.test.js +0 -56
- package/dist/test/discord-history-sync.test.js.map +0 -1
- package/dist/test/ephemeral-settle.test.d.ts +0 -2
- package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
- package/dist/test/ephemeral-settle.test.js +0 -354
- package/dist/test/ephemeral-settle.test.js.map +0 -1
- package/dist/test/event-gate-passthrough.test.d.ts +0 -15
- package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
- package/dist/test/event-gate-passthrough.test.js +0 -289
- package/dist/test/event-gate-passthrough.test.js.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
- package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.js +0 -137
- package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
- package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
- package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
- package/dist/test/event-gate-rate-limit.test.js +0 -627
- package/dist/test/event-gate-rate-limit.test.js.map +0 -1
- package/dist/test/event-gate-script.test.d.ts +0 -2
- package/dist/test/event-gate-script.test.d.ts.map +0 -1
- package/dist/test/event-gate-script.test.js +0 -95
- package/dist/test/event-gate-script.test.js.map +0 -1
- package/dist/test/event-gate-selfwake.test.d.ts +0 -15
- package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
- package/dist/test/event-gate-selfwake.test.js +0 -125
- package/dist/test/event-gate-selfwake.test.js.map +0 -1
- package/dist/test/event-gate-tags.test.d.ts +0 -2
- package/dist/test/event-gate-tags.test.d.ts.map +0 -1
- package/dist/test/event-gate-tags.test.js +0 -76
- package/dist/test/event-gate-tags.test.js.map +0 -1
- package/dist/test/event-gate.test.d.ts +0 -2
- package/dist/test/event-gate.test.d.ts.map +0 -1
- package/dist/test/event-gate.test.js +0 -919
- package/dist/test/event-gate.test.js.map +0 -1
- package/dist/test/explicit-prose-routing.test.d.ts +0 -11
- package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
- package/dist/test/explicit-prose-routing.test.js +0 -1394
- package/dist/test/explicit-prose-routing.test.js.map +0 -1
- package/dist/test/framework.test.d.ts +0 -5
- package/dist/test/framework.test.d.ts.map +0 -1
- package/dist/test/framework.test.js +0 -1048
- package/dist/test/framework.test.js.map +0 -1
- package/dist/test/gather-context-timeout.test.d.ts +0 -2
- package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
- package/dist/test/gather-context-timeout.test.js +0 -120
- package/dist/test/gather-context-timeout.test.js.map +0 -1
- package/dist/test/health-snapshot.test.d.ts +0 -2
- package/dist/test/health-snapshot.test.d.ts.map +0 -1
- package/dist/test/health-snapshot.test.js +0 -74
- package/dist/test/health-snapshot.test.js.map +0 -1
- package/dist/test/helpers/coalescing-fixture.d.ts +0 -72
- package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-fixture.js +0 -146
- package/dist/test/helpers/coalescing-fixture.js.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
- package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.js +0 -24
- package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
- package/dist/test/helpers/mock-membrane.d.ts +0 -53
- package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
- package/dist/test/helpers/mock-membrane.js +0 -168
- package/dist/test/helpers/mock-membrane.js.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
- package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.js +0 -143
- package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
- package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.js +0 -156
- package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
- package/dist/test/history-module-overview.test.d.ts +0 -2
- package/dist/test/history-module-overview.test.d.ts.map +0 -1
- package/dist/test/history-module-overview.test.js +0 -711
- package/dist/test/history-module-overview.test.js.map +0 -1
- package/dist/test/history-module-realstore.test.d.ts +0 -2
- package/dist/test/history-module-realstore.test.d.ts.map +0 -1
- package/dist/test/history-module-realstore.test.js +0 -363
- package/dist/test/history-module-realstore.test.js.map +0 -1
- package/dist/test/history-module-semantic.test.d.ts +0 -2
- package/dist/test/history-module-semantic.test.d.ts.map +0 -1
- package/dist/test/history-module-semantic.test.js +0 -213
- package/dist/test/history-module-semantic.test.js.map +0 -1
- package/dist/test/history-module-ux.test.d.ts +0 -2
- package/dist/test/history-module-ux.test.d.ts.map +0 -1
- package/dist/test/history-module-ux.test.js +0 -304
- package/dist/test/history-module-ux.test.js.map +0 -1
- package/dist/test/history-module.test.d.ts +0 -2
- package/dist/test/history-module.test.d.ts.map +0 -1
- package/dist/test/history-module.test.js +0 -619
- package/dist/test/history-module.test.js.map +0 -1
- package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
- package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
- package/dist/test/history-semantic-review-findings.test.js +0 -338
- package/dist/test/history-semantic-review-findings.test.js.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
- package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.js +0 -109
- package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
- package/dist/test/host-quiesce.test.d.ts +0 -2
- package/dist/test/host-quiesce.test.d.ts.map +0 -1
- package/dist/test/host-quiesce.test.js +0 -863
- package/dist/test/host-quiesce.test.js.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
- package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.js +0 -309
- package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
- package/dist/test/inference-failure-bounds.test.d.ts +0 -2
- package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
- package/dist/test/inference-failure-bounds.test.js +0 -1201
- package/dist/test/inference-failure-bounds.test.js.map +0 -1
- package/dist/test/inference-failure-observability.test.d.ts +0 -2
- package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
- package/dist/test/inference-failure-observability.test.js +0 -84
- package/dist/test/inference-failure-observability.test.js.map +0 -1
- package/dist/test/journal-tool.test.d.ts +0 -2
- package/dist/test/journal-tool.test.d.ts.map +0 -1
- package/dist/test/journal-tool.test.js +0 -33
- package/dist/test/journal-tool.test.js.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
- package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
- package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
- package/dist/test/kv-unified-wiring.test.d.ts +0 -2
- package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
- package/dist/test/kv-unified-wiring.test.js +0 -95
- package/dist/test/kv-unified-wiring.test.js.map +0 -1
- package/dist/test/late-events-after-stop.test.d.ts +0 -2
- package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
- package/dist/test/late-events-after-stop.test.js +0 -122
- package/dist/test/late-events-after-stop.test.js.map +0 -1
- package/dist/test/liveness-watchdog.test.d.ts +0 -2
- package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
- package/dist/test/liveness-watchdog.test.js +0 -94
- package/dist/test/liveness-watchdog.test.js.map +0 -1
- package/dist/test/machine-close-provenance.test.d.ts +0 -2
- package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
- package/dist/test/machine-close-provenance.test.js +0 -116
- package/dist/test/machine-close-provenance.test.js.map +0 -1
- package/dist/test/maintenance-timer.test.d.ts +0 -2
- package/dist/test/maintenance-timer.test.d.ts.map +0 -1
- package/dist/test/maintenance-timer.test.js +0 -265
- package/dist/test/maintenance-timer.test.js.map +0 -1
- package/dist/test/mcpl-access-provider.test.d.ts +0 -2
- package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
- package/dist/test/mcpl-access-provider.test.js +0 -20
- package/dist/test/mcpl-access-provider.test.js.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
- package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.js +0 -769
- package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
- package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
- package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-grant.test.js +0 -111
- package/dist/test/mcpl-capability-grant.test.js.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
- package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.js +0 -266
- package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
- package/dist/test/mcpl-child-env.test.d.ts +0 -2
- package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
- package/dist/test/mcpl-child-env.test.js +0 -158
- package/dist/test/mcpl-child-env.test.js.map +0 -1
- package/dist/test/mcpl-coalescing.test.d.ts +0 -2
- package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
- package/dist/test/mcpl-coalescing.test.js +0 -1125
- package/dist/test/mcpl-coalescing.test.js.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
- package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.js +0 -452
- package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
- package/dist/test/mcpl-empty-content.test.d.ts +0 -2
- package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
- package/dist/test/mcpl-empty-content.test.js +0 -368
- package/dist/test/mcpl-empty-content.test.js.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
- package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
- package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
- package/dist/test/mcpl-list-status.test.d.ts +0 -2
- package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
- package/dist/test/mcpl-list-status.test.js +0 -82
- package/dist/test/mcpl-list-status.test.js.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
- package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.js +0 -178
- package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
- package/dist/test/mcpl-push-convert.test.d.ts +0 -2
- package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
- package/dist/test/mcpl-push-convert.test.js +0 -42
- package/dist/test/mcpl-push-convert.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.js +0 -144
- package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +0 -236
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.js +0 -427
- package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
- package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fields.test.js +0 -149
- package/dist/test/mcpl-reference-fields.test.js.map +0 -1
- package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
- package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
- package/dist/test/mcpl-request-timeout.test.js +0 -138
- package/dist/test/mcpl-request-timeout.test.js.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
- package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
- package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.js +0 -147
- package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
- package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
- package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-classes.test.js +0 -80
- package/dist/test/mcpl-tool-classes.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
- package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
- package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
- package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
- package/dist/test/mcpl-ws-transport.test.js +0 -258
- package/dist/test/mcpl-ws-transport.test.js.map +0 -1
- package/dist/test/module-context-integration.test.d.ts +0 -18
- package/dist/test/module-context-integration.test.d.ts.map +0 -1
- package/dist/test/module-context-integration.test.js +0 -181
- package/dist/test/module-context-integration.test.js.map +0 -1
- package/dist/test/offline-recovery-branch.test.d.ts +0 -2
- package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
- package/dist/test/offline-recovery-branch.test.js +0 -226
- package/dist/test/offline-recovery-branch.test.js.map +0 -1
- package/dist/test/operator-surgery.test.d.ts +0 -2
- package/dist/test/operator-surgery.test.d.ts.map +0 -1
- package/dist/test/operator-surgery.test.js +0 -398
- package/dist/test/operator-surgery.test.js.map +0 -1
- package/dist/test/ops-alert.test.d.ts +0 -2
- package/dist/test/ops-alert.test.d.ts.map +0 -1
- package/dist/test/ops-alert.test.js +0 -153
- package/dist/test/ops-alert.test.js.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
- package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.js +0 -197
- package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
- package/dist/test/per-agent-delivery.test.d.ts +0 -2
- package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
- package/dist/test/per-agent-delivery.test.js +0 -108
- package/dist/test/per-agent-delivery.test.js.map +0 -1
- package/dist/test/physical-window-restart.test.d.ts +0 -14
- package/dist/test/physical-window-restart.test.d.ts.map +0 -1
- package/dist/test/physical-window-restart.test.js +0 -222
- package/dist/test/physical-window-restart.test.js.map +0 -1
- package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
- package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/placed-reaction-baseline.test.js +0 -312
- package/dist/test/placed-reaction-baseline.test.js.map +0 -1
- package/dist/test/present-while-acting.test.d.ts +0 -19
- package/dist/test/present-while-acting.test.d.ts.map +0 -1
- package/dist/test/present-while-acting.test.js +0 -706
- package/dist/test/present-while-acting.test.js.map +0 -1
- package/dist/test/prose-segments.test.d.ts +0 -2
- package/dist/test/prose-segments.test.d.ts.map +0 -1
- package/dist/test/prose-segments.test.js +0 -52
- package/dist/test/prose-segments.test.js.map +0 -1
- package/dist/test/prose-stream-router.test.d.ts +0 -2
- package/dist/test/prose-stream-router.test.d.ts.map +0 -1
- package/dist/test/prose-stream-router.test.js +0 -171
- package/dist/test/prose-stream-router.test.js.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
- package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.js +0 -435
- package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
- package/dist/test/provider-waits.test.d.ts +0 -2
- package/dist/test/provider-waits.test.d.ts.map +0 -1
- package/dist/test/provider-waits.test.js +0 -2196
- package/dist/test/provider-waits.test.js.map +0 -1
- package/dist/test/puppet-tool-call.test.d.ts +0 -2
- package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
- package/dist/test/puppet-tool-call.test.js +0 -224
- package/dist/test/puppet-tool-call.test.js.map +0 -1
- package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
- package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
- package/dist/test/puppet-turn-reservation.test.js +0 -139
- package/dist/test/puppet-turn-reservation.test.js.map +0 -1
- package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
- package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
- package/dist/test/reaction-baseline-platform.test.js +0 -124
- package/dist/test/reaction-baseline-platform.test.js.map +0 -1
- package/dist/test/record-journal.test.d.ts +0 -6
- package/dist/test/record-journal.test.d.ts.map +0 -1
- package/dist/test/record-journal.test.js +0 -269
- package/dist/test/record-journal.test.js.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
- package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.js +0 -81
- package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
- package/dist/test/refusal-rewind.test.d.ts +0 -2
- package/dist/test/refusal-rewind.test.d.ts.map +0 -1
- package/dist/test/refusal-rewind.test.js +0 -108
- package/dist/test/refusal-rewind.test.js.map +0 -1
- package/dist/test/refusal-single-call.test.d.ts +0 -2
- package/dist/test/refusal-single-call.test.d.ts.map +0 -1
- package/dist/test/refusal-single-call.test.js +0 -177
- package/dist/test/refusal-single-call.test.js.map +0 -1
- package/dist/test/release-changelog.test.d.ts +0 -2
- package/dist/test/release-changelog.test.d.ts.map +0 -1
- package/dist/test/release-changelog.test.js +0 -159
- package/dist/test/release-changelog.test.js.map +0 -1
- package/dist/test/same-round-think-policy.test.d.ts +0 -2
- package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
- package/dist/test/same-round-think-policy.test.js +0 -853
- package/dist/test/same-round-think-policy.test.js.map +0 -1
- package/dist/test/save-recent-image.test.d.ts +0 -26
- package/dist/test/save-recent-image.test.d.ts.map +0 -1
- package/dist/test/save-recent-image.test.js +0 -974
- package/dist/test/save-recent-image.test.js.map +0 -1
- package/dist/test/shutdown-errors.test.d.ts +0 -2
- package/dist/test/shutdown-errors.test.d.ts.map +0 -1
- package/dist/test/shutdown-errors.test.js +0 -662
- package/dist/test/shutdown-errors.test.js.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
- package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.js +0 -451
- package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
- package/dist/test/silent-heartbeat.test.d.ts +0 -2
- package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat.test.js +0 -165
- package/dist/test/silent-heartbeat.test.js.map +0 -1
- package/dist/test/state-scaling-e2e.test.d.ts +0 -22
- package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
- package/dist/test/state-scaling-e2e.test.js +0 -206
- package/dist/test/state-scaling-e2e.test.js.map +0 -1
- package/dist/test/state-scaling.test.d.ts +0 -12
- package/dist/test/state-scaling.test.d.ts.map +0 -1
- package/dist/test/state-scaling.test.js +0 -251
- package/dist/test/state-scaling.test.js.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
- package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.js +0 -672
- package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
- package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
- package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
- package/dist/test/surgery-marks-receipt.test.js +0 -540
- package/dist/test/surgery-marks-receipt.test.js.map +0 -1
- package/dist/test/thinking-token-stamp.test.d.ts +0 -12
- package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
- package/dist/test/thinking-token-stamp.test.js +0 -129
- package/dist/test/thinking-token-stamp.test.js.map +0 -1
- package/dist/test/timezone.test.d.ts +0 -2
- package/dist/test/timezone.test.d.ts.map +0 -1
- package/dist/test/timezone.test.js +0 -18
- package/dist/test/timezone.test.js.map +0 -1
- package/dist/test/tool-batch-hook.test.d.ts +0 -8
- package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
- package/dist/test/tool-batch-hook.test.js +0 -275
- package/dist/test/tool-batch-hook.test.js.map +0 -1
- package/dist/test/tool-policy.test.d.ts +0 -2
- package/dist/test/tool-policy.test.d.ts.map +0 -1
- package/dist/test/tool-policy.test.js +0 -51
- package/dist/test/tool-policy.test.js.map +0 -1
- package/dist/test/tool-presentation.test.d.ts +0 -2
- package/dist/test/tool-presentation.test.d.ts.map +0 -1
- package/dist/test/tool-presentation.test.js +0 -268
- package/dist/test/tool-presentation.test.js.map +0 -1
- package/dist/test/tool-result-content.test.d.ts +0 -2
- package/dist/test/tool-result-content.test.d.ts.map +0 -1
- package/dist/test/tool-result-content.test.js +0 -37
- package/dist/test/tool-result-content.test.js.map +0 -1
- package/dist/test/tool-result-guard.test.d.ts +0 -2
- package/dist/test/tool-result-guard.test.d.ts.map +0 -1
- package/dist/test/tool-result-guard.test.js +0 -3607
- package/dist/test/tool-result-guard.test.js.map +0 -1
- package/dist/test/tool-result-history.test.d.ts +0 -7
- package/dist/test/tool-result-history.test.d.ts.map +0 -1
- package/dist/test/tool-result-history.test.js +0 -156
- package/dist/test/tool-result-history.test.js.map +0 -1
- package/dist/test/tool-result-spill.test.d.ts +0 -13
- package/dist/test/tool-result-spill.test.d.ts.map +0 -1
- package/dist/test/tool-result-spill.test.js +0 -586
- package/dist/test/tool-result-spill.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
- package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
- package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
- package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.js +0 -129
- package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
- package/dist/test/trunk-channel-routing.test.d.ts +0 -19
- package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
- package/dist/test/trunk-channel-routing.test.js +0 -329
- package/dist/test/trunk-channel-routing.test.js.map +0 -1
- package/dist/test/tune-out-e2e.test.d.ts +0 -2
- package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
- package/dist/test/tune-out-e2e.test.js +0 -142
- package/dist/test/tune-out-e2e.test.js.map +0 -1
- package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
- package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
- package/dist/test/tune-out-gate-composition.test.js +0 -221
- package/dist/test/tune-out-gate-composition.test.js.map +0 -1
- package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
- package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
- package/dist/test/tune-out-lifecycle.test.js +0 -121
- package/dist/test/tune-out-lifecycle.test.js.map +0 -1
- package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
- package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
- package/dist/test/turn-trigger-provenance.test.js +0 -137
- package/dist/test/turn-trigger-provenance.test.js.map +0 -1
- package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
- package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
- package/dist/test/unconvertible-tool-result.test.js +0 -358
- package/dist/test/unconvertible-tool-result.test.js.map +0 -1
- package/dist/test/usage-accounting.test.d.ts +0 -2
- package/dist/test/usage-accounting.test.d.ts.map +0 -1
- package/dist/test/usage-accounting.test.js +0 -13
- package/dist/test/usage-accounting.test.js.map +0 -1
- package/dist/test/usage-tracker.test.d.ts +0 -2
- package/dist/test/usage-tracker.test.d.ts.map +0 -1
- package/dist/test/usage-tracker.test.js +0 -129
- package/dist/test/usage-tracker.test.js.map +0 -1
- package/dist/test/utils-surface.test.d.ts +0 -2
- package/dist/test/utils-surface.test.d.ts.map +0 -1
- package/dist/test/utils-surface.test.js +0 -145
- package/dist/test/utils-surface.test.js.map +0 -1
- package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
- package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
- package/dist/test/workspace-branch-continuation.test.js +0 -183
- package/dist/test/workspace-branch-continuation.test.js.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
- package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.js +0 -252
- package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
- package/dist/test/workspace-path-containment.test.d.ts +0 -19
- package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
- package/dist/test/workspace-path-containment.test.js +0 -91
- package/dist/test/workspace-path-containment.test.js.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
- package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.js +0 -174
- package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
- package/dist/test/workspace-read-image.test.d.ts +0 -2
- package/dist/test/workspace-read-image.test.d.ts.map +0 -1
- package/dist/test/workspace-read-image.test.js +0 -597
- package/dist/test/workspace-read-image.test.js.map +0 -1
- package/dist/test/workspace-read-text.test.d.ts +0 -2
- package/dist/test/workspace-read-text.test.d.ts.map +0 -1
- package/dist/test/workspace-read-text.test.js +0 -101
- package/dist/test/workspace-read-text.test.js.map +0 -1
- package/dist/test/workspace-restore-order.test.d.ts +0 -16
- package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
- package/dist/test/workspace-restore-order.test.js +0 -140
- package/dist/test/workspace-restore-order.test.js.map +0 -1
- package/dist/test/workspace-three-way.test.d.ts +0 -12
- package/dist/test/workspace-three-way.test.d.ts.map +0 -1
- package/dist/test/workspace-three-way.test.js +0 -3194
- package/dist/test/workspace-three-way.test.js.map +0 -1
- package/dist/test/workspace-watcher.test.d.ts +0 -2
- package/dist/test/workspace-watcher.test.d.ts.map +0 -1
- package/dist/test/workspace-watcher.test.js +0 -281
- package/dist/test/workspace-watcher.test.js.map +0 -1
- package/dist/test/xml-round-persist.test.d.ts +0 -19
- package/dist/test/xml-round-persist.test.d.ts.map +0 -1
- package/dist/test/xml-round-persist.test.js +0 -235
- package/dist/test/xml-round-persist.test.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
* a wrong adoption.
|
|
39
39
|
*/
|
|
40
40
|
import { candidateOf, sameCandidate, sameRootIdentity, } from './disk-agreement.js';
|
|
41
|
-
import { ROOT_REPLACED, fingerprintVouches, locateRoot, looksBinary, observePath, provenAbsent, readHead, readPath, sniffImageMime, walkScope, } from './observe.js';
|
|
42
|
-
import { EffectFailed, chainOf, syncDirectories, unlinkContained, writeContained } from './effects.js';
|
|
41
|
+
import { IGNORED, OTHER_MOUNT, ROOT_REPLACED, fingerprintVouches, ignoreBeneath, inOtherMount, locateRoot, looksBinary, observePath, passedOverAt, passedOverBetween, provenAbsent, readHead, readPath, sniffImageMime, walkScope, } from './observe.js';
|
|
42
|
+
import { EffectFailed, chainOf, chmodContained, narrowedTo, syncDirectories, unlinkContained, writeContained } from './effects.js';
|
|
43
43
|
const ABSENT = { kind: 'absent' };
|
|
44
44
|
export const WALK_CAP = 5000;
|
|
45
45
|
function diskCandidate(d) {
|
|
@@ -52,7 +52,58 @@ function diskCandidate(d) {
|
|
|
52
52
|
function agreedFromDisk(d) {
|
|
53
53
|
if (d.kind !== 'file')
|
|
54
54
|
return { kind: 'absent' };
|
|
55
|
-
return { kind: 'content', hash: d.hash, size: d.size, ...(d.fp ? { fp: d.fp } : {}) };
|
|
55
|
+
return { kind: 'content', hash: d.hash, size: d.size, ...(d.mode !== undefined ? { mode: d.mode } : {}), ...(d.fp ? { fp: d.fp } : {}) };
|
|
56
|
+
}
|
|
57
|
+
/** The file-type bits git records with a regular file's mode. */
|
|
58
|
+
const REGULAR_FILE = 0o100000;
|
|
59
|
+
/** A tree entry's mode for permission bits: with the regular-file type bits, as git records one. */
|
|
60
|
+
export function treeMode(perm) {
|
|
61
|
+
return REGULAR_FILE | (perm & 0o777);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The mode a tree entry takes for disk's permission bits, or, where disk's
|
|
65
|
+
* aren't observed, the entry's own. With neither, the placeholder an entry
|
|
66
|
+
* without a recorded mode has (see entryMode).
|
|
67
|
+
*/
|
|
68
|
+
function treeModeOf(perm, s) {
|
|
69
|
+
if (perm !== undefined)
|
|
70
|
+
return { mode: treeMode(perm) };
|
|
71
|
+
if (s?.mode !== undefined)
|
|
72
|
+
return { mode: treeMode(s.mode) };
|
|
73
|
+
return { mode: 0o644 };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The permission bits a tree entry records, or undefined when it records
|
|
77
|
+
* none. An entry without the file-type bits was written before modes were
|
|
78
|
+
* recorded, which wrote 0o644 whatever disk had: a placeholder, not a mode.
|
|
79
|
+
*/
|
|
80
|
+
export function entryMode(mode) {
|
|
81
|
+
return (mode & 0o170000) === REGULAR_FILE ? mode & 0o777 : undefined;
|
|
82
|
+
}
|
|
83
|
+
/** The store's side of a tree entry. */
|
|
84
|
+
export function storeSide(entry) {
|
|
85
|
+
if (!entry)
|
|
86
|
+
return null;
|
|
87
|
+
const mode = entryMode(entry.mode);
|
|
88
|
+
return { hash: entry.blobHash, size: entry.size, ...(mode !== undefined ? { mode } : {}) };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Where disk and the store hold the same bytes, what their modes ask for.
|
|
92
|
+
* A mode the store doesn't record agrees with any, and takes disk's
|
|
93
|
+
* (`fill`). The store's mode goes to disk (`push`) only where the evidence
|
|
94
|
+
* shows disk still has the mode they last agreed on; otherwise disk's mode
|
|
95
|
+
* is taken in as a change (`adopt`): disk changed it, or nothing says which
|
|
96
|
+
* side did, and an unknown never moves disk.
|
|
97
|
+
*/
|
|
98
|
+
function modeAction(disk, store, agreed) {
|
|
99
|
+
if (store === undefined)
|
|
100
|
+
return 'fill';
|
|
101
|
+
if (store === disk)
|
|
102
|
+
return undefined;
|
|
103
|
+
return agreed !== undefined && agreed === disk ? 'push' : 'adopt';
|
|
104
|
+
}
|
|
105
|
+
function octal(mode) {
|
|
106
|
+
return `0${mode.toString(8).padStart(3, '0')}`;
|
|
56
107
|
}
|
|
57
108
|
function inScope(path, scope) {
|
|
58
109
|
if (scope.kind === 'paths')
|
|
@@ -76,7 +127,7 @@ async function learnDisk(mount, path, tracked, opts) {
|
|
|
76
127
|
const p = tracked.p;
|
|
77
128
|
const trusted = (fp) => mount.ctimeTrustedDev !== null && fp.dev === mount.ctimeTrustedDev;
|
|
78
129
|
if (!opts.rehash && p?.kind === 'content' && fingerprintVouches(p.fp, seen.fp, trusted(seen.fp))) {
|
|
79
|
-
return { kind: 'file', hash: p.hash, size: seen.size, mtimeMs: seen.mtimeMs, fp: p.fp ?? null, ingestible: null };
|
|
130
|
+
return { kind: 'file', hash: p.hash, size: seen.size, mtimeMs: seen.mtimeMs, ...(mount.modesObserved ? { mode: seen.mode } : {}), fp: p.fp ?? null, ingestible: null };
|
|
80
131
|
}
|
|
81
132
|
const nothingTracked = p === undefined && !tracked.hasStore && !tracked.hasIntent;
|
|
82
133
|
if (nothingTracked && seen.size > mount.view.maxFileSize) {
|
|
@@ -96,6 +147,7 @@ async function learnDisk(mount, path, tracked, opts) {
|
|
|
96
147
|
hash: read.hash,
|
|
97
148
|
size: read.size,
|
|
98
149
|
mtimeMs: read.mtimeMs,
|
|
150
|
+
...(mount.modesObserved ? { mode: read.mode } : {}),
|
|
99
151
|
// A fingerprint is recorded only where it can later vouch for the bytes.
|
|
100
152
|
fp: trusted(read.fp) ? read.fp : null,
|
|
101
153
|
ingestible,
|
|
@@ -129,10 +181,66 @@ function keepStoreSide(hasStore, bi) {
|
|
|
129
181
|
function settleAdoption(p, s) {
|
|
130
182
|
const sc = s ? { kind: 'content', hash: s.hash } : ABSENT;
|
|
131
183
|
if (sameCandidate(sc, p.expect)) {
|
|
132
|
-
|
|
184
|
+
// Where modes are observed, the adoption took disk's mode with its bytes,
|
|
185
|
+
// so the entry's mode is the one they agreed on, but for an adoption that
|
|
186
|
+
// took the mode a stopped push of ours meant the old bytes to have: its
|
|
187
|
+
// entry holds that mode while disk holds the push's narrowed one, which a
|
|
188
|
+
// later sync then takes in. Where modes aren't observed, the entry's mode
|
|
189
|
+
// is the store's own, and the evidence records none.
|
|
190
|
+
return p.expect.kind === 'absent'
|
|
191
|
+
? { kind: 'absent' }
|
|
192
|
+
: { kind: 'content', hash: p.expect.hash, size: s.size, ...(s.mode !== undefined ? { mode: s.mode } : {}) };
|
|
133
193
|
}
|
|
134
194
|
return p.prior ?? 'forget';
|
|
135
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* What's in the way, and the way out, when disk's shape keeps a push from a
|
|
198
|
+
* path: no push writes a file over a directory or unlinks one, unlinks
|
|
199
|
+
* anything but a regular file or a followed symlink to one, or writes below
|
|
200
|
+
* a file or a symlink the walk won't take (`writeContained`,
|
|
201
|
+
* `unlinkContained`), forced or not. Null for any other reason, which is
|
|
202
|
+
* passed on as it is.
|
|
203
|
+
*/
|
|
204
|
+
function inTheWay(reason, deletion) {
|
|
205
|
+
// Observation's words for what a deletion never unlinks, which the unlink
|
|
206
|
+
// refuses in the same words.
|
|
207
|
+
if (deletion && (reason === 'not a regular file' || reason === 'a symlink to a directory, not walked')) {
|
|
208
|
+
const what = reason === 'not a regular file'
|
|
209
|
+
? 'a pipe, socket or device at this path, or a symlink to one'
|
|
210
|
+
: 'a symlink to a directory at this path';
|
|
211
|
+
return `disk has ${what}, and no push unlinks it, forced or not — ask whoever runs this host if it should go`;
|
|
212
|
+
}
|
|
213
|
+
if (reason === 'a directory') {
|
|
214
|
+
return deletion
|
|
215
|
+
? 'disk has a directory at this path, and no push unlinks one, forced or not — if it should go, move or remove it on disk'
|
|
216
|
+
: 'disk has a directory at this path, and no push writes a file over one, forced or not — ' +
|
|
217
|
+
'move or remove that directory on disk and materialize again, or write the file under another path';
|
|
218
|
+
}
|
|
219
|
+
// A deletion below a file finds nothing there to unlink, so only a write
|
|
220
|
+
// meets this one.
|
|
221
|
+
if (reason === 'a parent path is not a directory') {
|
|
222
|
+
return 'disk has a file or a symlink where this path needs a directory, and no push writes below one, forced or not — ' +
|
|
223
|
+
'move or remove it on disk and materialize again, or write the file under another path';
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The forced way out the refusal of a disk copy that couldn't be verified
|
|
229
|
+
* names, if any. A forced push skips the verification, so it gets past the
|
|
230
|
+
* note only where its effect can go on. A file the module can't read (EACCES)
|
|
231
|
+
* is overwritten, or unlinked, where disk lets the workspace write it, or
|
|
232
|
+
* unlink it, which a read's EACCES doesn't show: force is named on that
|
|
233
|
+
* condition. No other note names force: a forced push stops at some (a
|
|
234
|
+
* symlink the mount doesn't follow, what isn't a regular file, a parent it
|
|
235
|
+
* can't use); another writer still at the file ("the file changed while it
|
|
236
|
+
* was read") is answered by materializing again; and the rest aren't known
|
|
237
|
+
* to pass.
|
|
238
|
+
*/
|
|
239
|
+
function forcedWay(note, deletion, forced) {
|
|
240
|
+
if (note === 'cannot open (EACCES)')
|
|
241
|
+
return `, or, if disk lets the workspace ${deletion ? 'unlink' : 'write'} the file, ${forced}`;
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
136
244
|
/**
|
|
137
245
|
* The synchronous precondition of every workspace mutation: evidence owed a
|
|
138
246
|
* barrier is made durable first, and an adoption left pending on the
|
|
@@ -151,13 +259,32 @@ export function settleAdoptionBeforeMutation(store, agreement, mount, path) {
|
|
|
151
259
|
if (p?.kind !== 'pending' || p.effect !== 'adopt' || p.branchId !== store.currentBranch().id)
|
|
152
260
|
return;
|
|
153
261
|
const entry = store.treeGet(mount.treeStateId, path);
|
|
154
|
-
const settled = settleAdoption(p, entry ? { hash: entry.blobHash, size: entry.size } : null);
|
|
262
|
+
const settled = settleAdoption(p, entry ? { hash: entry.blobHash, size: entry.size, ...(entryMode(entry.mode) !== undefined ? { mode: entryMode(entry.mode) } : {}) } : null);
|
|
155
263
|
if (settled === 'forget')
|
|
156
264
|
agreement.forget(mount.name, path);
|
|
157
265
|
else
|
|
158
266
|
agreement.set(mount.name, path, settled, { afterCommittedState: true });
|
|
159
267
|
agreement.barrier();
|
|
160
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* What a push of ours that stopped partway left on disk, read by its own
|
|
271
|
+
* modes (Pending's `modes`): the new bytes at `from & to` or `to` were meant
|
|
272
|
+
* to have `to`; the old bytes at `from & to`, narrower than `from`, still
|
|
273
|
+
* have `from` as theirs. New bytes at `from` are a push's only where
|
|
274
|
+
* `from & to` is `from`: a push that narrows does so before its bytes, so
|
|
275
|
+
* otherwise they were given `from` since. Undefined where disk shows
|
|
276
|
+
* anything else: no push of ours, or a mode set since it stopped.
|
|
277
|
+
*/
|
|
278
|
+
function pushedMode(p, dc, d) {
|
|
279
|
+
const m = p.modes;
|
|
280
|
+
if (p.effect !== 'disk' || m === undefined || d.kind !== 'file' || d.mode === undefined)
|
|
281
|
+
return undefined;
|
|
282
|
+
const narrowed = m.from & m.to;
|
|
283
|
+
if (sameCandidate(dc, p.expect))
|
|
284
|
+
return d.mode === narrowed || d.mode === m.to ? m.to : undefined;
|
|
285
|
+
const prior = p.prior ? candidateOf(p.prior) : null;
|
|
286
|
+
return prior && sameCandidate(dc, prior) && narrowed !== m.from && d.mode === narrowed ? m.from : undefined;
|
|
287
|
+
}
|
|
161
288
|
/**
|
|
162
289
|
* Resolve a pending intent against what was observed. Returns the evidence
|
|
163
290
|
* the rule should use, and whether that resolution should be recorded.
|
|
@@ -169,11 +296,24 @@ function resolvePending(p, dc, s, d, branchId) {
|
|
|
169
296
|
if (sameCandidate(dc, p.expect)) {
|
|
170
297
|
// Our own effect shows on disk, but nothing proves it durable: decided
|
|
171
298
|
// on, never recorded. Only a push whose barriers succeed completes it.
|
|
299
|
+
// Where disk's mode is one of the push's own, the push that completes
|
|
300
|
+
// it gives the store's mode there.
|
|
172
301
|
const shown = p.expect.kind === 'absent' ? { kind: 'absent' } : agreedFromDisk(d);
|
|
173
|
-
return { p: shown, unconfirmed: true };
|
|
302
|
+
return { p: shown, unconfirmed: true, ...(pushedMode(p, dc, d) !== undefined ? { ownMode: true } : {}) };
|
|
174
303
|
}
|
|
175
|
-
if (priorCandidate && sameCandidate(dc, priorCandidate))
|
|
304
|
+
if (priorCandidate && sameCandidate(dc, priorCandidate)) {
|
|
305
|
+
// The push narrowed the mode and stopped before its bytes: disk's mode
|
|
306
|
+
// is the push's, so the rule decides from it, and the next push writes
|
|
307
|
+
// the bytes at it and then widens to the store's. The old bytes are
|
|
308
|
+
// never given the store's mode. Nothing is recorded: the intent, with
|
|
309
|
+
// the modes that map disk's narrowed one back to the old bytes' own,
|
|
310
|
+
// stays, carried by a push that goes on with it (pushPaths), until a
|
|
311
|
+
// push completes it or a sync adopts disk's copy.
|
|
312
|
+
if (prior.kind === 'content' && d.kind === 'file' && pushedMode(p, dc, d) !== undefined) {
|
|
313
|
+
return { p: { ...prior, mode: d.mode } };
|
|
314
|
+
}
|
|
176
315
|
return { p: prior, record: prior };
|
|
316
|
+
}
|
|
177
317
|
// A write whose prior was unknown left no file: it never created one (a
|
|
178
318
|
// partial write leaves a file behind), so P is as unknown as before.
|
|
179
319
|
if (!prior && dc.kind === 'absent' && p.expect.kind === 'content')
|
|
@@ -210,9 +350,12 @@ function adoptDisk(d, s) {
|
|
|
210
350
|
return { state: 'synced', ...(s ? { adopt: 'remove', op: 'deleted' } : {}), p: { kind: 'absent' }, intent: {} };
|
|
211
351
|
}
|
|
212
352
|
// Disk agreeing with the store is disk's state already, whatever the file
|
|
213
|
-
// is: a binary or oversize file the workspace holds stays held.
|
|
214
|
-
|
|
215
|
-
|
|
353
|
+
// is: a binary or oversize file the workspace holds stays held. Its mode
|
|
354
|
+
// is disk's too.
|
|
355
|
+
if (s && s.hash === d.hash) {
|
|
356
|
+
const mode = d.mode === undefined ? undefined : s.mode === undefined ? 'fill' : s.mode !== d.mode ? 'adopt' : undefined;
|
|
357
|
+
return { state: 'synced', p: agreedFromDisk(d), intent: {}, ...(mode ? { mode } : {}), ...(mode === 'adopt' ? { op: 'modified' } : {}) };
|
|
358
|
+
}
|
|
216
359
|
if (d.ingestible)
|
|
217
360
|
return { state: 'synced', adopt: 'ingest', op: s ? 'modified' : 'created', p: agreedFromDisk(d), intent: {} };
|
|
218
361
|
return { state: 'disk-only', ...(s ? { adopt: 'drop', op: 'deleted' } : {}), p: 'forget', intent: {} };
|
|
@@ -243,12 +386,22 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
243
386
|
if (adopt) {
|
|
244
387
|
// What a path sync gives up is exactly what a sync without a path would
|
|
245
388
|
// have kept of the workspace's own (a draft, a deletion, a conflict's
|
|
246
|
-
// workspace side), and the verdict says which.
|
|
247
|
-
|
|
389
|
+
// workspace side), and the verdict says which. Where a push of ours
|
|
390
|
+
// stopped partway, disk's mode is the push's: the store takes the one
|
|
391
|
+
// the push meant those bytes to have, and the evidence keeps disk's, so
|
|
392
|
+
// a later push moves disk there.
|
|
393
|
+
const meant = pIn?.kind === 'pending' ? pushedMode(pIn, dc, d) : undefined;
|
|
394
|
+
const taken = adoptDisk(meant === undefined ? d : { ...d, mode: meant }, s);
|
|
395
|
+
if (meant !== undefined) {
|
|
396
|
+
if (taken.p !== undefined && taken.p !== 'forget' && taken.p.kind === 'content')
|
|
397
|
+
taken.p = agreedFromDisk(d);
|
|
398
|
+
if (taken.adopt === 'ingest' || taken.mode !== undefined)
|
|
399
|
+
taken.diskMode = meant;
|
|
400
|
+
}
|
|
248
401
|
// A give-up is an adoption, or the intent it clears: a deletion or a
|
|
249
402
|
// conflict given up for a disk copy the workspace can't hold changes no
|
|
250
403
|
// tree entry, and is listed all the same.
|
|
251
|
-
if (taken.adopt || (bi && taken.intent !== undefined)) {
|
|
404
|
+
if (taken.adopt || taken.mode === 'adopt' || (bi && taken.intent !== undefined)) {
|
|
252
405
|
const kept = decide(d, s, pIn, bi, branchId, false);
|
|
253
406
|
if (WORKSPACE_KEPT.has(kept.state))
|
|
254
407
|
taken.discards = kept.state;
|
|
@@ -261,6 +414,9 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
261
414
|
// verdict below records newer evidence.
|
|
262
415
|
let p = pIn;
|
|
263
416
|
let resolution;
|
|
417
|
+
// Evidence a resolution decides from without recording it: a stopped
|
|
418
|
+
// push's narrowing, whose intent stays (resolvePending).
|
|
419
|
+
let unrecorded;
|
|
264
420
|
let uncaptured = false;
|
|
265
421
|
if (p?.kind === 'pending') {
|
|
266
422
|
const resolved = resolvePending(p, dc, s, d, branchId);
|
|
@@ -269,13 +425,19 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
269
425
|
// follows from that, and nothing is recorded — no completion, no
|
|
270
426
|
// agreement, no branch-intent change — until a push confirms it.
|
|
271
427
|
const state = sameCandidate(dc, sc) ? 'synced' : bi?.conflict ? 'conflict' : keepStoreSide(s !== null, bi);
|
|
272
|
-
return {
|
|
428
|
+
return {
|
|
429
|
+
state, note: UNCONFIRMED_NOTE, unconfirmed: true,
|
|
430
|
+
...(resolved.ownMode ? { ownMode: true } : {}),
|
|
431
|
+
};
|
|
273
432
|
}
|
|
274
433
|
p = resolved.p;
|
|
275
434
|
resolution = resolved.record;
|
|
435
|
+
if (resolution === undefined && p !== undefined && (p.kind === 'content' || p.kind === 'absent'))
|
|
436
|
+
unrecorded = p;
|
|
276
437
|
uncaptured = resolved.uncaptured === true;
|
|
277
438
|
}
|
|
278
|
-
const verdict = (v) => (resolution && v.p === undefined ? { ...v, p: resolution }
|
|
439
|
+
const verdict = (v) => (resolution && v.p === undefined ? { ...v, p: resolution }
|
|
440
|
+
: unrecorded && v.p === undefined && v.prior === undefined ? { ...v, prior: unrecorded } : v);
|
|
279
441
|
// Agreement settles everything, a recorded conflict included.
|
|
280
442
|
if (sameCandidate(dc, sc)) {
|
|
281
443
|
const settles = bi?.tombstone || bi?.conflict || bi?.origin ? { intent: {} } : {};
|
|
@@ -291,11 +453,23 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
291
453
|
const recorded = p?.kind === 'content' ? p : null;
|
|
292
454
|
// Re-record only when P says something else, or a fresh fingerprint can
|
|
293
455
|
// replace one that no longer vouches. A fresh one exists only where it's
|
|
294
|
-
// trusted, so both are judged as trusted here.
|
|
295
|
-
|
|
456
|
+
// trusted, so both are judged as trusted here. Evidence a resolution left
|
|
457
|
+
// unrecorded, a stopped push's narrowing, is stale too: the agreement
|
|
458
|
+
// replaces that push's intent, and the mode rule gives the store's mode.
|
|
459
|
+
const stale = unrecorded !== undefined || !recorded || recorded.hash !== agreed.hash || recorded.size !== agreed.size || recorded.mode !== agreed.mode ||
|
|
296
460
|
(agreed.fp !== undefined && fingerprintVouches(agreed.fp, agreed.fp, true) &&
|
|
297
461
|
!fingerprintVouches(recorded.fp, agreed.fp, true));
|
|
298
|
-
|
|
462
|
+
const mode = agreed.mode === undefined ? undefined : modeAction(agreed.mode, s.mode, recorded?.mode);
|
|
463
|
+
if (mode === 'push') {
|
|
464
|
+
return verdict({
|
|
465
|
+
state: 'workspace-draft',
|
|
466
|
+
mode,
|
|
467
|
+
note: `the workspace's mode (${octal(s.mode)}) differs from disk's (${octal(agreed.mode)}): materialize to apply it`,
|
|
468
|
+
...(stale ? { p: agreed } : {}),
|
|
469
|
+
...settles,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
return verdict({ state: 'synced', ...(mode ? { mode } : {}), ...(mode === 'adopt' ? { op: 'modified' } : {}), ...(stale ? { p: agreed } : {}), ...settles });
|
|
299
473
|
}
|
|
300
474
|
// A recorded conflict stays until it is resolved explicitly or disk and store converge.
|
|
301
475
|
if (bi?.conflict)
|
|
@@ -411,13 +585,19 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
411
585
|
if (inScope(p, scope))
|
|
412
586
|
candidates.add(p);
|
|
413
587
|
if (rootUnavailable === null) {
|
|
414
|
-
|
|
588
|
+
const resumeAfter = opts.resume ? agreement.walkResumesAfter(mount.name, scope.dir) : undefined;
|
|
589
|
+
walk = await walkScope(mount.view, mount.rootReal, scope.dir, scope.recursive, opts.cap ?? mount.walkCap, {
|
|
590
|
+
named: opts.named,
|
|
591
|
+
...(resumeAfter !== undefined ? { resumeAfter } : {}),
|
|
592
|
+
});
|
|
415
593
|
for (const f of walk.files)
|
|
416
594
|
if (inScope(f, scope))
|
|
417
595
|
candidates.add(f);
|
|
418
|
-
//
|
|
419
|
-
|
|
420
|
-
|
|
596
|
+
// The other entries it took (a link, a socket…). Ignored names, and the
|
|
597
|
+
// entries the cap left, are listed only when something tracks them
|
|
598
|
+
// (above).
|
|
599
|
+
for (const p of walk.othersTaken)
|
|
600
|
+
if (inScope(p, scope))
|
|
421
601
|
candidates.add(p);
|
|
422
602
|
for (const d of walk.dirs)
|
|
423
603
|
if (inScope(d, { kind: 'dir', dir: scope.dir, recursive: false }))
|
|
@@ -431,18 +611,59 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
431
611
|
gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable });
|
|
432
612
|
continue;
|
|
433
613
|
}
|
|
614
|
+
// What the mount passes over by design stays unobserved by a pass that
|
|
615
|
+
// names no path, however it reaches it, so no listing's absence proves a
|
|
616
|
+
// copy there gone. In another mount's directory, no pass of this mount
|
|
617
|
+
// observes anything, named or not.
|
|
618
|
+
// Beneath a directory a by-design rule covers, a pass that isn't named
|
|
619
|
+
// observes nothing. A path a rule covers by its own name is observed as a
|
|
620
|
+
// walk observes it: passed over where the walk lists it, and absent where
|
|
621
|
+
// the walk lists its directory without it; a pass that reaches it by its
|
|
622
|
+
// path alone, as a listing, glob or grep naming it does, passes over it.
|
|
623
|
+
// A pass that names its scope, as a sync naming a path and a file tool's
|
|
624
|
+
// pass on the path it acts on do, sets aside only what covers the scope,
|
|
625
|
+
// at it or above it, as its walk does (#276): a directory passed over by
|
|
626
|
+
// design beneath a named directory stays passed over, and so does what
|
|
627
|
+
// lies beneath it.
|
|
628
|
+
let byDesign;
|
|
629
|
+
if (inOtherMount(path, mount.view.others)) {
|
|
630
|
+
byDesign = OTHER_MOUNT;
|
|
631
|
+
}
|
|
632
|
+
else if (!opts.named) {
|
|
633
|
+
const slash = path.lastIndexOf('/');
|
|
634
|
+
const above = slash < 0 ? undefined : passedOverAt(path.slice(0, slash), mount.view.ignore, mount.view.others);
|
|
635
|
+
const own = above === undefined && !walk ? passedOverAt(path, mount.view.ignore, mount.view.others) : undefined;
|
|
636
|
+
byDesign = above ?? own;
|
|
637
|
+
}
|
|
638
|
+
else if (scope.kind === 'dir') {
|
|
639
|
+
byDesign = passedOverBetween(scope.dir, path, ignoreBeneath(scope.dir, mount.view.ignore), mount.view.others);
|
|
640
|
+
}
|
|
641
|
+
if (byDesign !== undefined) {
|
|
642
|
+
gathered.facts.set(path, { kind: 'unobserved', reason: byDesign });
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
434
645
|
if (walk && provenAbsent(walk, path)) {
|
|
435
646
|
gathered.facts.set(path, { kind: 'absent' });
|
|
436
647
|
continue;
|
|
437
648
|
}
|
|
438
|
-
if (walk
|
|
439
|
-
|
|
440
|
-
const region = walk.incomplete.find((r) => r.path === '' || path === r.path || path.startsWith(r.path + '/'));
|
|
441
|
-
gathered.facts.set(path, { kind: 'unobserved', reason: region ? region.reason : 'not reached by the walk' });
|
|
649
|
+
if (walk?.others.get(path) === IGNORED) {
|
|
650
|
+
gathered.facts.set(path, { kind: 'unobserved', reason: IGNORED });
|
|
442
651
|
continue;
|
|
443
652
|
}
|
|
444
|
-
if (walk
|
|
445
|
-
|
|
653
|
+
if (walk && !walk.files.has(path) && !walk.othersTaken.has(path)) {
|
|
654
|
+
// Not taken by the walk, or beneath a region it didn't reach: unproven
|
|
655
|
+
// either way. The nearest region holding it says why.
|
|
656
|
+
let region;
|
|
657
|
+
for (const r of walk.incomplete) {
|
|
658
|
+
if (r.path !== '' && path !== r.path && !path.startsWith(r.path + '/'))
|
|
659
|
+
continue;
|
|
660
|
+
// A link's own region is about what lies beneath it, not the link.
|
|
661
|
+
if (r.kind === 'symlink' && r.path === path)
|
|
662
|
+
continue;
|
|
663
|
+
if (region === undefined || r.path.length > region.path.length)
|
|
664
|
+
region = r;
|
|
665
|
+
}
|
|
666
|
+
gathered.facts.set(path, { kind: 'unobserved', reason: region ? region.reason : 'not reached by the walk' });
|
|
446
667
|
continue;
|
|
447
668
|
}
|
|
448
669
|
const p = agreement.get(mount.name, path);
|
|
@@ -511,8 +732,7 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
511
732
|
result.branchId = branchId;
|
|
512
733
|
const planned = [];
|
|
513
734
|
for (const [path, d] of facts) {
|
|
514
|
-
const
|
|
515
|
-
const s = entry ? { hash: entry.blobHash, size: entry.size } : null;
|
|
735
|
+
const s = storeSide(store.treeGet(mount.treeStateId, path));
|
|
516
736
|
const p = agreement.get(mount.name, path);
|
|
517
737
|
const bi = mount.intents.get(path);
|
|
518
738
|
const verdict = decide(d, s, p, bi, branchId, opts.adopt?.(path) === true);
|
|
@@ -545,13 +765,20 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
545
765
|
const v = x.verdict;
|
|
546
766
|
if (v.adopt === 'ingest' && x.d.kind === 'file' && x.d.ingestible) {
|
|
547
767
|
const blobHash = store.storeBlob(x.d.ingestible, 'text/plain');
|
|
548
|
-
store.treeSet(mount.treeStateId, x.path, { blobHash, size: x.d.ingestible.byteLength, mode
|
|
768
|
+
store.treeSet(mount.treeStateId, x.path, { blobHash, size: x.d.ingestible.byteLength, ...treeModeOf(v.diskMode ?? x.d.mode, x.s) });
|
|
549
769
|
committed = true;
|
|
550
770
|
}
|
|
551
771
|
else if ((v.adopt === 'remove' || v.adopt === 'drop') && x.s) {
|
|
552
772
|
store.treeRemove(mount.treeStateId, x.path);
|
|
553
773
|
committed = true;
|
|
554
774
|
}
|
|
775
|
+
else if ((v.mode === 'fill' || v.mode === 'adopt') && x.d.kind === 'file' && x.s) {
|
|
776
|
+
// The same bytes, with disk's mode. A fill records a mode where the
|
|
777
|
+
// entry had none, which is no change: an undo or a branch whose entry
|
|
778
|
+
// still has none agrees with any mode, so neither reads it as one.
|
|
779
|
+
store.treeSet(mount.treeStateId, x.path, { blobHash: x.s.hash, size: x.s.size, ...treeModeOf(v.diskMode ?? x.d.mode, x.s) });
|
|
780
|
+
committed = true;
|
|
781
|
+
}
|
|
555
782
|
if (v.conflict) {
|
|
556
783
|
const record = { kind: v.conflict, at: Date.now(), disk: counterpartOf(store, x.d) };
|
|
557
784
|
mount.intents.update(x.path, (cur) => ({ ...cur, conflict: record }));
|
|
@@ -562,10 +789,11 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
562
789
|
mount.intents.put(x.path, v.intent);
|
|
563
790
|
committed = true;
|
|
564
791
|
}
|
|
565
|
-
|
|
566
|
-
|
|
792
|
+
const changed = v.adopt !== undefined || v.mode === 'adopt';
|
|
793
|
+
if (v.op && changed)
|
|
794
|
+
result.ops.push({ path: x.path, op: v.op, ...(v.adopt === undefined ? { modeOnly: true } : {}) });
|
|
567
795
|
if (v.discards)
|
|
568
|
-
result.discarded.push({ path: x.path, was: v.discards, ...(v.op &&
|
|
796
|
+
result.discarded.push({ path: x.path, was: v.discards, ...(v.op && changed ? { op: v.op } : {}) });
|
|
569
797
|
}
|
|
570
798
|
// 4. Completions and agreements, after the commits they assert are synced —
|
|
571
799
|
// this pass's, and any earlier tool write's an agreement rests on.
|
|
@@ -585,6 +813,17 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
585
813
|
agreement.set(mount.name, x.path, next, { afterCommittedState: first });
|
|
586
814
|
first = false;
|
|
587
815
|
}
|
|
816
|
+
// Where the walk stopped, once what it observed is decided: the next pass
|
|
817
|
+
// of this scope resumes after it, or starts afresh once this one covered
|
|
818
|
+
// the scope. A walk that couldn't list its scope's own directory covered
|
|
819
|
+
// none of it, and leaves the place as it was. Unlike evidence, a place
|
|
820
|
+
// binds no root: it only says where the next walk starts, and that walk
|
|
821
|
+
// takes its turn after it in whatever directory is the root by then.
|
|
822
|
+
let resumeAfter;
|
|
823
|
+
if (opts.resume && walk && scope.kind === 'dir' && scope.recursive && walk.complete.has(scope.dir)) {
|
|
824
|
+
resumeAfter = walk.stoppedAfter ?? null;
|
|
825
|
+
agreement.recordWalk(mount.name, scope.dir, resumeAfter);
|
|
826
|
+
}
|
|
588
827
|
// 5. Durable before returning. An agreement advance (D = S) has no pending
|
|
589
828
|
// intent to recover from, so losing its append would leave an older P that
|
|
590
829
|
// another branch would misread as a disk edit.
|
|
@@ -614,27 +853,55 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
614
853
|
}
|
|
615
854
|
if (walk) {
|
|
616
855
|
const tracked = [...result.reports.values()].filter((r) => r.state === 'unverified').map((r) => r.path);
|
|
856
|
+
if (typeof resumeAfter === 'string' && scope.kind === 'dir') {
|
|
857
|
+
// A watched mount's catch-up scan takes turns with its whole-mount
|
|
858
|
+
// syncs; nothing else moves a place.
|
|
859
|
+
const next = scope.dir !== ''
|
|
860
|
+
? 'the next sync of this directory'
|
|
861
|
+
: mount.catchUpScan
|
|
862
|
+
? 'the next sync of the mount, or its catch-up scan if that comes first,'
|
|
863
|
+
: 'the next sync of the mount';
|
|
864
|
+
result.incomplete.push({
|
|
865
|
+
path: scope.dir,
|
|
866
|
+
reason: `the walk cap (${opts.cap ?? mount.walkCap}) was reached: ${next} resumes after ${mount.name}/${resumeAfter}`,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
617
869
|
for (const region of walk.incomplete) {
|
|
618
|
-
|
|
619
|
-
|
|
870
|
+
// A link's own region hides only what lies beneath it: the link itself
|
|
871
|
+
// is reported by path, with its own reason.
|
|
872
|
+
const hides = tracked.some((p) => (region.kind !== 'symlink' && p === region.path) || p.startsWith(region.path + '/'));
|
|
873
|
+
// A scope passed over whole is the answer to the pass that asked for
|
|
874
|
+
// it, so it's always named. Another mount's directory met beneath the
|
|
875
|
+
// scope is passed over by design even where this mount's tree holds
|
|
876
|
+
// copies there: no tool of this mount syncs, pushes or clears them
|
|
877
|
+
// (listings show them, naming their holder), so naming the directory
|
|
878
|
+
// as unreached would never clear.
|
|
879
|
+
const wholeScope = scope.kind === 'dir' && scope.dir !== '' && region.path === scope.dir;
|
|
880
|
+
const unreached = hides && region.reason !== OTHER_MOUNT;
|
|
881
|
+
if (region.kind === 'error' || region.kind === 'cap' || unreached || wholeScope)
|
|
620
882
|
result.incomplete.push({ path: region.path, reason: region.reason });
|
|
621
|
-
//
|
|
883
|
+
// A name passed over by design that hides nothing tracked is reported nowhere else:
|
|
622
884
|
// counted, so a sync that says 0 also says what it didn't look at
|
|
623
|
-
// (agent-framework #276). A symlink region isn't counted:
|
|
624
|
-
//
|
|
885
|
+
// (agent-framework #276). A symlink region isn't counted: a link the
|
|
886
|
+
// walk took is a candidate the pass reports by path, taken through the
|
|
625
887
|
// link when it's a file on a mount that follows symlinks, and
|
|
626
|
-
// otherwise listed under `skipped
|
|
888
|
+
// otherwise listed under `skipped`; a tracked link the cap left is
|
|
889
|
+
// unverified for the cap.
|
|
627
890
|
else if (region.kind === 'ignored')
|
|
628
891
|
result.passedOver.set(region.reason, (result.passedOver.get(region.reason) ?? 0) + 1);
|
|
629
892
|
}
|
|
630
893
|
}
|
|
631
894
|
return result;
|
|
632
895
|
}
|
|
896
|
+
/** Why a push skips a path in another mount's directory nested in its own. */
|
|
897
|
+
export const NOT_PUSHED_IN_OTHER_MOUNT = "it lies in another mount's directory, which no push of this mount writes";
|
|
633
898
|
/**
|
|
634
899
|
* Make disk hold the store's version of each path, under the same rule:
|
|
635
900
|
* drafts are written, agreement is left alone, conflicts and unverifiable
|
|
636
901
|
* disk copies are refused unless `force`, and a workspace deletion reaches
|
|
637
902
|
* disk only with `applyDeletions` (with `force` too when disk changed since).
|
|
903
|
+
* Forced or not, nothing but a regular file, or a followed symlink to one, is
|
|
904
|
+
* written over or unlinked (effects.ts).
|
|
638
905
|
* A path nothing has evidence about is written only when `named`.
|
|
639
906
|
* A path whose earlier push shows on disk unconfirmed is pushed again, so its
|
|
640
907
|
* completion rests on barriers that succeeded.
|
|
@@ -653,7 +920,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
653
920
|
agreement.ensureReconciled();
|
|
654
921
|
if (agreement.needsBarrier)
|
|
655
922
|
agreement.barrier(); // as a pass does: nothing decided from unsynced evidence
|
|
656
|
-
const result = { written: [], unchanged: [], deleted: [], skipped: [], pendingDeletions: [] };
|
|
923
|
+
const result = { written: [], unchanged: [], deleted: [], skipped: [], modesKept: [], pendingDeletions: [] };
|
|
657
924
|
if (mount.readOnly)
|
|
658
925
|
return result;
|
|
659
926
|
// A root that isn't available takes no writes, forced or not: restoring the
|
|
@@ -665,6 +932,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
665
932
|
result.skipped.push({ path, reason: root.reason });
|
|
666
933
|
return result;
|
|
667
934
|
}
|
|
935
|
+
// Another mount's directory nested in this one is that mount's: no push
|
|
936
|
+
// of this mount writes or deletes a path in it, forced or not. (On a mount
|
|
937
|
+
// that follows links, a link of this mount's that leads there is read as
|
|
938
|
+
// this mount's own path; on one that doesn't, the link is refused.)
|
|
939
|
+
if (mount.view.others.length > 0) {
|
|
940
|
+
const own = [];
|
|
941
|
+
for (const path of paths) {
|
|
942
|
+
if (inOtherMount(path, mount.view.others))
|
|
943
|
+
result.skipped.push({ path, reason: NOT_PUSHED_IN_OTHER_MOUNT });
|
|
944
|
+
else
|
|
945
|
+
own.push(path);
|
|
946
|
+
}
|
|
947
|
+
paths = own;
|
|
948
|
+
}
|
|
668
949
|
const plans = [];
|
|
669
950
|
// Observe disk.
|
|
670
951
|
const facts = new Map();
|
|
@@ -694,11 +975,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
694
975
|
result.sequence = store.currentSequence();
|
|
695
976
|
let recorded = false;
|
|
696
977
|
for (const [path, d] of facts) {
|
|
697
|
-
const
|
|
698
|
-
const s = entry ? { hash: entry.blobHash, size: entry.size } : null;
|
|
978
|
+
const s = storeSide(store.treeGet(mount.treeStateId, path));
|
|
699
979
|
const p = agreement.get(mount.name, path);
|
|
700
980
|
const bi = mount.intents.get(path);
|
|
701
981
|
const v = decide(d, s, p, bi, branchId, false);
|
|
982
|
+
// The ways out a refusal names, as materialize takes them: a deletion
|
|
983
|
+
// reaches disk only with applyDeletions.
|
|
984
|
+
const again = s ? 'materialize again' : 'materialize again with applyDeletions';
|
|
985
|
+
// Where disk has deleted a file the workspace holds, a sync takes the
|
|
986
|
+
// deletion, which removes the workspace's copy, and a forced push writes
|
|
987
|
+
// the workspace's copy back: there is no disk copy to adopt or overwrite.
|
|
988
|
+
const gone = s !== null && d.kind === 'absent';
|
|
989
|
+
const forced = !s ? 'materialize it with force and applyDeletions to delete it'
|
|
990
|
+
: gone ? "materialize it with force to write the workspace's copy back" : 'materialize it with force to overwrite it';
|
|
991
|
+
const takeDisk = gone ? "sync this path to take disk's deletion, which removes the workspace's copy" : 'sync this path to adopt the disk version';
|
|
702
992
|
// What the effect may find: what this observation saw, unless forced.
|
|
703
993
|
const expect = opts.force || d.kind === 'unobserved' || d.kind === 'unhashed'
|
|
704
994
|
? { kind: 'any' }
|
|
@@ -713,18 +1003,51 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
713
1003
|
result.skipped.push({
|
|
714
1004
|
path,
|
|
715
1005
|
reason: 'stale copy: disk changed since it last agreed with the workspace, which did not — ' +
|
|
716
|
-
|
|
1006
|
+
`${takeDisk}, or ${forced}`,
|
|
717
1007
|
});
|
|
718
1008
|
continue;
|
|
719
1009
|
}
|
|
720
1010
|
const priorP = p && (p.kind === 'absent' || p.kind === 'content') ? p : null;
|
|
721
1011
|
const blob = store.getBlob(s.hash);
|
|
722
|
-
|
|
723
|
-
|
|
1012
|
+
const forcedMode = mount.modesObserved && s.mode !== undefined && s.mode !== (d.kind === 'file' ? d.mode : undefined) ? s.mode : undefined;
|
|
1013
|
+
const agreedMode = priorP?.kind === 'content' ? priorP.mode : undefined;
|
|
1014
|
+
if (blob) {
|
|
1015
|
+
plans.push({
|
|
1016
|
+
path, kind: 'write', blob, hash: s.hash, prior: priorP, before: agreement.get(mount.name, path), expect,
|
|
1017
|
+
...(forcedMode !== undefined ? { apply: forcedMode } : {}),
|
|
1018
|
+
...(forcedMode !== undefined && d.kind === 'file' && agreedMode !== d.mode ? { overDisk: true } : {}),
|
|
1019
|
+
...(s.mode !== undefined ? { storeMode: s.mode } : {}),
|
|
1020
|
+
// Refused over disk's mode, the completion records what an unforced
|
|
1021
|
+
// write would: the mode disk last agreed with.
|
|
1022
|
+
...(agreedMode !== undefined ? { priorMode: agreedMode } : {}),
|
|
1023
|
+
...(d.kind === 'file' && d.mode !== undefined ? { seenMode: d.mode } : {}),
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
724
1026
|
else
|
|
725
1027
|
result.skipped.push({ path, reason: 'the workspace copy is missing from the store' });
|
|
726
1028
|
continue;
|
|
727
1029
|
}
|
|
1030
|
+
if (v.mode === 'adopt' && s && d.kind === 'file') {
|
|
1031
|
+
// Disk's mode changed since it last agreed, on the bytes the store
|
|
1032
|
+
// holds, and the store's didn't. A sync takes it in. Recording disk's
|
|
1033
|
+
// mode here would read as the store's change, which the next push
|
|
1034
|
+
// would revert; forced, disk takes the store's mode, as forced bytes do.
|
|
1035
|
+
if (!opts.force) {
|
|
1036
|
+
// modeAction adopts where disk changed the mode since they agreed, and
|
|
1037
|
+
// where nothing records a mode they agreed on.
|
|
1038
|
+
const agreedMode = p?.kind === 'content' ? p.mode : undefined;
|
|
1039
|
+
result.skipped.push({
|
|
1040
|
+
path,
|
|
1041
|
+
reason: (agreedMode === undefined
|
|
1042
|
+
? `disk's mode (${octal(d.mode)}) differs from the workspace's (${octal(s.mode)}), and nothing records which side changed it`
|
|
1043
|
+
: `disk's mode (${octal(d.mode)}) changed since it last agreed with the workspace's (${octal(s.mode)})`) +
|
|
1044
|
+
' — sync this path to take disk\'s mode in, or materialize this path with force to apply the workspace\'s',
|
|
1045
|
+
});
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
plans.push({ path, kind: 'chmod', mode: s.mode, hash: s.hash, size: s.size, prior: null, before: p, expect, overDisk: true });
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
728
1051
|
// Whatever the verdict learned about disk (an agreement, a resolved
|
|
729
1052
|
// intent) is recorded before anything is pushed over it, and the root it
|
|
730
1053
|
// was learned under before that (once per mount), as a pass does.
|
|
@@ -739,8 +1062,22 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
739
1062
|
// The prior a new intent carries is the last confirmed evidence: for a
|
|
740
1063
|
// path whose earlier push is unconfirmed, that push's own prior, never
|
|
741
1064
|
// the bytes it wrote.
|
|
742
|
-
const known = v.unconfirmed ? p.prior ?? undefined : v.p === 'forget' ? undefined : v.p !== undefined ? v.p : p;
|
|
1065
|
+
const known = v.unconfirmed ? p.prior ?? undefined : v.p === 'forget' ? undefined : v.p !== undefined ? v.p : v.prior ?? p;
|
|
743
1066
|
const prior = known && (known.kind === 'absent' || known.kind === 'content') ? known : null;
|
|
1067
|
+
// A push that re-plans over our own narrowing push, stopped before its
|
|
1068
|
+
// bytes, plans from disk's narrowed mode (the verdict's prior, which
|
|
1069
|
+
// resolvePending leaves unrecorded), as above, and goes on as that push:
|
|
1070
|
+
// its intent carries the stopped push's prior, the old bytes at their own
|
|
1071
|
+
// mode, never the mode it narrowed them to, and modes from that mode, so a
|
|
1072
|
+
// stop of this push too reads disk's narrowed mode as the push's own.
|
|
1073
|
+
// Past the adoptions handled above, a verdict carries a prior with P still
|
|
1074
|
+
// pending only from that narrowing, whose push recorded its modes.
|
|
1075
|
+
const stopped = v.prior !== undefined && p?.kind === 'pending' ? p : undefined;
|
|
1076
|
+
if (v.mode === 'push' && s && d.kind === 'file') {
|
|
1077
|
+
// Forced, disk takes the store's mode whatever it holds now, as it takes its bytes.
|
|
1078
|
+
plans.push({ path, kind: 'chmod', mode: s.mode, ...(opts.force ? {} : { from: d.mode }), hash: s.hash, size: s.size, prior, before: agreement.get(mount.name, path), expect });
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
744
1081
|
if (v.state === 'synced' && !v.unconfirmed) {
|
|
745
1082
|
if (v.intent !== undefined) {
|
|
746
1083
|
mount.intents.put(path, v.intent);
|
|
@@ -752,7 +1089,25 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
752
1089
|
}
|
|
753
1090
|
if (v.state === 'unverified') {
|
|
754
1091
|
if (!opts.force) {
|
|
755
|
-
|
|
1092
|
+
// An intent that can't be read is the one note fixing doesn't
|
|
1093
|
+
// answer: nothing is decided over it until a sync of the path
|
|
1094
|
+
// replaces it (decide()), and a sync replaces it only where it sees
|
|
1095
|
+
// disk's copy, so a copy it can't see is named first. For the rest,
|
|
1096
|
+
// fixing what the note names holds, and forcedWay says where force
|
|
1097
|
+
// does too. Where disk has deleted the file, that sync takes the
|
|
1098
|
+
// deletion.
|
|
1099
|
+
const sync = gone
|
|
1100
|
+
? "sync this path to take disk's deletion, which removes the workspace's copy and replaces the intent"
|
|
1101
|
+
: 'sync this path to adopt the disk version, which replaces the intent';
|
|
1102
|
+
result.skipped.push({
|
|
1103
|
+
path,
|
|
1104
|
+
reason: bi?.unreadable !== undefined
|
|
1105
|
+
? d.kind === 'absent' || d.kind === 'file'
|
|
1106
|
+
? `${v.note} — ${sync}`
|
|
1107
|
+
: `${v.note}, and disk's copy can't be verified (${d.kind === 'unobserved' ? d.reason : 'not hashed'}) — once it can be, ${sync}`
|
|
1108
|
+
: inTheWay(v.note, !s) ??
|
|
1109
|
+
`cannot verify disk copy (${v.note ?? 'not observed'}) — fix it and ${again}${forcedWay(v.note, !s, forced)}`,
|
|
1110
|
+
});
|
|
756
1111
|
continue;
|
|
757
1112
|
}
|
|
758
1113
|
}
|
|
@@ -772,15 +1127,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
772
1127
|
}
|
|
773
1128
|
result.skipped.push({
|
|
774
1129
|
path,
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
: kind
|
|
779
|
-
? '
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
1130
|
+
// Whatever was recorded, a disk with no copy now is answered for what
|
|
1131
|
+
// it holds; a path with no evidence still needs its push named.
|
|
1132
|
+
reason: gone
|
|
1133
|
+
? `disk has no copy of this file (conflict: ${kind}) — ${takeDisk}, or ` +
|
|
1134
|
+
`materialize ${noEvidence ? 'this path' : 'it'} with force to write the workspace's copy back`
|
|
1135
|
+
: noEvidence
|
|
1136
|
+
? `disk holds a different copy, and nothing records which is newer (conflict: ${kind}) — ` +
|
|
1137
|
+
`sync this path to adopt the disk version, or materialize this path with force ${s ? 'to overwrite it' : 'and applyDeletions to delete it'}`
|
|
1138
|
+
: kind === 'interrupted'
|
|
1139
|
+
? 'disk holds bytes that match neither what was being written there nor what disk last agreed with ' +
|
|
1140
|
+
'(conflict: interrupted), as a write that failed or was cut off partway leaves — check the file, then ' +
|
|
1141
|
+
`${forced}, or sync this path to adopt the disk copy as it is`
|
|
1142
|
+
: `stale copy: disk changed since it last agreed with the workspace (conflict: ${kind}) — ` +
|
|
1143
|
+
`sync this path to adopt the disk version, or ${forced}`,
|
|
784
1144
|
});
|
|
785
1145
|
continue;
|
|
786
1146
|
}
|
|
@@ -810,7 +1170,14 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
810
1170
|
continue;
|
|
811
1171
|
}
|
|
812
1172
|
if (!opts.applyDeletions) {
|
|
813
|
-
|
|
1173
|
+
// A deletion no push makes, forced or not (inTheWay), is refused for
|
|
1174
|
+
// that, as an unforced push refuses it, rather than left for
|
|
1175
|
+
// applyDeletions, which couldn't make it either.
|
|
1176
|
+
const lasting = inTheWay(v.note, true);
|
|
1177
|
+
if (lasting !== null)
|
|
1178
|
+
result.skipped.push({ path, reason: lasting });
|
|
1179
|
+
else
|
|
1180
|
+
result.pendingDeletions.push(path);
|
|
814
1181
|
continue;
|
|
815
1182
|
}
|
|
816
1183
|
if (d.kind === 'absent')
|
|
@@ -823,18 +1190,61 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
823
1190
|
result.skipped.push({ path, reason: 'the workspace copy is missing from the store' });
|
|
824
1191
|
continue;
|
|
825
1192
|
}
|
|
826
|
-
|
|
1193
|
+
// The store's mode goes to disk with its bytes where the file is new,
|
|
1194
|
+
// the push is forced, or disk still has the mode they last agreed on. A
|
|
1195
|
+
// push that completes our own unconfirmed one, whose bytes landed, is a
|
|
1196
|
+
// push like any other: it gives the store's mode where disk shows one of
|
|
1197
|
+
// the stopped push's own (pushedMode) or the one they last agreed on, and
|
|
1198
|
+
// keeps any other, set since it stopped (Ada-1017, room-203 #131062,
|
|
1199
|
+
// #131518). A mode disk changed since stays, and so does the evidence
|
|
1200
|
+
// that it did, up to the moment of the write.
|
|
1201
|
+
const dm = d.kind === 'file' ? d.mode : undefined;
|
|
1202
|
+
const priorMode = prior?.kind === 'content' ? prior.mode : undefined;
|
|
1203
|
+
const own = v.unconfirmed === true && v.ownMode === true;
|
|
1204
|
+
const apply = mount.modesObserved && s.mode !== undefined && s.mode !== dm &&
|
|
1205
|
+
(dm === undefined || opts.force === true || own || priorMode === dm) ? s.mode : undefined;
|
|
1206
|
+
plans.push({
|
|
1207
|
+
path, kind: 'write', blob, hash: s.hash, prior: stopped ? stopped.prior : prior, before: agreement.get(mount.name, path), expect,
|
|
1208
|
+
// With no mode in the store's entry, its `to` is the mode the push
|
|
1209
|
+
// leaves, the one the stopped push narrowed to: it claims none it lacks.
|
|
1210
|
+
...(stopped ? { ownModes: { from: stopped.modes.from, to: s.mode ?? (stopped.modes.from & stopped.modes.to) } } : {}),
|
|
1211
|
+
...(apply !== undefined ? { apply } : {}),
|
|
1212
|
+
...(apply !== undefined && dm !== undefined && opts.force !== true ? { from: dm } : {}),
|
|
1213
|
+
// Forced over a mode disk changed: without force, the bytes would keep it.
|
|
1214
|
+
...(apply !== undefined && dm !== undefined && priorMode !== dm && !own ? { overDisk: true } : {}),
|
|
1215
|
+
...(s.mode !== undefined ? { storeMode: s.mode } : {}),
|
|
1216
|
+
...(priorMode !== undefined ? { priorMode } : {}),
|
|
1217
|
+
...(dm !== undefined ? { seenMode: dm } : {}),
|
|
1218
|
+
});
|
|
827
1219
|
}
|
|
828
1220
|
// 1. Durable intents before any disk effect, the root they write under first.
|
|
1221
|
+
// A chmod announces none: it leaves the bytes as they are. Stopped before
|
|
1222
|
+
// its completion, it leaves disk at the store's mode or still at the one
|
|
1223
|
+
// the evidence agreed, and the next observation decides from that: synced
|
|
1224
|
+
// and recorded, or pushed again. Nothing is lost either way. A forced
|
|
1225
|
+
// chmod has no guard: stopped before it, disk keeps whatever mode it found,
|
|
1226
|
+
// which the next observation reads as disk's, and forced again, it applies
|
|
1227
|
+
// the store's.
|
|
829
1228
|
if (plans.length > 0)
|
|
830
1229
|
agreement.recordRootIdentity(mount.name, root.identity);
|
|
831
|
-
plans.
|
|
1230
|
+
const announced = plans.filter((step) => step.kind !== 'chmod');
|
|
1231
|
+
announced.forEach((step, i) => {
|
|
832
1232
|
agreement.intend(mount.name, step.path, {
|
|
833
1233
|
effect: 'disk',
|
|
834
1234
|
prior: step.prior,
|
|
835
1235
|
expect: step.kind === 'write' ? { kind: 'content', hash: step.hash } : ABSENT,
|
|
836
1236
|
branchId,
|
|
837
|
-
|
|
1237
|
+
// A write whose plan gives a mode (`apply`) records the modes it may
|
|
1238
|
+
// leave, so a stop is read by them: the mode it saw, or for a file it
|
|
1239
|
+
// creates the one it creates it at, and the one it gives. A file a
|
|
1240
|
+
// forced push creates at its entry's mode with no mode planned records
|
|
1241
|
+
// none. One that goes on as our own stopped narrowing records that
|
|
1242
|
+
// push's, from the old bytes' own mode, whether or not it gives a mode
|
|
1243
|
+
// itself.
|
|
1244
|
+
...(step.kind === 'write' && step.ownModes !== undefined ? { modes: step.ownModes }
|
|
1245
|
+
: step.kind === 'write' && step.apply !== undefined
|
|
1246
|
+
? { modes: { from: step.seenMode ?? step.apply, to: step.apply } } : {}),
|
|
1247
|
+
}, { durable: i === announced.length - 1 });
|
|
838
1248
|
});
|
|
839
1249
|
// 2. Effects, each bound at its point of use.
|
|
840
1250
|
const effected = [];
|
|
@@ -842,8 +1252,51 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
842
1252
|
opts.beforeEffect?.(step.path);
|
|
843
1253
|
try {
|
|
844
1254
|
if (step.kind === 'write') {
|
|
845
|
-
await writeContained(mount.view, mount.rootReal, step.path, step.blob, step.expect
|
|
846
|
-
|
|
1255
|
+
const { perm, widenRefused, modeKept } = await writeContained(mount.view, mount.rootReal, step.path, step.blob, step.expect, step.apply, step.from, step.overDisk === true,
|
|
1256
|
+
// Where modes go unobserved, nothing is applied, a created file's included.
|
|
1257
|
+
mount.modesObserved ? step.storeMode : undefined);
|
|
1258
|
+
effected.push({ step, dirs: chainOf(step.path), mode: perm, widenRefused, modeKept });
|
|
1259
|
+
}
|
|
1260
|
+
else if (step.kind === 'chmod') {
|
|
1261
|
+
// An inode change, made durable by the file's own fsync.
|
|
1262
|
+
const { refused, narrowing } = await chmodContained(mount.view, mount.rootReal, step.path, step.mode, step.expect, step.from);
|
|
1263
|
+
// A chmod announces no intent, so a refused one leaves the evidence
|
|
1264
|
+
// as planning read it, unless it says otherwise below.
|
|
1265
|
+
if (refused && narrowing && !step.overDisk) {
|
|
1266
|
+
// A narrowing of the store's own change that the kernel refused
|
|
1267
|
+
// stays owed, as a write's does: taking disk's wider mode in would
|
|
1268
|
+
// let a later write put new bytes out at it.
|
|
1269
|
+
result.skipped.push({
|
|
1270
|
+
path: step.path,
|
|
1271
|
+
reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused to narrow it, as it does for a file another user owns, ` +
|
|
1272
|
+
'so it stays owed: a retry is refused the same way until the file\'s owner or an administrator narrows it',
|
|
1273
|
+
});
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1276
|
+
if (refused && step.overDisk) {
|
|
1277
|
+
// Forced over a mode disk changed, or one nothing records: the
|
|
1278
|
+
// path is as it was before the push, so a sync takes disk's mode
|
|
1279
|
+
// in, as it would have without force.
|
|
1280
|
+
result.skipped.push({
|
|
1281
|
+
path: step.path,
|
|
1282
|
+
reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused the chmod, so disk keeps its mode, and a sync takes it in`,
|
|
1283
|
+
});
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
if (refused) {
|
|
1287
|
+
// A widening of the store's own change that the kernel refused:
|
|
1288
|
+
// disk keeps its mode, and the evidence records none, so a sync
|
|
1289
|
+
// takes disk's in by the rule for an unknown rather than owing a
|
|
1290
|
+
// mode this process can never give.
|
|
1291
|
+
agreement.set(mount.name, step.path, { kind: 'content', hash: step.hash, size: step.size });
|
|
1292
|
+
recorded = true;
|
|
1293
|
+
result.skipped.push({
|
|
1294
|
+
path: step.path,
|
|
1295
|
+
reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused the chmod, and a sync takes disk's mode in`,
|
|
1296
|
+
});
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
effected.push({ step, dirs: [] });
|
|
847
1300
|
}
|
|
848
1301
|
else {
|
|
849
1302
|
// Its directory is synced whether this unlink removed the entry or
|
|
@@ -858,7 +1311,8 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
858
1311
|
// exactly what it was, whatever kind that was.
|
|
859
1312
|
agreement.restore(mount.name, step.path, step.before);
|
|
860
1313
|
recorded = true;
|
|
861
|
-
|
|
1314
|
+
const why = inTheWay(failure.message, step.kind === 'unlink') ?? failure.message;
|
|
1315
|
+
result.skipped.push({ path: step.path, reason: `not ${step.kind === 'unlink' ? 'unlinked' : step.kind === 'chmod' ? 'given the workspace\'s mode' : 'written'}: ${why}` });
|
|
862
1316
|
}
|
|
863
1317
|
else {
|
|
864
1318
|
// No completion: the intent stays pending, and the next observation
|
|
@@ -874,7 +1328,8 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
874
1328
|
// 4. Completions. P is physical and global. Branch intent belongs to the
|
|
875
1329
|
// branch this push planned on: it is settled only while that branch is
|
|
876
1330
|
// still selected, and otherwise by convergence when the branch returns.
|
|
877
|
-
for (const { step, dirs } of effected) {
|
|
1331
|
+
for (const { step, dirs, mode: written, widenRefused, modeKept } of effected) {
|
|
1332
|
+
const mode = mount.modesObserved ? written : undefined;
|
|
878
1333
|
const failed = dirs.find((dir) => unsynced.has(dir));
|
|
879
1334
|
if (failed !== undefined) {
|
|
880
1335
|
result.skipped.push({
|
|
@@ -884,11 +1339,64 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
884
1339
|
});
|
|
885
1340
|
continue;
|
|
886
1341
|
}
|
|
887
|
-
|
|
1342
|
+
// The mode the evidence records: the one the push gave the file, if the
|
|
1343
|
+
// file has it; disk's own, where the store records none or the same; and
|
|
1344
|
+
// otherwise the one disk last agreed with, so a mode disk changed since
|
|
1345
|
+
// reads as disk's. (Where modes go unobserved, the evidence's writer
|
|
1346
|
+
// records none.)
|
|
1347
|
+
// A widening of the workspace's own change that the kernel refused
|
|
1348
|
+
// records none: a sync takes disk's mode in, rather than owing one this
|
|
1349
|
+
// process can never give. Forced over a mode disk changed, or one nothing
|
|
1350
|
+
// records (overDisk), any refused chmod ends where an unforced write
|
|
1351
|
+
// would: the evidence records the mode disk last agreed with, if any, and
|
|
1352
|
+
// a sync takes disk's mode in.
|
|
1353
|
+
const agreedMode = step.kind === 'chmod'
|
|
1354
|
+
? step.mode
|
|
1355
|
+
: step.kind === 'write'
|
|
1356
|
+
? widenRefused && !step.overDisk
|
|
1357
|
+
? undefined
|
|
1358
|
+
: step.apply !== undefined && step.apply === mode
|
|
1359
|
+
? mode
|
|
1360
|
+
: step.storeMode === undefined || step.storeMode === mode ? mode : step.priorMode
|
|
1361
|
+
: undefined;
|
|
1362
|
+
const value = step.kind === 'unlink'
|
|
1363
|
+
? { kind: 'absent' }
|
|
1364
|
+
: { kind: 'content', hash: step.hash, size: step.kind === 'write' ? step.blob.byteLength : step.size, ...(agreedMode !== undefined ? { mode: agreedMode } : {}) };
|
|
888
1365
|
agreement.set(mount.name, step.path, value);
|
|
889
1366
|
recorded = true;
|
|
1367
|
+
// Bytes written where the kernel refused the mode, or where disk's mode
|
|
1368
|
+
// changed since it last agreed, keep disk's mode, and the push says so
|
|
1369
|
+
// beside what it wrote: the bytes reached disk, so it's no refusal.
|
|
1370
|
+
if (step.kind === 'write' && widenRefused && mode !== undefined) {
|
|
1371
|
+
result.modesKept.push({
|
|
1372
|
+
path: step.path,
|
|
1373
|
+
reason: `written, its mode left at ${octal(mode)}: the kernel refused the chmod, ` +
|
|
1374
|
+
`so the workspace's (${octal(step.apply ?? step.storeMode ?? mode)}) isn't given, and a sync takes disk's mode in`,
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
else if (step.kind === 'write' && modeKept && mode !== undefined) {
|
|
1378
|
+
// Forced over a mode disk changed, and refused: the bytes are written
|
|
1379
|
+
// at it, the evidence records it as an unforced write's would.
|
|
1380
|
+
result.modesKept.push({
|
|
1381
|
+
path: step.path,
|
|
1382
|
+
reason: `written, its mode left at ${octal(mode)}: the kernel refused to narrow it ` +
|
|
1383
|
+
`${narrowedTo(mode & (step.apply ?? mode), step.apply ?? mode)}, so disk keeps its mode, and a sync takes it in`,
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
else if (step.kind === 'write' && mode !== undefined && step.storeMode !== undefined && mode !== step.storeMode) {
|
|
1387
|
+
result.modesKept.push({
|
|
1388
|
+
path: step.path,
|
|
1389
|
+
reason: (step.priorMode === undefined
|
|
1390
|
+
? `written, keeping disk's mode (${octal(mode)}), which differs from the workspace's (${octal(step.storeMode)}), and nothing records which side changed it`
|
|
1391
|
+
: `written, keeping disk's mode (${octal(mode)}), which changed since it last agreed with the workspace's (${octal(step.storeMode)})`) +
|
|
1392
|
+
' — sync this path to take disk\'s mode in, or materialize this path with force to apply the workspace\'s',
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
890
1395
|
const planned = store.currentBranch().id === branchId;
|
|
891
|
-
if (step.kind === '
|
|
1396
|
+
if (step.kind === 'chmod') {
|
|
1397
|
+
result.written.push(step.path);
|
|
1398
|
+
}
|
|
1399
|
+
else if (step.kind === 'write') {
|
|
892
1400
|
if (planned)
|
|
893
1401
|
mount.intents.update(step.path, (cur) => { const next = { ...cur }; delete next.conflict; delete next.origin; return next; });
|
|
894
1402
|
result.written.push(step.path);
|