@astrosheep/keiyaku 4.5.11 → 4.5.13
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/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +135 -377
- package/build/integrations/pi/keiyaku.ts +11 -116
- package/build/src/akuma/akuma-errors.d.ts +1 -0
- package/build/src/akuma/akuma-errors.js +1 -0
- package/build/src/akuma/akuma-handle.d.ts +1 -0
- package/build/src/akuma/akuma-handle.js +6 -7
- package/build/src/akuma/akuma-product.d.ts +6 -8
- package/build/src/akuma/akuma-product.js +141 -57
- package/build/src/akuma/akuma.d.ts +5 -7
- package/build/src/akuma/akuma.js +1 -22
- package/build/src/akuma/archetype.d.ts +6 -5
- package/build/src/akuma/archetype.js +137 -38
- package/build/src/akuma/body.d.ts +5 -5
- package/build/src/akuma/body.js +223 -63
- package/build/src/akuma/call-input.d.ts +4 -0
- package/build/src/akuma/call-input.js +21 -0
- package/build/src/akuma/call-request.d.ts +5 -8
- package/build/src/akuma/call-request.js +28 -73
- package/build/src/akuma/fleet-execution.d.ts +26 -0
- package/build/src/akuma/fleet-execution.js +109 -0
- package/build/src/{library/fleet-result.d.ts → akuma/fleet-observation.d.ts} +13 -57
- package/build/src/{library/fleet-result.js → akuma/fleet-observation.js} +4 -25
- package/build/src/akuma/fleet-request.d.ts +122 -0
- package/build/src/akuma/fleet-request.js +168 -0
- package/build/src/akuma/heart/facts.d.ts +23 -0
- package/build/src/akuma/heart/facts.js +7 -0
- package/build/src/akuma/heart/index.d.ts +43 -4
- package/build/src/akuma/heart/index.js +107 -7
- package/build/src/akuma/heart/request-authority.d.ts +2 -0
- package/build/src/akuma/heart/request-authority.js +28 -3
- package/build/src/akuma/heart/request-rows.d.ts +2 -0
- package/build/src/akuma/heart/request-rows.js +24 -5
- package/build/src/akuma/heart/rows.d.ts +4 -1
- package/build/src/akuma/heart/rows.js +46 -19
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +28 -6
- package/build/src/akuma/heart/storage.d.ts +1 -1
- package/build/src/akuma/heart/tells.d.ts +29 -0
- package/build/src/akuma/heart/tells.js +136 -5
- package/build/src/akuma/heart/timeline.js +9 -3
- package/build/src/akuma/projection-read.js +36 -3
- package/build/src/akuma/projection.js +3 -4
- package/build/src/akuma/provider.d.ts +4 -0
- package/build/src/akuma/provider.js +56 -3
- package/build/src/akuma/providers/claude/index.js +3 -0
- package/build/src/akuma/providers/codex-app-server/index.js +14 -12
- package/build/src/akuma/providers/pi/index.js +7 -1
- package/build/src/akuma/publication.js +65 -49
- package/build/src/akuma/request-lifecycle.d.ts +5 -4
- package/build/src/akuma/request-lifecycle.js +29 -16
- package/build/src/akuma/request-rendezvous.d.ts +15 -12
- package/build/src/akuma/request-rendezvous.js +80 -51
- package/build/src/akuma/request-serve.d.ts +1 -2
- package/build/src/akuma/request-serve.js +94 -39
- package/build/src/akuma/request-wire.d.ts +57 -26
- package/build/src/akuma/request-wire.js +64 -25
- package/build/src/akuma/turn-drive.d.ts +5 -4
- package/build/src/akuma/turn-drive.js +27 -11
- package/build/src/akuma-body.d.ts +4 -6
- package/build/src/akuma-body.js +19 -17
- package/build/src/bounded-list.d.ts +8 -0
- package/build/src/bounded-list.js +14 -0
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +1 -0
- package/build/src/cli/commands/akuma-invoke.js +1 -25
- package/build/src/cli/commands/contract-help.d.ts +5 -2
- package/build/src/cli/commands/contract-help.js +62 -12
- package/build/src/cli/commands/contract-invoke.d.ts +5 -0
- package/build/src/cli/commands/contract-invoke.js +26 -1
- package/build/src/cli/commands/contract.js +50 -18
- package/build/src/cli/commands/task-invoke.js +10 -2
- package/build/src/cli/commands/task-query.js +3 -4
- package/build/src/cli/coordinates.d.ts +13 -0
- package/build/src/cli/coordinates.js +38 -24
- package/build/src/cli/draft.d.ts +1 -1
- package/build/src/cli/invoke.js +14 -1
- package/build/src/cli/render/akuma-activity.d.ts +0 -1
- package/build/src/cli/render/akuma-activity.js +5 -38
- package/build/src/cli/render/akuma.js +4 -1
- package/build/src/cli/render/audit.js +4 -1
- package/build/src/cli/render/catalog.js +13 -39
- package/build/src/cli/render/contract.js +4 -14
- package/build/src/cli/render/kanshi-akuma.js +3 -8
- package/build/src/cli/render/kanshi.js +8 -34
- package/build/src/cli/render/nuke.js +7 -3
- package/build/src/cli/render/receipt.d.ts +1 -0
- package/build/src/cli/render/receipt.js +8 -0
- package/build/src/cli/render/refusal.js +4 -3
- package/build/src/cli/render/task.js +4 -37
- package/build/src/cli/render/terminal.d.ts +2 -6
- package/build/src/cli/render/terminal.js +4 -9
- package/build/src/cli/result.d.ts +2 -1
- package/build/src/contract-guidance.js +13 -3
- package/build/src/contract-worktree.d.ts +1 -0
- package/build/src/contract-worktree.js +26 -2
- package/build/src/core/facts/codec.d.ts +2 -1
- package/build/src/core/facts/codec.js +3 -0
- package/build/src/core/facts/gate.d.ts +2 -1
- package/build/src/core/facts/gate.js +63 -0
- package/build/src/core/verbs/abandon.d.ts +2 -1
- package/build/src/core/verbs/abandon.js +16 -0
- package/build/src/core/verbs/amend.d.ts +2 -1
- package/build/src/core/verbs/amend.js +20 -0
- package/build/src/core/verbs/arc.d.ts +2 -1
- package/build/src/core/verbs/arc.js +16 -0
- package/build/src/core/verbs/attestation.d.ts +2 -1
- package/build/src/core/verbs/attestation.js +16 -0
- package/build/src/core/verbs/bind.d.ts +2 -1
- package/build/src/core/verbs/bind.js +16 -0
- package/build/src/core/verbs/deliver.d.ts +2 -1
- package/build/src/core/verbs/deliver.js +16 -0
- package/build/src/core/verbs/placement.d.ts +2 -1
- package/build/src/core/verbs/placement.js +58 -1
- package/build/src/dispatch/association.d.ts +13 -0
- package/build/src/dispatch/association.js +20 -0
- package/build/src/dispatch/index.d.ts +6 -0
- package/build/src/dispatch/index.js +27 -3
- package/build/src/git/hooks.d.ts +9 -1
- package/build/src/git/hooks.js +79 -1
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +6 -11
- package/build/src/git/private-state-seat.d.ts +26 -1
- package/build/src/git/private-state-seat.js +78 -13
- package/build/src/git/process.d.ts +2 -0
- package/build/src/git/reconcile.d.ts +1 -2
- package/build/src/git/reconcile.js +0 -6
- package/build/src/git/repository.d.ts +0 -2
- package/build/src/git/repository.js +27 -25
- package/build/src/git/result-codec.d.ts +29 -0
- package/build/src/git/result-codec.js +306 -0
- package/build/src/git/target-placement.js +2 -8
- package/build/src/git/workspace.d.ts +2 -0
- package/build/src/git/workspace.js +4 -0
- package/build/src/index.d.ts +1 -0
- package/build/src/kanshi/fleet.js +1 -1
- package/build/src/kanshi/read.js +55 -28
- package/build/src/kanshi/report.d.ts +4 -3
- package/build/src/kanshi/select.js +14 -1
- package/build/src/library/address.d.ts +1 -0
- package/build/src/library/address.js +4 -7
- package/build/src/library/akuma-creation.d.ts +5 -3
- package/build/src/library/akuma-creation.js +90 -33
- package/build/src/library/audit.js +2 -1
- package/build/src/library/catalog.d.ts +10 -2
- package/build/src/library/catalog.js +65 -25
- package/build/src/library/composition.d.ts +1 -0
- package/build/src/library/composition.js +1 -0
- package/build/src/library/configuration.d.ts +4 -21
- package/build/src/library/configuration.js +2 -158
- package/build/src/library/continuation.d.ts +20 -1
- package/build/src/library/continuation.js +36 -0
- package/build/src/library/contract-bind.d.ts +1 -0
- package/build/src/library/contract-bind.js +16 -5
- package/build/src/library/contract-forwarding.d.ts +2 -2
- package/build/src/library/contract-forwarding.js +18 -4
- package/build/src/library/contract-handle.js +4 -3
- package/build/src/library/contract-operations.d.ts +5 -9
- package/build/src/library/contract-operations.js +34 -47
- package/build/src/library/contract.d.ts +11 -2
- package/build/src/library/contract.js +21 -1
- package/build/src/library/delivery.d.ts +4 -1
- package/build/src/library/delivery.js +47 -0
- package/build/src/library/fleet.d.ts +4 -136
- package/build/src/library/fleet.js +31 -315
- package/build/src/library/keiyaku.d.ts +7 -3
- package/build/src/library/keiyaku.js +1 -0
- package/build/src/library/mutation.d.ts +431 -3
- package/build/src/library/mutation.js +192 -19
- package/build/src/library/nuke.d.ts +7 -1
- package/build/src/library/nuke.js +18 -4
- package/build/src/library/reconcile.d.ts +14 -0
- package/build/src/library/reconcile.js +22 -8
- package/build/src/library/refusal.d.ts +9 -1
- package/build/src/library/refusal.js +76 -0
- package/build/src/library/region.d.ts +0 -8
- package/build/src/library/region.js +1 -29
- package/build/src/library/result-codec.d.ts +2 -0
- package/build/src/library/result-codec.js +12 -0
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/types.d.ts +2 -1
- package/build/src/markdown/types.js +3 -1
- package/build/src/plugin/akuma-signals.d.ts +12 -0
- package/build/src/plugin/akuma-signals.js +14 -0
- package/build/src/plugin/public.d.ts +51 -0
- package/build/src/plugin/public.js +1 -0
- package/build/src/plugin/runtime.d.ts +14 -0
- package/build/src/plugin/runtime.js +357 -0
- package/build/src/protocol/amend.js +3 -3
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/attempt.js +1 -1
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +1 -1
- package/build/src/protocol/bind.d.ts +3 -1
- package/build/src/protocol/bind.js +26 -0
- package/build/src/protocol/completion.js +0 -1
- package/build/src/protocol/deliver.d.ts +1 -1
- package/build/src/protocol/deliver.js +136 -57
- package/build/src/protocol/intent.d.ts +0 -1
- package/build/src/protocol/intent.js +0 -1
- package/build/src/protocol/operations.d.ts +9 -2
- package/build/src/protocol/operations.js +16 -1
- package/build/src/protocol/outcome.d.ts +3 -0
- package/build/src/protocol/outcome.js +17 -1
- package/build/src/protocol/placement.js +10 -3
- package/build/src/protocol/read/status.d.ts +8 -0
- package/build/src/protocol/read/status.js +49 -0
- package/build/src/protocol/reintegrate.js +10 -3
- package/build/src/protocol/result-codec.d.ts +22 -0
- package/build/src/protocol/result-codec.js +442 -0
- package/build/src/protocol/review.d.ts +1 -1
- package/build/src/protocol/review.js +81 -46
- package/build/src/protocol/run.d.ts +22 -2
- package/build/src/protocol/run.js +119 -29
- package/build/src/runtime/proc/lifecycle.js +1 -1
- package/build/src/runtime/proc/line-rpc.d.ts +7 -1
- package/build/src/runtime/proc/line-rpc.js +49 -9
- package/build/src/runtime/proc/run.d.ts +0 -1
- package/build/src/runtime/proc/run.js +1 -11
- package/build/src/runtime/proc/termination.d.ts +1 -0
- package/build/src/runtime/proc/termination.js +63 -18
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.d.ts +10 -0
- package/build/src/settings.js +88 -2
- package/build/src/settlement/result-codec.d.ts +2 -0
- package/build/src/settlement/result-codec.js +56 -0
- package/build/src/settlement/settle.d.ts +5 -12
- package/build/src/settlement/settle.js +60 -55
- package/build/src/task/board.d.ts +3 -0
- package/build/src/task/board.js +22 -4
- package/build/src/task/catalog.d.ts +13 -2
- package/build/src/task/catalog.js +59 -5
- package/build/src/task/compose.d.ts +4 -2
- package/build/src/task/compose.js +56 -30
- package/build/src/task/created-observation.d.ts +39 -0
- package/build/src/task/created-observation.js +26 -0
- package/build/src/task/identity.d.ts +6 -0
- package/build/src/task/identity.js +48 -7
- package/build/src/task/index.d.ts +4 -3
- package/build/src/task/index.js +19 -16
- package/build/src/task/input.d.ts +3 -1
- package/build/src/task/input.js +7 -4
- package/build/src/task/lifecycle-operations.d.ts +6 -0
- package/build/src/task/lifecycle-operations.js +116 -0
- package/build/src/task/mutation-result.d.ts +762 -20
- package/build/src/task/mutation-result.js +34 -9
- package/build/src/task/mutation.d.ts +4 -9
- package/build/src/task/mutation.js +17 -52
- package/build/src/task/operation-types.d.ts +114 -0
- package/build/src/task/operation-types.js +1 -0
- package/build/src/task/operations.d.ts +6 -113
- package/build/src/task/operations.js +75 -117
- package/build/src/task/query.d.ts +8 -11
- package/build/src/task/query.js +7 -14
- package/build/src/task/store.d.ts +11 -1
- package/build/src/task/store.js +169 -55
- package/build/src/task/view.d.ts +4 -0
- package/build/src/task/view.js +7 -0
- package/build/src/verification/declaration.d.ts +1 -0
- package/build/src/verification/declaration.js +18 -1
- package/build/src/verification/execution.d.ts +0 -1
- package/build/src/verification/execution.js +5 -5
- package/build/src/world.d.ts +0 -2
- package/build/src/world.js +3 -7
- package/package.json +17 -5
- package/build/src/cli/square-edge.d.ts +0 -7
- package/build/src/cli/square-edge.js +0 -159
- package/build/src/git/ref-migration.d.ts +0 -22
- package/build/src/git/ref-migration.js +0 -55
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +0 -102
- package/build/src/library/contract-forwarding-reconciliation-result.js +0 -92
- package/build/src/library/contract-forwarding-result.d.ts +0 -4270
- package/build/src/library/contract-forwarding-result.js +0 -521
|
@@ -2,6 +2,7 @@ import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul } from "
|
|
|
2
2
|
import { allocateAkumaDirectory } from "./identity.js";
|
|
3
3
|
import { abortableDelay } from "./abort.js";
|
|
4
4
|
const POLL_MS = 100;
|
|
5
|
+
const CUSTODY_HANDOFF_MS = 1_000;
|
|
5
6
|
export const BIRTH_TIMEOUT_MS = 30_000;
|
|
6
7
|
function diagnostic(error) {
|
|
7
8
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -43,24 +44,6 @@ async function observedBirthFailure(paths) {
|
|
|
43
44
|
function preAdmissionDiagnostic(exit) {
|
|
44
45
|
return exit.code === null ? `pre-admission signal ${exit.signal ?? "unknown"}` : `pre-admission exit ${exit.code}`;
|
|
45
46
|
}
|
|
46
|
-
async function sealObservedExit(paths, exit) {
|
|
47
|
-
const evidence = preAdmissionDiagnostic(exit);
|
|
48
|
-
try {
|
|
49
|
-
const leash = await HeldAkumaLeash.try(paths);
|
|
50
|
-
if (leash !== null) {
|
|
51
|
-
try {
|
|
52
|
-
await leash.sealIfUnborn(paths, { evidence, at: new Date().toISOString() });
|
|
53
|
-
}
|
|
54
|
-
finally {
|
|
55
|
-
leash.release();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
/* Parent evidence remains authoritative when best-effort sealing fails. */
|
|
61
|
-
}
|
|
62
|
-
throw new Error(evidence);
|
|
63
|
-
}
|
|
64
47
|
async function observeSettledExit(owned) {
|
|
65
48
|
if (owned === undefined)
|
|
66
49
|
return { kind: "pending" };
|
|
@@ -73,6 +56,21 @@ async function observeSettledExit(owned) {
|
|
|
73
56
|
return { kind: "exit-error", error };
|
|
74
57
|
}
|
|
75
58
|
}
|
|
59
|
+
async function observeExitWithin(owned, milliseconds) {
|
|
60
|
+
return await Promise.race([
|
|
61
|
+
owned.exited.then((exit) => ({ kind: "exited", exit }), (error) => ({ kind: "exit-error", error })),
|
|
62
|
+
abortableDelay(milliseconds).then(() => ({ kind: "timeout" })),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
async function attemptTermination(owned, force = false) {
|
|
66
|
+
const outcome = await Promise.race([
|
|
67
|
+
Promise.resolve()
|
|
68
|
+
.then(() => owned.terminate(force))
|
|
69
|
+
.then(() => ({ kind: "terminated" }), (error) => ({ kind: "error", error })),
|
|
70
|
+
abortableDelay(CUSTODY_HANDOFF_MS).then(() => ({ kind: "timeout" })),
|
|
71
|
+
]);
|
|
72
|
+
return outcome.kind === "error" ? outcome.error : undefined;
|
|
73
|
+
}
|
|
76
74
|
async function awaitBirth(paths, owned, signal) {
|
|
77
75
|
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
78
76
|
for (;;) {
|
|
@@ -84,7 +82,7 @@ async function awaitBirth(paths, owned, signal) {
|
|
|
84
82
|
if (failure !== null) {
|
|
85
83
|
const settled = await observeSettledExit(owned);
|
|
86
84
|
if (settled.kind === "exited")
|
|
87
|
-
|
|
85
|
+
throw new Error(preAdmissionDiagnostic(settled.exit));
|
|
88
86
|
if (settled.kind === "exit-error")
|
|
89
87
|
throw new Error(diagnostic(settled.error));
|
|
90
88
|
throw new Error(failure);
|
|
@@ -94,7 +92,7 @@ async function awaitBirth(paths, owned, signal) {
|
|
|
94
92
|
if (settled !== null)
|
|
95
93
|
return settled;
|
|
96
94
|
if (owned !== undefined)
|
|
97
|
-
await owned
|
|
95
|
+
await attemptTermination(owned, true);
|
|
98
96
|
throw new Error("Akuma birth timed out before Soul admission");
|
|
99
97
|
}
|
|
100
98
|
if (owned === undefined) {
|
|
@@ -111,8 +109,7 @@ async function awaitBirth(paths, owned, signal) {
|
|
|
111
109
|
const settledSoul = await readSoul(paths);
|
|
112
110
|
if (settledSoul !== null)
|
|
113
111
|
return settledSoul;
|
|
114
|
-
|
|
115
|
-
continue;
|
|
112
|
+
throw new Error(preAdmissionDiagnostic(outcome.exit));
|
|
116
113
|
}
|
|
117
114
|
throw new Error(diagnostic(outcome.error));
|
|
118
115
|
}
|
|
@@ -127,14 +124,6 @@ async function takeLeashUntil(paths, deadline) {
|
|
|
127
124
|
await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
|
|
128
125
|
}
|
|
129
126
|
}
|
|
130
|
-
async function takeLeash(paths) {
|
|
131
|
-
for (;;) {
|
|
132
|
-
const leash = await HeldAkumaLeash.try(paths);
|
|
133
|
-
if (leash !== null)
|
|
134
|
-
return leash;
|
|
135
|
-
await abortableDelay(POLL_MS);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
127
|
async function allocatedSoul(allocated) {
|
|
139
128
|
const soul = await readSoul(allocated.paths);
|
|
140
129
|
if (soul === null)
|
|
@@ -143,30 +132,54 @@ async function allocatedSoul(allocated) {
|
|
|
143
132
|
throw new Error("Akuma birth returned a different identity");
|
|
144
133
|
return soul;
|
|
145
134
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
135
|
+
function settlementEvidence(primary, terminationError, exitError) {
|
|
136
|
+
const reason = primary === undefined || primary === null ? "" : diagnostic(primary).trim();
|
|
137
|
+
if (reason.length > 0)
|
|
138
|
+
return reason;
|
|
139
|
+
const details = [terminationError, exitError]
|
|
140
|
+
.filter((error) => error !== undefined)
|
|
141
|
+
.map((error) => diagnostic(error).trim())
|
|
142
|
+
.filter((detail) => detail.length > 0);
|
|
143
|
+
return details[0] ?? "Akuma publication failed";
|
|
153
144
|
}
|
|
154
|
-
async function
|
|
145
|
+
async function settleLaunch(allocated, owned, failure) {
|
|
155
146
|
if ((await readSoul(allocated.paths)) !== null) {
|
|
156
147
|
await allocatedSoul(allocated);
|
|
148
|
+
const settled = await observeExitWithin(owned, CUSTODY_HANDOFF_MS);
|
|
149
|
+
if (settled.kind === "timeout") {
|
|
150
|
+
const leash = await HeldAkumaLeash.try(allocated.paths);
|
|
151
|
+
if (leash === null)
|
|
152
|
+
return "handoff";
|
|
153
|
+
leash.release();
|
|
154
|
+
}
|
|
155
|
+
if (settled.kind === "exit-error")
|
|
156
|
+
throw failure;
|
|
157
157
|
return "born";
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
let terminationError;
|
|
160
|
+
let exitError;
|
|
161
|
+
let outcome;
|
|
162
|
+
const preAdmissionExit = diagnostic(failure).startsWith("pre-admission ");
|
|
163
|
+
const settled = preAdmissionExit ? await observeSettledExit(owned) : { kind: "pending" };
|
|
164
|
+
if (settled.kind !== "exited") {
|
|
165
|
+
terminationError = await attemptTermination(owned);
|
|
166
|
+
const exit = await observeSettledExit(owned);
|
|
167
|
+
if (exit.kind === "exit-error")
|
|
168
|
+
exitError = exit.error;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
/* An already-settled pre-admission exit needs no second termination request. */
|
|
172
|
+
}
|
|
161
173
|
if ((await readSoul(allocated.paths)) !== null) {
|
|
162
174
|
await allocatedSoul(allocated);
|
|
163
175
|
return "born";
|
|
164
176
|
}
|
|
165
|
-
const leash = await
|
|
166
|
-
|
|
177
|
+
const leash = await HeldAkumaLeash.try(allocated.paths);
|
|
178
|
+
if (leash === null)
|
|
179
|
+
return "handoff";
|
|
167
180
|
try {
|
|
168
181
|
outcome = await leash.sealIfUnborn(allocated.paths, {
|
|
169
|
-
evidence:
|
|
182
|
+
evidence: settlementEvidence(failure, terminationError, exitError),
|
|
170
183
|
at: new Date().toISOString(),
|
|
171
184
|
});
|
|
172
185
|
}
|
|
@@ -242,19 +255,22 @@ export async function launchAkuma(input) {
|
|
|
242
255
|
return allocated;
|
|
243
256
|
}
|
|
244
257
|
catch (error) {
|
|
245
|
-
if (owned !== undefined
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
if (owned !== undefined) {
|
|
259
|
+
let outcome;
|
|
260
|
+
try {
|
|
261
|
+
outcome = await settleLaunch(allocated, owned, error);
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
owned.release();
|
|
265
|
+
}
|
|
266
|
+
if (outcome === "born" && input.signal?.aborted && error === input.signal.reason) {
|
|
248
267
|
if (input.awaitAsleep === true)
|
|
249
268
|
await awaitAsleepBirth(allocated.paths);
|
|
250
|
-
owned.release();
|
|
251
269
|
return allocated;
|
|
252
270
|
}
|
|
253
|
-
owned.release();
|
|
254
271
|
throw error;
|
|
255
272
|
}
|
|
256
273
|
await sealLocalFailure(allocated, error);
|
|
257
|
-
owned?.release();
|
|
258
274
|
throw error;
|
|
259
275
|
}
|
|
260
276
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { type Soul } from "./heart/index.js";
|
|
1
|
+
import { type RequestFact, type Soul } from "./heart/index.js";
|
|
2
2
|
import { type AkumaPaths } from "./identity.js";
|
|
3
3
|
import { type RequestEnvelope } from "./request-wire.js";
|
|
4
4
|
export type PumpInput = Readonly<{
|
|
5
5
|
paths: AkumaPaths;
|
|
6
|
-
|
|
6
|
+
allowed: readonly string[];
|
|
7
7
|
bodySequence: number;
|
|
8
8
|
now(): string;
|
|
9
|
-
spawn(launch: unknown): Promise<unknown>;
|
|
10
|
-
upstream?: unknown;
|
|
11
9
|
signal: AbortSignal;
|
|
12
10
|
}>;
|
|
13
11
|
type ServeClaim = (input: PumpInput & Readonly<{
|
|
@@ -35,5 +33,8 @@ export declare class BodyRequestPump {
|
|
|
35
33
|
stopAdmission(): void;
|
|
36
34
|
}
|
|
37
35
|
export declare function clearBodyRequestTransport(paths: AkumaPaths): Promise<void>;
|
|
36
|
+
export declare function settleReserved(paths: AkumaPaths, parent: Soul, request: Extract<RequestFact, {
|
|
37
|
+
state: "reserved";
|
|
38
|
+
}>, now: () => string, signal?: AbortSignal): Promise<boolean>;
|
|
38
39
|
export declare function settleBodyRequests(paths: AkumaPaths, parent: Soul, now: () => string, signal?: AbortSignal): Promise<"settled" | "pending">;
|
|
39
40
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access, mkdir, readFile, readdir, rm } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { abortableDelay } from "./abort.js";
|
|
4
|
-
import { HeldAkumaLeash, readNonterminalRequests, readSoul, serveRequest, voidRequest, } from "./heart/index.js";
|
|
4
|
+
import { HeldAkumaLeash, readNonterminalRequests, readSoul, serveRequest, unproveRequest, voidRequest, } from "./heart/index.js";
|
|
5
5
|
import { pathsForAkuId, worldRootForAkumaPaths } from "./identity.js";
|
|
6
6
|
import { BIRTH_TIMEOUT_MS } from "./publication.js";
|
|
7
7
|
import { decodeEnvelope } from "./request-wire.js";
|
|
@@ -77,6 +77,8 @@ export class BodyRequestPump {
|
|
|
77
77
|
}
|
|
78
78
|
async close() {
|
|
79
79
|
this.stopAdmission();
|
|
80
|
+
if (!this.executionSignal.signal.aborted)
|
|
81
|
+
this.executionSignal.abort(new Error("Body request pump closed"));
|
|
80
82
|
try {
|
|
81
83
|
await this.running;
|
|
82
84
|
}
|
|
@@ -112,14 +114,34 @@ async function settleReservedSoul(paths, parent, request, soul) {
|
|
|
112
114
|
? serveRequest(paths, request.id, request.child)
|
|
113
115
|
: voidRequest(paths, request.id, "reserved child origin does not match the request"));
|
|
114
116
|
}
|
|
115
|
-
async function
|
|
117
|
+
async function settleReservedWithLeash(paths, parent, request, leash, now) {
|
|
118
|
+
const childPaths = pathsForAkuId(worldRootForAkumaPaths(paths), request.child);
|
|
119
|
+
try {
|
|
120
|
+
const settled = await readSoul(childPaths);
|
|
121
|
+
if (settled !== null) {
|
|
122
|
+
await settleReservedSoul(paths, parent, request, settled);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const outcome = await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
126
|
+
if (outcome === "sealed") {
|
|
127
|
+
await voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const born = await readSoul(childPaths);
|
|
131
|
+
if (born !== null)
|
|
132
|
+
await settleReservedSoul(paths, parent, request, born);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
leash.release();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export async function settleReserved(paths, parent, request, now, signal) {
|
|
116
139
|
const childPaths = pathsForAkuId(worldRootForAkumaPaths(paths), request.child);
|
|
117
140
|
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
118
141
|
for (;;) {
|
|
119
142
|
signal?.throwIfAborted();
|
|
120
143
|
if (!(await access(childPaths.directory).then(() => true, () => false))) {
|
|
121
|
-
|
|
122
|
-
return true;
|
|
144
|
+
return false;
|
|
123
145
|
}
|
|
124
146
|
const soul = await readSoul(childPaths);
|
|
125
147
|
if (soul !== null) {
|
|
@@ -128,18 +150,7 @@ async function settleReserved(paths, parent, request, now, signal) {
|
|
|
128
150
|
}
|
|
129
151
|
const leash = await HeldAkumaLeash.try(childPaths);
|
|
130
152
|
if (leash !== null) {
|
|
131
|
-
|
|
132
|
-
const settled = await readSoul(childPaths);
|
|
133
|
-
if (settled !== null)
|
|
134
|
-
await settleReservedSoul(paths, parent, request, settled);
|
|
135
|
-
else {
|
|
136
|
-
await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
137
|
-
await voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
finally {
|
|
141
|
-
leash.release();
|
|
142
|
-
}
|
|
153
|
+
await settleReservedWithLeash(paths, parent, request, leash, now);
|
|
143
154
|
return true;
|
|
144
155
|
}
|
|
145
156
|
if (performance.now() >= deadline)
|
|
@@ -155,6 +166,8 @@ export async function settleBodyRequests(paths, parent, now, signal) {
|
|
|
155
166
|
await voidRequest(paths, request.id, "body died before serving the request");
|
|
156
167
|
else if (request.state === "reserved" && !(await settleReserved(paths, parent, request, now, signal)))
|
|
157
168
|
pending = true;
|
|
169
|
+
else if (request.state === "begun")
|
|
170
|
+
await unproveRequest(paths, request.id, "body died after service request began");
|
|
158
171
|
}
|
|
159
172
|
return pending ? "pending" : "settled";
|
|
160
173
|
}
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type RequestProtocol } from "./request-wire.js";
|
|
2
2
|
export declare class AkumaBodyRequestError extends Error {
|
|
3
3
|
readonly action: string;
|
|
4
|
-
readonly outcome: "refused" | "voided";
|
|
4
|
+
readonly outcome: "refused" | "voided" | "unproven" | "unknown";
|
|
5
5
|
readonly diagnostic: string;
|
|
6
|
+
readonly requestId: string;
|
|
6
7
|
readonly kind = "akuma-body-request";
|
|
7
|
-
constructor(action: string, outcome: "refused" | "voided", diagnostic: string);
|
|
8
|
+
constructor(action: string, outcome: "refused" | "voided" | "unproven" | "unknown", diagnostic: string, requestId: string);
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
export declare function requestBodyCommand<Input, Output, Service, Reference = Service>(input: Readonly<{
|
|
11
|
-
directory: string;
|
|
12
|
-
id?: string;
|
|
13
|
-
command: RequestCommand<Input, Output, Service, Reference>;
|
|
14
|
-
value: Input;
|
|
15
|
-
signal?: AbortSignal;
|
|
16
|
-
}>): Promise<Readonly<{
|
|
10
|
+
type RequestResponse<Output, Reference> = Readonly<{
|
|
17
11
|
kind: "returned";
|
|
18
12
|
result: Output;
|
|
19
13
|
requestId: string;
|
|
@@ -23,4 +17,13 @@ export declare function requestBodyCommand<Input, Output, Service, Reference = S
|
|
|
23
17
|
reference: Reference;
|
|
24
18
|
requestId: string;
|
|
25
19
|
action: string;
|
|
26
|
-
}
|
|
20
|
+
}>;
|
|
21
|
+
/** Generic rendezvous only: operation owners supply their own request and result codecs. */
|
|
22
|
+
export declare function requestBodyCommand<Input, Output, Reference>(input: Readonly<{
|
|
23
|
+
directory: string;
|
|
24
|
+
id?: string;
|
|
25
|
+
command: RequestProtocol<Input, Output, Reference>;
|
|
26
|
+
value: Input;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}>): Promise<RequestResponse<Output, Reference>>;
|
|
29
|
+
export {};
|
|
@@ -7,20 +7,25 @@ export class AkumaBodyRequestError extends Error {
|
|
|
7
7
|
action;
|
|
8
8
|
outcome;
|
|
9
9
|
diagnostic;
|
|
10
|
+
requestId;
|
|
10
11
|
kind = "akuma-body-request";
|
|
11
|
-
constructor(action, outcome, diagnostic) {
|
|
12
|
-
super(`${action} ${outcome === "
|
|
12
|
+
constructor(action, outcome, diagnostic, requestId) {
|
|
13
|
+
super(`${action} ${outcome === "refused" ? "refused" : outcome}: ${diagnostic}`);
|
|
13
14
|
this.action = action;
|
|
14
15
|
this.outcome = outcome;
|
|
15
16
|
this.diagnostic = diagnostic;
|
|
17
|
+
this.requestId = requestId;
|
|
16
18
|
this.name = "AkumaBodyRequestError";
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
function throwVoidedRequestFailure(action, evidence, failure, decodeFailure) {
|
|
21
|
+
function throwVoidedRequestFailure(action, evidence, failure, decodeFailure, requestId) {
|
|
20
22
|
const ownerFailure = decodeVoidedOwnerFailure(failure, decodeFailure);
|
|
21
23
|
if (ownerFailure !== null)
|
|
22
|
-
throw ownerFailure;
|
|
23
|
-
throw new AkumaBodyRequestError(action, "voided", evidence);
|
|
24
|
+
throw withRequestMetadata(ownerFailure, requestId, action);
|
|
25
|
+
throw new AkumaBodyRequestError(action, "voided", evidence, requestId);
|
|
26
|
+
}
|
|
27
|
+
function throwUnprovenRequestFailure(action, evidence, requestId) {
|
|
28
|
+
throw new AkumaBodyRequestError(action, "unproven", evidence, requestId);
|
|
24
29
|
}
|
|
25
30
|
function decodeVoidedOwnerFailure(failure, decodeFailure) {
|
|
26
31
|
if (failure === undefined || decodeFailure === undefined)
|
|
@@ -39,62 +44,86 @@ function withRequestMetadata(response, id, action) {
|
|
|
39
44
|
});
|
|
40
45
|
return response;
|
|
41
46
|
}
|
|
47
|
+
async function readRequestReceipt(input, path, id) {
|
|
48
|
+
try {
|
|
49
|
+
const receipt = decodeReceiptEnvelope(await readFile(path, "utf8"), id, input.command.action);
|
|
50
|
+
if (receipt === null)
|
|
51
|
+
throw new Error(`Akuma body request ${id} has an invalid receipt`);
|
|
52
|
+
if (receipt.state === "refused") {
|
|
53
|
+
throw new AkumaBodyRequestError(receipt.action, "refused", receipt.diagnostic, receipt.id);
|
|
54
|
+
}
|
|
55
|
+
if (receipt.state === "voided") {
|
|
56
|
+
throwVoidedRequestFailure(receipt.action, receipt.evidence, receipt.failure, input.command.decodeFailure, receipt.id);
|
|
57
|
+
}
|
|
58
|
+
if (receipt.state === "unproven")
|
|
59
|
+
throwUnprovenRequestFailure(receipt.action, receipt.evidence, receipt.id);
|
|
60
|
+
if ("reference" in receipt) {
|
|
61
|
+
let reference;
|
|
62
|
+
try {
|
|
63
|
+
reference = input.command.decodeReference(receipt.reference);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
67
|
+
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid durable reference: ${diagnostic}`);
|
|
68
|
+
}
|
|
69
|
+
return withRequestMetadata({ kind: "reference", reference }, id, input.command.action);
|
|
70
|
+
}
|
|
71
|
+
if (receipt.outcome.kind === "failed") {
|
|
72
|
+
const failure = receipt.outcome.failure;
|
|
73
|
+
throw new Error(failure.kind === "failed" ? failure.diagnostic : `Akuma ${failure.id} was not born`);
|
|
74
|
+
}
|
|
75
|
+
let result;
|
|
76
|
+
try {
|
|
77
|
+
result = input.command.decodeResult(receipt.outcome.result);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
81
|
+
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid live result: ${diagnostic}`);
|
|
82
|
+
}
|
|
83
|
+
return withRequestMetadata({ kind: "returned", result }, id, input.command.action);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error.code === "ENOENT")
|
|
87
|
+
return undefined;
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
42
91
|
/** Generic rendezvous only: operation owners supply their own request and result codecs. */
|
|
43
92
|
export async function requestBodyCommand(input) {
|
|
44
93
|
const id = input.id ?? randomUUID();
|
|
45
94
|
input.signal?.throwIfAborted();
|
|
46
95
|
const transportId = randomUUID();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
96
|
+
const payload = input.command.encodeRequest(input.value);
|
|
97
|
+
try {
|
|
98
|
+
await atomicJson(requestPath(input.directory, transportId), {
|
|
99
|
+
id,
|
|
100
|
+
action: input.command.action,
|
|
101
|
+
payload,
|
|
102
|
+
}, input.signal);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (error.code !== "ENOENT")
|
|
106
|
+
throw error;
|
|
107
|
+
if (input.signal?.aborted)
|
|
108
|
+
input.signal.throwIfAborted();
|
|
109
|
+
throw new AkumaBodyRequestError(input.command.action, "unknown", "parent request channel closed before request publication", id);
|
|
110
|
+
}
|
|
52
111
|
const path = receiptPath(input.directory, transportId);
|
|
53
112
|
for (;;) {
|
|
113
|
+
const response = await readRequestReceipt(input, path, id);
|
|
114
|
+
if (response !== undefined)
|
|
115
|
+
return response;
|
|
116
|
+
if (!(await access(input.directory).then(() => true, () => false))) {
|
|
117
|
+
throw new AkumaBodyRequestError(input.command.action, "unknown", "parent request channel closed before a receipt", id);
|
|
118
|
+
}
|
|
54
119
|
try {
|
|
55
|
-
|
|
56
|
-
if (receipt === null)
|
|
57
|
-
throw new Error(`Akuma body request ${id} has an invalid receipt`);
|
|
58
|
-
if (receipt.state === "refused")
|
|
59
|
-
throw new AkumaBodyRequestError(receipt.action, "refused", receipt.diagnostic);
|
|
60
|
-
if (receipt.state === "voided") {
|
|
61
|
-
throwVoidedRequestFailure(receipt.action, receipt.evidence, receipt.failure, input.command.decodeFailure);
|
|
62
|
-
}
|
|
63
|
-
if ("reference" in receipt) {
|
|
64
|
-
let reference;
|
|
65
|
-
try {
|
|
66
|
-
reference = input.command.decodeReference(receipt.reference);
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
70
|
-
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid durable reference: ${diagnostic}`);
|
|
71
|
-
}
|
|
72
|
-
return withRequestMetadata({
|
|
73
|
-
kind: "reference",
|
|
74
|
-
reference,
|
|
75
|
-
}, id, input.command.action);
|
|
76
|
-
}
|
|
77
|
-
if (receipt.outcome.kind === "failed") {
|
|
78
|
-
const failure = receipt.outcome.failure;
|
|
79
|
-
throw new Error(failure.kind === "failed" ? failure.diagnostic : `Akuma ${failure.id} was not born`);
|
|
80
|
-
}
|
|
81
|
-
let result;
|
|
82
|
-
try {
|
|
83
|
-
result = input.command.decodeResult(receipt.outcome.result);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
87
|
-
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid live result: ${diagnostic}`);
|
|
88
|
-
}
|
|
89
|
-
return withRequestMetadata({ kind: "returned", result }, id, input.command.action);
|
|
120
|
+
await abortableDelay(POLL_MS, input.signal);
|
|
90
121
|
}
|
|
91
122
|
catch (error) {
|
|
92
|
-
if (
|
|
93
|
-
throw
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
throw new AkumaBodyRequestError(input.command.action, "voided", "parent request channel closed before a receipt");
|
|
123
|
+
if (input.signal?.aborted) {
|
|
124
|
+
throw new AkumaBodyRequestError(input.command.action, "unknown", "request was cancelled after publication and before a receipt", id);
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
97
127
|
}
|
|
98
|
-
await abortableDelay(POLL_MS, input.signal);
|
|
99
128
|
}
|
|
100
129
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type ErasedRequestCommand, type RequestEnvelope } from "./request-wire.js";
|
|
2
2
|
import { BodyRequestPump as LifecycleBodyRequestPump, type PumpInput as LifecyclePumpInput } from "./request-lifecycle.js";
|
|
3
3
|
export { clearBodyRequestTransport, settleBodyRequests } from "./request-lifecycle.js";
|
|
4
|
-
type PumpInput =
|
|
5
|
-
upstream?: unknown;
|
|
4
|
+
type PumpInput = LifecyclePumpInput & Readonly<{
|
|
6
5
|
commands: Readonly<Record<string, ErasedRequestCommand>>;
|
|
7
6
|
}>;
|
|
8
7
|
export type ServeInput = Omit<PumpInput, "bodySequence"> & Readonly<{
|