@astrosheep/keiyaku 4.5.18 → 4.5.20
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/skills/keiyaku/SKILL.md +11 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +33 -14
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +0 -1
- package/build/src/akuma/akuma-handle.js +10 -10
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +35 -25
- package/build/src/akuma/akuma-product.d.ts +1 -0
- package/build/src/akuma/akuma-product.js +3 -0
- package/build/src/akuma/akuma.d.ts +20 -3
- package/build/src/akuma/akuma.js +3 -5
- package/build/src/akuma/allowed.d.ts +20 -0
- package/build/src/akuma/allowed.js +11 -0
- package/build/src/akuma/archetype.js +3 -0
- package/build/src/akuma/body.js +11 -36
- package/build/src/akuma/call-request.d.ts +3 -0
- package/build/src/akuma/call-request.js +12 -4
- package/build/src/akuma/fleet-execution.js +35 -11
- package/build/src/akuma/fleet-observation.d.ts +54 -0
- package/build/src/akuma/fleet-request.js +2 -1
- package/build/src/akuma/heart/index.d.ts +11 -17
- package/build/src/akuma/heart/index.js +91 -81
- package/build/src/akuma/heart/request-authority.js +19 -19
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +19 -6
- package/build/src/akuma/heart/storage.d.ts +2 -4
- package/build/src/akuma/heart/storage.js +63 -63
- package/build/src/akuma/heart/tells.d.ts +9 -19
- package/build/src/akuma/heart/tells.js +76 -76
- package/build/src/akuma/heart/timeline.d.ts +7 -1
- package/build/src/akuma/heart/timeline.js +62 -53
- package/build/src/akuma/provider-recipe.d.ts +1 -0
- package/build/src/akuma/provider-recipe.js +5 -0
- package/build/src/akuma/providers/acp/index.js +3 -0
- package/build/src/akuma/providers/claude/index.js +3 -0
- package/build/src/akuma/providers/codex-app-server/index.js +8 -0
- package/build/src/akuma/providers/grok-build/index.js +3 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +2 -0
- package/build/src/akuma/providers/pi/index.js +2 -0
- package/build/src/akuma/request-observation.d.ts +45 -0
- package/build/src/akuma/request-observation.js +162 -0
- package/build/src/akuma/request-rendezvous.d.ts +6 -3
- package/build/src/akuma/request-rendezvous.js +75 -14
- package/build/src/akuma/request-serve.js +27 -4
- package/build/src/akuma/request-wire.d.ts +5 -0
- package/build/src/akuma/request-wire.js +2 -0
- package/build/src/akuma-body.js +3 -0
- package/build/src/cli/commands/akuma-invoke.d.ts +1 -1
- package/build/src/cli/commands/akuma-invoke.js +1 -1
- package/build/src/cli/commands/akuma.js +13 -8
- package/build/src/cli/commands/contract-help.d.ts +15 -15
- package/build/src/cli/commands/contract-help.js +28 -15
- package/build/src/cli/commands/contract-invoke.d.ts +3 -0
- package/build/src/cli/commands/contract-invoke.js +25 -11
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/task.js +18 -18
- package/build/src/cli/invoke.d.ts +3 -0
- package/build/src/cli/invoke.js +58 -23
- package/build/src/cli/parse.d.ts +1 -0
- package/build/src/cli/parse.js +21 -4
- package/build/src/cli/render/akuma-activity.d.ts +1 -0
- package/build/src/cli/render/akuma-activity.js +1 -0
- package/build/src/cli/render/akuma.js +4 -1
- package/build/src/cli/render/execution-progress.d.ts +4 -0
- package/build/src/cli/render/execution-progress.js +55 -0
- package/build/src/cli/render/receipt.js +1 -1
- package/build/src/cli/runtime.js +27 -1
- package/build/src/git/hooks.d.ts +13 -1
- package/build/src/git/hooks.js +2 -1
- package/build/src/git/integration.js +4 -4
- package/build/src/git/process.d.ts +2 -0
- package/build/src/git/process.js +106 -0
- package/build/src/git/read-observation.js +79 -56
- package/build/src/git/target-placement.d.ts +13 -2
- package/build/src/git/target-placement.js +119 -68
- package/build/src/git/verification-environment.d.ts +10 -0
- package/build/src/git/verification-environment.js +281 -0
- package/build/src/library/akuma-creation.js +5 -3
- package/build/src/library/audit.d.ts +2 -0
- package/build/src/library/audit.js +1 -0
- package/build/src/library/composition.d.ts +1 -0
- package/build/src/library/contract-execution.d.ts +2 -0
- package/build/src/library/contract-execution.js +15 -1
- package/build/src/library/contract-forwarding.d.ts +4 -0
- package/build/src/library/contract-forwarding.js +3 -0
- package/build/src/library/contract-handle.d.ts +7 -0
- package/build/src/library/contract-handle.js +25 -0
- package/build/src/library/contract-operations.d.ts +5 -0
- package/build/src/library/contract-operations.js +20 -0
- package/build/src/library/execution-result.d.ts +2 -2
- package/build/src/library/execution.d.ts +8 -0
- package/build/src/library/execution.js +102 -0
- package/build/src/library/keiyaku.d.ts +2 -0
- package/build/src/library/mutation.js +15 -7
- package/build/src/plugin/akuma-signals.js +1 -1
- package/build/src/plugin/public.d.ts +2 -2
- package/build/src/plugin/runtime.d.ts +1 -3
- package/build/src/plugin/runtime.js +91 -88
- package/build/src/protocol/completion.js +28 -10
- package/build/src/protocol/execution-observation.d.ts +185 -0
- package/build/src/protocol/execution-observation.js +45 -0
- package/build/src/protocol/intent.d.ts +3 -2
- package/build/src/protocol/intent.js +44 -34
- package/build/src/protocol/placement.js +47 -29
- package/build/src/protocol/progress.d.ts +5 -1
- package/build/src/protocol/progress.js +10 -1
- package/build/src/protocol/result-codec.js +18 -4
- package/build/src/runtime/proc/run.d.ts +16 -4
- package/build/src/runtime/proc/run.js +64 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/verification/execution.d.ts +11 -2
- package/build/src/verification/execution.js +167 -42
- package/build/src/verification/observation.d.ts +45 -0
- package/build/src/verification/observation.js +30 -0
- package/package.json +7 -5
|
@@ -4,7 +4,7 @@ import { refuseRequest, reserveRequest } from "./heart/index.js";
|
|
|
4
4
|
import { archetypeName, parseAkuId } from "./identity.js";
|
|
5
5
|
import { publishAkuma } from "./publication.js";
|
|
6
6
|
import { decodeProviderOptions, decodeReadonlyRestraint } from "./provider-recipe.js";
|
|
7
|
-
import { decodeProviderExecution } from "./providers/index.js";
|
|
7
|
+
import { decodeProviderExecution, resolveProviderExecution } from "./providers/index.js";
|
|
8
8
|
import { requestBodyCommand } from "./request-rendezvous.js";
|
|
9
9
|
import { eraseRequestCommand, } from "./request-wire.js";
|
|
10
10
|
import { z } from "zod";
|
|
@@ -67,6 +67,7 @@ const akumaCallPayloadSchema = z
|
|
|
67
67
|
world: absolutePathSchema,
|
|
68
68
|
archetype: archetypeSchema,
|
|
69
69
|
body: z.string().optional(),
|
|
70
|
+
awaitAsleep: z.literal(true).optional(),
|
|
70
71
|
cwd: absolutePathSchema.optional(),
|
|
71
72
|
recipe: akumaCallRecipeSchema,
|
|
72
73
|
})
|
|
@@ -86,17 +87,24 @@ async function executeAkumaCall(request, facts, capabilities) {
|
|
|
86
87
|
await refuseRequest(paths, facts.id, `request world ${requestWorld} does not match ${world}`);
|
|
87
88
|
throw new Error(`request world ${requestWorld} does not match ${world}`);
|
|
88
89
|
}
|
|
90
|
+
const selected = await resolveProviderExecution(request.recipe.provider);
|
|
91
|
+
const admission = selected.adapter.admitOptions(request.recipe.options);
|
|
92
|
+
if (admission.kind === "refused") {
|
|
93
|
+
await refuseRequest(paths, facts.id, admission.diagnostic);
|
|
94
|
+
throw new Error(admission.diagnostic);
|
|
95
|
+
}
|
|
89
96
|
const recipe = {
|
|
90
97
|
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
91
98
|
allowed: clipAllowedActions(request.recipe.allowed, parent.allowed),
|
|
92
|
-
provider:
|
|
93
|
-
options:
|
|
94
|
-
...(
|
|
99
|
+
provider: selected.execution,
|
|
100
|
+
options: admission.options,
|
|
101
|
+
...(admission.readonly === undefined ? {} : { readonly: admission.readonly }),
|
|
95
102
|
};
|
|
96
103
|
const published = await publishAkuma({
|
|
97
104
|
worldPath: world,
|
|
98
105
|
archetype: request.archetype,
|
|
99
106
|
signal: facts.signal,
|
|
107
|
+
...(request.awaitAsleep === undefined ? {} : { awaitAsleep: request.awaitAsleep }),
|
|
100
108
|
launch: async (allocated) => {
|
|
101
109
|
if (!facts.admissionOpen())
|
|
102
110
|
throw new Error("body closed request admission");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AkumaNotBornError, defaultWaitComplete } from "./akuma.js";
|
|
2
2
|
import { createAkumaProduct } from "./akuma-product.js";
|
|
3
|
-
import { readBudgetedStatus } from "./akuma.js";
|
|
3
|
+
import { readBudgetedStatus, readWaitComplete } from "./akuma-observe.js";
|
|
4
4
|
import { NO_DISPATCH_ASSOCIATION } from "./dispatch-association.js";
|
|
5
5
|
import { EMPTY_CREATED_TASK_OBSERVATION } from "../task/created-observation.js";
|
|
6
6
|
import { fleetResultSchemas, parseAkumaObservation, } from "./fleet-observation.js";
|
|
@@ -45,6 +45,29 @@ async function observeWaitRound(path, ids, signal) {
|
|
|
45
45
|
}
|
|
46
46
|
return { statuses, unobserved };
|
|
47
47
|
}
|
|
48
|
+
async function probeWaitRound(input) {
|
|
49
|
+
let observed = 0;
|
|
50
|
+
let complete = 0;
|
|
51
|
+
for (const id of input.ids) {
|
|
52
|
+
input.signal?.throwIfAborted();
|
|
53
|
+
try {
|
|
54
|
+
if (await readWaitComplete(input.path, id))
|
|
55
|
+
complete += 1;
|
|
56
|
+
observed += 1;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (input.ids.length <= 1 || error instanceof AkumaNotBornError)
|
|
60
|
+
throw error;
|
|
61
|
+
// Plural wait retries unreadable members; final rendering owns diagnostics.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return observed > 0 && (input.completion === "any" ? complete > 0 : complete === input.ids.length);
|
|
65
|
+
}
|
|
66
|
+
function roundComplete(round, completion) {
|
|
67
|
+
const settled = round.statuses.map(defaultWaitComplete);
|
|
68
|
+
return (settled.length > 0 &&
|
|
69
|
+
(completion === "any" ? settled.some(Boolean) : round.unobserved.length === 0 && settled.every(Boolean)));
|
|
70
|
+
}
|
|
48
71
|
function delay(milliseconds, signal) {
|
|
49
72
|
return new Promise((resolve, reject) => {
|
|
50
73
|
let timer;
|
|
@@ -67,16 +90,17 @@ function delay(milliseconds, signal) {
|
|
|
67
90
|
export async function executeWaitAkuma(input) {
|
|
68
91
|
const deadline = input.timeoutMs === undefined ? undefined : performance.now() + input.timeoutMs;
|
|
69
92
|
for (;;) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
if ((deadline !== undefined && performance.now() >= deadline) || (await probeWaitRound(input))) {
|
|
94
|
+
const round = await observeWaitRound(input.path, input.ids, input.signal);
|
|
95
|
+
input.signal?.throwIfAborted();
|
|
96
|
+
// The probe is not a completion receipt. Judge the actual returned values.
|
|
97
|
+
if (roundComplete(round, input.completion) || (deadline !== undefined && performance.now() >= deadline)) {
|
|
98
|
+
return fleetResultSchemas.wait.parse({
|
|
99
|
+
completion: input.completion,
|
|
100
|
+
observations: round.statuses.map(akumaOnlyObservation),
|
|
101
|
+
unobserved: round.unobserved,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
80
104
|
}
|
|
81
105
|
await delay(deadline === undefined ? POLL_MS : Math.min(POLL_MS, Math.max(0, deadline - performance.now())), input.signal);
|
|
82
106
|
}
|
|
@@ -10,6 +10,24 @@ declare const akumaObservationSchema: z.ZodObject<{
|
|
|
10
10
|
asleep: "asleep";
|
|
11
11
|
stranded: "stranded";
|
|
12
12
|
}>;
|
|
13
|
+
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
14
|
+
"task.add": "task.add";
|
|
15
|
+
"task.addDocument": "task.addDocument";
|
|
16
|
+
"task.compose": "task.compose";
|
|
17
|
+
"task.done": "task.done";
|
|
18
|
+
"task.drop": "task.drop";
|
|
19
|
+
"task.hold": "task.hold";
|
|
20
|
+
"task.resume": "task.resume";
|
|
21
|
+
"task.start": "task.start";
|
|
22
|
+
"task.stop": "task.stop";
|
|
23
|
+
"task.update": "task.update";
|
|
24
|
+
"akuma.call": "akuma.call";
|
|
25
|
+
"akuma.kill": "akuma.kill";
|
|
26
|
+
"akuma.tell": "akuma.tell";
|
|
27
|
+
"contract.audit": "contract.audit";
|
|
28
|
+
"contract.deliver": "contract.deliver";
|
|
29
|
+
"contract.review": "contract.review";
|
|
30
|
+
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
13
31
|
readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
14
32
|
enforcement: z.ZodLiteral<"native">;
|
|
15
33
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -446,6 +464,24 @@ declare const akumaWaitResultSchema: z.ZodObject<{
|
|
|
446
464
|
asleep: "asleep";
|
|
447
465
|
stranded: "stranded";
|
|
448
466
|
}>;
|
|
467
|
+
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
468
|
+
"task.add": "task.add";
|
|
469
|
+
"task.addDocument": "task.addDocument";
|
|
470
|
+
"task.compose": "task.compose";
|
|
471
|
+
"task.done": "task.done";
|
|
472
|
+
"task.drop": "task.drop";
|
|
473
|
+
"task.hold": "task.hold";
|
|
474
|
+
"task.resume": "task.resume";
|
|
475
|
+
"task.start": "task.start";
|
|
476
|
+
"task.stop": "task.stop";
|
|
477
|
+
"task.update": "task.update";
|
|
478
|
+
"akuma.call": "akuma.call";
|
|
479
|
+
"akuma.kill": "akuma.kill";
|
|
480
|
+
"akuma.tell": "akuma.tell";
|
|
481
|
+
"contract.audit": "contract.audit";
|
|
482
|
+
"contract.deliver": "contract.deliver";
|
|
483
|
+
"contract.review": "contract.review";
|
|
484
|
+
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
449
485
|
readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
450
486
|
enforcement: z.ZodLiteral<"native">;
|
|
451
487
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -1001,6 +1037,24 @@ export declare const fleetResultSchemas: {
|
|
|
1001
1037
|
asleep: "asleep";
|
|
1002
1038
|
stranded: "stranded";
|
|
1003
1039
|
}>;
|
|
1040
|
+
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
1041
|
+
"task.add": "task.add";
|
|
1042
|
+
"task.addDocument": "task.addDocument";
|
|
1043
|
+
"task.compose": "task.compose";
|
|
1044
|
+
"task.done": "task.done";
|
|
1045
|
+
"task.drop": "task.drop";
|
|
1046
|
+
"task.hold": "task.hold";
|
|
1047
|
+
"task.resume": "task.resume";
|
|
1048
|
+
"task.start": "task.start";
|
|
1049
|
+
"task.stop": "task.stop";
|
|
1050
|
+
"task.update": "task.update";
|
|
1051
|
+
"akuma.call": "akuma.call";
|
|
1052
|
+
"akuma.kill": "akuma.kill";
|
|
1053
|
+
"akuma.tell": "akuma.tell";
|
|
1054
|
+
"contract.audit": "contract.audit";
|
|
1055
|
+
"contract.deliver": "contract.deliver";
|
|
1056
|
+
"contract.review": "contract.review";
|
|
1057
|
+
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
1004
1058
|
readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
1005
1059
|
enforcement: z.ZodLiteral<"native">;
|
|
1006
1060
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -100,7 +100,8 @@ export function fleetRequestProtocol(action) {
|
|
|
100
100
|
decodeResult: (result) => decodedFleetResult(action, result),
|
|
101
101
|
decodeReference: (reference) => decodeFleetService(action, reference),
|
|
102
102
|
isPermitted: (allowed) => action === "akuma.wait" ||
|
|
103
|
-
((action === "akuma.tell" || action === "akuma.tell-answer") && allowed.includes("akuma.tell"))
|
|
103
|
+
((action === "akuma.tell" || action === "akuma.tell-answer") && allowed.includes("akuma.tell")) ||
|
|
104
|
+
(action === "akuma.kill" && allowed.includes("akuma.kill")),
|
|
104
105
|
};
|
|
105
106
|
}
|
|
106
107
|
export function fleetRequestCommand(action, port) {
|
|
@@ -2,7 +2,7 @@ import type { AkumaPaths } from "../identity.js";
|
|
|
2
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
|
-
import { type ActivityFactSlice } from "./timeline.js";
|
|
5
|
+
import { type StatusFactInput, type ActivityFactSlice } from "./timeline.js";
|
|
6
6
|
export { HeartAbsentError, HeldAkumaLeash, classifyHeartSchema, initializeHeart, isHeartAbsent, probeLeash, } from "./storage.js";
|
|
7
7
|
export { admitRequest, beginRequest, isRequestInputConflict, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, unproveRequest, voidRequest, } from "./request-authority.js";
|
|
8
8
|
export { AkumaBusyError, life, lifeAt, projectTell } from "./facts.js";
|
|
@@ -22,6 +22,12 @@ export type ActivitySlice = ActivityFactSlice;
|
|
|
22
22
|
export type { ActivityFact };
|
|
23
23
|
export type { TimelineFact } from "./timeline.js";
|
|
24
24
|
export declare function activitySlice(paths: AkumaPaths): Promise<ActivitySlice>;
|
|
25
|
+
export declare function readStatusFacts(paths: AkumaPaths, input: StatusFactInput): Promise<ActivitySlice["rows"]>;
|
|
26
|
+
type LifeSnapshot = Pick<HeartSnapshot, "soul" | "latestBody" | "latestSession" | "latestKill"> & Readonly<{
|
|
27
|
+
hasPendingTell: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
/** Lifecycle probes do not load narration, Tell bodies, or delivery histories. */
|
|
30
|
+
export declare function readLifeSnapshot(paths: AkumaPaths): Promise<LifeSnapshot>;
|
|
25
31
|
export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequence" | "state" | "deliveries" | "binding">, options?: Readonly<{
|
|
26
32
|
interrupt?: boolean;
|
|
27
33
|
}>): Promise<Readonly<{
|
|
@@ -43,29 +49,17 @@ export declare function decidePendingTellDisposition(paths: AkumaPaths, input: R
|
|
|
43
49
|
handoff: boolean;
|
|
44
50
|
}>): Promise<PendingTellDisposition | null>;
|
|
45
51
|
export declare function readOpenPendingTellDisposition(paths: AkumaPaths): Promise<PendingTellDisposition | null>;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
* Heart-owned disposition custody proof. Sequence growth, spawn resolution, and
|
|
49
|
-
* an unqualified held leash are never proof. Returns the successor Body sequence
|
|
50
|
-
* when that exact Body took the frozen Tell-id snapshot by delivery, or true when
|
|
51
|
-
* the snapshot is already fully settled (no longer pending).
|
|
52
|
-
*/
|
|
53
|
-
export declare function provePendingTellDispositionCustody(paths: AkumaPaths, disposition: PendingTellDisposition): Promise<Readonly<{
|
|
54
|
-
kind: "proven";
|
|
55
|
-
successorBodySequence?: number;
|
|
56
|
-
} | {
|
|
57
|
-
kind: "unproven";
|
|
58
|
-
}>>;
|
|
59
|
-
export declare function recordUndeliveredPendingTells(paths: AkumaPaths, at: string, tellIds: readonly string[]): Promise<void>;
|
|
52
|
+
/** Prove and consume the persisted decision in one transaction, never a caller's stale member list. */
|
|
53
|
+
export declare function resolvePendingTellDisposition(paths: AkumaPaths, bodySequence: number, at: string, outcome?: "custody" | "undelivered"): Promise<boolean>;
|
|
60
54
|
export declare function readKill(paths: AkumaPaths, bodySequence: number): Promise<KillFact | null>;
|
|
61
|
-
export declare function requestStop(paths: AkumaPaths, at: string): Promise<Readonly<{
|
|
55
|
+
export declare function requestStop(paths: AkumaPaths, at: string, signal?: AbortSignal): Promise<Readonly<{
|
|
62
56
|
kind: "requested";
|
|
63
57
|
body: BodyFact;
|
|
64
58
|
}> | Readonly<{
|
|
65
59
|
kind: "already-killed" | "already-stopped";
|
|
66
60
|
body: BodyFact;
|
|
67
61
|
}>>;
|
|
68
|
-
export declare function requestPause(paths: AkumaPaths, at: string): Promise<Readonly<{
|
|
62
|
+
export declare function requestPause(paths: AkumaPaths, at: string, signal?: AbortSignal): Promise<Readonly<{
|
|
69
63
|
kind: "not-born";
|
|
70
64
|
} | {
|
|
71
65
|
kind: "requested";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { parsePublicHistoryId } from "../identity.js";
|
|
2
2
|
import { answeredTurnFact, endBodyFact, finishBodyFact, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, turnFact, } from "./rows.js";
|
|
3
|
-
import { insertTellDeliveryFact, dispositionSnapshotProven, insertTellBindingFact, insertTellDispositionSnapshot, insertTellFact, insertTellReceiptFact, insertUndeliveredTellReceipts, latestOpenTellDisposition, openBoundTurns, openTellDispositionIds, pendingTellFacts, resolveTellDispositionSnapshot,
|
|
4
|
-
import { activityFactSlice, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
|
|
5
|
-
import { isHeartAbsent, readSealFromLeash,
|
|
3
|
+
import { insertTellDeliveryFact, dispositionSnapshotProven, insertTellBindingFact, insertTellDispositionSnapshot, insertTellFact, insertTellReceiptFact, insertUndeliveredTellReceipts, latestOpenTellDisposition, openBoundTurns, openTellDispositionIds, pendingTellFacts, hasPendingTell, resolveTellDispositionSnapshot, tellDispositionResolved, tellFact, tellIdsForFence, } from "./tells.js";
|
|
4
|
+
import { activityFactSlice, statusFacts, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
|
|
5
|
+
import { isHeartAbsent, readSealFromLeash, withHeartTransaction, withReadOnlyHeart } from "./storage.js";
|
|
6
6
|
import { soulFact } from "./soul.js";
|
|
7
|
-
import { AkumaBusyError } from "./facts.js";
|
|
7
|
+
import { AkumaBusyError, HeartAuthorityCorruptionError } from "./facts.js";
|
|
8
8
|
export { HeartAbsentError, HeldAkumaLeash, classifyHeartSchema, initializeHeart, isHeartAbsent, probeLeash, } from "./storage.js";
|
|
9
9
|
export { admitRequest, beginRequest, isRequestInputConflict, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, unproveRequest, voidRequest, } from "./request-authority.js";
|
|
10
10
|
export { AkumaBusyError, life, lifeAt, projectTell } from "./facts.js";
|
|
@@ -12,7 +12,7 @@ export { drainPendingTells } from "./tells.js";
|
|
|
12
12
|
const ACTIVITY_LIMIT = 5_000;
|
|
13
13
|
export async function readSoul(paths) {
|
|
14
14
|
try {
|
|
15
|
-
return await
|
|
15
|
+
return await withReadOnlyHeart(paths, soulFact);
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
18
18
|
if (isHeartAbsent(error))
|
|
@@ -22,7 +22,7 @@ export async function readSoul(paths) {
|
|
|
22
22
|
}
|
|
23
23
|
export async function heartExists(paths) {
|
|
24
24
|
try {
|
|
25
|
-
return await
|
|
25
|
+
return await withReadOnlyHeart(paths, () => true);
|
|
26
26
|
}
|
|
27
27
|
catch (error) {
|
|
28
28
|
if (isHeartAbsent(error))
|
|
@@ -41,23 +41,43 @@ export async function readSeal(paths) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
export async function recordSession(paths, input) {
|
|
44
|
-
return await
|
|
44
|
+
return await withHeartTransaction(paths, (heart) => ({ sequence: insertSessionFact(heart, input), ...input }));
|
|
45
45
|
}
|
|
46
46
|
export async function appendActivity(paths, input) {
|
|
47
|
-
return await
|
|
47
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
48
48
|
const sequence = insertActivityFact(heart, input);
|
|
49
49
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
50
50
|
return sequence;
|
|
51
|
-
})
|
|
51
|
+
});
|
|
52
52
|
}
|
|
53
53
|
export async function activitySlice(paths) {
|
|
54
|
-
return await
|
|
54
|
+
return await withReadOnlyHeart(paths, (heart) => activityFactSlice(heart));
|
|
55
|
+
}
|
|
56
|
+
export async function readStatusFacts(paths, input) {
|
|
57
|
+
return await withReadOnlyHeart(paths, (heart) => statusFacts(heart, input));
|
|
58
|
+
}
|
|
59
|
+
/** Lifecycle probes do not load narration, Tell bodies, or delivery histories. */
|
|
60
|
+
export async function readLifeSnapshot(paths) {
|
|
61
|
+
try {
|
|
62
|
+
return await withReadOnlyHeart(paths, (heart) => ({
|
|
63
|
+
soul: soulFact(heart),
|
|
64
|
+
latestBody: latestBodyFact(heart),
|
|
65
|
+
latestSession: latestSessionFact(heart),
|
|
66
|
+
latestKill: latestKillFact(heart),
|
|
67
|
+
hasPendingTell: hasPendingTell(heart),
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (isHeartAbsent(error))
|
|
72
|
+
return { soul: null, latestBody: null, latestSession: null, latestKill: null, hasPendingTell: false };
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
55
75
|
}
|
|
56
76
|
function sameTellInput(existing, tell) {
|
|
57
77
|
return (existing.body === tell.body && existing.recordedAt === tell.recordedAt && existing.schemaJson === tell.schemaJson);
|
|
58
78
|
}
|
|
59
79
|
export async function recordTell(paths, tell, options = {}) {
|
|
60
|
-
return await
|
|
80
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
61
81
|
if (soulFact(heart) === null)
|
|
62
82
|
return { kind: "not-born" };
|
|
63
83
|
const existing = tellFact(heart, tell.id);
|
|
@@ -73,37 +93,40 @@ export async function recordTell(paths, tell, options = {}) {
|
|
|
73
93
|
const sequence = insertTellFact(heart, tell);
|
|
74
94
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
75
95
|
return { kind: "recorded", tell: { sequence, ...tell, state: "pending", deliveries: [] } };
|
|
76
|
-
})
|
|
96
|
+
});
|
|
77
97
|
}
|
|
78
98
|
export async function readTell(paths, id) {
|
|
79
|
-
return await
|
|
99
|
+
return await withReadOnlyHeart(paths, (heart) => tellFact(heart, id));
|
|
80
100
|
}
|
|
81
101
|
export async function recordTellDeliveries(paths, inputs) {
|
|
82
|
-
await
|
|
102
|
+
await withHeartTransaction(paths, (heart) => {
|
|
83
103
|
for (const input of inputs) {
|
|
84
104
|
const current = tellFact(heart, input.tellId);
|
|
85
105
|
if (current === null)
|
|
86
106
|
throw new Error(`unknown tell ${input.tellId}`);
|
|
87
107
|
}
|
|
108
|
+
let changed = false;
|
|
88
109
|
for (const input of inputs)
|
|
89
|
-
insertTellDeliveryFact(heart, input);
|
|
90
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
91
|
-
})
|
|
110
|
+
changed = insertTellDeliveryFact(heart, input) || changed;
|
|
111
|
+
pruneActivityFacts(heart, ACTIVITY_LIMIT, changed);
|
|
112
|
+
});
|
|
92
113
|
}
|
|
93
114
|
export async function recordTellReceipt(paths, input) {
|
|
94
|
-
await
|
|
115
|
+
await withHeartTransaction(paths, (heart) => {
|
|
95
116
|
const tellIds = input.evidence === "exact" ? [input.tellId] : tellIdsForFence(heart, input.turnSequence, input.fence);
|
|
96
117
|
if (tellIds.length === 0)
|
|
97
118
|
throw new Error("tell receipt has no delivery mapping");
|
|
98
|
-
insertTellReceiptFact(heart, input);
|
|
99
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
100
|
-
})
|
|
119
|
+
const changed = insertTellReceiptFact(heart, input);
|
|
120
|
+
pruneActivityFacts(heart, ACTIVITY_LIMIT, changed);
|
|
121
|
+
});
|
|
101
122
|
}
|
|
102
123
|
export async function decidePendingTellDisposition(paths, input) {
|
|
103
|
-
return await
|
|
124
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
104
125
|
const body = latestBodyFact(heart);
|
|
105
126
|
if (body === null || body.sequence !== input.bodySequence)
|
|
106
127
|
return null;
|
|
128
|
+
if (tellDispositionResolved(heart, input.bodySequence) === true)
|
|
129
|
+
return null;
|
|
107
130
|
const existing = openTellDispositionIds(heart, input.bodySequence);
|
|
108
131
|
if (existing !== null)
|
|
109
132
|
return { bodySequence: input.bodySequence, tellIds: existing };
|
|
@@ -122,46 +145,33 @@ export async function decidePendingTellDisposition(paths, input) {
|
|
|
122
145
|
insertTellDispositionSnapshot(heart, input.bodySequence, tellIds, input.at);
|
|
123
146
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
124
147
|
return { bodySequence: input.bodySequence, tellIds };
|
|
125
|
-
})
|
|
148
|
+
});
|
|
126
149
|
}
|
|
127
150
|
export async function readOpenPendingTellDisposition(paths) {
|
|
128
|
-
return await
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
151
|
+
return await withReadOnlyHeart(paths, (heart) => latestOpenTellDisposition(heart));
|
|
152
|
+
}
|
|
153
|
+
/** Prove and consume the persisted decision in one transaction, never a caller's stale member list. */
|
|
154
|
+
export async function resolvePendingTellDisposition(paths, bodySequence, at, outcome = "custody") {
|
|
155
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
156
|
+
if (tellDispositionResolved(heart, bodySequence) === true)
|
|
157
|
+
return true;
|
|
158
|
+
const tellIds = openTellDispositionIds(heart, bodySequence);
|
|
159
|
+
if (tellIds === null)
|
|
160
|
+
throw new HeartAuthorityCorruptionError(`Akuma disposition ${bodySequence} is missing`);
|
|
161
|
+
if (outcome === "undelivered")
|
|
162
|
+
insertUndeliveredTellReceipts(heart, tellIds, at);
|
|
163
|
+
if (!dispositionSnapshotProven(heart, tellIds))
|
|
164
|
+
return false;
|
|
132
165
|
resolveTellDispositionSnapshot(heart, bodySequence, at);
|
|
133
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Heart-owned disposition custody proof. Sequence growth, spawn resolution, and
|
|
138
|
-
* an unqualified held leash are never proof. Returns the successor Body sequence
|
|
139
|
-
* when that exact Body took the frozen Tell-id snapshot by delivery, or true when
|
|
140
|
-
* the snapshot is already fully settled (no longer pending).
|
|
141
|
-
*/
|
|
142
|
-
export async function provePendingTellDispositionCustody(paths, disposition) {
|
|
143
|
-
return await withHeart(paths, (heart) => readTransaction(heart, () => {
|
|
144
|
-
if (!dispositionSnapshotProven(heart, disposition))
|
|
145
|
-
return { kind: "unproven" };
|
|
146
|
-
const successorBodySequence = successorBodyHoldingDisposition(heart, disposition);
|
|
147
|
-
return successorBodySequence === null
|
|
148
|
-
? { kind: "proven" }
|
|
149
|
-
: { kind: "proven", successorBodySequence };
|
|
150
|
-
}));
|
|
151
|
-
}
|
|
152
|
-
export async function recordUndeliveredPendingTells(paths, at, tellIds) {
|
|
153
|
-
if (tellIds.length === 0)
|
|
154
|
-
return;
|
|
155
|
-
await withHeart(paths, (heart) => transaction(heart, () => {
|
|
156
|
-
insertUndeliveredTellReceipts(heart, tellIds, at);
|
|
157
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
158
|
-
}));
|
|
166
|
+
pruneActivityFacts(heart, ACTIVITY_LIMIT, true);
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
159
169
|
}
|
|
160
170
|
export async function readKill(paths, bodySequence) {
|
|
161
|
-
return await
|
|
171
|
+
return await withReadOnlyHeart(paths, (heart) => killFactForBody(heart, bodySequence));
|
|
162
172
|
}
|
|
163
|
-
export async function requestStop(paths, at) {
|
|
164
|
-
return await
|
|
173
|
+
export async function requestStop(paths, at, signal) {
|
|
174
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
165
175
|
const body = latestBodyFact(heart);
|
|
166
176
|
if (body === null)
|
|
167
177
|
throw new Error("Akuma has no Body to kill");
|
|
@@ -175,10 +185,10 @@ export async function requestStop(paths, at) {
|
|
|
175
185
|
}
|
|
176
186
|
insertStopControl(heart, body.sequence, at);
|
|
177
187
|
return { kind: "requested", body };
|
|
178
|
-
})
|
|
188
|
+
}, signal);
|
|
179
189
|
}
|
|
180
|
-
export async function requestPause(paths, at) {
|
|
181
|
-
return await
|
|
190
|
+
export async function requestPause(paths, at, signal) {
|
|
191
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
182
192
|
if (soulFact(heart) === null)
|
|
183
193
|
return { kind: "not-born" };
|
|
184
194
|
const body = latestBodyFact(heart);
|
|
@@ -186,45 +196,45 @@ export async function requestPause(paths, at) {
|
|
|
186
196
|
throw new Error("Akuma has no Body to interrupt");
|
|
187
197
|
insertPauseControl(heart, at);
|
|
188
198
|
return { kind: "requested", body };
|
|
189
|
-
})
|
|
199
|
+
}, signal);
|
|
190
200
|
}
|
|
191
201
|
export async function stopRequested(paths, bodySequence) {
|
|
192
|
-
return await
|
|
202
|
+
return await withReadOnlyHeart(paths, (heart) => {
|
|
193
203
|
const target = stopFact(heart);
|
|
194
204
|
return target !== null && (bodySequence === undefined || target.bodySequence === bodySequence);
|
|
195
205
|
});
|
|
196
206
|
}
|
|
197
207
|
export async function pauseRequested(paths, bodySequence) {
|
|
198
|
-
return await
|
|
208
|
+
return await withReadOnlyHeart(paths, (heart) => {
|
|
199
209
|
const target = pauseFact(heart);
|
|
200
210
|
return target !== null && (bodySequence === undefined || target.bodySequence === bodySequence);
|
|
201
211
|
});
|
|
202
212
|
}
|
|
203
213
|
export async function breakBody(paths, input) {
|
|
204
|
-
await
|
|
214
|
+
await withHeartTransaction(paths, (heart) => endBodyFact(heart, input));
|
|
205
215
|
}
|
|
206
216
|
export async function beginTurn(paths, input) {
|
|
207
|
-
return await
|
|
217
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
208
218
|
const fact = insertTurnStartFact(heart, input);
|
|
209
219
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
210
220
|
return fact;
|
|
211
|
-
})
|
|
221
|
+
});
|
|
212
222
|
}
|
|
213
223
|
export async function bindTellsToTurn(paths, input) {
|
|
214
|
-
await
|
|
224
|
+
await withHeartTransaction(paths, (heart) => {
|
|
215
225
|
for (const tellId of input.tellIds) {
|
|
216
226
|
if (tellFact(heart, tellId) === null)
|
|
217
227
|
throw new Error(`unknown tell ${tellId}`);
|
|
218
228
|
insertTellBindingFact(heart, { tellId, turnSequence: input.turnSequence, boundAt: input.boundAt });
|
|
219
229
|
}
|
|
220
230
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
221
|
-
})
|
|
231
|
+
});
|
|
222
232
|
}
|
|
223
233
|
export async function readOpenBoundTurns(paths, bodySequence) {
|
|
224
|
-
return await
|
|
234
|
+
return await withReadOnlyHeart(paths, (heart) => openBoundTurns(heart, bodySequence));
|
|
225
235
|
}
|
|
226
236
|
export async function failOpenBoundTurns(paths, input) {
|
|
227
|
-
return await
|
|
237
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
228
238
|
const sequences = openBoundTurns(heart, input.bodySequence);
|
|
229
239
|
for (const turnSequence of sequences) {
|
|
230
240
|
insertTurnEndFact(heart, {
|
|
@@ -234,22 +244,22 @@ export async function failOpenBoundTurns(paths, input) {
|
|
|
234
244
|
completedAt: input.completedAt,
|
|
235
245
|
});
|
|
236
246
|
}
|
|
237
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
247
|
+
pruneActivityFacts(heart, ACTIVITY_LIMIT, sequences.length > 0);
|
|
238
248
|
return sequences;
|
|
239
|
-
})
|
|
249
|
+
});
|
|
240
250
|
}
|
|
241
251
|
export async function readTurn(paths, sequence) {
|
|
242
|
-
return await
|
|
252
|
+
return await withReadOnlyHeart(paths, (heart) => turnFact(heart, sequence));
|
|
243
253
|
}
|
|
244
254
|
export async function endTurn(paths, input) {
|
|
245
|
-
return await
|
|
255
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
246
256
|
const fact = insertTurnEndFact(heart, { kind: "turn-end", ...input });
|
|
247
|
-
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
257
|
+
pruneActivityFacts(heart, ACTIVITY_LIMIT, true);
|
|
248
258
|
return fact;
|
|
249
|
-
})
|
|
259
|
+
});
|
|
250
260
|
}
|
|
251
261
|
export async function finishBodyIfIdle(paths, input) {
|
|
252
|
-
return await
|
|
262
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
253
263
|
if (stopFact(heart)?.bodySequence === input.sequence || pauseFact(heart)?.bodySequence === input.sequence) {
|
|
254
264
|
endBodyFact(heart, { ...input, end: "put-down" });
|
|
255
265
|
return { kind: "controlled" };
|
|
@@ -259,11 +269,11 @@ export async function finishBodyIfIdle(paths, input) {
|
|
|
259
269
|
return { kind: "pending", tells: pending.map((tell) => tell.id) };
|
|
260
270
|
finishBodyFact(heart, input);
|
|
261
271
|
return { kind: "finished" };
|
|
262
|
-
})
|
|
272
|
+
});
|
|
263
273
|
}
|
|
264
274
|
export async function readHeart(paths) {
|
|
265
275
|
try {
|
|
266
|
-
return await withReadOnlyHeart(paths, (heart) =>
|
|
276
|
+
return await withReadOnlyHeart(paths, (heart) => ({
|
|
267
277
|
soul: soulFact(heart),
|
|
268
278
|
latestBody: latestBodyFact(heart),
|
|
269
279
|
latestSession: latestSessionFact(heart),
|
|
@@ -272,7 +282,7 @@ export async function readHeart(paths) {
|
|
|
272
282
|
stop: stopFact(heart),
|
|
273
283
|
pause: pauseFact(heart),
|
|
274
284
|
lastActivityAt: readLastActivityAt(heart),
|
|
275
|
-
}))
|
|
285
|
+
}));
|
|
276
286
|
}
|
|
277
287
|
catch (error) {
|
|
278
288
|
if (isHeartAbsent(error)) {
|
|
@@ -291,14 +301,14 @@ export async function readHeart(paths) {
|
|
|
291
301
|
}
|
|
292
302
|
}
|
|
293
303
|
export async function readLastAnsweredTurn(paths) {
|
|
294
|
-
return await
|
|
304
|
+
return await withReadOnlyHeart(paths, lastAnsweredTurnFact);
|
|
295
305
|
}
|
|
296
306
|
export async function readForkPoint(paths, historyId) {
|
|
297
307
|
const turnSequence = parsePublicHistoryId(historyId);
|
|
298
308
|
if (turnSequence === null)
|
|
299
309
|
return null;
|
|
300
310
|
try {
|
|
301
|
-
return await
|
|
311
|
+
return await withReadOnlyHeart(paths, (heart) => {
|
|
302
312
|
const turn = answeredTurnFact(heart, turnSequence);
|
|
303
313
|
const outcome = turn?.end?.outcome;
|
|
304
314
|
if (outcome?.kind !== "answered" || outcome.historyId === undefined)
|