@astrosheep/keiyaku 4.0.4 → 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 +3 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +14 -0
- package/build/src/akuma/akuma.d.ts +0 -1
- package/build/src/akuma/akuma.js +1 -6
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +3 -10
- package/build/src/akuma/body.d.ts +5 -2
- package/build/src/akuma/body.js +29 -23
- package/build/src/akuma/heart/facts.d.ts +35 -9
- package/build/src/akuma/heart/index.d.ts +4 -13
- package/build/src/akuma/heart/index.js +2 -133
- 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 +0 -137
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +9 -2
- package/build/src/akuma/heart/soul.js +0 -36
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +1 -6
- package/build/src/akuma/providers/acp/core.js +6 -2
- package/build/src/akuma/providers/acp/index.js +0 -1
- 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/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.js +0 -1
- 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/index.js +11 -4
- 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 +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 +54 -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 +17 -9
- package/build/src/cli/commands/akuma.js +2 -2
- package/build/src/cli/commands/contract.d.ts +6 -6
- package/build/src/cli/commands/contract.js +3 -3
- package/build/src/cli/commands/task-invoke.js +98 -9
- package/build/src/cli/coordinates.d.ts +1 -0
- package/build/src/cli/coordinates.js +7 -4
- package/build/src/cli/invoke.js +28 -4
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +21 -8
- package/build/src/cli/render/akuma.js +56 -13
- package/build/src/cli/render/audit.js +2 -6
- package/build/src/cli/render/contract.js +40 -0
- package/build/src/cli/render/receipt.js +28 -1
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/result.d.ts +15 -7
- package/build/src/contract-worktree.d.ts +1 -2
- package/build/src/contract-worktree.js +4 -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/git/admission.d.ts +2 -1
- package/build/src/git/integration.d.ts +5 -2
- package/build/src/git/integration.js +54 -1
- 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 +2 -1
- package/build/src/git/reconcile.js +9 -6
- 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 +1 -1
- package/build/src/git/tender.js +2 -1
- 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 +1 -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/library/address.js +7 -1
- 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 +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 +55 -2
- package/build/src/library/contract.js +162 -23
- package/build/src/library/delivery.d.ts +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +64 -200
- package/build/src/protocol/operations.js +21 -640
- 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 +1 -1
- package/build/src/protocol/read/status.js +3 -1
- 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/settlement/fence.d.ts +1 -1
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/task/board.d.ts +0 -1
- package/build/src/task/board.js +0 -3
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +11 -4
- package/build/src/task/index.d.ts +1 -1
- package/build/src/task/index.js +2 -127
- 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 +2 -0
- package/build/src/task/operations.js +35 -11
- package/build/src/task/store.js +0 -2
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/workspace-place.d.ts +1 -4
- package/build/src/workspace-place.js +0 -15
- package/package.json +3 -3
|
@@ -15,9 +15,9 @@ read `<command> --help` before using flags.
|
|
|
15
15
|
then `keiyaku-workflow` for the remaining lifecycle.
|
|
16
16
|
- An Akuma is a callable worker; see `keiyaku-akuma`.
|
|
17
17
|
|
|
18
|
-
Settings owns named gate
|
|
19
|
-
freezes
|
|
20
|
-
|
|
18
|
+
Settings owns named gate bundles. Omitting `--gates` selects `gates.default`,
|
|
19
|
+
or freezes `["reviewed"]` when that entry is absent. `--gates <name,...>`
|
|
20
|
+
selects configured bundles in order; it does not add literal gate words.
|
|
21
21
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
@@ -94,6 +94,12 @@ frontmatter names `Contract`, then reads the listed owner documents and source
|
|
|
94
94
|
files before acting. Do not substitute a generic repository tour for the files
|
|
95
95
|
that actually govern the assignment.
|
|
96
96
|
|
|
97
|
+
Contract association, available forwarded actions, and the brief are
|
|
98
|
+
independent inputs. When a Reviewer should record its own verdict, include
|
|
99
|
+
`--allowed contract.review` and say in the brief to record `--satisfied` on
|
|
100
|
+
pass or `--unsatisfied` on failure. When a Deliverer should tender its completed
|
|
101
|
+
candidate, include `--allowed contract.deliver` and say so in the brief.
|
|
102
|
+
|
|
97
103
|
A `Deliverer` implements and verifies the terms in `Worktree`. Commission a
|
|
98
104
|
`Reviewer` after delivery. The reviewer inspects the complete current Contract
|
|
99
105
|
worktree snapshot, not a worker report or named candidate commit, and does not
|
|
@@ -182,6 +188,11 @@ substitute for them.
|
|
|
182
188
|
|
|
183
189
|
## Deliver
|
|
184
190
|
|
|
191
|
+
When the brief assigns delivery to the Deliverer, include `--allowed
|
|
192
|
+
contract.deliver`; require it to run the command below after verification and
|
|
193
|
+
return the receipt. Otherwise the coordinator runs it after accepting the
|
|
194
|
+
candidate.
|
|
195
|
+
|
|
185
196
|
Deliver when the worktree content is the candidate you intend to land:
|
|
186
197
|
|
|
187
198
|
```bash
|
|
@@ -217,6 +228,9 @@ keiyaku review <contract> --unsatisfied --summary "<finding>"
|
|
|
217
228
|
```
|
|
218
229
|
|
|
219
230
|
Have an independent reviewer inspect the delivered Contract worktree snapshot.
|
|
231
|
+
If it should record the verdict itself, dispatch it with `--allowed
|
|
232
|
+
contract.review` and state both verdicts in the brief. Otherwise its answer is
|
|
233
|
+
review input for the coordinator to record.
|
|
220
234
|
The `review` command records the verdict. `--satisfied` requests placement; if
|
|
221
235
|
the other gates are current, the receipt shows `claimed`.
|
|
222
236
|
|
package/build/src/akuma/akuma.js
CHANGED
|
@@ -107,7 +107,6 @@ async function bornListRow(paths, expected, snapshot) {
|
|
|
107
107
|
...(snapshot.soul.description === undefined ? {} : { description: snapshot.soul.description }),
|
|
108
108
|
life: currentLife,
|
|
109
109
|
lifeAt: lifeAt(currentLife, snapshot.latestBody, snapshot.latestKill, snapshot.soul.createdAt),
|
|
110
|
-
confinement: snapshot.soul.confinement,
|
|
111
110
|
pending: snapshot.pending.map((tell) => tell.id),
|
|
112
111
|
};
|
|
113
112
|
}
|
|
@@ -294,7 +293,6 @@ export class AkumaHandle {
|
|
|
294
293
|
allowed: source.allowed,
|
|
295
294
|
cwd: source.cwd,
|
|
296
295
|
origin: { kind: "fork", parent: this.id, at: input.at },
|
|
297
|
-
confinement: source.confinement,
|
|
298
296
|
},
|
|
299
297
|
birthSession,
|
|
300
298
|
}),
|
|
@@ -416,10 +414,7 @@ export class Akuma {
|
|
|
416
414
|
const cwd = input.cwd !== undefined && context?.cwdCanonical === true
|
|
417
415
|
? input.cwd
|
|
418
416
|
: await canonicalBirthCwd(selectedCwd);
|
|
419
|
-
const recipe =
|
|
420
|
-
...requestRecipe,
|
|
421
|
-
confinement: archetype.adapter.confinement({ cwd, options: archetype.options }),
|
|
422
|
-
});
|
|
417
|
+
const recipe = requestRecipe;
|
|
423
418
|
const published = await publishAkuma({
|
|
424
419
|
worldPath: this.path,
|
|
425
420
|
archetype: archetype.name,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const ALLOWED_ACTIONS: readonly ["akuma.call", "akuma.kill", "akuma.tell", "contract.deliver", "task.add", "task.addDocument", "task.compose", "task.done", "task.drop", "task.hold", "task.resume", "task.start", "task.stop", "task.update"];
|
|
1
|
+
export declare const ALLOWED_ACTIONS: readonly ["akuma.call", "akuma.kill", "akuma.tell", "contract.deliver", "contract.review", "task.add", "task.addDocument", "task.compose", "task.done", "task.drop", "task.hold", "task.resume", "task.start", "task.stop", "task.update"];
|
|
2
2
|
export type AllowedAction = (typeof ALLOWED_ACTIONS)[number];
|
|
3
3
|
export type AllowedActions = readonly AllowedAction[];
|
|
4
4
|
export declare function isAllowedAction(value: unknown): value is AllowedAction;
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
+
import { TASK_MUTATION_ACTIONS } from "../task/mutation.js";
|
|
1
2
|
export const ALLOWED_ACTIONS = Object.freeze([
|
|
2
3
|
"akuma.call",
|
|
3
4
|
"akuma.kill",
|
|
4
5
|
"akuma.tell",
|
|
5
6
|
"contract.deliver",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"task.compose",
|
|
9
|
-
"task.done",
|
|
10
|
-
"task.drop",
|
|
11
|
-
"task.hold",
|
|
12
|
-
"task.resume",
|
|
13
|
-
"task.start",
|
|
14
|
-
"task.stop",
|
|
15
|
-
"task.update",
|
|
7
|
+
"contract.review",
|
|
8
|
+
...TASK_MUTATION_ACTIONS,
|
|
16
9
|
]);
|
|
17
10
|
const ALLOWED_ACTION_SET = new Set(ALLOWED_ACTIONS);
|
|
18
11
|
export function isAllowedAction(value) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SessionFact, type Soul } from "./heart/index.js";
|
|
2
2
|
import type { AkumaPaths } from "./identity.js";
|
|
3
3
|
import { type ProviderAdapter } from "./provider.js";
|
|
4
|
-
import { type UpstreamExecutionPort, type RequestChildLaunch } from "./
|
|
4
|
+
import { type UpstreamExecutionPort, type RequestChildLaunch } from "./request-serve.js";
|
|
5
5
|
export declare const CONTROL_RESPONSE_MS = 1000;
|
|
6
6
|
export type BodyLaunch = Readonly<{
|
|
7
7
|
paths: AkumaPaths;
|
|
@@ -16,5 +16,8 @@ type BodyRuntime = Readonly<{
|
|
|
16
16
|
}>;
|
|
17
17
|
export declare function driveAkumaBody(launch: BodyLaunch, adapter?: ProviderAdapter, runtime?: BodyRuntime): Promise<void>;
|
|
18
18
|
export declare function spawnAkumaBody(launch: BodyLaunch): Promise<void>;
|
|
19
|
-
export declare function runAkumaBody(upstreamFor: (launch: BodyLaunch
|
|
19
|
+
export declare function runAkumaBody(upstreamFor: (launch: BodyLaunch, configuration: Readonly<{
|
|
20
|
+
home?: string;
|
|
21
|
+
gitPath?: string;
|
|
22
|
+
}>) => UpstreamExecutionPort): Promise<void>;
|
|
20
23
|
export {};
|
package/build/src/akuma/body.js
CHANGED
|
@@ -3,7 +3,7 @@ import { abortableDelay } from "./abort.js";
|
|
|
3
3
|
import { HeldAkumaLeash, appendActivity, beginTurn, breakBody, endTurn, finishBodyIfIdle, heartExists, isHeartAbsent, readHeart, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
|
|
4
4
|
import { encodeAgentEvent, } from "./provider.js";
|
|
5
5
|
import { resolveProviderExecution } from "./providers/index.js";
|
|
6
|
-
import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./
|
|
6
|
+
import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./request-serve.js";
|
|
7
7
|
import { spawnDetachedProcess, } from "../runtime/proc/run.js";
|
|
8
8
|
const LEASH_RETRY_MS = 25;
|
|
9
9
|
const BODY_CONTROL_OBSERVATION_MS = 100;
|
|
@@ -178,24 +178,22 @@ async function startTurnDrive(input) {
|
|
|
178
178
|
startedAt: input.now(),
|
|
179
179
|
...(input.call === undefined ? {} : { call: input.call }),
|
|
180
180
|
});
|
|
181
|
-
const requests =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
})
|
|
191
|
-
: null;
|
|
181
|
+
const requests = await BodyRequestPump.open({
|
|
182
|
+
paths: input.paths,
|
|
183
|
+
parent: input.soul,
|
|
184
|
+
bodySequence: input.bodySequence,
|
|
185
|
+
now: input.now,
|
|
186
|
+
spawn: input.runtimeSpawn,
|
|
187
|
+
...(input.upstream === undefined ? {} : { upstream: input.upstream }),
|
|
188
|
+
signal: input.supervisor.signal,
|
|
189
|
+
});
|
|
192
190
|
const driveInput = {
|
|
193
191
|
body: input.body,
|
|
194
192
|
launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
|
|
195
193
|
cwd,
|
|
196
194
|
options,
|
|
197
195
|
signal: input.supervisor.signal,
|
|
198
|
-
|
|
196
|
+
requests: { dir: requests.directory },
|
|
199
197
|
};
|
|
200
198
|
const setup = session === undefined
|
|
201
199
|
? input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
|
|
@@ -204,7 +202,7 @@ async function startTurnDrive(input) {
|
|
|
204
202
|
const selected = await setup;
|
|
205
203
|
if (input.supervisor.signal.aborted) {
|
|
206
204
|
await retireProviderCustody(input, turn.sequence, selected);
|
|
207
|
-
await requests
|
|
205
|
+
await requests.close();
|
|
208
206
|
return { kind: "stopped" };
|
|
209
207
|
}
|
|
210
208
|
if (input.launchTells.length > 0) {
|
|
@@ -216,13 +214,12 @@ async function startTurnDrive(input) {
|
|
|
216
214
|
deliveredAt: input.now(),
|
|
217
215
|
})));
|
|
218
216
|
}
|
|
219
|
-
|
|
220
|
-
void selected.completion.then(() => requests.stopAdmission());
|
|
217
|
+
void selected.completion.then(() => requests.stopAdmission());
|
|
221
218
|
return { turnSequence: turn.sequence, drive: selected, requests, cwd, options,
|
|
222
219
|
...(session === undefined ? {} : { resume: session }) };
|
|
223
220
|
}
|
|
224
221
|
catch (error) {
|
|
225
|
-
await requests
|
|
222
|
+
await requests.close();
|
|
226
223
|
if (input.supervisor.signal.aborted) {
|
|
227
224
|
if (input.supervisor.reason === "heart-gone")
|
|
228
225
|
throw error;
|
|
@@ -311,7 +308,7 @@ async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
|
|
|
311
308
|
}
|
|
312
309
|
async function stopActiveDrive(input, active) {
|
|
313
310
|
await retireProviderCustody(input, active.turnSequence, active.drive);
|
|
314
|
-
await active.requests
|
|
311
|
+
await active.requests.close();
|
|
315
312
|
}
|
|
316
313
|
function hasUnattemptedTell(liveTells, tellPump, pending, attempted) {
|
|
317
314
|
return liveTells && tellPump === null && pending.some((tell) => !attempted.has(tell.id));
|
|
@@ -320,7 +317,7 @@ function persistProviderEvent(_input, _active, event) {
|
|
|
320
317
|
return event.type === "session" ? event.coordinate : undefined;
|
|
321
318
|
}
|
|
322
319
|
async function settleCompletion(result, session, requests) {
|
|
323
|
-
await requests
|
|
320
|
+
await requests.close();
|
|
324
321
|
return result.kind === "answered" ? { ...result, ...(session === undefined ? {} : { session }) } : result;
|
|
325
322
|
}
|
|
326
323
|
async function consumeTurnDrive(input, active) {
|
|
@@ -360,7 +357,7 @@ async function consumeTurnDrive(input, active) {
|
|
|
360
357
|
input.supervisor.next(heart).then((observation) => ({ kind: "heart", observation })),
|
|
361
358
|
...(tellObservation === null ? [] : [tellObservation]),
|
|
362
359
|
receiptFailure,
|
|
363
|
-
|
|
360
|
+
requests.failure,
|
|
364
361
|
]);
|
|
365
362
|
if (next.kind === "event" && !next.event.done) {
|
|
366
363
|
await writeProviderEvent(input, active, next.event.value);
|
|
@@ -395,7 +392,7 @@ async function consumeTurnDrive(input, active) {
|
|
|
395
392
|
}
|
|
396
393
|
await retireProviderCustody(input, turnSequence, drive);
|
|
397
394
|
try {
|
|
398
|
-
await requests
|
|
395
|
+
await requests.close();
|
|
399
396
|
}
|
|
400
397
|
catch { /* preserve the first pump failure */ }
|
|
401
398
|
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
|
|
@@ -424,7 +421,7 @@ async function driveTurn(input) {
|
|
|
424
421
|
}
|
|
425
422
|
catch (error) {
|
|
426
423
|
if (await heartExists(input.paths)) {
|
|
427
|
-
await active.requests
|
|
424
|
+
await active.requests.close();
|
|
428
425
|
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error),
|
|
429
426
|
turnSequence: active.turnSequence };
|
|
430
427
|
}
|
|
@@ -615,9 +612,18 @@ export async function runAkumaBody(upstreamFor) {
|
|
|
615
612
|
if (encoded === undefined)
|
|
616
613
|
throw new TypeError("Akuma body launch payload is missing");
|
|
617
614
|
const launch = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
615
|
+
const mappedHome = process.env.KEIYAKU_HOME?.trim();
|
|
616
|
+
const mappedGitPath = process.env.KEIYAKU_GIT_PATH;
|
|
617
|
+
if (mappedGitPath !== undefined && mappedGitPath.trim().length === 0) {
|
|
618
|
+
throw new TypeError("KEIYAKU_GIT_PATH requires a nonblank value");
|
|
619
|
+
}
|
|
620
|
+
const configuration = {
|
|
621
|
+
...(mappedHome === undefined || mappedHome.length === 0 ? {} : { home: mappedHome }),
|
|
622
|
+
...(mappedGitPath === undefined ? {} : { gitPath: mappedGitPath }),
|
|
623
|
+
};
|
|
618
624
|
await driveAkumaBody(launch, undefined, {
|
|
619
625
|
now: () => new Date().toISOString(),
|
|
620
626
|
spawnChild: spawnAkumaBody,
|
|
621
|
-
upstream: upstreamFor(launch),
|
|
627
|
+
upstream: upstreamFor(launch, configuration),
|
|
622
628
|
});
|
|
623
629
|
}
|
|
@@ -2,13 +2,8 @@ import type { AkuId } from "../identity.js";
|
|
|
2
2
|
import type { ResumeCoordinate } from "../coordinate.js";
|
|
3
3
|
import type { ProviderExecution, ProviderOptions, ReadonlyRestraint } from "../provider-recipe.js";
|
|
4
4
|
import type { AllowedActions } from "../allowed.js";
|
|
5
|
+
import type { TaskMutationAction, TaskMutationRequest } from "../../task/mutation.js";
|
|
5
6
|
export type { ResumeCoordinate } from "../coordinate.js";
|
|
6
|
-
export type Confinement = Readonly<{
|
|
7
|
-
kind: "unconfined";
|
|
8
|
-
}> | Readonly<{
|
|
9
|
-
kind: "declared";
|
|
10
|
-
writableRoots: readonly string[];
|
|
11
|
-
}>;
|
|
12
7
|
export type AkumaOrigin = Readonly<{
|
|
13
8
|
kind: "direct";
|
|
14
9
|
}> | Readonly<{
|
|
@@ -29,11 +24,10 @@ export type Soul = Readonly<{
|
|
|
29
24
|
readonly?: ReadonlyRestraint;
|
|
30
25
|
cwd: string;
|
|
31
26
|
origin: AkumaOrigin;
|
|
32
|
-
confinement: Confinement;
|
|
33
27
|
allowed: AllowedActions;
|
|
34
28
|
createdAt: string;
|
|
35
29
|
}>;
|
|
36
|
-
export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "
|
|
30
|
+
export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "allowed">;
|
|
37
31
|
export type BodyEnd = "exited" | "broke-off" | "put-down";
|
|
38
32
|
export type BodyFact = Readonly<{
|
|
39
33
|
sequence: number;
|
|
@@ -129,6 +123,12 @@ export type TellReceiptInput = Readonly<{
|
|
|
129
123
|
turnSequence: number;
|
|
130
124
|
fence: string;
|
|
131
125
|
}>);
|
|
126
|
+
export type TaskRequestInput = Readonly<{
|
|
127
|
+
id: string;
|
|
128
|
+
action: TaskMutationAction;
|
|
129
|
+
world: string;
|
|
130
|
+
request: TaskMutationRequest;
|
|
131
|
+
}>;
|
|
132
132
|
export type RequestInput = Readonly<{
|
|
133
133
|
id: string;
|
|
134
134
|
action: "akuma.call";
|
|
@@ -152,7 +152,21 @@ export type RequestInput = Readonly<{
|
|
|
152
152
|
id: string;
|
|
153
153
|
action: "akuma.kill";
|
|
154
154
|
targets: readonly AkuId[];
|
|
155
|
-
}
|
|
155
|
+
}> | Readonly<{
|
|
156
|
+
id: string;
|
|
157
|
+
action: "contract.deliver";
|
|
158
|
+
repoRoot: string;
|
|
159
|
+
contractId: string;
|
|
160
|
+
message?: string;
|
|
161
|
+
includeDirty: boolean;
|
|
162
|
+
}> | Readonly<{
|
|
163
|
+
id: string;
|
|
164
|
+
action: "contract.review";
|
|
165
|
+
repoRoot: string;
|
|
166
|
+
contractId: string;
|
|
167
|
+
verdict: "satisfied" | "unsatisfied";
|
|
168
|
+
summary?: string;
|
|
169
|
+
}> | TaskRequestInput;
|
|
156
170
|
export type UpstreamRequestService = Readonly<{
|
|
157
171
|
action: "akuma.wait";
|
|
158
172
|
}> | Readonly<{
|
|
@@ -165,6 +179,18 @@ export type UpstreamRequestService = Readonly<{
|
|
|
165
179
|
id: AkuId;
|
|
166
180
|
evidence: KillEvidence;
|
|
167
181
|
}>[];
|
|
182
|
+
}> | Readonly<{
|
|
183
|
+
action: "contract.deliver";
|
|
184
|
+
repoRoot: string;
|
|
185
|
+
contractId: string;
|
|
186
|
+
deliveryFactId: string;
|
|
187
|
+
}> | Readonly<{
|
|
188
|
+
action: "contract.review";
|
|
189
|
+
repoRoot: string;
|
|
190
|
+
contractId: string;
|
|
191
|
+
reviewFactId: string;
|
|
192
|
+
}> | Readonly<{
|
|
193
|
+
action: TaskMutationRequest["action"];
|
|
168
194
|
}>;
|
|
169
195
|
type AdmittedRequest = RequestInput & Readonly<{
|
|
170
196
|
requester: AkuId;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { BodyEnd, BodyFact, ForkPoint, HeartSnapshot, KillFact,
|
|
1
|
+
import type { AkumaPaths } from "../identity.js";
|
|
2
|
+
import type { BodyEnd, BodyFact, ForkPoint, HeartSnapshot, KillFact, SealFact, SessionFact, Soul, TellDeliveryInput, TellFact, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact } from "./facts.js";
|
|
3
3
|
export type { CallFact } from "./facts.js";
|
|
4
4
|
import type { ActivityFact } from "./rows.js";
|
|
5
5
|
import { type ActivityFactSlice } from "./timeline.js";
|
|
6
6
|
export { HeartAbsentError, HeldAkumaLeash, initializeHeart, isHeartAbsent, probeLeash } from "./storage.js";
|
|
7
|
+
export { admitRequest, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./request-authority.js";
|
|
7
8
|
export { life, lifeAt } from "./facts.js";
|
|
8
|
-
export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact,
|
|
9
|
+
export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact, HeartSnapshot, ForkPoint, KillEvidence, KillFact, LeashProbe, PauseFact, RequestFact, RequestInput, RequestRecipe, UpstreamRequestService, SealFact, SessionFact, Soul, StopFact, TellFact, TellDelivery, TellDeliveryInput, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact, } from "./facts.js";
|
|
9
10
|
export type { ResumeCoordinate } from "../coordinate.js";
|
|
10
11
|
export declare function readSoul(paths: AkumaPaths): Promise<Soul | null>;
|
|
11
12
|
export declare function heartExists(paths: AkumaPaths): Promise<boolean>;
|
|
@@ -28,16 +29,6 @@ export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequ
|
|
|
28
29
|
}>>;
|
|
29
30
|
export declare function recordTellDeliveries(paths: AkumaPaths, inputs: readonly TellDeliveryInput[]): Promise<void>;
|
|
30
31
|
export declare function recordTellReceipt(paths: AkumaPaths, input: TellReceiptInput): Promise<void>;
|
|
31
|
-
export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
|
|
32
|
-
admittedAt: string;
|
|
33
|
-
}>): Promise<RequestFact>;
|
|
34
|
-
export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
35
|
-
export declare function serveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
36
|
-
export declare function serveUpstreamRequest(paths: AkumaPaths, id: string, service: UpstreamRequestService): Promise<RequestFact>;
|
|
37
|
-
export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
|
|
38
|
-
export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
|
|
39
|
-
export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
|
|
40
|
-
export declare function readNonterminalRequests(paths: AkumaPaths): Promise<readonly RequestFact[]>;
|
|
41
32
|
export declare function readKill(paths: AkumaPaths, bodySequence: number): Promise<KillFact | null>;
|
|
42
33
|
export declare function requestStop(paths: AkumaPaths, at: string): Promise<Readonly<{
|
|
43
34
|
kind: "requested";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { answeredTurnFact, endBodyFact, finishBodyFact, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl,
|
|
1
|
+
import { answeredTurnFact, endBodyFact, finishBodyFact, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, } from "./rows.js";
|
|
2
2
|
import { insertTellDeliveryFact, insertTellFact, insertTellReceiptFact, pendingTellFacts, tellFact, tellIdsForFence, } from "./tells.js";
|
|
3
3
|
import { activityFactSlice, pruneActivityFacts, } from "./timeline.js";
|
|
4
4
|
import { isHeartAbsent, readSealFromLeash, readTransaction, transaction, withHeart } from "./storage.js";
|
|
5
5
|
import { soulFact } from "./soul.js";
|
|
6
|
-
import { clipAllowedActions } from "../allowed.js";
|
|
7
6
|
export { HeartAbsentError, HeldAkumaLeash, initializeHeart, isHeartAbsent, probeLeash } from "./storage.js";
|
|
7
|
+
export { admitRequest, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./request-authority.js";
|
|
8
8
|
export { life, lifeAt } from "./facts.js";
|
|
9
9
|
const ACTIVITY_LIMIT = 5_000;
|
|
10
10
|
export async function readSoul(paths) {
|
|
@@ -89,137 +89,6 @@ export async function recordTellReceipt(paths, input) {
|
|
|
89
89
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
90
90
|
}));
|
|
91
91
|
}
|
|
92
|
-
function sameRequestInput(fact, input) {
|
|
93
|
-
if (fact.id !== input.id || fact.action !== input.action)
|
|
94
|
-
return false;
|
|
95
|
-
if (fact.action === "akuma.call" && input.action === "akuma.call") {
|
|
96
|
-
return fact.archetype === input.archetype
|
|
97
|
-
&& fact.body === input.body
|
|
98
|
-
&& fact.cwd === input.cwd
|
|
99
|
-
&& fact.world === input.world
|
|
100
|
-
&& JSON.stringify(fact.recipe) === JSON.stringify(input.recipe);
|
|
101
|
-
}
|
|
102
|
-
if (fact.action === "akuma.wait" && input.action === "akuma.wait") {
|
|
103
|
-
return fact.completion === input.completion
|
|
104
|
-
&& fact.timeoutMs === input.timeoutMs
|
|
105
|
-
&& JSON.stringify(fact.targets) === JSON.stringify(input.targets);
|
|
106
|
-
}
|
|
107
|
-
if (fact.action === "akuma.tell" && input.action === "akuma.tell") {
|
|
108
|
-
return fact.target === input.target && fact.body === input.body;
|
|
109
|
-
}
|
|
110
|
-
return fact.action === "akuma.kill" && input.action === "akuma.kill"
|
|
111
|
-
&& JSON.stringify(fact.targets) === JSON.stringify(input.targets);
|
|
112
|
-
}
|
|
113
|
-
export async function admitRequest(paths, input) {
|
|
114
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
115
|
-
const soul = soulFact(heart);
|
|
116
|
-
if (soul === null)
|
|
117
|
-
throw new Error("Akuma request admission requires a born Soul");
|
|
118
|
-
const action = input.action;
|
|
119
|
-
const parentAllowed = soul.allowed;
|
|
120
|
-
const permitted = action === "akuma.wait" || parentAllowed.includes(action);
|
|
121
|
-
const normalized = input.action === "akuma.call"
|
|
122
|
-
? {
|
|
123
|
-
...input,
|
|
124
|
-
recipe: {
|
|
125
|
-
...input.recipe,
|
|
126
|
-
allowed: permitted ? clipAllowedActions(input.recipe.allowed, parentAllowed) : input.recipe.allowed,
|
|
127
|
-
},
|
|
128
|
-
}
|
|
129
|
-
: input;
|
|
130
|
-
insertRequestFact(heart, {
|
|
131
|
-
...normalized,
|
|
132
|
-
requester: soul.id,
|
|
133
|
-
admittedAt: input.admittedAt,
|
|
134
|
-
...(permitted ? {} : { refusal: `not-allowed: ${action}` }),
|
|
135
|
-
});
|
|
136
|
-
const fact = requestFact(heart, input.id);
|
|
137
|
-
if (fact === null)
|
|
138
|
-
throw new Error(`Akuma request ${input.id} was not admitted`);
|
|
139
|
-
if (fact.requester !== soul.id || !sameRequestInput(fact, normalized)) {
|
|
140
|
-
throw new Error(`Akuma request ${input.id} reused different input`);
|
|
141
|
-
}
|
|
142
|
-
return fact;
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
145
|
-
export async function reserveRequest(paths, id, child) {
|
|
146
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
147
|
-
const before = requestFact(heart, id);
|
|
148
|
-
if (before === null)
|
|
149
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
150
|
-
if (before.action !== "akuma.call")
|
|
151
|
-
throw new Error(`Akuma request ${id} cannot reserve a child`);
|
|
152
|
-
if (before.state === "admitted")
|
|
153
|
-
updateRequestReserved(heart, id, child);
|
|
154
|
-
else if ((before.state !== "reserved" && before.state !== "served") || before.child !== child) {
|
|
155
|
-
throw new Error(`Akuma request ${id} cannot reserve ${child}`);
|
|
156
|
-
}
|
|
157
|
-
return requestFact(heart, id);
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
export async function serveRequest(paths, id, child) {
|
|
161
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
162
|
-
const before = requestFact(heart, id);
|
|
163
|
-
if (before === null)
|
|
164
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
165
|
-
if (before.action !== "akuma.call")
|
|
166
|
-
throw new Error(`Akuma request ${id} cannot serve a child`);
|
|
167
|
-
if (before.state === "reserved" && before.child === child)
|
|
168
|
-
updateRequestServed(heart, id, child);
|
|
169
|
-
else if (before.state !== "served" || before.child !== child) {
|
|
170
|
-
throw new Error(`Akuma request ${id} cannot serve ${child}`);
|
|
171
|
-
}
|
|
172
|
-
return requestFact(heart, id);
|
|
173
|
-
}));
|
|
174
|
-
}
|
|
175
|
-
export async function serveUpstreamRequest(paths, id, service) {
|
|
176
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
177
|
-
const before = requestFact(heart, id);
|
|
178
|
-
if (before === null)
|
|
179
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
180
|
-
if (before.action === "akuma.call" || service.action !== before.action) {
|
|
181
|
-
throw new Error(`Akuma request ${id} has a mismatched service reference`);
|
|
182
|
-
}
|
|
183
|
-
if (before.state === "admitted")
|
|
184
|
-
updateUpstreamRequestServed(heart, id, service);
|
|
185
|
-
else if (before.state !== "served" || JSON.stringify(before.service) !== JSON.stringify(service)) {
|
|
186
|
-
throw new Error(`Akuma request ${id} cannot be served as ${service.action}`);
|
|
187
|
-
}
|
|
188
|
-
return requestFact(heart, id);
|
|
189
|
-
}));
|
|
190
|
-
}
|
|
191
|
-
export async function refuseRequest(paths, id, diagnostic) {
|
|
192
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
193
|
-
const before = requestFact(heart, id);
|
|
194
|
-
if (before === null)
|
|
195
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
196
|
-
if (before.state === "admitted")
|
|
197
|
-
updateRequestRefused(heart, id, diagnostic);
|
|
198
|
-
else if (before.state !== "refused" || before.diagnostic !== diagnostic) {
|
|
199
|
-
throw new Error(`Akuma request ${id} cannot be refused`);
|
|
200
|
-
}
|
|
201
|
-
return requestFact(heart, id);
|
|
202
|
-
}));
|
|
203
|
-
}
|
|
204
|
-
export async function voidRequest(paths, id, evidence) {
|
|
205
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
206
|
-
const before = requestFact(heart, id);
|
|
207
|
-
if (before === null)
|
|
208
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
209
|
-
if (before.state === "admitted" || before.state === "reserved")
|
|
210
|
-
updateRequestVoided(heart, id, evidence);
|
|
211
|
-
else if (before.state !== "voided" || before.evidence !== evidence) {
|
|
212
|
-
throw new Error(`Akuma request ${id} cannot be voided`);
|
|
213
|
-
}
|
|
214
|
-
return requestFact(heart, id);
|
|
215
|
-
}));
|
|
216
|
-
}
|
|
217
|
-
export async function readRequest(paths, id) {
|
|
218
|
-
return await withHeart(paths, (heart) => requestFact(heart, id));
|
|
219
|
-
}
|
|
220
|
-
export async function readNonterminalRequests(paths) {
|
|
221
|
-
return await withHeart(paths, nonterminalRequestFacts);
|
|
222
|
-
}
|
|
223
92
|
export async function readKill(paths, bodySequence) {
|
|
224
93
|
return await withHeart(paths, (heart) => killFactForBody(heart, bodySequence));
|
|
225
94
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AkuId, AkumaPaths } from "../identity.js";
|
|
2
|
+
import type { RequestFact, RequestInput, UpstreamRequestService } from "./facts.js";
|
|
3
|
+
export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
|
|
4
|
+
admittedAt: string;
|
|
5
|
+
}>): Promise<RequestFact>;
|
|
6
|
+
export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
7
|
+
export declare function serveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
8
|
+
export declare function serveUpstreamRequest(paths: AkumaPaths, id: string, service: UpstreamRequestService): Promise<RequestFact>;
|
|
9
|
+
export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
|
|
10
|
+
export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
|
|
11
|
+
export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
|
|
12
|
+
export declare function readNonterminalRequests(paths: AkumaPaths): Promise<readonly RequestFact[]>;
|