@astrosheep/keiyaku 4.0.4 → 4.0.6
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/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +24 -4
- package/build/src/akuma/akuma.d.ts +2 -1
- package/build/src/akuma/akuma.js +27 -9
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +3 -10
- package/build/src/akuma/archetype.d.ts +3 -1
- package/build/src/akuma/archetype.js +11 -6
- package/build/src/akuma/body-turn.d.ts +64 -0
- package/build/src/akuma/body-turn.js +449 -0
- package/build/src/akuma/body.d.ts +4 -5
- package/build/src/akuma/body.js +9 -414
- package/build/src/akuma/heart/facts.d.ts +37 -9
- package/build/src/akuma/heart/facts.js +3 -1
- package/build/src/akuma/heart/index.d.ts +4 -13
- package/build/src/akuma/heart/index.js +14 -135
- package/build/src/akuma/heart/request-authority.d.ts +12 -0
- package/build/src/akuma/heart/request-authority.js +119 -0
- package/build/src/akuma/heart/request-rows.d.ts +16 -0
- package/build/src/akuma/heart/request-rows.js +88 -0
- package/build/src/akuma/heart/rows.d.ts +1 -28
- package/build/src/akuma/heart/rows.js +4 -138
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +11 -3
- package/build/src/akuma/heart/soul.js +0 -36
- package/build/src/akuma/heart/timeline.d.ts +1 -0
- package/build/src/akuma/heart/timeline.js +19 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/nuke.d.ts +2 -0
- package/build/src/akuma/nuke.js +152 -0
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +4 -7
- package/build/src/akuma/providers/acp/config.d.ts +8 -0
- package/build/src/akuma/providers/acp/config.js +37 -0
- package/build/src/akuma/providers/acp/core.js +12 -2
- package/build/src/akuma/providers/acp/index.d.ts +1 -8
- package/build/src/akuma/providers/acp/index.js +2 -38
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +12 -3
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +5 -2
- package/build/src/akuma/providers/grok-build/index.js +1 -2
- package/build/src/akuma/providers/index.d.ts +3 -2
- package/build/src/akuma/providers/index.js +36 -36
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +14 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +2 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +2 -2
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +29 -6
- package/build/src/akuma/request-serve.d.ts +88 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +125 -0
- package/build/src/akuma/request-wire.js +383 -0
- package/build/src/akuma/requests.d.ts +28 -94
- package/build/src/akuma/requests.js +52 -562
- package/build/src/akuma-body.d.ts +7 -0
- package/build/src/akuma-body.js +69 -2
- package/build/src/alias/index.d.ts +1 -0
- package/build/src/alias/index.js +34 -1
- package/build/src/body/arc.js +4 -29
- package/build/src/body/decode.js +5 -39
- package/build/src/body/envelope.d.ts +7 -0
- package/build/src/body/envelope.js +37 -0
- package/build/src/cli/accepted.js +21 -9
- package/build/src/cli/commands/akuma-invoke.js +1 -0
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +13 -10
- package/build/src/cli/commands/contract.d.ts +28 -17
- package/build/src/cli/commands/contract.js +23 -17
- package/build/src/cli/commands/install.d.ts +2 -2
- package/build/src/cli/commands/install.js +6 -6
- package/build/src/cli/commands/nuke.d.ts +10 -0
- package/build/src/cli/commands/nuke.js +20 -0
- package/build/src/cli/commands/task-invoke.d.ts +15 -0
- package/build/src/cli/commands/task-invoke.js +144 -24
- package/build/src/cli/commands/task-query.d.ts +2 -2
- package/build/src/cli/commands/task-query.js +1 -2
- package/build/src/cli/commands/task.js +22 -22
- package/build/src/cli/coordinates.d.ts +6 -2
- package/build/src/cli/coordinates.js +12 -56
- package/build/src/cli/invoke.d.ts +5 -4
- package/build/src/cli/invoke.js +112 -58
- package/build/src/cli/main.d.ts +0 -2
- package/build/src/cli/main.js +4 -140
- package/build/src/cli/parse.d.ts +17 -4
- package/build/src/cli/parse.js +93 -15
- package/build/src/cli/render/akuma.js +111 -53
- package/build/src/cli/render/audit.js +2 -6
- package/build/src/cli/render/contract.js +61 -20
- package/build/src/cli/render/kanshi.js +15 -5
- package/build/src/cli/render/nuke.d.ts +3 -0
- package/build/src/cli/render/nuke.js +8 -0
- package/build/src/cli/render/receipt.js +28 -1
- package/build/src/cli/render/refusal.d.ts +2 -1
- package/build/src/cli/render/refusal.js +31 -0
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/render/text.js +6 -1
- package/build/src/cli/result.d.ts +36 -9
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +140 -0
- package/build/src/cli/usage.d.ts +0 -2
- package/build/src/cli/usage.js +0 -4
- package/build/src/contract-worktree.d.ts +29 -14
- package/build/src/contract-worktree.js +131 -70
- package/build/src/core/facts/codec.js +9 -0
- package/build/src/core/facts/fold.js +13 -1
- package/build/src/core/facts/types.d.ts +8 -1
- package/build/src/core/subject.js +4 -3
- package/build/src/core/verbs/placement.d.ts +9 -1
- package/build/src/core/verbs/placement.js +24 -6
- package/build/src/core/verbs/reintegrate.d.ts +13 -0
- package/build/src/core/verbs/reintegrate.js +24 -0
- package/build/src/dispatch/index.d.ts +1 -1
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +2 -0
- package/build/src/git/hooks.js +34 -1
- package/build/src/git/integration.d.ts +9 -2
- package/build/src/git/integration.js +92 -1
- package/build/src/git/nuke.d.ts +2 -0
- package/build/src/git/nuke.js +97 -0
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +28 -0
- package/build/src/git/process.js +94 -0
- package/build/src/git/read-observation.d.ts +2 -1
- package/build/src/git/read-observation.js +3 -2
- package/build/src/git/reconcile.d.ts +4 -1
- package/build/src/git/reconcile.js +42 -8
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +7 -118
- package/build/src/git/scratch.d.ts +1 -1
- package/build/src/git/scratch.js +1 -1
- package/build/src/git/target-placement.d.ts +3 -2
- package/build/src/git/target-placement.js +15 -14
- package/build/src/git/tender.d.ts +2 -1
- package/build/src/git/tender.js +4 -3
- package/build/src/git/terminal-seal.d.ts +2 -2
- package/build/src/git/terminal-seal.js +3 -6
- package/build/src/git/workspace.d.ts +4 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/read.js +5 -1
- package/build/src/library/address.js +7 -1
- package/build/src/library/akuma-creation.d.ts +1 -0
- package/build/src/library/akuma-creation.js +8 -1
- package/build/src/library/audit.d.ts +3 -1
- package/build/src/library/audit.js +2 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +1 -1
- package/build/src/library/configuration.d.ts +1 -1
- package/build/src/library/configuration.js +52 -18
- package/build/src/library/contract.d.ts +59 -4
- package/build/src/library/contract.js +195 -34
- package/build/src/library/delivery.d.ts +4 -2
- package/build/src/library/fleet.d.ts +27 -7
- package/build/src/library/fleet.js +79 -39
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +0 -5
- package/build/src/library/keiyaku.d.ts +6 -2
- package/build/src/library/keiyaku.js +2 -0
- package/build/src/library/mutation.d.ts +3 -1
- package/build/src/library/mutation.js +3 -0
- package/build/src/library/nuke.d.ts +14 -0
- package/build/src/library/nuke.js +54 -0
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +8 -3
- package/build/src/library/refusal.d.ts +10 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +4 -1
- package/build/src/library/repo.js +10 -4
- package/build/src/protocol/abandon.d.ts +9 -0
- package/build/src/protocol/abandon.js +15 -0
- package/build/src/protocol/amend.d.ts +16 -0
- package/build/src/protocol/amend.js +77 -0
- package/build/src/protocol/arc.d.ts +6 -0
- package/build/src/protocol/arc.js +12 -0
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/audit.d.ts +53 -0
- package/build/src/protocol/audit.js +147 -0
- package/build/src/protocol/bind.d.ts +1 -1
- package/build/src/protocol/completion.d.ts +42 -0
- package/build/src/protocol/completion.js +183 -0
- package/build/src/protocol/deliver.d.ts +49 -0
- package/build/src/protocol/deliver.js +261 -0
- package/build/src/protocol/intent.d.ts +2 -1
- package/build/src/protocol/intent.js +8 -2
- package/build/src/protocol/operations.d.ts +93 -202
- package/build/src/protocol/operations.js +23 -642
- package/build/src/protocol/placement.d.ts +12 -13
- package/build/src/protocol/placement.js +8 -19
- package/build/src/protocol/read/status.d.ts +17 -5
- package/build/src/protocol/read/status.js +57 -13
- package/build/src/protocol/reconcile.d.ts +35 -0
- package/build/src/protocol/reconcile.js +41 -0
- package/build/src/protocol/reintegrate.d.ts +31 -0
- package/build/src/protocol/reintegrate.js +74 -0
- package/build/src/protocol/review.d.ts +34 -0
- package/build/src/protocol/review.js +156 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.js +9 -5
- package/build/src/settlement/fence.d.ts +3 -1
- package/build/src/settlement/fence.js +24 -0
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +1 -2
- package/build/src/task/board.d.ts +0 -1
- package/build/src/task/board.js +0 -3
- package/build/src/task/compose.d.ts +2 -2
- package/build/src/task/compose.js +13 -11
- package/build/src/task/context.d.ts +14 -2
- package/build/src/task/context.js +30 -7
- package/build/src/task/index.d.ts +7 -6
- package/build/src/task/index.js +17 -145
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +44 -0
- package/build/src/task/mutation.js +93 -0
- package/build/src/task/operations.d.ts +14 -6
- package/build/src/task/operations.js +57 -57
- package/build/src/task/store.d.ts +1 -0
- package/build/src/task/store.js +91 -3
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/workspace-place.d.ts +3 -4
- package/build/src/workspace-place.js +26 -15
- package/package.json +3 -3
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { access,
|
|
3
|
-
import { isAbsolute, join, resolve } from "node:path";
|
|
4
|
-
import { HeldAkumaLeash, admitRequest, readNonterminalRequests, readRequest, readSoul, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./heart/index.js";
|
|
5
|
-
import { parseAkuId, pathsForAkuId, archetypeName, worldRootForAkumaPaths, } from "./identity.js";
|
|
6
|
-
import { BIRTH_TIMEOUT_MS, publishAkuma } from "./publication.js";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
7
3
|
import { abortableDelay } from "./abort.js";
|
|
8
4
|
import { AKUMA_REQUESTS_ENV } from "./provider.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { decodeAllowedActions } from "./allowed.js";
|
|
5
|
+
import { absolute, atomicJson, decodeReceipt, receiptPath, requestPath, requestPayload, } from "./request-wire.js";
|
|
6
|
+
import { isTaskMutationAction } from "../task/mutation.js";
|
|
12
7
|
const POLL_MS = 25;
|
|
13
|
-
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
14
8
|
export class AkumaBodyRequestError extends Error {
|
|
15
9
|
outcome;
|
|
16
10
|
diagnostic;
|
|
@@ -22,268 +16,6 @@ export class AkumaBodyRequestError extends Error {
|
|
|
22
16
|
this.name = "AkumaBodyRequestError";
|
|
23
17
|
}
|
|
24
18
|
}
|
|
25
|
-
function diagnostic(error) {
|
|
26
|
-
return error instanceof Error ? error.message : String(error);
|
|
27
|
-
}
|
|
28
|
-
function object(value) {
|
|
29
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
30
|
-
? value
|
|
31
|
-
: null;
|
|
32
|
-
}
|
|
33
|
-
function exactKeys(value, expected) {
|
|
34
|
-
const actual = Object.keys(value).sort();
|
|
35
|
-
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
36
|
-
}
|
|
37
|
-
function absolute(value) {
|
|
38
|
-
return typeof value === "string" && isAbsolute(value) && resolve(value) === value;
|
|
39
|
-
}
|
|
40
|
-
function decodeRecipe(value, cwd) {
|
|
41
|
-
const recipe = object(value);
|
|
42
|
-
if (recipe === null)
|
|
43
|
-
return null;
|
|
44
|
-
const expectedKeys = [
|
|
45
|
-
...(recipe.description === undefined ? [] : ["description"]),
|
|
46
|
-
"allowed",
|
|
47
|
-
"options",
|
|
48
|
-
"provider",
|
|
49
|
-
...(recipe.readonly === undefined ? [] : ["readonly"]),
|
|
50
|
-
];
|
|
51
|
-
if (!exactKeys(recipe, expectedKeys))
|
|
52
|
-
return null;
|
|
53
|
-
if (recipe.description !== undefined
|
|
54
|
-
&& (typeof recipe.description !== "string" || recipe.description.trim().length === 0))
|
|
55
|
-
return null;
|
|
56
|
-
try {
|
|
57
|
-
const selected = resolveProviderExecution(recipe.provider);
|
|
58
|
-
const provider = selected.execution;
|
|
59
|
-
const adapter = selected.adapter;
|
|
60
|
-
const decodedOptions = decodeProviderOptions(recipe.options);
|
|
61
|
-
const readonly = recipe.readonly === undefined ? undefined : decodeReadonlyRestraint(recipe.readonly);
|
|
62
|
-
if ((decodedOptions.readonly === true) !== (readonly !== undefined))
|
|
63
|
-
return null;
|
|
64
|
-
const confinement = adapter.confinement({ cwd, options: decodedOptions });
|
|
65
|
-
return Object.freeze({
|
|
66
|
-
...(recipe.description === undefined ? {} : { description: recipe.description }),
|
|
67
|
-
allowed: decodeAllowedActions(recipe.allowed),
|
|
68
|
-
provider,
|
|
69
|
-
options: decodedOptions,
|
|
70
|
-
...(readonly === undefined ? {} : { readonly }),
|
|
71
|
-
confinement,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function canonicalAkuId(value) {
|
|
79
|
-
if (typeof value !== "string")
|
|
80
|
-
return null;
|
|
81
|
-
try {
|
|
82
|
-
const id = parseAkuId(value).id;
|
|
83
|
-
return id === value ? id : null;
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function canonicalTargets(value) {
|
|
90
|
-
if (!Array.isArray(value) || value.length === 0)
|
|
91
|
-
return null;
|
|
92
|
-
const ids = [];
|
|
93
|
-
for (const item of value) {
|
|
94
|
-
const id = canonicalAkuId(item);
|
|
95
|
-
if (id === null)
|
|
96
|
-
return null;
|
|
97
|
-
if (ids.length > 0 && Buffer.compare(Buffer.from(ids.at(-1)), Buffer.from(id)) >= 0)
|
|
98
|
-
return null;
|
|
99
|
-
ids.push(id);
|
|
100
|
-
}
|
|
101
|
-
return ids;
|
|
102
|
-
}
|
|
103
|
-
function decodeCallClaim(id, payload) {
|
|
104
|
-
const expected = [
|
|
105
|
-
"archetype",
|
|
106
|
-
"body",
|
|
107
|
-
...(payload.cwd === undefined ? [] : ["cwd"]),
|
|
108
|
-
"recipe",
|
|
109
|
-
"world",
|
|
110
|
-
];
|
|
111
|
-
if (!exactKeys(payload, expected)
|
|
112
|
-
|| typeof payload.body !== "string"
|
|
113
|
-
|| !absolute(payload.world))
|
|
114
|
-
return null;
|
|
115
|
-
if (payload.cwd !== undefined && !absolute(payload.cwd))
|
|
116
|
-
return null;
|
|
117
|
-
try {
|
|
118
|
-
archetypeName(payload.archetype);
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
id,
|
|
125
|
-
action: "akuma.call",
|
|
126
|
-
world: payload.world,
|
|
127
|
-
archetype: payload.archetype,
|
|
128
|
-
body: payload.body,
|
|
129
|
-
recipe: payload.recipe,
|
|
130
|
-
...(payload.cwd === undefined ? {} : { cwd: payload.cwd }),
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
function decodeWaitClaim(id, payload) {
|
|
134
|
-
const expected = [
|
|
135
|
-
"completion",
|
|
136
|
-
"targets",
|
|
137
|
-
...(payload.timeoutMs === undefined ? [] : ["timeoutMs"]),
|
|
138
|
-
];
|
|
139
|
-
const targets = canonicalTargets(payload.targets);
|
|
140
|
-
if (!exactKeys(payload, expected)
|
|
141
|
-
|| targets === null
|
|
142
|
-
|| (payload.completion !== "any" && payload.completion !== "all"))
|
|
143
|
-
return null;
|
|
144
|
-
if (payload.timeoutMs !== undefined
|
|
145
|
-
&& (!Number.isSafeInteger(payload.timeoutMs) || payload.timeoutMs < 0))
|
|
146
|
-
return null;
|
|
147
|
-
return {
|
|
148
|
-
id,
|
|
149
|
-
action: "akuma.wait",
|
|
150
|
-
targets,
|
|
151
|
-
completion: payload.completion,
|
|
152
|
-
...(payload.timeoutMs === undefined ? {} : { timeoutMs: payload.timeoutMs }),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
function decodeTellClaim(id, payload) {
|
|
156
|
-
const target = canonicalAkuId(payload.target);
|
|
157
|
-
if (!exactKeys(payload, ["body", "target"])
|
|
158
|
-
|| target === null
|
|
159
|
-
|| typeof payload.body !== "string")
|
|
160
|
-
return null;
|
|
161
|
-
return { id, action: "akuma.tell", target, body: payload.body };
|
|
162
|
-
}
|
|
163
|
-
function decodeKillClaim(id, payload) {
|
|
164
|
-
const targets = canonicalTargets(payload.targets);
|
|
165
|
-
return exactKeys(payload, ["targets"]) && targets !== null
|
|
166
|
-
? { id, action: "akuma.kill", targets }
|
|
167
|
-
: null;
|
|
168
|
-
}
|
|
169
|
-
function decodeClaim(bytes, fileId) {
|
|
170
|
-
let decoded;
|
|
171
|
-
try {
|
|
172
|
-
decoded = JSON.parse(bytes);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
const value = object(decoded);
|
|
178
|
-
if (value === null
|
|
179
|
-
|| !exactKeys(value, ["action", "id", "payload"])
|
|
180
|
-
|| value.id !== fileId
|
|
181
|
-
|| typeof value.id !== "string"
|
|
182
|
-
|| !UUID.test(value.id))
|
|
183
|
-
return null;
|
|
184
|
-
const payload = object(value.payload);
|
|
185
|
-
if (payload === null)
|
|
186
|
-
return null;
|
|
187
|
-
if (value.action === "akuma.call")
|
|
188
|
-
return decodeCallClaim(value.id, payload);
|
|
189
|
-
if (value.action === "akuma.wait")
|
|
190
|
-
return decodeWaitClaim(value.id, payload);
|
|
191
|
-
if (value.action === "akuma.tell")
|
|
192
|
-
return decodeTellClaim(value.id, payload);
|
|
193
|
-
if (value.action === "akuma.kill")
|
|
194
|
-
return decodeKillClaim(value.id, payload);
|
|
195
|
-
return null;
|
|
196
|
-
}
|
|
197
|
-
function decodeUpstreamFailure(value) {
|
|
198
|
-
const failure = object(value);
|
|
199
|
-
if (failure === null)
|
|
200
|
-
return null;
|
|
201
|
-
if (failure.kind === "akuma-not-born" && exactKeys(failure, ["id", "kind"])) {
|
|
202
|
-
const id = canonicalAkuId(failure.id);
|
|
203
|
-
return id === null ? null : { kind: failure.kind, id };
|
|
204
|
-
}
|
|
205
|
-
if (failure.kind === "failed"
|
|
206
|
-
&& exactKeys(failure, ["diagnostic", "kind"])
|
|
207
|
-
&& typeof failure.diagnostic === "string") {
|
|
208
|
-
return { kind: failure.kind, diagnostic: failure.diagnostic };
|
|
209
|
-
}
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
function decodeUpstreamOutcome(value) {
|
|
213
|
-
const outcome = object(value);
|
|
214
|
-
if (outcome?.kind === "returned" && exactKeys(outcome, ["kind", "result"])) {
|
|
215
|
-
return { kind: outcome.kind, result: outcome.result };
|
|
216
|
-
}
|
|
217
|
-
if (outcome?.kind !== "failed" || !exactKeys(outcome, ["failure", "kind"]))
|
|
218
|
-
return null;
|
|
219
|
-
const failure = decodeUpstreamFailure(outcome.failure);
|
|
220
|
-
return failure === null ? null : { kind: outcome.kind, failure };
|
|
221
|
-
}
|
|
222
|
-
function decodeReceipt(bytes, requestId, action) {
|
|
223
|
-
let decoded;
|
|
224
|
-
try {
|
|
225
|
-
decoded = JSON.parse(bytes);
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
const value = object(decoded);
|
|
231
|
-
if (value === null || value.id !== requestId || value.action !== action)
|
|
232
|
-
return null;
|
|
233
|
-
if (action === "akuma.call"
|
|
234
|
-
&& value.state === "served"
|
|
235
|
-
&& exactKeys(value, ["action", "child", "id", "state"])) {
|
|
236
|
-
const child = canonicalAkuId(value.child);
|
|
237
|
-
return child === null ? null : { id: requestId, action, state: value.state, child };
|
|
238
|
-
}
|
|
239
|
-
if (action !== "akuma.call"
|
|
240
|
-
&& value.state === "served"
|
|
241
|
-
&& exactKeys(value, ["action", "id", "outcome", "state"])) {
|
|
242
|
-
const outcome = decodeUpstreamOutcome(value.outcome);
|
|
243
|
-
return outcome === null ? null : { id: requestId, action, state: value.state, outcome };
|
|
244
|
-
}
|
|
245
|
-
if (value.state === "refused"
|
|
246
|
-
&& exactKeys(value, ["action", "diagnostic", "id", "state"])
|
|
247
|
-
&& typeof value.diagnostic === "string") {
|
|
248
|
-
return { id: requestId, action, state: value.state, diagnostic: value.diagnostic };
|
|
249
|
-
}
|
|
250
|
-
if (value.state === "voided"
|
|
251
|
-
&& exactKeys(value, ["action", "evidence", "id", "state"])
|
|
252
|
-
&& typeof value.evidence === "string") {
|
|
253
|
-
return { id: requestId, action, state: value.state, evidence: value.evidence };
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
async function atomicJson(path, value) {
|
|
258
|
-
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
259
|
-
try {
|
|
260
|
-
await writeFile(temporary, `${JSON.stringify(value)}\n`, { flag: "wx" });
|
|
261
|
-
await rename(temporary, path);
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
await rm(temporary, { force: true });
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function receiptFor(fact) {
|
|
268
|
-
if (fact.action === "akuma.call" && fact.state === "served") {
|
|
269
|
-
return { id: fact.id, action: fact.action, state: fact.state, child: fact.child };
|
|
270
|
-
}
|
|
271
|
-
if (fact.state === "refused") {
|
|
272
|
-
return { id: fact.id, action: fact.action, state: fact.state, diagnostic: fact.diagnostic };
|
|
273
|
-
}
|
|
274
|
-
if (fact.state === "voided")
|
|
275
|
-
return { id: fact.id, action: fact.action, state: fact.state, evidence: fact.evidence };
|
|
276
|
-
return null;
|
|
277
|
-
}
|
|
278
|
-
async function projectReceipt(directory, fact, outcome) {
|
|
279
|
-
const receipt = outcome === undefined
|
|
280
|
-
? receiptFor(fact)
|
|
281
|
-
: fact.action === "akuma.call" || fact.state !== "served"
|
|
282
|
-
? null
|
|
283
|
-
: { id: fact.id, action: fact.action, state: fact.state, outcome };
|
|
284
|
-
if (receipt !== null)
|
|
285
|
-
await atomicJson(join(directory, `${fact.id}.receipt.json`), receipt);
|
|
286
|
-
}
|
|
287
19
|
export function injectedBodyRequests() {
|
|
288
20
|
const directory = process.env[AKUMA_REQUESTS_ENV];
|
|
289
21
|
if (directory === undefined)
|
|
@@ -293,14 +25,18 @@ export function injectedBodyRequests() {
|
|
|
293
25
|
return directory;
|
|
294
26
|
}
|
|
295
27
|
async function requestBody(input) {
|
|
296
|
-
|
|
297
|
-
await atomicJson(
|
|
298
|
-
|
|
28
|
+
input.signal?.throwIfAborted();
|
|
29
|
+
await atomicJson(requestPath(input.directory, input.claim.id), {
|
|
30
|
+
id: input.claim.id,
|
|
31
|
+
action: input.claim.action,
|
|
32
|
+
payload: requestPayload(input.claim),
|
|
33
|
+
});
|
|
34
|
+
const path = receiptPath(input.directory, input.claim.id);
|
|
299
35
|
for (;;) {
|
|
300
36
|
try {
|
|
301
|
-
const receipt = decodeReceipt(await readFile(
|
|
37
|
+
const receipt = decodeReceipt(await readFile(path, "utf8"), input.claim.id, input.claim.action);
|
|
302
38
|
if (receipt === null)
|
|
303
|
-
throw new Error(`Akuma body request ${id} has an invalid receipt`);
|
|
39
|
+
throw new Error(`Akuma body request ${input.claim.id} has an invalid receipt`);
|
|
304
40
|
if (receipt.state === "refused")
|
|
305
41
|
throw new AkumaBodyRequestError("refused", receipt.diagnostic);
|
|
306
42
|
if (receipt.state === "voided")
|
|
@@ -314,7 +50,7 @@ async function requestBody(input) {
|
|
|
314
50
|
if (!await access(input.directory).then(() => true, () => false)) {
|
|
315
51
|
throw new AkumaBodyRequestError("voided", "parent request channel closed before a receipt");
|
|
316
52
|
}
|
|
317
|
-
await abortableDelay(POLL_MS);
|
|
53
|
+
await abortableDelay(POLL_MS, input.signal);
|
|
318
54
|
}
|
|
319
55
|
}
|
|
320
56
|
export async function requestBodyCall(input) {
|
|
@@ -325,13 +61,30 @@ export async function requestBodyCall(input) {
|
|
|
325
61
|
}
|
|
326
62
|
return receipt.child;
|
|
327
63
|
}
|
|
328
|
-
async function requestUpstream(directory, claim) {
|
|
329
|
-
const receipt = await requestBody({ directory, claim });
|
|
330
|
-
if (receipt.action === "akuma.call" || receipt.state !== "served") {
|
|
64
|
+
async function requestUpstream(directory, claim, signal) {
|
|
65
|
+
const receipt = await requestBody({ directory, claim, ...(signal === undefined ? {} : { signal }) });
|
|
66
|
+
if (receipt.action === "akuma.call" || receipt.state !== "served" || !("outcome" in receipt)) {
|
|
331
67
|
throw new Error(`Akuma body request ${claim.id} returned the wrong action`);
|
|
332
68
|
}
|
|
333
69
|
return receipt.outcome;
|
|
334
70
|
}
|
|
71
|
+
export async function requestBodyTask(input) {
|
|
72
|
+
const id = input.id ?? randomUUID();
|
|
73
|
+
const receipt = await requestBody({
|
|
74
|
+
directory: input.directory,
|
|
75
|
+
claim: { id, action: input.request.action, world: input.world, request: input.request },
|
|
76
|
+
});
|
|
77
|
+
if (!isTaskMutationAction(receipt.action) || receipt.action !== input.request.action || receipt.state !== "served") {
|
|
78
|
+
throw new Error(`Akuma body request ${id} returned the wrong action`);
|
|
79
|
+
}
|
|
80
|
+
if ("reference" in receipt)
|
|
81
|
+
return receipt.reference;
|
|
82
|
+
if (receipt.outcome.kind === "returned")
|
|
83
|
+
return receipt.outcome.result;
|
|
84
|
+
throw new Error(receipt.outcome.failure.kind === "failed"
|
|
85
|
+
? receipt.outcome.failure.diagnostic
|
|
86
|
+
: "Akuma body request parent is not born");
|
|
87
|
+
}
|
|
335
88
|
export async function requestBodyWait(input) {
|
|
336
89
|
const { directory, id = randomUUID(), ...claim } = input;
|
|
337
90
|
return await requestUpstream(directory, { ...claim, id, action: "akuma.wait" });
|
|
@@ -344,286 +97,23 @@ export async function requestBodyKill(input) {
|
|
|
344
97
|
const { directory, id = randomUUID(), ...claim } = input;
|
|
345
98
|
return await requestUpstream(directory, { ...claim, id, action: "akuma.kill" });
|
|
346
99
|
}
|
|
347
|
-
async function
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
fact = await refuseRequest(input.paths, request.id, `request world ${request.world} does not match ${servingWorld}`);
|
|
367
|
-
await projectReceipt(input.directory, fact);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
let child;
|
|
371
|
-
try {
|
|
372
|
-
input.signal.throwIfAborted();
|
|
373
|
-
const published = await publishAkuma({
|
|
374
|
-
worldPath: servingWorld,
|
|
375
|
-
archetype: request.archetype,
|
|
376
|
-
reserve: async (allocated) => { fact = await reserveRequest(input.paths, request.id, allocated.id); },
|
|
377
|
-
signal: input.signal,
|
|
378
|
-
launch: async (allocated) => await input.spawn({
|
|
379
|
-
paths: allocated.paths,
|
|
380
|
-
seed: {
|
|
381
|
-
id: allocated.id,
|
|
382
|
-
archetype: allocated.archetype,
|
|
383
|
-
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
384
|
-
provider: request.recipe.provider,
|
|
385
|
-
options: request.recipe.options,
|
|
386
|
-
...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
|
|
387
|
-
allowed: request.recipe.allowed,
|
|
388
|
-
cwd,
|
|
389
|
-
origin: { kind: "request", parent: input.parent.id, requestId: request.id },
|
|
390
|
-
confinement: request.recipe.confinement,
|
|
391
|
-
},
|
|
392
|
-
initialBody: request.body,
|
|
393
|
-
}),
|
|
394
|
-
});
|
|
395
|
-
child = published.id;
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
if (input.signal.aborted)
|
|
399
|
-
return;
|
|
400
|
-
const current = await readRequest(input.paths, request.id);
|
|
401
|
-
if (current === null)
|
|
402
|
-
throw error;
|
|
403
|
-
fact = current.state === "admitted" || current.state === "reserved"
|
|
404
|
-
? await voidRequest(input.paths, request.id, diagnostic(error))
|
|
405
|
-
: current;
|
|
406
|
-
await projectReceipt(input.directory, fact);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
fact = await serveRequest(input.paths, request.id, child);
|
|
410
|
-
await projectReceipt(input.directory, fact);
|
|
411
|
-
}
|
|
412
|
-
function upstreamFailure(error) {
|
|
413
|
-
const value = object(error);
|
|
414
|
-
if (value?.kind === "akuma-not-born") {
|
|
415
|
-
const id = canonicalAkuId(value.id);
|
|
416
|
-
if (id !== null)
|
|
417
|
-
return { kind: "akuma-not-born", id };
|
|
418
|
-
}
|
|
419
|
-
return { kind: "failed", diagnostic: diagnostic(error) };
|
|
420
|
-
}
|
|
421
|
-
async function serveUpstreamClaim(input) {
|
|
422
|
-
input.signal.throwIfAborted();
|
|
423
|
-
let fact = await admitRequest(input.paths, { ...input.claim, admittedAt: input.now() });
|
|
424
|
-
const existing = receiptFor(fact);
|
|
425
|
-
if (existing !== null) {
|
|
426
|
-
if (!input.signal.aborted)
|
|
427
|
-
await projectReceipt(input.directory, fact);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (fact.state === "served") {
|
|
431
|
-
await projectReceipt(input.directory, fact, {
|
|
432
|
-
kind: "failed",
|
|
433
|
-
failure: { kind: "failed", diagnostic: "served request receipt is no longer available" },
|
|
434
|
-
});
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
if (fact.state !== "admitted" || fact.action === "akuma.call") {
|
|
438
|
-
throw new Error(`Akuma request ${fact.id} cannot be served from ${fact.state}`);
|
|
439
|
-
}
|
|
440
|
-
const request = fact;
|
|
441
|
-
let outcome;
|
|
442
|
-
let killService = [];
|
|
443
|
-
try {
|
|
444
|
-
if (input.upstream === undefined)
|
|
445
|
-
throw new Error("upstream execution port is unavailable");
|
|
446
|
-
let result;
|
|
447
|
-
if (request.action === "akuma.wait") {
|
|
448
|
-
const waitRequest = request;
|
|
449
|
-
result = await input.upstream.wait({
|
|
450
|
-
targets: waitRequest.targets,
|
|
451
|
-
completion: waitRequest.completion,
|
|
452
|
-
...(waitRequest.timeoutMs === undefined ? {} : { timeoutMs: waitRequest.timeoutMs }),
|
|
453
|
-
signal: input.signal,
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
else if (request.action === "akuma.tell") {
|
|
457
|
-
const tellRequest = request;
|
|
458
|
-
result = await input.upstream.tell({
|
|
459
|
-
target: tellRequest.target,
|
|
460
|
-
body: tellRequest.body,
|
|
461
|
-
tellId: tellRequest.id,
|
|
462
|
-
recordedAt: tellRequest.admittedAt,
|
|
463
|
-
signal: input.signal,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
const killRequest = request;
|
|
468
|
-
const served = await input.upstream.kill({ targets: killRequest.targets, signal: input.signal });
|
|
469
|
-
killService = served.service;
|
|
470
|
-
result = served.result;
|
|
471
|
-
}
|
|
472
|
-
outcome = { kind: "returned", result };
|
|
473
|
-
}
|
|
474
|
-
catch (error) {
|
|
475
|
-
if (input.signal.aborted)
|
|
476
|
-
return;
|
|
477
|
-
outcome = { kind: "failed", failure: upstreamFailure(error) };
|
|
478
|
-
}
|
|
479
|
-
input.signal.throwIfAborted();
|
|
480
|
-
const service = request.action === "akuma.wait"
|
|
481
|
-
? { action: request.action }
|
|
482
|
-
: request.action === "akuma.tell"
|
|
483
|
-
? { action: request.action, target: request.target, tellId: request.id }
|
|
484
|
-
: { action: request.action, results: killService };
|
|
485
|
-
fact = await serveUpstreamRequest(input.paths, request.id, service);
|
|
486
|
-
await projectReceipt(input.directory, fact, outcome);
|
|
487
|
-
}
|
|
488
|
-
async function serveClaim(input) {
|
|
489
|
-
return input.claim.action === "akuma.call"
|
|
490
|
-
? await serveCallClaim({ ...input, claim: input.claim })
|
|
491
|
-
: await serveUpstreamClaim({ ...input, claim: input.claim });
|
|
492
|
-
}
|
|
493
|
-
async function requestFiles(directory) {
|
|
494
|
-
try {
|
|
495
|
-
return (await readdir(directory))
|
|
496
|
-
.filter((name) => name.endsWith(".request.json"))
|
|
497
|
-
.sort();
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
if (error.code === "ENOENT")
|
|
501
|
-
return [];
|
|
502
|
-
throw error;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
export class BodyRequestPump {
|
|
506
|
-
input;
|
|
507
|
-
directory;
|
|
508
|
-
failure;
|
|
509
|
-
closeSignal = new AbortController();
|
|
510
|
-
handled = new Set();
|
|
511
|
-
running;
|
|
512
|
-
cancelAdmission;
|
|
513
|
-
constructor(input) {
|
|
514
|
-
this.input = input;
|
|
515
|
-
this.directory = join(input.paths.directory, "requests", String(input.bodySequence));
|
|
516
|
-
this.cancelAdmission = () => this.stopAdmission();
|
|
517
|
-
input.signal.addEventListener("abort", this.cancelAdmission, { once: true });
|
|
518
|
-
if (input.signal.aborted)
|
|
519
|
-
this.cancelAdmission();
|
|
520
|
-
this.running = this.run();
|
|
521
|
-
this.failure = this.running.then(() => new Promise(() => { }), (error) => Promise.reject(error));
|
|
522
|
-
}
|
|
523
|
-
static async open(input) {
|
|
524
|
-
const directory = join(input.paths.directory, "requests", String(input.bodySequence));
|
|
525
|
-
await mkdir(directory, { recursive: true });
|
|
526
|
-
return new BodyRequestPump(input);
|
|
527
|
-
}
|
|
528
|
-
async run() {
|
|
529
|
-
while (!this.closeSignal.signal.aborted) {
|
|
530
|
-
for (const name of await requestFiles(this.directory)) {
|
|
531
|
-
if (this.closeSignal.signal.aborted)
|
|
532
|
-
return;
|
|
533
|
-
const id = name.slice(0, -".request.json".length);
|
|
534
|
-
if (this.handled.has(id))
|
|
535
|
-
continue;
|
|
536
|
-
const claim = decodeClaim(await readFile(join(this.directory, name), "utf8"), id);
|
|
537
|
-
if (claim === null) {
|
|
538
|
-
this.handled.add(id);
|
|
539
|
-
continue;
|
|
540
|
-
}
|
|
541
|
-
await serveClaim({ directory: this.directory, claim, ...this.input, signal: this.closeSignal.signal });
|
|
542
|
-
this.handled.add(id);
|
|
543
|
-
}
|
|
544
|
-
try {
|
|
545
|
-
await abortableDelay(POLL_MS, this.closeSignal.signal);
|
|
546
|
-
}
|
|
547
|
-
catch {
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
async close() {
|
|
553
|
-
this.stopAdmission();
|
|
554
|
-
try {
|
|
555
|
-
await this.running;
|
|
556
|
-
}
|
|
557
|
-
finally {
|
|
558
|
-
this.input.signal.removeEventListener("abort", this.cancelAdmission);
|
|
559
|
-
await rm(this.directory, { recursive: true, force: true });
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
stopAdmission() {
|
|
563
|
-
if (!this.closeSignal.signal.aborted)
|
|
564
|
-
this.closeSignal.abort(new Error("Body request pump closed"));
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
export async function clearBodyRequestTransport(paths) {
|
|
568
|
-
await rm(join(paths.directory, "requests"), { recursive: true, force: true });
|
|
569
|
-
}
|
|
570
|
-
function matchingRequestOrigin(soul, parent, requestId) {
|
|
571
|
-
return soul.origin.kind === "request"
|
|
572
|
-
&& soul.origin.parent === parent
|
|
573
|
-
&& soul.origin.requestId === requestId;
|
|
574
|
-
}
|
|
575
|
-
async function settleObservedSoul(paths, parent, request, soul) {
|
|
576
|
-
if (matchingRequestOrigin(soul, parent.id, request.id))
|
|
577
|
-
await serveRequest(paths, request.id, request.child);
|
|
578
|
-
else
|
|
579
|
-
await voidRequest(paths, request.id, "reserved child origin does not match the request");
|
|
580
|
-
}
|
|
581
|
-
async function settleReserved(paths, parent, request, now, signal) {
|
|
582
|
-
const childPaths = pathsForAkuId(request.world, request.child);
|
|
583
|
-
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
584
|
-
for (;;) {
|
|
585
|
-
signal?.throwIfAborted();
|
|
586
|
-
if (!await access(childPaths.directory).then(() => true, () => false)) {
|
|
587
|
-
await voidRequest(paths, request.id, "reserved child directory is absent");
|
|
588
|
-
return true;
|
|
589
|
-
}
|
|
590
|
-
const childSoul = await readSoul(childPaths);
|
|
591
|
-
if (childSoul !== null) {
|
|
592
|
-
await settleObservedSoul(paths, parent, request, childSoul);
|
|
593
|
-
return true;
|
|
594
|
-
}
|
|
595
|
-
const leash = await HeldAkumaLeash.try(childPaths);
|
|
596
|
-
if (leash !== null) {
|
|
597
|
-
try {
|
|
598
|
-
const settledSoul = await readSoul(childPaths);
|
|
599
|
-
if (settledSoul !== null) {
|
|
600
|
-
await settleObservedSoul(paths, parent, request, settledSoul);
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
604
|
-
await voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
finally {
|
|
608
|
-
leash.release();
|
|
609
|
-
}
|
|
610
|
-
return true;
|
|
611
|
-
}
|
|
612
|
-
if (performance.now() >= deadline)
|
|
613
|
-
return false;
|
|
614
|
-
await abortableDelay(POLL_MS, signal);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
export async function settleBodyRequests(paths, parent, now, signal) {
|
|
618
|
-
let pending = false;
|
|
619
|
-
for (const request of await readNonterminalRequests(paths)) {
|
|
620
|
-
signal?.throwIfAborted();
|
|
621
|
-
if (request.state === "admitted") {
|
|
622
|
-
await voidRequest(paths, request.id, "body died before serving the request");
|
|
623
|
-
}
|
|
624
|
-
else if (request.state === "reserved"
|
|
625
|
-
&& !await settleReserved(paths, parent, request, now, signal))
|
|
626
|
-
pending = true;
|
|
627
|
-
}
|
|
628
|
-
return pending ? "pending" : "settled";
|
|
100
|
+
async function requestContract(input, action) {
|
|
101
|
+
const { directory, id = randomUUID(), signal, ...claim } = input;
|
|
102
|
+
const receipt = await requestBody({
|
|
103
|
+
directory,
|
|
104
|
+
claim: { ...claim, id, action },
|
|
105
|
+
...(signal === undefined ? {} : { signal }),
|
|
106
|
+
});
|
|
107
|
+
if (receipt.action !== action || receipt.state !== "served") {
|
|
108
|
+
throw new Error(`Akuma body request ${id} returned the wrong action`);
|
|
109
|
+
}
|
|
110
|
+
return "reference" in receipt
|
|
111
|
+
? receipt.reference
|
|
112
|
+
: receipt.outcome;
|
|
113
|
+
}
|
|
114
|
+
export async function requestBodyDeliver(input) {
|
|
115
|
+
return await requestContract(input, "contract.deliver");
|
|
116
|
+
}
|
|
117
|
+
export async function requestBodyReview(input) {
|
|
118
|
+
return await requestContract(input, "contract.review");
|
|
629
119
|
}
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
import { type BodyLaunch } from "./akuma/body.js";
|
|
2
|
+
import type { UpstreamExecutionPort } from "./akuma/request-serve.js";
|
|
3
|
+
type BodyProcessConfiguration = Readonly<{
|
|
4
|
+
home?: string;
|
|
5
|
+
gitPath?: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function upstreamFor(launch: BodyLaunch, processConfiguration: BodyProcessConfiguration): UpstreamExecutionPort;
|
|
1
8
|
export {};
|