@animalabs/agent-framework 0.27.0 → 0.29.0
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 +145 -41
- package/dist/src/agent.d.ts +29 -2
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +73 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +3 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +11 -5
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/auto-continue.d.ts +5 -2
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +9 -5
- package/dist/src/auto-continue.js.map +1 -1
- package/dist/src/code-execution/isolate/runner.d.ts +7 -5
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/runner.js +7 -5
- package/dist/src/code-execution/isolate/runner.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +3 -2
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/cut-off-round.d.ts +24 -0
- package/dist/src/cut-off-round.d.ts.map +1 -0
- package/dist/src/cut-off-round.js +87 -0
- package/dist/src/cut-off-round.js.map +1 -0
- package/dist/src/framework.d.ts +468 -125
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +3651 -1111
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +133 -13
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +654 -59
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +3 -2
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +2 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/reply-judge.d.ts +116 -0
- package/dist/src/gate/reply-judge.d.ts.map +1 -0
- package/dist/src/gate/reply-judge.js +467 -0
- package/dist/src/gate/reply-judge.js.map +1 -0
- package/dist/src/gate/types.d.ts +173 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +202 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -0
- package/dist/src/heartbeat/heartbeat.js +778 -0
- package/dist/src/heartbeat/heartbeat.js.map +1 -0
- package/dist/src/heartbeat/reminder-time.d.ts +5 -0
- package/dist/src/heartbeat/reminder-time.d.ts.map +1 -0
- package/dist/src/heartbeat/reminder-time.js +107 -0
- package/dist/src/heartbeat/reminder-time.js.map +1 -0
- package/dist/src/held-writes.d.ts +3 -3
- package/dist/src/held-writes.js +3 -3
- package/dist/src/host-presentation.d.ts +170 -0
- package/dist/src/host-presentation.d.ts.map +1 -0
- package/dist/src/host-presentation.js +561 -0
- package/dist/src/host-presentation.js.map +1 -0
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/line-reader.d.ts +4 -0
- package/dist/src/line-reader.d.ts.map +1 -0
- package/dist/src/line-reader.js +59 -0
- package/dist/src/line-reader.js.map +1 -0
- package/dist/src/mcpl/capability-mask.d.ts.map +1 -1
- package/dist/src/mcpl/capability-mask.js +3 -2
- package/dist/src/mcpl/capability-mask.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +34 -6
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +133 -54
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +2 -1
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +1 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +16 -4
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +4 -3
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +29 -11
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +43 -70
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +11 -7
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +3 -2
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +25 -3
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-handler.js +2 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +12 -40
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +29 -23
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +18 -8
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +70 -30
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +25 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.js +25 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +9 -2
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +12 -2
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts +66 -14
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +150 -80
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts +10 -3
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +60 -30
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +88 -55
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +220 -111
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +27 -35
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +313 -91
- package/dist/src/mcpl/toolsets-module.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +16 -16
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +31 -13
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +10 -8
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +15 -9
- 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 +4 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +33 -25
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +30 -17
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/sender-name.d.ts +7 -0
- package/dist/src/modules/sender-name.d.ts.map +1 -0
- package/dist/src/modules/sender-name.js +10 -0
- package/dist/src/modules/sender-name.js.map +1 -0
- package/dist/src/modules/workspace/answers.d.ts +26 -0
- package/dist/src/modules/workspace/answers.d.ts.map +1 -0
- package/dist/src/modules/workspace/answers.js +138 -0
- package/dist/src/modules/workspace/answers.js.map +1 -0
- package/dist/src/modules/workspace/branch-intent.d.ts +5 -3
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +6 -2
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts +3 -0
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +59 -24
- package/dist/src/modules/workspace/direct-write.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +33 -11
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +48 -17
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/edit-text.d.ts +2 -1
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/edit-text.js +4 -2
- package/dist/src/modules/workspace/edit-text.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +4 -2
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +67 -50
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +63 -51
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +980 -547
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +125 -82
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +465 -241
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/read-page.d.ts.map +1 -1
- package/dist/src/modules/workspace/read-page.js +7 -1
- package/dist/src/modules/workspace/read-page.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +7 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +156 -50
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/result-text.d.ts +1 -0
- package/dist/src/modules/workspace/result-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/result-text.js.map +1 -1
- package/dist/src/modules/workspace/sync.d.ts +9 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -1
- package/dist/src/modules/workspace/sync.js +14 -0
- package/dist/src/modules/workspace/sync.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +96 -43
- 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.map +1 -1
- package/dist/src/modules/workspace/watcher.js +8 -3
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/notice-tags.d.ts +79 -0
- package/dist/src/notice-tags.d.ts.map +1 -0
- package/dist/src/notice-tags.js +83 -0
- package/dist/src/notice-tags.js.map +1 -0
- package/dist/src/prose-drafts.d.ts +4 -3
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +3 -2
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/reasoning-loss-notice.d.ts +23 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -0
- package/dist/src/reasoning-loss-notice.js +52 -0
- package/dist/src/reasoning-loss-notice.js.map +1 -0
- package/dist/src/reasoning-loss.d.ts +24 -0
- package/dist/src/reasoning-loss.d.ts.map +1 -0
- package/dist/src/reasoning-loss.js +102 -0
- package/dist/src/reasoning-loss.js.map +1 -0
- package/dist/src/send-tools.d.ts +3 -2
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +3 -2
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/sent-rows.js +1 -1
- package/dist/src/silent-heartbeat.d.ts +1 -53
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +56 -3
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/supplied-text.d.ts +35 -0
- package/dist/src/supplied-text.d.ts.map +1 -0
- package/dist/src/supplied-text.js +141 -0
- package/dist/src/supplied-text.js.map +1 -0
- package/dist/src/thinking-drops.d.ts +4 -11
- package/dist/src/thinking-drops.d.ts.map +1 -1
- package/dist/src/thinking-drops.js +7 -14
- package/dist/src/thinking-drops.js.map +1 -1
- package/dist/src/tool-args.d.ts +12 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +39 -4
- package/dist/src/tool-args.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +2 -1
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +5 -4
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +8 -4
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +23 -11
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +3 -2
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +24 -26
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +4 -1
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/types/agent.d.ts +63 -18
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +18 -8
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +58 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +27 -13
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +34 -1
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/agent.ts +76 -12
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +11 -5
- package/src/auto-continue.ts +12 -5
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/cut-off-round.ts +98 -0
- package/src/framework.ts +3772 -1138
- package/src/gate/event-gate.ts +705 -60
- package/src/gate/index.ts +9 -1
- package/src/gate/reply-judge.ts +512 -0
- package/src/gate/types.ts +176 -3
- package/src/heartbeat/heartbeat.ts +843 -0
- package/src/heartbeat/reminder-time.ts +107 -0
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +605 -0
- package/src/index.ts +5 -1
- package/src/line-reader.ts +58 -0
- package/src/mcpl/capability-mask.ts +3 -2
- package/src/mcpl/channel-registry.ts +139 -53
- package/src/mcpl/conversation-router.ts +2 -1
- package/src/mcpl/convert-block.ts +17 -4
- package/src/mcpl/hook-orchestrator.ts +4 -3
- package/src/mcpl/inbound-source.ts +45 -70
- package/src/mcpl/modern-connection.ts +11 -7
- package/src/mcpl/protocol-family.ts +24 -3
- package/src/mcpl/push-handler.ts +2 -2
- package/src/mcpl/references.ts +31 -23
- package/src/mcpl/server-connection.ts +76 -34
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tags.ts +13 -2
- package/src/mcpl/tool-presence.ts +149 -82
- package/src/mcpl/tool-signature.ts +64 -32
- package/src/mcpl/toolset-host.ts +212 -110
- package/src/mcpl/toolsets-module.ts +277 -91
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +32 -13
- package/src/module-registry.ts +14 -9
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +30 -18
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +151 -0
- package/src/modules/workspace/branch-intent.ts +10 -5
- package/src/modules/workspace/direct-write.ts +59 -23
- package/src/modules/workspace/disk-agreement.ts +52 -21
- package/src/modules/workspace/edit-text.ts +7 -5
- package/src/modules/workspace/effects.ts +69 -50
- package/src/modules/workspace/index.ts +966 -556
- package/src/modules/workspace/observe.ts +497 -242
- package/src/modules/workspace/read-page.ts +7 -1
- package/src/modules/workspace/reconcile.ts +184 -49
- package/src/modules/workspace/result-text.ts +2 -0
- package/src/modules/workspace/sync.ts +16 -0
- package/src/modules/workspace/types.ts +96 -43
- package/src/modules/workspace/watcher.ts +8 -3
- package/src/notice-tags.ts +84 -0
- package/src/prose-drafts.ts +4 -3
- package/src/reasoning-loss-notice.ts +64 -0
- package/src/reasoning-loss.ts +120 -0
- package/src/send-tools.ts +3 -2
- package/src/sent-rows.ts +1 -1
- package/src/silent-heartbeat.ts +4 -3
- package/src/supplied-text.ts +154 -0
- package/src/thinking-drops.ts +10 -16
- package/src/tool-args.ts +38 -4
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tool-result-guard.ts +26 -11
- package/src/tune-out/coordinator.ts +25 -27
- package/src/tune-out/tools.ts +4 -1
- package/src/types/agent.ts +63 -18
- package/src/types/events.ts +18 -8
- package/src/types/framework.ts +59 -0
- package/src/types/module.ts +28 -13
- package/src/types/trace.ts +36 -1
|
@@ -38,8 +38,10 @@
|
|
|
38
38
|
* a wrong adoption.
|
|
39
39
|
*/
|
|
40
40
|
import { candidateOf, sameCandidate, sameRootIdentity, } from './disk-agreement.js';
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
41
|
+
import { storedBytes } from './sync.js';
|
|
42
|
+
import { BENEATH_SYMLINK, CHANGED, CHANGED_WALK, DIRECTORY, EDITOR_FILE_REASON, FILE_CHANGED, IGNORED, LEAVES_MOUNT, LINK_NOT_WALKED, LINK_TO_DIRECTORY, NOT_A_DIRECTORY, NOT_FOLLOWED, NOT_REGULAR, OUTSIDE_PARENT, RESOLVES_OUTSIDE, ROOT_UNAVAILABLE, OTHER_MOUNT, ROOT_REPLACED, fingerprintVouches, ignoreBeneath, inOtherMount, locateRoot, looksBinary, observePath, passedOverAt, passedOverBetween, provenAbsent, readHead, readPath, sniffImageMime, walkScope, withinIncludes, } from './observe.js';
|
|
43
|
+
import { EffectFailed, callFailed, chainOf, chmodContained, narrowedTo, syncDirectories, unlinkContained, writeContained } from './effects.js';
|
|
44
|
+
import { OUTSIDE_STEP, RESOLVED_OUTSIDE_STEP, UNFOLLOWED_STEP, errnoClause, errnoWords } from './answers.js';
|
|
43
45
|
const ABSENT = { kind: 'absent' };
|
|
44
46
|
export const WALK_CAP = 5000;
|
|
45
47
|
function diskCandidate(d) {
|
|
@@ -196,21 +198,22 @@ function settleAdoption(p, s) {
|
|
|
196
198
|
/**
|
|
197
199
|
* What's in the way, and the way out, when disk's shape keeps a push from a
|
|
198
200
|
* 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,
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
201
|
+
* anything but a regular file or a followed symlink to one, writes below a
|
|
202
|
+
* file or a symlink the walk won't take, or writes or unlinks through a
|
|
203
|
+
* symlink the mount doesn't follow or one that leads out of the mount
|
|
204
|
+
* (`writeContained`, `unlinkContained`), forced or not. Null for any other
|
|
205
|
+
* reason.
|
|
203
206
|
*/
|
|
204
207
|
function inTheWay(reason, deletion) {
|
|
205
208
|
// Observation's words for what a deletion never unlinks, which the unlink
|
|
206
209
|
// refuses in the same words.
|
|
207
|
-
if (deletion && (reason ===
|
|
208
|
-
const what = reason ===
|
|
210
|
+
if (deletion && (reason === NOT_REGULAR || reason === LINK_TO_DIRECTORY)) {
|
|
211
|
+
const what = reason === NOT_REGULAR
|
|
209
212
|
? 'a pipe, socket or device at this path, or a symlink to one'
|
|
210
213
|
: 'a symlink to a directory at this path';
|
|
211
214
|
return `disk has ${what}, and no push unlinks it, forced or not — ask whoever runs this host if it should go`;
|
|
212
215
|
}
|
|
213
|
-
if (reason ===
|
|
216
|
+
if (reason === DIRECTORY) {
|
|
214
217
|
return deletion
|
|
215
218
|
? '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
219
|
: 'disk has a directory at this path, and no push writes a file over one, forced or not — ' +
|
|
@@ -218,12 +221,94 @@ function inTheWay(reason, deletion) {
|
|
|
218
221
|
}
|
|
219
222
|
// A deletion below a file finds nothing there to unlink, so only a write
|
|
220
223
|
// meets this one.
|
|
221
|
-
if (reason ===
|
|
224
|
+
if (reason === NOT_A_DIRECTORY) {
|
|
222
225
|
return 'disk has a file or a symlink where this path needs a directory, and no push writes below one, forced or not — ' +
|
|
223
226
|
'move or remove it on disk and materialize again, or write the file under another path';
|
|
224
227
|
}
|
|
228
|
+
const link = reason === NOT_FOLLOWED ? 'disk has a symlink at this path, which this mount does not follow'
|
|
229
|
+
: reason === LEAVES_MOUNT ? 'this path leads out of the mount through a symlink on it'
|
|
230
|
+
: null;
|
|
231
|
+
if (link !== null) {
|
|
232
|
+
return deletion
|
|
233
|
+
? `${link}, and no push unlinks ${reason === NOT_FOLLOWED ? 'one' : 'through one'}, forced or not — ask whoever runs this host if it should go`
|
|
234
|
+
: `${link}, and no push writes through one, forced or not — write the file under another path, ` +
|
|
235
|
+
`or whoever runs this host can remove the link, and ${THEN.write}`;
|
|
236
|
+
}
|
|
237
|
+
if (deletion && reason === BENEATH_SYMLINK) {
|
|
238
|
+
return 'a symlink on this path does not lead to a directory inside the mount, so nothing beneath it is in this mount, and no push unlinks beneath one, '
|
|
239
|
+
+ `forced or not — whoever runs this host can remove the link or make it lead to a directory inside the mount, and ${THEN.unlink}`;
|
|
240
|
+
}
|
|
241
|
+
if (reason === OUTSIDE_PARENT) {
|
|
242
|
+
return `a directory on this path leads out of the mount, and no push ${deletion ? 'unlinks' : 'writes'} beneath one, forced or not — ` +
|
|
243
|
+
(deletion ? 'ask whoever runs this host if what is there should go' : 'write the file under another path');
|
|
244
|
+
}
|
|
245
|
+
if (reason === NOT_REGULAR || reason === LINK_TO_DIRECTORY) {
|
|
246
|
+
const what = reason === NOT_REGULAR ? 'a pipe, socket or device at this path, or a symlink to one' : 'a symlink to a directory at this path';
|
|
247
|
+
return `disk has ${what}, and no push writes a file over it, forced or not — write the file under another path, ` +
|
|
248
|
+
`or whoever runs this host can remove it, and ${THEN.write}`;
|
|
249
|
+
}
|
|
225
250
|
return null;
|
|
226
251
|
}
|
|
252
|
+
const AGAIN = {
|
|
253
|
+
write: 'materializing again',
|
|
254
|
+
unlink: 'materializing again with applyDeletions',
|
|
255
|
+
sync: 'syncing this path again',
|
|
256
|
+
list: 'listing it',
|
|
257
|
+
read: 'calling again',
|
|
258
|
+
};
|
|
259
|
+
const THEN = {
|
|
260
|
+
write: 'materializing again then gets past it',
|
|
261
|
+
unlink: 'materializing again with applyDeletions then gets past it',
|
|
262
|
+
sync: 'a sync of this path then takes it in',
|
|
263
|
+
list: 'the workspace then reaches it',
|
|
264
|
+
read: 'a read then reaches it',
|
|
265
|
+
};
|
|
266
|
+
const CHANGED_WHILE = new Set([CHANGED, CHANGED_WALK, FILE_CHANGED]);
|
|
267
|
+
const WALKED_PAST = new Set([IGNORED, EDITOR_FILE_REASON, LINK_NOT_WALKED]);
|
|
268
|
+
export function explained(reason, cause, meets) {
|
|
269
|
+
if (meets === 'write' || meets === 'unlink') {
|
|
270
|
+
const shaped = inTheWay(reason, meets === 'unlink');
|
|
271
|
+
if (shaped !== null)
|
|
272
|
+
return shaped;
|
|
273
|
+
}
|
|
274
|
+
return withWayOn(reason, cause, meets);
|
|
275
|
+
}
|
|
276
|
+
function withWayOn(reason, cause, meets) {
|
|
277
|
+
const on = wayOn(reason, cause, meets);
|
|
278
|
+
return on === null ? reason : `${reason} — ${on}`;
|
|
279
|
+
}
|
|
280
|
+
export function wayOn(reason, cause, meets) {
|
|
281
|
+
const lasting = `${AGAIN[meets]} won't change that; `;
|
|
282
|
+
if (reason === ROOT_UNAVAILABLE) {
|
|
283
|
+
if (cause.errno === 'ENOENT' || cause.errno === 'ENOTDIR')
|
|
284
|
+
return `${lasting}whoever runs this host can put the mount's directory back at its path, and ${THEN[meets]}`;
|
|
285
|
+
if (cause.errno === undefined)
|
|
286
|
+
return `${AGAIN[meets]} checks it afresh; if it's still unavailable, whoever runs this host can check the mount's directory and its path`;
|
|
287
|
+
}
|
|
288
|
+
if (cause.errno !== undefined)
|
|
289
|
+
return errnoClause(cause.errno, AGAIN[meets], THEN[meets]);
|
|
290
|
+
if (cause.again === true || CHANGED_WHILE.has(reason))
|
|
291
|
+
return `${AGAIN[meets]} checks it afresh`;
|
|
292
|
+
switch (reason) {
|
|
293
|
+
case NOT_FOLLOWED:
|
|
294
|
+
return lasting + UNFOLLOWED_STEP;
|
|
295
|
+
case LEAVES_MOUNT:
|
|
296
|
+
return lasting + OUTSIDE_STEP;
|
|
297
|
+
case BENEATH_SYMLINK:
|
|
298
|
+
return `${lasting}nothing beneath it is in this mount, and whoever runs this host can make it lead to a directory inside the mount, or, where it leads to a directory outside, mount that directory`;
|
|
299
|
+
case OUTSIDE_PARENT:
|
|
300
|
+
case RESOLVES_OUTSIDE:
|
|
301
|
+
return lasting + RESOLVED_OUTSIDE_STEP;
|
|
302
|
+
case NOT_REGULAR:
|
|
303
|
+
return `${lasting}whoever runs this host can put a regular file there, and ${THEN[meets]}`;
|
|
304
|
+
case DIRECTORY:
|
|
305
|
+
return `${lasting}ls of this path lists what's in it`;
|
|
306
|
+
case LINK_TO_DIRECTORY:
|
|
307
|
+
return `${lasting}ls of the directory it leads to lists what's in it`;
|
|
308
|
+
default:
|
|
309
|
+
return meets === 'sync' && WALKED_PAST.has(reason) ? 'a sync of this path checks it' : null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
227
312
|
/**
|
|
228
313
|
* The forced way out the refusal of a disk copy that couldn't be verified
|
|
229
314
|
* names, if any. A forced push skips the verification, so it gets past the
|
|
@@ -237,10 +322,16 @@ function inTheWay(reason, deletion) {
|
|
|
237
322
|
* to pass.
|
|
238
323
|
*/
|
|
239
324
|
function forcedWay(note, deletion, forced) {
|
|
240
|
-
if (note ===
|
|
325
|
+
if (note === `cannot open (${errnoWords('EACCES')})`)
|
|
241
326
|
return `, or, if disk lets the workspace ${deletion ? 'unlink' : 'write'} the file, ${forced}`;
|
|
242
327
|
return '';
|
|
243
328
|
}
|
|
329
|
+
const UNSETTLED = "whether disk holds the change isn't known until it's checked: a materialize of this path checks it and says how it ended";
|
|
330
|
+
function unverifiedCopy(v, meets, forced) {
|
|
331
|
+
const note = v.note ?? 'not observed';
|
|
332
|
+
const on = wayOn(note, v.noteCause ?? {}, meets);
|
|
333
|
+
return `cannot verify disk copy (${note})${on !== null ? ` — ${on}` : ''}${forcedWay(v.note, meets === 'unlink', forced)}`;
|
|
334
|
+
}
|
|
244
335
|
/**
|
|
245
336
|
* The synchronous precondition of every workspace mutation: evidence owed a
|
|
246
337
|
* barrier is made durable first, and an adoption left pending on the
|
|
@@ -360,6 +451,9 @@ function adoptDisk(d, s) {
|
|
|
360
451
|
return { state: 'synced', adopt: 'ingest', op: s ? 'modified' : 'created', p: agreedFromDisk(d), intent: {} };
|
|
361
452
|
return { state: 'disk-only', ...(s ? { adopt: 'drop', op: 'deleted' } : {}), p: 'forget', intent: {} };
|
|
362
453
|
}
|
|
454
|
+
function causeOf({ errno, ownStep }) {
|
|
455
|
+
return { ...(errno !== undefined ? { errno } : {}), ...(ownStep ? { ownStep } : {}) };
|
|
456
|
+
}
|
|
363
457
|
/** The rule (see module doc). Pure. */
|
|
364
458
|
function decide(d, s, pIn, bi, branchId, adopt) {
|
|
365
459
|
// A branch intent that can't be read may have held a tombstone or a
|
|
@@ -369,9 +463,9 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
369
463
|
if (d.kind === 'unobserved') {
|
|
370
464
|
// Disk proves nothing, but an adoption on this branch settles by the tree.
|
|
371
465
|
if (pIn?.kind === 'pending' && pIn.effect === 'adopt' && pIn.branchId === branchId && !adopt) {
|
|
372
|
-
return { state: 'unverified', note: d.reason, p: settleAdoption(pIn, s) };
|
|
466
|
+
return { state: 'unverified', note: d.reason, noteCause: causeOf(d), p: settleAdoption(pIn, s) };
|
|
373
467
|
}
|
|
374
|
-
return { state: 'unverified', note: d.reason };
|
|
468
|
+
return { state: 'unverified', note: d.reason, noteCause: causeOf(d) };
|
|
375
469
|
}
|
|
376
470
|
if (d.kind === 'unhashed') {
|
|
377
471
|
// Observed this way only when nothing tracks the path, which is then a
|
|
@@ -549,6 +643,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
549
643
|
// is followed, as `rootReal` is: `followSymlinks` governs links within it.
|
|
550
644
|
const root = await locateRoot(mount.view, mount.rootReal);
|
|
551
645
|
const rootUnavailable = 'reason' in root ? root.reason : null;
|
|
646
|
+
const rootCause = 'reason' in root && root.errno !== undefined ? { errno: root.errno } : {};
|
|
552
647
|
// The branch is labelled where the tracked candidates are read, with no
|
|
553
648
|
// await between: the decision is checked against this label.
|
|
554
649
|
const branchId = store.currentBranch().id;
|
|
@@ -563,7 +658,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
563
658
|
if (rootUnavailable !== null) {
|
|
564
659
|
// Said whether or not anything is tracked: an unavailable mount must not
|
|
565
660
|
// read as a verified empty directory.
|
|
566
|
-
gathered.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : '', reason: rootUnavailable });
|
|
661
|
+
gathered.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : '', reason: explained(rootUnavailable, rootCause, 'list') });
|
|
567
662
|
}
|
|
568
663
|
// Which paths to decide: what disk shows, and what the store, P and intent
|
|
569
664
|
// track. The tracked ones are read synchronously, on this branch. A path
|
|
@@ -615,7 +710,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
615
710
|
// Observe. Tracked facts are read again, synchronously, when deciding.
|
|
616
711
|
for (const path of candidates) {
|
|
617
712
|
if (rootUnavailable !== null) {
|
|
618
|
-
gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable });
|
|
713
|
+
gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable, ...rootCause });
|
|
619
714
|
continue;
|
|
620
715
|
}
|
|
621
716
|
// What the mount passes over by design stays unobserved by a pass that
|
|
@@ -638,8 +733,8 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
638
733
|
}
|
|
639
734
|
else if (!opts.named) {
|
|
640
735
|
const slash = path.lastIndexOf('/');
|
|
641
|
-
const above = slash < 0 ? undefined : passedOverAt(path.slice(0, slash), mount.view.ignore, mount.view.others);
|
|
642
|
-
const own = above === undefined && !walk ? passedOverAt(path, mount.view.ignore, mount.view.others) : undefined;
|
|
736
|
+
const above = slash < 0 ? undefined : passedOverAt(path.slice(0, slash), mount.view.ignore, mount.view.others, true);
|
|
737
|
+
const own = above === undefined && !walk ? passedOverAt(path, mount.view.ignore, mount.view.others, false) : undefined;
|
|
643
738
|
byDesign = above ?? own;
|
|
644
739
|
}
|
|
645
740
|
else if (scope.kind === 'dir') {
|
|
@@ -670,7 +765,9 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
670
765
|
if (region === undefined || r.path.length > region.path.length)
|
|
671
766
|
region = r;
|
|
672
767
|
}
|
|
673
|
-
gathered.facts.set(path,
|
|
768
|
+
gathered.facts.set(path, region
|
|
769
|
+
? { kind: 'unobserved', reason: region.reason, ...(region.errno !== undefined ? { errno: region.errno } : {}) }
|
|
770
|
+
: { kind: 'unobserved', reason: 'not reached by the walk' });
|
|
674
771
|
continue;
|
|
675
772
|
}
|
|
676
773
|
const p = agreement.get(mount.name, path);
|
|
@@ -686,12 +783,13 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
686
783
|
const after = await locateRoot(mount.view, mount.rootReal);
|
|
687
784
|
if (!('identity' in after) || !sameRootIdentity(after.identity, gathered.rootIdentity)) {
|
|
688
785
|
const reason = 'reason' in after ? after.reason : ROOT_REPLACED;
|
|
786
|
+
const errno = 'errno' in after ? after.errno : undefined;
|
|
689
787
|
for (const path of gathered.facts.keys())
|
|
690
|
-
gathered.facts.set(path, { kind: 'unobserved', reason });
|
|
788
|
+
gathered.facts.set(path, { kind: 'unobserved', reason, ...(errno !== undefined ? { errno } : {}) });
|
|
691
789
|
gathered.rootIdentity = null;
|
|
692
790
|
gathered.walk = null;
|
|
693
791
|
gathered.dirs = [];
|
|
694
|
-
gathered.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : '', reason });
|
|
792
|
+
gathered.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : '', reason: explained(reason, errno !== undefined ? { errno } : {}, 'list') });
|
|
695
793
|
}
|
|
696
794
|
}
|
|
697
795
|
return gathered;
|
|
@@ -721,14 +819,13 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
721
819
|
}
|
|
722
820
|
}
|
|
723
821
|
if (gathered === null) {
|
|
724
|
-
result.
|
|
822
|
+
result.undecided = 'the selected branch kept changing while the scan ran';
|
|
823
|
+
result.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : '', reason: explained(result.undecided, { again: true }, 'list') });
|
|
725
824
|
return result;
|
|
726
825
|
}
|
|
727
826
|
if (opts.branchId !== undefined && gathered.branchId !== opts.branchId) {
|
|
728
|
-
result.
|
|
729
|
-
|
|
730
|
-
reason: 'the selected branch changed before this sync ran; nothing was taken from disk — sync again on this branch to take it',
|
|
731
|
-
});
|
|
827
|
+
result.undecided = 'the selected branch changed before this sync ran; nothing was taken from disk — sync again on this branch to take it';
|
|
828
|
+
result.incomplete.push({ path: scope.kind === 'dir' ? scope.dir : scope.paths.join(', '), reason: result.undecided });
|
|
732
829
|
return result;
|
|
733
830
|
}
|
|
734
831
|
const { walk, facts } = gathered;
|
|
@@ -746,9 +843,13 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
746
843
|
planned.push({ path, verdict, d, s, p, bi });
|
|
747
844
|
}
|
|
748
845
|
// The evidence about to be recorded describes the root it was gathered
|
|
749
|
-
// under, which is recorded first
|
|
750
|
-
//
|
|
751
|
-
|
|
846
|
+
// under, which is recorded first, so no crash can leave evidence without
|
|
847
|
+
// its root. Once a root is recorded, every pass that found it offers it,
|
|
848
|
+
// evidence or none: the same root on a new device, or with its first
|
|
849
|
+
// birth time, is recorded again (recordRootIdentity writes nothing
|
|
850
|
+
// otherwise), and a quiet mount's passes are where an old record learns
|
|
851
|
+
// its birth time.
|
|
852
|
+
if (gathered.rootIdentity && (agreement.rootIdentity(mount.name) !== undefined || planned.some((x) => x.verdict.adopt !== undefined || x.verdict.p !== undefined))) {
|
|
752
853
|
agreement.recordRootIdentity(mount.name, gathered.rootIdentity);
|
|
753
854
|
}
|
|
754
855
|
// 1. Intents for adoptions, durable before any tree commit.
|
|
@@ -855,6 +956,8 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
855
956
|
}
|
|
856
957
|
if (x.verdict.note)
|
|
857
958
|
report.note = x.verdict.note;
|
|
959
|
+
if (x.verdict.noteCause !== undefined)
|
|
960
|
+
report.noteCause = x.verdict.noteCause;
|
|
858
961
|
if (!(x.verdict.state === 'synced' && !entry))
|
|
859
962
|
result.reports.set(x.path, report);
|
|
860
963
|
}
|
|
@@ -885,8 +988,9 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
885
988
|
// holder), so naming the directory as unreached would never clear.
|
|
886
989
|
const wholeScope = scope.kind === 'dir' && scope.dir !== '' && region.path === scope.dir;
|
|
887
990
|
const unreached = hides && region.reason !== OTHER_MOUNT;
|
|
888
|
-
if (region.kind === 'error' || region.kind === 'cap' || unreached || wholeScope)
|
|
889
|
-
result.incomplete.push({ path: region.path, reason: region.reason });
|
|
991
|
+
if (region.kind === 'error' || region.kind === 'cap' || unreached || wholeScope) {
|
|
992
|
+
result.incomplete.push({ path: region.path, reason: explained(region.reason, region.errno !== undefined ? { errno: region.errno } : {}, 'list') });
|
|
993
|
+
}
|
|
890
994
|
// A name passed over by design that hides nothing tracked is reported nowhere else:
|
|
891
995
|
// counted, so a sync that says 0 also says what it didn't look at
|
|
892
996
|
// (agent-framework #276). A symlink region isn't counted: a link the
|
|
@@ -935,8 +1039,9 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
935
1039
|
// unmounted from. The push plans nothing, so it reports no branch.
|
|
936
1040
|
const root = await locateRoot(mount.view, mount.rootReal);
|
|
937
1041
|
if ('reason' in root) {
|
|
1042
|
+
const why = explained(root.reason, root.errno !== undefined ? { errno: root.errno } : {}, 'write');
|
|
938
1043
|
for (const path of paths)
|
|
939
|
-
result.skipped.push({ path, reason:
|
|
1044
|
+
result.skipped.push({ path, reason: why });
|
|
940
1045
|
return result;
|
|
941
1046
|
}
|
|
942
1047
|
// Another mount's directory nested in this one is that mount's: no push
|
|
@@ -965,7 +1070,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
965
1070
|
// nothing is decided or recorded from them.
|
|
966
1071
|
const after = await locateRoot(mount.view, mount.rootReal);
|
|
967
1072
|
if (!('identity' in after) || !sameRootIdentity(after.identity, root.identity)) {
|
|
968
|
-
const reason = 'reason' in after ? after.reason : ROOT_REPLACED;
|
|
1073
|
+
const reason = 'reason' in after ? explained(after.reason, after.errno !== undefined ? { errno: after.errno } : {}, 'write') : ROOT_REPLACED;
|
|
969
1074
|
for (const path of paths)
|
|
970
1075
|
result.skipped.push({ path, reason });
|
|
971
1076
|
return result;
|
|
@@ -986,9 +1091,6 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
986
1091
|
const p = agreement.get(mount.name, path);
|
|
987
1092
|
const bi = mount.intents.get(path);
|
|
988
1093
|
const v = decide(d, s, p, bi, branchId, false);
|
|
989
|
-
// The ways out a refusal names, as materialize takes them: a deletion
|
|
990
|
-
// reaches disk only with applyDeletions.
|
|
991
|
-
const again = s ? 'materialize again' : 'materialize again with applyDeletions';
|
|
992
1094
|
// Where disk has deleted a file the workspace holds, a sync takes the
|
|
993
1095
|
// deletion, which removes the workspace's copy, and a forced push writes
|
|
994
1096
|
// the workspace's copy back: there is no disk copy to adopt or overwrite.
|
|
@@ -1015,12 +1117,12 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1015
1117
|
continue;
|
|
1016
1118
|
}
|
|
1017
1119
|
const priorP = p && (p.kind === 'absent' || p.kind === 'content') ? p : null;
|
|
1018
|
-
const
|
|
1120
|
+
const stored = storedBytes(store, s.hash);
|
|
1019
1121
|
const forcedMode = mount.modesObserved && s.mode !== undefined && s.mode !== (d.kind === 'file' ? d.mode : undefined) ? s.mode : undefined;
|
|
1020
1122
|
const agreedMode = priorP?.kind === 'content' ? priorP.mode : undefined;
|
|
1021
|
-
if (
|
|
1123
|
+
if ('bytes' in stored) {
|
|
1022
1124
|
plans.push({
|
|
1023
|
-
path, kind: 'write', blob, hash: s.hash, prior: priorP, before: agreement.get(mount.name, path), expect,
|
|
1125
|
+
path, kind: 'write', blob: stored.bytes, hash: s.hash, prior: priorP, before: agreement.get(mount.name, path), expect,
|
|
1024
1126
|
...(forcedMode !== undefined ? { apply: forcedMode } : {}),
|
|
1025
1127
|
...(forcedMode !== undefined && d.kind === 'file' && agreedMode !== d.mode ? { overDisk: true } : {}),
|
|
1026
1128
|
...(s.mode !== undefined ? { storeMode: s.mode } : {}),
|
|
@@ -1031,7 +1133,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1031
1133
|
});
|
|
1032
1134
|
}
|
|
1033
1135
|
else
|
|
1034
|
-
result.skipped.push({ path, reason:
|
|
1136
|
+
result.skipped.push({ path, reason: unstoredCopy(stored) });
|
|
1035
1137
|
continue;
|
|
1036
1138
|
}
|
|
1037
1139
|
if (v.mode === 'adopt' && s && d.kind === 'file') {
|
|
@@ -1057,7 +1159,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1057
1159
|
}
|
|
1058
1160
|
// Whatever the verdict learned about disk (an agreement, a resolved
|
|
1059
1161
|
// intent) is recorded before anything is pushed over it, and the root it
|
|
1060
|
-
// was learned under before that
|
|
1162
|
+
// was learned under before that, as a pass does.
|
|
1061
1163
|
if (v.p !== undefined)
|
|
1062
1164
|
agreement.recordRootIdentity(mount.name, root.identity);
|
|
1063
1165
|
if (v.p === 'forget')
|
|
@@ -1112,8 +1214,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1112
1214
|
? d.kind === 'absent' || d.kind === 'file'
|
|
1113
1215
|
? `${v.note} — ${sync}`
|
|
1114
1216
|
: `${v.note}, and disk's copy can't be verified (${d.kind === 'unobserved' ? d.reason : 'not hashed'}) — once it can be, ${sync}`
|
|
1115
|
-
: inTheWay(v.note, !s) ??
|
|
1116
|
-
`cannot verify disk copy (${v.note ?? 'not observed'}) — fix it and ${again}${forcedWay(v.note, !s, forced)}`,
|
|
1217
|
+
: inTheWay(v.note, !s) ?? unverifiedCopy(v, s ? 'write' : 'unlink', forced),
|
|
1117
1218
|
});
|
|
1118
1219
|
continue;
|
|
1119
1220
|
}
|
|
@@ -1180,7 +1281,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1180
1281
|
// A deletion no push makes, forced or not (inTheWay), is refused for
|
|
1181
1282
|
// that, as an unforced push refuses it, rather than left for
|
|
1182
1283
|
// applyDeletions, which couldn't make it either.
|
|
1183
|
-
const lasting = inTheWay(v.note, true);
|
|
1284
|
+
const lasting = inTheWay(v.note, true) ?? (v.noteCause?.ownStep === true ? v.note ?? null : null);
|
|
1184
1285
|
if (lasting !== null)
|
|
1185
1286
|
result.skipped.push({ path, reason: lasting });
|
|
1186
1287
|
else
|
|
@@ -1192,11 +1293,12 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1192
1293
|
plans.push({ path, kind: 'unlink', prior, before: agreement.get(mount.name, path), expect });
|
|
1193
1294
|
continue;
|
|
1194
1295
|
}
|
|
1195
|
-
const
|
|
1196
|
-
if (!
|
|
1197
|
-
result.skipped.push({ path, reason:
|
|
1296
|
+
const stored = storedBytes(store, s.hash);
|
|
1297
|
+
if (!('bytes' in stored)) {
|
|
1298
|
+
result.skipped.push({ path, reason: unstoredCopy(stored) });
|
|
1198
1299
|
continue;
|
|
1199
1300
|
}
|
|
1301
|
+
const blob = stored.bytes;
|
|
1200
1302
|
// The store's mode goes to disk with its bytes where the file is new,
|
|
1201
1303
|
// the push is forced, or disk still has the mode they last agreed on. A
|
|
1202
1304
|
// push that completes our own unconfirmed one, whose bytes landed, is a
|
|
@@ -1312,19 +1414,19 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1312
1414
|
}
|
|
1313
1415
|
}
|
|
1314
1416
|
catch (err) {
|
|
1315
|
-
const failure = err instanceof EffectFailed ? err :
|
|
1417
|
+
const failure = err instanceof EffectFailed ? err : callFailed('the push failed', err, true, 'colon');
|
|
1316
1418
|
if (!failure.touched) {
|
|
1317
1419
|
// Disk at this path is as planning saw it: its evidence goes back to
|
|
1318
1420
|
// exactly what it was, whatever kind that was.
|
|
1319
1421
|
agreement.restore(mount.name, step.path, step.before);
|
|
1320
1422
|
recorded = true;
|
|
1321
|
-
const why =
|
|
1423
|
+
const why = step.kind === 'chmod' ? withWayOn(failure.message, failure.detail, 'write') : explained(failure.message, failure.detail, step.kind);
|
|
1322
1424
|
result.skipped.push({ path: step.path, reason: `not ${step.kind === 'unlink' ? 'unlinked' : step.kind === 'chmod' ? 'given the workspace\'s mode' : 'written'}: ${why}` });
|
|
1323
1425
|
}
|
|
1324
1426
|
else {
|
|
1325
1427
|
// No completion: the intent stays pending, and the next observation
|
|
1326
1428
|
// resolves it from whatever disk then holds.
|
|
1327
|
-
result.skipped.push({ path: step.path, reason: `${failure.message}
|
|
1429
|
+
result.skipped.push({ path: step.path, reason: `${failure.message} — ${UNSETTLED}` });
|
|
1328
1430
|
}
|
|
1329
1431
|
}
|
|
1330
1432
|
}
|
|
@@ -1342,7 +1444,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1342
1444
|
result.skipped.push({
|
|
1343
1445
|
path: step.path,
|
|
1344
1446
|
reason: `could not make the ${step.kind === 'write' ? 'write' : 'unlink'} durable (directory fsync of ${failed === '' ? 'the mount root' : failed}): ` +
|
|
1345
|
-
`${unsynced.get(failed)}
|
|
1447
|
+
`${unsynced.get(failed)} — ${UNSETTLED}`,
|
|
1346
1448
|
});
|
|
1347
1449
|
continue;
|
|
1348
1450
|
}
|
|
@@ -1421,4 +1523,8 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1421
1523
|
agreement.maybeCheckpoint();
|
|
1422
1524
|
return result;
|
|
1423
1525
|
}
|
|
1526
|
+
function unstoredCopy(stored) {
|
|
1527
|
+
return `${'missing' in stored ? 'the workspace copy is missing from the store' : `the workspace copy is unreadable in the store (${stored.unreadable})`}`
|
|
1528
|
+
+ " — a read of this path takes disk's copy where it can, and otherwise says what can be done";
|
|
1529
|
+
}
|
|
1424
1530
|
//# sourceMappingURL=reconcile.js.map
|