@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
package/build/src/akuma/body.js
CHANGED
|
@@ -3,9 +3,10 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import { abortableDelay } from "./abort.js";
|
|
4
4
|
import { BodySupervisor } from "./body-supervisor.js";
|
|
5
5
|
import { driveTurn, turnRecipe } from "./turn-drive.js";
|
|
6
|
-
import { HeldAkumaLeash, breakBody, endTurn, finishBodyIfIdle, heartExists, isHeartAbsent, projectTell, readHeart, readTell, readNonterminalRequests, } from "./heart/index.js";
|
|
6
|
+
import { HeldAkumaLeash, breakBody, decidePendingTellDisposition, drainPendingTells, endTurn, failOpenBoundTurns, finishBodyIfIdle, heartExists, isHeartAbsent, probeLeash, projectTell, provePendingTellDispositionCustody, readHeart, readOpenPendingTellDisposition, readTell, readTurn, readNonterminalRequests, recordUndeliveredPendingTells, resolvePendingTellDisposition, } from "./heart/index.js";
|
|
7
7
|
import { worldRootForAkumaPaths } from "./identity.js";
|
|
8
|
-
import {
|
|
8
|
+
import { pluginRuntime } from "../plugin/runtime.js";
|
|
9
|
+
import { World } from "../world.js";
|
|
9
10
|
import { resolveProviderExecution } from "./providers/index.js";
|
|
10
11
|
import { clearBodyRequestTransport, settleBodyRequests } from "./request-serve.js";
|
|
11
12
|
import { spawnDetachedProcess, } from "../runtime/proc/run.js";
|
|
@@ -16,8 +17,14 @@ export { CONTROL_RESPONSE_MS } from "./body-supervisor.js";
|
|
|
16
17
|
function missing(error) {
|
|
17
18
|
return isHeartAbsent(error) || error.code === "ENOENT";
|
|
18
19
|
}
|
|
20
|
+
async function failOpenBoundTurnsIfPresent(paths, bodySequence, diagnostic, at) {
|
|
21
|
+
if (!(await heartExists(paths)))
|
|
22
|
+
return;
|
|
23
|
+
await failOpenBoundTurns(paths, { bodySequence, diagnostic, completedAt: at });
|
|
24
|
+
}
|
|
19
25
|
async function putDownIfControlled(paths, supervisor, bodySequence, now) {
|
|
20
26
|
if (supervisor.reason === "control" && (await heartExists(paths))) {
|
|
27
|
+
await failOpenBoundTurnsIfPresent(paths, bodySequence, "Body put-down with open bound Turns", now());
|
|
21
28
|
await breakBody(paths, { sequence: bodySequence, end: "put-down", at: now() });
|
|
22
29
|
}
|
|
23
30
|
}
|
|
@@ -61,8 +68,48 @@ async function launchCwd(launch) {
|
|
|
61
68
|
throw new Error("Akuma wake has no born soul");
|
|
62
69
|
return (await turnRecipe(launch.paths, soul)).cwd;
|
|
63
70
|
}
|
|
71
|
+
function parseSchemaAnswerJson(raw) {
|
|
72
|
+
try {
|
|
73
|
+
JSON.parse(raw);
|
|
74
|
+
return { kind: "json", json: raw };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
kind: "invalid",
|
|
79
|
+
diagnostic: error instanceof Error ? error.message : "Answer is not valid JSON",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
64
83
|
async function persistTurn(paths, turnSequence, result, completedAt) {
|
|
84
|
+
const turn = await readTurn(paths, turnSequence);
|
|
85
|
+
const schemaJson = turn?.schemaJson;
|
|
65
86
|
if (result.kind === "answered" && result.session !== undefined) {
|
|
87
|
+
if (schemaJson !== undefined) {
|
|
88
|
+
const parsed = parseSchemaAnswerJson(result.answer);
|
|
89
|
+
if (parsed.kind === "invalid") {
|
|
90
|
+
const outcome = {
|
|
91
|
+
kind: "invalid-output",
|
|
92
|
+
diagnostic: parsed.diagnostic,
|
|
93
|
+
answer: result.answer,
|
|
94
|
+
session: result.session,
|
|
95
|
+
...(result.historyId === undefined ? {} : { historyId: result.historyId }),
|
|
96
|
+
};
|
|
97
|
+
await endTurn(paths, { turnSequence, outcome, completedAt });
|
|
98
|
+
return { outcome: "failed", diagnostic: parsed.diagnostic };
|
|
99
|
+
}
|
|
100
|
+
await endTurn(paths, {
|
|
101
|
+
turnSequence,
|
|
102
|
+
outcome: {
|
|
103
|
+
kind: "answered",
|
|
104
|
+
session: result.session,
|
|
105
|
+
answer: result.answer,
|
|
106
|
+
answerJson: parsed.json,
|
|
107
|
+
...(result.historyId === undefined ? {} : { historyId: result.historyId }),
|
|
108
|
+
},
|
|
109
|
+
completedAt,
|
|
110
|
+
});
|
|
111
|
+
return { outcome: "answered", answer: result.answer };
|
|
112
|
+
}
|
|
66
113
|
await endTurn(paths, {
|
|
67
114
|
turnSequence,
|
|
68
115
|
outcome: {
|
|
@@ -79,52 +126,24 @@ async function persistTurn(paths, turnSequence, result, completedAt) {
|
|
|
79
126
|
await endTurn(paths, { turnSequence, outcome: { kind: "failed", diagnostic }, completedAt });
|
|
80
127
|
return { outcome: "failed", diagnostic };
|
|
81
128
|
}
|
|
82
|
-
function completionMessage(identity, completion) {
|
|
83
|
-
const participant = completion?.participantName;
|
|
84
|
-
const contract = completion?.contractId;
|
|
85
|
-
const header = [identity, participant === undefined ? undefined : `(@${participant})`, contract]
|
|
86
|
-
.filter((value) => value !== undefined)
|
|
87
|
-
.join(" ");
|
|
88
|
-
return `${header}\n✓ came back`;
|
|
89
|
-
}
|
|
90
129
|
function boundedDiagnostic(error) {
|
|
91
130
|
const text = diagnostic(error);
|
|
92
131
|
return text.length <= 500 ? text : `${text.slice(0, 500)}...`;
|
|
93
132
|
}
|
|
94
|
-
async function
|
|
133
|
+
async function recordPluginDiagnostic(paths, occurrence, error) {
|
|
95
134
|
try {
|
|
96
|
-
|
|
97
|
-
const identity = launch.seed?.id ?? (await readHeart(launch.paths)).soul?.id;
|
|
98
|
-
if (identity === undefined)
|
|
99
|
-
return;
|
|
100
|
-
const square = await Square.at({ path: keiyakuSquarePath(worldRootForAkumaPaths(launch.paths)) });
|
|
101
|
-
try {
|
|
102
|
-
const joined = await square.implicitJoin(identity);
|
|
103
|
-
if (joined.state === "done" || joined.participant === undefined)
|
|
104
|
-
return;
|
|
105
|
-
await joined.participant.express(completionMessage(identity, launch.completion));
|
|
106
|
-
}
|
|
107
|
-
finally {
|
|
108
|
-
await square.close();
|
|
109
|
-
}
|
|
135
|
+
await appendFile(paths.log, `plugin ${occurrence} failed: ${boundedDiagnostic(error)}\n`);
|
|
110
136
|
}
|
|
111
|
-
catch
|
|
112
|
-
|
|
113
|
-
await appendFile(launch.paths.log, `square outcome express failed: ${boundedDiagnostic(error)}\n`);
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
/* express loss never changes Heart truth */
|
|
117
|
-
}
|
|
137
|
+
catch {
|
|
138
|
+
/* plugin diagnostic loss never changes Heart truth */
|
|
118
139
|
}
|
|
119
140
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
};
|
|
127
|
-
}
|
|
141
|
+
const DEFAULT_RUNTIME = {
|
|
142
|
+
now: () => new Date().toISOString(),
|
|
143
|
+
spawnChild: spawnAkumaBody,
|
|
144
|
+
externalCommands: {},
|
|
145
|
+
spawnBody: spawnAkumaBody,
|
|
146
|
+
};
|
|
128
147
|
export async function bodyProcessInput(launch, bodyModuleUrl = import.meta.url) {
|
|
129
148
|
const encoded = Buffer.from(JSON.stringify(launch), "utf8").toString("base64url");
|
|
130
149
|
const actorId = launch.seed?.id ?? (await readHeart(launch.paths)).soul?.id;
|
|
@@ -172,11 +191,40 @@ async function recoverBodyRequests(input) {
|
|
|
172
191
|
}
|
|
173
192
|
return false;
|
|
174
193
|
}
|
|
194
|
+
function turnOutcomeEmitter(launch, soul) {
|
|
195
|
+
let plugins;
|
|
196
|
+
const reportDiagnostic = (message) => {
|
|
197
|
+
void recordPluginDiagnostic(launch.paths, "turn outcome", message);
|
|
198
|
+
};
|
|
199
|
+
return (turnSequence, outcome) => {
|
|
200
|
+
void (async () => {
|
|
201
|
+
try {
|
|
202
|
+
plugins ??= pluginRuntime({
|
|
203
|
+
world: await World.at(worldRootForAkumaPaths(launch.paths)),
|
|
204
|
+
reportDiagnostic,
|
|
205
|
+
});
|
|
206
|
+
(await plugins).emit({
|
|
207
|
+
kind: "akuma.turn-outcome",
|
|
208
|
+
akumaId: soul.id,
|
|
209
|
+
turnSequence,
|
|
210
|
+
outcome: outcome.outcome === "answered"
|
|
211
|
+
? { kind: "answered", text: outcome.answer }
|
|
212
|
+
: { kind: "failed", reason: outcome.diagnostic },
|
|
213
|
+
...(launch.completion?.contractId === undefined ? {} : { contractId: launch.completion.contractId }),
|
|
214
|
+
}, reportDiagnostic);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
await recordPluginDiagnostic(launch.paths, "turn outcome", error);
|
|
218
|
+
}
|
|
219
|
+
})();
|
|
220
|
+
};
|
|
221
|
+
}
|
|
175
222
|
async function runBodyTurns(input) {
|
|
176
223
|
const { launch, soul, adapter, bodySequence, supervisor, runtime } = input;
|
|
177
224
|
let initial = launch.initialBody;
|
|
225
|
+
const emitTurnOutcome = turnOutcomeEmitter(launch, soul);
|
|
178
226
|
for (;;) {
|
|
179
|
-
const launchTells = supervisor.current().pending;
|
|
227
|
+
const launchTells = drainPendingTells(supervisor.current().pending);
|
|
180
228
|
if (supervisor.signal.aborted) {
|
|
181
229
|
await putDownIfControlled(launch.paths, supervisor, bodySequence, runtime.now);
|
|
182
230
|
return;
|
|
@@ -201,28 +249,32 @@ async function runBodyTurns(input) {
|
|
|
201
249
|
body: initial ?? "",
|
|
202
250
|
...(initial === undefined ? {} : { call: initial }),
|
|
203
251
|
launchTells,
|
|
204
|
-
...(
|
|
205
|
-
|
|
252
|
+
...(launchTells.find((tell) => tell.schemaJson !== undefined)?.schemaJson === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: { schemaJson: launchTells.find((tell) => tell.schemaJson !== undefined).schemaJson }),
|
|
255
|
+
world: runtime.world,
|
|
256
|
+
externalCommands: runtime.externalCommands,
|
|
206
257
|
now: runtime.now,
|
|
207
258
|
});
|
|
208
|
-
if (result.kind === "hung")
|
|
259
|
+
if (result.kind === "hung") {
|
|
260
|
+
await failOpenBoundTurnsIfPresent(launch.paths, bodySequence, "Body hung with open bound Turns", runtime.now());
|
|
209
261
|
return;
|
|
262
|
+
}
|
|
210
263
|
if (result.kind === "stopped") {
|
|
211
264
|
await putDownIfControlled(launch.paths, supervisor, bodySequence, runtime.now);
|
|
212
265
|
return;
|
|
213
266
|
}
|
|
214
|
-
if (result.kind === "handoff")
|
|
215
|
-
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
267
|
+
if (result.kind === "handoff")
|
|
268
|
+
return "handoff";
|
|
218
269
|
if (result.kind === "resume-unsupported") {
|
|
270
|
+
await failOpenBoundTurnsIfPresent(launch.paths, bodySequence, "resume-unsupported with open bound Turns", runtime.now());
|
|
219
271
|
await breakBody(launch.paths, { sequence: bodySequence, end: "broke-off", at: runtime.now() });
|
|
220
272
|
return;
|
|
221
273
|
}
|
|
222
274
|
const outcome = await persistTurn(launch.paths, result.turnSequence, result, runtime.now());
|
|
223
|
-
|
|
224
|
-
await expressInitialOutcome(launch);
|
|
275
|
+
emitTurnOutcome(result.turnSequence, outcome);
|
|
225
276
|
if (outcome.outcome === "failed") {
|
|
277
|
+
await failOpenBoundTurnsIfPresent(launch.paths, bodySequence, outcome.diagnostic, runtime.now());
|
|
226
278
|
await breakBody(launch.paths, { sequence: bodySequence, end: "broke-off", at: runtime.now() });
|
|
227
279
|
return;
|
|
228
280
|
}
|
|
@@ -230,24 +282,115 @@ async function runBodyTurns(input) {
|
|
|
230
282
|
initial = undefined;
|
|
231
283
|
}
|
|
232
284
|
}
|
|
233
|
-
|
|
285
|
+
async function projectUndeliveredPendingTellEvidence(paths, error) {
|
|
234
286
|
try {
|
|
235
|
-
|
|
236
|
-
return;
|
|
237
|
-
(await spawn({ paths, refuseIfHeld: true })).release();
|
|
287
|
+
await appendFile(paths.log, `pending Tell disposition undelivered: ${boundedDiagnostic(error)}\n`);
|
|
238
288
|
}
|
|
239
289
|
catch {
|
|
240
|
-
/*
|
|
290
|
+
/* log evidence loss never changes Heart truth */
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async function settleUndeliveredDisposition(paths, disposition, error) {
|
|
294
|
+
await projectUndeliveredPendingTellEvidence(paths, error);
|
|
295
|
+
if (!(await heartExists(paths)))
|
|
296
|
+
return;
|
|
297
|
+
const at = new Date().toISOString();
|
|
298
|
+
await recordUndeliveredPendingTells(paths, at, disposition.tellIds);
|
|
299
|
+
await resolvePendingTellDisposition(paths, disposition.bodySequence, at);
|
|
300
|
+
}
|
|
301
|
+
async function consumeProvenDisposition(paths, disposition) {
|
|
302
|
+
const proof = await provePendingTellDispositionCustody(paths, disposition);
|
|
303
|
+
if (proof.kind !== "proven")
|
|
304
|
+
return false;
|
|
305
|
+
await resolvePendingTellDisposition(paths, disposition.bodySequence, new Date().toISOString());
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Wait for Heart custody proof of the frozen Tell-id snapshot, or for the
|
|
310
|
+
* spawned child to exit without that proof. Sequence growth, spawn resolution,
|
|
311
|
+
* and an unqualified held leash never consume the disposition.
|
|
312
|
+
*/
|
|
313
|
+
async function awaitDispositionCustody(paths, disposition, child, schedule) {
|
|
314
|
+
for (;;) {
|
|
315
|
+
if ((await provePendingTellDispositionCustody(paths, disposition)).kind === "proven") {
|
|
316
|
+
child.release();
|
|
317
|
+
return { kind: "proven" };
|
|
318
|
+
}
|
|
319
|
+
const timerController = new AbortController();
|
|
320
|
+
const timer = schedule(WAKE_REREAD_MS, timerController.signal).then(() => ({ kind: "timer" }));
|
|
321
|
+
let winner;
|
|
322
|
+
try {
|
|
323
|
+
winner = await Promise.race([child.exited.then((exit) => ({ kind: "exited", exit })), timer]);
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
timerController.abort();
|
|
327
|
+
await timer.catch(() => undefined);
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
if (winner.kind === "timer")
|
|
331
|
+
continue;
|
|
332
|
+
timerController.abort();
|
|
333
|
+
await timer.catch(() => undefined);
|
|
334
|
+
if ((await provePendingTellDispositionCustody(paths, disposition)).kind === "proven") {
|
|
335
|
+
child.release();
|
|
336
|
+
return { kind: "proven" };
|
|
337
|
+
}
|
|
338
|
+
return winner.exit.code === LEASH_HELD_EXIT ? { kind: "held" } : failedChild(winner.exit);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async function resolveDecidedPendingTellDisposition(paths, disposition, spawn) {
|
|
342
|
+
try {
|
|
343
|
+
if (await consumeProvenDisposition(paths, disposition))
|
|
344
|
+
return;
|
|
345
|
+
const wake = await awaitDispositionCustody(paths, disposition, await spawn({ paths, refuseIfHeld: true }), abortableDelay);
|
|
346
|
+
if (wake.kind === "proven") {
|
|
347
|
+
await resolvePendingTellDisposition(paths, disposition.bodySequence, new Date().toISOString());
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Predecessor still holds the leash: leave the Heart disposition open.
|
|
351
|
+
if (wake.kind === "held")
|
|
352
|
+
return;
|
|
353
|
+
await settleUndeliveredDisposition(paths, disposition, wake.kind === "failed" ? wake.diagnostic : "successor custody unproven");
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
await settleUndeliveredDisposition(paths, disposition, error);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
export async function handoffPendingTells(paths, spawn = spawnAkumaBody) {
|
|
360
|
+
const open = await readOpenPendingTellDisposition(paths);
|
|
361
|
+
if (open !== null) {
|
|
362
|
+
await resolveDecidedPendingTellDisposition(paths, open, spawn);
|
|
363
|
+
return;
|
|
241
364
|
}
|
|
365
|
+
const before = await readHeart(paths);
|
|
366
|
+
if (before.pending.length === 0)
|
|
367
|
+
return;
|
|
368
|
+
if ((await probeLeash(paths)) === "held")
|
|
369
|
+
return;
|
|
370
|
+
const bodySequence = before.latestBody?.sequence;
|
|
371
|
+
if (bodySequence === undefined || before.latestBody?.end === undefined)
|
|
372
|
+
return;
|
|
373
|
+
const decided = await decidePendingTellDisposition(paths, {
|
|
374
|
+
bodySequence,
|
|
375
|
+
at: new Date().toISOString(),
|
|
376
|
+
handoff: before.latestBody.end === "put-down",
|
|
377
|
+
});
|
|
378
|
+
if (decided === null)
|
|
379
|
+
return;
|
|
380
|
+
await resolveDecidedPendingTellDisposition(paths, decided, spawn);
|
|
242
381
|
}
|
|
243
|
-
export async function driveAkumaBody(launch, adapter,
|
|
382
|
+
export async function driveAkumaBody(launch, adapter, runtimeInput = {}) {
|
|
383
|
+
const world = runtimeInput.world ?? (await World.at(worldRootForAkumaPaths(launch.paths)));
|
|
384
|
+
const runtime = { ...DEFAULT_RUNTIME, ...runtimeInput, world };
|
|
244
385
|
const acquired = await takeLeash(launch.paths, launch.refuseIfHeld);
|
|
245
386
|
if (acquired === "held")
|
|
246
387
|
return "held";
|
|
247
388
|
if (acquired === "absent")
|
|
248
389
|
return;
|
|
249
390
|
const leash = acquired;
|
|
250
|
-
let
|
|
391
|
+
let pendingTellDisposition = undefined;
|
|
392
|
+
let bodySequence;
|
|
393
|
+
let decidedDisposition = null;
|
|
251
394
|
try {
|
|
252
395
|
const soul = await bornSoul(launch, leash, runtime.now());
|
|
253
396
|
if (soul === null)
|
|
@@ -261,12 +404,12 @@ export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()
|
|
|
261
404
|
if (!(await prepareBodyStart(launch.paths, leash)))
|
|
262
405
|
return;
|
|
263
406
|
const body = await leash.recordBody(launch.paths, { leashTakenAt: runtime.now() });
|
|
264
|
-
|
|
407
|
+
bodySequence = body.sequence;
|
|
265
408
|
const supervisor = await BodySupervisor.open(launch.paths, body.sequence, leash);
|
|
266
409
|
const execution = { launch, soul, adapter: selected, bodySequence: body.sequence, supervisor, runtime };
|
|
267
410
|
try {
|
|
268
411
|
if (await recoverBodyRequests(execution))
|
|
269
|
-
await runBodyTurns(execution);
|
|
412
|
+
pendingTellDisposition = await runBodyTurns(execution);
|
|
270
413
|
}
|
|
271
414
|
finally {
|
|
272
415
|
await supervisor.close();
|
|
@@ -287,16 +430,33 @@ export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()
|
|
|
287
430
|
throw error;
|
|
288
431
|
}
|
|
289
432
|
finally {
|
|
433
|
+
if (bodySequence !== undefined && (await heartExists(launch.paths))) {
|
|
434
|
+
const body = (await readHeart(launch.paths)).latestBody;
|
|
435
|
+
const inert = body?.sequence === bodySequence && (body.end !== undefined || body.hung !== undefined);
|
|
436
|
+
if (inert) {
|
|
437
|
+
await failOpenBoundTurns(launch.paths, {
|
|
438
|
+
bodySequence,
|
|
439
|
+
diagnostic: body.hung?.diagnostic ?? `Body ${body.end ?? "ended"} with open bound Turns`,
|
|
440
|
+
completedAt: runtime.now(),
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
decidedDisposition = await decidePendingTellDisposition(launch.paths, {
|
|
444
|
+
bodySequence,
|
|
445
|
+
at: runtime.now(),
|
|
446
|
+
handoff: pendingTellDisposition === "handoff",
|
|
447
|
+
});
|
|
448
|
+
}
|
|
290
449
|
leash.release();
|
|
291
|
-
if (
|
|
292
|
-
await
|
|
450
|
+
if (decidedDisposition !== null) {
|
|
451
|
+
await resolveDecidedPendingTellDisposition(launch.paths, decidedDisposition, runtime.spawnBody ?? spawnAkumaBody);
|
|
452
|
+
}
|
|
293
453
|
}
|
|
294
454
|
}
|
|
295
455
|
export async function spawnAkumaBody(launch) {
|
|
296
456
|
return await spawnDetachedProcess(await bodyProcessInput(launch));
|
|
297
457
|
}
|
|
298
|
-
export async function runAkumaBody(launch,
|
|
299
|
-
return await driveAkumaBody(launch, undefined, {
|
|
458
|
+
export async function runAkumaBody(launch, world, externalCommands) {
|
|
459
|
+
return await driveAkumaBody(launch, undefined, { world, externalCommands });
|
|
300
460
|
}
|
|
301
461
|
const DIRECT_TELL_WAKE = {
|
|
302
462
|
spawn: async (paths) => await spawnAkumaBody({ paths, refuseIfHeld: true }),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
export function callReadonly(value, diagnostic = "Akuma call readonly must be true") {
|
|
4
|
+
if (value === undefined)
|
|
5
|
+
return {};
|
|
6
|
+
if (value !== true)
|
|
7
|
+
throw new TypeError(diagnostic);
|
|
8
|
+
return { readonly: true };
|
|
9
|
+
}
|
|
10
|
+
export async function canonicalBirthCwd(input, diagnostic = `cwd is not an existing directory: ${input}`) {
|
|
11
|
+
const selected = resolve(input);
|
|
12
|
+
try {
|
|
13
|
+
const canonical = await realpath(selected);
|
|
14
|
+
if (!(await stat(canonical)).isDirectory())
|
|
15
|
+
throw new Error("not a directory");
|
|
16
|
+
return canonical;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
throw new Error(diagnostic);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Soul } from "./heart/index.js";
|
|
2
2
|
import { type AkuId, type AkumaPaths } from "./identity.js";
|
|
3
|
-
import { type ErasedRequestCommand, type
|
|
3
|
+
import { type ChildRequestCommand, type ErasedRequestCommand, type RequestProtocol } from "./request-wire.js";
|
|
4
4
|
import type { OwnedProcess } from "../runtime/proc/run.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { type WorldRoot } from "../world.js";
|
|
@@ -59,19 +59,16 @@ export type AkumaCallRequestChildLaunch = Readonly<{
|
|
|
59
59
|
seed: Omit<Soul, "createdAt">;
|
|
60
60
|
initialBody: string;
|
|
61
61
|
}>;
|
|
62
|
-
type
|
|
63
|
-
id: string;
|
|
64
|
-
requester: string;
|
|
65
|
-
signal: AbortSignal;
|
|
62
|
+
type AkumaCallRequestCapabilities = Readonly<{
|
|
66
63
|
world: WorldRoot;
|
|
67
64
|
paths: AkumaPaths;
|
|
68
65
|
parent: Soul;
|
|
69
66
|
spawn(launch: AkumaCallRequestChildLaunch): Promise<OwnedProcess | void>;
|
|
70
|
-
admissionOpen(): boolean;
|
|
71
67
|
}>;
|
|
72
68
|
export declare function decodeAkumaCallRequest(value: unknown): AkumaCallRequest | null;
|
|
73
|
-
export declare function
|
|
74
|
-
export declare function
|
|
69
|
+
export declare function akumaCallRequestProtocol(): RequestProtocol<AkumaCallRequest, AkuId, AkuId>;
|
|
70
|
+
export declare function akumaCallRequestCommand(capabilities: AkumaCallRequestCapabilities): ChildRequestCommand<AkumaCallRequest, AkuId, AkuId>;
|
|
71
|
+
export declare function akumaCallRequestCommands(capabilities: AkumaCallRequestCapabilities): Readonly<Record<"akuma.call", ErasedRequestCommand>>;
|
|
75
72
|
export declare function requestForwardedAkumaCall(input: Omit<AkumaCallRequest, "action"> & Readonly<{
|
|
76
73
|
directory: string;
|
|
77
74
|
id: string;
|
|
@@ -6,7 +6,7 @@ import { publishAkuma } from "./publication.js";
|
|
|
6
6
|
import { decodeProviderOptions, decodeReadonlyRestraint } from "./provider-recipe.js";
|
|
7
7
|
import { decodeProviderExecution } from "./providers/index.js";
|
|
8
8
|
import { requestBodyCommand } from "./request-rendezvous.js";
|
|
9
|
-
import { eraseRequestCommand } from "./request-wire.js";
|
|
9
|
+
import { eraseRequestCommand, } from "./request-wire.js";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { World } from "../world.js";
|
|
12
12
|
function schemaDecode(decode, message) {
|
|
@@ -71,49 +71,6 @@ const akumaCallPayloadSchema = z
|
|
|
71
71
|
recipe: akumaCallRecipeSchema,
|
|
72
72
|
})
|
|
73
73
|
.strict();
|
|
74
|
-
function carriesLaunchWorld(value) {
|
|
75
|
-
const upstream = object(value);
|
|
76
|
-
return upstream !== null && typeof upstream.launchWorld === "function";
|
|
77
|
-
}
|
|
78
|
-
function decodeCallExecutionContext(value) {
|
|
79
|
-
const context = object(value);
|
|
80
|
-
const paths = object(context?.paths);
|
|
81
|
-
const parent = object(context?.parent);
|
|
82
|
-
const parentId = akuIdSchema.safeParse(parent?.id);
|
|
83
|
-
if (context === null ||
|
|
84
|
-
typeof context.id !== "string" ||
|
|
85
|
-
context.id.trim() === "" ||
|
|
86
|
-
typeof context.requester !== "string" ||
|
|
87
|
-
typeof context.signal !== "object" ||
|
|
88
|
-
context.signal === null ||
|
|
89
|
-
typeof context.signal.throwIfAborted !== "function" ||
|
|
90
|
-
paths === null ||
|
|
91
|
-
!["directory", "heart", "leash", "log", "requests"].every((key) => typeof paths[key] === "string") ||
|
|
92
|
-
parent === null ||
|
|
93
|
-
!parentId.success ||
|
|
94
|
-
typeof parent.cwd !== "string" ||
|
|
95
|
-
!Array.isArray(parent.allowed) ||
|
|
96
|
-
typeof context.spawn !== "function" ||
|
|
97
|
-
typeof context.admissionOpen !== "function")
|
|
98
|
-
throw new Error("invalid Akuma call execution context");
|
|
99
|
-
if (!carriesLaunchWorld(context.upstream))
|
|
100
|
-
throw new Error("Akuma call requires a minted launch World");
|
|
101
|
-
return {
|
|
102
|
-
id: context.id,
|
|
103
|
-
requester: context.requester,
|
|
104
|
-
signal: context.signal,
|
|
105
|
-
world: context.upstream.launchWorld(),
|
|
106
|
-
paths: context.paths,
|
|
107
|
-
parent: context.parent,
|
|
108
|
-
spawn: context.spawn,
|
|
109
|
-
admissionOpen: context.admissionOpen,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function object(value) {
|
|
113
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
114
|
-
? value
|
|
115
|
-
: null;
|
|
116
|
-
}
|
|
117
74
|
export function decodeAkumaCallRequest(value) {
|
|
118
75
|
const parsed = akumaCallPayloadSchema.safeParse(value);
|
|
119
76
|
return parsed.success ? { ...parsed.data, action: "akuma.call" } : null;
|
|
@@ -122,16 +79,16 @@ function callPayload(request) {
|
|
|
122
79
|
const { action: _action, ...payload } = request;
|
|
123
80
|
return payload;
|
|
124
81
|
}
|
|
125
|
-
async function executeAkumaCall(request,
|
|
126
|
-
const world =
|
|
82
|
+
async function executeAkumaCall(request, facts, capabilities) {
|
|
83
|
+
const { world, paths, parent, spawn } = capabilities;
|
|
127
84
|
const requestWorld = await World.prove(request.world);
|
|
128
85
|
if (requestWorld !== world) {
|
|
129
|
-
await refuseRequest(
|
|
86
|
+
await refuseRequest(paths, facts.id, `request world ${requestWorld} does not match ${world}`);
|
|
130
87
|
throw new Error(`request world ${requestWorld} does not match ${world}`);
|
|
131
88
|
}
|
|
132
89
|
const recipe = {
|
|
133
90
|
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
134
|
-
allowed: clipAllowedActions(request.recipe.allowed,
|
|
91
|
+
allowed: clipAllowedActions(request.recipe.allowed, parent.allowed),
|
|
135
92
|
provider: request.recipe.provider,
|
|
136
93
|
options: request.recipe.options,
|
|
137
94
|
...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
|
|
@@ -139,19 +96,19 @@ async function executeAkumaCall(request, context) {
|
|
|
139
96
|
const published = await publishAkuma({
|
|
140
97
|
worldPath: world,
|
|
141
98
|
archetype: request.archetype,
|
|
142
|
-
signal:
|
|
99
|
+
signal: facts.signal,
|
|
143
100
|
launch: async (allocated) => {
|
|
144
|
-
if (!
|
|
101
|
+
if (!facts.admissionOpen())
|
|
145
102
|
throw new Error("body closed request admission");
|
|
146
|
-
await reserveRequest(
|
|
147
|
-
return await
|
|
103
|
+
await reserveRequest(paths, facts.id, allocated.id);
|
|
104
|
+
return await spawn({
|
|
148
105
|
paths: allocated.paths,
|
|
149
106
|
seed: {
|
|
150
107
|
id: allocated.id,
|
|
151
108
|
archetype: allocated.archetype,
|
|
152
109
|
...recipe,
|
|
153
|
-
cwd: request.cwd ??
|
|
154
|
-
origin: { kind: "request", parent:
|
|
110
|
+
cwd: request.cwd ?? parent.cwd,
|
|
111
|
+
origin: { kind: "request", parent: parent.id, requestId: facts.id },
|
|
155
112
|
},
|
|
156
113
|
initialBody: request.body,
|
|
157
114
|
});
|
|
@@ -159,7 +116,7 @@ async function executeAkumaCall(request, context) {
|
|
|
159
116
|
});
|
|
160
117
|
return { result: published.id, child: published.id };
|
|
161
118
|
}
|
|
162
|
-
export function
|
|
119
|
+
export function akumaCallRequestProtocol() {
|
|
163
120
|
return {
|
|
164
121
|
action: "akuma.call",
|
|
165
122
|
encodeRequest: callPayload,
|
|
@@ -171,19 +128,6 @@ export function akumaCallRequestCommand() {
|
|
|
171
128
|
throw new Error("Akuma call returned an invalid child");
|
|
172
129
|
return child.data;
|
|
173
130
|
},
|
|
174
|
-
encodeService: (service) => service,
|
|
175
|
-
decodeService: (_service) => {
|
|
176
|
-
throw new Error("Akuma call has no service evidence");
|
|
177
|
-
},
|
|
178
|
-
projectService: (_service) => {
|
|
179
|
-
throw new Error("Akuma call has no service evidence");
|
|
180
|
-
},
|
|
181
|
-
projectChild: (child) => {
|
|
182
|
-
const id = akuIdSchema.safeParse(child);
|
|
183
|
-
if (!id.success)
|
|
184
|
-
throw new Error("Akuma call stored an invalid child reference");
|
|
185
|
-
return id.data;
|
|
186
|
-
},
|
|
187
131
|
decodeReference: (reference) => {
|
|
188
132
|
const child = akuIdSchema.safeParse(reference);
|
|
189
133
|
if (!child.success)
|
|
@@ -191,19 +135,30 @@ export function akumaCallRequestCommand() {
|
|
|
191
135
|
return child.data;
|
|
192
136
|
},
|
|
193
137
|
isPermitted: (allowed) => allowed.includes("akuma.call"),
|
|
194
|
-
decodeExecutionContext: decodeCallExecutionContext,
|
|
195
|
-
execute: executeAkumaCall,
|
|
196
138
|
};
|
|
197
139
|
}
|
|
198
|
-
export function
|
|
199
|
-
return {
|
|
140
|
+
export function akumaCallRequestCommand(capabilities) {
|
|
141
|
+
return {
|
|
142
|
+
completion: "child",
|
|
143
|
+
protocol: akumaCallRequestProtocol(),
|
|
144
|
+
projectChild: (child) => {
|
|
145
|
+
const id = akuIdSchema.safeParse(child);
|
|
146
|
+
if (!id.success)
|
|
147
|
+
throw new Error("Akuma call stored an invalid child reference");
|
|
148
|
+
return id.data;
|
|
149
|
+
},
|
|
150
|
+
execute: async (request, facts) => await executeAkumaCall(request, facts, capabilities),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function akumaCallRequestCommands(capabilities) {
|
|
154
|
+
return { "akuma.call": eraseRequestCommand(akumaCallRequestCommand(capabilities)) };
|
|
200
155
|
}
|
|
201
156
|
export async function requestForwardedAkumaCall(input) {
|
|
202
157
|
const { directory, id, signal, ...request } = input;
|
|
203
158
|
const response = await requestBodyCommand({
|
|
204
159
|
directory,
|
|
205
160
|
id,
|
|
206
|
-
command:
|
|
161
|
+
command: akumaCallRequestProtocol(),
|
|
207
162
|
value: { ...request, action: "akuma.call" },
|
|
208
163
|
...(signal === undefined ? {} : { signal }),
|
|
209
164
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type AkumaStatus } from "./akuma.js";
|
|
2
|
+
import type { WorldRoot } from "../world.js";
|
|
3
|
+
import { type AkumaKillResult, type AkumaTellResult, type AkumaWaitResult } from "./fleet-observation.js";
|
|
4
|
+
export type WaitExecutionInput = Readonly<{
|
|
5
|
+
path: WorldRoot;
|
|
6
|
+
ids: readonly AkumaStatus["id"][];
|
|
7
|
+
completion: "any" | "all";
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<AkumaWaitResult>;
|
|
12
|
+
export type TellExecutionInput = Readonly<{
|
|
13
|
+
path: WorldRoot;
|
|
14
|
+
id: AkumaStatus["id"];
|
|
15
|
+
body: string;
|
|
16
|
+
tellId?: string;
|
|
17
|
+
recordedAt?: string;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function executeTellAkuma(input: TellExecutionInput): Promise<AkumaTellResult>;
|
|
21
|
+
export type KillExecutionInput = Readonly<{
|
|
22
|
+
path: WorldRoot;
|
|
23
|
+
ids: readonly AkumaStatus["id"][];
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function executeKillAkuma(input: KillExecutionInput): Promise<AkumaKillResult>;
|