@astrosheep/keiyaku 4.0.3 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +15 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +34 -13
- package/build/src/akuma/akuma.d.ts +34 -12
- package/build/src/akuma/akuma.js +118 -63
- package/build/src/akuma/allowed.d.ts +7 -0
- package/build/src/akuma/allowed.js +33 -0
- package/build/src/akuma/archetype.d.ts +7 -4
- package/build/src/akuma/archetype.js +15 -16
- package/build/src/akuma/body.d.ts +6 -1
- package/build/src/akuma/body.js +36 -27
- package/build/src/akuma/heart/facts.d.ts +82 -14
- package/build/src/akuma/heart/index.d.ts +5 -18
- package/build/src/akuma/heart/index.js +14 -84
- package/build/src/akuma/heart/request-authority.d.ts +12 -0
- package/build/src/akuma/heart/request-authority.js +119 -0
- package/build/src/akuma/heart/request-rows.d.ts +16 -0
- package/build/src/akuma/heart/request-rows.js +88 -0
- package/build/src/akuma/heart/rows.d.ts +1 -26
- package/build/src/akuma/heart/rows.js +0 -50
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +22 -10
- package/build/src/akuma/heart/soul.js +2 -36
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +15 -0
- package/build/src/akuma/heart/timeline.d.ts +1 -5
- package/build/src/akuma/heart/timeline.js +8 -17
- package/build/src/akuma/index.d.ts +5 -2
- package/build/src/akuma/index.js +1 -0
- package/build/src/akuma/projection.d.ts +17 -3
- package/build/src/akuma/projection.js +40 -3
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +2 -7
- package/build/src/akuma/provider.js +2 -1
- package/build/src/akuma/providers/acp/core.d.ts +3 -1
- package/build/src/akuma/providers/acp/core.js +10 -6
- package/build/src/akuma/providers/acp/events.d.ts +11 -3
- package/build/src/akuma/providers/acp/events.js +78 -4
- package/build/src/akuma/providers/acp/index.js +0 -1
- package/build/src/akuma/providers/claude/events.js +62 -3
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +7 -3
- package/build/src/akuma/providers/codex-app-server/events.js +1 -13
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +0 -2
- package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
- package/build/src/akuma/providers/grok-build/index.js +72 -3
- package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +8 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
- package/build/src/akuma/providers/pi/events.js +17 -3
- package/build/src/akuma/providers/pi/index.js +11 -4
- package/build/src/akuma/providers/unified-patch.d.ts +4 -0
- package/build/src/akuma/providers/unified-patch.js +14 -0
- package/build/src/akuma/publication.d.ts +1 -1
- package/build/src/akuma/publication.js +1 -1
- package/build/src/akuma/request-serve.d.ts +87 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +124 -0
- package/build/src/akuma/request-wire.js +380 -0
- package/build/src/akuma/requests.d.ts +41 -41
- package/build/src/akuma/requests.js +75 -374
- package/build/src/akuma-body.d.ts +8 -0
- package/build/src/akuma-body.js +84 -0
- package/build/src/body/arc.js +4 -29
- package/build/src/body/decode.js +5 -39
- package/build/src/body/envelope.d.ts +7 -0
- package/build/src/body/envelope.js +37 -0
- package/build/src/cli/accepted.d.ts +4 -1
- package/build/src/cli/accepted.js +39 -9
- package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
- package/build/src/cli/commands/akuma-invoke.js +18 -10
- package/build/src/cli/commands/akuma.d.ts +11 -2
- package/build/src/cli/commands/akuma.js +67 -28
- package/build/src/cli/commands/amend.d.ts +1 -1
- package/build/src/cli/commands/amend.js +1 -1
- package/build/src/cli/commands/contract.d.ts +8 -8
- package/build/src/cli/commands/contract.js +3 -3
- package/build/src/cli/commands/install.js +2 -2
- package/build/src/cli/commands/task-invoke.js +98 -9
- package/build/src/cli/commands/task-query.d.ts +1 -1
- package/build/src/cli/commands/task-query.js +11 -5
- package/build/src/cli/coordinates.d.ts +2 -0
- package/build/src/cli/coordinates.js +12 -5
- package/build/src/cli/invoke.d.ts +1 -0
- package/build/src/cli/invoke.js +116 -75
- package/build/src/cli/main.d.ts +2 -0
- package/build/src/cli/main.js +29 -4
- package/build/src/cli/parse.d.ts +3 -2
- package/build/src/cli/parse.js +25 -8
- package/build/src/cli/render/akuma.d.ts +2 -2
- package/build/src/cli/render/akuma.js +138 -24
- package/build/src/cli/render/audit.js +18 -8
- package/build/src/cli/render/contract.d.ts +2 -0
- package/build/src/cli/render/contract.js +243 -36
- package/build/src/cli/render/kanshi.js +64 -29
- package/build/src/cli/render/receipt.d.ts +2 -1
- package/build/src/cli/render/receipt.js +37 -2
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/render/text.js +3 -1
- package/build/src/cli/result.d.ts +52 -9
- package/build/src/cli/selectors.d.ts +1 -0
- package/build/src/cli/selectors.js +9 -6
- package/build/src/contract-worktree.d.ts +1 -2
- package/build/src/contract-worktree.js +7 -9
- package/build/src/core/facts/codec.js +9 -0
- package/build/src/core/facts/fold.js +13 -1
- package/build/src/core/facts/types.d.ts +8 -1
- package/build/src/core/subject.js +4 -3
- package/build/src/core/verbs/placement.d.ts +9 -1
- package/build/src/core/verbs/placement.js +24 -6
- package/build/src/core/verbs/reintegrate.d.ts +13 -0
- package/build/src/core/verbs/reintegrate.js +24 -0
- package/build/src/dispatch/index.d.ts +1 -1
- package/build/src/dispatch/index.js +50 -39
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +0 -4
- package/build/src/git/hooks.js +0 -36
- package/build/src/git/integration.d.ts +7 -8
- package/build/src/git/integration.js +62 -9
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +26 -0
- package/build/src/git/process.js +94 -0
- package/build/src/git/read-observation.d.ts +2 -1
- package/build/src/git/read-observation.js +3 -2
- package/build/src/git/reconcile.d.ts +8 -2
- package/build/src/git/reconcile.js +63 -14
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +4 -118
- package/build/src/git/scratch.d.ts +1 -1
- package/build/src/git/scratch.js +1 -1
- package/build/src/git/target-placement.d.ts +1 -1
- package/build/src/git/target-placement.js +9 -7
- package/build/src/git/tender.d.ts +20 -5
- package/build/src/git/tender.js +45 -13
- package/build/src/git/terminal-seal.d.ts +16 -2
- package/build/src/git/terminal-seal.js +15 -5
- package/build/src/git/workspace.d.ts +2 -1
- package/build/src/git/workspace.js +13 -5
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +9 -1
- package/build/src/kanshi/read.js +91 -37
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/address.d.ts +5 -14
- package/build/src/library/address.js +27 -23
- package/build/src/library/akuma-creation.d.ts +4 -2
- package/build/src/library/akuma-creation.js +43 -26
- package/build/src/library/audit.d.ts +2 -1
- package/build/src/library/audit.js +1 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +4 -4
- package/build/src/library/catalog.d.ts +1 -2
- package/build/src/library/catalog.js +11 -6
- package/build/src/library/configuration.d.ts +5 -1
- package/build/src/library/configuration.js +71 -18
- package/build/src/library/contract.d.ts +70 -3
- package/build/src/library/contract.js +213 -27
- package/build/src/library/delivery.d.ts +1 -1
- package/build/src/library/fleet.d.ts +70 -12
- package/build/src/library/fleet.js +236 -56
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +1 -5
- package/build/src/library/keiyaku.d.ts +4 -4
- package/build/src/library/keiyaku.js +1 -2
- package/build/src/library/mutation.d.ts +2 -1
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +3 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +3 -1
- package/build/src/library/repo.js +8 -4
- package/build/src/protocol/abandon.d.ts +9 -0
- package/build/src/protocol/abandon.js +15 -0
- package/build/src/protocol/amend.d.ts +16 -0
- package/build/src/protocol/amend.js +77 -0
- package/build/src/protocol/arc.d.ts +6 -0
- package/build/src/protocol/arc.js +12 -0
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/audit.d.ts +53 -0
- package/build/src/protocol/audit.js +140 -0
- package/build/src/protocol/bind.d.ts +2 -3
- package/build/src/protocol/bind.js +2 -16
- package/build/src/protocol/completion.d.ts +32 -0
- package/build/src/protocol/completion.js +130 -0
- package/build/src/protocol/deliver.d.ts +37 -0
- package/build/src/protocol/deliver.js +160 -0
- package/build/src/protocol/intent.d.ts +1 -1
- package/build/src/protocol/intent.js +1 -1
- package/build/src/protocol/operations.d.ts +65 -198
- package/build/src/protocol/operations.js +21 -634
- package/build/src/protocol/placement.d.ts +4 -13
- package/build/src/protocol/placement.js +3 -15
- package/build/src/protocol/read/status.d.ts +4 -2
- package/build/src/protocol/read/status.js +27 -15
- package/build/src/protocol/reconcile.d.ts +35 -0
- package/build/src/protocol/reconcile.js +41 -0
- package/build/src/protocol/reintegrate.d.ts +31 -0
- package/build/src/protocol/reintegrate.js +74 -0
- package/build/src/protocol/review.d.ts +33 -0
- package/build/src/protocol/review.js +148 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.d.ts +1 -0
- package/build/src/runtime/proc/run.js +9 -2
- package/build/src/settlement/fence.d.ts +1 -1
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +2 -1
- package/build/src/settlement/settle.js +4 -1
- package/build/src/task/board.d.ts +18 -4
- package/build/src/task/board.js +73 -29
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +11 -4
- package/build/src/task/index.d.ts +4 -4
- package/build/src/task/index.js +8 -131
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +39 -0
- package/build/src/task/mutation.js +85 -0
- package/build/src/task/operations.d.ts +4 -19
- package/build/src/task/operations.js +64 -18
- package/build/src/task/query.d.ts +9 -2
- package/build/src/task/query.js +32 -64
- package/build/src/task/store.js +0 -2
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/verification/execution.js +2 -1
- package/build/src/workspace-place.d.ts +1 -4
- package/build/src/workspace-place.js +0 -15
- package/package.json +5 -3
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TASK_MUTATION_ACTIONS } from "../task/mutation.js";
|
|
2
|
+
export const ALLOWED_ACTIONS = Object.freeze([
|
|
3
|
+
"akuma.call",
|
|
4
|
+
"akuma.kill",
|
|
5
|
+
"akuma.tell",
|
|
6
|
+
"contract.deliver",
|
|
7
|
+
"contract.review",
|
|
8
|
+
...TASK_MUTATION_ACTIONS,
|
|
9
|
+
]);
|
|
10
|
+
const ALLOWED_ACTION_SET = new Set(ALLOWED_ACTIONS);
|
|
11
|
+
export function isAllowedAction(value) {
|
|
12
|
+
return typeof value === "string" && ALLOWED_ACTION_SET.has(value);
|
|
13
|
+
}
|
|
14
|
+
export function decodeAllowedActions(value, label = "allowed") {
|
|
15
|
+
if (!Array.isArray(value))
|
|
16
|
+
throw new TypeError(`${label} must be an array`);
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
for (const action of value) {
|
|
19
|
+
if (!isAllowedAction(action))
|
|
20
|
+
throw new TypeError(`${label} contains an unknown action: ${String(action)}`);
|
|
21
|
+
if (seen.has(action))
|
|
22
|
+
throw new TypeError(`${label} contains a duplicate action: ${action}`);
|
|
23
|
+
seen.add(action);
|
|
24
|
+
}
|
|
25
|
+
return Object.freeze([...seen].sort());
|
|
26
|
+
}
|
|
27
|
+
export function effectiveAllowedActions(value) {
|
|
28
|
+
return value === undefined ? ALLOWED_ACTIONS : decodeAllowedActions(value);
|
|
29
|
+
}
|
|
30
|
+
export function clipAllowedActions(requested, parent) {
|
|
31
|
+
const ceiling = new Set(parent);
|
|
32
|
+
return Object.freeze(requested.filter((action) => ceiling.has(action)));
|
|
33
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Settings } from "../settings.js";
|
|
2
2
|
import type { ProviderAdapter } from "./provider.js";
|
|
3
3
|
import { type ProviderExecution, type ProviderOptions, type ReadonlyRestraint } from "./provider-recipe.js";
|
|
4
|
+
import { type AllowedActions } from "./allowed.js";
|
|
4
5
|
type DecodedArchetype = Readonly<{
|
|
5
6
|
name: string;
|
|
6
7
|
path: string;
|
|
7
8
|
provider: string;
|
|
8
9
|
description?: string;
|
|
9
10
|
options: ProviderOptions;
|
|
11
|
+
allowed: AllowedActions;
|
|
10
12
|
}>;
|
|
11
13
|
export type ArchetypeCatalogRow = Readonly<{
|
|
12
14
|
name: string;
|
|
@@ -27,14 +29,15 @@ export declare class AkumaArchetypeError extends Error {
|
|
|
27
29
|
readonly kind = "akuma-archetype";
|
|
28
30
|
constructor(archetype: string, searched: readonly string[], reason: string, guidance?: string);
|
|
29
31
|
}
|
|
30
|
-
export declare function listArchetypes(input
|
|
31
|
-
|
|
32
|
+
export declare function listArchetypes(input?: Readonly<{
|
|
33
|
+
home?: string;
|
|
32
34
|
}>): Promise<readonly string[]>;
|
|
33
|
-
export declare function listArchetypeDefinitions(input
|
|
34
|
-
|
|
35
|
+
export declare function listArchetypeDefinitions(input?: Readonly<{
|
|
36
|
+
home?: string;
|
|
35
37
|
}>): Promise<readonly ArchetypeCatalogRow[]>;
|
|
36
38
|
export declare function loadArchetype(input: Readonly<{
|
|
37
39
|
name: string;
|
|
40
|
+
home?: string;
|
|
38
41
|
settings: Settings;
|
|
39
42
|
}>): Promise<AdmittedArchetype>;
|
|
40
43
|
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
-
import {
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
3
4
|
import { parseDocument } from "yaml";
|
|
4
5
|
import { archetypeName } from "./identity.js";
|
|
5
6
|
import { decodeProviderOptions, decodeProviderRecipe, } from "./provider-recipe.js";
|
|
6
7
|
import { resolveProviderExecution } from "./providers/index.js";
|
|
8
|
+
import { effectiveAllowedActions } from "./allowed.js";
|
|
7
9
|
export class AkumaArchetypeError extends Error {
|
|
8
10
|
archetype;
|
|
9
11
|
searched;
|
|
@@ -17,14 +19,11 @@ export class AkumaArchetypeError extends Error {
|
|
|
17
19
|
this.name = "AkumaArchetypeError";
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
|
-
function archetypeDirectory(
|
|
21
|
-
|
|
22
|
-
return userPath === undefined ? null : join(dirname(userPath), "akuma");
|
|
22
|
+
function archetypeDirectory(home) {
|
|
23
|
+
return join(home ?? join(homedir(), ".keiyaku"), "akuma");
|
|
23
24
|
}
|
|
24
|
-
async function archetypePaths(
|
|
25
|
-
const directory = archetypeDirectory(
|
|
26
|
-
if (directory === null)
|
|
27
|
-
return [];
|
|
25
|
+
async function archetypePaths(home) {
|
|
26
|
+
const directory = archetypeDirectory(home);
|
|
28
27
|
try {
|
|
29
28
|
return (await readdir(directory, { withFileTypes: true }))
|
|
30
29
|
.flatMap((entry) => {
|
|
@@ -46,8 +45,8 @@ async function archetypePaths(settings) {
|
|
|
46
45
|
throw error;
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
|
-
export async function listArchetypes(input) {
|
|
50
|
-
return (await archetypePaths(input.
|
|
48
|
+
export async function listArchetypes(input = {}) {
|
|
49
|
+
return (await archetypePaths(input.home)).map(({ name }) => name);
|
|
51
50
|
}
|
|
52
51
|
function archetypeField(values, key, required = false) {
|
|
53
52
|
const value = values[key];
|
|
@@ -96,6 +95,7 @@ function decodeArchetype(name, path, markdown) {
|
|
|
96
95
|
const readonly = archetypeReadonly(values);
|
|
97
96
|
const network = archetypeEnum(values, "network", ["disabled", "enabled"]);
|
|
98
97
|
const description = archetypeField(values, "description");
|
|
98
|
+
const allowed = effectiveAllowedActions(values.allowed);
|
|
99
99
|
const systemPrompt = lines.slice(closing + 1).join("\n");
|
|
100
100
|
return Object.freeze({
|
|
101
101
|
name,
|
|
@@ -109,12 +109,13 @@ function decodeArchetype(name, path, markdown) {
|
|
|
109
109
|
...(network === undefined ? {} : { network }),
|
|
110
110
|
...(systemPrompt.length === 0 ? {} : { systemPrompt }),
|
|
111
111
|
}),
|
|
112
|
+
allowed,
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
|
-
export async function listArchetypeDefinitions(input) {
|
|
115
|
+
export async function listArchetypeDefinitions(input = {}) {
|
|
115
116
|
// Reads still run concurrently, but the reported failure is the first invalid
|
|
116
117
|
// definition in catalog byte order, not whichever read happened to finish first.
|
|
117
|
-
const settled = await Promise.allSettled((await archetypePaths(input.
|
|
118
|
+
const settled = await Promise.allSettled((await archetypePaths(input.home)).map(async ({ name, path }) => {
|
|
118
119
|
try {
|
|
119
120
|
const definition = decodeArchetype(name, path, await readFile(path, "utf8"));
|
|
120
121
|
return Object.freeze({
|
|
@@ -209,11 +210,9 @@ function admitArchetype(archetype, settings) {
|
|
|
209
210
|
}
|
|
210
211
|
export async function loadArchetype(input) {
|
|
211
212
|
const name = archetypeName(input.name);
|
|
212
|
-
const directory = archetypeDirectory(input.
|
|
213
|
-
const missing = () => new AkumaArchetypeError(name, directory === null ? [] : [join(directory, `${name}.md`)], "was not found", "use `keiyaku ls aku/` to list available Akuma");
|
|
214
|
-
if (directory === null)
|
|
215
|
-
throw missing();
|
|
213
|
+
const directory = archetypeDirectory(input.home);
|
|
216
214
|
const path = join(directory, `${name}.md`);
|
|
215
|
+
const missing = () => new AkumaArchetypeError(name, [path], "was not found", "use `keiyaku ls aku/` to list available Akuma");
|
|
217
216
|
let markdown;
|
|
218
217
|
try {
|
|
219
218
|
markdown = await readFile(path, "utf8");
|
|
@@ -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 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;
|
|
@@ -12,7 +12,12 @@ export type BodyLaunch = Readonly<{
|
|
|
12
12
|
type BodyRuntime = Readonly<{
|
|
13
13
|
now(): string;
|
|
14
14
|
spawnChild?(launch: RequestChildLaunch): Promise<void>;
|
|
15
|
+
upstream?: UpstreamExecutionPort;
|
|
15
16
|
}>;
|
|
16
17
|
export declare function driveAkumaBody(launch: BodyLaunch, adapter?: ProviderAdapter, runtime?: BodyRuntime): Promise<void>;
|
|
17
18
|
export declare function spawnAkumaBody(launch: BodyLaunch): Promise<void>;
|
|
19
|
+
export declare function runAkumaBody(upstreamFor: (launch: BodyLaunch, configuration: Readonly<{
|
|
20
|
+
home?: string;
|
|
21
|
+
gitPath?: string;
|
|
22
|
+
}>) => UpstreamExecutionPort): Promise<void>;
|
|
18
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,23 +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
|
-
: 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
|
+
});
|
|
191
190
|
const driveInput = {
|
|
192
191
|
body: input.body,
|
|
193
192
|
launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
|
|
194
193
|
cwd,
|
|
195
194
|
options,
|
|
196
195
|
signal: input.supervisor.signal,
|
|
197
|
-
|
|
196
|
+
requests: { dir: requests.directory },
|
|
198
197
|
};
|
|
199
198
|
const setup = session === undefined
|
|
200
199
|
? input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
|
|
@@ -203,7 +202,7 @@ async function startTurnDrive(input) {
|
|
|
203
202
|
const selected = await setup;
|
|
204
203
|
if (input.supervisor.signal.aborted) {
|
|
205
204
|
await retireProviderCustody(input, turn.sequence, selected);
|
|
206
|
-
await requests
|
|
205
|
+
await requests.close();
|
|
207
206
|
return { kind: "stopped" };
|
|
208
207
|
}
|
|
209
208
|
if (input.launchTells.length > 0) {
|
|
@@ -215,13 +214,12 @@ async function startTurnDrive(input) {
|
|
|
215
214
|
deliveredAt: input.now(),
|
|
216
215
|
})));
|
|
217
216
|
}
|
|
218
|
-
|
|
219
|
-
void selected.completion.then(() => requests.stopAdmission());
|
|
217
|
+
void selected.completion.then(() => requests.stopAdmission());
|
|
220
218
|
return { turnSequence: turn.sequence, drive: selected, requests, cwd, options,
|
|
221
219
|
...(session === undefined ? {} : { resume: session }) };
|
|
222
220
|
}
|
|
223
221
|
catch (error) {
|
|
224
|
-
await requests
|
|
222
|
+
await requests.close();
|
|
225
223
|
if (input.supervisor.signal.aborted) {
|
|
226
224
|
if (input.supervisor.reason === "heart-gone")
|
|
227
225
|
throw error;
|
|
@@ -310,7 +308,7 @@ async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
|
|
|
310
308
|
}
|
|
311
309
|
async function stopActiveDrive(input, active) {
|
|
312
310
|
await retireProviderCustody(input, active.turnSequence, active.drive);
|
|
313
|
-
await active.requests
|
|
311
|
+
await active.requests.close();
|
|
314
312
|
}
|
|
315
313
|
function hasUnattemptedTell(liveTells, tellPump, pending, attempted) {
|
|
316
314
|
return liveTells && tellPump === null && pending.some((tell) => !attempted.has(tell.id));
|
|
@@ -319,7 +317,7 @@ function persistProviderEvent(_input, _active, event) {
|
|
|
319
317
|
return event.type === "session" ? event.coordinate : undefined;
|
|
320
318
|
}
|
|
321
319
|
async function settleCompletion(result, session, requests) {
|
|
322
|
-
await requests
|
|
320
|
+
await requests.close();
|
|
323
321
|
return result.kind === "answered" ? { ...result, ...(session === undefined ? {} : { session }) } : result;
|
|
324
322
|
}
|
|
325
323
|
async function consumeTurnDrive(input, active) {
|
|
@@ -359,7 +357,7 @@ async function consumeTurnDrive(input, active) {
|
|
|
359
357
|
input.supervisor.next(heart).then((observation) => ({ kind: "heart", observation })),
|
|
360
358
|
...(tellObservation === null ? [] : [tellObservation]),
|
|
361
359
|
receiptFailure,
|
|
362
|
-
|
|
360
|
+
requests.failure,
|
|
363
361
|
]);
|
|
364
362
|
if (next.kind === "event" && !next.event.done) {
|
|
365
363
|
await writeProviderEvent(input, active, next.event.value);
|
|
@@ -394,7 +392,7 @@ async function consumeTurnDrive(input, active) {
|
|
|
394
392
|
}
|
|
395
393
|
await retireProviderCustody(input, turnSequence, drive);
|
|
396
394
|
try {
|
|
397
|
-
await requests
|
|
395
|
+
await requests.close();
|
|
398
396
|
}
|
|
399
397
|
catch { /* preserve the first pump failure */ }
|
|
400
398
|
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
|
|
@@ -423,7 +421,7 @@ async function driveTurn(input) {
|
|
|
423
421
|
}
|
|
424
422
|
catch (error) {
|
|
425
423
|
if (await heartExists(input.paths)) {
|
|
426
|
-
await active.requests
|
|
424
|
+
await active.requests.close();
|
|
427
425
|
return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error),
|
|
428
426
|
turnSequence: active.turnSequence };
|
|
429
427
|
}
|
|
@@ -538,6 +536,7 @@ async function runBodyTurns(input) {
|
|
|
538
536
|
body: initial ?? "",
|
|
539
537
|
...(initial === undefined ? {} : { call: initial }),
|
|
540
538
|
launchTells,
|
|
539
|
+
...(runtime.upstream === undefined ? {} : { upstream: runtime.upstream }),
|
|
541
540
|
now: runtime.now,
|
|
542
541
|
});
|
|
543
542
|
if (result.kind === "stopped") {
|
|
@@ -601,20 +600,30 @@ export async function spawnAkumaBody(launch) {
|
|
|
601
600
|
if (actorId === undefined)
|
|
602
601
|
throw new Error("Akuma wake has no born soul");
|
|
603
602
|
const owned = await spawnDetachedProcess({
|
|
604
|
-
argv: [process.execPath, ...process.execArgv, fileURLToPath(import.meta.url), encoded],
|
|
603
|
+
argv: [process.execPath, ...process.execArgv, fileURLToPath(new URL("../akuma-body.js", import.meta.url)), encoded],
|
|
605
604
|
cwd: await launchCwd(launch),
|
|
606
605
|
env: { ...process.env, KEIYAKU_ACTOR_ID: actorId },
|
|
607
606
|
log: launch.paths.log,
|
|
608
607
|
});
|
|
609
608
|
owned.release();
|
|
610
609
|
}
|
|
611
|
-
async function
|
|
610
|
+
export async function runAkumaBody(upstreamFor) {
|
|
612
611
|
const encoded = process.argv[2];
|
|
613
612
|
if (encoded === undefined)
|
|
614
613
|
throw new TypeError("Akuma body launch payload is missing");
|
|
615
614
|
const launch = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if (
|
|
619
|
-
|
|
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
|
+
};
|
|
624
|
+
await driveAkumaBody(launch, undefined, {
|
|
625
|
+
now: () => new Date().toISOString(),
|
|
626
|
+
spawnChild: spawnAkumaBody,
|
|
627
|
+
upstream: upstreamFor(launch, configuration),
|
|
628
|
+
});
|
|
620
629
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
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
|
+
import type { AllowedActions } from "../allowed.js";
|
|
5
|
+
import type { TaskMutationAction, TaskMutationRequest } from "../../task/mutation.js";
|
|
4
6
|
export type { ResumeCoordinate } from "../coordinate.js";
|
|
5
|
-
export type Confinement = Readonly<{
|
|
6
|
-
kind: "unconfined";
|
|
7
|
-
}> | Readonly<{
|
|
8
|
-
kind: "declared";
|
|
9
|
-
writableRoots: readonly string[];
|
|
10
|
-
}>;
|
|
11
7
|
export type AkumaOrigin = Readonly<{
|
|
12
8
|
kind: "direct";
|
|
13
9
|
}> | Readonly<{
|
|
@@ -28,10 +24,10 @@ export type Soul = Readonly<{
|
|
|
28
24
|
readonly?: ReadonlyRestraint;
|
|
29
25
|
cwd: string;
|
|
30
26
|
origin: AkumaOrigin;
|
|
31
|
-
|
|
27
|
+
allowed: AllowedActions;
|
|
32
28
|
createdAt: string;
|
|
33
29
|
}>;
|
|
34
|
-
export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "
|
|
30
|
+
export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "allowed">;
|
|
35
31
|
export type BodyEnd = "exited" | "broke-off" | "put-down";
|
|
36
32
|
export type BodyFact = Readonly<{
|
|
37
33
|
sequence: number;
|
|
@@ -127,28 +123,100 @@ export type TellReceiptInput = Readonly<{
|
|
|
127
123
|
turnSequence: number;
|
|
128
124
|
fence: string;
|
|
129
125
|
}>);
|
|
126
|
+
export type TaskRequestInput = Readonly<{
|
|
127
|
+
id: string;
|
|
128
|
+
action: TaskMutationAction;
|
|
129
|
+
world: string;
|
|
130
|
+
request: TaskMutationRequest;
|
|
131
|
+
}>;
|
|
130
132
|
export type RequestInput = Readonly<{
|
|
131
133
|
id: string;
|
|
134
|
+
action: "akuma.call";
|
|
132
135
|
archetype: string;
|
|
133
136
|
body: string;
|
|
134
137
|
cwd?: string;
|
|
135
138
|
world: string;
|
|
136
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
|
+
}> | Readonly<{
|
|
163
|
+
id: string;
|
|
164
|
+
action: "contract.review";
|
|
165
|
+
repoRoot: string;
|
|
166
|
+
contractId: string;
|
|
167
|
+
verdict: "satisfied" | "unsatisfied";
|
|
168
|
+
summary?: string;
|
|
169
|
+
}> | TaskRequestInput;
|
|
170
|
+
export type UpstreamRequestService = Readonly<{
|
|
171
|
+
action: "akuma.wait";
|
|
172
|
+
}> | Readonly<{
|
|
173
|
+
action: "akuma.tell";
|
|
174
|
+
target: AkuId;
|
|
175
|
+
tellId: string;
|
|
176
|
+
}> | Readonly<{
|
|
177
|
+
action: "akuma.kill";
|
|
178
|
+
results: readonly Readonly<{
|
|
179
|
+
id: AkuId;
|
|
180
|
+
evidence: KillEvidence;
|
|
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"];
|
|
137
194
|
}>;
|
|
138
|
-
|
|
195
|
+
type AdmittedRequest = RequestInput & Readonly<{
|
|
196
|
+
requester: AkuId;
|
|
139
197
|
admittedAt: string;
|
|
140
|
-
}
|
|
198
|
+
}>;
|
|
199
|
+
export type RequestFact = (AdmittedRequest & Readonly<{
|
|
141
200
|
state: "admitted";
|
|
142
|
-
}> |
|
|
201
|
+
}>) | (Extract<AdmittedRequest, {
|
|
202
|
+
action: "akuma.call";
|
|
203
|
+
}> & Readonly<{
|
|
143
204
|
state: "reserved";
|
|
144
205
|
child: AkuId;
|
|
145
|
-
}> |
|
|
206
|
+
}>) | (Extract<AdmittedRequest, {
|
|
207
|
+
action: "akuma.call";
|
|
208
|
+
}> & Readonly<{
|
|
146
209
|
state: "served";
|
|
147
210
|
child: AkuId;
|
|
148
|
-
}> |
|
|
211
|
+
}>) | (Exclude<AdmittedRequest, {
|
|
212
|
+
action: "akuma.call";
|
|
213
|
+
}> & Readonly<{
|
|
214
|
+
state: "served";
|
|
215
|
+
service: UpstreamRequestService;
|
|
216
|
+
}>) | (AdmittedRequest & Readonly<{
|
|
149
217
|
state: "refused";
|
|
150
218
|
diagnostic: string;
|
|
151
|
-
}> | Readonly<{
|
|
219
|
+
}>) | (AdmittedRequest & Readonly<{
|
|
152
220
|
state: "voided";
|
|
153
221
|
evidence: string;
|
|
154
222
|
}>);
|
|
@@ -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>;
|
|
@@ -16,15 +17,10 @@ export declare function appendActivity(paths: AkumaPaths, input: Readonly<{
|
|
|
16
17
|
event: unknown;
|
|
17
18
|
at: string;
|
|
18
19
|
}>): Promise<number>;
|
|
19
|
-
export type ActivitySliceInput = Readonly<{
|
|
20
|
-
before?: number;
|
|
21
|
-
since?: number;
|
|
22
|
-
limit?: number;
|
|
23
|
-
}>;
|
|
24
20
|
export type ActivitySlice = ActivityFactSlice;
|
|
25
21
|
export type { ActivityFact };
|
|
26
22
|
export type { TimelineFact } from "./timeline.js";
|
|
27
|
-
export declare function activitySlice(paths: AkumaPaths
|
|
23
|
+
export declare function activitySlice(paths: AkumaPaths): Promise<ActivitySlice>;
|
|
28
24
|
export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequence" | "state" | "deliveries">): Promise<Readonly<{
|
|
29
25
|
kind: "not-born";
|
|
30
26
|
} | {
|
|
@@ -33,15 +29,6 @@ export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequ
|
|
|
33
29
|
}>>;
|
|
34
30
|
export declare function recordTellDeliveries(paths: AkumaPaths, inputs: readonly TellDeliveryInput[]): Promise<void>;
|
|
35
31
|
export declare function recordTellReceipt(paths: AkumaPaths, input: TellReceiptInput): Promise<void>;
|
|
36
|
-
export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
|
|
37
|
-
admittedAt: string;
|
|
38
|
-
}>): Promise<RequestFact>;
|
|
39
|
-
export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
40
|
-
export declare function serveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
|
|
41
|
-
export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
|
|
42
|
-
export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
|
|
43
|
-
export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
|
|
44
|
-
export declare function readNonterminalRequests(paths: AkumaPaths): Promise<readonly RequestFact[]>;
|
|
45
32
|
export declare function readKill(paths: AkumaPaths, bodySequence: number): Promise<KillFact | null>;
|
|
46
33
|
export declare function requestStop(paths: AkumaPaths, at: string): Promise<Readonly<{
|
|
47
34
|
kind: "requested";
|
|
@@ -1,9 +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
|
-
import { isHeartAbsent, readSealFromLeash, transaction, withHeart } from "./storage.js";
|
|
4
|
+
import { isHeartAbsent, readSealFromLeash, readTransaction, transaction, withHeart } from "./storage.js";
|
|
5
5
|
import { soulFact } from "./soul.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
9
|
const ACTIVITY_LIMIT = 5_000;
|
|
9
10
|
export async function readSoul(paths) {
|
|
@@ -46,14 +47,20 @@ export async function appendActivity(paths, input) {
|
|
|
46
47
|
return sequence;
|
|
47
48
|
}));
|
|
48
49
|
}
|
|
49
|
-
export async function activitySlice(paths
|
|
50
|
-
|
|
51
|
-
return await withHeart(paths, (heart) => activityFactSlice(heart, { ...input, limit }));
|
|
50
|
+
export async function activitySlice(paths) {
|
|
51
|
+
return await withHeart(paths, (heart) => readTransaction(heart, () => activityFactSlice(heart)));
|
|
52
52
|
}
|
|
53
53
|
export async function recordTell(paths, tell) {
|
|
54
54
|
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
55
55
|
if (soulFact(heart) === null)
|
|
56
56
|
return { kind: "not-born" };
|
|
57
|
+
const existing = tellFact(heart, tell.id);
|
|
58
|
+
if (existing !== null) {
|
|
59
|
+
if (existing.body !== tell.body || existing.recordedAt !== tell.recordedAt) {
|
|
60
|
+
throw new Error(`tell ${tell.id} reused different input`);
|
|
61
|
+
}
|
|
62
|
+
return { kind: "recorded", tell: existing };
|
|
63
|
+
}
|
|
57
64
|
const sequence = insertTellFact(heart, tell);
|
|
58
65
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
59
66
|
return { kind: "recorded", tell: { sequence, ...tell, state: "pending", deliveries: [] } };
|
|
@@ -82,83 +89,6 @@ export async function recordTellReceipt(paths, input) {
|
|
|
82
89
|
pruneActivityFacts(heart, ACTIVITY_LIMIT);
|
|
83
90
|
}));
|
|
84
91
|
}
|
|
85
|
-
function sameRequestInput(fact, input) {
|
|
86
|
-
return fact.id === input.id
|
|
87
|
-
&& fact.archetype === input.archetype
|
|
88
|
-
&& fact.body === input.body
|
|
89
|
-
&& fact.cwd === input.cwd
|
|
90
|
-
&& fact.world === input.world
|
|
91
|
-
&& JSON.stringify(fact.recipe) === JSON.stringify(input.recipe);
|
|
92
|
-
}
|
|
93
|
-
export async function admitRequest(paths, input) {
|
|
94
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
95
|
-
insertRequestFact(heart, input);
|
|
96
|
-
const fact = requestFact(heart, input.id);
|
|
97
|
-
if (fact === null)
|
|
98
|
-
throw new Error(`Akuma request ${input.id} was not admitted`);
|
|
99
|
-
if (!sameRequestInput(fact, input))
|
|
100
|
-
throw new Error(`Akuma request ${input.id} reused different input`);
|
|
101
|
-
return fact;
|
|
102
|
-
}));
|
|
103
|
-
}
|
|
104
|
-
export async function reserveRequest(paths, id, child) {
|
|
105
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
106
|
-
const before = requestFact(heart, id);
|
|
107
|
-
if (before === null)
|
|
108
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
109
|
-
if (before.state === "admitted")
|
|
110
|
-
updateRequestReserved(heart, id, child);
|
|
111
|
-
else if ((before.state !== "reserved" && before.state !== "served") || before.child !== child) {
|
|
112
|
-
throw new Error(`Akuma request ${id} cannot reserve ${child}`);
|
|
113
|
-
}
|
|
114
|
-
return requestFact(heart, id);
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
|
-
export async function serveRequest(paths, id, child) {
|
|
118
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
119
|
-
const before = requestFact(heart, id);
|
|
120
|
-
if (before === null)
|
|
121
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
122
|
-
if (before.state === "reserved" && before.child === child)
|
|
123
|
-
updateRequestServed(heart, id, child);
|
|
124
|
-
else if (before.state !== "served" || before.child !== child) {
|
|
125
|
-
throw new Error(`Akuma request ${id} cannot serve ${child}`);
|
|
126
|
-
}
|
|
127
|
-
return requestFact(heart, id);
|
|
128
|
-
}));
|
|
129
|
-
}
|
|
130
|
-
export async function refuseRequest(paths, id, diagnostic) {
|
|
131
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
132
|
-
const before = requestFact(heart, id);
|
|
133
|
-
if (before === null)
|
|
134
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
135
|
-
if (before.state === "admitted")
|
|
136
|
-
updateRequestRefused(heart, id, diagnostic);
|
|
137
|
-
else if (before.state !== "refused" || before.diagnostic !== diagnostic) {
|
|
138
|
-
throw new Error(`Akuma request ${id} cannot be refused`);
|
|
139
|
-
}
|
|
140
|
-
return requestFact(heart, id);
|
|
141
|
-
}));
|
|
142
|
-
}
|
|
143
|
-
export async function voidRequest(paths, id, evidence) {
|
|
144
|
-
return await withHeart(paths, (heart) => transaction(heart, () => {
|
|
145
|
-
const before = requestFact(heart, id);
|
|
146
|
-
if (before === null)
|
|
147
|
-
throw new Error(`unknown Akuma request ${id}`);
|
|
148
|
-
if (before.state === "admitted" || before.state === "reserved")
|
|
149
|
-
updateRequestVoided(heart, id, evidence);
|
|
150
|
-
else if (before.state !== "voided" || before.evidence !== evidence) {
|
|
151
|
-
throw new Error(`Akuma request ${id} cannot be voided`);
|
|
152
|
-
}
|
|
153
|
-
return requestFact(heart, id);
|
|
154
|
-
}));
|
|
155
|
-
}
|
|
156
|
-
export async function readRequest(paths, id) {
|
|
157
|
-
return await withHeart(paths, (heart) => requestFact(heart, id));
|
|
158
|
-
}
|
|
159
|
-
export async function readNonterminalRequests(paths) {
|
|
160
|
-
return await withHeart(paths, nonterminalRequestFacts);
|
|
161
|
-
}
|
|
162
92
|
export async function readKill(paths, bodySequence) {
|
|
163
93
|
return await withHeart(paths, (heart) => killFactForBody(heart, bodySequence));
|
|
164
94
|
}
|
|
@@ -234,7 +164,7 @@ export async function finishBodyIfIdle(paths, input) {
|
|
|
234
164
|
}
|
|
235
165
|
export async function readHeart(paths) {
|
|
236
166
|
try {
|
|
237
|
-
return await withHeart(paths, (heart) => ({
|
|
167
|
+
return await withHeart(paths, (heart) => readTransaction(heart, () => ({
|
|
238
168
|
soul: soulFact(heart),
|
|
239
169
|
latestBody: latestBodyFact(heart),
|
|
240
170
|
latestSession: latestSessionFact(heart),
|
|
@@ -242,7 +172,7 @@ export async function readHeart(paths) {
|
|
|
242
172
|
latestKill: latestKillFact(heart),
|
|
243
173
|
stop: stopFact(heart),
|
|
244
174
|
pause: pauseFact(heart),
|
|
245
|
-
}));
|
|
175
|
+
})));
|
|
246
176
|
}
|
|
247
177
|
catch (error) {
|
|
248
178
|
if (isHeartAbsent(error)) {
|
|
@@ -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[]>;
|