@astrosheep/keiyaku 4.6.19 → 4.6.21
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 +7 -3
- package/build/plugins/pi/README.md +111 -0
- package/build/plugins/pi/akuma-tools.ts +310 -0
- package/build/plugins/pi/keiyaku.ts +2 -0
- package/build/src/akuma/akuma-call.d.ts +4 -1
- package/build/src/akuma/akuma-call.js +24 -7
- package/build/src/akuma/akuma-instance.d.ts +28 -8
- package/build/src/akuma/akuma-instance.js +85 -42
- package/build/src/akuma/akuma-owner.d.ts +18 -9
- package/build/src/akuma/akuma-owner.js +31 -25
- package/build/src/akuma/akuma-selection-execution.d.ts +4 -1
- package/build/src/akuma/akuma-selection-execution.js +8 -4
- package/build/src/akuma/akuma.d.ts +17 -0
- package/build/src/akuma/body-launch.d.ts +107 -0
- package/build/src/akuma/body-launch.js +57 -0
- package/build/src/akuma/body-supervisor.d.ts +7 -6
- package/build/src/akuma/body-supervisor.js +17 -12
- package/build/src/akuma/body.d.ts +13 -94
- package/build/src/akuma/body.js +124 -296
- package/build/src/akuma/call-input.d.ts +2 -0
- package/build/src/akuma/call-input.js +21 -1
- package/build/src/akuma/call-request.d.ts +6 -2
- package/build/src/akuma/call-request.js +9 -1
- package/build/src/akuma/detached-body.d.ts +9 -0
- package/build/src/akuma/detached-body.js +94 -0
- package/build/src/akuma/execution-instructions.d.ts +8 -0
- package/build/src/akuma/execution-instructions.js +17 -0
- package/build/src/akuma/heart/facts.d.ts +21 -1
- package/build/src/akuma/heart/facts.js +10 -0
- package/build/src/akuma/heart/index.d.ts +16 -1
- package/build/src/akuma/heart/index.js +95 -30
- package/build/src/akuma/heart/rows.d.ts +14 -2
- package/build/src/akuma/heart/rows.js +48 -4
- package/build/src/akuma/heart/schema.d.ts +4 -1
- package/build/src/akuma/heart/schema.js +87 -30
- package/build/src/akuma/heart/soul.js +4 -0
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +59 -15
- package/build/src/akuma/heart/timeline.d.ts +6 -4
- package/build/src/akuma/heart/timeline.js +14 -4
- package/build/src/akuma/in-process-body.d.ts +5 -0
- package/build/src/akuma/in-process-body.js +57 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/projection.d.ts +44 -1
- package/build/src/akuma/projection.js +13 -1
- package/build/src/akuma/provider.d.ts +4 -0
- package/build/src/akuma/providers/acp/core.js +1 -1
- package/build/src/akuma/providers/acp/index.js +3 -0
- package/build/src/akuma/providers/claude/index.js +8 -5
- package/build/src/akuma/providers/codex-app-server/configuration.d.ts +5 -0
- package/build/src/akuma/providers/codex-app-server/configuration.js +72 -0
- package/build/src/akuma/providers/codex-app-server/index.js +7 -10
- package/build/src/akuma/providers/execution-environment.d.ts +8 -2
- package/build/src/akuma/providers/execution-environment.js +10 -1
- package/build/src/akuma/providers/grok-build/index.js +23 -16
- package/build/src/akuma/providers/index.d.ts +1 -0
- package/build/src/akuma/providers/index.js +8 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +9 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +6 -0
- package/build/src/akuma/providers/opencode-sdk/session.js +4 -3
- package/build/src/akuma/providers/paseo/index.js +8 -2
- package/build/src/akuma/providers/pi/index.js +27 -10
- package/build/src/akuma/publication.d.ts +4 -3
- package/build/src/akuma/publication.js +21 -18
- package/build/src/akuma/selection-observation.d.ts +51 -0
- package/build/src/akuma/selection-owner-port.d.ts +2 -1
- package/build/src/akuma/selection-owner-port.js +4 -3
- package/build/src/akuma/turn-drive.d.ts +4 -2
- package/build/src/akuma/turn-drive.js +58 -21
- package/build/src/akuma-body.d.ts +0 -10
- package/build/src/akuma-body.js +13 -118
- package/build/src/body-host.d.ts +28 -0
- package/build/src/body-host.js +86 -0
- package/build/src/body-requests.d.ts +13 -0
- package/build/src/body-requests.js +131 -0
- package/build/src/cli/commands/akuma-grammar.d.ts +8 -1
- package/build/src/cli/commands/akuma-grammar.js +36 -6
- package/build/src/cli/commands/akuma.js +11 -0
- package/build/src/cli/commands/report.d.ts +6 -0
- package/build/src/cli/commands/report.js +31 -0
- package/build/src/cli/parse.js +1 -0
- package/build/src/cli/render/akuma-activity.js +27 -17
- package/build/src/cli/render/terminal.d.ts +5 -0
- package/build/src/cli/render/terminal.js +7 -0
- package/build/src/cli/runtime.js +4 -1
- package/build/src/index.d.ts +3 -1
- package/build/src/index.js +1 -0
- package/build/src/library/akuma-creation.d.ts +7 -3
- package/build/src/library/akuma-creation.js +23 -11
- package/build/src/library/akumas.d.ts +4 -1
- package/build/src/library/akumas.js +13 -5
- package/build/src/library/selection.d.ts +2 -1
- package/build/src/library/selection.js +6 -3
- package/build/src/plugin/public.d.ts +11 -0
- package/build/src/plugin/runtime.js +1 -0
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +3 -3
- package/plugins/paseo/plugin/server/keiyaku.ts +1 -0
- package/plugins/paseo/plugin/server/mirror.ts +2 -2
- package/plugins/pi/README.md +111 -0
- package/plugins/pi/akuma-tools.ts +310 -0
- package/plugins/pi/keiyaku.ts +2 -0
package/build/src/akuma-body.js
CHANGED
|
@@ -1,128 +1,23 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { selectionRequestPort } from "./akuma/selection-owner-port.js";
|
|
8
|
-
import { selectionRequestCommands } from "./akuma/selection-request.js";
|
|
9
|
-
import { composeContractLibrary } from "./library/contract-composition.js";
|
|
10
|
-
import { contractRequestCommands } from "./library/contract-operations.js";
|
|
11
|
-
import { createKeiyakuHandle } from "./library/keiyaku.js";
|
|
12
|
-
import { Repo } from "./library/repo.js";
|
|
13
|
-
import { settings } from "./settings.js";
|
|
14
|
-
import { Debts } from "./debt/index.js";
|
|
15
|
-
import { debtMutationRequestCommands } from "./debt/mutation.js";
|
|
16
|
-
import { World } from "./world.js";
|
|
17
|
-
import { readSoul } from "./akuma/heart/index.js";
|
|
18
|
-
async function contractDependencies(repoRoot, processConfiguration) {
|
|
19
|
-
const repo = await Repo.at({
|
|
20
|
-
path: repoRoot,
|
|
21
|
-
...(processConfiguration.gitPath === undefined ? {} : { gitPath: processConfiguration.gitPath }),
|
|
22
|
-
});
|
|
23
|
-
if (repo.root !== repoRoot)
|
|
24
|
-
throw new TypeError("forwarded Contract repoRoot must equal the canonical primary worktree");
|
|
25
|
-
const world = await World.prove(repo.root);
|
|
26
|
-
const configuration = await settings({
|
|
27
|
-
root: world,
|
|
28
|
-
...(processConfiguration.home === undefined ? {} : { home: processConfiguration.home }),
|
|
29
|
-
});
|
|
30
|
-
return [repo, configuration];
|
|
31
|
-
}
|
|
32
|
-
function contractChannel(repo, contractId, requester, configuration) {
|
|
33
|
-
return composeContractLibrary(localExecutionContext(), createKeiyakuHandle, {
|
|
34
|
-
settings: configuration,
|
|
35
|
-
actor: requester,
|
|
36
|
-
}).select({
|
|
37
|
-
repo,
|
|
38
|
-
id: contractId,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function contractUpstream(processConfiguration) {
|
|
42
|
-
return {
|
|
43
|
-
previewDelivery: async (input) => {
|
|
44
|
-
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
45
|
-
return await contractChannel(repo, input.contractId, input.requester, configuration).previewDelivery({
|
|
46
|
-
includeDirty: input.includeDirty,
|
|
47
|
-
showDiff: input.showDiff,
|
|
48
|
-
signal: input.signal,
|
|
49
|
-
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
50
|
-
},
|
|
51
|
-
deliver: async (input) => {
|
|
52
|
-
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
53
|
-
return await contractChannel(repo, input.contractId, input.requester, configuration).deliver({
|
|
54
|
-
includeDirty: input.includeDirty,
|
|
55
|
-
materializeConflict: input.materializeConflict,
|
|
56
|
-
...(input.message === undefined ? {} : { message: input.message }),
|
|
57
|
-
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
58
|
-
signal: input.signal,
|
|
59
|
-
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
60
|
-
},
|
|
61
|
-
review: async (input) => {
|
|
62
|
-
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
63
|
-
return await contractChannel(repo, input.contractId, input.requester, configuration).review({
|
|
64
|
-
verdict: input.verdict,
|
|
65
|
-
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
66
|
-
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
67
|
-
signal: input.signal,
|
|
68
|
-
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
const DEBT_LIFECYCLE = {
|
|
73
|
-
done: async (handle, input) => await handle.done(input),
|
|
74
|
-
drop: async (handle, input) => await handle.drop(input),
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* The upper Body edge composes the forced-local Debts SDK the descriptor
|
|
78
|
-
* execution entries consume. Each ability is one ordinary local product
|
|
79
|
-
* operation; no generic debt(request) dispatcher is introduced here.
|
|
80
|
-
*/
|
|
81
|
-
function debtMutationRequestPort() {
|
|
82
|
-
return {
|
|
83
|
-
add: async ({ world, options }) => await Debts.of(world).add(options),
|
|
84
|
-
addDocument: async ({ world, document }) => await Debts.of(world).addDocument(document),
|
|
85
|
-
update: async ({ world, id, options }) => await Debts.of(world).debt({ id }).update(options),
|
|
86
|
-
lifecycle: async ({ world, verb, id, note, signal }) => await DEBT_LIFECYCLE[verb](Debts.of(world).debt({ id }), {
|
|
87
|
-
...(note === undefined ? {} : { note }),
|
|
88
|
-
...(signal === undefined ? {} : { signal }),
|
|
89
|
-
}),
|
|
90
|
-
batch: async ({ world, verb, ids, note, signal }) => await Debts.of(world).batch({
|
|
91
|
-
verb,
|
|
92
|
-
ids,
|
|
93
|
-
...(note === undefined ? {} : { note }),
|
|
94
|
-
...(signal === undefined ? {} : { signal }),
|
|
95
|
-
}),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
export async function externalRequestCommandsFor(launch, processConfiguration) {
|
|
99
|
-
const world = await World.prove(worldRootForAkumaPaths(launch.paths));
|
|
100
|
-
const servingBody = launch.seed?.id ?? (await readSoul(launch.paths))?.id;
|
|
101
|
-
return {
|
|
102
|
-
world,
|
|
103
|
-
commands: composeRequestCommands(selectionRequestCommands(selectionRequestPort(world, (message) => {
|
|
104
|
-
void recordPluginDiagnostic(launch.paths, "outcome observation", message);
|
|
105
|
-
}, servingBody)), contractRequestCommands(contractUpstream(processConfiguration)), debtMutationRequestCommands(debtMutationRequestPort())),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function bodyProcessConfiguration() {
|
|
109
|
-
const mappedHome = process.env.KEIYAKU_HOME?.trim();
|
|
110
|
-
const mappedGitPath = process.env.KEIYAKU_GIT_PATH;
|
|
111
|
-
if (mappedGitPath !== undefined && mappedGitPath.trim().length === 0) {
|
|
112
|
-
throw new TypeError("KEIYAKU_GIT_PATH requires a nonblank value");
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
...(mappedHome === undefined || mappedHome.length === 0 ? {} : { home: mappedHome }),
|
|
116
|
-
...(mappedGitPath === undefined ? {} : { gitPath: mappedGitPath }),
|
|
117
|
-
};
|
|
118
|
-
}
|
|
3
|
+
import { driveAkumaBody } from "./akuma/body.js";
|
|
4
|
+
import { bodyLaunchSchema } from "./akuma/body-launch.js";
|
|
5
|
+
import { LEASH_HELD_EXIT, spawnAkumaBody } from "./akuma/detached-body.js";
|
|
6
|
+
import { externalRequestCommandsFor, bodyProcessConfiguration } from "./body-requests.js";
|
|
119
7
|
async function runBodyEntrypoint() {
|
|
120
8
|
const encoded = process.argv[2];
|
|
121
9
|
if (encoded === undefined)
|
|
122
10
|
throw new TypeError("Akuma body launch payload is missing");
|
|
123
11
|
const launch = bodyLaunchSchema.parse(JSON.parse(Buffer.from(encoded, "base64url").toString("utf8")));
|
|
124
|
-
const
|
|
125
|
-
|
|
12
|
+
const spawn = spawnAkumaBody;
|
|
13
|
+
const { world, commands, executionAssociation } = await externalRequestCommandsFor(launch, bodyProcessConfiguration(), spawn);
|
|
14
|
+
if ((await driveAkumaBody(launch, undefined, {
|
|
15
|
+
world,
|
|
16
|
+
externalCommands: commands,
|
|
17
|
+
executionAssociation,
|
|
18
|
+
spawn,
|
|
19
|
+
requestSpawn: spawn,
|
|
20
|
+
})) === "held")
|
|
126
21
|
process.exitCode = LEASH_HELD_EXIT;
|
|
127
22
|
}
|
|
128
23
|
/** Only the spawned entrypoint launches a Body; importing this module composes commands without side effects. */
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BodyLauncher } from "./akuma/body-launch.js";
|
|
2
|
+
export type AkumaHostOptions = Readonly<{
|
|
3
|
+
/** Detached by default. In-process Bodies share this Node runtime's lifetime. */
|
|
4
|
+
hosting?: "detached" | "in-process";
|
|
5
|
+
/** Plugin diagnostics produced in this host, never remote Body logs. */
|
|
6
|
+
reportDiagnostic?: (message: string) => void;
|
|
7
|
+
}>;
|
|
8
|
+
declare class ScopedAkumaHost {
|
|
9
|
+
#private;
|
|
10
|
+
static launcher(scope: ScopedAkumaHost): BodyLauncher;
|
|
11
|
+
readonly hosting: "in-process";
|
|
12
|
+
readonly reportDiagnostic?: (message: string) => void;
|
|
13
|
+
constructor(options?: Pick<AkumaHostOptions, "reportDiagnostic">);
|
|
14
|
+
/** Stop only this scope's exact launches. Hung/failed retirement rejects; no identity-wide kill is issued. */
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/** An ephemeral capability, not an Akuma identity set or persisted hosting policy. */
|
|
18
|
+
export type AkumaHostScope = ScopedAkumaHost;
|
|
19
|
+
export declare const AkumaHost: Readonly<{
|
|
20
|
+
/** Create an in-process launch scope. Pass the scope itself as the public host option. */
|
|
21
|
+
inProcess(options?: Pick<AkumaHostOptions, "reportDiagnostic">): AkumaHostScope;
|
|
22
|
+
}>;
|
|
23
|
+
/** Capture host capabilities once, independently of observation and request routing. */
|
|
24
|
+
export declare function captureAkumaHost(host?: AkumaHostOptions): Readonly<{
|
|
25
|
+
spawn: BodyLauncher;
|
|
26
|
+
reportDiagnostic?: (message: string) => void;
|
|
27
|
+
}>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { setMaxListeners } from "node:events";
|
|
2
|
+
import { spawnAkumaBody } from "./akuma/detached-body.js";
|
|
3
|
+
import { launchInProcessBody } from "./akuma/in-process-body.js";
|
|
4
|
+
import { bodyProcessConfiguration, externalRequestCommandsFor } from "./body-requests.js";
|
|
5
|
+
function inProcessLauncher(scopeSignal, enroll) {
|
|
6
|
+
const spawn = (launch) => {
|
|
7
|
+
scopeSignal?.throwIfAborted();
|
|
8
|
+
const pending = launchInProcessBody(launch, async (signal) => {
|
|
9
|
+
signal.throwIfAborted();
|
|
10
|
+
const { world, commands, executionAssociation } = await externalRequestCommandsFor(launch, bodyProcessConfiguration(), spawnAkumaBody);
|
|
11
|
+
return { world, externalCommands: commands, executionAssociation, spawn, requestSpawn: spawnAkumaBody };
|
|
12
|
+
}, undefined, scopeSignal);
|
|
13
|
+
// Every launch, including automatic succession, enrols before yielding.
|
|
14
|
+
enroll?.(pending);
|
|
15
|
+
return pending;
|
|
16
|
+
};
|
|
17
|
+
return spawn;
|
|
18
|
+
}
|
|
19
|
+
const inProcessBody = inProcessLauncher();
|
|
20
|
+
class ScopedAkumaHost {
|
|
21
|
+
static launcher(scope) {
|
|
22
|
+
return scope.#launch;
|
|
23
|
+
}
|
|
24
|
+
hosting = "in-process";
|
|
25
|
+
reportDiagnostic;
|
|
26
|
+
#controller = new AbortController();
|
|
27
|
+
#active = new Set();
|
|
28
|
+
#failures = [];
|
|
29
|
+
#closing;
|
|
30
|
+
#launch;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
setMaxListeners(0, this.#controller.signal);
|
|
33
|
+
const reportDiagnostic = captureAkumaHost(options).reportDiagnostic;
|
|
34
|
+
if (reportDiagnostic !== undefined)
|
|
35
|
+
this.reportDiagnostic = reportDiagnostic;
|
|
36
|
+
this.#launch = inProcessLauncher(this.#controller.signal, (pending) => {
|
|
37
|
+
const done = pending.then((child) => child.completed);
|
|
38
|
+
this.#active.add(done);
|
|
39
|
+
void done.then(() => this.#active.delete(done), (error) => {
|
|
40
|
+
this.#active.delete(done);
|
|
41
|
+
this.#failures.push(error);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
Object.freeze(this);
|
|
45
|
+
}
|
|
46
|
+
/** Stop only this scope's exact launches. Hung/failed retirement rejects; no identity-wide kill is issued. */
|
|
47
|
+
close() {
|
|
48
|
+
if (this.#closing !== undefined)
|
|
49
|
+
return this.#closing;
|
|
50
|
+
this.#controller.abort(new Error("Akuma host scope is closed"));
|
|
51
|
+
this.#closing = (async () => {
|
|
52
|
+
await Promise.allSettled([...this.#active]);
|
|
53
|
+
if (this.#failures.length)
|
|
54
|
+
throw new AggregateError(this.#failures, "Akuma host scope retirement failed");
|
|
55
|
+
})();
|
|
56
|
+
return this.#closing;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export const AkumaHost = Object.freeze({
|
|
60
|
+
/** Create an in-process launch scope. Pass the scope itself as the public host option. */
|
|
61
|
+
inProcess(options) {
|
|
62
|
+
return new ScopedAkumaHost(options);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
/** Capture host capabilities once, independently of observation and request routing. */
|
|
66
|
+
export function captureAkumaHost(host) {
|
|
67
|
+
if (host !== undefined && (typeof host !== "object" || host === null || Array.isArray(host)))
|
|
68
|
+
throw new TypeError("Akuma host options must be an object");
|
|
69
|
+
const unknown = Object.keys(host ?? {}).find((key) => key !== "reportDiagnostic" && key !== "hosting");
|
|
70
|
+
if (unknown !== undefined)
|
|
71
|
+
throw new TypeError(`Akuma host options has unknown field: ${unknown}`);
|
|
72
|
+
const hosting = host?.hosting;
|
|
73
|
+
if (hosting !== undefined && hosting !== "detached" && hosting !== "in-process")
|
|
74
|
+
throw new TypeError("Akuma host hosting must be detached or in-process");
|
|
75
|
+
const reportDiagnostic = host?.reportDiagnostic;
|
|
76
|
+
if (reportDiagnostic !== undefined && typeof reportDiagnostic !== "function")
|
|
77
|
+
throw new TypeError("Akuma host reportDiagnostic must be a function");
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
spawn: host instanceof ScopedAkumaHost
|
|
80
|
+
? ScopedAkumaHost.launcher(host)
|
|
81
|
+
: hosting === "in-process"
|
|
82
|
+
? inProcessBody
|
|
83
|
+
: spawnAkumaBody,
|
|
84
|
+
...(reportDiagnostic === undefined ? {} : { reportDiagnostic }),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BodyLaunch, BodyLauncher } from "./akuma/body-launch.js";
|
|
2
|
+
import { World } from "./world.js";
|
|
3
|
+
import type { ExecutionAssociationReader } from "./akuma/execution-instructions.js";
|
|
4
|
+
export type BodyProcessConfiguration = Readonly<{
|
|
5
|
+
home?: string;
|
|
6
|
+
gitPath?: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function externalRequestCommandsFor(launch: BodyLaunch, processConfiguration: BodyProcessConfiguration, spawn: BodyLauncher): Promise<Readonly<{
|
|
9
|
+
world: Awaited<ReturnType<typeof World.prove>>;
|
|
10
|
+
commands: Readonly<Record<string, import("./akuma/request-wire.js").ErasedRequestCommand>>;
|
|
11
|
+
executionAssociation: ExecutionAssociationReader;
|
|
12
|
+
}>>;
|
|
13
|
+
export declare function bodyProcessConfiguration(): BodyProcessConfiguration;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { worldRootForAkumaPaths } from "./akuma/identity.js";
|
|
2
|
+
import { composeRequestCommands } from "./akuma/request-wire.js";
|
|
3
|
+
import { localExecutionContext } from "./akuma/requests.js";
|
|
4
|
+
import { selectionRequestPort } from "./akuma/selection-owner-port.js";
|
|
5
|
+
import { selectionRequestCommands } from "./akuma/selection-request.js";
|
|
6
|
+
import { composeContractLibrary } from "./library/contract-composition.js";
|
|
7
|
+
import { contractRequestCommands } from "./library/contract-operations.js";
|
|
8
|
+
import { createKeiyakuHandle } from "./library/keiyaku.js";
|
|
9
|
+
import { Repo } from "./library/repo.js";
|
|
10
|
+
import { settings } from "./settings.js";
|
|
11
|
+
import { Debts } from "./debt/index.js";
|
|
12
|
+
import { debtMutationRequestCommands } from "./debt/mutation.js";
|
|
13
|
+
import { World } from "./world.js";
|
|
14
|
+
import { readSoul } from "./akuma/heart/index.js";
|
|
15
|
+
import { readDispatch } from "./dispatch/index.js";
|
|
16
|
+
import { NoGitWorldError, repositoryAt } from "./git/repository.js";
|
|
17
|
+
async function contractDependencies(repoRoot, processConfiguration) {
|
|
18
|
+
const repo = await Repo.at({
|
|
19
|
+
path: repoRoot,
|
|
20
|
+
...(processConfiguration.gitPath === undefined ? {} : { gitPath: processConfiguration.gitPath }),
|
|
21
|
+
});
|
|
22
|
+
if (repo.root !== repoRoot)
|
|
23
|
+
throw new TypeError("forwarded Contract repoRoot must equal the canonical primary worktree");
|
|
24
|
+
const world = await World.prove(repo.root);
|
|
25
|
+
const configuration = await settings({
|
|
26
|
+
root: world,
|
|
27
|
+
...(processConfiguration.home === undefined ? {} : { home: processConfiguration.home }),
|
|
28
|
+
});
|
|
29
|
+
return [repo, configuration];
|
|
30
|
+
}
|
|
31
|
+
function contractChannel(repo, contractId, requester, configuration) {
|
|
32
|
+
return composeContractLibrary(localExecutionContext(), createKeiyakuHandle, {
|
|
33
|
+
settings: configuration,
|
|
34
|
+
actor: requester,
|
|
35
|
+
}).select({
|
|
36
|
+
repo,
|
|
37
|
+
id: contractId,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function contractUpstream(processConfiguration) {
|
|
41
|
+
return {
|
|
42
|
+
previewDelivery: async (input) => {
|
|
43
|
+
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
44
|
+
return await contractChannel(repo, input.contractId, input.requester, configuration).previewDelivery({
|
|
45
|
+
includeDirty: input.includeDirty,
|
|
46
|
+
showDiff: input.showDiff,
|
|
47
|
+
signal: input.signal,
|
|
48
|
+
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
49
|
+
},
|
|
50
|
+
deliver: async (input) => {
|
|
51
|
+
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
52
|
+
return await contractChannel(repo, input.contractId, input.requester, configuration).deliver({
|
|
53
|
+
includeDirty: input.includeDirty,
|
|
54
|
+
materializeConflict: input.materializeConflict,
|
|
55
|
+
...(input.message === undefined ? {} : { message: input.message }),
|
|
56
|
+
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
57
|
+
signal: input.signal,
|
|
58
|
+
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
59
|
+
},
|
|
60
|
+
review: async (input) => {
|
|
61
|
+
const [repo, configuration] = await contractDependencies(input.repoRoot, processConfiguration);
|
|
62
|
+
return await contractChannel(repo, input.contractId, input.requester, configuration).review({
|
|
63
|
+
verdict: input.verdict,
|
|
64
|
+
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
65
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
66
|
+
signal: input.signal,
|
|
67
|
+
}, input.observe === undefined ? undefined : { observe: input.observe });
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const DEBT_LIFECYCLE = {
|
|
72
|
+
done: async (handle, input) => await handle.done(input),
|
|
73
|
+
drop: async (handle, input) => await handle.drop(input),
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* The upper Body edge composes the forced-local Debts SDK the descriptor
|
|
77
|
+
* execution entries consume. Each ability is one ordinary local product
|
|
78
|
+
* operation; no generic debt(request) dispatcher is introduced here.
|
|
79
|
+
*/
|
|
80
|
+
function debtMutationRequestPort() {
|
|
81
|
+
return {
|
|
82
|
+
add: async ({ world, options }) => await Debts.of(world).add(options),
|
|
83
|
+
addDocument: async ({ world, document }) => await Debts.of(world).addDocument(document),
|
|
84
|
+
update: async ({ world, id, options }) => await Debts.of(world).debt({ id }).update(options),
|
|
85
|
+
lifecycle: async ({ world, verb, id, note, signal }) => await DEBT_LIFECYCLE[verb](Debts.of(world).debt({ id }), {
|
|
86
|
+
...(note === undefined ? {} : { note }),
|
|
87
|
+
...(signal === undefined ? {} : { signal }),
|
|
88
|
+
}),
|
|
89
|
+
batch: async ({ world, verb, ids, note, signal }) => await Debts.of(world).batch({
|
|
90
|
+
verb,
|
|
91
|
+
ids,
|
|
92
|
+
...(note === undefined ? {} : { note }),
|
|
93
|
+
...(signal === undefined ? {} : { signal }),
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export async function externalRequestCommandsFor(launch, processConfiguration, spawn) {
|
|
98
|
+
const world = await World.prove(worldRootForAkumaPaths(launch.paths));
|
|
99
|
+
const servingBody = launch.seed?.id ?? (await readSoul(launch.paths))?.id;
|
|
100
|
+
return {
|
|
101
|
+
world,
|
|
102
|
+
executionAssociation: async () => {
|
|
103
|
+
if (servingBody !== undefined) {
|
|
104
|
+
try {
|
|
105
|
+
const dispatch = await readDispatch(await repositoryAt(world), servingBody);
|
|
106
|
+
if (dispatch !== null)
|
|
107
|
+
return { contractId: dispatch.contractId };
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (!(error instanceof NoGitWorldError)) {
|
|
111
|
+
console.error(`Keiyaku execution association unavailable for ${servingBody}: ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const contractId = launch.completion?.contractId;
|
|
116
|
+
return contractId === undefined ? undefined : { contractId };
|
|
117
|
+
},
|
|
118
|
+
commands: composeRequestCommands(selectionRequestCommands(selectionRequestPort(world, spawn, servingBody)), contractRequestCommands(contractUpstream(processConfiguration)), debtMutationRequestCommands(debtMutationRequestPort())),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function bodyProcessConfiguration() {
|
|
122
|
+
const mappedHome = process.env.KEIYAKU_HOME?.trim();
|
|
123
|
+
const mappedGitPath = process.env.KEIYAKU_GIT_PATH;
|
|
124
|
+
if (mappedGitPath !== undefined && mappedGitPath.trim().length === 0) {
|
|
125
|
+
throw new TypeError("KEIYAKU_GIT_PATH requires a nonblank value");
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
...(mappedHome === undefined || mappedHome.length === 0 ? {} : { home: mappedHome }),
|
|
129
|
+
...(mappedGitPath === undefined ? {} : { gitPath: mappedGitPath }),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -24,10 +24,14 @@ export type ParsedAkumaCommand = Output & ((Readonly<{
|
|
|
24
24
|
mode: "wait" | "detach";
|
|
25
25
|
timeoutMs?: number;
|
|
26
26
|
allowed?: AllowedActions;
|
|
27
|
+
writableDirectories?: readonly string[];
|
|
28
|
+
bare?: boolean;
|
|
27
29
|
schema?: string;
|
|
28
30
|
}> & Readonly<{
|
|
29
31
|
prompt?: AkumaPromptSource;
|
|
30
|
-
}>) | Readonly<{
|
|
32
|
+
}>) | (Readonly<{
|
|
33
|
+
command: "report";
|
|
34
|
+
}> & Prompted) | Readonly<{
|
|
31
35
|
command: "kill";
|
|
32
36
|
akuma: readonly string[];
|
|
33
37
|
}> | Readonly<{
|
|
@@ -58,10 +62,13 @@ export type ParsedAkumaCommand = Output & ((Readonly<{
|
|
|
58
62
|
}> | (Readonly<{
|
|
59
63
|
command: "fork";
|
|
60
64
|
at: string;
|
|
65
|
+
bare?: boolean;
|
|
61
66
|
}> & Addressed));
|
|
62
67
|
export type InvokedAkumaCommand = Exclude<ParsedAkumaCommand, {
|
|
63
68
|
command: "history";
|
|
64
69
|
contract: string;
|
|
70
|
+
} | {
|
|
71
|
+
command: "report";
|
|
65
72
|
}>;
|
|
66
73
|
export type AkumaAction = ParsedAkumaCommand["command"];
|
|
67
74
|
export declare function isAkumaAction(value: string | undefined): value is AkumaAction;
|
|
@@ -9,6 +9,14 @@ const SET_SELECTORS = '(<aku/...> | @alias | <kei/...> | "aku/<name-pattern>/<he
|
|
|
9
9
|
const SET_DETAILS = "Globs contain * and use lowercase hex digits or * in the suffix. --repo requires at least one Contract (kei/...) selector.";
|
|
10
10
|
const SCHEMA_DETAILS = "--schema supplies a JSON Schema answer contract to the provider; on observation the CLI parses JSON but does not independently validate schema conformance.";
|
|
11
11
|
const AKUMA_COMMAND_SPECS = {
|
|
12
|
+
report: {
|
|
13
|
+
arity: 1,
|
|
14
|
+
stdin: true,
|
|
15
|
+
flags: { json: "boolean" },
|
|
16
|
+
usage: "report (<text> | -) [--json]",
|
|
17
|
+
purpose: "Record progress in the invoking Akuma's Heart without ending work.",
|
|
18
|
+
details: "Give one nonblank text argument, or - to read stdin. Requires explicit Akuma, World, Body and Turn execution declarations; no recipient or parent forwarding. Recorded means persisted, not received.",
|
|
19
|
+
},
|
|
12
20
|
call: {
|
|
13
21
|
arity: 1,
|
|
14
22
|
stdin: true,
|
|
@@ -17,18 +25,23 @@ const AKUMA_COMMAND_SPECS = {
|
|
|
17
25
|
alias: "value",
|
|
18
26
|
wait: "value",
|
|
19
27
|
allowed: "repeat",
|
|
28
|
+
"add-dir": "repeat",
|
|
29
|
+
bare: "boolean",
|
|
20
30
|
json: "boolean",
|
|
21
31
|
schema: "value",
|
|
22
32
|
},
|
|
23
|
-
usage: "call <akuma-name> [--contract <kei/...>] [--repo <path>] [--workdir <path>] [--alias <name>] [--allowed <product.action>]... [--schema <file>] [--wait <duration>] [<prompt> | -]",
|
|
33
|
+
usage: "call <akuma-name> [--contract <kei/...>] [--repo <path>] [--workdir <path>] [--alias <name>] [--allowed <product.action>]... [--add-dir <path>]... [--bare] [--schema <file>] [--wait <duration>] [<prompt> | -]",
|
|
24
34
|
purpose: "Call an Akuma into the world.",
|
|
25
35
|
details: [
|
|
26
36
|
"Use keiyaku ls aku/ to find visible Akuma names; hidden definitions can still be called by name.",
|
|
27
37
|
"Omit the prompt to birth without a Tell; otherwise give <prompt> as one argument, or use - to read stdin.",
|
|
28
38
|
"--schema and --wait require a prompt.",
|
|
39
|
+
"--bare omits Keiyaku's runtime instruction section for this birth and its later execution; personality, tools, permissions, and report remain unchanged.",
|
|
40
|
+
"Generic ACP needs --bare: it has no verified native runtime-instruction channel. Existing sessions without the section are not retrofitted; ordinary resume retains existing native instructions.",
|
|
29
41
|
"By default, call returns after birth and optional first Tell admission; --wait also waits for its first answer, up to the given duration.",
|
|
30
42
|
"--contract records an association, not the work or execution directory; include the Contract and worktree context in the prompt as needed. --repo requires --contract.",
|
|
31
43
|
"--workdir selects where the Akuma works; relative paths resolve from the invocation directory selected by -C/--cwd, or the process cwd when omitted. Without --workdir, the invocation directory is used.",
|
|
44
|
+
"--add-dir explicitly grants another existing writable directory to Codex native workspace-write tools; repeat for multiple roots. Relative paths resolve from the invocation directory. Other sandbox modes, permission profiles, and providers refuse nonempty grants instead of broadening policy. Existing network policy and writable roots are preserved. This is separate from --allowed product actions and never grants the repo or Home automatically.",
|
|
32
45
|
"--alias <name> gives the new Akuma the selector @name instead of aku/<id>; an existing @name is reassigned to this Akuma.",
|
|
33
46
|
`Default actions: ${DEFAULT_ALLOWED_ACTIONS.join(", ")}.`,
|
|
34
47
|
...(EXTRA_ALLOWED_ACTIONS.length === 0
|
|
@@ -108,10 +121,13 @@ const AKUMA_COMMAND_SPECS = {
|
|
|
108
121
|
fork: {
|
|
109
122
|
arity: 1,
|
|
110
123
|
stdin: false,
|
|
111
|
-
flags: { at: "value", json: "boolean" },
|
|
112
|
-
usage: "fork <aku/...|@alias> --at <historyId> [--repo <path>]",
|
|
124
|
+
flags: { at: "value", bare: "boolean", json: "boolean" },
|
|
125
|
+
usage: "fork <aku/...|@alias> --at <historyId> [--bare] [--repo <path>]",
|
|
113
126
|
purpose: "Create a new Akuma from an answered turn.",
|
|
114
|
-
details:
|
|
127
|
+
details: [
|
|
128
|
+
"--at takes a retained answered turn id (turn/<n>); find its historyId in paged keiyaku history <aku/...|@alias> --json. Fork also requires a retained provider fork point.",
|
|
129
|
+
"A fork inherits bare; --bare additionally omits only the child's Keiyaku runtime instructions.",
|
|
130
|
+
].join("\n"),
|
|
115
131
|
},
|
|
116
132
|
kill: {
|
|
117
133
|
arity: "one-or-more",
|
|
@@ -126,7 +142,9 @@ export function isAkumaAction(value) {
|
|
|
126
142
|
return value !== undefined && Object.hasOwn(AKUMA_COMMAND_SPECS, value);
|
|
127
143
|
}
|
|
128
144
|
export function isParsedAkumaCommand(command) {
|
|
129
|
-
return isAkumaAction(command.command) &&
|
|
145
|
+
return (isAkumaAction(command.command) &&
|
|
146
|
+
command.command !== "report" &&
|
|
147
|
+
!("contract" in command && command.command === "history"));
|
|
130
148
|
}
|
|
131
149
|
export function renderAkumaRootRows() {
|
|
132
150
|
return Object.entries(AKUMA_COMMAND_SPECS).map(([action, spec]) => ` ${action.padEnd(10)} ${spec.purpose}`);
|
|
@@ -256,7 +274,7 @@ function parseAddressed(action, rawSelectors, flags, output, fail) {
|
|
|
256
274
|
}
|
|
257
275
|
const akuma = rawSelectors[0];
|
|
258
276
|
const at = stringFlag(flags.at, "fork requires --at <historyId>", fail);
|
|
259
|
-
return { command: action, akuma, at, output };
|
|
277
|
+
return { command: action, akuma, at, ...(flags.bare === true ? { bare: true } : {}), output };
|
|
260
278
|
}
|
|
261
279
|
function parsePrompted(action, positionals, stdin, fail) {
|
|
262
280
|
if (positionals.length === 0)
|
|
@@ -338,11 +356,21 @@ function parseCall(flags, archetype, prompt, output, fail) {
|
|
|
338
356
|
mode,
|
|
339
357
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
340
358
|
...(allowed === undefined ? {} : { allowed }),
|
|
359
|
+
...(flags["add-dir"] === undefined ? {} : { writableDirectories: flags["add-dir"] }),
|
|
360
|
+
...(flags.bare === true ? { bare: true } : {}),
|
|
341
361
|
...(schema === undefined ? {} : { schema }),
|
|
342
362
|
...(prompt === undefined ? {} : { prompt }),
|
|
343
363
|
output,
|
|
344
364
|
};
|
|
345
365
|
}
|
|
366
|
+
function parseReport(positionals, stdin, output, fail) {
|
|
367
|
+
if (stdin ? positionals.length !== 0 : positionals.length !== 1)
|
|
368
|
+
fail("report requires one text argument or stdin, not both");
|
|
369
|
+
const value = positionals[0];
|
|
370
|
+
if (value !== undefined && value.trim() === "")
|
|
371
|
+
fail("report requires nonblank text");
|
|
372
|
+
return { command: "report", output, prompt: stdin ? { kind: "stdin" } : { kind: "argument", value: value } };
|
|
373
|
+
}
|
|
346
374
|
export function parseAkumaCommand(argv) {
|
|
347
375
|
const candidate = argv[0];
|
|
348
376
|
if (!isAkumaAction(candidate))
|
|
@@ -354,6 +382,8 @@ export function parseAkumaCommand(argv) {
|
|
|
354
382
|
};
|
|
355
383
|
const { flags, positionals, stdin } = scanArgs(argv, scanSpec(action, spec), fail);
|
|
356
384
|
const output = flags.json === true ? "json" : "text";
|
|
385
|
+
if (action === "report")
|
|
386
|
+
return parseReport(positionals, stdin !== undefined, output, fail);
|
|
357
387
|
if (action === "call" || action === "tell" || action === "ask") {
|
|
358
388
|
const parsed = parsePrompted(action, positionals, stdin !== undefined, fail);
|
|
359
389
|
return action === "call"
|
|
@@ -106,6 +106,8 @@ async function runCall(command, input) {
|
|
|
106
106
|
...(input.contract === undefined ? {} : { contract: input.contract }),
|
|
107
107
|
...(command.alias === undefined ? {} : { alias: command.alias }),
|
|
108
108
|
...(command.allowed === undefined ? {} : { allowed: command.allowed }),
|
|
109
|
+
...(input.writableDirectories === undefined ? {} : { writableDirectories: input.writableDirectories }),
|
|
110
|
+
...(command.bare === undefined ? {} : { bare: command.bare }),
|
|
109
111
|
...(schema === undefined ? {} : { schema }),
|
|
110
112
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
111
113
|
};
|
|
@@ -267,6 +269,7 @@ async function runFork(command, input) {
|
|
|
267
269
|
...(caller === undefined ? {} : { caller }),
|
|
268
270
|
akuma: command.akuma,
|
|
269
271
|
at: command.at,
|
|
272
|
+
...(command.bare === undefined ? {} : { bare: command.bare }),
|
|
270
273
|
...(input.repo === undefined ? {} : { repo: input.repo }),
|
|
271
274
|
});
|
|
272
275
|
return emit(command.output, receipt, () => renderForkText(receipt), forkOutcome(receipt));
|
|
@@ -299,6 +302,13 @@ async function callExecutionCwd(command, cwd, workdir) {
|
|
|
299
302
|
async function akumaInput(command, coordinates, workdir, runtime) {
|
|
300
303
|
const path = await akumaWorld(command, coordinates);
|
|
301
304
|
const executionCwd = await callExecutionCwd(command, coordinates.cwd, workdir);
|
|
305
|
+
const writableDirectories = command.command !== "call" || command.writableDirectories === undefined
|
|
306
|
+
? undefined
|
|
307
|
+
: await Promise.all(command.writableDirectories.map((path) => {
|
|
308
|
+
if (path.trim() === "")
|
|
309
|
+
throw new TypeError("--add-dir requires a nonblank directory");
|
|
310
|
+
return canonicalBirthCwd(resolve(coordinates.cwd, path));
|
|
311
|
+
}));
|
|
302
312
|
const execution = runtime.execution;
|
|
303
313
|
const home = command.command === "call" ? runtime.home : undefined;
|
|
304
314
|
const configuration = command.command === "call" ? await settingsAt(path, home) : undefined;
|
|
@@ -310,6 +320,7 @@ async function akumaInput(command, coordinates, workdir, runtime) {
|
|
|
310
320
|
return {
|
|
311
321
|
path,
|
|
312
322
|
...(executionCwd === undefined ? {} : { executionCwd }),
|
|
323
|
+
...(writableDirectories === undefined ? {} : { writableDirectories }),
|
|
313
324
|
...(home === undefined ? {} : { home }),
|
|
314
325
|
...(configuration === undefined ? {} : { settings: configuration }),
|
|
315
326
|
...(contract === undefined ? {} : { contract }),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CliRuntime } from "../runtime.js";
|
|
2
|
+
import { type CliOutcome } from "../streams.js";
|
|
3
|
+
import type { ParsedAkumaCommand } from "./akuma-grammar.js";
|
|
4
|
+
export declare function runReport(command: Extract<ParsedAkumaCommand, {
|
|
5
|
+
command: "report";
|
|
6
|
+
}>, runtime: CliRuntime): Promise<CliOutcome>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Akuma } from "../../index.js";
|
|
2
|
+
import { akumaCallerFromEnvironment } from "../akuma-caller.js";
|
|
3
|
+
import { emit, writeStderr } from "../streams.js";
|
|
4
|
+
import { CliUsageError } from "../usage.js";
|
|
5
|
+
function executionSequence(environment, key) {
|
|
6
|
+
const value = environment[key];
|
|
7
|
+
if (value === undefined || !/^[1-9][0-9]*$/u.test(value) || !Number.isSafeInteger(Number(value)))
|
|
8
|
+
throw new CliUsageError(`report requires an explicit positive execution coordinate: ${key}`);
|
|
9
|
+
return Number(value);
|
|
10
|
+
}
|
|
11
|
+
export async function runReport(command, runtime) {
|
|
12
|
+
const text = command.prompt.kind === "stdin" ? await runtime.readStdin() : command.prompt.value;
|
|
13
|
+
if (text.trim() === "")
|
|
14
|
+
throw new CliUsageError("report requires nonblank text");
|
|
15
|
+
const environment = runtime.environment;
|
|
16
|
+
if (environment.KEIYAKU_ACTOR_ID === undefined || environment.KEIYAKU_ACTOR_WORLD === undefined)
|
|
17
|
+
throw new CliUsageError("report requires explicit KEIYAKU_ACTOR_ID and KEIYAKU_ACTOR_WORLD");
|
|
18
|
+
const bodySequence = executionSequence(environment, "KEIYAKU_BODY_SEQUENCE");
|
|
19
|
+
const turnSequence = executionSequence(environment, "KEIYAKU_TURN_SEQUENCE");
|
|
20
|
+
const caller = await akumaCallerFromEnvironment(environment);
|
|
21
|
+
if (caller?.kind !== "akuma")
|
|
22
|
+
throw new CliUsageError("report requires explicit Akuma identity");
|
|
23
|
+
const result = await Akuma.select(caller.world, caller.akuId, { reportDiagnostic: writeStderr }).report(text, {
|
|
24
|
+
bodySequence,
|
|
25
|
+
turnSequence,
|
|
26
|
+
signal: runtime.signal,
|
|
27
|
+
});
|
|
28
|
+
return emit(command.output, result, () => result.kind === "recorded"
|
|
29
|
+
? `recorded ${caller.akuId} report/${result.report.sequence} · body/${bodySequence} · turn/${turnSequence}`
|
|
30
|
+
: `refused report · ${result.reason}`, result.kind === "recorded" ? "accepted" : "refused");
|
|
31
|
+
}
|
package/build/src/cli/parse.js
CHANGED