@openchambery/web 1.19.20 → 2.0.0-beta.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 +13 -11
- package/bin/cli-opencode.test.js +208 -0
- package/bin/cli.js +62 -9
- package/bin/lib/cli-startup.js +105 -2
- package/bin/lib/cli-startup.test.js +165 -0
- package/dist/assets/{AgentAvatar-NT957MuI.js → AgentAvatar-CLWWNu_Q.js} +1 -1
- package/dist/assets/AssistantView-BTCkm8yk.js +3 -0
- package/dist/assets/{DiagramView-C_JfbxNl.js → DiagramView-xuSJTnv7.js} +1 -1
- package/dist/assets/{FadeInOnReveal-CilRl4gc.js → FadeInOnReveal-Ov0D96d0.js} +1 -1
- package/dist/assets/{Icon-i5GiQRLq.js → Icon-DD-BuMfZ.js} +1 -1
- package/dist/assets/MarkdownRenderer-bc_p1H7l.js +2 -0
- package/dist/assets/{MarkdownRendererImpl-B1iUwzOz.js → MarkdownRendererImpl-SKi4oG0c.js} +1 -1
- package/dist/assets/{MarkstreamRendererImpl-BPtMj3-X.js → MarkstreamRendererImpl-CnkodGJW.js} +1 -1
- package/dist/assets/MobileDetailNavigation-Bnx59U_J.js +1 -0
- package/dist/assets/{MobileShareBridge-CKClHsWN.js → MobileShareBridge-BQlP4J-F.js} +1 -1
- package/dist/assets/MobileSurface-BXLeiZ4d.js +2 -0
- package/dist/assets/{MultiRunWindow-DiA24bnN.js → MultiRunWindow-ChZGob0v.js} +1 -1
- package/dist/assets/{OnboardingScreen-BGRLk4Wi.js → OnboardingScreen-DtQJxZG-.js} +1 -1
- package/dist/assets/{OverlayScrollbar-NuQI58XD.js → OverlayScrollbar-pMwxaCca.js} +1 -1
- package/dist/assets/SettingsView-B5I0KDTZ.js +25 -0
- package/dist/assets/{SettingsWindow-XlzRSS7E.js → SettingsWindow-DfnsFa8y.js} +1 -1
- package/dist/assets/{TerminalView-DdIaaLba.js → TerminalView-Dh9MWCpS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-BbwuLdXU.js → ToolOutputDialog-BejmjrRk.js} +1 -1
- package/dist/assets/{appThemeRegistry-ChzfD7mc.js → appThemeRegistry-COGfxTFV.js} +1 -1
- package/dist/assets/{button-DtzFDvij.js → button-D-rATN7w.js} +1 -1
- package/dist/assets/{collapsible-D-nzhcyF.js → collapsible-BXRd5_Hr.js} +1 -1
- package/dist/assets/{context-menu-BzVSzHLG.js → context-menu-jGtH6fR9.js} +1 -1
- package/dist/assets/{diagram-2YWalSb5.js → diagram-DQf7Y_uR.js} +1 -1
- package/dist/assets/{dialog-DGV7DsZC.js → dialog-bfbvR4VH.js} +1 -1
- package/dist/assets/es-c52LTHHe.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-DyjmxUEN.js → fileMentionTouchSelection-BvrNCroG.js} +1 -1
- package/dist/assets/{fr-DsBZeN8Y.js → fr-PisFbUE8.js} +3 -3
- package/dist/assets/gitApi-ButwzQ0N.js +9 -0
- package/dist/assets/{input-CbB2HdLg.js → input-8r6F_Fza.js} +1 -1
- package/dist/assets/insertionBoundaries-DGs7S5zv.js +1 -0
- package/dist/assets/ja-C8Ikun3Z.js +15 -0
- package/dist/assets/ko-ClFys5o2.js +15 -0
- package/dist/assets/main-CCE_4y5F.js +2 -0
- package/dist/assets/main-Dn9rpsgl.js +169 -0
- package/dist/assets/{markdownHeightCache-C9ym9Tsb.js → markdownHeightCache-1Qo6y6IJ.js} +1 -1
- package/dist/assets/miniChat-BpjxVqgg.js +2 -0
- package/dist/assets/mobile-nMJCaNq1.js +2 -0
- package/dist/assets/{multirun-8fkF0Ji_.js → multirun-BvSG94mW.js} +1 -1
- package/dist/assets/pl-CnaKWN5F.js +15 -0
- package/dist/assets/platform-CWTIp02q.js +4 -0
- package/dist/assets/{projectMeta--y6tyjrv.js → projectMeta-DOe49dM_.js} +2 -2
- package/dist/assets/pt-BR-s8OpfRI6.js +15 -0
- package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +2 -0
- package/dist/assets/renderMobileApp-y-S8y8v_.js +28 -0
- package/dist/assets/{runtimeConfig-DYWtBrkW.js → runtimeConfig-BMvqa5we.js} +1 -1
- package/dist/assets/{runtimeEndpointReset-BSWg99jc.js → runtimeEndpointReset-B6BxhvR0.js} +5 -5
- package/dist/assets/{sessionChangeSummary-BwupJF-Q.js → sessionChangeSummary-VVBlEXuh.js} +1 -1
- package/dist/assets/{sessionLookup-DP2X1qRR.js → sessionLookup-gh-hVRIc.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CfgEJfB0.js → sortable-tabs-strip-CudoSgV4.js} +1 -1
- package/dist/assets/{src-DZ60kHBP.css → src-BzX5UI-c.css} +1 -1
- package/dist/assets/{store-B6dImdlY.js → store-DJczmczv.js} +4 -4
- package/dist/assets/{terminalApi-xjqssKke.js → terminalApi-DiF6JmBP.js} +1 -1
- package/dist/assets/{textarea-BnD799LW.js → textarea-3XR8sUfy.js} +1 -1
- package/dist/assets/{tooltip-Djn7MSOX.js → tooltip-CQvpK-UV.js} +1 -1
- package/dist/assets/uk-CaX0iqkB.js +15 -0
- package/dist/assets/{useAppFontEffects-DWLxpWlS.js → useAppFontEffects-Cpmpo7Wb.js} +45 -45
- package/dist/assets/{useDesktopWindowControlsLayout-BGPR_rq6.js → useDesktopWindowControlsLayout-B1GX59-L.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-CbV9_r1s.js → useEffectiveDirectory-CN6JoCFw.js} +1 -1
- package/dist/assets/{useFontPreferences-B1JYyzpK.js → useFontPreferences-DcbXQOkc.js} +1 -1
- package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +414 -0
- package/dist/assets/{useSessionAutoCleanup-Dnors7hB.js → useSessionAutoCleanup-BLjymaFt.js} +1 -1
- package/dist/assets/{useWorkerHighlightedLines-DQqqrOBU.js → useWorkerHighlightedLines-Bqn4AiBL.js} +1 -1
- package/dist/assets/vendor-opencode-client-BOe2qpQb.js +12 -0
- package/dist/assets/{vendor-yaml-DIcAK3EC.js → vendor-yaml-C9KlJAlj.js} +37 -37
- package/dist/assets/zh-CN-20MYEjha.js +15 -0
- package/dist/assets/{zh-TW-BsOQbrwT.js → zh-TW-DiN04qTw.js} +3 -3
- package/dist/index.html +6 -6
- package/dist/mini-chat.html +6 -6
- package/dist/mobile.html +6 -6
- package/package.json +2 -2
- package/server/index.js +107 -0
- package/server/lib/assistants/DOCUMENTATION.md +18 -18
- package/server/lib/assistants/assign.js +2 -1
- package/server/lib/assistants/contact-store.js +37 -19
- package/server/lib/assistants/projection-history.test.js +207 -0
- package/server/lib/assistants/routes.js +5 -5
- package/server/lib/assistants/service.js +493 -123
- package/server/lib/assistants/service.test.js +203 -133
- package/server/lib/conversations/DOCUMENTATION.md +4 -4
- package/server/lib/conversations/service.js +86 -57
- package/server/lib/conversations/service.test.js +116 -100
- package/server/lib/event-stream/global-hub.js +2 -1
- package/server/lib/llm/DOCUMENTATION.md +71 -84
- package/server/lib/llm/catalog.js +111 -45
- package/server/lib/llm/catalog.test.js +121 -59
- package/server/lib/llm/completions.js +37 -12
- package/server/lib/llm/completions.test.js +45 -4
- package/server/lib/llm/generate.js +421 -450
- package/server/lib/llm/generate.test.js +553 -487
- package/server/lib/llm/routes.js +6 -4
- package/server/lib/message-queue/DOCUMENTATION.md +5 -5
- package/server/lib/message-queue/opencode-adapter.js +191 -104
- package/server/lib/message-queue/opencode-adapter.test.js +328 -58
- package/server/lib/message-queue/runtime.test.js +6 -6
- package/server/lib/message-queue/worker.js +7 -1
- package/server/lib/opencode/DOCUMENTATION.md +28 -5
- package/server/lib/opencode/config-entity-routes.js +84 -13
- package/server/lib/opencode/config-entity-routes.test.js +41 -10
- package/server/lib/opencode/ensure-cli.js +239 -0
- package/server/lib/opencode/ensure-cli.test.js +119 -0
- package/server/lib/opencode/env-runtime.js +193 -110
- package/server/lib/opencode/env-runtime.test.js +221 -17
- package/server/lib/opencode/feature-routes-runtime.js +37 -1
- package/server/lib/opencode/lifecycle.js +204 -70
- package/server/lib/opencode/lifecycle.test.js +376 -6
- package/server/lib/opencode/network-runtime.js +28 -16
- package/server/lib/opencode/network-runtime.test.js +68 -4
- package/server/lib/opencode/opencode2-pin.js +139 -0
- package/server/lib/opencode/opencode2-pin.test.js +87 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +203 -0
- package/server/lib/opencode/plugin-compatibility.js +15 -0
- package/server/lib/opencode/plugin-compatibility.test.js +21 -0
- package/server/lib/opencode/plugins.js +4 -3
- package/server/lib/opencode/plugins.test.js +12 -0
- package/server/lib/opencode/proxy.js +153 -16
- package/server/lib/opencode/proxy.test.js +120 -0
- package/server/lib/opencode/routes.js +25 -32
- package/server/lib/opencode/routes.test.js +51 -52
- package/server/lib/opencode/server-utils-runtime.js +2 -0
- package/server/lib/opencode/skill-routes.js +6 -7
- package/server/lib/opencode/skill-routes.test.js +36 -5
- package/server/lib/opencode/v1-migration-gate.js +157 -0
- package/server/lib/opencode/v1-migration-gate.test.js +111 -0
- package/server/lib/opencode/v2-client.js +49 -0
- package/server/lib/opencode/watcher.js +2 -1
- package/server/lib/opencode/watcher.test.js +1 -1
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +71 -39
- package/server/lib/scheduled-tasks/managed-tool-route.js +31 -1
- package/server/lib/scheduled-tasks/managed-tool-route.test.js +23 -0
- package/server/lib/scheduled-tasks/routes.js +27 -0
- package/server/lib/scheduled-tasks/routes.test.js +94 -0
- package/server/lib/scheduled-tasks/runtime.js +331 -308
- package/server/lib/scheduled-tasks/runtime.test.js +530 -318
- package/server/lib/session-goal/DOCUMENTATION.md +65 -14
- package/server/lib/session-goal/capability.js +57 -0
- package/server/lib/session-goal/capability.test.js +33 -0
- package/server/lib/session-goal/routes.js +231 -2
- package/server/lib/session-goal/routes.test.js +211 -0
- package/server/lib/session-goal/runtime.js +46 -4
- package/server/lib/session-goal/runtime.test.js +62 -1
- package/server/lib/session-index/sync-runtime.js +20 -17
- package/server/lib/session-index/sync-runtime.test.js +9 -8
- package/server/lib/session-metadata/DOCUMENTATION.md +41 -0
- package/server/lib/session-metadata/routes.js +94 -0
- package/server/lib/session-metadata/routes.test.js +111 -0
- package/server/lib/session-metadata/session-metadata-store.js +235 -0
- package/server/lib/session-metadata/session-metadata-store.test.js +184 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +3 -3
- package/server/lib/session-turn-pages/reconcile.service.js +1 -1
- package/server/lib/session-turn-pages/reconcile.service.test.js +16 -0
- package/server/lib/session-turn-pages/routes.js +204 -71
- package/server/lib/session-turn-pages/routes.test.js +285 -0
- package/server/lib/session-turn-pages/service.js +6 -2
- package/server/lib/session-turn-pages/service.test.js +34 -0
- package/server/lib/small-model/DOCUMENTATION.md +5 -4
- package/server/lib/small-model/catalog.js +56 -6
- package/server/lib/small-model/catalog.test.js +47 -0
- package/server/lib/small-model/index.js +3 -3
- package/server/lib/small-model/opencode-session.js +50 -206
- package/server/lib/small-model/opencode-session.test.js +58 -88
- package/server/opencode-proxy.test.js +61 -12
- package/dist/assets/AssistantView-BjvfkSRS.js +0 -3
- package/dist/assets/MarkdownRenderer-Cg82L3fN.js +0 -2
- package/dist/assets/MobileDetailNavigation-s_vvUD_F.js +0 -1
- package/dist/assets/MobileSurface-DHpXHbJp.js +0 -2
- package/dist/assets/SettingsView-l0J7pfYo.js +0 -25
- package/dist/assets/es-rqMiRP7-.js +0 -15
- package/dist/assets/gitApi-CHpibtno.js +0 -7
- package/dist/assets/insertionBoundaries-Yd1Lorjw.js +0 -1
- package/dist/assets/ja-Bgr8-dOg.js +0 -15
- package/dist/assets/ko-B_Gxh-0l.js +0 -15
- package/dist/assets/main-BoRXxmB3.js +0 -2
- package/dist/assets/main-DCDcdV5o.js +0 -169
- package/dist/assets/miniChat-12fxk5KR.js +0 -2
- package/dist/assets/mobile-CkZem9Ad.js +0 -2
- package/dist/assets/pl-DW2XJGC4.js +0 -15
- package/dist/assets/platform-0w_Q9_ji.js +0 -2
- package/dist/assets/pt-BR-CIsanf4T.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-COFc0ZDJ.js +0 -2
- package/dist/assets/renderMobileApp-BKzx7JL3.js +0 -28
- package/dist/assets/uk-BPmPEUYJ.js +0 -15
- package/dist/assets/useMobileNavigationStore-DrB_awgk.js +0 -413
- package/dist/assets/vendor-opencode-sdk-C07HQypa.js +0 -7
- package/dist/assets/zh-CN-R8-mDcIp.js +0 -15
|
@@ -3,6 +3,8 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { mergePathValues } from './path-utils.js';
|
|
6
|
+
import { PINNED_OPENCODE2_VERSION, isAcceptableOpenCode2HealthVersion, isOpenCode1xVersion } from './opencode2-pin.js';
|
|
7
|
+
import { ensurePinnedOpenCode2Cli, installedOpenCode2BinaryPath, readOpenCode2BinaryVersion } from './ensure-cli.js';
|
|
6
8
|
|
|
7
9
|
export const createOpenCodeEnvRuntime = (deps) => {
|
|
8
10
|
const {
|
|
@@ -12,6 +14,9 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
12
14
|
} = deps;
|
|
13
15
|
const runSpawnSync = typeof deps.spawnSync === 'function' ? deps.spawnSync : spawnSync;
|
|
14
16
|
const resolveHomeDir = typeof deps.homedir === 'function' ? deps.homedir : () => os.homedir();
|
|
17
|
+
const ensurePinnedCli = typeof deps.ensurePinnedOpenCode2Cli === 'function'
|
|
18
|
+
? deps.ensurePinnedOpenCode2Cli
|
|
19
|
+
: ensurePinnedOpenCode2Cli;
|
|
15
20
|
|
|
16
21
|
const parseNullSeparatedEnvSnapshot = (raw) => {
|
|
17
22
|
if (typeof raw !== 'string' || raw.length === 0) {
|
|
@@ -275,41 +280,20 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
275
280
|
return normalized.endsWith(`${path.sep}programs${path.sep}opencode${path.sep}opencode.exe`);
|
|
276
281
|
};
|
|
277
282
|
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
for (const root of roots) {
|
|
289
|
-
for (const name of names) {
|
|
290
|
-
candidates.push(path.join(root, name));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return candidates;
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const resolveBundledOpenCodeCliPath = () => {
|
|
297
|
-
for (const candidate of bundledOpenCodeCliCandidates()) {
|
|
298
|
-
if (isExecutable(candidate) && !isWindowsOpenCodeDesktopAppPath(candidate)) {
|
|
299
|
-
return candidate;
|
|
300
|
-
}
|
|
283
|
+
const resolveInstalledOpenCodeCliPath = () => {
|
|
284
|
+
const installed = installedOpenCode2BinaryPath(PINNED_OPENCODE2_VERSION, {
|
|
285
|
+
env: process.env,
|
|
286
|
+
homedir: resolveHomeDir,
|
|
287
|
+
platform: process.platform,
|
|
288
|
+
});
|
|
289
|
+
if (isExecutable(installed) && !isWindowsOpenCodeDesktopAppPath(installed)) {
|
|
290
|
+
clearWslOpencodeResolution();
|
|
291
|
+
state.resolvedOpencodeBinarySource = 'installed';
|
|
292
|
+
return installed;
|
|
301
293
|
}
|
|
302
294
|
return null;
|
|
303
295
|
};
|
|
304
296
|
|
|
305
|
-
const bundledOpenCodeCliFallback = () => {
|
|
306
|
-
const bundled = resolveBundledOpenCodeCliPath();
|
|
307
|
-
if (!bundled) return null;
|
|
308
|
-
clearWslOpencodeResolution();
|
|
309
|
-
state.resolvedOpencodeBinarySource = 'bundled';
|
|
310
|
-
return bundled;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
297
|
const clearWslOpencodeResolution = () => {
|
|
314
298
|
state.useWslForOpencode = false;
|
|
315
299
|
state.resolvedWslBinary = null;
|
|
@@ -330,6 +314,28 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
330
314
|
return trimmed;
|
|
331
315
|
};
|
|
332
316
|
|
|
317
|
+
const createOpenCode1xVersionError = (candidate, version) => {
|
|
318
|
+
const error = new Error(
|
|
319
|
+
`OpenCode 1.x is not supported (${candidate} reports ${version}). Install OpenCode v2 (opencode).`
|
|
320
|
+
);
|
|
321
|
+
error.code = 'OPENCODE_BINARY_INVALID';
|
|
322
|
+
return error;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const acceptOpenCodeV2Candidate = (candidate, source) => {
|
|
326
|
+
if (typeof candidate !== 'string' || !candidate.trim()) return null;
|
|
327
|
+
if (!isExecutable(candidate) || isWindowsOpenCodeDesktopAppPath(candidate) || isMacOpenCodeAppBundlePath(candidate)) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const version = readOpenCode2BinaryVersion(candidate);
|
|
331
|
+
if (!isAcceptableOpenCode2HealthVersion(version)) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
clearWslOpencodeResolution();
|
|
335
|
+
state.resolvedOpencodeBinarySource = source;
|
|
336
|
+
return candidate;
|
|
337
|
+
};
|
|
338
|
+
|
|
333
339
|
const resolveOpencodeCliPath = () => {
|
|
334
340
|
const explicit = [
|
|
335
341
|
process.env.OPENCODE_BINARY,
|
|
@@ -341,118 +347,111 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
341
347
|
.filter(Boolean);
|
|
342
348
|
|
|
343
349
|
for (const candidate of explicit) {
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
state.resolvedOpencodeBinarySource = 'env';
|
|
347
|
-
return candidate;
|
|
350
|
+
if (isWindowsOpenCodeDesktopAppPath(candidate) || isMacOpenCodeAppBundlePath(candidate)) {
|
|
351
|
+
continue;
|
|
348
352
|
}
|
|
353
|
+
if (!isExecutable(candidate)) continue;
|
|
354
|
+
const version = readOpenCode2BinaryVersion(candidate);
|
|
355
|
+
if (isOpenCode1xVersion(version)) {
|
|
356
|
+
throw createOpenCode1xVersionError(candidate, version);
|
|
357
|
+
}
|
|
358
|
+
const accepted = acceptOpenCodeV2Candidate(candidate, 'env');
|
|
359
|
+
if (accepted) return accepted;
|
|
349
360
|
}
|
|
350
361
|
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
state.resolvedOpencodeBinarySource = 'path';
|
|
358
|
-
return resolvedFromPath;
|
|
362
|
+
// Match master: reuse a globally installed CLI. Official v2 is `opencode`;
|
|
363
|
+
// `opencode2` remains a compatibility alias. Skip 1.x binaries by version.
|
|
364
|
+
for (const name of process.platform === 'win32' ? ['opencode', 'opencode2'] : ['opencode', 'opencode2']) {
|
|
365
|
+
const resolvedFromPath = searchPathFor(name);
|
|
366
|
+
const accepted = acceptOpenCodeV2Candidate(resolvedFromPath, 'path');
|
|
367
|
+
if (accepted) return accepted;
|
|
359
368
|
}
|
|
360
369
|
|
|
361
370
|
const home = resolveHomeDir();
|
|
362
|
-
const unixFallbacks = [
|
|
363
|
-
path.join(home, '.opencode', 'bin',
|
|
364
|
-
path.join(home, '.bun', 'bin',
|
|
365
|
-
path.join(home, '.local', 'bin',
|
|
366
|
-
path.join(home, 'bin',
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
];
|
|
371
|
+
const unixFallbacks = ['opencode', 'opencode2'].flatMap((name) => [
|
|
372
|
+
path.join(home, '.opencode', 'bin', name),
|
|
373
|
+
path.join(home, '.bun', 'bin', name),
|
|
374
|
+
path.join(home, '.local', 'bin', name),
|
|
375
|
+
path.join(home, 'bin', name),
|
|
376
|
+
`/opt/homebrew/bin/${name}`,
|
|
377
|
+
`/usr/local/bin/${name}`,
|
|
378
|
+
`/home/linuxbrew/.linuxbrew/bin/${name}`,
|
|
379
|
+
`/usr/bin/${name}`,
|
|
380
|
+
`/bin/${name}`,
|
|
381
|
+
]);
|
|
373
382
|
|
|
374
383
|
const winFallbacks = (() => {
|
|
375
384
|
const userProfile = process.env.USERPROFILE || home;
|
|
376
385
|
const appData = process.env.APPDATA || '';
|
|
377
386
|
const localAppData = process.env.LOCALAPPDATA || '';
|
|
378
387
|
const programData = process.env.ProgramData || 'C:\\ProgramData';
|
|
379
|
-
|
|
380
388
|
const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
path.join(userProfile, '.opencode', 'bin'
|
|
384
|
-
path.join(
|
|
385
|
-
path.join(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
path.join(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
path.join(programData, 'chocolatey', 'bin', 'opencode.exe'),
|
|
392
|
-
path.join(programData, 'chocolatey', 'bin', 'opencode.cmd'),
|
|
393
|
-
path.join(userProfile, '.bun', 'bin', 'opencode.exe'),
|
|
394
|
-
path.join(userProfile, '.bun', 'bin', 'opencode.cmd'),
|
|
395
|
-
].filter(Boolean);
|
|
389
|
+
const names = ['opencode.exe', 'opencode.cmd', 'opencode2.exe', 'opencode2.cmd'];
|
|
390
|
+
const dirs = [
|
|
391
|
+
path.join(userProfile, '.opencode', 'bin'),
|
|
392
|
+
path.join(appData, 'npm'),
|
|
393
|
+
path.join(programFiles, 'nodejs'),
|
|
394
|
+
path.join(userProfile, 'scoop', 'shims'),
|
|
395
|
+
path.join(programData, 'chocolatey', 'bin'),
|
|
396
|
+
path.join(userProfile, '.bun', 'bin'),
|
|
397
|
+
];
|
|
398
|
+
return dirs.flatMap((dir) => names.map((name) => path.join(dir, name))).filter(Boolean);
|
|
396
399
|
})();
|
|
397
400
|
|
|
398
401
|
const fallbacks = process.platform === 'win32' ? winFallbacks : unixFallbacks;
|
|
399
402
|
for (const candidate of fallbacks) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
state.resolvedOpencodeBinarySource = 'fallback';
|
|
403
|
-
return candidate;
|
|
404
|
-
}
|
|
403
|
+
const accepted = acceptOpenCodeV2Candidate(candidate, 'fallback');
|
|
404
|
+
if (accepted) return accepted;
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
if (process.platform === 'win32') {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
408
|
+
for (const name of ['opencode', 'opencode2']) {
|
|
409
|
+
try {
|
|
410
|
+
const result = runSpawnSync('where', [name], {
|
|
411
|
+
encoding: 'utf8',
|
|
412
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
413
|
+
windowsHide: true,
|
|
414
|
+
});
|
|
415
|
+
if (result.status === 0) {
|
|
416
|
+
const lines = (result.stdout || '')
|
|
417
|
+
.split(/\r?\n/)
|
|
418
|
+
.map((line) => line.trim())
|
|
419
|
+
.filter(Boolean);
|
|
420
|
+
for (const line of lines) {
|
|
421
|
+
const accepted = acceptOpenCodeV2Candidate(line, 'where');
|
|
422
|
+
if (accepted) return accepted;
|
|
423
|
+
}
|
|
424
424
|
}
|
|
425
|
+
} catch {
|
|
425
426
|
}
|
|
426
|
-
} catch {
|
|
427
427
|
}
|
|
428
428
|
// Do not auto-detect OpenCode from WSL. OpenCode sessions are keyed by
|
|
429
429
|
// server-visible directories, and mixing Windows paths with WSL paths
|
|
430
430
|
// creates duplicate/missing project state in the desktop app.
|
|
431
|
-
return
|
|
431
|
+
return resolveInstalledOpenCodeCliPath();
|
|
432
432
|
}
|
|
433
433
|
|
|
434
434
|
const shells = [process.env.SHELL, '/bin/zsh', '/bin/bash', '/bin/sh'].filter(Boolean);
|
|
435
|
-
for (const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return found;
|
|
435
|
+
for (const name of ['opencode', 'opencode2']) {
|
|
436
|
+
for (const shell of shells) {
|
|
437
|
+
if (!isExecutable(shell)) continue;
|
|
438
|
+
try {
|
|
439
|
+
const result = runSpawnSync(shell, ['-lic', `command -v ${name}`], {
|
|
440
|
+
encoding: 'utf8',
|
|
441
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
442
|
+
windowsHide: true,
|
|
443
|
+
});
|
|
444
|
+
if (result.status === 0) {
|
|
445
|
+
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
|
446
|
+
const accepted = acceptOpenCodeV2Candidate(found, 'shell');
|
|
447
|
+
if (accepted) return accepted;
|
|
449
448
|
}
|
|
449
|
+
} catch {
|
|
450
450
|
}
|
|
451
|
-
} catch {
|
|
452
451
|
}
|
|
453
452
|
}
|
|
454
453
|
|
|
455
|
-
return
|
|
454
|
+
return resolveInstalledOpenCodeCliPath();
|
|
456
455
|
};
|
|
457
456
|
|
|
458
457
|
const resolveNodeCliPath = () => {
|
|
@@ -912,7 +911,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
912
911
|
const createConfiguredOpencodeBinaryError = (raw, normalized) => {
|
|
913
912
|
const configured = typeof raw === 'string' ? raw.trim() : '';
|
|
914
913
|
const candidate = typeof normalized === 'string' && normalized.trim().length > 0 ? normalized.trim() : configured;
|
|
915
|
-
const messageSuffix = 'OpenChamber needs the standalone
|
|
914
|
+
const messageSuffix = 'OpenChamber needs the standalone OpenCode v2 CLI (`opencode`). Install it and set settings.opencodeBinary to the CLI path, for example ~/.opencode/bin/opencode, or leave the setting empty to use PATH lookup.';
|
|
916
915
|
const error = (() => {
|
|
917
916
|
if (isKnownOpenCodeDesktopAppPath(candidate) || isKnownOpenCodeDesktopAppPath(configured)) {
|
|
918
917
|
const platformName = process.platform === 'win32' ? 'Windows desktop app install' : 'macOS desktop app bundle';
|
|
@@ -1013,6 +1012,25 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
1013
1012
|
return null;
|
|
1014
1013
|
}
|
|
1015
1014
|
|
|
1015
|
+
if (normalized && isKnownOpenCodeDesktopAppPath(normalized)) {
|
|
1016
|
+
if (strict) {
|
|
1017
|
+
throw createConfiguredOpencodeBinaryError(raw, normalized);
|
|
1018
|
+
}
|
|
1019
|
+
console.warn(`Configured settings.opencodeBinary points at a desktop app, not the CLI: ${normalized}`);
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if (normalized && isExecutable(normalized)) {
|
|
1024
|
+
const version = readOpenCode2BinaryVersion(normalized);
|
|
1025
|
+
if (isOpenCode1xVersion(version)) {
|
|
1026
|
+
if (strict) {
|
|
1027
|
+
throw createOpenCode1xVersionError(normalized, version);
|
|
1028
|
+
}
|
|
1029
|
+
console.warn(`Configured settings.opencodeBinary points at OpenCode 1.x, which OpenChamber refuses: ${normalized}`);
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1016
1034
|
if (normalized && isExecutable(normalized) && !isKnownOpenCodeDesktopAppPath(normalized)) {
|
|
1017
1035
|
clearWslOpencodeResolution();
|
|
1018
1036
|
process.env.OPENCODE_BINARY = normalized;
|
|
@@ -1048,6 +1066,9 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
1048
1066
|
}
|
|
1049
1067
|
|
|
1050
1068
|
const existing = typeof process.env.OPENCODE_BINARY === 'string' ? process.env.OPENCODE_BINARY.trim() : '';
|
|
1069
|
+
if (existing && isExecutable(existing) && isOpenCode1xVersion(readOpenCode2BinaryVersion(existing))) {
|
|
1070
|
+
throw createOpenCode1xVersionError(existing, readOpenCode2BinaryVersion(existing));
|
|
1071
|
+
}
|
|
1051
1072
|
if (existing && isExecutable(existing)) {
|
|
1052
1073
|
clearWslOpencodeResolution();
|
|
1053
1074
|
state.resolvedOpencodeBinary = existing;
|
|
@@ -1079,6 +1100,67 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
1079
1100
|
return null;
|
|
1080
1101
|
};
|
|
1081
1102
|
|
|
1103
|
+
// Last-resort only: used after pin install fails. Never consulted by resolveOpencodeCliPath.
|
|
1104
|
+
const resolveBundledOpenCodeCliPath = () => {
|
|
1105
|
+
const dirs = [];
|
|
1106
|
+
const envDir = typeof process.env.OPENCHAMBER_BUNDLED_OPENCODE_CLI_DIR === 'string'
|
|
1107
|
+
? process.env.OPENCHAMBER_BUNDLED_OPENCODE_CLI_DIR.trim()
|
|
1108
|
+
: '';
|
|
1109
|
+
if (envDir) {
|
|
1110
|
+
dirs.push(envDir);
|
|
1111
|
+
}
|
|
1112
|
+
if (typeof process.resourcesPath === 'string' && process.resourcesPath.trim()) {
|
|
1113
|
+
dirs.push(path.join(process.resourcesPath, 'opencode-cli'));
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Official v2 name + packaging contract name (see electron opencode2-bundle-contract).
|
|
1117
|
+
const names = ['opencode', 'opencode.exe', 'opencode2', 'opencode2.exe'];
|
|
1118
|
+
for (const dir of dirs) {
|
|
1119
|
+
for (const name of names) {
|
|
1120
|
+
const accepted = acceptOpenCodeV2Candidate(path.join(dir, name), 'bundled');
|
|
1121
|
+
if (accepted) {
|
|
1122
|
+
return accepted;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return null;
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
const ensurePinnedOpenCode2CliEnv = async (options = {}) => {
|
|
1130
|
+
const discovered = state.resolvedOpencodeBinary || resolveOpencodeCliPath();
|
|
1131
|
+
const source = state.resolvedOpencodeBinarySource;
|
|
1132
|
+
const explicit = source === 'env' || source === 'settings';
|
|
1133
|
+
try {
|
|
1134
|
+
const result = await ensurePinnedCli({
|
|
1135
|
+
discoveredPath: discovered,
|
|
1136
|
+
preferDiscovered: explicit,
|
|
1137
|
+
env: process.env,
|
|
1138
|
+
homedir: resolveHomeDir,
|
|
1139
|
+
...options,
|
|
1140
|
+
});
|
|
1141
|
+
if (!result?.path) {
|
|
1142
|
+
return ensureOpencodeCliEnv();
|
|
1143
|
+
}
|
|
1144
|
+
if (result.source === 'installed') {
|
|
1145
|
+
clearWslOpencodeResolution();
|
|
1146
|
+
process.env.OPENCODE_BINARY = result.path;
|
|
1147
|
+
state.resolvedOpencodeBinary = result.path;
|
|
1148
|
+
state.resolvedOpencodeBinarySource = 'installed';
|
|
1149
|
+
}
|
|
1150
|
+
return ensureOpencodeCliEnv();
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
const bundled = resolveBundledOpenCodeCliPath();
|
|
1153
|
+
if (!bundled) {
|
|
1154
|
+
throw error;
|
|
1155
|
+
}
|
|
1156
|
+
clearWslOpencodeResolution();
|
|
1157
|
+
process.env.OPENCODE_BINARY = bundled;
|
|
1158
|
+
state.resolvedOpencodeBinary = bundled;
|
|
1159
|
+
state.resolvedOpencodeBinarySource = 'bundled';
|
|
1160
|
+
return ensureOpencodeCliEnv();
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1082
1164
|
const resolveGitBinaryForSpawn = () => {
|
|
1083
1165
|
if (process.platform !== 'win32') {
|
|
1084
1166
|
return 'git';
|
|
@@ -1162,6 +1244,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|
|
1162
1244
|
return {
|
|
1163
1245
|
applyLoginShellEnvSnapshot,
|
|
1164
1246
|
ensureOpencodeCliEnv,
|
|
1247
|
+
ensurePinnedOpenCode2CliEnv,
|
|
1165
1248
|
applyOpencodeBinaryFromSettings,
|
|
1166
1249
|
getLoginShellEnvSnapshot,
|
|
1167
1250
|
resolveOpencodeCliPath,
|