@astrosheep/keiyaku 4.5.7 → 4.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- 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/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +10 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +372 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/body.d.ts +6 -4
- package/build/src/akuma/body.js +5 -3
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +6 -78
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +856 -137
- package/build/src/akuma/projection.js +190 -0
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +104 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.js +1 -1
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +42 -14
- package/build/src/akuma/request-lifecycle.d.ts +3 -9
- package/build/src/akuma/request-lifecycle.js +4 -4
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +5 -65
- package/build/src/akuma/request-serve.js +81 -208
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +32 -10
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +7 -7
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +26 -19
- package/build/src/cli/commands/contract.d.ts +13 -13
- package/build/src/cli/commands/contract.js +32 -17
- 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-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +37 -22
- package/build/src/cli/render/akuma-activity.d.ts +4 -1
- package/build/src/cli/render/akuma-activity.js +45 -30
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +5 -9
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +25 -65
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +111 -0
- package/build/src/cli/render/kanshi.js +108 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +28 -0
- package/build/src/cli/render/terminal.js +65 -0
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +3 -1
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +36 -18
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +19 -7
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +11 -0
- package/build/src/git/reconcile.js +64 -11
- package/build/src/git/repository.d.ts +6 -2
- package/build/src/git/repository.js +8 -0
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +1 -1
- package/build/src/library/audit.js +5 -3
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +371 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +96 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +83 -0
- package/build/src/library/contract-forwarding-result.d.ts +6723 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +72 -0
- package/build/src/library/contract-forwarding.js +125 -0
- package/build/src/library/contract-handle.d.ts +36 -0
- package/build/src/library/contract-handle.js +313 -0
- package/build/src/library/contract-operations.d.ts +1044 -67
- package/build/src/library/contract-operations.js +190 -118
- package/build/src/library/contract.d.ts +11 -32
- package/build/src/library/contract.js +16 -289
- package/build/src/library/fleet-result.d.ts +1454 -0
- package/build/src/library/fleet-result.js +96 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +4 -0
- package/build/src/library/keiyaku.d.ts +371 -20
- package/build/src/library/keiyaku.js +8 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +8 -0
- package/build/src/runtime/proc/run.js +27 -0
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- package/build/src/akuma/request-execution.js +0 -98
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
import { clipAllowedActions, decodeAllowedActions } from "./allowed.js";
|
|
3
|
+
import { refuseRequest, reserveRequest } from "./heart/index.js";
|
|
4
|
+
import { archetypeName, parseAkuId } from "./identity.js";
|
|
5
|
+
import { publishAkuma } from "./publication.js";
|
|
6
|
+
import { decodeProviderOptions, decodeReadonlyRestraint } from "./provider-recipe.js";
|
|
7
|
+
import { decodeProviderExecution } from "./providers/index.js";
|
|
8
|
+
import { requestBodyCommand } from "./request-rendezvous.js";
|
|
9
|
+
import { eraseRequestCommand } from "./request-wire.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { World } from "../world.js";
|
|
12
|
+
function schemaDecode(decode, message) {
|
|
13
|
+
return z.unknown().transform((value, context) => {
|
|
14
|
+
try {
|
|
15
|
+
return decode(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
context.addIssue({ code: "custom", message });
|
|
19
|
+
return z.NEVER;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const absolutePathSchema = z.string().refine((value) => isAbsolute(value) && resolve(value) === value);
|
|
24
|
+
const akuIdSchema = z.string().transform((value, context) => {
|
|
25
|
+
try {
|
|
26
|
+
const id = parseAkuId(value).id;
|
|
27
|
+
if (id !== value) {
|
|
28
|
+
context.addIssue({ code: "custom", message: "expected canonical AkuId" });
|
|
29
|
+
return z.NEVER;
|
|
30
|
+
}
|
|
31
|
+
return id;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
context.addIssue({ code: "custom", message: "expected canonical AkuId" });
|
|
35
|
+
return z.NEVER;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const archetypeSchema = z.string().transform((value, context) => {
|
|
39
|
+
try {
|
|
40
|
+
return archetypeName(value);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
context.addIssue({ code: "custom", message: "expected archetype" });
|
|
44
|
+
return z.NEVER;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const allowedActionsSchema = schemaDecode(decodeAllowedActions, "expected allowed actions");
|
|
48
|
+
const providerExecutionSchema = schemaDecode(decodeProviderExecution, "expected provider execution");
|
|
49
|
+
const providerOptionsSchema = schemaDecode(decodeProviderOptions, "expected provider options");
|
|
50
|
+
const readonlyRestraintSchema = schemaDecode(decodeReadonlyRestraint, "expected readonly restraint");
|
|
51
|
+
const akumaCallRecipeSchema = z
|
|
52
|
+
.object({
|
|
53
|
+
description: z.string().trim().min(1).optional(),
|
|
54
|
+
allowed: allowedActionsSchema,
|
|
55
|
+
provider: providerExecutionSchema,
|
|
56
|
+
options: providerOptionsSchema,
|
|
57
|
+
readonly: readonlyRestraintSchema.optional(),
|
|
58
|
+
})
|
|
59
|
+
.strict()
|
|
60
|
+
.superRefine((recipe, context) => {
|
|
61
|
+
if ((recipe.options.readonly === true) !== (recipe.readonly !== undefined)) {
|
|
62
|
+
context.addIssue({ code: "custom", message: "readonly recipe fields disagree" });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const akumaCallPayloadSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
world: absolutePathSchema,
|
|
68
|
+
archetype: archetypeSchema,
|
|
69
|
+
body: z.string(),
|
|
70
|
+
cwd: absolutePathSchema.optional(),
|
|
71
|
+
recipe: akumaCallRecipeSchema,
|
|
72
|
+
})
|
|
73
|
+
.strict();
|
|
74
|
+
function carriesLaunchWorld(value) {
|
|
75
|
+
const upstream = object(value);
|
|
76
|
+
return upstream !== null && typeof upstream.launchWorld === "function";
|
|
77
|
+
}
|
|
78
|
+
function decodeCallExecutionContext(value) {
|
|
79
|
+
const context = object(value);
|
|
80
|
+
const paths = object(context?.paths);
|
|
81
|
+
const parent = object(context?.parent);
|
|
82
|
+
const parentId = akuIdSchema.safeParse(parent?.id);
|
|
83
|
+
if (context === null ||
|
|
84
|
+
typeof context.id !== "string" ||
|
|
85
|
+
context.id.trim() === "" ||
|
|
86
|
+
typeof context.requester !== "string" ||
|
|
87
|
+
typeof context.signal !== "object" ||
|
|
88
|
+
context.signal === null ||
|
|
89
|
+
typeof context.signal.throwIfAborted !== "function" ||
|
|
90
|
+
paths === null ||
|
|
91
|
+
!["directory", "heart", "leash", "log", "requests"].every((key) => typeof paths[key] === "string") ||
|
|
92
|
+
parent === null ||
|
|
93
|
+
!parentId.success ||
|
|
94
|
+
typeof parent.cwd !== "string" ||
|
|
95
|
+
!Array.isArray(parent.allowed) ||
|
|
96
|
+
typeof context.spawn !== "function" ||
|
|
97
|
+
typeof context.admissionOpen !== "function")
|
|
98
|
+
throw new Error("invalid Akuma call execution context");
|
|
99
|
+
if (!carriesLaunchWorld(context.upstream))
|
|
100
|
+
throw new Error("Akuma call requires a minted launch World");
|
|
101
|
+
return {
|
|
102
|
+
id: context.id,
|
|
103
|
+
requester: context.requester,
|
|
104
|
+
signal: context.signal,
|
|
105
|
+
world: context.upstream.launchWorld(),
|
|
106
|
+
paths: context.paths,
|
|
107
|
+
parent: context.parent,
|
|
108
|
+
spawn: context.spawn,
|
|
109
|
+
admissionOpen: context.admissionOpen,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function object(value) {
|
|
113
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
114
|
+
? value
|
|
115
|
+
: null;
|
|
116
|
+
}
|
|
117
|
+
export function decodeAkumaCallRequest(value) {
|
|
118
|
+
const parsed = akumaCallPayloadSchema.safeParse(value);
|
|
119
|
+
return parsed.success ? { ...parsed.data, action: "akuma.call" } : null;
|
|
120
|
+
}
|
|
121
|
+
function callPayload(request) {
|
|
122
|
+
const { action: _action, ...payload } = request;
|
|
123
|
+
return payload;
|
|
124
|
+
}
|
|
125
|
+
async function executeAkumaCall(request, context) {
|
|
126
|
+
const world = context.world;
|
|
127
|
+
const requestWorld = await World.prove(request.world);
|
|
128
|
+
if (requestWorld !== world) {
|
|
129
|
+
await refuseRequest(context.paths, context.id, `request world ${requestWorld} does not match ${world}`);
|
|
130
|
+
throw new Error(`request world ${requestWorld} does not match ${world}`);
|
|
131
|
+
}
|
|
132
|
+
const recipe = {
|
|
133
|
+
...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
|
|
134
|
+
allowed: clipAllowedActions(request.recipe.allowed, context.parent.allowed),
|
|
135
|
+
provider: request.recipe.provider,
|
|
136
|
+
options: request.recipe.options,
|
|
137
|
+
...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
|
|
138
|
+
};
|
|
139
|
+
const published = await publishAkuma({
|
|
140
|
+
worldPath: world,
|
|
141
|
+
archetype: request.archetype,
|
|
142
|
+
signal: context.signal,
|
|
143
|
+
launch: async (allocated) => {
|
|
144
|
+
if (!context.admissionOpen())
|
|
145
|
+
throw new Error("body closed request admission");
|
|
146
|
+
await reserveRequest(context.paths, context.id, allocated.id);
|
|
147
|
+
return await context.spawn({
|
|
148
|
+
paths: allocated.paths,
|
|
149
|
+
seed: {
|
|
150
|
+
id: allocated.id,
|
|
151
|
+
archetype: allocated.archetype,
|
|
152
|
+
...recipe,
|
|
153
|
+
cwd: request.cwd ?? context.parent.cwd,
|
|
154
|
+
origin: { kind: "request", parent: context.parent.id, requestId: context.id },
|
|
155
|
+
},
|
|
156
|
+
initialBody: request.body,
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
return { result: published.id, child: published.id };
|
|
161
|
+
}
|
|
162
|
+
export function akumaCallRequestCommand() {
|
|
163
|
+
return {
|
|
164
|
+
action: "akuma.call",
|
|
165
|
+
encodeRequest: callPayload,
|
|
166
|
+
decodeRequest: decodeAkumaCallRequest,
|
|
167
|
+
encodeResult: (result) => result,
|
|
168
|
+
decodeResult: (result) => {
|
|
169
|
+
const child = akuIdSchema.safeParse(result);
|
|
170
|
+
if (!child.success)
|
|
171
|
+
throw new Error("Akuma call returned an invalid child");
|
|
172
|
+
return child.data;
|
|
173
|
+
},
|
|
174
|
+
encodeService: (service) => service,
|
|
175
|
+
decodeService: (_service) => {
|
|
176
|
+
throw new Error("Akuma call has no service evidence");
|
|
177
|
+
},
|
|
178
|
+
projectService: (_service) => {
|
|
179
|
+
throw new Error("Akuma call has no service evidence");
|
|
180
|
+
},
|
|
181
|
+
projectChild: (child) => {
|
|
182
|
+
const id = akuIdSchema.safeParse(child);
|
|
183
|
+
if (!id.success)
|
|
184
|
+
throw new Error("Akuma call stored an invalid child reference");
|
|
185
|
+
return id.data;
|
|
186
|
+
},
|
|
187
|
+
decodeReference: (reference) => {
|
|
188
|
+
const child = akuIdSchema.safeParse(reference);
|
|
189
|
+
if (!child.success)
|
|
190
|
+
throw new Error("Akuma call stored an invalid child reference");
|
|
191
|
+
return child.data;
|
|
192
|
+
},
|
|
193
|
+
isPermitted: (allowed) => allowed.includes("akuma.call"),
|
|
194
|
+
decodeExecutionContext: decodeCallExecutionContext,
|
|
195
|
+
execute: executeAkumaCall,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
export function akumaCallRequestCommands() {
|
|
199
|
+
return { "akuma.call": eraseRequestCommand(akumaCallRequestCommand()) };
|
|
200
|
+
}
|
|
201
|
+
export async function requestForwardedAkumaCall(input) {
|
|
202
|
+
const { directory, id, signal, ...request } = input;
|
|
203
|
+
const response = await requestBodyCommand({
|
|
204
|
+
directory,
|
|
205
|
+
id,
|
|
206
|
+
command: akumaCallRequestCommand(),
|
|
207
|
+
value: { ...request, action: "akuma.call" },
|
|
208
|
+
...(signal === undefined ? {} : { signal }),
|
|
209
|
+
});
|
|
210
|
+
return response.kind === "returned" ? response.result : response.reference;
|
|
211
|
+
}
|
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
export type { ResumeCoordinate } from "../coordinate.js";
|
|
7
6
|
export type AkumaOrigin = Readonly<{
|
|
8
7
|
kind: "direct";
|
|
@@ -123,75 +122,10 @@ export type TellReceiptInput = Readonly<{
|
|
|
123
122
|
turnSequence: number;
|
|
124
123
|
fence: string;
|
|
125
124
|
}>);
|
|
126
|
-
export type TaskRequestInput = Readonly<{
|
|
127
|
-
id: string;
|
|
128
|
-
action: TaskMutationAction;
|
|
129
|
-
world: string;
|
|
130
|
-
request: TaskMutationRequest;
|
|
131
|
-
}>;
|
|
132
125
|
export type RequestInput = Readonly<{
|
|
133
126
|
id: string;
|
|
134
|
-
action:
|
|
135
|
-
|
|
136
|
-
body: string;
|
|
137
|
-
cwd?: string;
|
|
138
|
-
world: string;
|
|
139
|
-
recipe: RequestRecipe;
|
|
140
|
-
}> | Readonly<{
|
|
141
|
-
id: string;
|
|
142
|
-
action: "akuma.wait";
|
|
143
|
-
targets: readonly AkuId[];
|
|
144
|
-
completion: "any" | "all";
|
|
145
|
-
timeoutMs?: number;
|
|
146
|
-
}> | Readonly<{
|
|
147
|
-
id: string;
|
|
148
|
-
action: "akuma.tell";
|
|
149
|
-
target: AkuId;
|
|
150
|
-
body: string;
|
|
151
|
-
}> | Readonly<{
|
|
152
|
-
id: string;
|
|
153
|
-
action: "akuma.kill";
|
|
154
|
-
targets: readonly AkuId[];
|
|
155
|
-
}> | Readonly<{
|
|
156
|
-
id: string;
|
|
157
|
-
action: "contract.deliver";
|
|
158
|
-
repoRoot: string;
|
|
159
|
-
contractId: string;
|
|
160
|
-
message?: string;
|
|
161
|
-
includeDirty: boolean;
|
|
162
|
-
materializeConflict: boolean;
|
|
163
|
-
}> | Readonly<{
|
|
164
|
-
id: string;
|
|
165
|
-
action: "contract.review";
|
|
166
|
-
repoRoot: string;
|
|
167
|
-
contractId: string;
|
|
168
|
-
verdict: "satisfied" | "unsatisfied";
|
|
169
|
-
summary?: string;
|
|
170
|
-
}> | TaskRequestInput;
|
|
171
|
-
export type UpstreamRequestService = Readonly<{
|
|
172
|
-
action: "akuma.wait";
|
|
173
|
-
}> | Readonly<{
|
|
174
|
-
action: "akuma.tell";
|
|
175
|
-
target: AkuId;
|
|
176
|
-
tellId: string;
|
|
177
|
-
}> | Readonly<{
|
|
178
|
-
action: "akuma.kill";
|
|
179
|
-
results: readonly Readonly<{
|
|
180
|
-
id: AkuId;
|
|
181
|
-
evidence: KillEvidence;
|
|
182
|
-
}>[];
|
|
183
|
-
}> | Readonly<{
|
|
184
|
-
action: "contract.deliver";
|
|
185
|
-
repoRoot: string;
|
|
186
|
-
contractId: string;
|
|
187
|
-
deliveryFactId: string;
|
|
188
|
-
}> | Readonly<{
|
|
189
|
-
action: "contract.review";
|
|
190
|
-
repoRoot: string;
|
|
191
|
-
contractId: string;
|
|
192
|
-
reviewFactId: string;
|
|
193
|
-
}> | Readonly<{
|
|
194
|
-
action: TaskMutationRequest["action"];
|
|
127
|
+
action: string;
|
|
128
|
+
payloadJson: string;
|
|
195
129
|
}>;
|
|
196
130
|
type AdmittedRequest = RequestInput & Readonly<{
|
|
197
131
|
requester: AkuId;
|
|
@@ -199,21 +133,15 @@ type AdmittedRequest = RequestInput & Readonly<{
|
|
|
199
133
|
}>;
|
|
200
134
|
export type RequestFact = (AdmittedRequest & Readonly<{
|
|
201
135
|
state: "admitted";
|
|
202
|
-
}>) | (
|
|
203
|
-
action: "akuma.call";
|
|
204
|
-
}> & Readonly<{
|
|
136
|
+
}>) | (AdmittedRequest & Readonly<{
|
|
205
137
|
state: "reserved";
|
|
206
138
|
child: AkuId;
|
|
207
|
-
}>) | (
|
|
208
|
-
action: "akuma.call";
|
|
209
|
-
}> & Readonly<{
|
|
139
|
+
}>) | (AdmittedRequest & Readonly<{
|
|
210
140
|
state: "served";
|
|
211
141
|
child: AkuId;
|
|
212
|
-
}>) | (
|
|
213
|
-
action: "akuma.call";
|
|
214
|
-
}> & Readonly<{
|
|
142
|
+
}>) | (AdmittedRequest & Readonly<{
|
|
215
143
|
state: "served";
|
|
216
|
-
|
|
144
|
+
serviceJson: string;
|
|
217
145
|
}>) | (AdmittedRequest & Readonly<{
|
|
218
146
|
state: "refused";
|
|
219
147
|
diagnostic: string;
|
|
@@ -6,7 +6,7 @@ import { type ActivityFactSlice } from "./timeline.js";
|
|
|
6
6
|
export { HeartAbsentError, HeldAkumaLeash, classifyHeartSchema, initializeHeart, isHeartAbsent, probeLeash, } from "./storage.js";
|
|
7
7
|
export { admitRequest, isRequestInputConflict, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./request-authority.js";
|
|
8
8
|
export { life, lifeAt } from "./facts.js";
|
|
9
|
-
export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact, HeartSnapshot, ForkPoint, KillEvidence, KillFact, LeashProbe, PauseFact, RequestFact, RequestInput, RequestRecipe,
|
|
9
|
+
export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact, HeartSnapshot, ForkPoint, KillEvidence, KillFact, LeashProbe, PauseFact, RequestFact, RequestInput, RequestRecipe, SealFact, SessionFact, Soul, StopFact, TellFact, TellDelivery, TellDeliveryInput, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact, } from "./facts.js";
|
|
10
10
|
export type { ResumeCoordinate } from "../coordinate.js";
|
|
11
11
|
export declare function readSoul(paths: AkumaPaths): Promise<Soul | null>;
|
|
12
12
|
export declare function heartExists(paths: AkumaPaths): Promise<boolean>;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { RequestFact, RequestInput
|
|
1
|
+
import { type AkuId, type AkumaPaths } from "../identity.js";
|
|
2
|
+
import type { RequestFact, RequestInput } from "./facts.js";
|
|
3
3
|
export declare function isRequestInputConflict(error: unknown): error is Error;
|
|
4
4
|
export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
|
|
5
5
|
admittedAt: string;
|
|
6
|
+
permitted: boolean;
|
|
6
7
|
}>): Promise<RequestFact>;
|
|
7
8
|
export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
8
|
-
export declare function serveRequest(paths: AkumaPaths, id: string, child:
|
|
9
|
-
export declare function serveUpstreamRequest(paths: AkumaPaths, id: string,
|
|
9
|
+
export declare function serveRequest(paths: AkumaPaths, id: string, child: string): Promise<RequestFact>;
|
|
10
|
+
export declare function serveUpstreamRequest(paths: AkumaPaths, id: string, serviceJson: string): Promise<RequestFact>;
|
|
10
11
|
export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
|
|
11
12
|
export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
|
|
12
13
|
export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { parseAkuId } from "../identity.js";
|
|
1
2
|
import { insertRequestFact, nonterminalRequestFacts, requestFact, updateRequestRefused, updateRequestReserved, updateRequestServed, updateRequestVoided, updateUpstreamRequestServed, } from "./request-rows.js";
|
|
2
3
|
import { transaction, withHeart } from "./storage.js";
|
|
3
4
|
import { soulFact } from "./soul.js";
|
|
4
|
-
import { clipAllowedActions } from "../allowed.js";
|
|
5
5
|
import { requestPayloadJson } from "./request-rows.js";
|
|
6
6
|
// This stays out of the public Heart index: only transport service projects it as a refusal.
|
|
7
7
|
class RequestInputConflictError extends Error {
|
|
@@ -18,31 +18,19 @@ export async function admitRequest(paths, input) {
|
|
|
18
18
|
const soul = soulFact(heart);
|
|
19
19
|
if (soul === null)
|
|
20
20
|
throw new Error("Akuma request admission requires a born Soul");
|
|
21
|
-
const
|
|
22
|
-
const parentAllowed = soul.allowed;
|
|
23
|
-
const permitted = action === "akuma.wait" || parentAllowed.includes(action);
|
|
24
|
-
const normalized = input.action === "akuma.call"
|
|
25
|
-
? {
|
|
26
|
-
...input,
|
|
27
|
-
recipe: {
|
|
28
|
-
...input.recipe,
|
|
29
|
-
allowed: permitted ? clipAllowedActions(input.recipe.allowed, parentAllowed) : input.recipe.allowed,
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
: input;
|
|
21
|
+
const { permitted, ...request } = input;
|
|
33
22
|
insertRequestFact(heart, {
|
|
34
|
-
...
|
|
23
|
+
...request,
|
|
35
24
|
requester: soul.id,
|
|
36
|
-
|
|
37
|
-
...(permitted ? {} : { refusal: `not-allowed: ${action}` }),
|
|
25
|
+
...(permitted ? {} : { refusal: `not-allowed: ${input.action}` }),
|
|
38
26
|
});
|
|
39
27
|
const fact = requestFact(heart, input.id);
|
|
40
28
|
if (fact === null)
|
|
41
29
|
throw new Error(`Akuma request ${input.id} was not admitted`);
|
|
42
30
|
if (fact.requester !== soul.id ||
|
|
43
|
-
fact.id !==
|
|
44
|
-
fact.action !==
|
|
45
|
-
requestPayloadJson(fact) !== requestPayloadJson(
|
|
31
|
+
fact.id !== input.id ||
|
|
32
|
+
fact.action !== input.action ||
|
|
33
|
+
requestPayloadJson(fact) !== requestPayloadJson(input)) {
|
|
46
34
|
throw new RequestInputConflictError(input.id);
|
|
47
35
|
}
|
|
48
36
|
return fact;
|
|
@@ -53,43 +41,41 @@ export async function reserveRequest(paths, id, child) {
|
|
|
53
41
|
const before = requestFact(heart, id);
|
|
54
42
|
if (before === null)
|
|
55
43
|
throw new Error(`unknown Akuma request ${id}`);
|
|
56
|
-
if (before.action !== "akuma.call")
|
|
57
|
-
throw new Error(`Akuma request ${id} cannot reserve a child`);
|
|
58
44
|
if (before.state === "admitted")
|
|
59
45
|
updateRequestReserved(heart, id, child);
|
|
60
|
-
else if ((before.state !== "reserved" && before.state !== "served") ||
|
|
46
|
+
else if ((before.state !== "reserved" && before.state !== "served") ||
|
|
47
|
+
!("child" in before) ||
|
|
48
|
+
before.child !== child) {
|
|
61
49
|
throw new Error(`Akuma request ${id} cannot reserve ${child}`);
|
|
62
50
|
}
|
|
63
51
|
return requestFact(heart, id);
|
|
64
52
|
}));
|
|
65
53
|
}
|
|
66
54
|
export async function serveRequest(paths, id, child) {
|
|
55
|
+
const parsed = parseAkuId(child);
|
|
56
|
+
if (parsed.id !== child)
|
|
57
|
+
throw new Error(`Akuma request ${id} has a noncanonical child`);
|
|
67
58
|
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
68
59
|
const before = requestFact(heart, id);
|
|
69
60
|
if (before === null)
|
|
70
61
|
throw new Error(`unknown Akuma request ${id}`);
|
|
71
|
-
if (before.
|
|
72
|
-
|
|
73
|
-
if (before.state
|
|
74
|
-
updateRequestServed(heart, id, child);
|
|
75
|
-
else if (before.state !== "served" || before.child !== child) {
|
|
62
|
+
if (before.state === "reserved" && before.child === parsed.id)
|
|
63
|
+
updateRequestServed(heart, id, parsed.id);
|
|
64
|
+
else if (before.state !== "served" || !("child" in before) || before.child !== parsed.id) {
|
|
76
65
|
throw new Error(`Akuma request ${id} cannot serve ${child}`);
|
|
77
66
|
}
|
|
78
67
|
return requestFact(heart, id);
|
|
79
68
|
}));
|
|
80
69
|
}
|
|
81
|
-
export async function serveUpstreamRequest(paths, id,
|
|
70
|
+
export async function serveUpstreamRequest(paths, id, serviceJson) {
|
|
82
71
|
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
83
72
|
const before = requestFact(heart, id);
|
|
84
73
|
if (before === null)
|
|
85
74
|
throw new Error(`unknown Akuma request ${id}`);
|
|
86
|
-
if (before.action === "akuma.call" || service.action !== before.action) {
|
|
87
|
-
throw new Error(`Akuma request ${id} has a mismatched service reference`);
|
|
88
|
-
}
|
|
89
75
|
if (before.state === "admitted")
|
|
90
|
-
updateUpstreamRequestServed(heart, id,
|
|
91
|
-
else if (before.state !== "served") {
|
|
92
|
-
throw new Error(`Akuma request ${id} cannot be served
|
|
76
|
+
updateUpstreamRequestServed(heart, id, serviceJson);
|
|
77
|
+
else if (before.state !== "served" || !("serviceJson" in before) || before.serviceJson !== serviceJson) {
|
|
78
|
+
throw new Error(`Akuma request ${id} cannot be served with this service reference`);
|
|
93
79
|
}
|
|
94
80
|
return requestFact(heart, id);
|
|
95
81
|
}));
|
|
@@ -1,45 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
function json(value) {
|
|
3
|
-
return JSON.stringify(value);
|
|
4
|
-
}
|
|
5
|
-
function parsed(value) {
|
|
1
|
+
function assertJsonText(value) {
|
|
6
2
|
if (typeof value !== "string")
|
|
7
3
|
throw new Error("Akuma authority contains non-text JSON");
|
|
8
|
-
|
|
4
|
+
JSON.parse(value);
|
|
5
|
+
return value;
|
|
9
6
|
}
|
|
10
7
|
export function requestPayloadJson(input) {
|
|
11
|
-
|
|
12
|
-
return json(payload);
|
|
8
|
+
return assertJsonText(input.payloadJson);
|
|
13
9
|
}
|
|
14
10
|
function decodeRequestRow(row) {
|
|
15
|
-
const knownAction = ["akuma.call", "akuma.wait", "akuma.tell", "akuma.kill", "contract.deliver", "contract.review"].includes(row.action) || isTaskMutationAction(row.action);
|
|
16
|
-
if (!knownAction)
|
|
17
|
-
throw new Error(`Akuma authority contains an unknown request action: ${row.action}`);
|
|
18
|
-
const payload = parsed(row.payload_json);
|
|
19
11
|
const input = {
|
|
20
12
|
id: row.id,
|
|
21
13
|
requester: row.requester,
|
|
22
14
|
action: row.action,
|
|
23
|
-
|
|
15
|
+
payloadJson: assertJsonText(row.payload_json),
|
|
24
16
|
admittedAt: row.admitted_at,
|
|
25
17
|
};
|
|
26
18
|
if (row.state === "reserved") {
|
|
27
|
-
if (
|
|
19
|
+
if (row.child === null || row.service_json !== null) {
|
|
28
20
|
throw new Error("Akuma authority contains an invalid reserved request");
|
|
29
21
|
}
|
|
30
22
|
return { ...input, state: row.state, child: row.child };
|
|
31
23
|
}
|
|
32
24
|
if (row.state === "served") {
|
|
33
|
-
if (
|
|
34
|
-
if (row.child === null)
|
|
35
|
-
throw new Error("Akuma authority contains a served call without a child");
|
|
25
|
+
if (row.child !== null && row.service_json === null) {
|
|
36
26
|
return { ...input, state: row.state, child: row.child };
|
|
37
27
|
}
|
|
38
|
-
if (row.
|
|
39
|
-
|
|
28
|
+
if (row.child === null && row.service_json !== null) {
|
|
29
|
+
return { ...input, state: row.state, serviceJson: assertJsonText(row.service_json) };
|
|
40
30
|
}
|
|
41
|
-
|
|
42
|
-
return { ...input, state: row.state, service };
|
|
31
|
+
throw new Error("Akuma authority contains an invalid served request");
|
|
43
32
|
}
|
|
44
33
|
if (row.state === "refused")
|
|
45
34
|
return { ...input, state: row.state, diagnostic: row.diagnostic };
|
|
@@ -82,8 +71,8 @@ export function updateRequestServed(database, id, child) {
|
|
|
82
71
|
export function updateUpstreamRequestServed(database, id, service) {
|
|
83
72
|
database
|
|
84
73
|
.prepare(`UPDATE requests SET state = 'served', service_json = ?
|
|
85
|
-
WHERE id = ? AND state = 'admitted'
|
|
86
|
-
.run(
|
|
74
|
+
WHERE id = ? AND state = 'admitted'`)
|
|
75
|
+
.run(assertJsonText(service), id);
|
|
87
76
|
}
|
|
88
77
|
export function updateRequestRefused(database, id, diagnostic) {
|
|
89
78
|
database
|
|
@@ -2,5 +2,5 @@ import type { DatabaseSync } from "node:sqlite";
|
|
|
2
2
|
export declare function assertHeartSchemaVersion(database: DatabaseSync): void;
|
|
3
3
|
export declare function assertLeashSchemaVersion(database: DatabaseSync): void;
|
|
4
4
|
export declare function heartSchemaIsCurrent(database: DatabaseSync): boolean;
|
|
5
|
-
export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version =
|
|
5
|
+
export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 21)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 21);\n CREATE TABLE IF NOT EXISTS soul (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n soul_json TEXT NOT NULL CHECK (json_valid(soul_json))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS bodies (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n leash_taken_at TEXT NOT NULL,\n hung_diagnostic TEXT,\n hung_at TEXT,\n end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),\n ended_at TEXT,\n CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)\n OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS sessions (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n provider TEXT NOT NULL,\n coordinate_json TEXT NOT NULL CHECK (json_valid(coordinate_json)),\n cwd TEXT NOT NULL,\n options_json TEXT NOT NULL CHECK (json_valid(options_json)),\n admitted_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS turns (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\n started_at TEXT NOT NULL,\n end_sequence INTEGER UNIQUE REFERENCES timeline(sequence) ON DELETE SET NULL,\n outcome TEXT CHECK (outcome IN ('answered', 'failed')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\n diagnostic TEXT,\n completed_at TEXT,\n CHECK (\n (outcome = 'answered' AND session_json IS NOT NULL AND answer IS NOT NULL AND diagnostic IS NULL)\n OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NOT NULL)\n OR (outcome IS NULL AND end_sequence IS NULL AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NULL AND completed_at IS NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS timeline (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('turn-start', 'call', 'activity', 'tell', 'turn-end'))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS calls (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n event_json TEXT NOT NULL CHECK (json_valid(event_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tells (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL UNIQUE REFERENCES timeline(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n recorded_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_deliveries (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n route TEXT NOT NULL CHECK (route IN ('launch', 'live')),\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT NOT NULL,\n receipt TEXT CHECK (receipt IN ('unavailable', 'required')),\n delivered_at TEXT NOT NULL,\n CHECK ((route = 'launch' AND receipt IS NULL) OR (route = 'live' AND receipt IS NOT NULL)),\n UNIQUE (tell_id, turn_sequence, fence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_receipts (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n evidence TEXT NOT NULL CHECK (evidence IN ('exact', 'fence')),\n tell_id TEXT REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT,\n kind TEXT NOT NULL,\n received_at TEXT NOT NULL,\n CHECK (\n (evidence = 'exact' AND tell_id IS NOT NULL AND turn_sequence IS NULL AND fence IS NULL)\n OR (evidence = 'fence' AND tell_id IS NULL AND turn_sequence IS NOT NULL AND fence IS NOT NULL)\n )\n ) STRICT;\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_exact\n ON tell_receipts(tell_id, kind) WHERE evidence = 'exact';\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_fence\n ON tell_receipts(turn_sequence, fence, kind) WHERE evidence = 'fence';\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n requester TEXT NOT NULL,\n action TEXT NOT NULL,\n payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),\n child TEXT,\n service_json TEXT CHECK (service_json IS NULL OR json_valid(service_json)),\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'reserved' AND child IS NOT NULL AND service_json IS NULL\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'served'\n AND ((child IS NOT NULL AND service_json IS NULL)\n OR (child IS NULL AND service_json IS NOT NULL))\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND service_json IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS control (\n kind TEXT PRIMARY KEY CHECK (kind IN ('stop', 'pause')),\n value_json TEXT NOT NULL CHECK (json_valid(value_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS kills (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n body_sequence INTEGER NOT NULL UNIQUE REFERENCES bodies(sequence),\n evidence TEXT NOT NULL CHECK (evidence = 'killed'),\n at TEXT NOT NULL\n ) STRICT;\n";
|
|
6
6
|
export declare const LEASH_SCHEMA = "\n PRAGMA journal_mode=DELETE;\n CREATE TABLE IF NOT EXISTS leash_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 4)\n ) STRICT;\n INSERT OR IGNORE INTO leash_schema(singleton, version) VALUES (1, 4);\n CREATE TABLE IF NOT EXISTS seal (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n evidence TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const HEART_SCHEMA_VERSION =
|
|
1
|
+
const HEART_SCHEMA_VERSION = 21;
|
|
2
2
|
const LEASH_SCHEMA_VERSION = 4;
|
|
3
3
|
function assertSchemaVersion(database, table, expected) {
|
|
4
4
|
const row = database.prepare(`SELECT version FROM ${table} WHERE singleton = 1`).get();
|
|
@@ -119,14 +119,7 @@ export const HEART_SCHEMA = `
|
|
|
119
119
|
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
120
120
|
id TEXT NOT NULL UNIQUE,
|
|
121
121
|
requester TEXT NOT NULL,
|
|
122
|
-
action TEXT NOT NULL
|
|
123
|
-
action IN (
|
|
124
|
-
'akuma.call', 'akuma.wait', 'akuma.tell', 'akuma.kill',
|
|
125
|
-
'contract.deliver', 'contract.review',
|
|
126
|
-
'task.add', 'task.addDocument', 'task.compose', 'task.update', 'task.start',
|
|
127
|
-
'task.stop', 'task.hold', 'task.resume', 'task.done', 'task.drop'
|
|
128
|
-
)
|
|
129
|
-
),
|
|
122
|
+
action TEXT NOT NULL,
|
|
130
123
|
payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),
|
|
131
124
|
admitted_at TEXT NOT NULL,
|
|
132
125
|
state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),
|
|
@@ -136,12 +129,11 @@ export const HEART_SCHEMA = `
|
|
|
136
129
|
evidence TEXT,
|
|
137
130
|
CHECK (
|
|
138
131
|
(state = 'admitted' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)
|
|
139
|
-
OR (state = 'reserved' AND
|
|
140
|
-
AND child IS NOT NULL AND service_json IS NULL
|
|
132
|
+
OR (state = 'reserved' AND child IS NOT NULL AND service_json IS NULL
|
|
141
133
|
AND diagnostic IS NULL AND evidence IS NULL)
|
|
142
134
|
OR (state = 'served'
|
|
143
|
-
AND ((
|
|
144
|
-
OR (
|
|
135
|
+
AND ((child IS NOT NULL AND service_json IS NULL)
|
|
136
|
+
OR (child IS NULL AND service_json IS NOT NULL))
|
|
145
137
|
AND diagnostic IS NULL AND evidence IS NULL)
|
|
146
138
|
OR (state = 'refused' AND child IS NULL AND service_json IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)
|
|
147
139
|
OR (state = 'voided' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AkuId } from "./identity.js";
|
|
2
2
|
import type { WorldRoot } from "../world.js";
|
|
3
|
-
export { Akuma, AkumaHandle, AkumaNotBornError, defaultWaitComplete } from "./akuma.js";
|
|
3
|
+
export { Akuma, AkumaHandle, AkumaNotBornError, akumaIdSchema, akumaStatusSchema, defaultWaitComplete, parseAkumaStatus, } from "./akuma.js";
|
|
4
4
|
export type { AkumaCallInput } from "./akuma.js";
|
|
5
5
|
export { ALLOWED_ACTIONS } from "./allowed.js";
|
|
6
6
|
export type { AllowedAction, AllowedActions } from "./allowed.js";
|
package/build/src/akuma/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readSoul } from "./heart/index.js";
|
|
2
2
|
import { pathsForAkuId } from "./identity.js";
|
|
3
|
-
export { Akuma, AkumaHandle, AkumaNotBornError, defaultWaitComplete } from "./akuma.js";
|
|
3
|
+
export { Akuma, AkumaHandle, AkumaNotBornError, akumaIdSchema, akumaStatusSchema, defaultWaitComplete, parseAkumaStatus, } from "./akuma.js";
|
|
4
4
|
export { ALLOWED_ACTIONS } from "./allowed.js";
|
|
5
5
|
export async function probeBornAkuma(worldPath, id) {
|
|
6
6
|
const soul = await readSoul(pathsForAkuId(worldPath, id));
|
|
@@ -76,7 +76,14 @@ export function selectSnapshot(ledger, input) {
|
|
|
76
76
|
return { snapshot: { kind: "unborn", entries: [], omitted: 0, ...EMPTY_REPORTED }, ordinaryCount: 0 };
|
|
77
77
|
const pending = ledger.rows.filter(isPendingTell);
|
|
78
78
|
const latestTold = input.aperture === "monitoring" ? ledger.rows.findLast(isToldTell) : undefined;
|
|
79
|
-
const
|
|
79
|
+
const admittedTell = input.aperture === "receipt" && input.admittedTellId !== undefined
|
|
80
|
+
? ledger.rows.find((row) => row.kind === "tell" && row.tellId === input.admittedTellId)
|
|
81
|
+
: undefined;
|
|
82
|
+
const pins = input.aperture === "receipt" && input.admittedTellId !== undefined
|
|
83
|
+
? admittedTell === undefined
|
|
84
|
+
? []
|
|
85
|
+
: [admittedTell]
|
|
86
|
+
: [...pending, ...(latestTold === undefined ? [] : [latestTold])];
|
|
80
87
|
const reported = frontierReportedChanges(ledger);
|
|
81
88
|
if (ledger.openTurn !== undefined) {
|
|
82
89
|
const window = ledger.openTurn.rows;
|