@animalabs/agent-framework 0.28.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 +88 -25
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +4 -1
- 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 +7 -3
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/auto-continue.d.ts +2 -0
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +5 -2
- 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/framework.d.ts +164 -36
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +1120 -479
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +34 -10
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +118 -48
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/types.d.ts +12 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.js +34 -8
- package/dist/src/heartbeat/heartbeat.js.map +1 -1
- 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 +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -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/channel-registry.d.ts +34 -6
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +131 -53
- 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 +3 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +3 -1
- 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.map +1 -1
- package/dist/src/mcpl/server-connection.js +20 -20
- 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/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +18 -17
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +17 -16
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +8 -26
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +16 -6
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +14 -25
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +180 -50
- 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 +28 -12
- 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 +6 -7
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +6 -7
- 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.js +8 -6
- 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 +5 -1
- package/dist/src/modules/workspace/answers.d.ts.map +1 -1
- package/dist/src/modules/workspace/answers.js +16 -1
- package/dist/src/modules/workspace/answers.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +6 -4
- package/dist/src/modules/workspace/direct-write.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 +50 -40
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +1 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +66 -36
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +51 -20
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +120 -82
- package/dist/src/modules/workspace/observe.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 +133 -37
- package/dist/src/modules/workspace/reconcile.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/reasoning-loss-notice.d.ts.map +1 -1
- package/dist/src/reasoning-loss-notice.js +5 -3
- package/dist/src/reasoning-loss-notice.js.map +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/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +9 -8
- 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/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/types/agent.d.ts +23 -9
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +43 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -11
- package/dist/src/types/module.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/agent.ts +4 -1
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +7 -3
- package/src/auto-continue.ts +8 -2
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/framework.ts +1132 -492
- package/src/gate/event-gate.ts +128 -47
- package/src/gate/index.ts +1 -1
- package/src/gate/types.ts +12 -2
- package/src/heartbeat/heartbeat.ts +48 -9
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +605 -0
- package/src/index.ts +2 -2
- package/src/line-reader.ts +58 -0
- package/src/mcpl/channel-registry.ts +137 -52
- 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 +3 -1
- 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 +20 -18
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tool-presence.ts +18 -17
- package/src/mcpl/tool-signature.ts +17 -16
- package/src/mcpl/toolset-host.ts +18 -6
- package/src/mcpl/toolsets-module.ts +142 -50
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +29 -12
- package/src/module-registry.ts +6 -7
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +8 -6
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +20 -2
- package/src/modules/workspace/direct-write.ts +4 -3
- package/src/modules/workspace/effects.ts +50 -40
- package/src/modules/workspace/index.ts +58 -34
- package/src/modules/workspace/observe.ts +139 -88
- package/src/modules/workspace/reconcile.ts +159 -36
- package/src/notice-tags.ts +84 -0
- package/src/reasoning-loss-notice.ts +5 -3
- package/src/silent-heartbeat.ts +4 -3
- package/src/supplied-text.ts +154 -0
- package/src/tool-args.ts +9 -8
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tune-out/coordinator.ts +25 -27
- package/src/types/agent.ts +23 -9
- package/src/types/framework.ts +44 -0
- package/src/types/module.ts +23 -11
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
*/
|
|
40
40
|
import { candidateOf, sameCandidate, sameRootIdentity, } from './disk-agreement.js';
|
|
41
41
|
import { storedBytes } from './sync.js';
|
|
42
|
-
import { IGNORED, NOT_A_DIRECTORY, OTHER_MOUNT, ROOT_REPLACED, fingerprintVouches, ignoreBeneath, inOtherMount, locateRoot, looksBinary, observePath, passedOverAt, passedOverBetween, provenAbsent, readHead, readPath, sniffImageMime, walkScope, withinIncludes, } from './observe.js';
|
|
43
|
-
import { EffectFailed, chainOf, chmodContained, narrowedTo, syncDirectories, unlinkContained, writeContained } from './effects.js';
|
|
44
|
-
import { errnoWords } from './answers.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';
|
|
45
45
|
const ABSENT = { kind: 'absent' };
|
|
46
46
|
export const WALK_CAP = 5000;
|
|
47
47
|
function diskCandidate(d) {
|
|
@@ -198,21 +198,22 @@ function settleAdoption(p, s) {
|
|
|
198
198
|
/**
|
|
199
199
|
* What's in the way, and the way out, when disk's shape keeps a push from a
|
|
200
200
|
* path: no push writes a file over a directory or unlinks one, unlinks
|
|
201
|
-
* anything but a regular file or a followed symlink to one,
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
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.
|
|
205
206
|
*/
|
|
206
207
|
function inTheWay(reason, deletion) {
|
|
207
208
|
// Observation's words for what a deletion never unlinks, which the unlink
|
|
208
209
|
// refuses in the same words.
|
|
209
|
-
if (deletion && (reason ===
|
|
210
|
-
const what = reason ===
|
|
210
|
+
if (deletion && (reason === NOT_REGULAR || reason === LINK_TO_DIRECTORY)) {
|
|
211
|
+
const what = reason === NOT_REGULAR
|
|
211
212
|
? 'a pipe, socket or device at this path, or a symlink to one'
|
|
212
213
|
: 'a symlink to a directory at this path';
|
|
213
214
|
return `disk has ${what}, and no push unlinks it, forced or not — ask whoever runs this host if it should go`;
|
|
214
215
|
}
|
|
215
|
-
if (reason ===
|
|
216
|
+
if (reason === DIRECTORY) {
|
|
216
217
|
return deletion
|
|
217
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'
|
|
218
219
|
: 'disk has a directory at this path, and no push writes a file over one, forced or not — ' +
|
|
@@ -224,8 +225,90 @@ function inTheWay(reason, deletion) {
|
|
|
224
225
|
return 'disk has a file or a symlink where this path needs a directory, and no push writes below one, forced or not — ' +
|
|
225
226
|
'move or remove it on disk and materialize again, or write the file under another path';
|
|
226
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
|
+
}
|
|
227
250
|
return null;
|
|
228
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
|
+
}
|
|
229
312
|
/**
|
|
230
313
|
* The forced way out the refusal of a disk copy that couldn't be verified
|
|
231
314
|
* names, if any. A forced push skips the verification, so it gets past the
|
|
@@ -243,6 +326,12 @@ function forcedWay(note, deletion, forced) {
|
|
|
243
326
|
return `, or, if disk lets the workspace ${deletion ? 'unlink' : 'write'} the file, ${forced}`;
|
|
244
327
|
return '';
|
|
245
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
|
+
}
|
|
246
335
|
/**
|
|
247
336
|
* The synchronous precondition of every workspace mutation: evidence owed a
|
|
248
337
|
* barrier is made durable first, and an adoption left pending on the
|
|
@@ -362,6 +451,9 @@ function adoptDisk(d, s) {
|
|
|
362
451
|
return { state: 'synced', adopt: 'ingest', op: s ? 'modified' : 'created', p: agreedFromDisk(d), intent: {} };
|
|
363
452
|
return { state: 'disk-only', ...(s ? { adopt: 'drop', op: 'deleted' } : {}), p: 'forget', intent: {} };
|
|
364
453
|
}
|
|
454
|
+
function causeOf({ errno, ownStep }) {
|
|
455
|
+
return { ...(errno !== undefined ? { errno } : {}), ...(ownStep ? { ownStep } : {}) };
|
|
456
|
+
}
|
|
365
457
|
/** The rule (see module doc). Pure. */
|
|
366
458
|
function decide(d, s, pIn, bi, branchId, adopt) {
|
|
367
459
|
// A branch intent that can't be read may have held a tombstone or a
|
|
@@ -371,9 +463,9 @@ function decide(d, s, pIn, bi, branchId, adopt) {
|
|
|
371
463
|
if (d.kind === 'unobserved') {
|
|
372
464
|
// Disk proves nothing, but an adoption on this branch settles by the tree.
|
|
373
465
|
if (pIn?.kind === 'pending' && pIn.effect === 'adopt' && pIn.branchId === branchId && !adopt) {
|
|
374
|
-
return { state: 'unverified', note: d.reason, p: settleAdoption(pIn, s) };
|
|
466
|
+
return { state: 'unverified', note: d.reason, noteCause: causeOf(d), p: settleAdoption(pIn, s) };
|
|
375
467
|
}
|
|
376
|
-
return { state: 'unverified', note: d.reason };
|
|
468
|
+
return { state: 'unverified', note: d.reason, noteCause: causeOf(d) };
|
|
377
469
|
}
|
|
378
470
|
if (d.kind === 'unhashed') {
|
|
379
471
|
// Observed this way only when nothing tracks the path, which is then a
|
|
@@ -551,6 +643,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
551
643
|
// is followed, as `rootReal` is: `followSymlinks` governs links within it.
|
|
552
644
|
const root = await locateRoot(mount.view, mount.rootReal);
|
|
553
645
|
const rootUnavailable = 'reason' in root ? root.reason : null;
|
|
646
|
+
const rootCause = 'reason' in root && root.errno !== undefined ? { errno: root.errno } : {};
|
|
554
647
|
// The branch is labelled where the tracked candidates are read, with no
|
|
555
648
|
// await between: the decision is checked against this label.
|
|
556
649
|
const branchId = store.currentBranch().id;
|
|
@@ -565,7 +658,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
565
658
|
if (rootUnavailable !== null) {
|
|
566
659
|
// Said whether or not anything is tracked: an unavailable mount must not
|
|
567
660
|
// read as a verified empty directory.
|
|
568
|
-
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') });
|
|
569
662
|
}
|
|
570
663
|
// Which paths to decide: what disk shows, and what the store, P and intent
|
|
571
664
|
// track. The tracked ones are read synchronously, on this branch. A path
|
|
@@ -617,7 +710,7 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
617
710
|
// Observe. Tracked facts are read again, synchronously, when deciding.
|
|
618
711
|
for (const path of candidates) {
|
|
619
712
|
if (rootUnavailable !== null) {
|
|
620
|
-
gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable });
|
|
713
|
+
gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable, ...rootCause });
|
|
621
714
|
continue;
|
|
622
715
|
}
|
|
623
716
|
// What the mount passes over by design stays unobserved by a pass that
|
|
@@ -672,7 +765,9 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
672
765
|
if (region === undefined || r.path.length > region.path.length)
|
|
673
766
|
region = r;
|
|
674
767
|
}
|
|
675
|
-
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' });
|
|
676
771
|
continue;
|
|
677
772
|
}
|
|
678
773
|
const p = agreement.get(mount.name, path);
|
|
@@ -688,12 +783,13 @@ async function gather(store, agreement, mount, scope, opts) {
|
|
|
688
783
|
const after = await locateRoot(mount.view, mount.rootReal);
|
|
689
784
|
if (!('identity' in after) || !sameRootIdentity(after.identity, gathered.rootIdentity)) {
|
|
690
785
|
const reason = 'reason' in after ? after.reason : ROOT_REPLACED;
|
|
786
|
+
const errno = 'errno' in after ? after.errno : undefined;
|
|
691
787
|
for (const path of gathered.facts.keys())
|
|
692
|
-
gathered.facts.set(path, { kind: 'unobserved', reason });
|
|
788
|
+
gathered.facts.set(path, { kind: 'unobserved', reason, ...(errno !== undefined ? { errno } : {}) });
|
|
693
789
|
gathered.rootIdentity = null;
|
|
694
790
|
gathered.walk = null;
|
|
695
791
|
gathered.dirs = [];
|
|
696
|
-
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') });
|
|
697
793
|
}
|
|
698
794
|
}
|
|
699
795
|
return gathered;
|
|
@@ -723,14 +819,13 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
723
819
|
}
|
|
724
820
|
}
|
|
725
821
|
if (gathered === null) {
|
|
726
|
-
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') });
|
|
727
824
|
return result;
|
|
728
825
|
}
|
|
729
826
|
if (opts.branchId !== undefined && gathered.branchId !== opts.branchId) {
|
|
730
|
-
result.
|
|
731
|
-
|
|
732
|
-
reason: 'the selected branch changed before this sync ran; nothing was taken from disk — sync again on this branch to take it',
|
|
733
|
-
});
|
|
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 });
|
|
734
829
|
return result;
|
|
735
830
|
}
|
|
736
831
|
const { walk, facts } = gathered;
|
|
@@ -861,6 +956,8 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
861
956
|
}
|
|
862
957
|
if (x.verdict.note)
|
|
863
958
|
report.note = x.verdict.note;
|
|
959
|
+
if (x.verdict.noteCause !== undefined)
|
|
960
|
+
report.noteCause = x.verdict.noteCause;
|
|
864
961
|
if (!(x.verdict.state === 'synced' && !entry))
|
|
865
962
|
result.reports.set(x.path, report);
|
|
866
963
|
}
|
|
@@ -891,8 +988,9 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
|
|
|
891
988
|
// holder), so naming the directory as unreached would never clear.
|
|
892
989
|
const wholeScope = scope.kind === 'dir' && scope.dir !== '' && region.path === scope.dir;
|
|
893
990
|
const unreached = hides && region.reason !== OTHER_MOUNT;
|
|
894
|
-
if (region.kind === 'error' || region.kind === 'cap' || unreached || wholeScope)
|
|
895
|
-
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
|
+
}
|
|
896
994
|
// A name passed over by design that hides nothing tracked is reported nowhere else:
|
|
897
995
|
// counted, so a sync that says 0 also says what it didn't look at
|
|
898
996
|
// (agent-framework #276). A symlink region isn't counted: a link the
|
|
@@ -941,8 +1039,9 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
941
1039
|
// unmounted from. The push plans nothing, so it reports no branch.
|
|
942
1040
|
const root = await locateRoot(mount.view, mount.rootReal);
|
|
943
1041
|
if ('reason' in root) {
|
|
1042
|
+
const why = explained(root.reason, root.errno !== undefined ? { errno: root.errno } : {}, 'write');
|
|
944
1043
|
for (const path of paths)
|
|
945
|
-
result.skipped.push({ path, reason:
|
|
1044
|
+
result.skipped.push({ path, reason: why });
|
|
946
1045
|
return result;
|
|
947
1046
|
}
|
|
948
1047
|
// Another mount's directory nested in this one is that mount's: no push
|
|
@@ -971,7 +1070,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
971
1070
|
// nothing is decided or recorded from them.
|
|
972
1071
|
const after = await locateRoot(mount.view, mount.rootReal);
|
|
973
1072
|
if (!('identity' in after) || !sameRootIdentity(after.identity, root.identity)) {
|
|
974
|
-
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;
|
|
975
1074
|
for (const path of paths)
|
|
976
1075
|
result.skipped.push({ path, reason });
|
|
977
1076
|
return result;
|
|
@@ -992,9 +1091,6 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
992
1091
|
const p = agreement.get(mount.name, path);
|
|
993
1092
|
const bi = mount.intents.get(path);
|
|
994
1093
|
const v = decide(d, s, p, bi, branchId, false);
|
|
995
|
-
// The ways out a refusal names, as materialize takes them: a deletion
|
|
996
|
-
// reaches disk only with applyDeletions.
|
|
997
|
-
const again = s ? 'materialize again' : 'materialize again with applyDeletions';
|
|
998
1094
|
// Where disk has deleted a file the workspace holds, a sync takes the
|
|
999
1095
|
// deletion, which removes the workspace's copy, and a forced push writes
|
|
1000
1096
|
// the workspace's copy back: there is no disk copy to adopt or overwrite.
|
|
@@ -1118,8 +1214,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1118
1214
|
? d.kind === 'absent' || d.kind === 'file'
|
|
1119
1215
|
? `${v.note} — ${sync}`
|
|
1120
1216
|
: `${v.note}, and disk's copy can't be verified (${d.kind === 'unobserved' ? d.reason : 'not hashed'}) — once it can be, ${sync}`
|
|
1121
|
-
: inTheWay(v.note, !s) ??
|
|
1122
|
-
`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),
|
|
1123
1218
|
});
|
|
1124
1219
|
continue;
|
|
1125
1220
|
}
|
|
@@ -1186,7 +1281,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1186
1281
|
// A deletion no push makes, forced or not (inTheWay), is refused for
|
|
1187
1282
|
// that, as an unforced push refuses it, rather than left for
|
|
1188
1283
|
// applyDeletions, which couldn't make it either.
|
|
1189
|
-
const lasting = inTheWay(v.note, true);
|
|
1284
|
+
const lasting = inTheWay(v.note, true) ?? (v.noteCause?.ownStep === true ? v.note ?? null : null);
|
|
1190
1285
|
if (lasting !== null)
|
|
1191
1286
|
result.skipped.push({ path, reason: lasting });
|
|
1192
1287
|
else
|
|
@@ -1319,19 +1414,19 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1319
1414
|
}
|
|
1320
1415
|
}
|
|
1321
1416
|
catch (err) {
|
|
1322
|
-
const failure = err instanceof EffectFailed ? err :
|
|
1417
|
+
const failure = err instanceof EffectFailed ? err : callFailed('the push failed', err, true, 'colon');
|
|
1323
1418
|
if (!failure.touched) {
|
|
1324
1419
|
// Disk at this path is as planning saw it: its evidence goes back to
|
|
1325
1420
|
// exactly what it was, whatever kind that was.
|
|
1326
1421
|
agreement.restore(mount.name, step.path, step.before);
|
|
1327
1422
|
recorded = true;
|
|
1328
|
-
const why =
|
|
1423
|
+
const why = step.kind === 'chmod' ? withWayOn(failure.message, failure.detail, 'write') : explained(failure.message, failure.detail, step.kind);
|
|
1329
1424
|
result.skipped.push({ path: step.path, reason: `not ${step.kind === 'unlink' ? 'unlinked' : step.kind === 'chmod' ? 'given the workspace\'s mode' : 'written'}: ${why}` });
|
|
1330
1425
|
}
|
|
1331
1426
|
else {
|
|
1332
1427
|
// No completion: the intent stays pending, and the next observation
|
|
1333
1428
|
// resolves it from whatever disk then holds.
|
|
1334
|
-
result.skipped.push({ path: step.path, reason: `${failure.message}
|
|
1429
|
+
result.skipped.push({ path: step.path, reason: `${failure.message} — ${UNSETTLED}` });
|
|
1335
1430
|
}
|
|
1336
1431
|
}
|
|
1337
1432
|
}
|
|
@@ -1349,7 +1444,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1349
1444
|
result.skipped.push({
|
|
1350
1445
|
path: step.path,
|
|
1351
1446
|
reason: `could not make the ${step.kind === 'write' ? 'write' : 'unlink'} durable (directory fsync of ${failed === '' ? 'the mount root' : failed}): ` +
|
|
1352
|
-
`${unsynced.get(failed)}
|
|
1447
|
+
`${unsynced.get(failed)} — ${UNSETTLED}`,
|
|
1353
1448
|
});
|
|
1354
1449
|
continue;
|
|
1355
1450
|
}
|
|
@@ -1429,6 +1524,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
|
|
|
1429
1524
|
return result;
|
|
1430
1525
|
}
|
|
1431
1526
|
function unstoredCopy(stored) {
|
|
1432
|
-
return 'missing' in stored ? 'the workspace copy is missing from the store' : `the workspace copy is unreadable in the store (${stored.unreadable})
|
|
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";
|
|
1433
1529
|
}
|
|
1434
1530
|
//# sourceMappingURL=reconcile.js.map
|