@astrosheep/keiyaku 4.0.5 → 4.1.0
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 +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +10 -4
- package/build/src/akuma/akuma.d.ts +2 -0
- package/build/src/akuma/akuma.js +26 -3
- package/build/src/akuma/archetype.d.ts +3 -1
- package/build/src/akuma/archetype.js +19 -7
- package/build/src/akuma/body-turn.d.ts +64 -0
- package/build/src/akuma/body-turn.js +449 -0
- package/build/src/akuma/body.d.ts +3 -7
- package/build/src/akuma/body.js +9 -420
- package/build/src/akuma/heart/facts.d.ts +2 -0
- package/build/src/akuma/heart/facts.js +3 -1
- package/build/src/akuma/heart/index.js +12 -2
- package/build/src/akuma/heart/rows.js +4 -1
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +3 -2
- package/build/src/akuma/heart/timeline.d.ts +1 -0
- package/build/src/akuma/heart/timeline.js +19 -0
- package/build/src/akuma/nuke.d.ts +2 -0
- package/build/src/akuma/nuke.js +152 -0
- package/build/src/akuma/provider-recipe.d.ts +2 -0
- package/build/src/akuma/provider-recipe.js +10 -0
- package/build/src/akuma/provider.d.ts +3 -1
- package/build/src/akuma/providers/acp/config.d.ts +10 -0
- package/build/src/akuma/providers/acp/config.js +45 -0
- package/build/src/akuma/providers/acp/core.d.ts +5 -2
- package/build/src/akuma/providers/acp/core.js +35 -16
- package/build/src/akuma/providers/acp/index.d.ts +1 -8
- package/build/src/akuma/providers/acp/index.js +10 -39
- package/build/src/akuma/providers/claude/index.d.ts +1 -1
- package/build/src/akuma/providers/claude/index.js +14 -5
- package/build/src/akuma/providers/codex-app-server/index.js +9 -1
- package/build/src/akuma/providers/grok-build/index.js +16 -2
- package/build/src/akuma/providers/index.d.ts +3 -2
- package/build/src/akuma/providers/index.js +37 -37
- package/build/src/akuma/providers/opencode-sdk/index.js +9 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +30 -12
- package/build/src/akuma/request-serve.d.ts +1 -0
- package/build/src/akuma/request-serve.js +31 -31
- package/build/src/akuma/request-wire.d.ts +3 -2
- package/build/src/akuma/request-wire.js +5 -2
- package/build/src/akuma-body.js +15 -1
- package/build/src/alias/index.d.ts +1 -0
- package/build/src/alias/index.js +34 -1
- package/build/src/body/amend.js +0 -9
- package/build/src/body/region.js +2 -2
- package/build/src/cli/accepted.js +6 -0
- package/build/src/cli/commands/akuma-invoke.js +1 -0
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +11 -8
- package/build/src/cli/commands/contract.d.ts +28 -15
- package/build/src/cli/commands/contract.js +34 -18
- package/build/src/cli/commands/install.d.ts +2 -2
- package/build/src/cli/commands/install.js +6 -6
- package/build/src/cli/commands/nuke.d.ts +10 -0
- package/build/src/cli/commands/nuke.js +20 -0
- package/build/src/cli/commands/task-invoke.d.ts +19 -1
- package/build/src/cli/commands/task-invoke.js +63 -29
- package/build/src/cli/commands/task-query.d.ts +2 -2
- package/build/src/cli/commands/task-query.js +1 -2
- package/build/src/cli/commands/task.js +30 -22
- package/build/src/cli/coordinates.d.ts +5 -2
- package/build/src/cli/coordinates.js +5 -52
- package/build/src/cli/invoke.d.ts +5 -4
- package/build/src/cli/invoke.js +89 -59
- package/build/src/cli/main.d.ts +0 -2
- package/build/src/cli/main.js +4 -140
- package/build/src/cli/parse.d.ts +15 -2
- package/build/src/cli/parse.js +73 -8
- package/build/src/cli/render/akuma.js +95 -49
- package/build/src/cli/render/catalog.js +5 -1
- package/build/src/cli/render/contract.js +72 -49
- package/build/src/cli/render/kanshi.js +157 -99
- package/build/src/cli/render/nuke.d.ts +3 -0
- package/build/src/cli/render/nuke.js +8 -0
- package/build/src/cli/render/receipt.d.ts +1 -0
- package/build/src/cli/render/receipt.js +18 -14
- package/build/src/cli/render/refusal.d.ts +2 -1
- package/build/src/cli/render/refusal.js +37 -0
- package/build/src/cli/render/task.js +63 -11
- package/build/src/cli/render/text.js +6 -1
- package/build/src/cli/result.d.ts +28 -2
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +140 -0
- package/build/src/cli/usage.d.ts +0 -2
- package/build/src/cli/usage.js +0 -4
- package/build/src/contract-worktree.d.ts +26 -12
- package/build/src/contract-worktree.js +119 -64
- package/build/src/git/hooks.d.ts +2 -0
- package/build/src/git/hooks.js +34 -1
- package/build/src/git/integration.d.ts +4 -0
- package/build/src/git/integration.js +38 -0
- package/build/src/git/nuke.d.ts +2 -0
- package/build/src/git/nuke.js +92 -0
- package/build/src/git/process.d.ts +2 -0
- package/build/src/git/repository.js +4 -1
- package/build/src/git/target-placement.d.ts +2 -1
- package/build/src/git/target-placement.js +6 -7
- package/build/src/git/tender.d.ts +14 -2
- package/build/src/git/tender.js +45 -6
- package/build/src/git/workspace.d.ts +3 -0
- package/build/src/kanshi/read.js +37 -13
- package/build/src/kanshi/report.d.ts +2 -1
- package/build/src/library/akuma-creation.d.ts +1 -0
- package/build/src/library/akuma-creation.js +8 -1
- package/build/src/library/audit.d.ts +1 -0
- package/build/src/library/audit.js +1 -0
- package/build/src/library/continuation.d.ts +26 -0
- package/build/src/library/continuation.js +78 -0
- package/build/src/library/contract.d.ts +14 -8
- package/build/src/library/contract.js +82 -35
- package/build/src/library/delivery.d.ts +18 -11
- package/build/src/library/keiyaku.d.ts +5 -1
- package/build/src/library/keiyaku.js +2 -0
- package/build/src/library/mutation.d.ts +1 -0
- package/build/src/library/mutation.js +14 -4
- package/build/src/library/nuke.d.ts +14 -0
- package/build/src/library/nuke.js +54 -0
- package/build/src/library/reconcile.js +5 -2
- package/build/src/library/refusal.d.ts +10 -1
- package/build/src/library/repo.d.ts +1 -0
- package/build/src/library/repo.js +2 -0
- package/build/src/protocol/audit.js +12 -5
- package/build/src/protocol/completion.d.ts +11 -1
- package/build/src/protocol/completion.js +68 -15
- package/build/src/protocol/deliver.d.ts +25 -3
- package/build/src/protocol/deliver.js +148 -14
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +7 -1
- package/build/src/protocol/operations.d.ts +36 -4
- package/build/src/protocol/operations.js +2 -2
- package/build/src/protocol/placement.d.ts +9 -1
- package/build/src/protocol/placement.js +5 -4
- package/build/src/protocol/read/status.d.ts +16 -4
- package/build/src/protocol/read/status.js +54 -12
- package/build/src/protocol/review.d.ts +1 -0
- package/build/src/protocol/review.js +8 -0
- package/build/src/runtime/proc/run.js +9 -5
- package/build/src/settlement/settle.js +1 -2
- package/build/src/task/board.d.ts +21 -2
- package/build/src/task/board.js +25 -12
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +2 -7
- package/build/src/task/context.d.ts +14 -2
- package/build/src/task/context.js +30 -7
- package/build/src/task/identity.js +14 -4
- package/build/src/task/index.d.ts +7 -5
- package/build/src/task/index.js +21 -18
- package/build/src/task/mutation.d.ts +7 -2
- package/build/src/task/mutation.js +14 -6
- package/build/src/task/operations.d.ts +14 -7
- package/build/src/task/operations.js +37 -50
- package/build/src/task/query.js +2 -2
- package/build/src/task/store.d.ts +3 -0
- package/build/src/task/store.js +21 -2
- package/build/src/workspace-place.d.ts +2 -0
- package/build/src/workspace-place.js +27 -1
- package/package.json +1 -1
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
import { decodeProviderRecipe } from "../provider-recipe.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import { decodeAcpConfig } from "./acp/config.js";
|
|
3
|
+
export function decodeProviderExecution(input) {
|
|
4
|
+
const decoded = decodeProviderRecipe(input);
|
|
5
|
+
if ((decoded.kind === "claude-agent-sdk" || decoded.kind === "opencode-sdk") && decoded.config !== undefined) {
|
|
6
|
+
throw new TypeError(`provider execution config is unsupported by ${decoded.kind}`);
|
|
7
|
+
}
|
|
8
|
+
if (decoded.kind === "pi") {
|
|
9
|
+
if (decoded.executable !== undefined || decoded.config !== undefined) {
|
|
10
|
+
throw new TypeError("Pi provider does not support executable or config");
|
|
11
|
+
}
|
|
12
|
+
if (decoded.env !== undefined && Object.keys(decoded.env).length > 0) {
|
|
13
|
+
throw new TypeError("env injection not supported for provider pi");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (decoded.kind === "grok-build" && decoded.config !== undefined) {
|
|
17
|
+
throw new TypeError("Grok Build does not support execution config");
|
|
18
|
+
}
|
|
19
|
+
const config = decoded.kind === "acp" ? decodeAcpConfig(decoded.config) : decoded.config;
|
|
20
|
+
return Object.freeze({
|
|
21
|
+
name: decoded.name,
|
|
22
|
+
kind: decoded.kind,
|
|
23
|
+
...(decoded.executable === undefined ? {} : { executable: decoded.executable }),
|
|
24
|
+
...(config === undefined ? {} : { config }),
|
|
25
|
+
...(decoded.env === undefined ? {} : { env: decoded.env }),
|
|
26
|
+
});
|
|
20
27
|
}
|
|
21
|
-
function adapterFor(execution) {
|
|
28
|
+
async function adapterFor(execution) {
|
|
22
29
|
if (execution.kind === "acp")
|
|
23
|
-
return createAcpProvider(execution);
|
|
30
|
+
return (await import("./acp/index.js")).createAcpProvider(execution);
|
|
24
31
|
if (execution.kind === "claude-agent-sdk") {
|
|
32
|
+
const { claudeProvider, createClaudeProvider } = await import("./claude/index.js");
|
|
25
33
|
return execution.executable === undefined && execution.env === undefined
|
|
26
|
-
?
|
|
27
|
-
: createClaudeProvider(
|
|
34
|
+
? claudeProvider
|
|
35
|
+
: createClaudeProvider(execution);
|
|
28
36
|
}
|
|
29
37
|
if (execution.kind === "codex-app-server")
|
|
30
|
-
return createCodexAppServerProvider(execution);
|
|
38
|
+
return (await import("./codex-app-server/index.js")).createCodexAppServerProvider(execution);
|
|
31
39
|
if (execution.kind === "grok-build")
|
|
32
|
-
return createGrokBuildProvider(execution);
|
|
40
|
+
return (await import("./grok-build/index.js")).createGrokBuildProvider(execution);
|
|
33
41
|
if (execution.kind === "opencode-sdk")
|
|
34
|
-
return createOpencodeProvider(execution);
|
|
42
|
+
return (await import("./opencode-sdk/index.js")).createOpencodeProvider(execution);
|
|
35
43
|
if (execution.kind === "pi")
|
|
36
|
-
return createPiProvider(execution);
|
|
44
|
+
return (await import("./pi/index.js")).createPiProvider(execution);
|
|
37
45
|
throw new TypeError(`unknown Akuma provider kind ${execution.kind}`);
|
|
38
46
|
}
|
|
39
|
-
export function resolveProviderExecution(input) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const execution = Object.freeze({
|
|
43
|
-
name: decoded.name,
|
|
44
|
-
kind: decoded.kind,
|
|
45
|
-
...(decoded.executable === undefined ? {} : { executable: decoded.executable }),
|
|
46
|
-
...(config === undefined ? {} : { config }),
|
|
47
|
-
...(decoded.env === undefined ? {} : { env: decoded.env }),
|
|
48
|
-
});
|
|
49
|
-
return Object.freeze({ execution, adapter: adapterFor(execution) });
|
|
47
|
+
export async function resolveProviderExecution(input) {
|
|
48
|
+
const execution = decodeProviderExecution(input);
|
|
49
|
+
return Object.freeze({ execution, adapter: await adapterFor(execution) });
|
|
50
50
|
}
|
|
@@ -24,6 +24,9 @@ function opencodeSessionId(coordinateValue) {
|
|
|
24
24
|
function admit(options) {
|
|
25
25
|
if (options.network !== undefined)
|
|
26
26
|
throw new Error("OpenCode does not support explicit network");
|
|
27
|
+
if (options.systemPromptMode === "replace") {
|
|
28
|
+
throw new Error("OpenCode V1 does not support replacing the native system prompt");
|
|
29
|
+
}
|
|
27
30
|
if (options.model !== undefined)
|
|
28
31
|
parseModel(options.model);
|
|
29
32
|
}
|
|
@@ -195,6 +198,11 @@ function terminalSettlement(events, close) {
|
|
|
195
198
|
});
|
|
196
199
|
return { completion, finish };
|
|
197
200
|
}
|
|
201
|
+
async function forceDisposeOpencode(abortController, close, finish) {
|
|
202
|
+
abortController.abort();
|
|
203
|
+
await close();
|
|
204
|
+
await finish({ kind: "failed", diagnostic: "OpenCode session force-disposed" });
|
|
205
|
+
}
|
|
198
206
|
async function drive(execution, input, loader) {
|
|
199
207
|
admit(input.options);
|
|
200
208
|
const signal = input.signal ?? new AbortController().signal;
|
|
@@ -256,6 +264,7 @@ async function drive(execution, input, loader) {
|
|
|
256
264
|
void session.abort({ path: { id: sessionId }, query: { directory: input.cwd }, throwOnError: true }).catch(() => undefined);
|
|
257
265
|
await finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
|
|
258
266
|
},
|
|
267
|
+
forceDispose: () => forceDisposeOpencode(abortController, closeOnce, finish),
|
|
259
268
|
};
|
|
260
269
|
}
|
|
261
270
|
catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
2
2
|
import type { ResumeCoordinate } from "../../heart/index.js";
|
|
3
3
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
4
4
|
export type OpencodeSdkSession = Pick<OpencodeClient["session"], "create" | "get" | "fork" | "abort" | "promptAsync" | "messages">;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
2
|
import { abortable } from "../../abort.js";
|
|
3
3
|
import { spawnDetachedProcess } from "../../../runtime/proc/run.js";
|
|
4
|
-
import { createOpencodeClient } from "@opencode-ai/sdk";
|
|
5
4
|
export const OPENCODE_SDK_PROVIDER = "opencode-sdk";
|
|
6
5
|
export function parseModel(model) {
|
|
7
6
|
const slash = model.indexOf("/");
|
|
@@ -50,6 +49,7 @@ export async function loadOpencode(execution, cwd, signal, loader) {
|
|
|
50
49
|
env: { ...process.env, ...execution.env },
|
|
51
50
|
log: `${cwd}/.opencode.log`,
|
|
52
51
|
});
|
|
52
|
+
const { createOpencodeClient } = await import("@opencode-ai/sdk");
|
|
53
53
|
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}`, directory: cwd });
|
|
54
54
|
try {
|
|
55
55
|
await waitReady(client, cwd, signal);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAgentSession, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager,
|
|
1
|
+
import type { createAgentSession, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager, CreateAgentSessionOptions } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
3
3
|
import { type ProviderAdapter } from "../../provider.js";
|
|
4
4
|
export type PiSdk = Readonly<{
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createAgentSession, createBashToolDefinition, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
2
1
|
import { abortable } from "../../abort.js";
|
|
3
2
|
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
4
3
|
import { piTerminalFailure, translatePiEvent } from "./events.js";
|
|
@@ -33,7 +32,9 @@ async function piCreateOptions(sdk, input) {
|
|
|
33
32
|
const resourceLoader = input.options.systemPrompt === undefined ? undefined : new sdk.DefaultResourceLoader({
|
|
34
33
|
cwd: input.cwd,
|
|
35
34
|
agentDir: sdk.getAgentDir(),
|
|
36
|
-
|
|
35
|
+
...(input.options.systemPromptMode === "append"
|
|
36
|
+
? { appendSystemPromptOverride: (base) => [...base, input.options.systemPrompt] }
|
|
37
|
+
: { systemPromptOverride: () => input.options.systemPrompt }),
|
|
37
38
|
});
|
|
38
39
|
await resourceLoader?.reload();
|
|
39
40
|
const sessionManager = input.session.kind === "fresh"
|
|
@@ -41,6 +42,14 @@ async function piCreateOptions(sdk, input) {
|
|
|
41
42
|
: "sessionFile" in input.session.coordinate
|
|
42
43
|
? sdk.SessionManager.open(input.session.coordinate.sessionFile)
|
|
43
44
|
: (() => { throw new Error("Pi resume requires sessionFile"); })();
|
|
45
|
+
const customTools = input.requests === undefined || input.options.readonly === true
|
|
46
|
+
? undefined
|
|
47
|
+
: [(await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
|
|
48
|
+
spawnHook: (context) => ({
|
|
49
|
+
...context,
|
|
50
|
+
env: { ...context.env, [AKUMA_REQUESTS_ENV]: input.requests.dir },
|
|
51
|
+
}),
|
|
52
|
+
})];
|
|
44
53
|
return {
|
|
45
54
|
cwd: input.cwd,
|
|
46
55
|
sessionManager,
|
|
@@ -48,20 +57,19 @@ async function piCreateOptions(sdk, input) {
|
|
|
48
57
|
...(resourceLoader === undefined ? {} : { resourceLoader }),
|
|
49
58
|
...(input.options.effort === undefined ? {} : { thinkingLevel: input.options.effort }),
|
|
50
59
|
...(input.options.readonly === undefined ? {} : { tools: ["read", "grep", "find", "ls"] }),
|
|
51
|
-
...(
|
|
52
|
-
? {}
|
|
53
|
-
: { customTools: [createBashToolDefinition(input.cwd, {
|
|
54
|
-
spawnHook: (context) => ({
|
|
55
|
-
...context,
|
|
56
|
-
env: { ...context.env, [AKUMA_REQUESTS_ENV]: input.requests.dir },
|
|
57
|
-
}),
|
|
58
|
-
})] }),
|
|
60
|
+
...(customTools === undefined ? {} : { customTools }),
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
63
|
async function createPiSession(sdk, input, signal) {
|
|
62
64
|
const setup = piCreateOptions(sdk, input).then(async (options) => await sdk.createAgentSession(options));
|
|
63
65
|
return await abortable(setup, signal, (created) => created.session.dispose());
|
|
64
66
|
}
|
|
67
|
+
function forceDisposePi(dispose, settle, setAborting) {
|
|
68
|
+
setAborting();
|
|
69
|
+
dispose();
|
|
70
|
+
settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
|
|
71
|
+
return Promise.resolve();
|
|
72
|
+
}
|
|
65
73
|
async function drivePi(sdk, input, signal) {
|
|
66
74
|
const created = await createPiSession(sdk, input, signal);
|
|
67
75
|
const native = created.session;
|
|
@@ -155,6 +163,7 @@ async function drivePi(sdk, input, signal) {
|
|
|
155
163
|
})();
|
|
156
164
|
return abortRequest;
|
|
157
165
|
},
|
|
166
|
+
forceDispose: () => forceDisposePi(dispose, settle, () => { aborting = true; }),
|
|
158
167
|
};
|
|
159
168
|
}
|
|
160
169
|
function piSessionFile(coordinate) {
|
|
@@ -170,8 +179,17 @@ async function forkPi(sdk, input) {
|
|
|
170
179
|
throw new Error("Pi fork did not create a distinct child session file");
|
|
171
180
|
return { session: { sessionFile: child } };
|
|
172
181
|
}
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
async function loadPiSdk() {
|
|
183
|
+
const sdk = await import("@earendil-works/pi-coding-agent");
|
|
184
|
+
return {
|
|
185
|
+
createAgentSession: sdk.createAgentSession,
|
|
186
|
+
DefaultResourceLoader: sdk.DefaultResourceLoader,
|
|
187
|
+
getAgentDir: sdk.getAgentDir,
|
|
188
|
+
ModelRuntime: sdk.ModelRuntime,
|
|
189
|
+
SessionManager: sdk.SessionManager,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
export function createPiProvider(execution = { name: "pi", kind: "pi" }, load = loadPiSdk) {
|
|
175
193
|
if (execution.executable !== undefined || execution.config !== undefined) {
|
|
176
194
|
throw new TypeError("Pi provider does not support executable or config");
|
|
177
195
|
}
|
|
@@ -222,6 +222,7 @@ async function executeDeliver(input, request) {
|
|
|
222
222
|
contractId: request.contractId,
|
|
223
223
|
...(request.message === undefined ? {} : { message: request.message }),
|
|
224
224
|
includeDirty: request.includeDirty,
|
|
225
|
+
materializeConflict: request.materializeConflict,
|
|
225
226
|
requester: request.requester,
|
|
226
227
|
signal: input.signal,
|
|
227
228
|
});
|
|
@@ -303,12 +304,8 @@ async function serveUpstream(input) {
|
|
|
303
304
|
try {
|
|
304
305
|
const served = await execute(input, request);
|
|
305
306
|
outcome = { kind: "returned", result: served.result };
|
|
306
|
-
if (served.service
|
|
307
|
-
|
|
308
|
-
await projectReceipt(input.directory, fact);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
service = served.service;
|
|
307
|
+
if (served.service !== undefined)
|
|
308
|
+
service = served.service;
|
|
312
309
|
}
|
|
313
310
|
catch (error) {
|
|
314
311
|
outcome = { kind: "failed", failure: failure(error) };
|
|
@@ -368,37 +365,40 @@ export class BodyRequestPump {
|
|
|
368
365
|
return new BodyRequestPump(input);
|
|
369
366
|
}
|
|
370
367
|
async run() {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
directory: this.directory,
|
|
383
|
-
claim,
|
|
384
|
-
...this.input,
|
|
385
|
-
signal: this.executionSignal.signal,
|
|
386
|
-
admissionOpen: () => !this.admissionClosed,
|
|
387
|
-
});
|
|
388
|
-
}
|
|
368
|
+
while (!this.closeSignal.signal.aborted) {
|
|
369
|
+
for (const name of await requestFiles(this.directory)) {
|
|
370
|
+
if (this.closeSignal.signal.aborted)
|
|
371
|
+
return;
|
|
372
|
+
const id = name.slice(0, -".request.json".length);
|
|
373
|
+
if (this.handled.has(id))
|
|
374
|
+
continue;
|
|
375
|
+
const path = join(this.directory, name);
|
|
376
|
+
const claim = decodeClaim(await readFile(path, "utf8"), id);
|
|
377
|
+
if (claim === null) {
|
|
378
|
+
await rm(path, { force: true });
|
|
389
379
|
this.handled.add(id);
|
|
380
|
+
continue;
|
|
390
381
|
}
|
|
391
|
-
|
|
392
|
-
await
|
|
382
|
+
if (!this.admissionClosed) {
|
|
383
|
+
await serve({
|
|
384
|
+
directory: this.directory,
|
|
385
|
+
claim,
|
|
386
|
+
...this.input,
|
|
387
|
+
signal: this.executionSignal.signal,
|
|
388
|
+
admissionOpen: () => !this.admissionClosed,
|
|
389
|
+
});
|
|
393
390
|
}
|
|
394
|
-
|
|
391
|
+
this.handled.add(id);
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
await abortableDelay(POLL_MS, this.closeSignal.signal);
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
if (this.closeSignal.signal.aborted)
|
|
395
398
|
return;
|
|
396
|
-
|
|
399
|
+
throw error;
|
|
397
400
|
}
|
|
398
401
|
}
|
|
399
|
-
catch {
|
|
400
|
-
// Request transport loss is recovered from Heart on the next Body.
|
|
401
|
-
}
|
|
402
402
|
}
|
|
403
403
|
async close() {
|
|
404
404
|
this.stopAdmission();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type AkuId } from "./identity.js";
|
|
2
2
|
import { decodeProviderOptions, type ReadonlyRestraint } from "./provider-recipe.js";
|
|
3
|
-
import {
|
|
3
|
+
import { decodeProviderExecution } from "./providers/index.js";
|
|
4
4
|
import { type TaskMutationAction, type TaskMutationRequest } from "../task/mutation.js";
|
|
5
5
|
export type RequestRecipe = Readonly<{
|
|
6
6
|
description?: string;
|
|
7
7
|
allowed: readonly string[];
|
|
8
|
-
provider: ReturnType<typeof
|
|
8
|
+
provider: ReturnType<typeof decodeProviderExecution>;
|
|
9
9
|
options: ReturnType<typeof decodeProviderOptions>;
|
|
10
10
|
readonly?: ReadonlyRestraint;
|
|
11
11
|
}>;
|
|
@@ -43,6 +43,7 @@ export type DeliverRequestClaim = Readonly<{
|
|
|
43
43
|
contractId: string;
|
|
44
44
|
message?: string;
|
|
45
45
|
includeDirty: boolean;
|
|
46
|
+
materializeConflict: boolean;
|
|
46
47
|
}>;
|
|
47
48
|
export type ReviewRequestClaim = Readonly<{
|
|
48
49
|
id: string;
|
|
@@ -4,7 +4,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
4
4
|
import { decodeAllowedActions } from "./allowed.js";
|
|
5
5
|
import { archetypeName, parseAkuId } from "./identity.js";
|
|
6
6
|
import { decodeProviderOptions, decodeReadonlyRestraint, } from "./provider-recipe.js";
|
|
7
|
-
import {
|
|
7
|
+
import { decodeProviderExecution } from "./providers/index.js";
|
|
8
8
|
import { decodeTaskMutationRequest, isTaskMutationAction, } from "../task/mutation.js";
|
|
9
9
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
10
10
|
function object(value) {
|
|
@@ -69,7 +69,7 @@ export function decodeRecipe(value) {
|
|
|
69
69
|
return Object.freeze({
|
|
70
70
|
...(recipe.description === undefined ? {} : { description: recipe.description }),
|
|
71
71
|
allowed: decodeAllowedActions(recipe.allowed),
|
|
72
|
-
provider:
|
|
72
|
+
provider: decodeProviderExecution(recipe.provider),
|
|
73
73
|
options,
|
|
74
74
|
...(readonly === undefined ? {} : { readonly }),
|
|
75
75
|
});
|
|
@@ -153,6 +153,7 @@ function decodeDeliver(id, payload) {
|
|
|
153
153
|
const valid = exactKeys(payload, [
|
|
154
154
|
"contractId",
|
|
155
155
|
"includeDirty",
|
|
156
|
+
"materializeConflict",
|
|
156
157
|
"repoRoot",
|
|
157
158
|
...(payload.message === undefined ? [] : ["message"]),
|
|
158
159
|
]);
|
|
@@ -161,6 +162,7 @@ function decodeDeliver(id, payload) {
|
|
|
161
162
|
&& selected !== null
|
|
162
163
|
&& absolute(payload.repoRoot)
|
|
163
164
|
&& typeof payload.includeDirty === "boolean"
|
|
165
|
+
&& typeof payload.materializeConflict === "boolean"
|
|
164
166
|
&& (payload.message === undefined
|
|
165
167
|
|| (typeof payload.message === "string"
|
|
166
168
|
&& payload.message.trim().length > 0))
|
|
@@ -170,6 +172,7 @@ function decodeDeliver(id, payload) {
|
|
|
170
172
|
repoRoot: payload.repoRoot,
|
|
171
173
|
contractId: selected,
|
|
172
174
|
includeDirty: payload.includeDirty,
|
|
175
|
+
materializeConflict: payload.materializeConflict,
|
|
173
176
|
...(payload.message === undefined
|
|
174
177
|
? {}
|
|
175
178
|
: { message: payload.message }),
|
package/build/src/akuma-body.js
CHANGED
|
@@ -48,6 +48,7 @@ export function upstreamFor(launch, processConfiguration) {
|
|
|
48
48
|
requester: input.requester,
|
|
49
49
|
...(input.message === undefined ? {} : { message: input.message }),
|
|
50
50
|
includeDirty: input.includeDirty,
|
|
51
|
+
materializeConflict: input.materializeConflict,
|
|
51
52
|
requireBranchesToBeUpToDate: requireBranchesToBeUpToDateFrom({ settings: configuration }),
|
|
52
53
|
hooks: worktreeHooksFrom({ settings: configuration }),
|
|
53
54
|
signal: input.signal,
|
|
@@ -81,4 +82,17 @@ export function upstreamFor(launch, processConfiguration) {
|
|
|
81
82
|
}),
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
+
const encoded = process.argv[2];
|
|
86
|
+
if (encoded === undefined)
|
|
87
|
+
throw new TypeError("Akuma body launch payload is missing");
|
|
88
|
+
const launch = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
89
|
+
const mappedHome = process.env.KEIYAKU_HOME?.trim();
|
|
90
|
+
const mappedGitPath = process.env.KEIYAKU_GIT_PATH;
|
|
91
|
+
if (mappedGitPath !== undefined && mappedGitPath.trim().length === 0) {
|
|
92
|
+
throw new TypeError("KEIYAKU_GIT_PATH requires a nonblank value");
|
|
93
|
+
}
|
|
94
|
+
const configuration = {
|
|
95
|
+
...(mappedHome === undefined || mappedHome.length === 0 ? {} : { home: mappedHome }),
|
|
96
|
+
...(mappedGitPath === undefined ? {} : { gitPath: mappedGitPath }),
|
|
97
|
+
};
|
|
98
|
+
await runAkumaBody(launch, upstreamFor(launch, configuration));
|
|
@@ -9,6 +9,7 @@ export type AliasMove = Readonly<{
|
|
|
9
9
|
alias: AliasBinding;
|
|
10
10
|
previous: AkuId | null;
|
|
11
11
|
}>;
|
|
12
|
+
export declare function nukeAliases(world: WorldRoot): Promise<void>;
|
|
12
13
|
export declare function readAliases(world: WorldRoot): Promise<readonly AliasBinding[]>;
|
|
13
14
|
export declare function resolveAlias(world: WorldRoot, value: AkumaAlias): Promise<AkuId | null>;
|
|
14
15
|
export declare function moveAlias(input: Readonly<{
|
package/build/src/alias/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile } from "node:fs/promises";
|
|
1
|
+
import { lstat, mkdir, readFile, unlink } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { parseAkuId } from "../akuma/identity.js";
|
|
4
4
|
import { replaceFileDurably } from "../coordination/durable-file.js";
|
|
@@ -77,6 +77,39 @@ async function read(path) {
|
|
|
77
77
|
throw error;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
+
async function regularFile(path) {
|
|
81
|
+
try {
|
|
82
|
+
const value = await lstat(path);
|
|
83
|
+
if (!value.isFile() || value.isSymbolicLink())
|
|
84
|
+
throw new Error(`Alias custody is not a regular file: ${path}`);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === "ENOENT")
|
|
89
|
+
return false;
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export async function nukeAliases(world) {
|
|
94
|
+
const location = paths(world);
|
|
95
|
+
const initialAuthority = await regularFile(location.authority);
|
|
96
|
+
const initialLock = await regularFile(location.lock);
|
|
97
|
+
if (!initialAuthority && !initialLock)
|
|
98
|
+
return;
|
|
99
|
+
const held = await acquireSqliteTransactionLock({ path: location.lock, mode: "immediate" });
|
|
100
|
+
try {
|
|
101
|
+
// Alias writers use this same custody lock. Observe after acquiring it so
|
|
102
|
+
// an authority committed by a prior holder is part of this reset sweep.
|
|
103
|
+
const authorityPresent = await regularFile(location.authority);
|
|
104
|
+
if (authorityPresent) {
|
|
105
|
+
await read(location.authority);
|
|
106
|
+
await unlink(location.authority);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
held.close();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
80
113
|
export async function readAliases(world) {
|
|
81
114
|
return await read(paths(world).authority);
|
|
82
115
|
}
|
package/build/src/body/amend.js
CHANGED
|
@@ -151,15 +151,6 @@ function applyRemove(body, operation, document) {
|
|
|
151
151
|
body.extensionIndexes.delete(normalizeTitle(operation.target));
|
|
152
152
|
}
|
|
153
153
|
function applyUpdate(body, operation, document) {
|
|
154
|
-
if (operation.target.startsWith("Criterion ")) {
|
|
155
|
-
const title = operation.target.slice("Criterion ".length);
|
|
156
|
-
const index = criterionIndex(body, title);
|
|
157
|
-
if (index < 0)
|
|
158
|
-
refusal(`unknown criterion '${title}'`);
|
|
159
|
-
const criterion = body.criteria[index];
|
|
160
|
-
body.criteria[index] = { ...criterion, body: prose(document, operation.section, "criterion") };
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
154
|
const index = extensionIndex(body, operation.target);
|
|
164
155
|
if (index < 0)
|
|
165
156
|
refusal(`unknown extension '${operation.target}'`);
|
package/build/src/body/region.js
CHANGED
|
@@ -175,8 +175,8 @@ function patternsOverlap(left, right) {
|
|
|
175
175
|
}
|
|
176
176
|
export function decodeRegion(document, section) {
|
|
177
177
|
const blocks = directChildren(section, "code_block");
|
|
178
|
-
if (blocks.length !== 1 || !blocks[0].closed || blocks[0].info.
|
|
179
|
-
refusal("Region must contain one closed fence
|
|
178
|
+
if (blocks.length !== 1 || !blocks[0].closed || (blocks[0].info !== "" && blocks[0].info !== "txt")) {
|
|
179
|
+
refusal("Region must contain one closed fence with no info string or the exact 'txt' info string");
|
|
180
180
|
}
|
|
181
181
|
const other = section.children.filter((node) => node !== blocks[0] && nonblank(document, node));
|
|
182
182
|
if (other.length > 0)
|
|
@@ -51,10 +51,13 @@ export function acceptedDeliver(result, coordinate) {
|
|
|
51
51
|
return {
|
|
52
52
|
...acceptedEnvelope(result, coordinate),
|
|
53
53
|
verb: "deliver",
|
|
54
|
+
...(value.completion === undefined ? {} : { completion: value.completion }),
|
|
54
55
|
...(verificationVerdict === undefined ? {} : { verificationVerdict }),
|
|
55
56
|
...(value.verification === undefined ? {} : { verification: value.verification }),
|
|
56
57
|
...(value.verificationReuse === undefined ? {} : { verificationReuse: value.verificationReuse }),
|
|
58
|
+
...(value.verificationSummary === undefined ? {} : { verificationSummary: value.verificationSummary }),
|
|
57
59
|
...(value.placement === undefined ? {} : { placement: value.placement }),
|
|
60
|
+
...(value.continuation === undefined ? {} : { continuation: value.continuation }),
|
|
58
61
|
...(value.cleanup === undefined ? {} : { cleanup: value.cleanup }),
|
|
59
62
|
...(value.leak === undefined ? {} : { leak: value.leak }),
|
|
60
63
|
};
|
|
@@ -70,10 +73,13 @@ export function acceptedReview(result, coordinate) {
|
|
|
70
73
|
...acceptedEnvelope(result, coordinate),
|
|
71
74
|
verb: "review",
|
|
72
75
|
verdict: reviewAttestation.data.verdict,
|
|
76
|
+
...(value.completion === undefined ? {} : { completion: value.completion }),
|
|
73
77
|
...(verificationVerdict === undefined ? {} : { verificationVerdict }),
|
|
74
78
|
...(value.verification === undefined ? {} : { verification: value.verification }),
|
|
75
79
|
...(value.verificationReuse === undefined ? {} : { verificationReuse: value.verificationReuse }),
|
|
80
|
+
...(value.verificationSummary === undefined ? {} : { verificationSummary: value.verificationSummary }),
|
|
76
81
|
...(value.placement === undefined ? {} : { placement: value.placement }),
|
|
82
|
+
...(value.continuation === undefined ? {} : { continuation: value.continuation }),
|
|
77
83
|
...(value.workspace === undefined ? {} : { workspace: value.workspace }),
|
|
78
84
|
...(value.cleanup === undefined ? {} : { cleanup: value.cleanup }),
|
|
79
85
|
...(value.leak === undefined ? {} : { leak: value.leak }),
|
|
@@ -102,6 +102,7 @@ export async function invokeAkuma(command, input) {
|
|
|
102
102
|
...(input.statedCwd === undefined ? {} : { cwd: input.statedCwd }),
|
|
103
103
|
mode: command.mode,
|
|
104
104
|
...(command.timeoutMs === undefined ? {} : { timeoutMs: command.timeoutMs }),
|
|
105
|
+
...(command.readonly === undefined ? {} : { readonly: command.readonly }),
|
|
105
106
|
...(input.contract === undefined ? {} : { contract: input.contract }),
|
|
106
107
|
...(command.alias === undefined ? {} : { alias: command.alias }),
|
|
107
108
|
...(command.allowed === undefined ? {} : { allowed: command.allowed }),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CliUsageError, isBlankInput, usageLine
|
|
1
|
+
import { CliUsageError, isBlankInput, usageLine } from "../usage.js";
|
|
2
2
|
import { archetypeName, parseAkuId } from "../../akuma/identity.js";
|
|
3
3
|
import { parseDuration as decodeDuration } from "../../duration.js";
|
|
4
4
|
import { parseAkumaAlias, parseAkumaGlob } from "../../identity/selector.js";
|
|
@@ -12,16 +12,18 @@ const AKUMA_COMMAND_SPECS = {
|
|
|
12
12
|
alias: "value",
|
|
13
13
|
wait: "value",
|
|
14
14
|
detach: "boolean",
|
|
15
|
+
readonly: "boolean",
|
|
15
16
|
allowed: "repeatable",
|
|
16
17
|
json: "boolean",
|
|
17
18
|
},
|
|
18
|
-
usage: "call <akuma-name> [--contract <kei/...>] [--alias @name] [--allowed <product.action>]... [--wait <duration> | -d | --detach]
|
|
19
|
+
usage: "call <akuma-name> [--contract <kei/...>] [--alias @name] [--readonly] [--allowed <product.action>]... [--wait <duration> | -d | --detach] (<prompt> | -)",
|
|
19
20
|
purpose: "Birth an Akuma from <akuma-name> with one prompt.",
|
|
20
21
|
details: [
|
|
21
22
|
"Give <prompt> as one argument, or use final - to read stdin.",
|
|
22
23
|
"Default: --wait 5m. An explicit --wait replaces that duration; -d and --detach return after birth.",
|
|
23
24
|
"--contract dispatches the born Akuma to that Contract.",
|
|
24
25
|
"--alias assigns the world-local @name selector to the born Akuma.",
|
|
26
|
+
"--readonly adds the one-way read-only birth restriction.",
|
|
25
27
|
"Repeated --allowed replaces the Archetype list; --allowed none selects an empty list.",
|
|
26
28
|
"With --contract, Dispatch succeeds first. If @name exists, the alias then moves.",
|
|
27
29
|
].join("\n"),
|
|
@@ -30,14 +32,14 @@ const AKUMA_COMMAND_SPECS = {
|
|
|
30
32
|
arity: "one-or-more",
|
|
31
33
|
stdin: false,
|
|
32
34
|
flags: { any: "boolean", all: "boolean", timeout: "value", json: "boolean" },
|
|
33
|
-
usage: "wait <akuma-selector>... [--any | --all] [--timeout <duration>]
|
|
35
|
+
usage: "wait <akuma-selector>... [--any | --all] [--timeout <duration>]",
|
|
34
36
|
purpose: "Wait for one Akuma or an explicitly selected Akuma set.",
|
|
35
37
|
},
|
|
36
38
|
tell: {
|
|
37
39
|
arity: 1,
|
|
38
40
|
stdin: true,
|
|
39
41
|
flags: { interrupt: "boolean", json: "boolean" },
|
|
40
|
-
usage: "tell <aku/...|@alias> [--interrupt]
|
|
42
|
+
usage: "tell <aku/...|@alias> [--interrupt] (<prompt> | -)",
|
|
41
43
|
purpose: "Send one prompt to an existing Akuma and wake it.",
|
|
42
44
|
details: [
|
|
43
45
|
"Give <prompt> as one argument, or use final - to read stdin.",
|
|
@@ -48,21 +50,21 @@ const AKUMA_COMMAND_SPECS = {
|
|
|
48
50
|
arity: 1,
|
|
49
51
|
stdin: false,
|
|
50
52
|
flags: { before: "value", since: "value", limit: "value", last: "boolean", json: "boolean" },
|
|
51
|
-
usage: "history <aku/...|@alias|kei/...> [--before <index> | --since <index>] [--limit <count>] [--last]
|
|
53
|
+
usage: "history <aku/...|@alias|kei/...> [--before <index> | --since <index>] [--limit <count>] [--last]",
|
|
52
54
|
purpose: "Read Akuma execution history or one complete Contract journal and Dispatch timeline.",
|
|
53
55
|
},
|
|
54
56
|
fork: {
|
|
55
57
|
arity: 1,
|
|
56
58
|
stdin: false,
|
|
57
59
|
flags: { at: "value", json: "boolean" },
|
|
58
|
-
usage: "fork <aku/...> --at <historyId>
|
|
60
|
+
usage: "fork <aku/...> --at <historyId>",
|
|
59
61
|
purpose: "Fork one Akuma at a retained answered history point.",
|
|
60
62
|
},
|
|
61
63
|
kill: {
|
|
62
64
|
arity: "one-or-more",
|
|
63
65
|
stdin: false,
|
|
64
66
|
flags: { json: "boolean" },
|
|
65
|
-
usage: "kill <akuma-selector>...
|
|
67
|
+
usage: "kill <akuma-selector>...",
|
|
66
68
|
purpose: "Put down the current Body of an Akuma selector snapshot.",
|
|
67
69
|
},
|
|
68
70
|
};
|
|
@@ -77,7 +79,7 @@ export function renderAkumaRootRows() {
|
|
|
77
79
|
}
|
|
78
80
|
export function renderAkumaHelp(action) {
|
|
79
81
|
const spec = AKUMA_COMMAND_SPECS[action];
|
|
80
|
-
return
|
|
82
|
+
return `${spec.purpose}\n\n${usageLine(spec.usage)}${spec.details === undefined ? "" : `\n\n${spec.details}`}`;
|
|
81
83
|
}
|
|
82
84
|
export function renderAkumaUsage(action) {
|
|
83
85
|
return usageLine(AKUMA_COMMAND_SPECS[action].usage);
|
|
@@ -305,6 +307,7 @@ function parseCall(flags, archetype, prompt, output, fail) {
|
|
|
305
307
|
...(alias === undefined ? {} : { alias }),
|
|
306
308
|
mode,
|
|
307
309
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
310
|
+
...(flags.readonly === true ? { readonly: true } : {}),
|
|
308
311
|
...(allowed === undefined ? {} : { allowed }),
|
|
309
312
|
prompt,
|
|
310
313
|
output,
|