@astrosheep/keiyaku 2.8.5 → 2.9.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 +35 -15
- package/build/.tsbuildinfo +1 -1
- package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
- package/build/agents/harness/control-types.js +1 -0
- package/build/agents/harness/execution-handle.js +23 -3
- package/build/agents/harness/index.js +6 -607
- package/build/agents/harness/outcome.js +141 -0
- package/build/agents/harness/projection.js +310 -0
- package/build/agents/harness/router.js +201 -0
- package/build/agents/harness/runtime.js +2 -1
- package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
- package/build/agents/launch-snapshot/resolve.js +72 -0
- package/build/agents/opencode-sdk.js +24 -3
- package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
- package/build/agents/providers/claude-agent-sdk/events.js +218 -0
- package/build/agents/providers/claude-agent-sdk/session.js +158 -0
- package/build/agents/providers/codex-app-server/adapter.js +347 -0
- package/build/agents/providers/codex-app-server/events.js +352 -0
- package/build/agents/providers/codex-app-server/session.js +266 -0
- package/build/agents/providers/codex-sdk.js +23 -5
- package/build/agents/providers/opencode-sdk/adapter.js +344 -0
- package/build/agents/providers/opencode-sdk/events.js +354 -0
- package/build/agents/providers/opencode-sdk/session.js +180 -0
- package/build/agents/providers/pi/adapter.js +269 -0
- package/build/agents/providers/pi/checkpoint.js +41 -0
- package/build/agents/providers/pi/events.js +282 -0
- package/build/agents/{selector_v2.js → selector.js} +8 -6
- package/build/cli/commands/akuma/akuma/handler.js +4 -0
- package/build/cli/commands/akuma/akuma/meta.js +16 -0
- package/build/cli/commands/akuma/catalog.js +8 -0
- package/build/cli/commands/akuma/list/handler.js +15 -0
- package/build/cli/commands/akuma/list/meta-ls.js +9 -0
- package/build/cli/commands/akuma/view/handler.js +34 -0
- package/build/cli/commands/akuma/view/meta.js +8 -0
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +10 -0
- package/build/cli/commands/contract/amend/meta.js +12 -0
- package/build/cli/commands/contract/arc/handler.js +9 -0
- package/build/cli/commands/contract/arc/meta.js +26 -0
- package/build/cli/commands/contract/bind/handler.js +23 -0
- package/build/cli/commands/contract/bind/meta.js +30 -0
- package/build/cli/commands/contract/catalog.js +16 -0
- package/build/cli/commands/contract/forfeit/handler.js +13 -0
- package/build/cli/commands/contract/forfeit/meta.js +12 -0
- package/build/cli/commands/contract/log/handler.js +12 -0
- package/build/cli/commands/contract/log/meta.js +12 -0
- package/build/cli/commands/contract/petition/handler.js +26 -0
- package/build/cli/commands/contract/petition/meta.js +23 -0
- package/build/cli/commands/contract/renew/handler.js +10 -0
- package/build/cli/commands/contract/renew/meta.js +17 -0
- package/build/cli/commands/projection/call/handler.js +42 -0
- package/build/cli/commands/projection/call/meta.js +9 -0
- package/build/cli/commands/projection/catalog.js +14 -0
- package/build/cli/commands/projection/kill/handler.js +37 -0
- package/build/cli/commands/projection/kill/meta.js +11 -0
- package/build/cli/commands/projection/revive/handler.js +56 -0
- package/build/cli/commands/projection/revive/meta.js +9 -0
- package/build/cli/commands/projection/status/handler.js +25 -0
- package/build/cli/commands/projection/status/meta.js +9 -0
- package/build/cli/commands/projection/tell/handler.js +36 -0
- package/build/cli/commands/projection/tell/meta.js +9 -0
- package/build/cli/commands/projection/wait/handler.js +23 -0
- package/build/cli/commands/projection/wait/meta.js +11 -0
- package/build/cli/commands/registry.js +100 -0
- package/build/cli/commands/shared.js +71 -0
- package/build/cli/commands/skills/catalog.js +6 -0
- package/build/cli/commands/skills/install/handler.js +10 -0
- package/build/cli/commands/skills/install/meta.js +9 -0
- package/build/cli/commands/skills/skills/handler.js +4 -0
- package/build/cli/commands/skills/skills/meta.js +10 -0
- package/build/cli/commands/system/catalog.js +8 -0
- package/build/cli/commands/system/completion/handler.js +10 -0
- package/build/cli/commands/system/completion/meta.js +9 -0
- package/build/cli/commands/system/dump-env/handler.js +3 -0
- package/build/cli/commands/system/dump-env/meta.js +10 -0
- package/build/cli/commands/system/guide/handler.js +4 -0
- package/build/cli/commands/system/guide/meta.js +9 -0
- package/build/cli/commands/task/add/handler.js +21 -0
- package/build/cli/commands/task/add/meta.js +8 -0
- package/build/cli/commands/task/catalog.js +22 -0
- package/build/cli/commands/task/doctor/handler.js +4 -0
- package/build/cli/commands/task/doctor/meta.js +8 -0
- package/build/cli/commands/task/done/handler.js +17 -0
- package/build/cli/commands/task/done/meta.js +8 -0
- package/build/cli/commands/task/drop/handler.js +6 -0
- package/build/cli/commands/task/drop/meta.js +8 -0
- package/build/cli/commands/task/ls/handler.js +13 -0
- package/build/cli/commands/task/ls/meta.js +8 -0
- package/build/cli/commands/task/shared.js +131 -0
- package/build/cli/commands/task/start/handler.js +6 -0
- package/build/cli/commands/task/start/meta.js +8 -0
- package/build/cli/commands/task/stop/handler.js +17 -0
- package/build/cli/commands/task/stop/meta.js +8 -0
- package/build/cli/commands/task/task/handler.js +5 -0
- package/build/cli/commands/task/task/meta.js +11 -0
- package/build/cli/commands/task/update/handler.js +18 -0
- package/build/cli/commands/task/update/meta.js +8 -0
- package/build/cli/commands/task/view/handler.js +14 -0
- package/build/cli/commands/task/view/meta.js +8 -0
- package/build/cli/completion.js +26 -27
- package/build/cli/flags.js +79 -2
- package/build/cli/help.js +27 -49
- package/build/cli/index.js +121 -374
- package/build/cli/output-stream-error-policy.js +17 -0
- package/build/cli/parse-flags.js +197 -0
- package/build/cli/parse-metadata.js +129 -0
- package/build/cli/parse-selectors.js +65 -0
- package/build/cli/parse.js +46 -313
- package/build/cli/projection-address.js +5 -0
- package/build/cli/render/arc.js +1 -1
- package/build/cli/render/errors.js +4 -3
- package/build/cli/render/format.js +14 -0
- package/build/cli/render/kanshi.js +106 -0
- package/build/cli/render/petition.js +24 -1
- package/build/cli/render/projection-activity.js +5 -1
- package/build/cli/render/shared.js +2 -2
- package/build/cli/render/status.js +79 -13
- package/build/cli/render/task.js +113 -0
- package/build/cli/render/wait.js +23 -3
- package/build/cli/types.js +1 -1
- package/build/config/{akuma-loader_v2.js → akuma-loader.js} +7 -4
- package/build/config/env.js +9 -4
- package/build/config/settings/disease.js +26 -0
- package/build/config/settings/knobs.js +8 -0
- package/build/config/settings/loader.js +244 -0
- package/build/config/settings/schema.js +276 -0
- package/build/core/addressing.js +1 -1
- package/build/core/amend.js +5 -8
- package/build/core/arc.js +7 -8
- package/build/core/bind-workspace.js +123 -0
- package/build/core/bind.js +75 -155
- package/build/core/call/call.js +229 -0
- package/build/core/call/context.js +251 -0
- package/build/core/call/execution.js +217 -0
- package/build/core/call/prompt.js +42 -0
- package/build/core/call/reference.js +24 -0
- package/build/core/call-persist.js +10 -3
- package/build/core/claim-delivery.js +247 -0
- package/build/core/claim.js +39 -277
- package/build/core/context.js +2 -1
- package/build/core/{render.js → contract-view.js} +12 -140
- package/build/core/draft.js +107 -9
- package/build/core/entry.js +9 -1
- package/build/core/execution-coordinate.js +4 -20
- package/build/core/execution-pact.js +16 -31
- package/build/core/forfeit.js +35 -22
- package/build/core/hints.js +2 -2
- package/build/core/log.js +2 -2
- package/build/core/path-coordinate.js +27 -0
- package/build/core/petition-claim-gates.js +8 -6
- package/build/core/petition-preview.js +97 -0
- package/build/core/petition-run.js +5 -7
- package/build/core/petition.js +39 -26
- package/build/core/projection/generation/database.js +306 -0
- package/build/core/projection/generation/identity.js +84 -0
- package/build/core/projection/generation/model.js +201 -0
- package/build/core/projection/generation/store.js +73 -0
- package/build/core/projection/generation/transitions.js +258 -0
- package/build/core/projection/heart.js +0 -307
- package/build/core/projection/tell/database.js +109 -0
- package/build/core/projection/tell/model.js +97 -0
- package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
- package/build/core/projection-activity.js +23 -2
- package/build/core/projection-coordinate.js +14 -2
- package/build/core/projection-core.js +2 -1
- package/build/core/projection-execution-observer.js +259 -0
- package/build/core/projection-generation-continuation.js +1 -1
- package/build/core/projection-generation-execution.js +90 -20
- package/build/core/projection-generation-launcher.js +1 -1
- package/build/core/projection-generation-runner.js +198 -4
- package/build/core/projection-identity.js +1 -1
- package/build/core/projection-kill.js +50 -17
- package/build/core/projection-life-observer.js +1 -1
- package/build/core/projection-life-protocol.js +10 -0
- package/build/core/projection-mint.js +1 -1
- package/build/core/projection-status.js +45 -32
- package/build/core/projection-wait.js +12 -2
- package/build/core/projection-wake.js +5 -2
- package/build/core/{queue_v2.js → queue.js} +2 -1
- package/build/core/registry.js +1 -1
- package/build/core/renew.js +9 -11
- package/build/core/response-artifact-catalog-sqlite.js +112 -0
- package/build/core/response-artifact-catalog.js +7 -0
- package/build/core/seal.js +44 -16
- package/build/core/status/board.js +289 -0
- package/build/core/status/drift.js +99 -0
- package/build/core/status/lifecycle.js +84 -0
- package/build/core/status/reconciliation.js +131 -0
- package/build/core/stored-agent-event.js +28 -4
- package/build/core/target-ref.js +10 -0
- package/build/core/task/board.js +175 -0
- package/build/core/task/commands.js +211 -0
- package/build/core/task/document.js +189 -0
- package/build/core/task/model.js +1 -0
- package/build/core/task/settlement-git.js +207 -0
- package/build/core/task/settlement-policy.js +82 -0
- package/build/core/task/source-board.js +84 -0
- package/build/core/task/source-model.js +1 -0
- package/build/core/task/validation.js +44 -0
- package/build/core/task-contract.js +237 -0
- package/build/core/task-doctor.js +14 -0
- package/build/core/task-git-actor.js +38 -0
- package/build/core/task-git-runtime.js +37 -0
- package/build/core/task-git-store.js +385 -0
- package/build/core/task-repository.js +1 -0
- package/build/core/task-store-repository.js +86 -0
- package/build/core/task-store.js +1 -0
- package/build/core/task-worktree.js +51 -0
- package/build/core/task.js +4 -0
- package/build/core/transcripts.js +138 -56
- package/build/core/validation.js +17 -0
- package/build/core/verdict.js +2 -2
- package/build/core/worktree-path.js +33 -8
- package/build/flow-error.js +5 -2
- package/build/generated/version.js +1 -1
- package/build/git/branches.js +33 -9
- package/build/git/commits.js +3 -0
- package/build/git/core.js +9 -0
- package/build/git/diff/parsers.js +0 -94
- package/build/index.js +2 -0
- package/build/keiyaku-constants.js +2 -0
- package/build/keiyaku.js +4 -3
- package/package.json +3 -2
- package/skills/keiyaku/SKILL.md +30 -13
- package/skills/keiyaku-akuma/SKILL.md +30 -57
- package/skills/keiyaku-task/SKILL.md +51 -0
- package/skills/keiyaku-workflow/SKILL.md +71 -0
- package/build/agents/harness/pump.js +0 -158
- package/build/agents/providers/codex-app-server.js +0 -864
- package/build/agents/providers/opencode-sdk.js +0 -363
- package/build/agents/providers/pi.js +0 -557
- package/build/config/settings.js +0 -533
- package/build/core/call.js +0 -686
- package/build/core/projection/generation.js +0 -412
- package/build/core/projection/identity.js +0 -81
- package/build/core/projection/mint.js +0 -174
- package/build/core/projection-generation-store.js +0 -707
- package/build/core/status.js +0 -539
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { FlowError } from "../../flow-error.js";
|
|
3
|
-
import { appendDebugBlock, appendDebugLog } from "../../telemetry/debug-log.js";
|
|
4
|
-
import { createOpencode } from "../opencode-sdk.js";
|
|
5
|
-
import { SUBAGENT_SESSION_VERSION } from "../session.js";
|
|
6
|
-
import { createProjectionDriver } from "../harness/execution-handle.js";
|
|
7
|
-
import { buildSubagentEnv, coerceString, createAbortError, emitProviderEvidence, sha256Utf8 } from "../harness/runtime.js";
|
|
8
|
-
import { activityCallFromNamedTool } from "../harness/activity-values.js";
|
|
9
|
-
import { appendEventType, renderEventTypeSummary } from "./event-type-tail.js";
|
|
10
|
-
/** Identity-only opacity boundary for OpenCode session.prompt variant. */
|
|
11
|
-
function toOpencodeSdkVariant(effort) {
|
|
12
|
-
return effort;
|
|
13
|
-
}
|
|
14
|
-
export const opencodeSessionSchema = z.object({ sessionId: z.string().trim().min(1) });
|
|
15
|
-
const OPENCODE_EVENT_SESSION_IDLE = "session.idle";
|
|
16
|
-
const OPENCODE_EVENT_SESSION_ERROR = "session.error";
|
|
17
|
-
const OPENCODE_SDK_PROVIDER = "opencode-sdk";
|
|
18
|
-
function opencodeIngressDisposition(event) {
|
|
19
|
-
if (event.type === OPENCODE_EVENT_SESSION_IDLE)
|
|
20
|
-
return "acknowledged-unpersisted";
|
|
21
|
-
if (event.type === OPENCODE_EVENT_SESSION_ERROR)
|
|
22
|
-
return "mapped";
|
|
23
|
-
if (event.type === "message.part.updated" && event.properties.part.type === "tool") {
|
|
24
|
-
return event.properties.part.state.status === "pending" ? "acknowledged-unpersisted" : "mapped";
|
|
25
|
-
}
|
|
26
|
-
return "unknown";
|
|
27
|
-
}
|
|
28
|
-
const OPENCODE_DEFAULT_EXECUTABLE = "opencode";
|
|
29
|
-
const OPENCODE_ASSISTANT_ROLE = "assistant";
|
|
30
|
-
const OPENCODE_TEXT_PART_TYPE = "text";
|
|
31
|
-
let opencodeSdkLoader;
|
|
32
|
-
/**
|
|
33
|
-
* Convert configured opaque OpenCode model string at the first slash into the
|
|
34
|
-
* 1.17.20 prompt model object. No string compatibility path remains.
|
|
35
|
-
*/
|
|
36
|
-
export function parseOpencodeModelRef(model) {
|
|
37
|
-
const trimmed = model.trim();
|
|
38
|
-
const slash = trimmed.indexOf("/");
|
|
39
|
-
if (slash <= 0 || slash === trimmed.length - 1) {
|
|
40
|
-
throw new FlowError("INVALID_SETTINGS", `Invalid opencode model '${model}'. Expected opaque shape '<provider>/<model>' with non-empty segments split at the first slash.`);
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
providerID: trimmed.slice(0, slash),
|
|
44
|
-
modelID: trimmed.slice(slash + 1),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function extractTextFromMessage(message) {
|
|
48
|
-
if (!message?.parts)
|
|
49
|
-
return undefined;
|
|
50
|
-
const text = message.parts
|
|
51
|
-
.filter((part) => part.type === OPENCODE_TEXT_PART_TYPE)
|
|
52
|
-
.map((part) => coerceString(part.text))
|
|
53
|
-
.filter((part) => Boolean(part))
|
|
54
|
-
.join("");
|
|
55
|
-
return text.trim() || undefined;
|
|
56
|
-
}
|
|
57
|
-
function extractFinalAssistantMessage(messages) {
|
|
58
|
-
let lastText;
|
|
59
|
-
let lastAssistantText;
|
|
60
|
-
for (const message of messages) {
|
|
61
|
-
const text = extractTextFromMessage(message);
|
|
62
|
-
if (!text)
|
|
63
|
-
continue;
|
|
64
|
-
lastText = text;
|
|
65
|
-
if (message.info?.role === OPENCODE_ASSISTANT_ROLE) {
|
|
66
|
-
lastAssistantText = text;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return lastAssistantText ?? lastText;
|
|
70
|
-
}
|
|
71
|
-
function eventSessionId(event) {
|
|
72
|
-
const properties = event.properties;
|
|
73
|
-
if (!properties || typeof properties !== "object" || !("sessionID" in properties))
|
|
74
|
-
return undefined;
|
|
75
|
-
return typeof properties.sessionID === "string" ? properties.sessionID : undefined;
|
|
76
|
-
}
|
|
77
|
-
function extractToolCall(part) {
|
|
78
|
-
const input = part.state.input;
|
|
79
|
-
const stringFact = (primary, fallback) => {
|
|
80
|
-
const first = input[primary];
|
|
81
|
-
if (typeof first === "string" && first.length > 0)
|
|
82
|
-
return first;
|
|
83
|
-
const second = fallback === undefined ? undefined : input[fallback];
|
|
84
|
-
return typeof second === "string" && second.length > 0 ? second : undefined;
|
|
85
|
-
};
|
|
86
|
-
const integerFact = (key) => {
|
|
87
|
-
const value = input[key];
|
|
88
|
-
return typeof value === "number" && Number.isInteger(value) ? value : undefined;
|
|
89
|
-
};
|
|
90
|
-
const tool = part.tool.toLowerCase();
|
|
91
|
-
let facts = {};
|
|
92
|
-
if (tool === "bash" || tool === "shell") {
|
|
93
|
-
facts = { command: stringFact("command") };
|
|
94
|
-
}
|
|
95
|
-
else if (tool === "read") {
|
|
96
|
-
facts = {
|
|
97
|
-
path: stringFact("filePath", "path"),
|
|
98
|
-
offset: integerFact("offset"),
|
|
99
|
-
limit: integerFact("limit"),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
else if (tool === "write" || tool === "edit") {
|
|
103
|
-
facts = { path: stringFact("filePath", "path") };
|
|
104
|
-
}
|
|
105
|
-
else if (tool === "grep" || tool === "search" || tool === "glob") {
|
|
106
|
-
facts = { query: stringFact("pattern", "query") };
|
|
107
|
-
}
|
|
108
|
-
const classifierTool = tool === "grep" || tool === "glob" ? "search" : part.tool;
|
|
109
|
-
return activityCallFromNamedTool(classifierTool, facts);
|
|
110
|
-
}
|
|
111
|
-
function completedResult(state) {
|
|
112
|
-
const exit = state.metadata.exit;
|
|
113
|
-
const exitCode = typeof exit === "number" && Number.isInteger(exit) ? exit : undefined;
|
|
114
|
-
const message = coerceString(state.output);
|
|
115
|
-
return {
|
|
116
|
-
status: exitCode !== undefined && exitCode !== 0 ? "error" : "ok",
|
|
117
|
-
...(message ? { message } : {}),
|
|
118
|
-
...(exitCode === undefined ? {} : { exitCode }),
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
function isToolPartUpdated(event) {
|
|
122
|
-
return event.type === "message.part.updated" && event.properties.part.type === "tool";
|
|
123
|
-
}
|
|
124
|
-
function sessionErrorMessage(event) {
|
|
125
|
-
const data = event.properties.error?.data;
|
|
126
|
-
const message = data && "message" in data ? coerceString(data.message) : undefined;
|
|
127
|
-
return message ?? `${OPENCODE_SDK_PROVIDER} session error`;
|
|
128
|
-
}
|
|
129
|
-
async function withAbort(promise, signal, message) {
|
|
130
|
-
if (signal.aborted) {
|
|
131
|
-
throw createAbortError(message);
|
|
132
|
-
}
|
|
133
|
-
return new Promise((resolve, reject) => {
|
|
134
|
-
const cleanup = () => {
|
|
135
|
-
signal.removeEventListener("abort", onAbort);
|
|
136
|
-
};
|
|
137
|
-
const onAbort = () => {
|
|
138
|
-
cleanup();
|
|
139
|
-
reject(createAbortError(message));
|
|
140
|
-
};
|
|
141
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
142
|
-
promise.then((value) => {
|
|
143
|
-
cleanup();
|
|
144
|
-
resolve(value);
|
|
145
|
-
}, (error) => {
|
|
146
|
-
cleanup();
|
|
147
|
-
reject(error);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
async function loadOpencodeSdk(executable, cwd, env, signal) {
|
|
152
|
-
if (opencodeSdkLoader) {
|
|
153
|
-
return opencodeSdkLoader(cwd);
|
|
154
|
-
}
|
|
155
|
-
const sdk = await createOpencode({
|
|
156
|
-
executable,
|
|
157
|
-
directory: cwd,
|
|
158
|
-
env,
|
|
159
|
-
signal,
|
|
160
|
-
});
|
|
161
|
-
return {
|
|
162
|
-
client: sdk.client,
|
|
163
|
-
close: sdk.server?.close,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
async function awaitSessionIdle(input) {
|
|
167
|
-
const firstRunning = new Map();
|
|
168
|
-
const running = new Set();
|
|
169
|
-
const subscribed = await input.client.event.subscribe({ directory: input.directory });
|
|
170
|
-
for await (const event of subscribed.stream) {
|
|
171
|
-
if (eventSessionId(event) !== input.sessionId) {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
input.incrementEventCount();
|
|
175
|
-
appendEventType(input.recordedEventTypes, event.type);
|
|
176
|
-
let sessionError;
|
|
177
|
-
input.builder.ingress(OPENCODE_SDK_PROVIDER, event.type, event, opencodeIngressDisposition(event), () => {
|
|
178
|
-
if (event.type === OPENCODE_EVENT_SESSION_ERROR) {
|
|
179
|
-
sessionError = sessionErrorMessage(event);
|
|
180
|
-
input.builder.emit({ type: "diagnostic", text: sessionError });
|
|
181
|
-
input.builder.emit({ type: "fail", message: sessionError });
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
if (isToolPartUpdated(event)) {
|
|
185
|
-
const part = event.properties.part;
|
|
186
|
-
if (part.state.status === "pending")
|
|
187
|
-
return;
|
|
188
|
-
if (part.state.status === "running") {
|
|
189
|
-
const activity = firstRunning.get(part.id) ?? { tool: part.tool, call: extractToolCall(part) };
|
|
190
|
-
if (!firstRunning.has(part.id))
|
|
191
|
-
firstRunning.set(part.id, activity);
|
|
192
|
-
const phase = running.has(part.id) ? "updated" : "started";
|
|
193
|
-
running.add(part.id);
|
|
194
|
-
input.builder.emit({ type: "activity", phase, id: part.id, ...activity });
|
|
195
|
-
}
|
|
196
|
-
else if (part.state.status === "completed") {
|
|
197
|
-
const activity = firstRunning.get(part.id) ?? { tool: part.tool, call: extractToolCall(part) };
|
|
198
|
-
input.builder.emit({
|
|
199
|
-
type: "activity",
|
|
200
|
-
phase: "completed",
|
|
201
|
-
id: part.id,
|
|
202
|
-
...activity,
|
|
203
|
-
result: completedResult(part.state),
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
else if (part.state.status === "error") {
|
|
207
|
-
const activity = firstRunning.get(part.id) ?? { tool: part.tool, call: extractToolCall(part) };
|
|
208
|
-
input.builder.emit({
|
|
209
|
-
type: "activity",
|
|
210
|
-
phase: "completed",
|
|
211
|
-
id: part.id,
|
|
212
|
-
...activity,
|
|
213
|
-
result: { status: "error", message: part.state.error },
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
if (sessionError !== undefined)
|
|
219
|
-
throw new Error(sessionError);
|
|
220
|
-
if (event.type === OPENCODE_EVENT_SESSION_IDLE) {
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
const message = `${OPENCODE_SDK_PROVIDER} event stream ended before ${OPENCODE_EVENT_SESSION_IDLE}`;
|
|
225
|
-
input.builder.emit({ type: "fail", message });
|
|
226
|
-
throw new Error(message);
|
|
227
|
-
}
|
|
228
|
-
export function setOpencodeSdkLoaderForTests(loader) {
|
|
229
|
-
opencodeSdkLoader = loader;
|
|
230
|
-
}
|
|
231
|
-
export function resetOpencodeSdkLoaderForTests() {
|
|
232
|
-
opencodeSdkLoader = undefined;
|
|
233
|
-
}
|
|
234
|
-
export async function startOpencode(prompt, cwd, options = {}) {
|
|
235
|
-
const sessionId = options.sessionId?.trim();
|
|
236
|
-
const executable = options.executable ?? OPENCODE_DEFAULT_EXECUTABLE;
|
|
237
|
-
// A configured value is always intentional. Validate even empty/blank input
|
|
238
|
-
// before loading the SDK so it cannot silently become the provider default.
|
|
239
|
-
const modelRef = options.model === undefined ? undefined : parseOpencodeModelRef(options.model);
|
|
240
|
-
const recordedEventTypes = [];
|
|
241
|
-
let totalEventCount = 0;
|
|
242
|
-
let resumedSessionId;
|
|
243
|
-
let sdk;
|
|
244
|
-
let activeAbort;
|
|
245
|
-
appendDebugLog(`startOpencode: executable=${executable} model=${options.model ?? "default"} mode=${sessionId ? "resume" : "fresh"}`, { cwd, section: OPENCODE_SDK_PROVIDER });
|
|
246
|
-
return createProjectionDriver({
|
|
247
|
-
steerMode: "replay",
|
|
248
|
-
initialTurn: options.initialTurn,
|
|
249
|
-
onIngress: options.onIngress,
|
|
250
|
-
async abort() {
|
|
251
|
-
activeAbort?.abort();
|
|
252
|
-
},
|
|
253
|
-
async run(builder) {
|
|
254
|
-
activeAbort = new AbortController();
|
|
255
|
-
const combined = new AbortController();
|
|
256
|
-
const forward = () => combined.abort();
|
|
257
|
-
builder.signal.addEventListener("abort", forward, { once: true });
|
|
258
|
-
options.signal?.addEventListener("abort", forward, { once: true });
|
|
259
|
-
activeAbort.signal.addEventListener("abort", forward, { once: true });
|
|
260
|
-
if (builder.signal.aborted || options.signal?.aborted || activeAbort.signal.aborted) {
|
|
261
|
-
forward();
|
|
262
|
-
}
|
|
263
|
-
try {
|
|
264
|
-
const env = buildSubagentEnv();
|
|
265
|
-
sdk = await withAbort(loadOpencodeSdk(executable, cwd, env, combined.signal), combined.signal, `${OPENCODE_SDK_PROVIDER} exec cancelled by client`);
|
|
266
|
-
// OpenCode 1.17.20 session.create has no model field; keep cwd only.
|
|
267
|
-
const session = sessionId
|
|
268
|
-
? await withAbort(sdk.client.session.get({ sessionID: sessionId, directory: cwd }, { throwOnError: true }), combined.signal, `${OPENCODE_SDK_PROVIDER} exec cancelled by client`)
|
|
269
|
-
: await withAbort(sdk.client.session.create({ directory: cwd }, { throwOnError: true }), combined.signal, `${OPENCODE_SDK_PROVIDER} exec cancelled by client`);
|
|
270
|
-
resumedSessionId = session.data.id || sessionId;
|
|
271
|
-
if (!resumedSessionId) {
|
|
272
|
-
const message = `${OPENCODE_SDK_PROVIDER} exec could not determine session id`;
|
|
273
|
-
builder.emit({ type: "fail", message });
|
|
274
|
-
throw new Error(message);
|
|
275
|
-
}
|
|
276
|
-
const activeSessionId = resumedSessionId;
|
|
277
|
-
if (options.onEvidence)
|
|
278
|
-
emitProviderEvidence(options.onEvidence, { type: "session", provider: OPENCODE_SDK_PROVIDER, sessionId: activeSessionId }, (text) => builder.emit({ type: "diagnostic", text }));
|
|
279
|
-
const idlePromise = awaitSessionIdle({
|
|
280
|
-
client: sdk.client,
|
|
281
|
-
builder,
|
|
282
|
-
sessionId: activeSessionId,
|
|
283
|
-
directory: cwd,
|
|
284
|
-
recordedEventTypes,
|
|
285
|
-
incrementEventCount: () => {
|
|
286
|
-
totalEventCount += 1;
|
|
287
|
-
},
|
|
288
|
-
});
|
|
289
|
-
// session.prompt is the OpenCode SDK input crossing. Emitting the run
|
|
290
|
-
// acknowledgement after the call returns keeps synchronous startup
|
|
291
|
-
// failures replayable without delaying completion of the request.
|
|
292
|
-
if (options.onEvidence) {
|
|
293
|
-
emitProviderEvidence(options.onEvidence, {
|
|
294
|
-
type: "outbound",
|
|
295
|
-
provider: OPENCODE_SDK_PROVIDER,
|
|
296
|
-
direction: "input",
|
|
297
|
-
kind: "replay-prompt",
|
|
298
|
-
...sha256Utf8(prompt),
|
|
299
|
-
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
300
|
-
}
|
|
301
|
-
const textPart = { type: OPENCODE_TEXT_PART_TYPE, text: prompt };
|
|
302
|
-
builder.emit({ type: "turn", phase: "started" });
|
|
303
|
-
const promptPromise = sdk.client.session.prompt({
|
|
304
|
-
sessionID: activeSessionId,
|
|
305
|
-
directory: cwd,
|
|
306
|
-
...(modelRef ? { model: modelRef } : {}),
|
|
307
|
-
...(options.effort ? { variant: toOpencodeSdkVariant(options.effort) } : {}),
|
|
308
|
-
parts: [textPart],
|
|
309
|
-
}, { throwOnError: true });
|
|
310
|
-
if (options.onEvidence) {
|
|
311
|
-
emitProviderEvidence(options.onEvidence, {
|
|
312
|
-
type: "ack",
|
|
313
|
-
provider: OPENCODE_SDK_PROVIDER,
|
|
314
|
-
fence: { kind: "ordinal", ordinal: 0 },
|
|
315
|
-
outbound: "run",
|
|
316
|
-
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
317
|
-
}
|
|
318
|
-
const [promptResult] = await withAbort(Promise.all([promptPromise, idlePromise]), combined.signal, `${OPENCODE_SDK_PROVIDER} exec cancelled by client`);
|
|
319
|
-
let finalMessage = extractTextFromMessage(promptResult.data);
|
|
320
|
-
if (!finalMessage) {
|
|
321
|
-
const messages = await withAbort(sdk.client.session.messages({ sessionID: activeSessionId, directory: cwd }, { throwOnError: true }), combined.signal, `${OPENCODE_SDK_PROVIDER} exec cancelled by client`);
|
|
322
|
-
finalMessage = extractFinalAssistantMessage(messages.data);
|
|
323
|
-
}
|
|
324
|
-
if (finalMessage) {
|
|
325
|
-
builder.emit({ type: "message", text: finalMessage });
|
|
326
|
-
}
|
|
327
|
-
const sessionEnvelope = {
|
|
328
|
-
provider: "opencode-sdk",
|
|
329
|
-
version: SUBAGENT_SESSION_VERSION,
|
|
330
|
-
handle: { sessionId: resumedSessionId },
|
|
331
|
-
};
|
|
332
|
-
const resolvedFinal = finalMessage ?? "";
|
|
333
|
-
if (options.onEvidence) {
|
|
334
|
-
emitProviderEvidence(options.onEvidence, {
|
|
335
|
-
type: "checkpoint",
|
|
336
|
-
provider: OPENCODE_SDK_PROVIDER,
|
|
337
|
-
fence: { kind: "ordinal", ordinal: 1 },
|
|
338
|
-
source: "response",
|
|
339
|
-
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
340
|
-
}
|
|
341
|
-
builder.emit({ type: "turn", phase: "completed" });
|
|
342
|
-
builder.emit({
|
|
343
|
-
type: "done",
|
|
344
|
-
finalMessage: resolvedFinal,
|
|
345
|
-
session: sessionEnvelope,
|
|
346
|
-
});
|
|
347
|
-
return { finalMessage: resolvedFinal, session: sessionEnvelope };
|
|
348
|
-
}
|
|
349
|
-
catch (error) {
|
|
350
|
-
appendDebugLog(`startOpencode error: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`, { cwd, section: OPENCODE_SDK_PROVIDER });
|
|
351
|
-
throw error;
|
|
352
|
-
}
|
|
353
|
-
finally {
|
|
354
|
-
if (resumedSessionId) {
|
|
355
|
-
appendDebugBlock("opencode-sdk stdout event types", renderEventTypeSummary(recordedEventTypes, totalEventCount), { cwd, section: OPENCODE_SDK_PROVIDER });
|
|
356
|
-
}
|
|
357
|
-
await sdk?.close?.();
|
|
358
|
-
builder.signal.removeEventListener("abort", forward);
|
|
359
|
-
options.signal?.removeEventListener("abort", forward);
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
}
|