@integrity-labs/agt-cli 0.28.621 → 0.28.623
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/dist/bin/agt.js +4 -4
- package/dist/{chunk-QSPSXG4K.js → chunk-UIB2SMFE.js} +94 -279
- package/dist/chunk-UIB2SMFE.js.map +1 -0
- package/dist/{chunk-MSQXSVA5.js → chunk-X73OEEMY.js} +4 -3
- package/dist/chunk-X73OEEMY.js.map +1 -0
- package/dist/{claude-pair-runtime-63GQ5AOP.js → claude-pair-runtime-4JKKKO2Q.js} +2 -2
- package/dist/lib/manager-worker.js +11 -11
- package/dist/{persistent-session-IFZS5AXT.js → persistent-session-UCWXUJE6.js} +2 -2
- package/dist/{responsiveness-probe-76U4MR6U.js → responsiveness-probe-YDGTWNZ3.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-MSQXSVA5.js.map +0 -1
- package/dist/chunk-QSPSXG4K.js.map +0 -1
- /package/dist/{claude-pair-runtime-63GQ5AOP.js.map → claude-pair-runtime-4JKKKO2Q.js.map} +0 -0
- /package/dist/{persistent-session-IFZS5AXT.js.map → persistent-session-UCWXUJE6.js.map} +0 -0
- /package/dist/{responsiveness-probe-76U4MR6U.js.map → responsiveness-probe-YDGTWNZ3.js.map} +0 -0
package/dist/bin/agt.js
CHANGED
|
@@ -40,10 +40,10 @@ import {
|
|
|
40
40
|
success,
|
|
41
41
|
table,
|
|
42
42
|
warn
|
|
43
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-X73OEEMY.js";
|
|
44
44
|
import {
|
|
45
45
|
readDirectChatSessionState
|
|
46
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-UIB2SMFE.js";
|
|
47
47
|
import {
|
|
48
48
|
AnchorSessionClient,
|
|
49
49
|
CHANNEL_REGISTRY,
|
|
@@ -4909,7 +4909,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4909
4909
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4910
4910
|
import chalk18 from "chalk";
|
|
4911
4911
|
import ora16 from "ora";
|
|
4912
|
-
var cliVersion = true ? "0.28.
|
|
4912
|
+
var cliVersion = true ? "0.28.623" : "dev";
|
|
4913
4913
|
async function fetchLatestVersion() {
|
|
4914
4914
|
const host2 = getHost();
|
|
4915
4915
|
if (!host2) return null;
|
|
@@ -6089,7 +6089,7 @@ function handleError(err) {
|
|
|
6089
6089
|
}
|
|
6090
6090
|
|
|
6091
6091
|
// src/bin/agt.ts
|
|
6092
|
-
var cliVersion2 = true ? "0.28.
|
|
6092
|
+
var cliVersion2 = true ? "0.28.623" : "dev";
|
|
6093
6093
|
var program = new Command();
|
|
6094
6094
|
program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
|
|
6095
6095
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -848,7 +848,6 @@ function buildOpencodeIntegrationServers(integrations, ctx) {
|
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
// ../../packages/core/dist/provisioning/frameworks/opencode/opencode-client.js
|
|
851
|
-
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
852
851
|
var HttpOpencodeClient = class _HttpOpencodeClient {
|
|
853
852
|
base;
|
|
854
853
|
headers;
|
|
@@ -895,68 +894,44 @@ var HttpOpencodeClient = class _HttpOpencodeClient {
|
|
|
895
894
|
}
|
|
896
895
|
}
|
|
897
896
|
async createSession(params) {
|
|
898
|
-
const out = await this.call("POST", "/
|
|
899
|
-
const id = out.
|
|
897
|
+
const out = await this.call("POST", "/session", params ?? {});
|
|
898
|
+
const id = out.id;
|
|
900
899
|
if (!id)
|
|
901
900
|
throw new Error("opencode createSession returned no session id");
|
|
902
901
|
return { sessionID: id };
|
|
903
902
|
}
|
|
904
|
-
async
|
|
905
|
-
const out = await this.call("POST", `/
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
// provider/model instead of defaulting the session to a free Zen model.
|
|
909
|
-
...params.model ? { model: params.model } : {},
|
|
910
|
-
delivery: params.delivery ?? "queue"
|
|
903
|
+
async sendMessage(params) {
|
|
904
|
+
const out = await this.call("POST", `/session/${params.sessionID}/message`, {
|
|
905
|
+
parts: [{ type: "text", text: params.text }],
|
|
906
|
+
...params.model ? { model: { providerID: params.model.providerID, modelID: params.model.id } } : {}
|
|
911
907
|
});
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
async waitIdle(sessionID, opts = {}) {
|
|
915
|
-
const timeoutMs = opts.timeoutMs ?? 12e4;
|
|
916
|
-
const pollIntervalMs = opts.pollIntervalMs ?? 300;
|
|
917
|
-
const deadline = Date.now() + timeoutMs;
|
|
918
|
-
for (; ; ) {
|
|
919
|
-
const newest = _HttpOpencodeClient.newestByCreated(await this.fetchMessages(sessionID));
|
|
920
|
-
if (newest?.type === "assistant" && newest.time?.completed != null)
|
|
921
|
-
return;
|
|
922
|
-
if (Date.now() >= deadline) {
|
|
923
|
-
throw new Error(`opencode waitIdle: session ${sessionID} did not go idle within ${timeoutMs}ms`);
|
|
924
|
-
}
|
|
925
|
-
await delay(pollIntervalMs);
|
|
926
|
-
}
|
|
908
|
+
const reply = _HttpOpencodeClient.textOf(out.parts ?? []);
|
|
909
|
+
return { reply, messageID: out.info?.id, parentID: out.info?.parentID };
|
|
927
910
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
const
|
|
931
|
-
if (!newest)
|
|
932
|
-
return null;
|
|
933
|
-
const text = (newest.content ?? []).filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
|
|
911
|
+
/** Concatenated text of the `text` parts of one message, or null if none. */
|
|
912
|
+
static textOf(parts) {
|
|
913
|
+
const text = parts.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
|
|
934
914
|
return text || null;
|
|
935
915
|
}
|
|
936
916
|
async fetchMessages(sessionID) {
|
|
937
|
-
const out = await this.call("GET", `/
|
|
938
|
-
|
|
917
|
+
const out = await this.call("GET", `/session/${sessionID}/message`);
|
|
918
|
+
if (!Array.isArray(out))
|
|
919
|
+
return [];
|
|
920
|
+
return out.map((m) => ({
|
|
921
|
+
id: m.info?.id,
|
|
922
|
+
type: m.info?.role,
|
|
923
|
+
time: m.info?.time,
|
|
924
|
+
finish: m.info?.finish,
|
|
925
|
+
content: m.parts ?? []
|
|
926
|
+
}));
|
|
939
927
|
}
|
|
940
928
|
async listSessions() {
|
|
941
|
-
const out = await this.call("GET", "/
|
|
942
|
-
return (out
|
|
929
|
+
const out = await this.call("GET", "/session");
|
|
930
|
+
return (Array.isArray(out) ? out : []).filter((s) => typeof s.id === "string").map((s) => ({ id: s.id, title: s.title, updated: s.time?.updated, created: s.time?.created }));
|
|
943
931
|
}
|
|
944
932
|
async getStructuredMessages(sessionID) {
|
|
945
933
|
return this.fetchMessages(sessionID);
|
|
946
934
|
}
|
|
947
|
-
/** The message with the greatest `time.created` (opencode returns newest-first, but don't rely on order). */
|
|
948
|
-
static newestByCreated(messages) {
|
|
949
|
-
let newest;
|
|
950
|
-
let newestT = Number.NEGATIVE_INFINITY;
|
|
951
|
-
for (const m of messages) {
|
|
952
|
-
const t = m.time?.created ?? 0;
|
|
953
|
-
if (t >= newestT) {
|
|
954
|
-
newestT = t;
|
|
955
|
-
newest = m;
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return newest;
|
|
959
|
-
}
|
|
960
935
|
};
|
|
961
936
|
|
|
962
937
|
// ../../packages/core/dist/provisioning/frameworks/opencode/opencode-transcript.js
|
|
@@ -1025,123 +1000,13 @@ function buildPart(p, redact, maxPartChars) {
|
|
|
1025
1000
|
return { kind: "other" };
|
|
1026
1001
|
}
|
|
1027
1002
|
|
|
1028
|
-
// ../../packages/core/dist/provisioning/frameworks/opencode/opencode-run.js
|
|
1029
|
-
var OpencodeRunError = class extends Error {
|
|
1030
|
-
admitted;
|
|
1031
|
-
constructor(message, admitted, options) {
|
|
1032
|
-
super(message, options);
|
|
1033
|
-
this.name = "OpencodeRunError";
|
|
1034
|
-
this.admitted = admitted;
|
|
1035
|
-
}
|
|
1036
|
-
};
|
|
1037
|
-
function runCrossedAdmission(stdout) {
|
|
1038
|
-
for (const line2 of stdout.split("\n")) {
|
|
1039
|
-
const trimmed = line2.trim();
|
|
1040
|
-
if (!trimmed)
|
|
1041
|
-
continue;
|
|
1042
|
-
try {
|
|
1043
|
-
JSON.parse(trimmed);
|
|
1044
|
-
return true;
|
|
1045
|
-
} catch {
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
return false;
|
|
1049
|
-
}
|
|
1050
|
-
function buildOpencodeRunArgs(params, opts = {}) {
|
|
1051
|
-
const args = [
|
|
1052
|
-
"run",
|
|
1053
|
-
"--attach",
|
|
1054
|
-
params.serveUrl,
|
|
1055
|
-
"--dir",
|
|
1056
|
-
params.projectDir,
|
|
1057
|
-
"--session",
|
|
1058
|
-
params.sessionID,
|
|
1059
|
-
"--format",
|
|
1060
|
-
"json"
|
|
1061
|
-
];
|
|
1062
|
-
if (opts.includePasswordArg && params.password) {
|
|
1063
|
-
args.push("-p", params.password);
|
|
1064
|
-
}
|
|
1065
|
-
if (params.model) {
|
|
1066
|
-
args.push("--model", `${params.model.providerID}/${params.model.id}`);
|
|
1067
|
-
}
|
|
1068
|
-
if (params.agent) {
|
|
1069
|
-
args.push("--agent", params.agent);
|
|
1070
|
-
}
|
|
1071
|
-
args.push(params.text);
|
|
1072
|
-
return args;
|
|
1073
|
-
}
|
|
1074
|
-
function parseOpencodeRunReply(stdout) {
|
|
1075
|
-
const parts = [];
|
|
1076
|
-
for (const line2 of stdout.split("\n")) {
|
|
1077
|
-
const trimmed = line2.trim();
|
|
1078
|
-
if (!trimmed)
|
|
1079
|
-
continue;
|
|
1080
|
-
let evt;
|
|
1081
|
-
try {
|
|
1082
|
-
evt = JSON.parse(trimmed);
|
|
1083
|
-
} catch {
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
|
-
const e = evt;
|
|
1087
|
-
if (e?.type === "text" && e.part && e.part.type === "text" && typeof e.part.text === "string") {
|
|
1088
|
-
parts.push(e.part.text);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
const reply = parts.join("").trim();
|
|
1092
|
-
return reply.length > 0 ? reply : null;
|
|
1093
|
-
}
|
|
1094
|
-
function parseOpencodeRunError(stdout) {
|
|
1095
|
-
for (const line2 of stdout.split("\n")) {
|
|
1096
|
-
const trimmed = line2.trim();
|
|
1097
|
-
if (!trimmed)
|
|
1098
|
-
continue;
|
|
1099
|
-
let evt;
|
|
1100
|
-
try {
|
|
1101
|
-
evt = JSON.parse(trimmed);
|
|
1102
|
-
} catch {
|
|
1103
|
-
continue;
|
|
1104
|
-
}
|
|
1105
|
-
const e = evt;
|
|
1106
|
-
if (e?.type === "error") {
|
|
1107
|
-
const msg = e.error?.data?.message;
|
|
1108
|
-
if (typeof msg === "string" && msg.length > 0)
|
|
1109
|
-
return msg;
|
|
1110
|
-
const name = e.error?.name;
|
|
1111
|
-
if (typeof name === "string" && name.length > 0)
|
|
1112
|
-
return name;
|
|
1113
|
-
return "opencode run reported an error event";
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
return null;
|
|
1117
|
-
}
|
|
1118
|
-
function parseRunToolCalls(stdout) {
|
|
1119
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1120
|
-
const out = [];
|
|
1121
|
-
for (const line2 of stdout.split("\n")) {
|
|
1122
|
-
const trimmed = line2.trim();
|
|
1123
|
-
if (!trimmed)
|
|
1124
|
-
continue;
|
|
1125
|
-
let evt;
|
|
1126
|
-
try {
|
|
1127
|
-
evt = JSON.parse(trimmed);
|
|
1128
|
-
} catch {
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
const e = evt;
|
|
1132
|
-
if (e.part && e.part.type === "tool" && typeof e.part.tool === "string") {
|
|
1133
|
-
if (!seen.has(e.part.tool)) {
|
|
1134
|
-
seen.add(e.part.tool);
|
|
1135
|
-
out.push(e.part.tool);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
return out;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
1003
|
// ../../packages/core/dist/provisioning/frameworks/opencode/inbound-bridge.js
|
|
1143
1004
|
var InboundError = class extends Error {
|
|
1144
|
-
/**
|
|
1005
|
+
/**
|
|
1006
|
+
* False ONLY when the turn provably never reached the agent (createSession
|
|
1007
|
+
* failed). A failure once the message is in flight is reported as `true`: the
|
|
1008
|
+
* turn probably ran, so retrying it would duplicate it.
|
|
1009
|
+
*/
|
|
1145
1010
|
admitted;
|
|
1146
1011
|
sessionID;
|
|
1147
1012
|
cause;
|
|
@@ -1171,24 +1036,64 @@ var OpencodeInboundBridge = class {
|
|
|
1171
1036
|
client;
|
|
1172
1037
|
gate;
|
|
1173
1038
|
sessionDefaults;
|
|
1174
|
-
delivery;
|
|
1175
1039
|
awaitReply;
|
|
1176
|
-
runTurn;
|
|
1177
1040
|
/** conversationKey → sessionID (one session per thread/DM). */
|
|
1178
1041
|
sessions = /* @__PURE__ */ new Map();
|
|
1179
1042
|
/** conversationKey → in-flight createSession, so concurrent inbound for the
|
|
1180
1043
|
* same conversation share one session instead of racing to create two. */
|
|
1181
1044
|
inFlight = /* @__PURE__ */ new Map();
|
|
1045
|
+
/**
|
|
1046
|
+
* conversationKey → tail of the turn chain for that conversation. Turns on one
|
|
1047
|
+
* conversation run STRICTLY ONE AT A TIME.
|
|
1048
|
+
*
|
|
1049
|
+
* This is load-bearing for correctness, not a politeness measure (ENG-9096).
|
|
1050
|
+
* opencode queues overlapping turns correctly - the transcript comes out in
|
|
1051
|
+
* order and nothing is lost - but every concurrent `POST /session/{id}/message`
|
|
1052
|
+
* returns the SAME assistant message: the newest one, not the caller's own.
|
|
1053
|
+
* Measured: two overlapping turns, and the POST that submitted the FIRST
|
|
1054
|
+
* message received the reply to the SECOND, while the first turn's reply was
|
|
1055
|
+
* returned to nobody. On a channel that means one person being handed the
|
|
1056
|
+
* answer to someone else's question in the same thread.
|
|
1057
|
+
*
|
|
1058
|
+
* The response gives no way to detect this after the fact: it carries
|
|
1059
|
+
* `info.parentID` (the user message it answers) but the caller is never told
|
|
1060
|
+
* its own user-message id, so there is nothing to compare against. Serialising
|
|
1061
|
+
* is therefore the fix, not a mitigation - the alternative is undetectable.
|
|
1062
|
+
*
|
|
1063
|
+
* `opencode run --attach` did not need this: each spawn streamed only its own
|
|
1064
|
+
* turn, so correlation came free. This is the one property the subprocess had
|
|
1065
|
+
* that the HTTP path does not.
|
|
1066
|
+
*/
|
|
1067
|
+
turnChains = /* @__PURE__ */ new Map();
|
|
1182
1068
|
constructor(opts) {
|
|
1183
1069
|
this.client = opts.client;
|
|
1184
1070
|
this.gate = opts.gate ?? (() => ({ admit: true }));
|
|
1185
1071
|
this.sessionDefaults = opts.sessionDefaults;
|
|
1186
|
-
this.delivery = opts.delivery ?? "queue";
|
|
1187
1072
|
this.awaitReply = opts.awaitReply ?? true;
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Run `fn` only once every previously-queued turn for `conversationKey` has
|
|
1076
|
+
* settled.
|
|
1077
|
+
*
|
|
1078
|
+
* `then(fn, fn)` — the SAME handler on both arms — is what keeps the chain
|
|
1079
|
+
* alive: a predecessor that rejected still lets the next turn run, so one
|
|
1080
|
+
* failed turn cannot strand every later message in that conversation. The
|
|
1081
|
+
* promise returned to the caller is that same one, so the caller still sees
|
|
1082
|
+
* the real failure.
|
|
1083
|
+
*
|
|
1084
|
+
* There was a second, redundant guard here (storing a tail wrapped to always
|
|
1085
|
+
* resolve). It was removed deliberately. With both present, sabotaging EITHER
|
|
1086
|
+
* one alone still passed every test, because the other silently covered it —
|
|
1087
|
+
* so neither was actually protected by anything. One mechanism, one test that
|
|
1088
|
+
* fails when it goes. Storing the rejecting promise raises no unhandled
|
|
1089
|
+
* rejection, because it is the same object the caller already handled; that
|
|
1090
|
+
* was measured, not assumed.
|
|
1091
|
+
*/
|
|
1092
|
+
serialize(conversationKey, fn) {
|
|
1093
|
+
const prior = this.turnChains.get(conversationKey) ?? Promise.resolve();
|
|
1094
|
+
const next = prior.then(fn, fn);
|
|
1095
|
+
this.turnChains.set(conversationKey, next);
|
|
1096
|
+
return next;
|
|
1192
1097
|
}
|
|
1193
1098
|
/** Resolve (creating on first use) the opencode session for a conversation. */
|
|
1194
1099
|
async ensureSession(conversationKey) {
|
|
@@ -1238,55 +1143,19 @@ var OpencodeInboundBridge = class {
|
|
|
1238
1143
|
cause: err
|
|
1239
1144
|
});
|
|
1240
1145
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
const framed = frameInboundPrompt(msg);
|
|
1244
|
-
const model = this.sessionDefaults?.model ?? null;
|
|
1245
|
-
if (!awaitReply) {
|
|
1246
|
-
void runner({ sessionID, text: framed, model }).catch((err) => {
|
|
1247
|
-
console.error(`[opencode-bridge] fire-and-forget run turn failed for session ${sessionID}:`, err instanceof Error ? err.name : typeof err);
|
|
1248
|
-
});
|
|
1249
|
-
return { status: "admitted", sessionID, admittedSeq: 0 };
|
|
1250
|
-
}
|
|
1251
|
-
try {
|
|
1252
|
-
const { admittedSeq: seq, reply } = await runner({ sessionID, text: framed, model });
|
|
1253
|
-
return { status: "replied", sessionID, admittedSeq: seq, reply };
|
|
1254
|
-
} catch (err) {
|
|
1255
|
-
const admitted = err instanceof OpencodeRunError ? err.admitted : false;
|
|
1256
|
-
throw new InboundError(admitted ? "opencode run turn failed after admission (not retried; avoids duplicate)" : "opencode run turn failed before admission (treated as retryable)", { admitted, sessionID, cause: err });
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
let admittedSeq;
|
|
1260
|
-
try {
|
|
1261
|
-
({ admittedSeq } = await this.client.prompt({
|
|
1262
|
-
sessionID,
|
|
1263
|
-
text: frameInboundPrompt(msg),
|
|
1264
|
-
delivery: this.delivery,
|
|
1265
|
-
// ENG-7931: the serve does not apply the config default model to
|
|
1266
|
-
// API-created sessions, so run each turn on the explicitly-resolved
|
|
1267
|
-
// model (same one used for session-create).
|
|
1268
|
-
model: this.sessionDefaults?.model
|
|
1269
|
-
}));
|
|
1270
|
-
} catch (err) {
|
|
1271
|
-
throw new InboundError("opencode prompt failed (admit ambiguous, treated as retryable)", {
|
|
1272
|
-
admitted: false,
|
|
1273
|
-
sessionID,
|
|
1274
|
-
cause: err
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1146
|
+
const framed = frameInboundPrompt(msg);
|
|
1147
|
+
const model = this.sessionDefaults?.model;
|
|
1277
1148
|
if (!awaitReply) {
|
|
1278
|
-
|
|
1149
|
+
void this.serialize(msg.conversationKey, () => this.client.sendMessage({ sessionID, text: framed, model })).catch((err) => {
|
|
1150
|
+
console.error(`[opencode-bridge] fire-and-forget turn failed for session ${sessionID}:`, err instanceof Error ? err.name : typeof err);
|
|
1151
|
+
});
|
|
1152
|
+
return { status: "admitted", sessionID };
|
|
1279
1153
|
}
|
|
1280
1154
|
try {
|
|
1281
|
-
await this.client.
|
|
1282
|
-
|
|
1283
|
-
return { status: "replied", sessionID, admittedSeq, reply };
|
|
1155
|
+
const { reply } = await this.serialize(msg.conversationKey, () => this.client.sendMessage({ sessionID, text: framed, model }));
|
|
1156
|
+
return { status: "replied", sessionID, reply };
|
|
1284
1157
|
} catch (err) {
|
|
1285
|
-
throw new InboundError("opencode
|
|
1286
|
-
admitted: true,
|
|
1287
|
-
sessionID,
|
|
1288
|
-
cause: err
|
|
1289
|
-
});
|
|
1158
|
+
throw new InboundError("opencode turn failed; the turn may have run to completion regardless, so it is not redelivered", { admitted: true, sessionID, cause: err });
|
|
1290
1159
|
}
|
|
1291
1160
|
}
|
|
1292
1161
|
};
|
|
@@ -2385,76 +2254,22 @@ function noteOpencodeTurnOutcome(codeName, outcome, startedOn) {
|
|
|
2385
2254
|
function getBridge(codeName, port, password) {
|
|
2386
2255
|
const cached = bridges.get(codeName);
|
|
2387
2256
|
if (cached && cached.port === port && cached.password === password) return cached.bridge;
|
|
2388
|
-
const client = new HttpOpencodeClient({
|
|
2257
|
+
const client = new HttpOpencodeClient({
|
|
2258
|
+
baseUrl: baseUrlFor(port),
|
|
2259
|
+
password,
|
|
2260
|
+
// A turn now runs inside one request, so the request timeout IS the turn
|
|
2261
|
+
// budget (see OPENCODE_RUN_TIMEOUT_MS). Leaving the client's 120s default
|
|
2262
|
+
// would quietly shorten it.
|
|
2263
|
+
requestTimeoutMs: OPENCODE_RUN_TIMEOUT_MS
|
|
2264
|
+
});
|
|
2389
2265
|
const model = sessions.get(codeName)?.model ?? null;
|
|
2390
|
-
const projectDir = sessions.get(codeName)?.projectDir ?? null;
|
|
2391
2266
|
const bridge = new OpencodeInboundBridge({
|
|
2392
2267
|
client,
|
|
2393
|
-
sessionDefaults: model ? { model } : void 0
|
|
2394
|
-
runTurn: projectDir ? makeRunTurn(codeName, port, password, projectDir) : void 0
|
|
2268
|
+
sessionDefaults: model ? { model } : void 0
|
|
2395
2269
|
});
|
|
2396
2270
|
bridges.set(codeName, { port, password, bridge });
|
|
2397
2271
|
return bridge;
|
|
2398
2272
|
}
|
|
2399
|
-
function makeRunTurn(codeName, port, password, projectDir) {
|
|
2400
|
-
return ({ sessionID, text, model }) => new Promise((resolve, reject) => {
|
|
2401
|
-
const args = buildOpencodeRunArgs({
|
|
2402
|
-
bin: OPENCODE_BIN,
|
|
2403
|
-
serveUrl: baseUrlFor(port),
|
|
2404
|
-
projectDir,
|
|
2405
|
-
password,
|
|
2406
|
-
sessionID,
|
|
2407
|
-
text,
|
|
2408
|
-
model: model ?? null
|
|
2409
|
-
});
|
|
2410
|
-
const child = spawn(OPENCODE_BIN, args, {
|
|
2411
|
-
cwd: projectDir,
|
|
2412
|
-
// Password off argv (would show in `ps`); it rides the env instead.
|
|
2413
|
-
env: { ...process.env, OPENCODE_SERVER_PASSWORD: password },
|
|
2414
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2415
|
-
});
|
|
2416
|
-
let stdout = "";
|
|
2417
|
-
let stderr = "";
|
|
2418
|
-
let settled = false;
|
|
2419
|
-
const finish = (fn) => {
|
|
2420
|
-
if (settled) return;
|
|
2421
|
-
settled = true;
|
|
2422
|
-
clearTimeout(timer);
|
|
2423
|
-
fn();
|
|
2424
|
-
};
|
|
2425
|
-
const fail = (message, cause) => reject(new OpencodeRunError(message, runCrossedAdmission(stdout), { cause }));
|
|
2426
|
-
const timer = setTimeout(() => {
|
|
2427
|
-
finish(() => {
|
|
2428
|
-
try {
|
|
2429
|
-
child.kill("SIGKILL");
|
|
2430
|
-
} catch {
|
|
2431
|
-
}
|
|
2432
|
-
fail(`opencode run timed out after ${OPENCODE_RUN_TIMEOUT_MS}ms`);
|
|
2433
|
-
});
|
|
2434
|
-
}, OPENCODE_RUN_TIMEOUT_MS);
|
|
2435
|
-
child.stdout.on("data", (d) => {
|
|
2436
|
-
stdout += d.toString();
|
|
2437
|
-
});
|
|
2438
|
-
child.stderr.on("data", (d) => {
|
|
2439
|
-
stderr += d.toString();
|
|
2440
|
-
});
|
|
2441
|
-
child.on("error", (err) => finish(() => fail(`opencode run spawn failed: ${err instanceof Error ? err.message : err}`, err)));
|
|
2442
|
-
child.on("close", (code) => finish(() => {
|
|
2443
|
-
const runError = parseOpencodeRunError(stdout);
|
|
2444
|
-
if (code !== 0 || runError) {
|
|
2445
|
-
const tail = runError ?? (stderr.trim() || stdout.trim()).slice(-500);
|
|
2446
|
-
fail(`opencode run failed (exit ${code ?? "null"}): ${tail}`);
|
|
2447
|
-
return;
|
|
2448
|
-
}
|
|
2449
|
-
const reply = parseOpencodeRunReply(stdout);
|
|
2450
|
-
const tools = parseRunToolCalls(stdout);
|
|
2451
|
-
if (tools.length > 0) {
|
|
2452
|
-
console.error(`[opencode-run] ${codeName} tools: ${tools.join(", ")}`);
|
|
2453
|
-
}
|
|
2454
|
-
resolve({ admittedSeq: 0, reply });
|
|
2455
|
-
}));
|
|
2456
|
-
});
|
|
2457
|
-
}
|
|
2458
2273
|
function stopOpencodeSession(codeName, log2) {
|
|
2459
2274
|
const tmuxSession = opencodeTmuxSession(codeName);
|
|
2460
2275
|
try {
|
|
@@ -4352,4 +4167,4 @@ export {
|
|
|
4352
4167
|
stopAllSessionsAndWait,
|
|
4353
4168
|
getProjectDir
|
|
4354
4169
|
};
|
|
4355
|
-
//# sourceMappingURL=chunk-
|
|
4170
|
+
//# sourceMappingURL=chunk-UIB2SMFE.js.map
|