@astrosheep/keiyaku 4.0.3 → 4.0.5
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 +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +15 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +34 -13
- package/build/src/akuma/akuma.d.ts +34 -12
- package/build/src/akuma/akuma.js +118 -63
- package/build/src/akuma/allowed.d.ts +7 -0
- package/build/src/akuma/allowed.js +33 -0
- package/build/src/akuma/archetype.d.ts +7 -4
- package/build/src/akuma/archetype.js +15 -16
- package/build/src/akuma/body.d.ts +6 -1
- package/build/src/akuma/body.js +36 -27
- package/build/src/akuma/heart/facts.d.ts +82 -14
- package/build/src/akuma/heart/index.d.ts +5 -18
- package/build/src/akuma/heart/index.js +14 -84
- 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 -26
- package/build/src/akuma/heart/rows.js +0 -50
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +22 -10
- package/build/src/akuma/heart/soul.js +2 -36
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +15 -0
- package/build/src/akuma/heart/timeline.d.ts +1 -5
- package/build/src/akuma/heart/timeline.js +8 -17
- package/build/src/akuma/index.d.ts +5 -2
- package/build/src/akuma/index.js +1 -0
- package/build/src/akuma/projection.d.ts +17 -3
- package/build/src/akuma/projection.js +40 -3
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +2 -7
- package/build/src/akuma/provider.js +2 -1
- package/build/src/akuma/providers/acp/core.d.ts +3 -1
- package/build/src/akuma/providers/acp/core.js +10 -6
- package/build/src/akuma/providers/acp/events.d.ts +11 -3
- package/build/src/akuma/providers/acp/events.js +78 -4
- package/build/src/akuma/providers/acp/index.js +0 -1
- package/build/src/akuma/providers/claude/events.js +62 -3
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +7 -3
- package/build/src/akuma/providers/codex-app-server/events.js +1 -13
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +0 -2
- package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
- package/build/src/akuma/providers/grok-build/index.js +72 -3
- package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +8 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
- package/build/src/akuma/providers/pi/events.js +17 -3
- package/build/src/akuma/providers/pi/index.js +11 -4
- package/build/src/akuma/providers/unified-patch.d.ts +4 -0
- package/build/src/akuma/providers/unified-patch.js +14 -0
- package/build/src/akuma/publication.d.ts +1 -1
- package/build/src/akuma/publication.js +1 -1
- package/build/src/akuma/request-serve.d.ts +87 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +124 -0
- package/build/src/akuma/request-wire.js +380 -0
- package/build/src/akuma/requests.d.ts +41 -41
- package/build/src/akuma/requests.js +75 -374
- package/build/src/akuma-body.d.ts +8 -0
- package/build/src/akuma-body.js +84 -0
- 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.d.ts +4 -1
- package/build/src/cli/accepted.js +39 -9
- package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
- package/build/src/cli/commands/akuma-invoke.js +18 -10
- package/build/src/cli/commands/akuma.d.ts +11 -2
- package/build/src/cli/commands/akuma.js +67 -28
- package/build/src/cli/commands/amend.d.ts +1 -1
- package/build/src/cli/commands/amend.js +1 -1
- package/build/src/cli/commands/contract.d.ts +8 -8
- package/build/src/cli/commands/contract.js +3 -3
- package/build/src/cli/commands/install.js +2 -2
- package/build/src/cli/commands/task-invoke.js +98 -9
- package/build/src/cli/commands/task-query.d.ts +1 -1
- package/build/src/cli/commands/task-query.js +11 -5
- package/build/src/cli/coordinates.d.ts +2 -0
- package/build/src/cli/coordinates.js +12 -5
- package/build/src/cli/invoke.d.ts +1 -0
- package/build/src/cli/invoke.js +116 -75
- package/build/src/cli/main.d.ts +2 -0
- package/build/src/cli/main.js +29 -4
- package/build/src/cli/parse.d.ts +3 -2
- package/build/src/cli/parse.js +25 -8
- package/build/src/cli/render/akuma.d.ts +2 -2
- package/build/src/cli/render/akuma.js +138 -24
- package/build/src/cli/render/audit.js +18 -8
- package/build/src/cli/render/contract.d.ts +2 -0
- package/build/src/cli/render/contract.js +243 -36
- package/build/src/cli/render/kanshi.js +64 -29
- package/build/src/cli/render/receipt.d.ts +2 -1
- package/build/src/cli/render/receipt.js +37 -2
- 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 +3 -1
- package/build/src/cli/result.d.ts +52 -9
- package/build/src/cli/selectors.d.ts +1 -0
- package/build/src/cli/selectors.js +9 -6
- package/build/src/contract-worktree.d.ts +1 -2
- package/build/src/contract-worktree.js +7 -9
- 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/dispatch/index.js +50 -39
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +0 -4
- package/build/src/git/hooks.js +0 -36
- package/build/src/git/integration.d.ts +7 -8
- package/build/src/git/integration.js +62 -9
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +26 -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 +8 -2
- package/build/src/git/reconcile.js +63 -14
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +4 -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 +1 -1
- package/build/src/git/target-placement.js +9 -7
- package/build/src/git/tender.d.ts +20 -5
- package/build/src/git/tender.js +45 -13
- package/build/src/git/terminal-seal.d.ts +16 -2
- package/build/src/git/terminal-seal.js +15 -5
- package/build/src/git/workspace.d.ts +2 -1
- package/build/src/git/workspace.js +13 -5
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +9 -1
- package/build/src/kanshi/read.js +91 -37
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/address.d.ts +5 -14
- package/build/src/library/address.js +27 -23
- package/build/src/library/akuma-creation.d.ts +4 -2
- package/build/src/library/akuma-creation.js +43 -26
- package/build/src/library/audit.d.ts +2 -1
- package/build/src/library/audit.js +1 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +4 -4
- package/build/src/library/catalog.d.ts +1 -2
- package/build/src/library/catalog.js +11 -6
- package/build/src/library/configuration.d.ts +5 -1
- package/build/src/library/configuration.js +71 -18
- package/build/src/library/contract.d.ts +70 -3
- package/build/src/library/contract.js +213 -27
- package/build/src/library/delivery.d.ts +1 -1
- package/build/src/library/fleet.d.ts +70 -12
- package/build/src/library/fleet.js +236 -56
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +1 -5
- package/build/src/library/keiyaku.d.ts +4 -4
- package/build/src/library/keiyaku.js +1 -2
- package/build/src/library/mutation.d.ts +2 -1
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +3 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +3 -1
- package/build/src/library/repo.js +8 -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 +140 -0
- package/build/src/protocol/bind.d.ts +2 -3
- package/build/src/protocol/bind.js +2 -16
- package/build/src/protocol/completion.d.ts +32 -0
- package/build/src/protocol/completion.js +130 -0
- package/build/src/protocol/deliver.d.ts +37 -0
- package/build/src/protocol/deliver.js +160 -0
- package/build/src/protocol/intent.d.ts +1 -1
- package/build/src/protocol/intent.js +1 -1
- package/build/src/protocol/operations.d.ts +65 -198
- package/build/src/protocol/operations.js +21 -634
- package/build/src/protocol/placement.d.ts +4 -13
- package/build/src/protocol/placement.js +3 -15
- package/build/src/protocol/read/status.d.ts +4 -2
- package/build/src/protocol/read/status.js +27 -15
- 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 +33 -0
- package/build/src/protocol/review.js +148 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.d.ts +1 -0
- package/build/src/runtime/proc/run.js +9 -2
- package/build/src/settlement/fence.d.ts +1 -1
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +2 -1
- package/build/src/settlement/settle.js +4 -1
- package/build/src/task/board.d.ts +18 -4
- package/build/src/task/board.js +73 -29
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +11 -4
- package/build/src/task/index.d.ts +4 -4
- package/build/src/task/index.js +8 -131
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +39 -0
- package/build/src/task/mutation.js +85 -0
- package/build/src/task/operations.d.ts +4 -19
- package/build/src/task/operations.js +64 -18
- package/build/src/task/query.d.ts +9 -2
- package/build/src/task/query.js +32 -64
- package/build/src/task/store.js +0 -2
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/verification/execution.js +2 -1
- package/build/src/workspace-place.d.ts +1 -4
- package/build/src/workspace-place.js +0 -15
- package/package.json +5 -3
|
@@ -1,15 +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, 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 {
|
|
5
|
+
import { absolute, atomicJson, decodeReceipt, receiptPath, requestPath, requestPayload, } from "./request-wire.js";
|
|
6
|
+
import { isTaskMutationAction } from "../task/mutation.js";
|
|
11
7
|
const POLL_MS = 25;
|
|
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;
|
|
13
8
|
export class AkumaBodyRequestError extends Error {
|
|
14
9
|
outcome;
|
|
15
10
|
diagnostic;
|
|
@@ -21,169 +16,6 @@ export class AkumaBodyRequestError extends Error {
|
|
|
21
16
|
this.name = "AkumaBodyRequestError";
|
|
22
17
|
}
|
|
23
18
|
}
|
|
24
|
-
function diagnostic(error) {
|
|
25
|
-
return error instanceof Error ? error.message : String(error);
|
|
26
|
-
}
|
|
27
|
-
function object(value) {
|
|
28
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
29
|
-
? value
|
|
30
|
-
: null;
|
|
31
|
-
}
|
|
32
|
-
function exactKeys(value, expected) {
|
|
33
|
-
const actual = Object.keys(value).sort();
|
|
34
|
-
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
35
|
-
}
|
|
36
|
-
function absolute(value) {
|
|
37
|
-
return typeof value === "string" && isAbsolute(value) && resolve(value) === value;
|
|
38
|
-
}
|
|
39
|
-
function matchingConfinement(value, expected) {
|
|
40
|
-
const confinement = object(value);
|
|
41
|
-
if (confinement === null || confinement.kind !== expected.kind)
|
|
42
|
-
return false;
|
|
43
|
-
if (expected.kind === "unconfined")
|
|
44
|
-
return exactKeys(confinement, ["kind"]);
|
|
45
|
-
if (!exactKeys(confinement, ["kind", "writableRoots"]) || !Array.isArray(confinement.writableRoots))
|
|
46
|
-
return false;
|
|
47
|
-
return confinement.writableRoots.length === expected.writableRoots.length
|
|
48
|
-
&& confinement.writableRoots.every((root, index) => root === expected.writableRoots[index]);
|
|
49
|
-
}
|
|
50
|
-
function decodeRecipe(value, cwd) {
|
|
51
|
-
const recipe = object(value);
|
|
52
|
-
if (recipe === null)
|
|
53
|
-
return null;
|
|
54
|
-
const expectedKeys = [
|
|
55
|
-
"confinement",
|
|
56
|
-
...(recipe.description === undefined ? [] : ["description"]),
|
|
57
|
-
"options",
|
|
58
|
-
"provider",
|
|
59
|
-
...(recipe.readonly === undefined ? [] : ["readonly"]),
|
|
60
|
-
];
|
|
61
|
-
if (!exactKeys(recipe, expectedKeys))
|
|
62
|
-
return null;
|
|
63
|
-
if (recipe.description !== undefined
|
|
64
|
-
&& (typeof recipe.description !== "string" || recipe.description.trim().length === 0))
|
|
65
|
-
return null;
|
|
66
|
-
try {
|
|
67
|
-
const selected = resolveProviderExecution(recipe.provider);
|
|
68
|
-
const provider = selected.execution;
|
|
69
|
-
const adapter = selected.adapter;
|
|
70
|
-
const decodedOptions = decodeProviderOptions(recipe.options);
|
|
71
|
-
const readonly = recipe.readonly === undefined ? undefined : decodeReadonlyRestraint(recipe.readonly);
|
|
72
|
-
if ((decodedOptions.readonly === true) !== (readonly !== undefined))
|
|
73
|
-
return null;
|
|
74
|
-
const confinement = adapter.confinement({ cwd, options: decodedOptions });
|
|
75
|
-
if (!matchingConfinement(recipe.confinement, confinement))
|
|
76
|
-
return null;
|
|
77
|
-
return Object.freeze({
|
|
78
|
-
...(recipe.description === undefined ? {} : { description: recipe.description }),
|
|
79
|
-
provider,
|
|
80
|
-
options: decodedOptions,
|
|
81
|
-
...(readonly === undefined ? {} : { readonly }),
|
|
82
|
-
confinement,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function decodeClaim(bytes, fileId) {
|
|
90
|
-
let decoded;
|
|
91
|
-
try {
|
|
92
|
-
decoded = JSON.parse(bytes);
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const value = object(decoded);
|
|
98
|
-
if (value === null)
|
|
99
|
-
return null;
|
|
100
|
-
const expected = [
|
|
101
|
-
"archetype",
|
|
102
|
-
"body",
|
|
103
|
-
...(value.cwd === undefined ? [] : ["cwd"]),
|
|
104
|
-
"id",
|
|
105
|
-
"recipe",
|
|
106
|
-
"world",
|
|
107
|
-
];
|
|
108
|
-
if (!exactKeys(value, expected))
|
|
109
|
-
return null;
|
|
110
|
-
if (value.id !== fileId || typeof value.id !== "string" || !UUID.test(value.id))
|
|
111
|
-
return null;
|
|
112
|
-
if (typeof value.body !== "string" || !absolute(value.world))
|
|
113
|
-
return null;
|
|
114
|
-
if (value.cwd !== undefined && !absolute(value.cwd))
|
|
115
|
-
return null;
|
|
116
|
-
try {
|
|
117
|
-
archetypeName(value.archetype);
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
const recipe = decodeRecipe(value.recipe, (value.cwd ?? value.world));
|
|
123
|
-
if (recipe === null)
|
|
124
|
-
return null;
|
|
125
|
-
return {
|
|
126
|
-
id: value.id,
|
|
127
|
-
world: value.world,
|
|
128
|
-
archetype: value.archetype,
|
|
129
|
-
body: value.body,
|
|
130
|
-
recipe,
|
|
131
|
-
...(value.cwd === undefined ? {} : { cwd: value.cwd }),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
function decodeReceipt(bytes, requestId) {
|
|
135
|
-
let decoded;
|
|
136
|
-
try {
|
|
137
|
-
decoded = JSON.parse(bytes);
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
const value = object(decoded);
|
|
143
|
-
if (value === null || value.id !== requestId)
|
|
144
|
-
return null;
|
|
145
|
-
if (value.state === "served" && exactKeys(value, ["child", "id", "state"])) {
|
|
146
|
-
try {
|
|
147
|
-
return { id: requestId, state: "served", child: parseAkuId(value.child).id };
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (value.state === "refused" && exactKeys(value, ["diagnostic", "id", "state"])
|
|
154
|
-
&& typeof value.diagnostic === "string") {
|
|
155
|
-
return { id: requestId, state: "refused", diagnostic: value.diagnostic };
|
|
156
|
-
}
|
|
157
|
-
if (value.state === "voided" && exactKeys(value, ["evidence", "id", "state"])
|
|
158
|
-
&& typeof value.evidence === "string") {
|
|
159
|
-
return { id: requestId, state: "voided", evidence: value.evidence };
|
|
160
|
-
}
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
async function atomicJson(path, value) {
|
|
164
|
-
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
165
|
-
try {
|
|
166
|
-
await writeFile(temporary, `${JSON.stringify(value)}\n`, { flag: "wx" });
|
|
167
|
-
await rename(temporary, path);
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
await rm(temporary, { force: true });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function receiptFor(fact) {
|
|
174
|
-
if (fact.state === "served")
|
|
175
|
-
return { id: fact.id, state: fact.state, child: fact.child };
|
|
176
|
-
if (fact.state === "refused")
|
|
177
|
-
return { id: fact.id, state: fact.state, diagnostic: fact.diagnostic };
|
|
178
|
-
if (fact.state === "voided")
|
|
179
|
-
return { id: fact.id, state: fact.state, evidence: fact.evidence };
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
async function projectReceipt(directory, fact) {
|
|
183
|
-
const receipt = receiptFor(fact);
|
|
184
|
-
if (receipt !== null)
|
|
185
|
-
await atomicJson(join(directory, `${fact.id}.receipt.json`), receipt);
|
|
186
|
-
}
|
|
187
19
|
export function injectedBodyRequests() {
|
|
188
20
|
const directory = process.env[AKUMA_REQUESTS_ENV];
|
|
189
21
|
if (directory === undefined)
|
|
@@ -192,227 +24,96 @@ export function injectedBodyRequests() {
|
|
|
192
24
|
throw new Error(`${AKUMA_REQUESTS_ENV} must be an absolute normalized path`);
|
|
193
25
|
return directory;
|
|
194
26
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
recipe: input.recipe,
|
|
202
|
-
...(input.cwd === undefined ? {} : { cwd: input.cwd }),
|
|
27
|
+
async function requestBody(input) {
|
|
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),
|
|
203
33
|
});
|
|
204
|
-
const
|
|
34
|
+
const path = receiptPath(input.directory, input.claim.id);
|
|
205
35
|
for (;;) {
|
|
206
36
|
try {
|
|
207
|
-
const receipt = decodeReceipt(await readFile(
|
|
37
|
+
const receipt = decodeReceipt(await readFile(path, "utf8"), input.claim.id, input.claim.action);
|
|
208
38
|
if (receipt === null)
|
|
209
|
-
throw new Error(`Akuma body request ${input.id} has an invalid receipt`);
|
|
210
|
-
if (receipt.state === "served")
|
|
211
|
-
return receipt.child;
|
|
39
|
+
throw new Error(`Akuma body request ${input.claim.id} has an invalid receipt`);
|
|
212
40
|
if (receipt.state === "refused")
|
|
213
41
|
throw new AkumaBodyRequestError("refused", receipt.diagnostic);
|
|
214
|
-
|
|
42
|
+
if (receipt.state === "voided")
|
|
43
|
+
throw new AkumaBodyRequestError("voided", receipt.evidence);
|
|
44
|
+
return receipt;
|
|
215
45
|
}
|
|
216
46
|
catch (error) {
|
|
217
47
|
if (error.code !== "ENOENT")
|
|
218
48
|
throw error;
|
|
219
49
|
}
|
|
220
|
-
await
|
|
50
|
+
if (!await access(input.directory).then(() => true, () => false)) {
|
|
51
|
+
throw new AkumaBodyRequestError("voided", "parent request channel closed before a receipt");
|
|
52
|
+
}
|
|
53
|
+
await abortableDelay(POLL_MS, input.signal);
|
|
221
54
|
}
|
|
222
55
|
}
|
|
223
|
-
async function
|
|
224
|
-
input
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (!input.signal.aborted)
|
|
229
|
-
await projectReceipt(input.directory, fact);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (fact.state !== "admitted")
|
|
233
|
-
throw new Error(`Akuma request ${fact.id} cannot be replayed from ${fact.state}`);
|
|
234
|
-
const request = fact;
|
|
235
|
-
const servingWorld = worldRootForAkumaPaths(input.paths);
|
|
236
|
-
if (request.world !== servingWorld) {
|
|
237
|
-
fact = await refuseRequest(input.paths, request.id, `request world ${request.world} does not match ${servingWorld}`);
|
|
238
|
-
await projectReceipt(input.directory, fact);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
const cwd = resolve(request.cwd ?? servingWorld);
|
|
242
|
-
let child;
|
|
243
|
-
try {
|
|
244
|
-
input.signal.throwIfAborted();
|
|
245
|
-
const published = await publishAkuma({
|
|
246
|
-
worldPath: servingWorld,
|
|
247
|
-
archetype: request.archetype,
|
|
248
|
-
reserve: async (allocated) => { fact = await reserveRequest(input.paths, request.id, allocated.id); },
|
|
249
|
-
signal: input.signal,
|
|
250
|
-
launch: async (allocated) => await input.spawn({
|
|
251
|
-
paths: allocated.paths,
|
|
252
|
-
seed: {
|
|
253
|
-
id: allocated.id,
|
|
254
|
-
archetype: allocated.archetype,
|
|
255
|
-
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
256
|
-
provider: request.recipe.provider,
|
|
257
|
-
options: request.recipe.options,
|
|
258
|
-
...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
|
|
259
|
-
cwd,
|
|
260
|
-
origin: { kind: "request", parent: input.parent.id, requestId: request.id },
|
|
261
|
-
confinement: request.recipe.confinement,
|
|
262
|
-
},
|
|
263
|
-
initialBody: request.body,
|
|
264
|
-
}),
|
|
265
|
-
});
|
|
266
|
-
child = published.id;
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
if (input.signal.aborted)
|
|
270
|
-
return;
|
|
271
|
-
const current = await readRequest(input.paths, request.id);
|
|
272
|
-
if (current === null)
|
|
273
|
-
throw error;
|
|
274
|
-
fact = current.state === "admitted" || current.state === "reserved"
|
|
275
|
-
? await voidRequest(input.paths, request.id, diagnostic(error))
|
|
276
|
-
: current;
|
|
277
|
-
await projectReceipt(input.directory, fact);
|
|
278
|
-
return;
|
|
56
|
+
export async function requestBodyCall(input) {
|
|
57
|
+
const { directory, ...claim } = input;
|
|
58
|
+
const receipt = await requestBody({ directory, claim: { ...claim, action: "akuma.call" } });
|
|
59
|
+
if (receipt.action !== "akuma.call" || receipt.state !== "served") {
|
|
60
|
+
throw new Error(`Akuma body request ${input.id} returned the wrong action`);
|
|
279
61
|
}
|
|
280
|
-
|
|
281
|
-
await projectReceipt(input.directory, fact);
|
|
62
|
+
return receipt.child;
|
|
282
63
|
}
|
|
283
|
-
async function
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
.sort();
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
if (error.code === "ENOENT")
|
|
291
|
-
return [];
|
|
292
|
-
throw error;
|
|
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)) {
|
|
67
|
+
throw new Error(`Akuma body request ${claim.id} returned the wrong action`);
|
|
293
68
|
}
|
|
69
|
+
return receipt.outcome;
|
|
294
70
|
}
|
|
295
|
-
export
|
|
296
|
-
input;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
try {
|
|
335
|
-
await abortableDelay(POLL_MS, this.closeSignal.signal);
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
async close() {
|
|
343
|
-
this.stopAdmission();
|
|
344
|
-
try {
|
|
345
|
-
await this.running;
|
|
346
|
-
}
|
|
347
|
-
finally {
|
|
348
|
-
this.input.signal.removeEventListener("abort", this.cancelAdmission);
|
|
349
|
-
await rm(this.directory, { recursive: true, force: true });
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
stopAdmission() {
|
|
353
|
-
if (!this.closeSignal.signal.aborted)
|
|
354
|
-
this.closeSignal.abort(new Error("Body request pump closed"));
|
|
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
|
+
}
|
|
88
|
+
export async function requestBodyWait(input) {
|
|
89
|
+
const { directory, id = randomUUID(), ...claim } = input;
|
|
90
|
+
return await requestUpstream(directory, { ...claim, id, action: "akuma.wait" });
|
|
91
|
+
}
|
|
92
|
+
export async function requestBodyTell(input) {
|
|
93
|
+
const { directory, id = randomUUID(), ...claim } = input;
|
|
94
|
+
return await requestUpstream(directory, { ...claim, id, action: "akuma.tell" });
|
|
95
|
+
}
|
|
96
|
+
export async function requestBodyKill(input) {
|
|
97
|
+
const { directory, id = randomUUID(), ...claim } = input;
|
|
98
|
+
return await requestUpstream(directory, { ...claim, id, action: "akuma.kill" });
|
|
99
|
+
}
|
|
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`);
|
|
355
109
|
}
|
|
110
|
+
return "reference" in receipt
|
|
111
|
+
? receipt.reference
|
|
112
|
+
: receipt.outcome;
|
|
356
113
|
}
|
|
357
|
-
export async function
|
|
358
|
-
await
|
|
359
|
-
}
|
|
360
|
-
function matchingRequestOrigin(soul, parent, requestId) {
|
|
361
|
-
return soul.origin.kind === "request"
|
|
362
|
-
&& soul.origin.parent === parent
|
|
363
|
-
&& soul.origin.requestId === requestId;
|
|
364
|
-
}
|
|
365
|
-
async function settleObservedSoul(paths, parent, request, soul) {
|
|
366
|
-
if (matchingRequestOrigin(soul, parent.id, request.id))
|
|
367
|
-
await serveRequest(paths, request.id, request.child);
|
|
368
|
-
else
|
|
369
|
-
await voidRequest(paths, request.id, "reserved child origin does not match the request");
|
|
114
|
+
export async function requestBodyDeliver(input) {
|
|
115
|
+
return await requestContract(input, "contract.deliver");
|
|
370
116
|
}
|
|
371
|
-
async function
|
|
372
|
-
|
|
373
|
-
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
374
|
-
for (;;) {
|
|
375
|
-
signal?.throwIfAborted();
|
|
376
|
-
if (!await access(childPaths.directory).then(() => true, () => false)) {
|
|
377
|
-
await voidRequest(paths, request.id, "reserved child directory is absent");
|
|
378
|
-
return true;
|
|
379
|
-
}
|
|
380
|
-
const childSoul = await readSoul(childPaths);
|
|
381
|
-
if (childSoul !== null) {
|
|
382
|
-
await settleObservedSoul(paths, parent, request, childSoul);
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
const leash = await HeldAkumaLeash.try(childPaths);
|
|
386
|
-
if (leash !== null) {
|
|
387
|
-
try {
|
|
388
|
-
const settledSoul = await readSoul(childPaths);
|
|
389
|
-
if (settledSoul !== null) {
|
|
390
|
-
await settleObservedSoul(paths, parent, request, settledSoul);
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
|
|
394
|
-
await voidRequest(paths, request.id, "reserved child was sealed unborn");
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
finally {
|
|
398
|
-
leash.release();
|
|
399
|
-
}
|
|
400
|
-
return true;
|
|
401
|
-
}
|
|
402
|
-
if (performance.now() >= deadline)
|
|
403
|
-
return false;
|
|
404
|
-
await abortableDelay(POLL_MS, signal);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
export async function settleBodyRequests(paths, parent, now, signal) {
|
|
408
|
-
let pending = false;
|
|
409
|
-
for (const request of await readNonterminalRequests(paths)) {
|
|
410
|
-
signal?.throwIfAborted();
|
|
411
|
-
if (request.state === "admitted") {
|
|
412
|
-
await voidRequest(paths, request.id, "body died before serving the request");
|
|
413
|
-
}
|
|
414
|
-
else if (request.state === "reserved" && !await settleReserved(paths, parent, request, now, signal))
|
|
415
|
-
pending = true;
|
|
416
|
-
}
|
|
417
|
-
return pending ? "pending" : "settled";
|
|
117
|
+
export async function requestBodyReview(input) {
|
|
118
|
+
return await requestContract(input, "contract.review");
|
|
418
119
|
}
|
|
@@ -0,0 +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;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { runAkumaBody } from "./akuma/body.js";
|
|
2
|
+
import { worldRootForAkumaPaths } from "./akuma/identity.js";
|
|
3
|
+
import { executeKillAkuma, executeTellAkuma, executeWaitAkuma, } from "./library/fleet.js";
|
|
4
|
+
import { requireBranchesToBeUpToDateFrom, worktreeHooksFrom, } from "./library/configuration.js";
|
|
5
|
+
import { executeForwardedDeliver, executeForwardedReview, } from "./library/contract.js";
|
|
6
|
+
import { Repo } from "./library/repo.js";
|
|
7
|
+
import { settings } from "./settings.js";
|
|
8
|
+
import { executeTaskMutation } from "./task/mutation.js";
|
|
9
|
+
export function upstreamFor(launch, processConfiguration) {
|
|
10
|
+
const path = worldRootForAkumaPaths(launch.paths);
|
|
11
|
+
return {
|
|
12
|
+
wait: async (input) => await executeWaitAkuma({
|
|
13
|
+
path,
|
|
14
|
+
ids: input.targets,
|
|
15
|
+
completion: input.completion,
|
|
16
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
17
|
+
signal: input.signal,
|
|
18
|
+
}),
|
|
19
|
+
tell: async (input) => await executeTellAkuma({
|
|
20
|
+
path,
|
|
21
|
+
id: input.target,
|
|
22
|
+
body: input.body,
|
|
23
|
+
tellId: input.tellId,
|
|
24
|
+
recordedAt: input.recordedAt,
|
|
25
|
+
signal: input.signal,
|
|
26
|
+
}),
|
|
27
|
+
kill: async (input) => {
|
|
28
|
+
const result = await executeKillAkuma({ path, ids: input.targets, signal: input.signal });
|
|
29
|
+
return {
|
|
30
|
+
result,
|
|
31
|
+
service: result.results.map(({ id, evidence }) => ({ id, evidence })),
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
deliver: async (input) => {
|
|
35
|
+
const [repo, configuration] = await Promise.all([
|
|
36
|
+
Repo.at({
|
|
37
|
+
path: input.repoRoot,
|
|
38
|
+
...(processConfiguration.gitPath === undefined ? {} : { gitPath: processConfiguration.gitPath }),
|
|
39
|
+
}),
|
|
40
|
+
settings({
|
|
41
|
+
root: input.repoRoot,
|
|
42
|
+
...(processConfiguration.home === undefined ? {} : { home: processConfiguration.home }),
|
|
43
|
+
}),
|
|
44
|
+
]);
|
|
45
|
+
return await executeForwardedDeliver({
|
|
46
|
+
repo,
|
|
47
|
+
contractId: input.contractId,
|
|
48
|
+
requester: input.requester,
|
|
49
|
+
...(input.message === undefined ? {} : { message: input.message }),
|
|
50
|
+
includeDirty: input.includeDirty,
|
|
51
|
+
requireBranchesToBeUpToDate: requireBranchesToBeUpToDateFrom({ settings: configuration }),
|
|
52
|
+
hooks: worktreeHooksFrom({ settings: configuration }),
|
|
53
|
+
signal: input.signal,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
review: async (input) => {
|
|
57
|
+
const [repo, configuration] = await Promise.all([
|
|
58
|
+
Repo.at({
|
|
59
|
+
path: input.repoRoot,
|
|
60
|
+
...(processConfiguration.gitPath === undefined ? {} : { gitPath: processConfiguration.gitPath }),
|
|
61
|
+
}),
|
|
62
|
+
settings({
|
|
63
|
+
root: input.repoRoot,
|
|
64
|
+
...(processConfiguration.home === undefined ? {} : { home: processConfiguration.home }),
|
|
65
|
+
}),
|
|
66
|
+
]);
|
|
67
|
+
return await executeForwardedReview({
|
|
68
|
+
repo,
|
|
69
|
+
contractId: input.contractId,
|
|
70
|
+
requester: input.requester,
|
|
71
|
+
verdict: input.verdict,
|
|
72
|
+
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
73
|
+
hooks: worktreeHooksFrom({ settings: configuration }),
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
task: async (input) => await executeTaskMutation({
|
|
77
|
+
world: input.world,
|
|
78
|
+
request: input.request,
|
|
79
|
+
requester: input.requester,
|
|
80
|
+
signal: input.signal,
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
await runAkumaBody(upstreamFor);
|
package/build/src/body/arc.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { sectionContent } from "../markdown/query.js";
|
|
2
|
+
import { decodeDocumentEnvelope } from "./envelope.js";
|
|
3
3
|
function refusal(message) {
|
|
4
4
|
throw new TypeError(message);
|
|
5
5
|
}
|
|
6
|
-
function nonblankRaw(document, node) {
|
|
7
|
-
return rawSlice(document, node.span).trim().length > 0;
|
|
8
|
-
}
|
|
9
|
-
function topLevelSections(document) {
|
|
10
|
-
return indexedHeadings(indexDocument(document), { level: 2 })
|
|
11
|
-
.filter((node) => node.type === "section");
|
|
12
|
-
}
|
|
13
6
|
function requiredProse(document, sections, name) {
|
|
14
7
|
const section = sections.get(name);
|
|
15
8
|
if (section === undefined)
|
|
@@ -20,31 +13,13 @@ function requiredProse(document, sections, name) {
|
|
|
20
13
|
return value;
|
|
21
14
|
}
|
|
22
15
|
export function decodeArcDocument(source) {
|
|
23
|
-
const document =
|
|
24
|
-
if (document.frontmatter !== undefined)
|
|
25
|
-
refusal("arc document may not contain frontmatter");
|
|
26
|
-
const titles = indexedHeadings(indexDocument(document), { level: 1 })
|
|
27
|
-
.filter((node) => node.type === "section");
|
|
28
|
-
if (titles.length !== 1)
|
|
29
|
-
refusal("arc document requires exactly one H1 title");
|
|
30
|
-
const title = titles[0];
|
|
16
|
+
const { document, title, sections } = decodeDocumentEnvelope(source, "arc");
|
|
31
17
|
if (title.title.trim().length === 0)
|
|
32
18
|
refusal("arc title must be nonblank");
|
|
33
|
-
|
|
34
|
-
refusal("arc title may not contain content before the first H2 section");
|
|
35
|
-
}
|
|
36
|
-
const stray = document.children.filter((node) => node.type !== "section" && nonblankRaw(document, node));
|
|
37
|
-
if (stray.length > 0)
|
|
38
|
-
refusal("arc document contains content outside an H1 or H2 section");
|
|
39
|
-
const sections = new Map();
|
|
40
|
-
for (const section of topLevelSections(document)) {
|
|
41
|
-
const name = normalizeTitle(section.title);
|
|
42
|
-
if (sections.has(name))
|
|
43
|
-
refusal(`duplicate arc section '${section.title}'`);
|
|
19
|
+
for (const [name, section] of sections) {
|
|
44
20
|
if (name !== "objective" && name !== "brief") {
|
|
45
21
|
refusal(`arc document does not allow ## ${section.title}`);
|
|
46
22
|
}
|
|
47
|
-
sections.set(name, section);
|
|
48
23
|
}
|
|
49
24
|
return {
|
|
50
25
|
title: title.title,
|