@astrosheep/keiyaku 4.0.0 → 4.0.2
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 +133 -8
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
- package/build/src/akuma/abort.d.ts +2 -0
- package/build/src/akuma/abort.js +50 -0
- package/build/src/akuma/akuma.d.ts +50 -33
- package/build/src/akuma/akuma.js +175 -127
- package/build/src/akuma/archetype.d.ts +14 -5
- package/build/src/akuma/archetype.js +85 -39
- package/build/src/akuma/body.d.ts +3 -5
- package/build/src/akuma/body.js +490 -183
- package/build/src/akuma/coordinate.d.ts +9 -0
- package/build/src/akuma/coordinate.js +22 -0
- package/build/src/akuma/heart/facts.d.ts +88 -45
- package/build/src/akuma/heart/facts.js +19 -8
- package/build/src/akuma/heart/index.d.ts +64 -55
- package/build/src/akuma/heart/index.js +172 -252
- package/build/src/akuma/heart/rows.d.ts +38 -83
- package/build/src/akuma/heart/rows.js +117 -155
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +61 -22
- package/build/src/akuma/heart/soul.d.ts +8 -0
- package/build/src/akuma/heart/soul.js +136 -0
- package/build/src/akuma/heart/storage.d.ts +47 -0
- package/build/src/akuma/heart/storage.js +224 -0
- package/build/src/akuma/heart/tells.d.ts +12 -0
- package/build/src/akuma/heart/tells.js +79 -0
- package/build/src/akuma/heart/timeline.d.ts +15 -0
- package/build/src/akuma/heart/timeline.js +86 -0
- package/build/src/akuma/identity.d.ts +2 -2
- package/build/src/akuma/identity.js +9 -9
- package/build/src/akuma/index.d.ts +10 -3
- package/build/src/akuma/index.js +7 -1
- package/build/src/akuma/projection.d.ts +176 -0
- package/build/src/akuma/projection.js +256 -0
- package/build/src/akuma/provider-recipe.d.ts +24 -0
- package/build/src/akuma/provider-recipe.js +100 -0
- package/build/src/akuma/provider.d.ts +67 -13
- package/build/src/akuma/provider.js +172 -105
- package/build/src/akuma/providers/acp/core.d.ts +19 -0
- package/build/src/akuma/providers/acp/core.js +159 -0
- package/build/src/akuma/providers/acp/events.d.ts +20 -0
- package/build/src/akuma/providers/acp/events.js +73 -0
- package/build/src/akuma/providers/acp/index.d.ts +12 -0
- package/build/src/akuma/providers/acp/index.js +94 -0
- package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
- package/build/src/akuma/providers/claude/events.js +238 -0
- package/build/src/akuma/providers/claude/index.d.ts +47 -0
- package/build/src/akuma/providers/claude/index.js +279 -0
- package/build/src/akuma/providers/claude/input.d.ts +13 -0
- package/build/src/akuma/providers/claude/input.js +109 -0
- package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
- package/build/src/akuma/providers/codex-app-server/events.js +15 -12
- package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
- package/build/src/akuma/providers/codex-app-server/index.js +77 -33
- package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
- package/build/src/akuma/providers/grok-build/index.js +70 -0
- package/build/src/akuma/providers/index.d.ts +5 -3
- package/build/src/akuma/providers/index.js +35 -56
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
- package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
- package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
- package/build/src/akuma/providers/pi/events.d.ts +33 -0
- package/build/src/akuma/providers/pi/events.js +166 -0
- package/build/src/akuma/providers/pi/index.d.ts +11 -0
- package/build/src/akuma/providers/pi/index.js +191 -0
- package/build/src/akuma/publication.d.ts +3 -3
- package/build/src/akuma/publication.js +28 -40
- package/build/src/akuma/requests.d.ts +9 -6
- package/build/src/akuma/requests.js +95 -65
- package/build/src/alias/index.d.ts +4 -3
- package/build/src/alias/index.js +12 -13
- package/build/src/body/decode.js +7 -1
- package/build/src/body/region.d.ts +2 -0
- package/build/src/body/region.js +77 -7
- package/build/src/body/render.js +2 -1
- package/build/src/body/shape.js +7 -1
- package/build/src/body/verification.js +19 -4
- package/build/src/cli/accepted.d.ts +18 -12
- package/build/src/cli/accepted.js +73 -34
- package/build/src/cli/actor.js +3 -3
- package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
- package/build/src/cli/commands/akuma-invoke.js +101 -52
- package/build/src/cli/commands/akuma.d.ts +27 -9
- package/build/src/cli/commands/akuma.js +151 -80
- package/build/src/cli/commands/contract.d.ts +155 -0
- package/build/src/cli/commands/contract.js +20 -0
- package/build/src/cli/commands/install.js +2 -0
- package/build/src/cli/commands/task-invoke.d.ts +19 -4
- package/build/src/cli/commands/task-invoke.js +65 -17
- package/build/src/cli/commands/task-query.d.ts +5 -0
- package/build/src/cli/commands/task-query.js +247 -0
- package/build/src/cli/commands/task.d.ts +3 -1
- package/build/src/cli/commands/task.js +52 -14
- package/build/src/cli/coordinates.d.ts +18 -0
- package/build/src/cli/coordinates.js +120 -0
- package/build/src/cli/draft.d.ts +8 -0
- package/build/src/cli/draft.js +96 -0
- package/build/src/cli/invoke.d.ts +9 -3
- package/build/src/cli/invoke.js +287 -108
- package/build/src/cli/main.js +54 -7
- package/build/src/cli/parse.d.ts +21 -117
- package/build/src/cli/parse.js +79 -84
- package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
- package/build/src/cli/render/akuma-tool-command.js +144 -0
- package/build/src/cli/render/akuma-tool.d.ts +4 -2
- package/build/src/cli/render/akuma-tool.js +35 -5
- package/build/src/cli/render/akuma.d.ts +3 -1
- package/build/src/cli/render/akuma.js +247 -212
- package/build/src/cli/render/audit.d.ts +3 -0
- package/build/src/cli/render/audit.js +104 -0
- package/build/src/cli/render/catalog.d.ts +2 -0
- package/build/src/cli/render/catalog.js +16 -0
- package/build/src/cli/render/contract.d.ts +3 -3
- package/build/src/cli/render/contract.js +200 -54
- package/build/src/cli/render/kanshi.js +272 -129
- package/build/src/cli/render/receipt.d.ts +19 -0
- package/build/src/cli/render/receipt.js +106 -0
- package/build/src/cli/render/refusal.d.ts +16 -2
- package/build/src/cli/render/refusal.js +88 -3
- package/build/src/cli/render/region.d.ts +2 -0
- package/build/src/cli/render/region.js +17 -0
- package/build/src/cli/render/task.d.ts +2 -1
- package/build/src/cli/render/task.js +223 -60
- package/build/src/cli/render/terminal.d.ts +20 -0
- package/build/src/cli/render/terminal.js +121 -0
- package/build/src/cli/render/text.js +11 -3
- package/build/src/cli/result.d.ts +126 -19
- package/build/src/cli/usage.d.ts +1 -0
- package/build/src/cli/usage.js +3 -0
- package/build/src/contract-worktree.d.ts +44 -0
- package/build/src/contract-worktree.js +251 -0
- package/build/src/coordination/durable-file.d.ts +5 -1
- package/build/src/coordination/durable-file.js +57 -10
- package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
- package/build/src/coordination/sqlite-transaction-lock.js +22 -5
- package/build/src/core/facts/codec.js +23 -4
- package/build/src/core/facts/eligibility.d.ts +1 -10
- package/build/src/core/facts/eligibility.js +0 -49
- package/build/src/core/facts/fold.js +1 -6
- package/build/src/core/facts/gate.d.ts +1 -0
- package/build/src/core/facts/gate.js +1 -0
- package/build/src/core/facts/observation.d.ts +3 -0
- package/build/src/core/facts/observation.js +12 -0
- package/build/src/core/facts/types.d.ts +10 -3
- package/build/src/core/subject.js +2 -2
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +3 -18
- package/build/src/core/verbs/bind.js +2 -16
- package/build/src/core/verbs/deliver.d.ts +1 -1
- package/build/src/core/verbs/deliver.js +14 -4
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +7 -9
- package/build/src/dispatch/index.d.ts +5 -3
- package/build/src/dispatch/index.js +30 -21
- package/build/src/duration.d.ts +10 -0
- package/build/src/duration.js +22 -0
- package/build/src/git/admission.d.ts +2 -2
- package/build/src/git/admission.js +33 -23
- package/build/src/git/hooks.d.ts +15 -0
- package/build/src/git/hooks.js +70 -18
- package/build/src/git/identity.d.ts +5 -1
- package/build/src/git/identity.js +23 -4
- package/build/src/git/integration.d.ts +48 -0
- package/build/src/git/integration.js +250 -0
- package/build/src/git/observe.d.ts +29 -15
- package/build/src/git/observe.js +185 -76
- package/build/src/git/read-observation.d.ts +41 -0
- package/build/src/git/read-observation.js +361 -0
- package/build/src/git/reconcile.d.ts +17 -5
- package/build/src/git/reconcile.js +305 -109
- package/build/src/git/repository.d.ts +41 -18
- package/build/src/git/repository.js +220 -114
- package/build/src/git/scratch.d.ts +17 -0
- package/build/src/git/scratch.js +73 -0
- package/build/src/git/target-placement.d.ts +92 -0
- package/build/src/git/target-placement.js +375 -0
- package/build/src/git/tender.d.ts +49 -0
- package/build/src/git/tender.js +63 -0
- package/build/src/git/terminal-seal.d.ts +24 -0
- package/build/src/git/terminal-seal.js +89 -0
- package/build/src/git/tree.d.ts +2 -2
- package/build/src/git/tree.js +4 -0
- package/build/src/git/workspace.d.ts +53 -0
- package/build/src/git/workspace.js +139 -0
- package/build/src/identity/selector.d.ts +6 -0
- package/build/src/identity/selector.js +19 -0
- package/build/src/index.d.ts +4 -2
- package/build/src/index.js +2 -1
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +7 -3
- package/build/src/kanshi/read.js +245 -45
- package/build/src/kanshi/report.d.ts +81 -6
- package/build/src/kanshi/select.d.ts +5 -0
- package/build/src/kanshi/select.js +33 -1
- package/build/src/library/address.d.ts +57 -0
- package/build/src/library/address.js +165 -0
- package/build/src/library/akuma-creation.d.ts +16 -7
- package/build/src/library/akuma-creation.js +96 -22
- package/build/src/library/audit.d.ts +18 -0
- package/build/src/library/audit.js +44 -0
- package/build/src/library/bind.d.ts +21 -0
- package/build/src/library/bind.js +56 -0
- package/build/src/library/catalog.d.ts +58 -0
- package/build/src/library/catalog.js +69 -0
- package/build/src/library/configuration.d.ts +6 -15
- package/build/src/library/configuration.js +14 -17
- package/build/src/library/contract.d.ts +23 -49
- package/build/src/library/contract.js +171 -185
- package/build/src/library/delivery.d.ts +24 -0
- package/build/src/library/delivery.js +21 -0
- package/build/src/library/fleet.d.ts +65 -0
- package/build/src/library/fleet.js +153 -0
- package/build/src/library/input.d.ts +3 -0
- package/build/src/library/input.js +19 -0
- package/build/src/library/keiyaku.d.ts +18 -3
- package/build/src/library/keiyaku.js +12 -1
- package/build/src/library/mutation.d.ts +39 -0
- package/build/src/library/mutation.js +37 -0
- package/build/src/library/reconcile.d.ts +29 -0
- package/build/src/library/reconcile.js +179 -0
- package/build/src/library/refusal.d.ts +21 -0
- package/build/src/library/refusal.js +29 -0
- package/build/src/library/region.d.ts +14 -1
- package/build/src/library/region.js +18 -4
- package/build/src/library/repo.d.ts +4 -13
- package/build/src/library/repo.js +14 -24
- package/build/src/protocol/attempt.d.ts +16 -3
- package/build/src/protocol/attempt.js +41 -10
- package/build/src/protocol/bind.d.ts +9 -2
- package/build/src/protocol/bind.js +48 -40
- package/build/src/protocol/intent.d.ts +57 -20
- package/build/src/protocol/intent.js +55 -79
- package/build/src/protocol/operations.d.ts +152 -43
- package/build/src/protocol/operations.js +482 -166
- package/build/src/protocol/outcome.d.ts +14 -3
- package/build/src/protocol/outcome.js +11 -3
- package/build/src/protocol/placement.d.ts +41 -0
- package/build/src/protocol/placement.js +147 -0
- package/build/src/protocol/read/documents.d.ts +2 -2
- package/build/src/protocol/read/documents.js +4 -4
- package/build/src/protocol/read/status.d.ts +18 -5
- package/build/src/protocol/read/status.js +73 -13
- package/build/src/protocol/run.d.ts +49 -7
- package/build/src/protocol/run.js +53 -25
- package/build/src/runtime/proc/line-rpc.d.ts +4 -8
- package/build/src/runtime/proc/line-rpc.js +22 -28
- package/build/src/runtime/proc/run.d.ts +23 -21
- package/build/src/runtime/proc/run.js +123 -89
- package/build/src/runtime/proc/stdio.d.ts +18 -0
- package/build/src/runtime/proc/stdio.js +58 -0
- package/build/src/settings.d.ts +7 -1
- package/build/src/settings.js +32 -17
- package/build/src/settlement/fence.d.ts +5 -0
- package/build/src/settlement/fence.js +14 -0
- package/build/src/settlement/holder.d.ts +35 -4
- package/build/src/settlement/holder.js +127 -28
- package/build/src/settlement/settle.d.ts +9 -1
- package/build/src/settlement/settle.js +74 -37
- package/build/src/task/board.d.ts +23 -5
- package/build/src/task/board.js +17 -10
- package/build/src/task/compose.d.ts +2 -2
- package/build/src/task/compose.js +18 -10
- package/build/src/task/context.d.ts +3 -3
- package/build/src/task/context.js +15 -20
- package/build/src/task/document.d.ts +2 -1
- package/build/src/task/document.js +15 -5
- package/build/src/task/index.d.ts +27 -15
- package/build/src/task/index.js +57 -35
- package/build/src/task/operations.d.ts +38 -13
- package/build/src/task/operations.js +80 -46
- package/build/src/task/query.d.ts +67 -0
- package/build/src/task/query.js +279 -0
- package/build/src/task/store.d.ts +5 -7
- package/build/src/task/store.js +43 -28
- package/build/src/verification/declaration.d.ts +1 -0
- package/build/src/verification/execution.d.ts +51 -0
- package/build/src/verification/execution.js +108 -0
- package/build/src/workspace-place.d.ts +41 -0
- package/build/src/workspace-place.js +386 -0
- package/build/src/world.d.ts +24 -0
- package/build/src/world.js +136 -0
- package/package.json +8 -4
- package/build/src/akuma/activity.d.ts +0 -66
- package/build/src/akuma/activity.js +0 -139
- package/build/src/akuma/providers/claude.js +0 -305
- package/build/src/context-root.d.ts +0 -4
- package/build/src/context-root.js +0 -15
- package/build/src/git/delivery.d.ts +0 -20
- package/build/src/git/delivery.js +0 -109
- package/build/src/git/verification.d.ts +0 -14
- package/build/src/git/verification.js +0 -56
- package/build/src/protocol/read/audit.d.ts +0 -25
- package/build/src/protocol/read/audit.js +0 -39
- package/build/src/verification/producer.d.ts +0 -23
- package/build/src/verification/producer.js +0 -54
package/build/src/akuma/body.js
CHANGED
|
@@ -1,18 +1,151 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { abortableDelay } from "./abort.js";
|
|
3
|
+
import { HeldAkumaLeash, appendActivity, beginTurn, breakBody, endTurn, finishBodyIfIdle, heartExists, isHeartAbsent, readHeart, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
|
|
4
|
+
import { encodeAgentEvent, } from "./provider.js";
|
|
5
|
+
import { resolveProviderExecution } from "./providers/index.js";
|
|
6
|
+
import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./requests.js";
|
|
7
|
+
import { spawnDetachedProcess, } from "../runtime/proc/run.js";
|
|
7
8
|
const LEASH_RETRY_MS = 25;
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const BODY_CONTROL_OBSERVATION_MS = 100;
|
|
10
|
+
export const CONTROL_RESPONSE_MS = 1_000;
|
|
11
|
+
class BodySupervisor {
|
|
12
|
+
paths;
|
|
13
|
+
bodySequence;
|
|
14
|
+
leash;
|
|
15
|
+
signal;
|
|
16
|
+
controller = new AbortController();
|
|
17
|
+
finished = new AbortController();
|
|
18
|
+
observer;
|
|
19
|
+
waiter;
|
|
20
|
+
observation;
|
|
21
|
+
stopping;
|
|
22
|
+
constructor(paths, bodySequence, leash, observation) {
|
|
23
|
+
this.paths = paths;
|
|
24
|
+
this.bodySequence = bodySequence;
|
|
25
|
+
this.leash = leash;
|
|
26
|
+
this.signal = this.controller.signal;
|
|
27
|
+
this.observation = observation;
|
|
28
|
+
this.observer = this.observe();
|
|
29
|
+
}
|
|
30
|
+
static async open(paths, bodySequence, leash) {
|
|
31
|
+
return new BodySupervisor(paths, bodySequence, leash, await readHeart(paths));
|
|
32
|
+
}
|
|
33
|
+
get reason() { return this.stopping; }
|
|
34
|
+
current() { return this.observation; }
|
|
35
|
+
async recordHung(diagnostic, at) {
|
|
36
|
+
await this.leash.recordBodyHung(this.paths, { sequence: this.bodySequence, diagnostic, at });
|
|
37
|
+
}
|
|
38
|
+
async refresh() {
|
|
39
|
+
this.publish(await readHeart(this.paths));
|
|
40
|
+
return this.observation;
|
|
41
|
+
}
|
|
42
|
+
next(after) {
|
|
43
|
+
if (this.observation !== after)
|
|
44
|
+
return Promise.resolve(this.observation);
|
|
45
|
+
return new Promise((resolve) => { this.waiter = resolve; });
|
|
46
|
+
}
|
|
47
|
+
cancel(reason) {
|
|
48
|
+
if (this.stopping !== undefined)
|
|
49
|
+
return;
|
|
50
|
+
this.stopping = reason;
|
|
51
|
+
this.controller.abort(new Error(reason === "control"
|
|
52
|
+
? "Akuma Body interrupted by durable control"
|
|
53
|
+
: "Akuma Heart disappeared"));
|
|
54
|
+
this.waiter?.(this.observation);
|
|
55
|
+
this.waiter = undefined;
|
|
56
|
+
}
|
|
57
|
+
async close() {
|
|
58
|
+
this.finished.abort();
|
|
59
|
+
await this.observer;
|
|
60
|
+
this.waiter = undefined;
|
|
61
|
+
}
|
|
62
|
+
publish(snapshot) {
|
|
63
|
+
this.observation = snapshot;
|
|
64
|
+
this.waiter?.(snapshot);
|
|
65
|
+
this.waiter = undefined;
|
|
66
|
+
}
|
|
67
|
+
async observe() {
|
|
68
|
+
for (;;) {
|
|
69
|
+
const snapshot = this.observation;
|
|
70
|
+
if (!await heartExists(this.paths)) {
|
|
71
|
+
this.cancel("heart-gone");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (bodyControlRequested(snapshot, this.bodySequence)) {
|
|
75
|
+
this.cancel("control");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await abortableDelay(BODY_CONTROL_OBSERVATION_MS, this.finished.signal);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
await this.refresh();
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (await heartExists(this.paths))
|
|
89
|
+
throw error;
|
|
90
|
+
this.cancel("heart-gone");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function serializeEffects() {
|
|
97
|
+
let tail = Promise.resolve();
|
|
98
|
+
let failed = false;
|
|
99
|
+
let failure;
|
|
100
|
+
const serialize = async (effect) => {
|
|
101
|
+
const result = tail.then(effect);
|
|
102
|
+
tail = result.then(() => undefined, (error) => {
|
|
103
|
+
if (!failed)
|
|
104
|
+
failure = error;
|
|
105
|
+
failed = true;
|
|
106
|
+
});
|
|
107
|
+
return await result;
|
|
108
|
+
};
|
|
109
|
+
serialize.drain = async () => {
|
|
110
|
+
await tail;
|
|
111
|
+
if (failed)
|
|
112
|
+
throw failure;
|
|
113
|
+
};
|
|
114
|
+
return serialize;
|
|
10
115
|
}
|
|
11
116
|
function missing(error) {
|
|
12
|
-
return error.code === "ENOENT";
|
|
117
|
+
return isHeartAbsent(error) || error.code === "ENOENT";
|
|
13
118
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
119
|
+
async function writeProviderEvent(input, active, event) {
|
|
120
|
+
if (input.supervisor.signal.aborted)
|
|
121
|
+
return;
|
|
122
|
+
const at = input.now();
|
|
123
|
+
if (event.type === "session") {
|
|
124
|
+
await recordSession(input.paths, {
|
|
125
|
+
provider: input.soul.provider.name,
|
|
126
|
+
coordinate: event.coordinate,
|
|
127
|
+
cwd: active.cwd,
|
|
128
|
+
options: active.options,
|
|
129
|
+
admittedAt: at,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
await appendActivity(input.paths, {
|
|
133
|
+
turnSequence: active.turnSequence,
|
|
134
|
+
event: encodeAgentEvent(event),
|
|
135
|
+
at,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function bodyControlRequested(snapshot, bodySequence) {
|
|
139
|
+
return snapshot.stop?.bodySequence === bodySequence
|
|
140
|
+
|| snapshot.pause?.bodySequence === bodySequence;
|
|
141
|
+
}
|
|
142
|
+
async function putDownIfControlled(paths, supervisor, bodySequence, now) {
|
|
143
|
+
if (supervisor.reason === "control" && await heartExists(paths)) {
|
|
144
|
+
await breakBody(paths, { sequence: bodySequence, end: "put-down", at: now() });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function turnRecipe(paths, soul) {
|
|
148
|
+
const latest = (await readHeart(paths)).latestSession;
|
|
16
149
|
const admitted = latest?.provider === soul.provider.name ? latest : undefined;
|
|
17
150
|
const session = admitted?.coordinate;
|
|
18
151
|
return {
|
|
@@ -24,7 +157,7 @@ function turnRecipe(paths, soul) {
|
|
|
24
157
|
async function takeLeash(paths) {
|
|
25
158
|
for (;;) {
|
|
26
159
|
try {
|
|
27
|
-
const leash = HeldAkumaLeash.try(paths);
|
|
160
|
+
const leash = await HeldAkumaLeash.try(paths);
|
|
28
161
|
if (leash !== null)
|
|
29
162
|
return leash;
|
|
30
163
|
}
|
|
@@ -33,168 +166,305 @@ async function takeLeash(paths) {
|
|
|
33
166
|
return null;
|
|
34
167
|
throw error;
|
|
35
168
|
}
|
|
36
|
-
await
|
|
169
|
+
await abortableDelay(LEASH_RETRY_MS);
|
|
37
170
|
}
|
|
38
171
|
}
|
|
39
|
-
async function settlePredecessor(paths) {
|
|
40
|
-
const predecessor = readHeart(paths).latestBody;
|
|
41
|
-
if (predecessor === null)
|
|
42
|
-
return true;
|
|
43
|
-
const probe = probeProcessTree(predecessor.collar);
|
|
44
|
-
if (probe.kind === "gone")
|
|
45
|
-
return true;
|
|
46
|
-
if (probe.kind === "unverifiable")
|
|
47
|
-
return false;
|
|
48
|
-
const evidence = await putDownProcessTree(predecessor.collar);
|
|
49
|
-
return evidence !== "unavailable" && evidence !== "alive-after-sigkill";
|
|
50
|
-
}
|
|
51
172
|
async function startTurnDrive(input) {
|
|
52
|
-
const { cwd, options, session } = turnRecipe(input.paths, input.soul);
|
|
173
|
+
const { cwd, options, session } = await turnRecipe(input.paths, input.soul);
|
|
174
|
+
if (session !== undefined && input.adapter.resume === undefined)
|
|
175
|
+
return { kind: "resume-unsupported" };
|
|
176
|
+
const turn = await beginTurn(input.paths, {
|
|
177
|
+
bodySequence: input.bodySequence,
|
|
178
|
+
startedAt: input.now(),
|
|
179
|
+
...(input.call === undefined ? {} : { call: input.call }),
|
|
180
|
+
});
|
|
53
181
|
const requests = input.soul.confinement.kind === "declared"
|
|
54
|
-
?
|
|
182
|
+
? await BodyRequestPump.open({
|
|
55
183
|
paths: input.paths,
|
|
56
184
|
parent: input.soul,
|
|
57
185
|
bodySequence: input.bodySequence,
|
|
58
186
|
now: input.now,
|
|
59
187
|
spawn: input.runtimeSpawn,
|
|
188
|
+
signal: input.supervisor.signal,
|
|
60
189
|
})
|
|
61
190
|
: null;
|
|
191
|
+
const driveInput = {
|
|
192
|
+
body: input.body,
|
|
193
|
+
launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
|
|
194
|
+
cwd,
|
|
195
|
+
options,
|
|
196
|
+
signal: input.supervisor.signal,
|
|
197
|
+
...(requests === null ? {} : { requests: { dir: requests.directory } }),
|
|
198
|
+
};
|
|
199
|
+
const setup = session === undefined
|
|
200
|
+
? input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
|
|
201
|
+
: input.adapter.resume({ ...driveInput, session: { kind: "resume", coordinate: session } });
|
|
62
202
|
try {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
203
|
+
const selected = await setup;
|
|
204
|
+
if (input.supervisor.signal.aborted) {
|
|
205
|
+
await retireProviderCustody(input, turn.sequence, selected);
|
|
206
|
+
await requests?.close();
|
|
207
|
+
return { kind: "stopped" };
|
|
208
|
+
}
|
|
209
|
+
if (input.launchTells.length > 0) {
|
|
210
|
+
await recordTellDeliveries(input.paths, input.launchTells.map((tell) => ({
|
|
211
|
+
tellId: tell.id,
|
|
212
|
+
route: "launch",
|
|
213
|
+
turnSequence: turn.sequence,
|
|
214
|
+
fence: selected.admission.fence,
|
|
215
|
+
deliveredAt: input.now(),
|
|
216
|
+
})));
|
|
217
|
+
}
|
|
70
218
|
if (requests !== null)
|
|
71
|
-
void
|
|
72
|
-
return { drive, requests, cwd, options,
|
|
219
|
+
void selected.completion.then(() => requests.stopAdmission());
|
|
220
|
+
return { turnSequence: turn.sequence, drive: selected, requests, cwd, options,
|
|
221
|
+
...(session === undefined ? {} : { resume: session }) };
|
|
73
222
|
}
|
|
74
223
|
catch (error) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
224
|
+
await requests?.close();
|
|
225
|
+
if (input.supervisor.signal.aborted) {
|
|
226
|
+
if (input.supervisor.reason === "heart-gone")
|
|
227
|
+
throw error;
|
|
228
|
+
return { kind: "stopped" };
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
kind: "failed",
|
|
232
|
+
turnSequence: turn.sequence,
|
|
233
|
+
diagnostic: error instanceof Error ? error.message : String(error),
|
|
234
|
+
};
|
|
78
235
|
}
|
|
79
236
|
}
|
|
237
|
+
async function retireProviderCustody(input, turnSequence, drive) {
|
|
238
|
+
const outcome = await Promise.race([
|
|
239
|
+
drive.abort().then(() => ({ kind: "retired" }), (error) => ({ kind: "held", error })),
|
|
240
|
+
abortableDelay(CONTROL_RESPONSE_MS).then(() => ({
|
|
241
|
+
kind: "held",
|
|
242
|
+
error: new Error(`provider custody remained live after ${CONTROL_RESPONSE_MS}ms`),
|
|
243
|
+
})),
|
|
244
|
+
]);
|
|
245
|
+
if (outcome.kind === "retired")
|
|
246
|
+
return;
|
|
247
|
+
if (await heartExists(input.paths)) {
|
|
248
|
+
const diagnostic = outcome.error instanceof Error ? outcome.error.message : String(outcome.error);
|
|
249
|
+
const at = input.now();
|
|
250
|
+
try {
|
|
251
|
+
await input.supervisor.recordHung(diagnostic, at);
|
|
252
|
+
await appendActivity(input.paths, {
|
|
253
|
+
turnSequence,
|
|
254
|
+
event: encodeAgentEvent({ type: "note", text: `Provider custody was not retired: ${diagnostic}` }),
|
|
255
|
+
at,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch { /* undisposed provider custody still owns the leash */ }
|
|
259
|
+
}
|
|
260
|
+
for (;;)
|
|
261
|
+
await abortableDelay(60_000);
|
|
262
|
+
}
|
|
263
|
+
function pumpReceipts(writers) {
|
|
264
|
+
const { input, turnSequence, drive, writeWitness, mayWrite } = writers;
|
|
265
|
+
return (async () => {
|
|
266
|
+
if (drive.receipts === undefined)
|
|
267
|
+
return;
|
|
268
|
+
for await (const receipt of drive.receipts) {
|
|
269
|
+
if (!mayWrite())
|
|
270
|
+
return;
|
|
271
|
+
await writeWitness(async () => {
|
|
272
|
+
if (!mayWrite())
|
|
273
|
+
return;
|
|
274
|
+
await recordTellReceipt(input.paths, receipt.evidence === "exact"
|
|
275
|
+
? { ...receipt, receivedAt: input.now() }
|
|
276
|
+
: { ...receipt, turnSequence, receivedAt: input.now() });
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
})();
|
|
280
|
+
}
|
|
281
|
+
function observeReceiptFailure(receiptPump) {
|
|
282
|
+
return receiptPump.then(() => new Promise(() => { }), (error) => Promise.reject(error));
|
|
283
|
+
}
|
|
284
|
+
async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
|
|
285
|
+
const { input, turnSequence, drive, writeWitness, mayWrite } = writers;
|
|
286
|
+
for (const tell of pending) {
|
|
287
|
+
if (attempted.has(tell.id))
|
|
288
|
+
continue;
|
|
289
|
+
attempted.add(tell.id);
|
|
290
|
+
const outcome = await writeWitness(async () => {
|
|
291
|
+
const submission = await tellLive({ id: tell.id, text: tell.body });
|
|
292
|
+
if (!mayWrite())
|
|
293
|
+
return "turn-ended";
|
|
294
|
+
if (submission.kind === "turn-ended")
|
|
295
|
+
return "turn-ended";
|
|
296
|
+
await recordTellDeliveries(input.paths, [{
|
|
297
|
+
tellId: tell.id,
|
|
298
|
+
route: "live",
|
|
299
|
+
turnSequence,
|
|
300
|
+
fence: submission.fence,
|
|
301
|
+
receipt: drive.receipts === undefined ? "unavailable" : "required",
|
|
302
|
+
deliveredAt: input.now(),
|
|
303
|
+
}]);
|
|
304
|
+
return "accepted";
|
|
305
|
+
});
|
|
306
|
+
if (outcome === "turn-ended")
|
|
307
|
+
return "turn-ended";
|
|
308
|
+
}
|
|
309
|
+
return "live";
|
|
310
|
+
}
|
|
311
|
+
async function stopActiveDrive(input, active) {
|
|
312
|
+
await retireProviderCustody(input, active.turnSequence, active.drive);
|
|
313
|
+
await active.requests?.close();
|
|
314
|
+
}
|
|
315
|
+
function hasUnattemptedTell(liveTells, tellPump, pending, attempted) {
|
|
316
|
+
return liveTells && tellPump === null && pending.some((tell) => !attempted.has(tell.id));
|
|
317
|
+
}
|
|
318
|
+
function persistProviderEvent(_input, _active, event) {
|
|
319
|
+
return event.type === "session" ? event.coordinate : undefined;
|
|
320
|
+
}
|
|
321
|
+
async function settleCompletion(result, session, requests) {
|
|
322
|
+
await requests?.close();
|
|
323
|
+
return result.kind === "answered" ? { ...result, ...(session === undefined ? {} : { session }) } : result;
|
|
324
|
+
}
|
|
80
325
|
async function consumeTurnDrive(input, active) {
|
|
81
|
-
const { drive, requests,
|
|
82
|
-
let
|
|
83
|
-
let
|
|
326
|
+
const { turnSequence, drive, requests, resume } = active;
|
|
327
|
+
let heart = input.supervisor.current();
|
|
328
|
+
let turnSession = resume;
|
|
329
|
+
const attempted = new Set(input.launchTells.map((tell) => tell.id));
|
|
330
|
+
const writeWitness = serializeEffects();
|
|
331
|
+
let writesOpen = true;
|
|
332
|
+
const mayWrite = () => writesOpen && !input.supervisor.signal.aborted;
|
|
333
|
+
const writers = { input, turnSequence, drive, writeWitness, mayWrite };
|
|
334
|
+
const receiptPump = pumpReceipts(writers);
|
|
335
|
+
const receiptFailure = observeReceiptFailure(receiptPump);
|
|
84
336
|
const iterator = drive.events[Symbol.asyncIterator]();
|
|
85
337
|
let pending = iterator.next();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
338
|
+
let liveTells = true;
|
|
339
|
+
let tellPump = null;
|
|
340
|
+
let tellObservation = null;
|
|
341
|
+
try {
|
|
342
|
+
for (;;) {
|
|
343
|
+
if (input.supervisor.signal.aborted) {
|
|
344
|
+
writesOpen = false;
|
|
345
|
+
await stopActiveDrive(input, active);
|
|
346
|
+
return { kind: "stopped" };
|
|
91
347
|
}
|
|
92
|
-
|
|
93
|
-
|
|
348
|
+
if (hasUnattemptedTell(liveTells, tellPump, heart.pending, attempted)) {
|
|
349
|
+
if (drive.tell === undefined) {
|
|
350
|
+
writesOpen = false;
|
|
351
|
+
await stopActiveDrive(input, active);
|
|
352
|
+
return { kind: "handoff" };
|
|
353
|
+
}
|
|
354
|
+
tellPump = submitPendingLiveTells(writers, heart.pending, attempted, drive.tell);
|
|
355
|
+
tellObservation = tellPump.then((result) => ({ kind: "tell", result }));
|
|
94
356
|
}
|
|
95
|
-
|
|
357
|
+
const next = await Promise.race([
|
|
358
|
+
pending.then((event) => ({ kind: "event", event })),
|
|
359
|
+
input.supervisor.next(heart).then((observation) => ({ kind: "heart", observation })),
|
|
360
|
+
...(tellObservation === null ? [] : [tellObservation]),
|
|
361
|
+
receiptFailure,
|
|
362
|
+
...(requests === null ? [] : [requests.failure]),
|
|
363
|
+
]);
|
|
364
|
+
if (next.kind === "event" && !next.event.done) {
|
|
365
|
+
await writeProviderEvent(input, active, next.event.value);
|
|
366
|
+
}
|
|
367
|
+
if (next.kind === "heart") {
|
|
368
|
+
heart = next.observation;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (next.kind === "tell") {
|
|
372
|
+
tellPump = null;
|
|
373
|
+
tellObservation = null;
|
|
374
|
+
liveTells = next.result === "live";
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (next.event.done)
|
|
378
|
+
break;
|
|
379
|
+
turnSession = persistProviderEvent(input, active, next.event.value) ?? turnSession;
|
|
380
|
+
pending = iterator.next();
|
|
96
381
|
}
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
turnSession = event.coordinate;
|
|
110
|
-
recordSession(input.paths, {
|
|
111
|
-
provider: input.soul.provider.name,
|
|
112
|
-
coordinate: event.coordinate,
|
|
113
|
-
cwd,
|
|
114
|
-
options,
|
|
115
|
-
admittedAt: at,
|
|
116
|
-
});
|
|
382
|
+
const result = await drive.completion;
|
|
383
|
+
if (tellPump !== null)
|
|
384
|
+
await tellPump;
|
|
385
|
+
await writeWitness.drain();
|
|
386
|
+
writesOpen = false;
|
|
387
|
+
return await settleCompletion(result, turnSession, requests);
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
writesOpen = false;
|
|
391
|
+
if (input.supervisor.signal.aborted) {
|
|
392
|
+
await stopActiveDrive(input, active);
|
|
393
|
+
return { kind: "stopped" };
|
|
117
394
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
at,
|
|
122
|
-
});
|
|
123
|
-
if (!entered && input.tellId !== undefined) {
|
|
124
|
-
entered = true;
|
|
125
|
-
advanceTell(input.paths, input.tellId, "seen");
|
|
126
|
-
advanceTell(input.paths, input.tellId, "consumed");
|
|
395
|
+
await retireProviderCustody(input, turnSequence, drive);
|
|
396
|
+
try {
|
|
397
|
+
await requests?.close();
|
|
127
398
|
}
|
|
128
|
-
|
|
399
|
+
catch { /* preserve the first pump failure */ }
|
|
400
|
+
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
|
|
129
401
|
}
|
|
130
|
-
const result = await drive.completion;
|
|
131
|
-
if (requests !== null)
|
|
132
|
-
await requests.close();
|
|
133
|
-
if (!entered && result.kind === "answered" && input.tellId !== undefined) {
|
|
134
|
-
advanceTell(input.paths, input.tellId, "seen");
|
|
135
|
-
advanceTell(input.paths, input.tellId, "consumed");
|
|
136
|
-
}
|
|
137
|
-
return result.kind === "answered"
|
|
138
|
-
? { ...result, ...(turnSession === undefined ? {} : { session: turnSession }) }
|
|
139
|
-
: result;
|
|
140
402
|
}
|
|
141
403
|
async function driveTurn(input) {
|
|
142
|
-
|
|
404
|
+
let active;
|
|
143
405
|
try {
|
|
144
|
-
|
|
406
|
+
const started = await startTurnDrive(input);
|
|
407
|
+
if ("kind" in started)
|
|
408
|
+
return started;
|
|
409
|
+
active = started;
|
|
145
410
|
}
|
|
146
411
|
catch (error) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
try {
|
|
153
|
-
await active.drive.abort();
|
|
412
|
+
if (!await heartExists(input.paths)) {
|
|
413
|
+
input.supervisor.cancel("heart-gone");
|
|
414
|
+
return { kind: "stopped" };
|
|
154
415
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
const result = await consumeTurnDrive(input, active);
|
|
420
|
+
return result.kind === "stopped" || result.kind === "handoff"
|
|
421
|
+
? result
|
|
422
|
+
: { ...result, turnSequence: active.turnSequence };
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
if (await heartExists(input.paths)) {
|
|
426
|
+
await active.requests?.close();
|
|
427
|
+
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error),
|
|
428
|
+
turnSequence: active.turnSequence };
|
|
158
429
|
}
|
|
159
|
-
|
|
160
|
-
|
|
430
|
+
input.supervisor.cancel("heart-gone");
|
|
431
|
+
await stopActiveDrive(input, active);
|
|
432
|
+
return { kind: "stopped" };
|
|
161
433
|
}
|
|
162
434
|
}
|
|
163
|
-
function bornSoul(launch, leash, now) {
|
|
164
|
-
const before = readHeart(launch.paths);
|
|
165
|
-
if (before.
|
|
166
|
-
return null;
|
|
167
|
-
if (before.soul !== null) {
|
|
168
|
-
clearAbandonedControl(launch.paths);
|
|
435
|
+
async function bornSoul(launch, leash, now) {
|
|
436
|
+
const before = await readHeart(launch.paths);
|
|
437
|
+
if (before.soul !== null)
|
|
169
438
|
return before.soul;
|
|
170
|
-
}
|
|
171
439
|
if (launch.seed === undefined)
|
|
172
440
|
throw new Error("Akuma wake has no born soul");
|
|
173
441
|
const candidate = { ...launch.seed, createdAt: now };
|
|
174
|
-
if (leash.birth(launch.paths, candidate, launch.birthSession) === "sealed")
|
|
442
|
+
if (await leash.birth(launch.paths, candidate, launch.birthSession) === "sealed")
|
|
175
443
|
return null;
|
|
176
|
-
const born = readHeart(launch.paths).soul;
|
|
444
|
+
const born = (await readHeart(launch.paths)).soul;
|
|
177
445
|
if (born === null || born.id !== candidate.id) {
|
|
178
446
|
throw new Error("Akuma birth identity does not match its directory");
|
|
179
447
|
}
|
|
180
448
|
return born;
|
|
181
449
|
}
|
|
182
|
-
function launchCwd(launch) {
|
|
450
|
+
async function launchCwd(launch) {
|
|
183
451
|
if (launch.seed !== undefined)
|
|
184
452
|
return launch.seed.cwd;
|
|
185
|
-
const
|
|
186
|
-
const soul = snapshot.soul;
|
|
453
|
+
const soul = (await readHeart(launch.paths)).soul;
|
|
187
454
|
if (soul === null)
|
|
188
455
|
throw new Error("Akuma wake has no born soul");
|
|
189
|
-
return
|
|
190
|
-
? snapshot.latestSession.cwd
|
|
191
|
-
: soul.cwd;
|
|
456
|
+
return (await turnRecipe(launch.paths, soul)).cwd;
|
|
192
457
|
}
|
|
193
|
-
function persistTurn(paths,
|
|
194
|
-
|
|
195
|
-
|
|
458
|
+
async function persistTurn(paths, turnSequence, result, completedAt) {
|
|
459
|
+
await endTurn(paths, {
|
|
460
|
+
turnSequence,
|
|
196
461
|
outcome: result.kind === "answered" && result.session !== undefined
|
|
197
|
-
? {
|
|
462
|
+
? {
|
|
463
|
+
kind: "answered",
|
|
464
|
+
session: result.session,
|
|
465
|
+
answer: result.answer,
|
|
466
|
+
...(result.historyId === undefined ? {} : { historyId: result.historyId }),
|
|
467
|
+
}
|
|
198
468
|
: result.kind === "answered"
|
|
199
469
|
? { kind: "failed", diagnostic: "Provider answered without a resumable session" }
|
|
200
470
|
: { kind: "failed", diagnostic: result.diagnostic },
|
|
@@ -204,82 +474,114 @@ function persistTurn(paths, bodySequence, result, completedAt) {
|
|
|
204
474
|
}
|
|
205
475
|
function defaultRuntime() {
|
|
206
476
|
return {
|
|
207
|
-
collar: currentProcessCollar(),
|
|
208
477
|
now: () => new Date().toISOString(),
|
|
209
|
-
|
|
210
|
-
spawnChild: async (launch) => await spawnAkumaBody(launch),
|
|
478
|
+
spawnChild: spawnAkumaBody,
|
|
211
479
|
};
|
|
212
480
|
}
|
|
213
|
-
function
|
|
214
|
-
|
|
481
|
+
async function prepareBodyStart(paths, leash) {
|
|
482
|
+
const before = await readHeart(paths);
|
|
483
|
+
if (before.pause !== null)
|
|
484
|
+
return false;
|
|
485
|
+
if (before.stop === null)
|
|
486
|
+
return true;
|
|
487
|
+
if (before.latestBody?.sequence === before.stop.bodySequence && before.latestBody.end === "put-down") {
|
|
488
|
+
await leash.settleStop(paths);
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
await leash.clearStop(paths);
|
|
492
|
+
}
|
|
493
|
+
return true;
|
|
215
494
|
}
|
|
216
|
-
async function
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
495
|
+
async function recoverBodyRequests(input) {
|
|
496
|
+
const { launch, soul, bodySequence, supervisor, runtime } = input;
|
|
497
|
+
try {
|
|
498
|
+
const result = await settleBodyRequests(launch.paths, soul, runtime.now, supervisor.signal);
|
|
499
|
+
await clearBodyRequestTransport(launch.paths);
|
|
500
|
+
if (result === "settled")
|
|
501
|
+
return true;
|
|
502
|
+
await breakBody(launch.paths, { sequence: bodySequence, end: "broke-off", at: runtime.now() });
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
if (!supervisor.signal.aborted)
|
|
506
|
+
throw error;
|
|
507
|
+
await clearBodyRequestTransport(launch.paths);
|
|
508
|
+
await putDownIfControlled(launch.paths, supervisor, bodySequence, runtime.now);
|
|
509
|
+
}
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
async function runBodyTurns(input) {
|
|
513
|
+
const { launch, soul, adapter, bodySequence, supervisor, runtime } = input;
|
|
514
|
+
let initial = launch.initialBody;
|
|
515
|
+
for (;;) {
|
|
516
|
+
const launchTells = supervisor.current().pending;
|
|
517
|
+
if (supervisor.signal.aborted) {
|
|
518
|
+
await putDownIfControlled(launch.paths, supervisor, bodySequence, runtime.now);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
if (initial === undefined && launchTells.length === 0) {
|
|
522
|
+
const finished = await finishBodyIfIdle(launch.paths, { sequence: bodySequence, at: runtime.now() });
|
|
523
|
+
if (finished.kind === "finished")
|
|
524
|
+
return;
|
|
525
|
+
if (finished.kind === "controlled") {
|
|
526
|
+
supervisor.cancel("control");
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const result = await driveTurn({
|
|
532
|
+
paths: launch.paths,
|
|
533
|
+
soul,
|
|
534
|
+
adapter,
|
|
535
|
+
bodySequence,
|
|
536
|
+
supervisor,
|
|
537
|
+
runtimeSpawn: runtime.spawnChild ?? spawnAkumaBody,
|
|
538
|
+
body: initial ?? "",
|
|
539
|
+
...(initial === undefined ? {} : { call: initial }),
|
|
540
|
+
launchTells,
|
|
541
|
+
now: runtime.now,
|
|
542
|
+
});
|
|
543
|
+
if (result.kind === "stopped") {
|
|
544
|
+
await putDownIfControlled(launch.paths, supervisor, bodySequence, runtime.now);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (result.kind === "handoff") {
|
|
548
|
+
await breakBody(launch.paths, { sequence: bodySequence, end: "put-down", at: runtime.now() });
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (result.kind === "resume-unsupported"
|
|
552
|
+
|| await persistTurn(launch.paths, result.turnSequence, result, runtime.now()) === "failed") {
|
|
553
|
+
await breakBody(launch.paths, { sequence: bodySequence, end: "broke-off", at: runtime.now() });
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
await supervisor.refresh();
|
|
557
|
+
initial = undefined;
|
|
558
|
+
}
|
|
224
559
|
}
|
|
225
560
|
export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()) {
|
|
226
561
|
const leash = await takeLeash(launch.paths);
|
|
227
562
|
if (leash === null)
|
|
228
563
|
return;
|
|
229
564
|
try {
|
|
230
|
-
const soul = bornSoul(launch, leash, runtime.now());
|
|
565
|
+
const soul = await bornSoul(launch, leash, runtime.now());
|
|
231
566
|
if (soul === null)
|
|
232
567
|
return;
|
|
233
|
-
const selected = adapter ??
|
|
234
|
-
|
|
235
|
-
if (body === null)
|
|
568
|
+
const selected = adapter ?? resolveProviderExecution(soul.provider).adapter;
|
|
569
|
+
if (!await prepareBodyStart(launch.paths, leash))
|
|
236
570
|
return;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (prompt === undefined) {
|
|
247
|
-
const finished = finishBodyIfIdle(launch.paths, { sequence: body.sequence, at: runtime.now() });
|
|
248
|
-
if (finished.kind === "finished")
|
|
249
|
-
return;
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
if (tell !== undefined)
|
|
253
|
-
advanceTell(launch.paths, tell.id, "delivered");
|
|
254
|
-
const result = await driveTurn({
|
|
255
|
-
paths: launch.paths,
|
|
256
|
-
soul,
|
|
257
|
-
adapter: selected,
|
|
258
|
-
bodySequence: body.sequence,
|
|
259
|
-
runtimeSpawn: childSpawner(runtime),
|
|
260
|
-
prompt,
|
|
261
|
-
...(tell === undefined ? {} : { tellId: tell.id }),
|
|
262
|
-
now: runtime.now,
|
|
263
|
-
});
|
|
264
|
-
if (result.kind === "heart-gone") {
|
|
265
|
-
await runtime.putDownOwnTree(runtime.collar);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
if (result.kind === "stopped") {
|
|
269
|
-
breakBody(launch.paths, { sequence: body.sequence, end: "put-down", at: runtime.now() });
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (persistTurn(launch.paths, body.sequence, result, runtime.now()) === "failed") {
|
|
273
|
-
breakBody(launch.paths, { sequence: body.sequence, end: "broke-off", at: runtime.now() });
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
initial = undefined;
|
|
571
|
+
const body = await leash.recordBody(launch.paths, { leashTakenAt: runtime.now() });
|
|
572
|
+
const supervisor = await BodySupervisor.open(launch.paths, body.sequence, leash);
|
|
573
|
+
const execution = { launch, soul, adapter: selected, bodySequence: body.sequence, supervisor, runtime };
|
|
574
|
+
try {
|
|
575
|
+
if (await recoverBodyRequests(execution))
|
|
576
|
+
await runBodyTurns(execution);
|
|
577
|
+
}
|
|
578
|
+
finally {
|
|
579
|
+
await supervisor.close();
|
|
277
580
|
}
|
|
278
581
|
}
|
|
279
582
|
catch (error) {
|
|
280
|
-
if (heartExists(launch.paths))
|
|
583
|
+
if (await heartExists(launch.paths))
|
|
281
584
|
throw error;
|
|
282
|
-
await runtime.putDownOwnTree(runtime.collar);
|
|
283
585
|
}
|
|
284
586
|
finally {
|
|
285
587
|
leash.release();
|
|
@@ -287,11 +589,16 @@ export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()
|
|
|
287
589
|
}
|
|
288
590
|
export async function spawnAkumaBody(launch) {
|
|
289
591
|
const encoded = Buffer.from(JSON.stringify(launch), "utf8").toString("base64url");
|
|
290
|
-
|
|
592
|
+
const actorId = launch.seed?.id ?? (await readHeart(launch.paths)).soul?.id;
|
|
593
|
+
if (actorId === undefined)
|
|
594
|
+
throw new Error("Akuma wake has no born soul");
|
|
595
|
+
const owned = await spawnDetachedProcess({
|
|
291
596
|
argv: [process.execPath, ...process.execArgv, fileURLToPath(import.meta.url), encoded],
|
|
292
|
-
cwd: launchCwd(launch),
|
|
597
|
+
cwd: await launchCwd(launch),
|
|
598
|
+
env: { ...process.env, KEIYAKU_ACTOR_ID: actorId },
|
|
293
599
|
log: launch.paths.log,
|
|
294
600
|
});
|
|
601
|
+
owned.release();
|
|
295
602
|
}
|
|
296
603
|
async function main() {
|
|
297
604
|
const encoded = process.argv[2];
|