@cabane/companion 0.6.46 → 0.6.48
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/cli.js +58 -18
- package/dist/runtime.js +47 -13
- package/dist/static/app.js +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -149,6 +149,7 @@ var runPrepareHook = (hook, input) => {
|
|
|
149
149
|
CABANE_AGENT_ID: input.agentId,
|
|
150
150
|
CABANE_AGENT_USERNAME: input.agentUsername,
|
|
151
151
|
CABANE_RUNTIME: input.runtime ?? "",
|
|
152
|
+
CABANE_HOST_ACCESS: input.hostAccess ? "1" : "0",
|
|
152
153
|
// CT319: the conversation anchor is gone. These are kept as DEPRECATED
|
|
153
154
|
// back-compat constants so an old user prepare script that still reads
|
|
154
155
|
// them doesn't crash; a hook should key off CABANE_TRIGGER_ENTRY_PATHS.
|
|
@@ -823,6 +824,7 @@ var HARNESS_LABELS = {
|
|
|
823
824
|
};
|
|
824
825
|
var LABELS = HARNESS_LABELS;
|
|
825
826
|
var OFFER_ORDER = ["claude-code", "codex", "opencode"];
|
|
827
|
+
var DEFAULT_OPENCODE_SERVER_URL = "http://127.0.0.1:4096";
|
|
826
828
|
function parseHarnessRuntime(raw) {
|
|
827
829
|
const key = raw.trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
828
830
|
if (key === "claude-code" || key === "claudecode" || key === "claude") return "claude-code";
|
|
@@ -941,6 +943,15 @@ function deriveOpencode(signals, manifestHas) {
|
|
|
941
943
|
enable: null
|
|
942
944
|
};
|
|
943
945
|
}
|
|
946
|
+
if (signals.opencodeReachable && signals.opencodeDetectedUrl) {
|
|
947
|
+
return {
|
|
948
|
+
...base,
|
|
949
|
+
state: "detected_not_exposed",
|
|
950
|
+
version: signals.opencodeVersion,
|
|
951
|
+
detail: signals.opencodeDetectedUrl,
|
|
952
|
+
enable: "opencode"
|
|
953
|
+
};
|
|
954
|
+
}
|
|
944
955
|
return {
|
|
945
956
|
...base,
|
|
946
957
|
state: "not_detected",
|
|
@@ -950,17 +961,32 @@ function deriveOpencode(signals, manifestHas) {
|
|
|
950
961
|
};
|
|
951
962
|
}
|
|
952
963
|
var PROBE_TIMEOUT_MS = 4e3;
|
|
964
|
+
var DEFAULT_OPENCODE_PROBE_TIMEOUT_MS = 1e3;
|
|
965
|
+
function probeDefaultOpencodeVersion(probeOpencode = (url) => probeOpencodeVersion(url)) {
|
|
966
|
+
return withTimeout(
|
|
967
|
+
probeOpencode(DEFAULT_OPENCODE_SERVER_URL),
|
|
968
|
+
null,
|
|
969
|
+
DEFAULT_OPENCODE_PROBE_TIMEOUT_MS
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
async function resolveOpencodeServerUrl(configuredServerUrl, requestedServerUrl, probeDefault = probeDefaultOpencodeVersion) {
|
|
973
|
+
const requested = requestedServerUrl?.trim();
|
|
974
|
+
if (requested) return requested;
|
|
975
|
+
if (configuredServerUrl) return configuredServerUrl;
|
|
976
|
+
return await probeDefault() !== null ? DEFAULT_OPENCODE_SERVER_URL : null;
|
|
977
|
+
}
|
|
953
978
|
async function probeHarnessSignals(cfg, deps = {}) {
|
|
954
979
|
const probeClaudePresence = deps.probeClaudePresence ?? claudeOnPath;
|
|
955
980
|
const probeClaudeVersion = deps.probeClaudeVersion ?? (() => probeCliVersion("claude"));
|
|
956
981
|
const probeCodexVersion = deps.probeCodexVersion ?? (() => probeCliVersion("codex"));
|
|
957
982
|
const probeOpencode = deps.probeOpencode ?? ((url) => probeOpencodeVersion(url));
|
|
958
|
-
const
|
|
983
|
+
const configuredServerUrl = cfg.opencode?.serverUrl;
|
|
984
|
+
const opencodeProbeUrl = configuredServerUrl ?? DEFAULT_OPENCODE_SERVER_URL;
|
|
959
985
|
const [claudeOnPathResult, claudeVersion, codexVersion, opencodeVersion] = await Promise.all([
|
|
960
986
|
withTimeout(probeClaudePresence(), false),
|
|
961
987
|
withTimeout(probeClaudeVersion(), null),
|
|
962
988
|
withTimeout(probeCodexVersion(), null),
|
|
963
|
-
|
|
989
|
+
configuredServerUrl ? withTimeout(probeOpencode(opencodeProbeUrl), null) : probeDefaultOpencodeVersion(probeOpencode)
|
|
964
990
|
]);
|
|
965
991
|
return {
|
|
966
992
|
claudeOnPath: claudeOnPathResult,
|
|
@@ -973,13 +999,14 @@ async function probeHarnessSignals(cfg, deps = {}) {
|
|
|
973
999
|
codexOnPath: codexVersion !== null,
|
|
974
1000
|
codexVersion,
|
|
975
1001
|
codexEnabled: isCodexEnabled(cfg),
|
|
976
|
-
opencodeConfigured: !!
|
|
1002
|
+
opencodeConfigured: !!configuredServerUrl,
|
|
977
1003
|
// A version came back ⟺ the serve answered its health endpoint (CT584).
|
|
978
1004
|
opencodeReachable: opencodeVersion !== null,
|
|
979
|
-
opencodeVersion
|
|
1005
|
+
opencodeVersion,
|
|
1006
|
+
opencodeDetectedUrl: opencodeVersion !== null ? opencodeProbeUrl : null
|
|
980
1007
|
};
|
|
981
1008
|
}
|
|
982
|
-
function withTimeout(promise, fallback) {
|
|
1009
|
+
function withTimeout(promise, fallback, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
983
1010
|
return new Promise((resolve) => {
|
|
984
1011
|
let settled = false;
|
|
985
1012
|
const done = (v) => {
|
|
@@ -988,7 +1015,7 @@ function withTimeout(promise, fallback) {
|
|
|
988
1015
|
resolve(v);
|
|
989
1016
|
}
|
|
990
1017
|
};
|
|
991
|
-
const timer = setTimeout(() => done(fallback),
|
|
1018
|
+
const timer = setTimeout(() => done(fallback), timeoutMs);
|
|
992
1019
|
timer.unref?.();
|
|
993
1020
|
promise.then(
|
|
994
1021
|
(v) => {
|
|
@@ -1316,13 +1343,14 @@ async function connect2(raw, opts = {}) {
|
|
|
1316
1343
|
if (runtime === "claude-code") next = { ...cfg, claudeCode: { enabled: true } };
|
|
1317
1344
|
else if (runtime === "codex") next = { ...cfg, codex: { enabled: true } };
|
|
1318
1345
|
else {
|
|
1319
|
-
const
|
|
1346
|
+
const requestedServerUrl = opts.serverUrl?.trim();
|
|
1347
|
+
const serverUrl = await resolveOpencodeServerUrl(void 0, requestedServerUrl);
|
|
1320
1348
|
if (!serverUrl) {
|
|
1321
1349
|
throw new CompanionError(
|
|
1322
1350
|
"opencode is addressed by URL \u2014 pass it: `cabane-companion connect opencode --url http://127.0.0.1:4096`."
|
|
1323
1351
|
);
|
|
1324
1352
|
}
|
|
1325
|
-
if (await probeOpencodeVersion(serverUrl) === null) {
|
|
1353
|
+
if (requestedServerUrl && await probeOpencodeVersion(serverUrl) === null) {
|
|
1326
1354
|
throw new CompanionError(
|
|
1327
1355
|
`Couldn\u2019t reach an opencode server at ${serverUrl}. Start \`opencode serve\` and check the URL.`
|
|
1328
1356
|
);
|
|
@@ -5750,7 +5778,8 @@ var ENV_ENVELOPE_KEYS = [
|
|
|
5750
5778
|
"CABANE_PLAYGROUND_BIN",
|
|
5751
5779
|
"CABANE_CONVERSATION_ID",
|
|
5752
5780
|
"CABANE_AGENT_ID",
|
|
5753
|
-
"CABANE_CONVERSATION_TITLE"
|
|
5781
|
+
"CABANE_CONVERSATION_TITLE",
|
|
5782
|
+
"CABANE_HOST_ACCESS"
|
|
5754
5783
|
];
|
|
5755
5784
|
function buildRunSpec2(req, resumeThreadId, instructionsFile = null, threadPromptFingerprint = null) {
|
|
5756
5785
|
const { policy, config } = req;
|
|
@@ -7834,6 +7863,7 @@ var Dispatcher = class {
|
|
|
7834
7863
|
agentId: payload.agentId,
|
|
7835
7864
|
agentUsername: this.opts.agentUsername,
|
|
7836
7865
|
runtime: turnContext.runtime,
|
|
7866
|
+
hostAccess: turnContext.policy.hostFs,
|
|
7837
7867
|
triggerEntryPaths: turnContext.conversation.triggerEntryPaths ?? [],
|
|
7838
7868
|
title: turnContext.conversation.title,
|
|
7839
7869
|
messageBody: message.body,
|
|
@@ -7895,6 +7925,7 @@ ${reason}`,
|
|
|
7895
7925
|
agentId: payload.agentId,
|
|
7896
7926
|
agentUsername: this.opts.agentUsername,
|
|
7897
7927
|
runtime: turnContext.runtime,
|
|
7928
|
+
hostAccess: turnContext.policy.hostFs,
|
|
7898
7929
|
// CT317/CT319: the trigger message's referenced-entry paths — what the
|
|
7899
7930
|
// tasker prepare hook keys its per-task env off. Defaults to `[]` for
|
|
7900
7931
|
// an older API. The conversation anchor is gone (CT319).
|
|
@@ -7938,7 +7969,10 @@ ${reason}`,
|
|
|
7938
7969
|
}
|
|
7939
7970
|
}
|
|
7940
7971
|
}
|
|
7941
|
-
const turnEnv =
|
|
7972
|
+
const turnEnv = {
|
|
7973
|
+
...hookEnv,
|
|
7974
|
+
CABANE_HOST_ACCESS: turnContext.policy.hostFs ? "1" : "0"
|
|
7975
|
+
};
|
|
7942
7976
|
const key = runKey(payload.conversationId, payload.agentId);
|
|
7943
7977
|
const abortController = new AbortController();
|
|
7944
7978
|
this.aborts.set(key, abortController);
|
|
@@ -8001,9 +8035,8 @@ ${reason}`,
|
|
|
8001
8035
|
...turnContext.turnToken ? { turnToken: turnContext.turnToken } : {},
|
|
8002
8036
|
// SJ524: the hook-resolved cwd overrides the static local cwd.
|
|
8003
8037
|
...effectiveCwd ? { cwd: effectiveCwd } : {},
|
|
8004
|
-
//
|
|
8005
|
-
|
|
8006
|
-
...turnEnv ? { env: turnEnv } : {},
|
|
8038
|
+
// CT1103: the prepare-hook env plus the authoritative host-access token.
|
|
8039
|
+
env: turnEnv,
|
|
8007
8040
|
mcpServers: resolvedMcpServers,
|
|
8008
8041
|
summonServer,
|
|
8009
8042
|
// CT238: this turn's conversation, forwarded as the active-conversation
|
|
@@ -10056,11 +10089,13 @@ async function createCompanionRuntime(opts = {}) {
|
|
|
10056
10089
|
});
|
|
10057
10090
|
await supervisor.start();
|
|
10058
10091
|
const connectHarness = async (runtime, serverUrl) => {
|
|
10059
|
-
const
|
|
10092
|
+
const currentConfig = supervisor.currentConfig();
|
|
10093
|
+
const resolvedServerUrl = runtime === "opencode" ? await resolveOpencodeServerUrl(currentConfig.opencode?.serverUrl, serverUrl) : null;
|
|
10094
|
+
const candidate = runtime === "opencode" ? { ...currentConfig, opencode: { serverUrl: resolvedServerUrl ?? "" } } : currentConfig;
|
|
10060
10095
|
const verdict = await shakeOutHarness(runtime, candidate);
|
|
10061
10096
|
if (verdict === "absent") return { ok: false, error: absentLine(runtime) };
|
|
10062
10097
|
const result = await supervisor.enableHarness(
|
|
10063
|
-
runtime === "opencode" ? { runtime: "opencode", serverUrl:
|
|
10098
|
+
runtime === "opencode" ? { runtime: "opencode", serverUrl: resolvedServerUrl ?? "" } : { runtime }
|
|
10064
10099
|
);
|
|
10065
10100
|
if (!result.ok) return { ok: false, error: result.error };
|
|
10066
10101
|
return { ok: true, message: connectedLine(runtime, verdict) };
|
|
@@ -10330,17 +10365,22 @@ function reportAlreadyRunning(pid) {
|
|
|
10330
10365
|
write("Connect a harness to the running companion: cabane-companion connect claude-code");
|
|
10331
10366
|
}
|
|
10332
10367
|
async function collectHarnessChoices(interactive) {
|
|
10333
|
-
const opencodeUrl = "http://127.0.0.1:4096";
|
|
10334
10368
|
const [claudePresent, claudeVersion, codexVersion, opencodeVersion] = await Promise.all([
|
|
10335
10369
|
claudeOnPath().catch(() => false),
|
|
10336
10370
|
probeCliVersion("claude").catch(() => null),
|
|
10337
10371
|
probeCliVersion("codex").catch(() => null),
|
|
10338
|
-
|
|
10372
|
+
probeDefaultOpencodeVersion()
|
|
10339
10373
|
]);
|
|
10340
10374
|
const found = [
|
|
10341
10375
|
...claudePresent ? [{ runtime: "claude-code", version: claudeVersion }] : [],
|
|
10342
10376
|
...codexVersion ? [{ runtime: "codex", version: codexVersion }] : [],
|
|
10343
|
-
...opencodeVersion ? [
|
|
10377
|
+
...opencodeVersion ? [
|
|
10378
|
+
{
|
|
10379
|
+
runtime: "opencode",
|
|
10380
|
+
version: opencodeVersion,
|
|
10381
|
+
serverUrl: DEFAULT_OPENCODE_SERVER_URL
|
|
10382
|
+
}
|
|
10383
|
+
] : []
|
|
10344
10384
|
].sort((a, b) => OFFER_ORDER.indexOf(a.runtime) - OFFER_ORDER.indexOf(b.runtime));
|
|
10345
10385
|
if (found.length === 0) {
|
|
10346
10386
|
write(
|
package/dist/runtime.js
CHANGED
|
@@ -141,6 +141,7 @@ var runPrepareHook = (hook, input) => {
|
|
|
141
141
|
CABANE_AGENT_ID: input.agentId,
|
|
142
142
|
CABANE_AGENT_USERNAME: input.agentUsername,
|
|
143
143
|
CABANE_RUNTIME: input.runtime ?? "",
|
|
144
|
+
CABANE_HOST_ACCESS: input.hostAccess ? "1" : "0",
|
|
144
145
|
// CT319: the conversation anchor is gone. These are kept as DEPRECATED
|
|
145
146
|
// back-compat constants so an old user prepare script that still reads
|
|
146
147
|
// them doesn't crash; a hook should key off CABANE_TRIGGER_ENTRY_PATHS.
|
|
@@ -1300,6 +1301,7 @@ var HARNESS_LABELS = {
|
|
|
1300
1301
|
opencode: "OpenCode"
|
|
1301
1302
|
};
|
|
1302
1303
|
var LABELS = HARNESS_LABELS;
|
|
1304
|
+
var DEFAULT_OPENCODE_SERVER_URL = "http://127.0.0.1:4096";
|
|
1303
1305
|
function deriveHarnessSnapshot(signals) {
|
|
1304
1306
|
const advertised = new Set(
|
|
1305
1307
|
buildCompanionManifest({
|
|
@@ -1411,6 +1413,15 @@ function deriveOpencode(signals, manifestHas) {
|
|
|
1411
1413
|
enable: null
|
|
1412
1414
|
};
|
|
1413
1415
|
}
|
|
1416
|
+
if (signals.opencodeReachable && signals.opencodeDetectedUrl) {
|
|
1417
|
+
return {
|
|
1418
|
+
...base,
|
|
1419
|
+
state: "detected_not_exposed",
|
|
1420
|
+
version: signals.opencodeVersion,
|
|
1421
|
+
detail: signals.opencodeDetectedUrl,
|
|
1422
|
+
enable: "opencode"
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1414
1425
|
return {
|
|
1415
1426
|
...base,
|
|
1416
1427
|
state: "not_detected",
|
|
@@ -1420,17 +1431,32 @@ function deriveOpencode(signals, manifestHas) {
|
|
|
1420
1431
|
};
|
|
1421
1432
|
}
|
|
1422
1433
|
var PROBE_TIMEOUT_MS = 4e3;
|
|
1434
|
+
var DEFAULT_OPENCODE_PROBE_TIMEOUT_MS = 1e3;
|
|
1435
|
+
function probeDefaultOpencodeVersion(probeOpencode = (url) => probeOpencodeVersion(url)) {
|
|
1436
|
+
return withTimeout(
|
|
1437
|
+
probeOpencode(DEFAULT_OPENCODE_SERVER_URL),
|
|
1438
|
+
null,
|
|
1439
|
+
DEFAULT_OPENCODE_PROBE_TIMEOUT_MS
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
async function resolveOpencodeServerUrl(configuredServerUrl, requestedServerUrl, probeDefault = probeDefaultOpencodeVersion) {
|
|
1443
|
+
const requested = requestedServerUrl?.trim();
|
|
1444
|
+
if (requested) return requested;
|
|
1445
|
+
if (configuredServerUrl) return configuredServerUrl;
|
|
1446
|
+
return await probeDefault() !== null ? DEFAULT_OPENCODE_SERVER_URL : null;
|
|
1447
|
+
}
|
|
1423
1448
|
async function probeHarnessSignals(cfg, deps = {}) {
|
|
1424
1449
|
const probeClaudePresence = deps.probeClaudePresence ?? claudeOnPath;
|
|
1425
1450
|
const probeClaudeVersion = deps.probeClaudeVersion ?? (() => probeCliVersion("claude"));
|
|
1426
1451
|
const probeCodexVersion = deps.probeCodexVersion ?? (() => probeCliVersion("codex"));
|
|
1427
1452
|
const probeOpencode = deps.probeOpencode ?? ((url) => probeOpencodeVersion(url));
|
|
1428
|
-
const
|
|
1453
|
+
const configuredServerUrl = cfg.opencode?.serverUrl;
|
|
1454
|
+
const opencodeProbeUrl = configuredServerUrl ?? DEFAULT_OPENCODE_SERVER_URL;
|
|
1429
1455
|
const [claudeOnPathResult, claudeVersion, codexVersion, opencodeVersion] = await Promise.all([
|
|
1430
1456
|
withTimeout(probeClaudePresence(), false),
|
|
1431
1457
|
withTimeout(probeClaudeVersion(), null),
|
|
1432
1458
|
withTimeout(probeCodexVersion(), null),
|
|
1433
|
-
|
|
1459
|
+
configuredServerUrl ? withTimeout(probeOpencode(opencodeProbeUrl), null) : probeDefaultOpencodeVersion(probeOpencode)
|
|
1434
1460
|
]);
|
|
1435
1461
|
return {
|
|
1436
1462
|
claudeOnPath: claudeOnPathResult,
|
|
@@ -1443,13 +1469,14 @@ async function probeHarnessSignals(cfg, deps = {}) {
|
|
|
1443
1469
|
codexOnPath: codexVersion !== null,
|
|
1444
1470
|
codexVersion,
|
|
1445
1471
|
codexEnabled: isCodexEnabled(cfg),
|
|
1446
|
-
opencodeConfigured: !!
|
|
1472
|
+
opencodeConfigured: !!configuredServerUrl,
|
|
1447
1473
|
// A version came back ⟺ the serve answered its health endpoint (CT584).
|
|
1448
1474
|
opencodeReachable: opencodeVersion !== null,
|
|
1449
|
-
opencodeVersion
|
|
1475
|
+
opencodeVersion,
|
|
1476
|
+
opencodeDetectedUrl: opencodeVersion !== null ? opencodeProbeUrl : null
|
|
1450
1477
|
};
|
|
1451
1478
|
}
|
|
1452
|
-
function withTimeout(promise, fallback) {
|
|
1479
|
+
function withTimeout(promise, fallback, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
1453
1480
|
return new Promise((resolve) => {
|
|
1454
1481
|
let settled = false;
|
|
1455
1482
|
const done = (v) => {
|
|
@@ -1458,7 +1485,7 @@ function withTimeout(promise, fallback) {
|
|
|
1458
1485
|
resolve(v);
|
|
1459
1486
|
}
|
|
1460
1487
|
};
|
|
1461
|
-
const timer = setTimeout(() => done(fallback),
|
|
1488
|
+
const timer = setTimeout(() => done(fallback), timeoutMs);
|
|
1462
1489
|
timer.unref?.();
|
|
1463
1490
|
promise.then(
|
|
1464
1491
|
(v) => {
|
|
@@ -5259,7 +5286,8 @@ var ENV_ENVELOPE_KEYS = [
|
|
|
5259
5286
|
"CABANE_PLAYGROUND_BIN",
|
|
5260
5287
|
"CABANE_CONVERSATION_ID",
|
|
5261
5288
|
"CABANE_AGENT_ID",
|
|
5262
|
-
"CABANE_CONVERSATION_TITLE"
|
|
5289
|
+
"CABANE_CONVERSATION_TITLE",
|
|
5290
|
+
"CABANE_HOST_ACCESS"
|
|
5263
5291
|
];
|
|
5264
5292
|
function buildRunSpec2(req, resumeThreadId, instructionsFile = null, threadPromptFingerprint = null) {
|
|
5265
5293
|
const { policy, config } = req;
|
|
@@ -7343,6 +7371,7 @@ var Dispatcher = class {
|
|
|
7343
7371
|
agentId: payload.agentId,
|
|
7344
7372
|
agentUsername: this.opts.agentUsername,
|
|
7345
7373
|
runtime: turnContext.runtime,
|
|
7374
|
+
hostAccess: turnContext.policy.hostFs,
|
|
7346
7375
|
triggerEntryPaths: turnContext.conversation.triggerEntryPaths ?? [],
|
|
7347
7376
|
title: turnContext.conversation.title,
|
|
7348
7377
|
messageBody: message.body,
|
|
@@ -7404,6 +7433,7 @@ ${reason}`,
|
|
|
7404
7433
|
agentId: payload.agentId,
|
|
7405
7434
|
agentUsername: this.opts.agentUsername,
|
|
7406
7435
|
runtime: turnContext.runtime,
|
|
7436
|
+
hostAccess: turnContext.policy.hostFs,
|
|
7407
7437
|
// CT317/CT319: the trigger message's referenced-entry paths — what the
|
|
7408
7438
|
// tasker prepare hook keys its per-task env off. Defaults to `[]` for
|
|
7409
7439
|
// an older API. The conversation anchor is gone (CT319).
|
|
@@ -7447,7 +7477,10 @@ ${reason}`,
|
|
|
7447
7477
|
}
|
|
7448
7478
|
}
|
|
7449
7479
|
}
|
|
7450
|
-
const turnEnv =
|
|
7480
|
+
const turnEnv = {
|
|
7481
|
+
...hookEnv,
|
|
7482
|
+
CABANE_HOST_ACCESS: turnContext.policy.hostFs ? "1" : "0"
|
|
7483
|
+
};
|
|
7451
7484
|
const key = runKey(payload.conversationId, payload.agentId);
|
|
7452
7485
|
const abortController = new AbortController();
|
|
7453
7486
|
this.aborts.set(key, abortController);
|
|
@@ -7510,9 +7543,8 @@ ${reason}`,
|
|
|
7510
7543
|
...turnContext.turnToken ? { turnToken: turnContext.turnToken } : {},
|
|
7511
7544
|
// SJ524: the hook-resolved cwd overrides the static local cwd.
|
|
7512
7545
|
...effectiveCwd ? { cwd: effectiveCwd } : {},
|
|
7513
|
-
//
|
|
7514
|
-
|
|
7515
|
-
...turnEnv ? { env: turnEnv } : {},
|
|
7546
|
+
// CT1103: the prepare-hook env plus the authoritative host-access token.
|
|
7547
|
+
env: turnEnv,
|
|
7516
7548
|
mcpServers: resolvedMcpServers,
|
|
7517
7549
|
summonServer,
|
|
7518
7550
|
// CT238: this turn's conversation, forwarded as the active-conversation
|
|
@@ -9565,11 +9597,13 @@ async function createCompanionRuntime(opts = {}) {
|
|
|
9565
9597
|
});
|
|
9566
9598
|
await supervisor.start();
|
|
9567
9599
|
const connectHarness = async (runtime, serverUrl) => {
|
|
9568
|
-
const
|
|
9600
|
+
const currentConfig = supervisor.currentConfig();
|
|
9601
|
+
const resolvedServerUrl = runtime === "opencode" ? await resolveOpencodeServerUrl(currentConfig.opencode?.serverUrl, serverUrl) : null;
|
|
9602
|
+
const candidate = runtime === "opencode" ? { ...currentConfig, opencode: { serverUrl: resolvedServerUrl ?? "" } } : currentConfig;
|
|
9569
9603
|
const verdict = await shakeOutHarness(runtime, candidate);
|
|
9570
9604
|
if (verdict === "absent") return { ok: false, error: absentLine(runtime) };
|
|
9571
9605
|
const result = await supervisor.enableHarness(
|
|
9572
|
-
runtime === "opencode" ? { runtime: "opencode", serverUrl:
|
|
9606
|
+
runtime === "opencode" ? { runtime: "opencode", serverUrl: resolvedServerUrl ?? "" } : { runtime }
|
|
9573
9607
|
);
|
|
9574
9608
|
if (!result.ok) return { ok: false, error: result.error };
|
|
9575
9609
|
return { ok: true, message: connectedLine(runtime, verdict) };
|
package/dist/static/app.js
CHANGED
|
@@ -158,6 +158,7 @@ function renderHarnesses() {
|
|
|
158
158
|
const input = el('input');
|
|
159
159
|
input.type = 'text';
|
|
160
160
|
input.placeholder = 'opencode serve URL (e.g. http://127.0.0.1:4096)';
|
|
161
|
+
if (h.state === 'detected_not_exposed') input.value = h.detail;
|
|
161
162
|
const btn = el('button', 'primary small', 'Add opencode');
|
|
162
163
|
const submit = () => {
|
|
163
164
|
const url = input.value.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.48",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect a coding agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
|
|
6
6
|
"license": "UNLICENSED",
|