@astrosheep/keiyaku 4.0.1 → 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 +137 -5
- 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 +3 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
- package/build/src/akuma/abort.d.ts +2 -0
- package/build/src/akuma/abort.js +50 -0
- package/build/src/akuma/akuma.d.ts +23 -14
- package/build/src/akuma/akuma.js +120 -104
- package/build/src/akuma/archetype.d.ts +7 -6
- package/build/src/akuma/archetype.js +68 -41
- package/build/src/akuma/body.d.ts +3 -5
- package/build/src/akuma/body.js +408 -213
- package/build/src/akuma/heart/facts.d.ts +25 -34
- package/build/src/akuma/heart/facts.js +18 -7
- package/build/src/akuma/heart/index.d.ts +39 -42
- package/build/src/akuma/heart/index.js +134 -93
- package/build/src/akuma/heart/rows.d.ts +9 -31
- package/build/src/akuma/heart/rows.js +26 -44
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +7 -15
- 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 +28 -14
- package/build/src/akuma/heart/storage.js +86 -26
- package/build/src/akuma/identity.d.ts +2 -2
- package/build/src/akuma/identity.js +9 -9
- package/build/src/akuma/index.d.ts +6 -1
- package/build/src/akuma/index.js +6 -0
- package/build/src/akuma/projection.d.ts +117 -38
- package/build/src/akuma/projection.js +208 -97
- 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 +12 -4
- package/build/src/akuma/provider.js +117 -70
- 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/events.js +66 -13
- package/build/src/akuma/providers/claude/index.d.ts +2 -1
- package/build/src/akuma/providers/claude/index.js +35 -21
- package/build/src/akuma/providers/codex-app-server/events.js +4 -1
- package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
- package/build/src/akuma/providers/codex-app-server/index.js +24 -31
- 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 +24 -59
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
- package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
- package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
- package/build/src/akuma/providers/pi/events.js +49 -11
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +50 -21
- 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 -7
- package/build/src/akuma/requests.js +92 -65
- package/build/src/alias/index.d.ts +2 -2
- package/build/src/alias/index.js +10 -10
- 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/cli/accepted.d.ts +17 -13
- package/build/src/cli/accepted.js +72 -34
- package/build/src/cli/actor.js +3 -3
- package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
- package/build/src/cli/commands/akuma-invoke.js +14 -9
- package/build/src/cli/commands/akuma.d.ts +13 -3
- package/build/src/cli/commands/akuma.js +67 -34
- package/build/src/cli/commands/contract.d.ts +18 -5
- package/build/src/cli/commands/contract.js +9 -3
- package/build/src/cli/commands/task-invoke.d.ts +17 -4
- package/build/src/cli/commands/task-invoke.js +43 -20
- 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 +51 -13
- 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 +4 -3
- package/build/src/cli/invoke.js +160 -179
- package/build/src/cli/main.js +34 -6
- package/build/src/cli/parse.d.ts +9 -2
- package/build/src/cli/parse.js +29 -7
- 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 +2 -2
- package/build/src/cli/render/akuma-tool.js +30 -4
- package/build/src/cli/render/akuma.d.ts +1 -0
- package/build/src/cli/render/akuma.js +211 -116
- package/build/src/cli/render/audit.d.ts +3 -0
- package/build/src/cli/render/audit.js +104 -0
- package/build/src/cli/render/contract.d.ts +3 -3
- package/build/src/cli/render/contract.js +192 -79
- package/build/src/cli/render/kanshi.js +263 -168
- 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 -20
- 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 +7 -0
- package/build/src/cli/render/terminal.js +46 -0
- package/build/src/cli/render/text.js +6 -3
- package/build/src/cli/result.d.ts +115 -20
- package/build/src/cli/usage.d.ts +1 -0
- package/build/src/cli/usage.js +3 -0
- package/build/src/contract-worktree.d.ts +6 -5
- package/build/src/contract-worktree.js +95 -57
- package/build/src/coordination/durable-file.d.ts +4 -3
- package/build/src/coordination/durable-file.js +29 -25
- 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/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/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +0 -11
- package/build/src/core/verbs/deliver.d.ts +1 -1
- package/build/src/core/verbs/deliver.js +1 -7
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +4 -1
- package/build/src/dispatch/index.d.ts +2 -2
- package/build/src/dispatch/index.js +17 -17
- package/build/src/git/admission.d.ts +1 -1
- package/build/src/git/admission.js +11 -11
- package/build/src/git/hooks.js +13 -13
- package/build/src/git/integration.d.ts +14 -15
- package/build/src/git/integration.js +80 -44
- package/build/src/git/observe.d.ts +5 -3
- package/build/src/git/observe.js +18 -12
- package/build/src/git/read-observation.js +9 -9
- package/build/src/git/reconcile.d.ts +2 -0
- package/build/src/git/reconcile.js +138 -95
- package/build/src/git/repository.d.ts +27 -19
- package/build/src/git/repository.js +155 -83
- package/build/src/git/scratch.d.ts +7 -3
- package/build/src/git/scratch.js +44 -37
- package/build/src/git/target-placement.d.ts +40 -4
- package/build/src/git/target-placement.js +221 -101
- package/build/src/git/tender.d.ts +6 -5
- package/build/src/git/tender.js +24 -43
- package/build/src/git/terminal-seal.d.ts +1 -1
- package/build/src/git/terminal-seal.js +7 -5
- package/build/src/git/workspace.d.ts +36 -4
- package/build/src/git/workspace.js +53 -18
- package/build/src/identity/selector.js +1 -1
- package/build/src/index.d.ts +3 -3
- package/build/src/index.js +1 -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 +2 -1
- package/build/src/kanshi/read.js +118 -27
- package/build/src/kanshi/report.d.ts +50 -0
- package/build/src/kanshi/select.d.ts +5 -0
- package/build/src/kanshi/select.js +32 -0
- package/build/src/library/address.d.ts +12 -3
- package/build/src/library/address.js +77 -46
- package/build/src/library/akuma-creation.d.ts +6 -1
- package/build/src/library/akuma-creation.js +86 -13
- package/build/src/library/audit.d.ts +18 -0
- package/build/src/library/audit.js +44 -0
- package/build/src/library/bind.js +4 -4
- package/build/src/library/catalog.d.ts +1 -1
- package/build/src/library/catalog.js +5 -8
- package/build/src/library/contract.d.ts +5 -6
- package/build/src/library/contract.js +11 -35
- package/build/src/library/delivery.d.ts +2 -1
- package/build/src/library/fleet.d.ts +2 -2
- package/build/src/library/fleet.js +35 -71
- package/build/src/library/keiyaku.d.ts +3 -2
- package/build/src/library/keiyaku.js +1 -0
- package/build/src/library/mutation.d.ts +7 -6
- package/build/src/library/mutation.js +23 -25
- package/build/src/library/reconcile.d.ts +29 -0
- package/build/src/library/reconcile.js +179 -0
- package/build/src/library/region.d.ts +12 -0
- package/build/src/library/region.js +15 -1
- package/build/src/library/repo.d.ts +4 -16
- package/build/src/library/repo.js +13 -38
- package/build/src/protocol/attempt.js +6 -6
- package/build/src/protocol/bind.js +4 -4
- package/build/src/protocol/intent.d.ts +15 -2
- package/build/src/protocol/intent.js +21 -6
- package/build/src/protocol/operations.d.ts +73 -22
- package/build/src/protocol/operations.js +292 -88
- package/build/src/protocol/outcome.d.ts +9 -3
- package/build/src/protocol/outcome.js +3 -1
- package/build/src/protocol/placement.d.ts +15 -4
- package/build/src/protocol/placement.js +58 -25
- package/build/src/protocol/read/status.d.ts +8 -1
- package/build/src/protocol/read/status.js +61 -14
- package/build/src/runtime/proc/line-rpc.d.ts +3 -8
- package/build/src/runtime/proc/line-rpc.js +16 -43
- package/build/src/runtime/proc/run.d.ts +15 -29
- package/build/src/runtime/proc/run.js +113 -105
- 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 +2 -2
- package/build/src/settings.js +8 -8
- package/build/src/settlement/fence.d.ts +0 -4
- package/build/src/settlement/fence.js +0 -9
- package/build/src/settlement/holder.d.ts +11 -1
- package/build/src/settlement/holder.js +25 -0
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +52 -89
- package/build/src/task/board.d.ts +3 -3
- package/build/src/task/board.js +6 -9
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +18 -10
- package/build/src/task/context.d.ts +3 -3
- package/build/src/task/context.js +14 -14
- package/build/src/task/document.d.ts +2 -1
- package/build/src/task/document.js +15 -5
- package/build/src/task/index.d.ts +19 -7
- package/build/src/task/index.js +42 -23
- package/build/src/task/operations.d.ts +15 -9
- package/build/src/task/operations.js +78 -48
- package/build/src/task/query.d.ts +67 -0
- package/build/src/task/query.js +279 -0
- package/build/src/task/store.d.ts +2 -2
- package/build/src/task/store.js +40 -25
- package/build/src/verification/execution.d.ts +4 -2
- package/build/src/verification/execution.js +9 -5
- package/build/src/workspace-place.d.ts +41 -0
- package/build/src/workspace-place.js +386 -0
- package/build/src/world.d.ts +13 -2
- package/build/src/world.js +81 -48
- package/package.json +3 -2
- package/build/src/protocol/read/audit.d.ts +0 -31
- package/build/src/protocol/read/audit.js +0 -55
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { access, mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { HeldAkumaLeash, admitRequest, readNonterminalRequests, readRequest, readSoul, refuseRequest, reserveRequest, serveRequest, voidRequest, } from "./heart/index.js";
|
|
5
5
|
import { parseAkuId, pathsForAkuId, archetypeName, worldRootForAkumaPaths, } from "./identity.js";
|
|
6
6
|
import { BIRTH_TIMEOUT_MS, publishAkuma } from "./publication.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { abortableDelay } from "./abort.js";
|
|
8
|
+
import { AKUMA_REQUESTS_ENV } from "./provider.js";
|
|
9
|
+
import { decodeProviderOptions, decodeReadonlyRestraint } from "./provider-recipe.js";
|
|
10
|
+
import { resolveProviderExecution } from "./providers/index.js";
|
|
9
11
|
const POLL_MS = 25;
|
|
10
12
|
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;
|
|
11
13
|
export class AkumaBodyRequestError extends Error {
|
|
@@ -19,9 +21,6 @@ export class AkumaBodyRequestError extends Error {
|
|
|
19
21
|
this.name = "AkumaBodyRequestError";
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
|
-
function wait(milliseconds) {
|
|
23
|
-
return new Promise((resolveWait) => setTimeout(resolveWait, milliseconds));
|
|
24
|
-
}
|
|
25
24
|
function diagnostic(error) {
|
|
26
25
|
return error instanceof Error ? error.message : String(error);
|
|
27
26
|
}
|
|
@@ -57,6 +56,7 @@ function decodeRecipe(value, cwd) {
|
|
|
57
56
|
...(recipe.description === undefined ? [] : ["description"]),
|
|
58
57
|
"options",
|
|
59
58
|
"provider",
|
|
59
|
+
...(recipe.readonly === undefined ? [] : ["readonly"]),
|
|
60
60
|
];
|
|
61
61
|
if (!exactKeys(recipe, expectedKeys))
|
|
62
62
|
return null;
|
|
@@ -64,19 +64,21 @@ function decodeRecipe(value, cwd) {
|
|
|
64
64
|
&& (typeof recipe.description !== "string" || recipe.description.trim().length === 0))
|
|
65
65
|
return null;
|
|
66
66
|
try {
|
|
67
|
-
const
|
|
68
|
-
const
|
|
67
|
+
const selected = resolveProviderExecution(recipe.provider);
|
|
68
|
+
const provider = selected.execution;
|
|
69
|
+
const adapter = selected.adapter;
|
|
69
70
|
const decodedOptions = decodeProviderOptions(recipe.options);
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
71
|
+
const readonly = recipe.readonly === undefined ? undefined : decodeReadonlyRestraint(recipe.readonly);
|
|
72
|
+
if ((decodedOptions.readonly === true) !== (readonly !== undefined))
|
|
72
73
|
return null;
|
|
73
|
-
const confinement = adapter.confinement({ cwd, options:
|
|
74
|
+
const confinement = adapter.confinement({ cwd, options: decodedOptions });
|
|
74
75
|
if (!matchingConfinement(recipe.confinement, confinement))
|
|
75
76
|
return null;
|
|
76
77
|
return Object.freeze({
|
|
77
78
|
...(recipe.description === undefined ? {} : { description: recipe.description }),
|
|
78
79
|
provider,
|
|
79
|
-
options:
|
|
80
|
+
options: decodedOptions,
|
|
81
|
+
...(readonly === undefined ? {} : { readonly }),
|
|
80
82
|
confinement,
|
|
81
83
|
});
|
|
82
84
|
}
|
|
@@ -158,14 +160,14 @@ function decodeReceipt(bytes, requestId) {
|
|
|
158
160
|
}
|
|
159
161
|
return null;
|
|
160
162
|
}
|
|
161
|
-
function atomicJson(path, value) {
|
|
163
|
+
async function atomicJson(path, value) {
|
|
162
164
|
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
163
165
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
await writeFile(temporary, `${JSON.stringify(value)}\n`, { flag: "wx" });
|
|
167
|
+
await rename(temporary, path);
|
|
166
168
|
}
|
|
167
169
|
finally {
|
|
168
|
-
|
|
170
|
+
await rm(temporary, { force: true });
|
|
169
171
|
}
|
|
170
172
|
}
|
|
171
173
|
function receiptFor(fact) {
|
|
@@ -177,10 +179,10 @@ function receiptFor(fact) {
|
|
|
177
179
|
return { id: fact.id, state: fact.state, evidence: fact.evidence };
|
|
178
180
|
return null;
|
|
179
181
|
}
|
|
180
|
-
function projectReceipt(directory, fact) {
|
|
182
|
+
async function projectReceipt(directory, fact) {
|
|
181
183
|
const receipt = receiptFor(fact);
|
|
182
184
|
if (receipt !== null)
|
|
183
|
-
atomicJson(join(directory, `${fact.id}.receipt.json`), receipt);
|
|
185
|
+
await atomicJson(join(directory, `${fact.id}.receipt.json`), receipt);
|
|
184
186
|
}
|
|
185
187
|
export function injectedBodyRequests() {
|
|
186
188
|
const directory = process.env[AKUMA_REQUESTS_ENV];
|
|
@@ -191,7 +193,7 @@ export function injectedBodyRequests() {
|
|
|
191
193
|
return directory;
|
|
192
194
|
}
|
|
193
195
|
export async function requestBodyCall(input) {
|
|
194
|
-
atomicJson(join(input.directory, `${input.id}.request.json`), {
|
|
196
|
+
await atomicJson(join(input.directory, `${input.id}.request.json`), {
|
|
195
197
|
id: input.id,
|
|
196
198
|
world: input.world,
|
|
197
199
|
archetype: input.archetype,
|
|
@@ -202,7 +204,7 @@ export async function requestBodyCall(input) {
|
|
|
202
204
|
const receiptPath = join(input.directory, `${input.id}.receipt.json`);
|
|
203
205
|
for (;;) {
|
|
204
206
|
try {
|
|
205
|
-
const receipt = decodeReceipt(
|
|
207
|
+
const receipt = decodeReceipt(await readFile(receiptPath, "utf8"), input.id);
|
|
206
208
|
if (receipt === null)
|
|
207
209
|
throw new Error(`Akuma body request ${input.id} has an invalid receipt`);
|
|
208
210
|
if (receipt.state === "served")
|
|
@@ -215,14 +217,16 @@ export async function requestBodyCall(input) {
|
|
|
215
217
|
if (error.code !== "ENOENT")
|
|
216
218
|
throw error;
|
|
217
219
|
}
|
|
218
|
-
await
|
|
220
|
+
await abortableDelay(POLL_MS);
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
async function serveClaim(input) {
|
|
222
|
-
|
|
224
|
+
input.signal.throwIfAborted();
|
|
225
|
+
let fact = await admitRequest(input.paths, { ...input.claim, admittedAt: input.now() });
|
|
223
226
|
const existing = receiptFor(fact);
|
|
224
227
|
if (existing !== null) {
|
|
225
|
-
|
|
228
|
+
if (!input.signal.aborted)
|
|
229
|
+
await projectReceipt(input.directory, fact);
|
|
226
230
|
return;
|
|
227
231
|
}
|
|
228
232
|
if (fact.state !== "admitted")
|
|
@@ -230,17 +234,19 @@ async function serveClaim(input) {
|
|
|
230
234
|
const request = fact;
|
|
231
235
|
const servingWorld = worldRootForAkumaPaths(input.paths);
|
|
232
236
|
if (request.world !== servingWorld) {
|
|
233
|
-
fact = refuseRequest(input.paths, request.id, `request world ${request.world} does not match ${servingWorld}`);
|
|
234
|
-
projectReceipt(input.directory, fact);
|
|
237
|
+
fact = await refuseRequest(input.paths, request.id, `request world ${request.world} does not match ${servingWorld}`);
|
|
238
|
+
await projectReceipt(input.directory, fact);
|
|
235
239
|
return;
|
|
236
240
|
}
|
|
237
241
|
const cwd = resolve(request.cwd ?? servingWorld);
|
|
238
242
|
let child;
|
|
239
243
|
try {
|
|
244
|
+
input.signal.throwIfAborted();
|
|
240
245
|
const published = await publishAkuma({
|
|
241
246
|
worldPath: servingWorld,
|
|
242
247
|
archetype: request.archetype,
|
|
243
|
-
reserve: (allocated) => { fact = reserveRequest(input.paths, request.id, allocated.id); },
|
|
248
|
+
reserve: async (allocated) => { fact = await reserveRequest(input.paths, request.id, allocated.id); },
|
|
249
|
+
signal: input.signal,
|
|
244
250
|
launch: async (allocated) => await input.spawn({
|
|
245
251
|
paths: allocated.paths,
|
|
246
252
|
seed: {
|
|
@@ -249,6 +255,7 @@ async function serveClaim(input) {
|
|
|
249
255
|
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
250
256
|
provider: request.recipe.provider,
|
|
251
257
|
options: request.recipe.options,
|
|
258
|
+
...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
|
|
252
259
|
cwd,
|
|
253
260
|
origin: { kind: "request", parent: input.parent.id, requestId: request.id },
|
|
254
261
|
confinement: request.recipe.confinement,
|
|
@@ -259,21 +266,23 @@ async function serveClaim(input) {
|
|
|
259
266
|
child = published.id;
|
|
260
267
|
}
|
|
261
268
|
catch (error) {
|
|
262
|
-
|
|
269
|
+
if (input.signal.aborted)
|
|
270
|
+
return;
|
|
271
|
+
const current = await readRequest(input.paths, request.id);
|
|
263
272
|
if (current === null)
|
|
264
273
|
throw error;
|
|
265
274
|
fact = current.state === "admitted" || current.state === "reserved"
|
|
266
|
-
? voidRequest(input.paths, request.id, diagnostic(error))
|
|
275
|
+
? await voidRequest(input.paths, request.id, diagnostic(error))
|
|
267
276
|
: current;
|
|
268
|
-
projectReceipt(input.directory, fact);
|
|
277
|
+
await projectReceipt(input.directory, fact);
|
|
269
278
|
return;
|
|
270
279
|
}
|
|
271
|
-
fact = serveRequest(input.paths, request.id, child);
|
|
272
|
-
projectReceipt(input.directory, fact);
|
|
280
|
+
fact = await serveRequest(input.paths, request.id, child);
|
|
281
|
+
await projectReceipt(input.directory, fact);
|
|
273
282
|
}
|
|
274
|
-
function requestFiles(directory) {
|
|
283
|
+
async function requestFiles(directory) {
|
|
275
284
|
try {
|
|
276
|
-
return
|
|
285
|
+
return (await readdir(directory))
|
|
277
286
|
.filter((name) => name.endsWith(".request.json"))
|
|
278
287
|
.sort();
|
|
279
288
|
}
|
|
@@ -287,35 +296,47 @@ export class BodyRequestPump {
|
|
|
287
296
|
input;
|
|
288
297
|
directory;
|
|
289
298
|
failure;
|
|
290
|
-
|
|
299
|
+
closeSignal = new AbortController();
|
|
291
300
|
handled = new Set();
|
|
292
301
|
running;
|
|
302
|
+
cancelAdmission;
|
|
293
303
|
constructor(input) {
|
|
294
304
|
this.input = input;
|
|
295
305
|
this.directory = join(input.paths.directory, "requests", String(input.bodySequence));
|
|
296
|
-
|
|
306
|
+
this.cancelAdmission = () => this.stopAdmission();
|
|
307
|
+
input.signal.addEventListener("abort", this.cancelAdmission, { once: true });
|
|
308
|
+
if (input.signal.aborted)
|
|
309
|
+
this.cancelAdmission();
|
|
297
310
|
this.running = this.run();
|
|
298
311
|
this.failure = this.running.then(() => new Promise(() => { }), (error) => Promise.reject(error));
|
|
299
312
|
}
|
|
313
|
+
static async open(input) {
|
|
314
|
+
const directory = join(input.paths.directory, "requests", String(input.bodySequence));
|
|
315
|
+
await mkdir(directory, { recursive: true });
|
|
316
|
+
return new BodyRequestPump(input);
|
|
317
|
+
}
|
|
300
318
|
async run() {
|
|
301
|
-
while (!this.
|
|
302
|
-
for (const name of requestFiles(this.directory)) {
|
|
303
|
-
if (this.
|
|
319
|
+
while (!this.closeSignal.signal.aborted) {
|
|
320
|
+
for (const name of await requestFiles(this.directory)) {
|
|
321
|
+
if (this.closeSignal.signal.aborted)
|
|
304
322
|
return;
|
|
305
323
|
const id = name.slice(0, -".request.json".length);
|
|
306
324
|
if (this.handled.has(id))
|
|
307
325
|
continue;
|
|
308
|
-
const claim = decodeClaim(
|
|
326
|
+
const claim = decodeClaim(await readFile(join(this.directory, name), "utf8"), id);
|
|
309
327
|
if (claim === null) {
|
|
310
328
|
this.handled.add(id);
|
|
311
329
|
continue;
|
|
312
330
|
}
|
|
313
|
-
|
|
314
|
-
return;
|
|
315
|
-
await serveClaim({ directory: this.directory, claim, ...this.input });
|
|
331
|
+
await serveClaim({ directory: this.directory, claim, ...this.input, signal: this.closeSignal.signal });
|
|
316
332
|
this.handled.add(id);
|
|
317
333
|
}
|
|
318
|
-
|
|
334
|
+
try {
|
|
335
|
+
await abortableDelay(POLL_MS, this.closeSignal.signal);
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
319
340
|
}
|
|
320
341
|
}
|
|
321
342
|
async close() {
|
|
@@ -324,48 +345,53 @@ export class BodyRequestPump {
|
|
|
324
345
|
await this.running;
|
|
325
346
|
}
|
|
326
347
|
finally {
|
|
327
|
-
|
|
348
|
+
this.input.signal.removeEventListener("abort", this.cancelAdmission);
|
|
349
|
+
await rm(this.directory, { recursive: true, force: true });
|
|
328
350
|
}
|
|
329
351
|
}
|
|
330
|
-
stopAdmission() {
|
|
352
|
+
stopAdmission() {
|
|
353
|
+
if (!this.closeSignal.signal.aborted)
|
|
354
|
+
this.closeSignal.abort(new Error("Body request pump closed"));
|
|
355
|
+
}
|
|
331
356
|
}
|
|
332
|
-
export function clearBodyRequestTransport(paths) {
|
|
333
|
-
|
|
357
|
+
export async function clearBodyRequestTransport(paths) {
|
|
358
|
+
await rm(join(paths.directory, "requests"), { recursive: true, force: true });
|
|
334
359
|
}
|
|
335
360
|
function matchingRequestOrigin(soul, parent, requestId) {
|
|
336
361
|
return soul.origin.kind === "request"
|
|
337
362
|
&& soul.origin.parent === parent
|
|
338
363
|
&& soul.origin.requestId === requestId;
|
|
339
364
|
}
|
|
340
|
-
function settleObservedSoul(paths, parent, request, soul) {
|
|
365
|
+
async function settleObservedSoul(paths, parent, request, soul) {
|
|
341
366
|
if (matchingRequestOrigin(soul, parent.id, request.id))
|
|
342
|
-
serveRequest(paths, request.id, request.child);
|
|
367
|
+
await serveRequest(paths, request.id, request.child);
|
|
343
368
|
else
|
|
344
|
-
voidRequest(paths, request.id, "reserved child origin does not match the request");
|
|
369
|
+
await voidRequest(paths, request.id, "reserved child origin does not match the request");
|
|
345
370
|
}
|
|
346
|
-
async function settleReserved(paths, parent, request, now) {
|
|
371
|
+
async function settleReserved(paths, parent, request, now, signal) {
|
|
347
372
|
const childPaths = pathsForAkuId(request.world, request.child);
|
|
348
373
|
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
349
374
|
for (;;) {
|
|
350
|
-
|
|
351
|
-
|
|
375
|
+
signal?.throwIfAborted();
|
|
376
|
+
if (!await access(childPaths.directory).then(() => true, () => false)) {
|
|
377
|
+
await voidRequest(paths, request.id, "reserved child directory is absent");
|
|
352
378
|
return true;
|
|
353
379
|
}
|
|
354
|
-
const childSoul = readSoul(childPaths);
|
|
380
|
+
const childSoul = await readSoul(childPaths);
|
|
355
381
|
if (childSoul !== null) {
|
|
356
|
-
settleObservedSoul(paths, parent, request, childSoul);
|
|
382
|
+
await settleObservedSoul(paths, parent, request, childSoul);
|
|
357
383
|
return true;
|
|
358
384
|
}
|
|
359
|
-
const leash = HeldAkumaLeash.try(childPaths);
|
|
385
|
+
const leash = await HeldAkumaLeash.try(childPaths);
|
|
360
386
|
if (leash !== null) {
|
|
361
387
|
try {
|
|
362
|
-
const settledSoul = readSoul(childPaths);
|
|
388
|
+
const settledSoul = await readSoul(childPaths);
|
|
363
389
|
if (settledSoul !== null) {
|
|
364
|
-
settleObservedSoul(paths, parent, request, settledSoul);
|
|
390
|
+
await settleObservedSoul(paths, parent, request, settledSoul);
|
|
365
391
|
}
|
|
366
392
|
else {
|
|
367
|
-
leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
368
|
-
voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
393
|
+
await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
394
|
+
await voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
369
395
|
}
|
|
370
396
|
}
|
|
371
397
|
finally {
|
|
@@ -375,16 +401,17 @@ async function settleReserved(paths, parent, request, now) {
|
|
|
375
401
|
}
|
|
376
402
|
if (performance.now() >= deadline)
|
|
377
403
|
return false;
|
|
378
|
-
await
|
|
404
|
+
await abortableDelay(POLL_MS, signal);
|
|
379
405
|
}
|
|
380
406
|
}
|
|
381
|
-
export async function settleBodyRequests(paths, parent, now) {
|
|
407
|
+
export async function settleBodyRequests(paths, parent, now, signal) {
|
|
382
408
|
let pending = false;
|
|
383
|
-
for (const request of readNonterminalRequests(paths)) {
|
|
409
|
+
for (const request of await readNonterminalRequests(paths)) {
|
|
410
|
+
signal?.throwIfAborted();
|
|
384
411
|
if (request.state === "admitted") {
|
|
385
|
-
voidRequest(paths, request.id, "body died before serving the request");
|
|
412
|
+
await voidRequest(paths, request.id, "body died before serving the request");
|
|
386
413
|
}
|
|
387
|
-
else if (request.state === "reserved" && !await settleReserved(paths, parent, request, now))
|
|
414
|
+
else if (request.state === "reserved" && !await settleReserved(paths, parent, request, now, signal))
|
|
388
415
|
pending = true;
|
|
389
416
|
}
|
|
390
417
|
return pending ? "pending" : "settled";
|
|
@@ -9,8 +9,8 @@ export type AliasMove = Readonly<{
|
|
|
9
9
|
alias: AliasBinding;
|
|
10
10
|
previous: AkuId | null;
|
|
11
11
|
}>;
|
|
12
|
-
export declare function readAliases(world: WorldRoot): readonly AliasBinding[]
|
|
13
|
-
export declare function resolveAlias(world: WorldRoot, value: AkumaAlias): AkuId | null
|
|
12
|
+
export declare function readAliases(world: WorldRoot): Promise<readonly AliasBinding[]>;
|
|
13
|
+
export declare function resolveAlias(world: WorldRoot, value: AkumaAlias): Promise<AkuId | null>;
|
|
14
14
|
export declare function moveAlias(input: Readonly<{
|
|
15
15
|
world: WorldRoot;
|
|
16
16
|
alias: AkumaAlias;
|
package/build/src/alias/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { parseAkuId } from "../akuma/identity.js";
|
|
4
4
|
import { replaceFileDurably } from "../coordination/durable-file.js";
|
|
@@ -67,9 +67,9 @@ function decode(path, bytes) {
|
|
|
67
67
|
corruption(`Alias bytes are not canonical: ${path}`);
|
|
68
68
|
return bindings;
|
|
69
69
|
}
|
|
70
|
-
function read(path) {
|
|
70
|
+
async function read(path) {
|
|
71
71
|
try {
|
|
72
|
-
return decode(path,
|
|
72
|
+
return decode(path, await readFile(path, "utf8"));
|
|
73
73
|
}
|
|
74
74
|
catch (error) {
|
|
75
75
|
if (error.code === "ENOENT")
|
|
@@ -77,12 +77,12 @@ function read(path) {
|
|
|
77
77
|
throw error;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
export function readAliases(world) {
|
|
81
|
-
return read(paths(world).authority);
|
|
80
|
+
export async function readAliases(world) {
|
|
81
|
+
return await read(paths(world).authority);
|
|
82
82
|
}
|
|
83
|
-
export function resolveAlias(world, value) {
|
|
83
|
+
export async function resolveAlias(world, value) {
|
|
84
84
|
const alias = parseAkumaAlias(value);
|
|
85
|
-
return readAliases(world).find((binding) => binding.alias === alias)?.akuId ?? null;
|
|
85
|
+
return (await readAliases(world)).find((binding) => binding.alias === alias)?.akuId ?? null;
|
|
86
86
|
}
|
|
87
87
|
export async function moveAlias(input) {
|
|
88
88
|
const alias = parseAkumaAlias(input.alias);
|
|
@@ -90,11 +90,11 @@ export async function moveAlias(input) {
|
|
|
90
90
|
const location = paths(input.world);
|
|
91
91
|
const held = await acquireSqliteTransactionLock({ path: location.lock, mode: "immediate" });
|
|
92
92
|
try {
|
|
93
|
-
const current = read(location.authority);
|
|
93
|
+
const current = await read(location.authority);
|
|
94
94
|
const previous = current.find((binding) => binding.alias === alias)?.akuId ?? null;
|
|
95
95
|
const next = [...current.filter((binding) => binding.alias !== alias), { alias, akuId }];
|
|
96
|
-
|
|
97
|
-
replaceFileDurably(location.authority, canonical(next));
|
|
96
|
+
await mkdir(dirname(location.authority), { recursive: true });
|
|
97
|
+
await replaceFileDurably(location.authority, canonical(next));
|
|
98
98
|
return { alias: { alias, akuId }, previous };
|
|
99
99
|
}
|
|
100
100
|
finally {
|
package/build/src/body/decode.js
CHANGED
|
@@ -91,7 +91,13 @@ function verification(document, section) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
export function decodeContractDocument(source) {
|
|
94
|
-
|
|
94
|
+
let document;
|
|
95
|
+
try {
|
|
96
|
+
document = parseToAST(source);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
refusal(error instanceof Error ? error.message : String(error));
|
|
100
|
+
}
|
|
95
101
|
if (document.frontmatter !== undefined)
|
|
96
102
|
refusal("contract document may not contain frontmatter");
|
|
97
103
|
const titles = indexedHeadings(indexDocument(document), { level: 1 })
|
|
@@ -2,5 +2,7 @@ import type { DocumentNode, SectionNode } from "../markdown/types.js";
|
|
|
2
2
|
export declare class RegionDocumentError extends Error {
|
|
3
3
|
constructor(message: string);
|
|
4
4
|
}
|
|
5
|
+
export declare function assertCanonicalRegionPath(path: string): void;
|
|
5
6
|
export declare function decodeRegion(document: DocumentNode, section: SectionNode): readonly string[];
|
|
6
7
|
export declare function regionsOverlap(mine: readonly string[], theirs: readonly string[]): readonly [string, string][];
|
|
8
|
+
export declare function regionPatternsMatchPath(patterns: readonly string[], path: string): readonly string[];
|
package/build/src/body/region.js
CHANGED
|
@@ -28,15 +28,79 @@ function compileRegionPattern(pattern) {
|
|
|
28
28
|
refusal(`Region pattern '${pattern}' contains a forbidden glob form`);
|
|
29
29
|
if (pattern.startsWith("/"))
|
|
30
30
|
refusal(`Region pattern '${pattern}' must be repository-relative`);
|
|
31
|
-
if (pattern.endsWith("/"))
|
|
32
|
-
refusal(`Region pattern '${pattern}' may not end with /`);
|
|
33
31
|
if (pattern.includes(".."))
|
|
34
32
|
refusal(`Region pattern '${pattern}' may not contain ..`);
|
|
35
33
|
const segments = pattern.split("/");
|
|
36
|
-
|
|
34
|
+
const directory = pattern.endsWith("/");
|
|
35
|
+
if (segments.some((segment, index) => segment.length === 0 && !(directory && index === segments.length - 1))) {
|
|
37
36
|
refusal(`Region pattern '${pattern}' may not contain an empty segment`);
|
|
38
37
|
}
|
|
39
|
-
|
|
38
|
+
const source = directory ? `${pattern}**` : pattern;
|
|
39
|
+
const canonical = directory ? [...segments.slice(0, -1), "**"] : segments;
|
|
40
|
+
return { source, segments: canonical.map((segment) => compileSegment(segment, pattern)) };
|
|
41
|
+
}
|
|
42
|
+
export function assertCanonicalRegionPath(path) {
|
|
43
|
+
if (path.length === 0 || /[\r\n\0]/u.test(path) || path.startsWith("/") || path.endsWith("/")) {
|
|
44
|
+
refusal(`Region path '${path}' must be a canonical repository-relative path`);
|
|
45
|
+
}
|
|
46
|
+
if (path.split("/").some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
|
|
47
|
+
refusal(`Region path '${path}' must be a canonical repository-relative path`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function segmentMatchesPath(pattern, path) {
|
|
51
|
+
const queue = [[0, 0]];
|
|
52
|
+
const visited = new Set();
|
|
53
|
+
let cursor = 0;
|
|
54
|
+
while (cursor < queue.length) {
|
|
55
|
+
const [patternIndex, pathIndex] = queue[cursor++];
|
|
56
|
+
const key = `${patternIndex}:${pathIndex}`;
|
|
57
|
+
if (visited.has(key))
|
|
58
|
+
continue;
|
|
59
|
+
visited.add(key);
|
|
60
|
+
if (patternIndex === pattern.length && pathIndex === path.length)
|
|
61
|
+
return true;
|
|
62
|
+
const character = pattern[patternIndex];
|
|
63
|
+
if (character === "*") {
|
|
64
|
+
queue.push([patternIndex + 1, pathIndex]);
|
|
65
|
+
if (pathIndex < path.length)
|
|
66
|
+
queue.push([patternIndex, pathIndex + 1]);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (character === "?") {
|
|
70
|
+
if (pathIndex < path.length)
|
|
71
|
+
queue.push([patternIndex + 1, pathIndex + 1]);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (character !== undefined && character === path[pathIndex])
|
|
75
|
+
queue.push([patternIndex + 1, pathIndex + 1]);
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
function patternMatchesPath(pattern, path) {
|
|
80
|
+
const queue = [[0, 0]];
|
|
81
|
+
const visited = new Set();
|
|
82
|
+
let cursor = 0;
|
|
83
|
+
while (cursor < queue.length) {
|
|
84
|
+
const [patternIndex, pathIndex] = queue[cursor++];
|
|
85
|
+
const key = `${patternIndex}:${pathIndex}`;
|
|
86
|
+
if (visited.has(key))
|
|
87
|
+
continue;
|
|
88
|
+
visited.add(key);
|
|
89
|
+
if (patternIndex === pattern.length && pathIndex === path.length)
|
|
90
|
+
return true;
|
|
91
|
+
const segment = pattern[patternIndex];
|
|
92
|
+
if (segment?.kind === "deep") {
|
|
93
|
+
queue.push([patternIndex + 1, pathIndex]);
|
|
94
|
+
if (pathIndex < path.length)
|
|
95
|
+
queue.push([patternIndex, pathIndex + 1]);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (segment === undefined || path[pathIndex] === undefined)
|
|
99
|
+
continue;
|
|
100
|
+
if (segmentMatchesPath(segment.characters, Array.from(path[pathIndex])))
|
|
101
|
+
queue.push([patternIndex + 1, pathIndex + 1]);
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
40
104
|
}
|
|
41
105
|
function segmentTransition(characters, index) {
|
|
42
106
|
const character = characters[index];
|
|
@@ -120,9 +184,7 @@ export function decodeRegion(document, section) {
|
|
|
120
184
|
const patterns = blocks[0].lines.slice(1, -1).filter((line) => line.trim().length > 0);
|
|
121
185
|
if (patterns.length === 0)
|
|
122
186
|
refusal("Region must declare at least one path pattern");
|
|
123
|
-
|
|
124
|
-
compileRegionPattern(pattern);
|
|
125
|
-
return patterns;
|
|
187
|
+
return patterns.map((pattern) => compileRegionPattern(pattern).source);
|
|
126
188
|
}
|
|
127
189
|
export function regionsOverlap(mine, theirs) {
|
|
128
190
|
const myPatterns = mine.map((pattern) => compileRegionPattern(pattern));
|
|
@@ -137,3 +199,11 @@ export function regionsOverlap(mine, theirs) {
|
|
|
137
199
|
}
|
|
138
200
|
return overlaps;
|
|
139
201
|
}
|
|
202
|
+
export function regionPatternsMatchPath(patterns, path) {
|
|
203
|
+
assertCanonicalRegionPath(path);
|
|
204
|
+
const pathSegments = path.split("/");
|
|
205
|
+
return patterns
|
|
206
|
+
.map((pattern) => compileRegionPattern(pattern))
|
|
207
|
+
.filter((pattern) => patternMatchesPath(pattern.segments, pathSegments))
|
|
208
|
+
.map((pattern) => pattern.source);
|
|
209
|
+
}
|
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import { type ContractId, type MutationResult } from "../index.js";
|
|
2
|
-
import type { AcceptedResult, InvocationResult } from "./result.js";
|
|
1
|
+
import { type AmendResult, type AuditReport, type BindResult, type ContractId, type Delivery, type MutationResult, type Review } from "../index.js";
|
|
2
|
+
import type { AcceptedAbandonResult, AcceptedAmendResult, AcceptedArcResult, AcceptedAuditResult, AcceptedBindResult, AcceptedDeliverResult, AcceptedResult, AcceptedReviewResult, InvocationResult } from "./result.js";
|
|
3
3
|
type MutationObservation = Pick<MutationResult<unknown>, "facts" | "head" | "effects" | "lags" | "settlement">;
|
|
4
|
-
type
|
|
4
|
+
type MutationCallOptions = Readonly<{
|
|
5
5
|
coordinate?: ContractId;
|
|
6
|
-
target?: string | null;
|
|
7
|
-
report?: import("../index.js").AuditReport;
|
|
8
|
-
workspace?: AcceptedResult["workspace"];
|
|
9
|
-
obligations?: Pick<AcceptedResult, "verification" | "placement" | "leak">;
|
|
10
|
-
diff?: AcceptedResult["diff"];
|
|
11
|
-
}>;
|
|
12
|
-
type MutationCallOptions<Result extends MutationObservation> = Readonly<{
|
|
13
|
-
coordinate?: ContractId;
|
|
14
|
-
project?: (result: Result) => ResultOptions | Promise<ResultOptions>;
|
|
15
6
|
projectRefusal?: (refusal: unknown) => unknown;
|
|
16
7
|
}>;
|
|
17
|
-
export declare function
|
|
8
|
+
export declare function acceptedBind(result: BindResult, target: string | null): AcceptedBindResult;
|
|
9
|
+
export declare function acceptedAmend(result: AmendResult, coordinate: ContractId): AcceptedAmendResult;
|
|
10
|
+
export declare function acceptedDeliver(result: MutationResult<Delivery>, coordinate: ContractId): AcceptedDeliverResult;
|
|
11
|
+
export declare function acceptedReview(result: MutationResult<Review>, coordinate: ContractId): AcceptedReviewResult;
|
|
12
|
+
export declare function acceptedArc(result: MutationResult<void>, coordinate: ContractId): AcceptedArcResult;
|
|
13
|
+
export declare function acceptedAbandon(result: MutationResult<void>, coordinate: ContractId): AcceptedAbandonResult;
|
|
14
|
+
export declare function acceptedAudit(result: MutationResult<AuditReport>, coordinate: ContractId): AcceptedAuditResult;
|
|
15
|
+
export declare function resultFromMutationCall<const Verb extends AcceptedResult["verb"], Result extends MutationObservation>(verb: Verb, call: () => Promise<Result>, project: (result: Result) => Extract<AcceptedResult, {
|
|
16
|
+
verb: NoInfer<Verb>;
|
|
17
|
+
}>, options?: MutationCallOptions): Promise<Extract<AcceptedResult, {
|
|
18
|
+
verb: Verb;
|
|
19
|
+
}> | Extract<InvocationResult, {
|
|
20
|
+
kind: "refused" | "retry";
|
|
21
|
+
}>>;
|
|
18
22
|
export {};
|