@astrosheep/keiyaku 4.0.6 → 4.1.1
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 +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
- package/build/src/akuma/akuma.d.ts +17 -14
- package/build/src/akuma/akuma.js +122 -114
- package/build/src/akuma/allowed.d.ts +1 -0
- package/build/src/akuma/allowed.js +6 -0
- package/build/src/akuma/archetype.js +12 -2
- package/build/src/akuma/body-turn.js +27 -15
- package/build/src/akuma/body.d.ts +44 -3
- package/build/src/akuma/body.js +142 -33
- package/build/src/akuma/coordinate.js +17 -7
- package/build/src/akuma/heart/facts.js +1 -1
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/index.js +2 -4
- package/build/src/akuma/heart/request-authority.js +4 -4
- package/build/src/akuma/heart/request-rows.js +27 -16
- package/build/src/akuma/heart/rows.js +79 -41
- package/build/src/akuma/heart/soul.js +1 -1
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +76 -11
- package/build/src/akuma/heart/tells.js +35 -18
- package/build/src/akuma/heart/timeline.js +19 -11
- package/build/src/akuma/identity.d.ts +1 -0
- package/build/src/akuma/identity.js +1 -0
- package/build/src/akuma/index.d.ts +3 -3
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/nuke.js +106 -14
- package/build/src/akuma/projection.d.ts +11 -9
- package/build/src/akuma/projection.js +110 -53
- package/build/src/akuma/provider-recipe.d.ts +2 -0
- package/build/src/akuma/provider-recipe.js +21 -5
- package/build/src/akuma/provider.js +105 -62
- package/build/src/akuma/providers/acp/config.d.ts +2 -0
- package/build/src/akuma/providers/acp/config.js +13 -6
- package/build/src/akuma/providers/acp/core.d.ts +5 -2
- package/build/src/akuma/providers/acp/core.js +45 -25
- package/build/src/akuma/providers/acp/events.js +38 -29
- package/build/src/akuma/providers/acp/index.js +18 -8
- package/build/src/akuma/providers/claude/events.js +8 -12
- package/build/src/akuma/providers/claude/index.d.ts +2 -1
- package/build/src/akuma/providers/claude/index.js +59 -26
- package/build/src/akuma/providers/claude/input.js +6 -2
- package/build/src/akuma/providers/codex-app-server/events.js +61 -36
- package/build/src/akuma/providers/codex-app-server/index.js +29 -14
- package/build/src/akuma/providers/grok-build/index.js +28 -17
- package/build/src/akuma/providers/index.js +3 -19
- package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
- package/build/src/akuma/providers/opencode-sdk/index.js +29 -17
- package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
- package/build/src/akuma/providers/pi/events.js +26 -19
- package/build/src/akuma/providers/pi/index.js +58 -38
- package/build/src/akuma/publication.js +9 -9
- package/build/src/akuma/request-serve.js +37 -40
- package/build/src/akuma/request-wire.d.ts +2 -2
- package/build/src/akuma/request-wire.js +75 -102
- package/build/src/akuma/requests.js +2 -2
- package/build/src/akuma-body.js +6 -5
- package/build/src/body/amend.d.ts +4 -1
- package/build/src/body/amend.js +14 -15
- package/build/src/body/decode.js +2 -4
- package/build/src/body/envelope.js +2 -4
- package/build/src/body/region.d.ts +1 -2
- package/build/src/body/region.js +4 -72
- package/build/src/body/render.js +17 -12
- package/build/src/body/shape.js +1 -7
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +10 -1
- package/build/src/cli/commands/akuma-invoke.js +18 -6
- package/build/src/cli/commands/akuma.js +10 -13
- package/build/src/cli/commands/amend.d.ts +2 -2
- package/build/src/cli/commands/amend.js +2 -4
- package/build/src/cli/commands/bind.d.ts +4 -4
- package/build/src/cli/commands/bind.js +16 -6
- package/build/src/cli/commands/contract.d.ts +99 -10
- package/build/src/cli/commands/contract.js +128 -24
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +23 -15
- package/build/src/cli/commands/task-invoke.d.ts +4 -1
- package/build/src/cli/commands/task-invoke.js +191 -68
- package/build/src/cli/commands/task-query.js +48 -24
- package/build/src/cli/commands/task.js +150 -30
- package/build/src/cli/coordinates.js +2 -4
- package/build/src/cli/invoke.js +88 -44
- package/build/src/cli/main.js +4 -2
- package/build/src/cli/parse.d.ts +2 -89
- package/build/src/cli/parse.js +87 -79
- package/build/src/cli/render/akuma-tool-command.js +6 -7
- package/build/src/cli/render/akuma-tool.js +10 -8
- package/build/src/cli/render/akuma.js +149 -53
- package/build/src/cli/render/audit.js +5 -15
- package/build/src/cli/render/board.d.ts +1 -0
- package/build/src/cli/render/board.js +17 -0
- package/build/src/cli/render/catalog.js +84 -7
- package/build/src/cli/render/contract-observation.d.ts +10 -0
- package/build/src/cli/render/contract-observation.js +58 -0
- package/build/src/cli/render/contract.js +57 -54
- package/build/src/cli/render/kanshi.js +281 -209
- package/build/src/cli/render/receipt.d.ts +1 -0
- package/build/src/cli/render/receipt.js +20 -23
- package/build/src/cli/render/refusal.js +16 -15
- package/build/src/cli/render/region.js +22 -6
- package/build/src/cli/render/settings.js +4 -4
- package/build/src/cli/render/task.js +93 -21
- package/build/src/cli/render/terminal.js +16 -5
- package/build/src/cli/result.d.ts +11 -4
- package/build/src/cli/runtime.d.ts +6 -1
- package/build/src/cli/runtime.js +84 -63
- package/build/src/cli/selectors.js +2 -4
- package/build/src/cli/usage.js +6 -5
- package/build/src/contract-worktree.d.ts +1 -25
- package/build/src/contract-worktree.js +87 -174
- package/build/src/coordination/durable-file.js +7 -3
- package/build/src/coordination/sqlite-transaction-lock.js +29 -12
- package/build/src/core/facts/codec.js +7 -3
- package/build/src/core/facts/types.d.ts +1 -1
- package/build/src/core/subject.js +16 -9
- package/build/src/core/verbs/abandon.d.ts +1 -1
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +7 -7
- package/build/src/core/verbs/attestation.js +4 -1
- package/build/src/core/verbs/bind.d.ts +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +10 -8
- package/build/src/dispatch/index.js +8 -6
- package/build/src/duration.js +5 -1
- package/build/src/git/admission.js +5 -3
- package/build/src/git/hooks.d.ts +8 -0
- package/build/src/git/hooks.js +63 -14
- package/build/src/git/identity.js +1 -4
- package/build/src/git/integration.d.ts +2 -3
- package/build/src/git/integration.js +32 -39
- package/build/src/git/nuke.d.ts +1 -1
- package/build/src/git/nuke.js +110 -62
- package/build/src/git/observe.d.ts +13 -1
- package/build/src/git/observe.js +51 -44
- package/build/src/git/process.js +4 -2
- package/build/src/git/read-observation.js +10 -8
- package/build/src/git/reconcile.d.ts +14 -3
- package/build/src/git/reconcile.js +123 -102
- package/build/src/git/repository.d.ts +2 -0
- package/build/src/git/repository.js +13 -22
- package/build/src/git/target-placement.d.ts +9 -10
- package/build/src/git/target-placement.js +59 -62
- package/build/src/git/tender.d.ts +13 -2
- package/build/src/git/tender.js +28 -22
- package/build/src/git/terminal-seal.js +15 -12
- package/build/src/git/tree.js +5 -2
- package/build/src/git/workspace.d.ts +24 -2
- package/build/src/git/workspace.js +120 -16
- package/build/src/identity/coordinates.js +3 -1
- package/build/src/identity/selector.js +6 -3
- package/build/src/kanshi/fleet.d.ts +6 -0
- package/build/src/kanshi/fleet.js +27 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +77 -45
- package/build/src/kanshi/report.d.ts +13 -24
- package/build/src/kanshi/select.js +25 -24
- package/build/src/library/address.d.ts +2 -1
- package/build/src/library/address.js +7 -8
- package/build/src/library/akuma-creation.js +20 -12
- package/build/src/library/audit.d.ts +0 -1
- package/build/src/library/audit.js +1 -2
- package/build/src/library/bind.d.ts +53 -5
- package/build/src/library/bind.js +98 -22
- package/build/src/library/catalog.d.ts +1 -0
- package/build/src/library/catalog.js +6 -3
- package/build/src/library/configuration.js +3 -1
- package/build/src/library/continuation.d.ts +37 -0
- package/build/src/library/continuation.js +86 -0
- package/build/src/library/contract.d.ts +39 -45
- package/build/src/library/contract.js +141 -118
- package/build/src/library/delivery.d.ts +18 -13
- package/build/src/library/fleet.d.ts +1 -1
- package/build/src/library/fleet.js +19 -11
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +14 -0
- package/build/src/library/keiyaku.d.ts +8 -7
- package/build/src/library/keiyaku.js +3 -3
- package/build/src/library/mutation.js +11 -4
- package/build/src/library/nuke.js +14 -5
- package/build/src/library/reconcile.d.ts +9 -4
- package/build/src/library/reconcile.js +30 -24
- package/build/src/library/refusal.d.ts +13 -5
- package/build/src/library/refusal.js +7 -0
- package/build/src/library/region.d.ts +8 -7
- package/build/src/library/region.js +31 -11
- package/build/src/library/repo.js +2 -2
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/parse.js +11 -7
- package/build/src/markdown/query.js +4 -2
- package/build/src/protocol/amend.js +3 -1
- package/build/src/protocol/attempt.d.ts +7 -3
- package/build/src/protocol/attempt.js +9 -5
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +4 -14
- package/build/src/protocol/bind.d.ts +19 -6
- package/build/src/protocol/bind.js +28 -13
- package/build/src/protocol/completion.d.ts +0 -1
- package/build/src/protocol/completion.js +1 -3
- package/build/src/protocol/deliver.d.ts +12 -4
- package/build/src/protocol/deliver.js +60 -51
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +9 -7
- package/build/src/protocol/operations.d.ts +10 -9
- package/build/src/protocol/operations.js +5 -3
- package/build/src/protocol/placement.d.ts +0 -1
- package/build/src/protocol/placement.js +6 -6
- package/build/src/protocol/read/observation.d.ts +11 -0
- package/build/src/protocol/read/observation.js +37 -0
- package/build/src/protocol/read/status.d.ts +23 -12
- package/build/src/protocol/read/status.js +90 -72
- package/build/src/protocol/reconcile.d.ts +1 -0
- package/build/src/protocol/reconcile.js +2 -3
- package/build/src/protocol/reintegrate.js +1 -1
- package/build/src/protocol/review.d.ts +0 -1
- package/build/src/protocol/review.js +15 -22
- package/build/src/protocol/run.d.ts +1 -0
- package/build/src/protocol/run.js +4 -5
- package/build/src/runtime/proc/launch.d.ts +33 -0
- package/build/src/runtime/proc/launch.js +98 -0
- package/build/src/runtime/proc/line-rpc.js +9 -3
- package/build/src/runtime/proc/run.d.ts +12 -6
- package/build/src/runtime/proc/run.js +78 -21
- package/build/src/runtime/proc/stdio.js +7 -10
- package/build/src/settings.js +6 -2
- package/build/src/settlement/fence.d.ts +0 -2
- package/build/src/settlement/fence.js +0 -24
- package/build/src/settlement/holder.js +13 -10
- package/build/src/settlement/settle.js +39 -6
- package/build/src/task/board.d.ts +21 -2
- package/build/src/task/board.js +35 -16
- package/build/src/task/compose.js +85 -22
- package/build/src/task/context.js +21 -8
- package/build/src/task/document.js +46 -10
- package/build/src/task/identity.js +19 -6
- package/build/src/task/index.js +118 -27
- package/build/src/task/input.js +29 -7
- package/build/src/task/mutation.js +61 -19
- package/build/src/task/operations.d.ts +8 -2
- package/build/src/task/operations.js +97 -32
- package/build/src/task/query.js +57 -28
- package/build/src/task/store.d.ts +5 -1
- package/build/src/task/store.js +88 -95
- package/build/src/verification/execution.js +14 -11
- package/build/src/workspace-place.js +19 -7
- package/build/src/world.js +16 -6
- package/package.json +8 -3
|
@@ -46,7 +46,8 @@ const RUNTIME_DROPPED_EVENT_KINDS = new Set([
|
|
|
46
46
|
]);
|
|
47
47
|
function object(value) {
|
|
48
48
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
49
|
-
? value
|
|
49
|
+
? value
|
|
50
|
+
: undefined;
|
|
50
51
|
}
|
|
51
52
|
function text(value) {
|
|
52
53
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
@@ -83,8 +84,7 @@ function editCall(input, metadata) {
|
|
|
83
84
|
}
|
|
84
85
|
function writeCall(input, metadata) {
|
|
85
86
|
const path = text(metadata?.filepath) ?? text(input?.filePath);
|
|
86
|
-
const op = metadata?.exists === false ? "add"
|
|
87
|
-
: metadata?.exists === true ? "update" : undefined;
|
|
87
|
+
const op = metadata?.exists === false ? "add" : metadata?.exists === true ? "update" : undefined;
|
|
88
88
|
return path === undefined || op === undefined ? undefined : fileChange([change(op, path, undefined)]);
|
|
89
89
|
}
|
|
90
90
|
function applyPatchFile(value) {
|
|
@@ -92,10 +92,13 @@ function applyPatchFile(value) {
|
|
|
92
92
|
if (file === undefined)
|
|
93
93
|
return undefined;
|
|
94
94
|
const type = file.type;
|
|
95
|
-
const op = type === "add"
|
|
96
|
-
|
|
95
|
+
const op = type === "add"
|
|
96
|
+
? "add"
|
|
97
|
+
: type === "delete"
|
|
98
|
+
? "delete"
|
|
97
99
|
: type === "update" || type === "modify" || type === "move"
|
|
98
|
-
? "update"
|
|
100
|
+
? "update"
|
|
101
|
+
: undefined;
|
|
99
102
|
const path = type === "move" ? text(file.movePath) : text(file.filePath);
|
|
100
103
|
return op === undefined || path === undefined ? undefined : change(op, path, diffstat(file));
|
|
101
104
|
}
|
|
@@ -115,9 +118,7 @@ function strongerCall(previous, next) {
|
|
|
115
118
|
return next;
|
|
116
119
|
}
|
|
117
120
|
function runCall(name, value) {
|
|
118
|
-
return name === "bash" || name === "shell"
|
|
119
|
-
? { kind: "run", command: text(value?.command) ?? name }
|
|
120
|
-
: undefined;
|
|
121
|
+
return name === "bash" || name === "shell" ? { kind: "run", command: text(value?.command) ?? name } : undefined;
|
|
121
122
|
}
|
|
122
123
|
function readCall(name, value) {
|
|
123
124
|
if (name !== "read")
|
|
@@ -189,9 +190,16 @@ function resultFor(state, failed) {
|
|
|
189
190
|
const exit = object(state.metadata)?.exit;
|
|
190
191
|
const exitCode = typeof exit === "number" && Number.isInteger(exit) ? exit : undefined;
|
|
191
192
|
if (failed) {
|
|
192
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
status: "error",
|
|
195
|
+
message: text(state.error) ?? "OpenCode tool failed",
|
|
196
|
+
...(exitCode === undefined ? {} : { exitCode }),
|
|
197
|
+
};
|
|
193
198
|
}
|
|
194
|
-
return {
|
|
199
|
+
return {
|
|
200
|
+
status: exitCode !== undefined && exitCode !== 0 ? "error" : "ok",
|
|
201
|
+
...(exitCode === undefined ? {} : { exitCode }),
|
|
202
|
+
};
|
|
195
203
|
}
|
|
196
204
|
function mapToolPart(part, events, state) {
|
|
197
205
|
if (!belongs(part, state))
|
|
@@ -202,8 +210,9 @@ function mapToolPart(part, events, state) {
|
|
|
202
210
|
if (id === undefined || name === undefined || toolState === undefined)
|
|
203
211
|
return;
|
|
204
212
|
const next = callFor(name, toolState.input, toolState.metadata);
|
|
205
|
-
if ((toolState.status === "pending" || toolState.status === "running")
|
|
206
|
-
|
|
213
|
+
if ((toolState.status === "pending" || toolState.status === "running") &&
|
|
214
|
+
!state.tools.has(id) &&
|
|
215
|
+
!state.completedTools.has(id)) {
|
|
207
216
|
if (next === undefined)
|
|
208
217
|
return;
|
|
209
218
|
const observed = { name, call: next };
|
|
@@ -251,17 +260,19 @@ function mapSessionError(properties, events, state) {
|
|
|
251
260
|
function mapTodo(properties, events, state) {
|
|
252
261
|
if (properties.sessionID !== state.sessionId || !Array.isArray(properties.todos))
|
|
253
262
|
return;
|
|
254
|
-
const summary = properties.todos
|
|
263
|
+
const summary = properties.todos
|
|
264
|
+
.flatMap((value) => {
|
|
255
265
|
const todo = object(value);
|
|
256
266
|
const content = text(todo?.content);
|
|
257
267
|
return content === undefined ? [] : [`${text(todo?.status) ?? "todo"}: ${content}`];
|
|
258
|
-
})
|
|
268
|
+
})
|
|
269
|
+
.join("; ");
|
|
259
270
|
if (summary.length > 0)
|
|
260
271
|
events.emit(noteEvent(summary));
|
|
261
272
|
}
|
|
262
273
|
function ignoredEvent(type) {
|
|
263
|
-
return typeof type === "string"
|
|
264
|
-
|
|
274
|
+
return (typeof type === "string" &&
|
|
275
|
+
(OPENCODE_EVENT_DISPOSITIONS[type] === "dropped" || RUNTIME_DROPPED_EVENT_KINDS.has(type)));
|
|
265
276
|
}
|
|
266
277
|
export function mapEvent(value, events, state) {
|
|
267
278
|
const event = object(value);
|
|
@@ -276,7 +287,10 @@ export function mapEvent(value, events, state) {
|
|
|
276
287
|
}
|
|
277
288
|
if (event.type === "message.updated") {
|
|
278
289
|
const info = object(properties.info);
|
|
279
|
-
if (info !== undefined &&
|
|
290
|
+
if (info !== undefined &&
|
|
291
|
+
info.sessionID === state.sessionId &&
|
|
292
|
+
info.role === "assistant" &&
|
|
293
|
+
info.error !== undefined) {
|
|
280
294
|
state.failure = diagnostic(info.error);
|
|
281
295
|
}
|
|
282
296
|
return;
|
|
@@ -5,7 +5,8 @@ import { createEventState, mapEvent } from "./events.js";
|
|
|
5
5
|
import { coordinate, loadOpencode, OPENCODE_SDK_PROVIDER, parseModel } from "./session.js";
|
|
6
6
|
function object(value) {
|
|
7
7
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
8
|
-
? value
|
|
8
|
+
? value
|
|
9
|
+
: undefined;
|
|
9
10
|
}
|
|
10
11
|
function text(value) {
|
|
11
12
|
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
@@ -24,6 +25,9 @@ function opencodeSessionId(coordinateValue) {
|
|
|
24
25
|
function admit(options) {
|
|
25
26
|
if (options.network !== undefined)
|
|
26
27
|
throw new Error("OpenCode does not support explicit network");
|
|
28
|
+
if (options.systemPromptMode === "replace") {
|
|
29
|
+
throw new Error("OpenCode V1 does not support replacing the native system prompt");
|
|
30
|
+
}
|
|
27
31
|
if (options.model !== undefined)
|
|
28
32
|
parseModel(options.model);
|
|
29
33
|
}
|
|
@@ -132,10 +136,7 @@ function nativeProgress(type, properties, busy) {
|
|
|
132
136
|
function startsTurn(value, sessionId, messageID) {
|
|
133
137
|
const event = object(value);
|
|
134
138
|
const info = object(object(event?.properties)?.info);
|
|
135
|
-
return event?.type === "message.updated"
|
|
136
|
-
&& info?.sessionID === sessionId
|
|
137
|
-
&& info.role === "user"
|
|
138
|
-
&& info.id === messageID;
|
|
139
|
+
return (event?.type === "message.updated" && info?.sessionID === sessionId && info.role === "user" && info.id === messageID);
|
|
139
140
|
}
|
|
140
141
|
async function observeTurn(input) {
|
|
141
142
|
let active = false;
|
|
@@ -203,9 +204,7 @@ async function forceDisposeOpencode(abortController, close, finish) {
|
|
|
203
204
|
async function drive(execution, input, loader) {
|
|
204
205
|
admit(input.options);
|
|
205
206
|
const signal = input.signal ?? new AbortController().signal;
|
|
206
|
-
const resumeSessionId = input.session.kind === "resume"
|
|
207
|
-
? opencodeSessionId(input.session.coordinate)
|
|
208
|
-
: undefined;
|
|
207
|
+
const resumeSessionId = input.session.kind === "resume" ? opencodeSessionId(input.session.coordinate) : undefined;
|
|
209
208
|
const abortController = new AbortController();
|
|
210
209
|
const abortSetup = () => abortController.abort(signal.reason);
|
|
211
210
|
signal.addEventListener("abort", abortSetup, { once: true });
|
|
@@ -237,11 +236,20 @@ async function drive(execution, input, loader) {
|
|
|
237
236
|
const messageID = `msg_${randomUUID().replaceAll("-", "")}`;
|
|
238
237
|
const submissionState = { started: false };
|
|
239
238
|
events.emit({ type: "session", coordinate: coordinate(sessionId) });
|
|
240
|
-
const streamResult = await abortable(runtime.client.event.subscribe({ query: { directory: input.cwd } }), abortController.signal, async (late) => {
|
|
239
|
+
const streamResult = await abortable(runtime.client.event.subscribe({ query: { directory: input.cwd } }), abortController.signal, async (late) => {
|
|
240
|
+
await late.stream[Symbol.asyncIterator]().return?.(undefined);
|
|
241
|
+
});
|
|
241
242
|
iterator = streamResult.stream[Symbol.asyncIterator]();
|
|
242
243
|
const { completion, finish } = terminalSettlement(events, closeOnce);
|
|
243
244
|
const observation = observeTurn({
|
|
244
|
-
iterator,
|
|
245
|
+
iterator,
|
|
246
|
+
session,
|
|
247
|
+
sessionId,
|
|
248
|
+
cwd: input.cwd,
|
|
249
|
+
messageID,
|
|
250
|
+
events,
|
|
251
|
+
state,
|
|
252
|
+
submissionState,
|
|
245
253
|
});
|
|
246
254
|
submissionState.started = true;
|
|
247
255
|
await abortable(session.promptAsync({
|
|
@@ -258,7 +266,9 @@ async function drive(execution, input, loader) {
|
|
|
258
266
|
completion,
|
|
259
267
|
abort: async () => {
|
|
260
268
|
abortController.abort();
|
|
261
|
-
void session
|
|
269
|
+
void session
|
|
270
|
+
.abort({ path: { id: sessionId }, query: { directory: input.cwd }, throwOnError: true })
|
|
271
|
+
.catch(() => undefined);
|
|
262
272
|
await finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
|
|
263
273
|
},
|
|
264
274
|
forceDispose: () => forceDisposeOpencode(abortController, closeOnce, finish),
|
|
@@ -285,12 +295,14 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
|
|
|
285
295
|
return {
|
|
286
296
|
kind: "admitted",
|
|
287
297
|
options: Object.freeze({ ...options }),
|
|
288
|
-
...(options.readonly === undefined
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
298
|
+
...(options.readonly === undefined
|
|
299
|
+
? {}
|
|
300
|
+
: {
|
|
301
|
+
readonly: {
|
|
302
|
+
enforcement: "none",
|
|
303
|
+
diagnostic: "OpenCode V1 cannot remove task-surface mutation capabilities",
|
|
304
|
+
},
|
|
305
|
+
}),
|
|
294
306
|
};
|
|
295
307
|
},
|
|
296
308
|
start: (input) => drive(execution, input, loader),
|
|
@@ -33,20 +33,29 @@ async function availablePort() {
|
|
|
33
33
|
reject(new Error("OpenCode port unavailable"));
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
server.close((error) => error === undefined ? resolve(address.port) : reject(error));
|
|
36
|
+
server.close((error) => (error === undefined ? resolve(address.port) : reject(error)));
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
export async function loadOpencode(execution, cwd, signal, loader) {
|
|
41
41
|
if (loader) {
|
|
42
42
|
const loaded = await loader(cwd, execution);
|
|
43
|
-
return {
|
|
43
|
+
return {
|
|
44
|
+
client: loaded.client,
|
|
45
|
+
close: async () => {
|
|
46
|
+
await loaded.close?.();
|
|
47
|
+
},
|
|
48
|
+
};
|
|
44
49
|
}
|
|
45
50
|
const port = await availablePort();
|
|
46
51
|
const owned = await spawnDetachedProcess({
|
|
47
52
|
argv: [execution.executable ?? "opencode", "serve", "--hostname", "127.0.0.1", "--port", String(port)],
|
|
48
53
|
cwd,
|
|
49
|
-
env: {
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
...(execution.config === undefined ? {} : { OPENCODE_CONFIG_CONTENT: JSON.stringify(execution.config) }),
|
|
57
|
+
...execution.env,
|
|
58
|
+
},
|
|
50
59
|
log: `${cwd}/.opencode.log`,
|
|
51
60
|
});
|
|
52
61
|
const { createOpencodeClient } = await import("@opencode-ai/sdk");
|
|
@@ -58,6 +67,13 @@ export async function loadOpencode(execution, cwd, signal, loader) {
|
|
|
58
67
|
await owned.terminate();
|
|
59
68
|
throw error;
|
|
60
69
|
}
|
|
61
|
-
return {
|
|
70
|
+
return {
|
|
71
|
+
client,
|
|
72
|
+
close: async () => {
|
|
73
|
+
await owned.terminate();
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function coordinate(sessionId) {
|
|
78
|
+
return { sessionId };
|
|
62
79
|
}
|
|
63
|
-
export function coordinate(sessionId) { return { sessionId }; }
|
|
@@ -23,25 +23,29 @@ export const PI_EVENT_DISPOSITIONS = {
|
|
|
23
23
|
};
|
|
24
24
|
function record(value) {
|
|
25
25
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
26
|
-
? value
|
|
26
|
+
? value
|
|
27
|
+
: null;
|
|
27
28
|
}
|
|
28
29
|
function textContent(content) {
|
|
29
30
|
if (typeof content === "string")
|
|
30
31
|
return content;
|
|
31
32
|
if (!Array.isArray(content))
|
|
32
33
|
return "";
|
|
33
|
-
return content
|
|
34
|
+
return content
|
|
35
|
+
.map((block) => {
|
|
34
36
|
const value = record(block);
|
|
35
37
|
return value?.type === "text" && typeof value.text === "string" ? value.text : "";
|
|
36
|
-
})
|
|
38
|
+
})
|
|
39
|
+
.join("");
|
|
37
40
|
}
|
|
38
41
|
function hasTextContent(content) {
|
|
39
42
|
if (typeof content === "string")
|
|
40
43
|
return true;
|
|
41
|
-
return Array.isArray(content) &&
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
return (Array.isArray(content) &&
|
|
45
|
+
content.some((block) => {
|
|
46
|
+
const value = record(block);
|
|
47
|
+
return value?.type === "text" && typeof value.text === "string";
|
|
48
|
+
}));
|
|
45
49
|
}
|
|
46
50
|
function positiveLine(value) {
|
|
47
51
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
|
|
@@ -50,9 +54,7 @@ function optionalText(value) {
|
|
|
50
54
|
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
51
55
|
}
|
|
52
56
|
function runCall(name, value) {
|
|
53
|
-
return name === "bash" && typeof value.command === "string"
|
|
54
|
-
? { kind: "run", command: value.command }
|
|
55
|
-
: undefined;
|
|
57
|
+
return name === "bash" && typeof value.command === "string" ? { kind: "run", command: value.command } : undefined;
|
|
56
58
|
}
|
|
57
59
|
function readCall(name, value) {
|
|
58
60
|
if (name !== "read" || typeof value.path !== "string")
|
|
@@ -101,11 +103,10 @@ function refineEditCall(call, result) {
|
|
|
101
103
|
}
|
|
102
104
|
function toolCall(name, args) {
|
|
103
105
|
const value = record(args) ?? {};
|
|
104
|
-
return runCall(name, value)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
?? { kind: "other", display: name };
|
|
106
|
+
return (runCall(name, value) ??
|
|
107
|
+
readCall(name, value) ??
|
|
108
|
+
searchCall(name, value) ??
|
|
109
|
+
fileChangeCall(name, value) ?? { kind: "other", display: name });
|
|
109
110
|
}
|
|
110
111
|
function translateNote(event) {
|
|
111
112
|
if (event.type === "auto_retry_start")
|
|
@@ -122,11 +123,16 @@ function translateToolEnd(event, state) {
|
|
|
122
123
|
state.tools.delete(event.toolCallId);
|
|
123
124
|
const name = started?.name ?? event.toolName;
|
|
124
125
|
const call = started?.call ?? { kind: "other", display: name };
|
|
125
|
-
return [
|
|
126
|
-
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
type: "tool",
|
|
129
|
+
phase: "completed",
|
|
130
|
+
id: event.toolCallId,
|
|
131
|
+
name,
|
|
127
132
|
call: event.isError ? call : refineEditCall(call, event.result),
|
|
128
133
|
result: { status: event.isError ? "error" : "ok" },
|
|
129
|
-
}
|
|
134
|
+
},
|
|
135
|
+
];
|
|
130
136
|
}
|
|
131
137
|
function translateMessage(event, state) {
|
|
132
138
|
const message = record(event.message);
|
|
@@ -174,7 +180,8 @@ export function piTerminalFailure(messages) {
|
|
|
174
180
|
if (message.stopReason !== "error")
|
|
175
181
|
return null;
|
|
176
182
|
return typeof message.errorMessage === "string" && message.errorMessage.trim().length > 0
|
|
177
|
-
? message.errorMessage
|
|
183
|
+
? message.errorMessage
|
|
184
|
+
: "Pi provider ended with an error";
|
|
178
185
|
}
|
|
179
186
|
return null;
|
|
180
187
|
}
|
|
@@ -3,7 +3,9 @@ import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
|
3
3
|
import { piTerminalFailure, translatePiEvent } from "./events.js";
|
|
4
4
|
const PI_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
5
5
|
const MODEL_PATTERN = /^[^/\s]+\/[^\s]+$/u;
|
|
6
|
-
function diagnostic(error) {
|
|
6
|
+
function diagnostic(error) {
|
|
7
|
+
return error instanceof Error ? error.message : String(error);
|
|
8
|
+
}
|
|
7
9
|
function admitPiOptions(options) {
|
|
8
10
|
if (options.network !== undefined)
|
|
9
11
|
return { kind: "refused", diagnostic: "Pi provider does not support the network option" };
|
|
@@ -29,25 +31,33 @@ async function piCreateOptions(sdk, input) {
|
|
|
29
31
|
if (model === undefined)
|
|
30
32
|
throw new Error(`Pi model '${input.options.model}' is unavailable`);
|
|
31
33
|
}
|
|
32
|
-
const resourceLoader = input.options.systemPrompt === undefined
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const resourceLoader = input.options.systemPrompt === undefined
|
|
35
|
+
? undefined
|
|
36
|
+
: new sdk.DefaultResourceLoader({
|
|
37
|
+
cwd: input.cwd,
|
|
38
|
+
agentDir: sdk.getAgentDir(),
|
|
39
|
+
...(input.options.systemPromptMode === "append"
|
|
40
|
+
? { appendSystemPromptOverride: (base) => [...base, input.options.systemPrompt] }
|
|
41
|
+
: { systemPromptOverride: () => input.options.systemPrompt }),
|
|
42
|
+
});
|
|
37
43
|
await resourceLoader?.reload();
|
|
38
44
|
const sessionManager = input.session.kind === "fresh"
|
|
39
45
|
? sdk.SessionManager.create(input.cwd)
|
|
40
46
|
: "sessionFile" in input.session.coordinate
|
|
41
47
|
? sdk.SessionManager.open(input.session.coordinate.sessionFile)
|
|
42
|
-
: (() => {
|
|
48
|
+
: (() => {
|
|
49
|
+
throw new Error("Pi resume requires sessionFile");
|
|
50
|
+
})();
|
|
43
51
|
const customTools = input.requests === undefined || input.options.readonly === true
|
|
44
52
|
? undefined
|
|
45
|
-
: [
|
|
53
|
+
: [
|
|
54
|
+
(await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
|
|
46
55
|
spawnHook: (context) => ({
|
|
47
56
|
...context,
|
|
48
57
|
env: { ...context.env, [AKUMA_REQUESTS_ENV]: input.requests.dir },
|
|
49
58
|
}),
|
|
50
|
-
})
|
|
59
|
+
}),
|
|
60
|
+
];
|
|
51
61
|
return {
|
|
52
62
|
cwd: input.cwd,
|
|
53
63
|
sessionManager,
|
|
@@ -58,8 +68,13 @@ async function piCreateOptions(sdk, input) {
|
|
|
58
68
|
...(customTools === undefined ? {} : { customTools }),
|
|
59
69
|
};
|
|
60
70
|
}
|
|
61
|
-
async function createPiSession(sdk, input, signal) {
|
|
62
|
-
const setup = piCreateOptions(sdk, input).then(async (options) =>
|
|
71
|
+
async function createPiSession(sdk, execution, input, signal) {
|
|
72
|
+
const setup = piCreateOptions(sdk, input).then(async (options) => {
|
|
73
|
+
if (execution.config !== undefined) {
|
|
74
|
+
throw new TypeError("Pi provider config cannot be consumed by native CreateAgentSessionOptions");
|
|
75
|
+
}
|
|
76
|
+
return await sdk.createAgentSession(options);
|
|
77
|
+
});
|
|
63
78
|
return await abortable(setup, signal, (created) => created.session.dispose());
|
|
64
79
|
}
|
|
65
80
|
function forceDisposePi(dispose, settle, setAborting) {
|
|
@@ -68,8 +83,8 @@ function forceDisposePi(dispose, settle, setAborting) {
|
|
|
68
83
|
settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
|
|
69
84
|
return Promise.resolve();
|
|
70
85
|
}
|
|
71
|
-
async function drivePi(sdk, input, signal) {
|
|
72
|
-
const created = await createPiSession(sdk, input, signal);
|
|
86
|
+
async function drivePi(sdk, execution, input, signal) {
|
|
87
|
+
const created = await createPiSession(sdk, execution, input, signal);
|
|
73
88
|
const native = created.session;
|
|
74
89
|
if (signal.aborted) {
|
|
75
90
|
native.dispose();
|
|
@@ -110,7 +125,9 @@ async function drivePi(sdk, input, signal) {
|
|
|
110
125
|
});
|
|
111
126
|
events.emit({ type: "session", coordinate: { sessionFile: native.sessionFile, sessionId: native.sessionId } });
|
|
112
127
|
let settleCompletion;
|
|
113
|
-
const completion = new Promise((resolve) => {
|
|
128
|
+
const completion = new Promise((resolve) => {
|
|
129
|
+
settleCompletion = resolve;
|
|
130
|
+
});
|
|
114
131
|
const settle = (result) => {
|
|
115
132
|
if (settled)
|
|
116
133
|
return;
|
|
@@ -121,24 +138,22 @@ async function drivePi(sdk, input, signal) {
|
|
|
121
138
|
void (async () => {
|
|
122
139
|
try {
|
|
123
140
|
await native.prompt([input.body, ...input.launchTells.map((tell) => tell.text)].join("\n\n"));
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
let result;
|
|
142
|
+
if (aborting)
|
|
143
|
+
result = { kind: "failed", diagnostic: "Pi session aborted" };
|
|
144
|
+
else if (terminalFailure !== null)
|
|
145
|
+
result = { kind: "failed", diagnostic: terminalFailure };
|
|
146
|
+
else if (!state.assistantSeen)
|
|
147
|
+
result = { kind: "failed", diagnostic: "Pi completed without a native assistant answer" };
|
|
148
|
+
else {
|
|
149
|
+
const historyId = native.sessionManager.getLeafId();
|
|
150
|
+
result = {
|
|
151
|
+
kind: "answered",
|
|
152
|
+
answer: state.answer,
|
|
153
|
+
...(historyId === null ? {} : { historyId }),
|
|
154
|
+
};
|
|
131
155
|
}
|
|
132
|
-
|
|
133
|
-
settle({ kind: "failed", diagnostic: "Pi completed without a native assistant answer" });
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const historyId = native.sessionManager.getLeafId();
|
|
137
|
-
settle({
|
|
138
|
-
kind: "answered",
|
|
139
|
-
answer: state.answer,
|
|
140
|
-
...(historyId === null ? {} : { historyId }),
|
|
141
|
-
});
|
|
156
|
+
settle(result);
|
|
142
157
|
}
|
|
143
158
|
catch (error) {
|
|
144
159
|
settle(aborting
|
|
@@ -147,7 +162,9 @@ async function drivePi(sdk, input, signal) {
|
|
|
147
162
|
}
|
|
148
163
|
})();
|
|
149
164
|
return {
|
|
150
|
-
admission: { fence: native.sessionId },
|
|
165
|
+
admission: { fence: native.sessionId },
|
|
166
|
+
events,
|
|
167
|
+
completion,
|
|
151
168
|
abort: () => {
|
|
152
169
|
abortRequest ??= (async () => {
|
|
153
170
|
if (settled)
|
|
@@ -156,12 +173,16 @@ async function drivePi(sdk, input, signal) {
|
|
|
156
173
|
try {
|
|
157
174
|
await native.abort();
|
|
158
175
|
}
|
|
159
|
-
catch {
|
|
176
|
+
catch {
|
|
177
|
+
/* prompt settlement still proves local cleanup */
|
|
178
|
+
}
|
|
160
179
|
settle({ kind: "failed", diagnostic: "Pi session aborted" });
|
|
161
180
|
})();
|
|
162
181
|
return abortRequest;
|
|
163
182
|
},
|
|
164
|
-
forceDispose: () => forceDisposePi(dispose, settle, () => {
|
|
183
|
+
forceDispose: () => forceDisposePi(dispose, settle, () => {
|
|
184
|
+
aborting = true;
|
|
185
|
+
}),
|
|
165
186
|
};
|
|
166
187
|
}
|
|
167
188
|
function piSessionFile(coordinate) {
|
|
@@ -188,16 +209,15 @@ async function loadPiSdk() {
|
|
|
188
209
|
};
|
|
189
210
|
}
|
|
190
211
|
export function createPiProvider(execution = { name: "pi", kind: "pi" }, load = loadPiSdk) {
|
|
191
|
-
if (execution.executable !== undefined
|
|
192
|
-
throw new TypeError("Pi provider does not support executable
|
|
193
|
-
}
|
|
212
|
+
if (execution.executable !== undefined)
|
|
213
|
+
throw new TypeError("Pi provider does not support executable");
|
|
194
214
|
if (execution.env !== undefined && Object.keys(execution.env).length > 0) {
|
|
195
215
|
throw new TypeError("env injection not supported for provider pi");
|
|
196
216
|
}
|
|
197
217
|
const drive = async (input) => {
|
|
198
218
|
const signal = input.signal ?? new AbortController().signal;
|
|
199
219
|
signal.throwIfAborted();
|
|
200
|
-
return drivePi(await abortable(load(), signal), input, signal);
|
|
220
|
+
return drivePi(await abortable(load(), signal), execution, input, signal);
|
|
201
221
|
};
|
|
202
222
|
return {
|
|
203
223
|
admitOptions: admitPiOptions,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul
|
|
2
|
-
import { allocateAkumaDirectory
|
|
1
|
+
import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul } from "./heart/index.js";
|
|
2
|
+
import { allocateAkumaDirectory } from "./identity.js";
|
|
3
3
|
import { abortableDelay } from "./abort.js";
|
|
4
|
-
const POLL_MS =
|
|
4
|
+
const POLL_MS = 100;
|
|
5
5
|
export const BIRTH_TIMEOUT_MS = 30_000;
|
|
6
6
|
function diagnostic(error) {
|
|
7
7
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -22,9 +22,7 @@ async function settleTimedOutBirth(paths) {
|
|
|
22
22
|
}
|
|
23
23
|
if (result === "sealed") {
|
|
24
24
|
const seal = await readSeal(paths);
|
|
25
|
-
throw new Error(seal?.evidence === "call-timeout" || seal === null
|
|
26
|
-
? "Akuma body failed before birth"
|
|
27
|
-
: seal.evidence);
|
|
25
|
+
throw new Error(seal?.evidence === "call-timeout" || seal === null ? "Akuma body failed before birth" : seal.evidence);
|
|
28
26
|
}
|
|
29
27
|
const soul = await readSoul(paths);
|
|
30
28
|
if (soul === null)
|
|
@@ -57,7 +55,7 @@ async function awaitBirth(paths, signal) {
|
|
|
57
55
|
if (settled !== null)
|
|
58
56
|
return settled;
|
|
59
57
|
}
|
|
60
|
-
await abortableDelay(POLL_MS, signal);
|
|
58
|
+
await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())), signal);
|
|
61
59
|
}
|
|
62
60
|
}
|
|
63
61
|
async function takeLeashUntil(paths, deadline) {
|
|
@@ -67,7 +65,7 @@ async function takeLeashUntil(paths, deadline) {
|
|
|
67
65
|
return leash;
|
|
68
66
|
if (performance.now() >= deadline)
|
|
69
67
|
return null;
|
|
70
|
-
await abortableDelay(POLL_MS);
|
|
68
|
+
await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
|
|
71
69
|
}
|
|
72
70
|
}
|
|
73
71
|
async function awaitAsleepBirth(paths) {
|
|
@@ -98,7 +96,9 @@ async function sealLocalFailure(allocated, error) {
|
|
|
98
96
|
leash.release();
|
|
99
97
|
}
|
|
100
98
|
}
|
|
101
|
-
catch {
|
|
99
|
+
catch {
|
|
100
|
+
/* the original local publication failure remains authoritative */
|
|
101
|
+
}
|
|
102
102
|
}
|
|
103
103
|
export async function publishAkuma(input) {
|
|
104
104
|
input.signal?.throwIfAborted();
|