fix(desktop): terminate sidecar on main window close
- Terminate the sidecar when the macOS main window is closed - Update opencode-ai/sdk to v1.1.53 across all packages
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@octokit/rest": "^22.0.1",
|
"@octokit/rest": "^22.0.1",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
"@fontsource/ibm-plex-sans": "^5.1.1",
|
"@fontsource/ibm-plex-sans": "^5.1.1",
|
||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@pierre/diffs": "^1.0.5",
|
"@pierre/diffs": "^1.0.5",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
@@ -202,7 +202,7 @@
|
|||||||
"version": "1.6.4",
|
"version": "1.6.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@openchamber/ui": "workspace:*",
|
"@openchamber/ui": "workspace:*",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"jsonc-parser": "^3.3.1",
|
"jsonc-parser": "^3.3.1",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
@@ -231,7 +231,7 @@
|
|||||||
"@fontsource/ibm-plex-sans": "^5.1.1",
|
"@fontsource/ibm-plex-sans": "^5.1.1",
|
||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@octokit/rest": "^22.0.1",
|
"@octokit/rest": "^22.0.1",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
|
|||||||
+1
-1
@@ -85,7 +85,7 @@
|
|||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@octokit/rest": "^22.0.1",
|
"@octokit/rest": "^22.0.1",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
|
|||||||
@@ -1482,6 +1482,14 @@ fn main() {
|
|||||||
*state.focused.lock().expect("focus mutex") = *focused;
|
*state.focused.lock().expect("focus mutex") = *focused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
if let tauri::WindowEvent::CloseRequested { .. } = event {
|
||||||
|
// Ensure sidecar is not left running when users close the main window.
|
||||||
|
let app = window.app_handle();
|
||||||
|
kill_sidecar(app.clone());
|
||||||
|
app.exit(0);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
desktop_notify,
|
desktop_notify,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
"@fontsource/ibm-plex-sans": "^5.1.1",
|
"@fontsource/ibm-plex-sans": "^5.1.1",
|
||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@pierre/diffs": "^1.0.5",
|
"@pierre/diffs": "^1.0.5",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
|
|||||||
@@ -10,6 +10,30 @@ type ProbeResult = {
|
|||||||
summary: string;
|
summary: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type OpenChamberHealthSnapshot = {
|
||||||
|
openCodePort?: unknown;
|
||||||
|
openCodeRunning?: unknown;
|
||||||
|
isOpenCodeReady?: unknown;
|
||||||
|
lastOpenCodeError?: unknown;
|
||||||
|
opencodeBinaryResolved?: unknown;
|
||||||
|
opencodeBinarySource?: unknown;
|
||||||
|
opencodeShimInterpreter?: unknown;
|
||||||
|
nodeBinaryResolved?: unknown;
|
||||||
|
bunBinaryResolved?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OpenChamberOpencodeResolution = {
|
||||||
|
configured?: unknown;
|
||||||
|
resolved?: unknown;
|
||||||
|
resolvedDir?: unknown;
|
||||||
|
source?: unknown;
|
||||||
|
detectedNow?: unknown;
|
||||||
|
detectedSourceNow?: unknown;
|
||||||
|
shim?: unknown;
|
||||||
|
node?: unknown;
|
||||||
|
bun?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
const getCurrentDirectory = (): string => {
|
const getCurrentDirectory = (): string => {
|
||||||
const state = useSessionStore.getState();
|
const state = useSessionStore.getState();
|
||||||
const currentSessionId = state.currentSessionId;
|
const currentSessionId = state.currentSessionId;
|
||||||
@@ -85,6 +109,72 @@ export const buildOpenCodeStatusReport = async (): Promise<string> => {
|
|||||||
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
||||||
const apiBase = origin ? `${origin.replace(/\/+$/, '')}/api/` : '';
|
const apiBase = origin ? `${origin.replace(/\/+$/, '')}/api/` : '';
|
||||||
|
|
||||||
|
const openChamberHealth: OpenChamberHealthSnapshot | null = await (async () => {
|
||||||
|
if (!origin) return null;
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||||
|
try {
|
||||||
|
const resp = await fetch(`${origin.replace(/\/+$/, '')}/health`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { Accept: 'application/json' },
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
if (!resp.ok) return null;
|
||||||
|
const json = (await resp.json().catch(() => null)) as unknown;
|
||||||
|
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
||||||
|
return json as OpenChamberHealthSnapshot;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const openChamberOpencodeResolutionResult: {
|
||||||
|
data: OpenChamberOpencodeResolution | null;
|
||||||
|
status: number | null;
|
||||||
|
error: string | null;
|
||||||
|
} = await (async () => {
|
||||||
|
if (!origin) return null;
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), 7000);
|
||||||
|
try {
|
||||||
|
const resp = await fetch(`${origin.replace(/\/+$/, '')}/api/config/opencode-resolution`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { Accept: 'application/json' },
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
const contentType = resp.headers.get('content-type') || '(none)';
|
||||||
|
if (!resp.ok) {
|
||||||
|
return { data: null, status: resp.status, error: `http ${resp.status} content-type=${contentType}` };
|
||||||
|
}
|
||||||
|
const raw = await resp.text();
|
||||||
|
let json: unknown = null;
|
||||||
|
try {
|
||||||
|
json = JSON.parse(raw);
|
||||||
|
} catch {
|
||||||
|
const snippet = raw.replace(/\s+/g, ' ').slice(0, 120);
|
||||||
|
return {
|
||||||
|
data: null,
|
||||||
|
status: resp.status,
|
||||||
|
error: `invalid json content-type=${contentType} body=${snippet || '(empty)'}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!json || typeof json !== 'object' || Array.isArray(json)) {
|
||||||
|
return { data: null, status: resp.status, error: `invalid json-shape content-type=${contentType}` };
|
||||||
|
}
|
||||||
|
return { data: json as OpenChamberOpencodeResolution, status: resp.status, error: null };
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
data: null,
|
||||||
|
status: null,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
})() || { data: null, status: null, error: null };
|
||||||
|
|
||||||
const buildProbeUrl = (pathname: string, includeDirectory = true): string | null => {
|
const buildProbeUrl = (pathname: string, includeDirectory = true): string | null => {
|
||||||
if (!apiBase) return null;
|
if (!apiBase) return null;
|
||||||
const url = new URL(pathname.replace(/^\/+/, ''), apiBase);
|
const url = new URL(pathname.replace(/^\/+/, ''), apiBase);
|
||||||
@@ -132,6 +222,73 @@ export const buildOpenCodeStatusReport = async (): Promise<string> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isLikelyMac = /Mac OS X|Macintosh/.test(platform);
|
||||||
|
if (isLikelyMac) {
|
||||||
|
lines.push('');
|
||||||
|
lines.push('OpenCode CLI resolution:');
|
||||||
|
|
||||||
|
const openChamberOpencodeResolution = openChamberOpencodeResolutionResult.data;
|
||||||
|
const configured =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.configured === 'string'
|
||||||
|
? openChamberOpencodeResolution.configured
|
||||||
|
: null;
|
||||||
|
const resolved =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.resolved === 'string'
|
||||||
|
? openChamberOpencodeResolution.resolved
|
||||||
|
: (openChamberHealth && typeof openChamberHealth.opencodeBinaryResolved === 'string' ? openChamberHealth.opencodeBinaryResolved : '');
|
||||||
|
const resolvedDir =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.resolvedDir === 'string'
|
||||||
|
? openChamberOpencodeResolution.resolvedDir
|
||||||
|
: '';
|
||||||
|
const source =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.source === 'string'
|
||||||
|
? openChamberOpencodeResolution.source
|
||||||
|
: (openChamberHealth && typeof openChamberHealth.opencodeBinarySource === 'string' ? openChamberHealth.opencodeBinarySource : '');
|
||||||
|
const shim =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.shim === 'string'
|
||||||
|
? openChamberOpencodeResolution.shim
|
||||||
|
: (openChamberHealth && typeof openChamberHealth.opencodeShimInterpreter === 'string' ? openChamberHealth.opencodeShimInterpreter : '');
|
||||||
|
const node =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.node === 'string'
|
||||||
|
? openChamberOpencodeResolution.node
|
||||||
|
: (openChamberHealth && typeof openChamberHealth.nodeBinaryResolved === 'string' ? openChamberHealth.nodeBinaryResolved : '');
|
||||||
|
const bun =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.bun === 'string'
|
||||||
|
? openChamberOpencodeResolution.bun
|
||||||
|
: (openChamberHealth && typeof openChamberHealth.bunBinaryResolved === 'string' ? openChamberHealth.bunBinaryResolved : '');
|
||||||
|
const detectedNow =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.detectedNow === 'string'
|
||||||
|
? openChamberOpencodeResolution.detectedNow
|
||||||
|
: '';
|
||||||
|
const detectedSourceNow =
|
||||||
|
openChamberOpencodeResolution && typeof openChamberOpencodeResolution.detectedSourceNow === 'string'
|
||||||
|
? openChamberOpencodeResolution.detectedSourceNow
|
||||||
|
: '';
|
||||||
|
|
||||||
|
if (configured !== null) {
|
||||||
|
lines.push(`- configured: ${configured.trim().length === 0 ? '(cleared)' : configured}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved) {
|
||||||
|
const dir = resolvedDir || (resolved.includes('/') ? resolved.split('/').slice(0, -1).join('/') || '/' : '');
|
||||||
|
lines.push(`- opencode: ${resolved}${dir ? ` (dir=${dir})` : ''}`);
|
||||||
|
} else {
|
||||||
|
lines.push('- opencode: (n/a)');
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(`- source: ${source || '(n/a)'}`);
|
||||||
|
if (detectedNow) {
|
||||||
|
lines.push(`- detected-now: ${detectedNow}`);
|
||||||
|
lines.push(`- detected-source: ${detectedSourceNow || '(n/a)'}`);
|
||||||
|
}
|
||||||
|
lines.push(`- shim: ${shim || '(n/a)'}`);
|
||||||
|
lines.push(`- node: ${node || '(n/a)'}`);
|
||||||
|
lines.push(`- bun: ${bun || '(n/a)'}`);
|
||||||
|
if (!openChamberOpencodeResolution && openChamberOpencodeResolutionResult.error) {
|
||||||
|
lines.push(`- resolution-endpoint: ${openChamberOpencodeResolutionResult.error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lines.push('');
|
lines.push('');
|
||||||
if (probes.length) {
|
if (probes.length) {
|
||||||
lines.push('OpenCode API probes:');
|
lines.push('OpenCode API probes:');
|
||||||
|
|||||||
@@ -229,7 +229,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@openchamber/ui": "workspace:*",
|
"@openchamber/ui": "workspace:*",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"jsonc-parser": "^3.3.1",
|
"jsonc-parser": "^3.3.1",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@fontsource/ibm-plex-sans": "^5.1.1",
|
"@fontsource/ibm-plex-sans": "^5.1.1",
|
||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@octokit/rest": "^22.0.1",
|
"@octokit/rest": "^22.0.1",
|
||||||
"@opencode-ai/sdk": "^1.1.52",
|
"@opencode-ai/sdk": "^1.1.53",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
|
|||||||
@@ -1875,6 +1875,7 @@ const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
|||||||
let globalEventWatcherAbortController = null;
|
let globalEventWatcherAbortController = null;
|
||||||
|
|
||||||
let resolvedOpencodeBinary = null;
|
let resolvedOpencodeBinary = null;
|
||||||
|
let resolvedOpencodeBinarySource = null;
|
||||||
let resolvedNodeBinary = null;
|
let resolvedNodeBinary = null;
|
||||||
let resolvedBunBinary = null;
|
let resolvedBunBinary = null;
|
||||||
|
|
||||||
@@ -1927,12 +1928,14 @@ function resolveOpencodeCliPath() {
|
|||||||
|
|
||||||
for (const candidate of explicit) {
|
for (const candidate of explicit) {
|
||||||
if (isExecutable(candidate)) {
|
if (isExecutable(candidate)) {
|
||||||
|
resolvedOpencodeBinarySource = 'env';
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedFromPath = searchPathFor('opencode');
|
const resolvedFromPath = searchPathFor('opencode');
|
||||||
if (resolvedFromPath) {
|
if (resolvedFromPath) {
|
||||||
|
resolvedOpencodeBinarySource = 'path';
|
||||||
return resolvedFromPath;
|
return resolvedFromPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1970,6 +1973,7 @@ function resolveOpencodeCliPath() {
|
|||||||
const fallbacks = process.platform === 'win32' ? winFallbacks : unixFallbacks;
|
const fallbacks = process.platform === 'win32' ? winFallbacks : unixFallbacks;
|
||||||
for (const candidate of fallbacks) {
|
for (const candidate of fallbacks) {
|
||||||
if (isExecutable(candidate)) {
|
if (isExecutable(candidate)) {
|
||||||
|
resolvedOpencodeBinarySource = 'fallback';
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1986,7 +1990,10 @@ function resolveOpencodeCliPath() {
|
|||||||
.map((line) => line.trim())
|
.map((line) => line.trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const found = lines.find((line) => isExecutable(line));
|
const found = lines.find((line) => isExecutable(line));
|
||||||
if (found) return found;
|
if (found) {
|
||||||
|
resolvedOpencodeBinarySource = 'where';
|
||||||
|
return found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
@@ -2005,6 +2012,7 @@ function resolveOpencodeCliPath() {
|
|||||||
if (result.status === 0) {
|
if (result.status === 0) {
|
||||||
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
||||||
if (found && isExecutable(found)) {
|
if (found && isExecutable(found)) {
|
||||||
|
resolvedOpencodeBinarySource = 'shell';
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2284,6 +2292,7 @@ async function applyOpencodeBinaryFromSettings() {
|
|||||||
if (normalized === '') {
|
if (normalized === '') {
|
||||||
delete process.env.OPENCODE_BINARY;
|
delete process.env.OPENCODE_BINARY;
|
||||||
resolvedOpencodeBinary = null;
|
resolvedOpencodeBinary = null;
|
||||||
|
resolvedOpencodeBinarySource = null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2291,6 +2300,7 @@ async function applyOpencodeBinaryFromSettings() {
|
|||||||
process.env.OPENCODE_BINARY = normalized;
|
process.env.OPENCODE_BINARY = normalized;
|
||||||
prependToPath(path.dirname(normalized));
|
prependToPath(path.dirname(normalized));
|
||||||
resolvedOpencodeBinary = normalized;
|
resolvedOpencodeBinary = normalized;
|
||||||
|
resolvedOpencodeBinarySource = 'settings';
|
||||||
ensureOpencodeShimRuntime(normalized);
|
ensureOpencodeShimRuntime(normalized);
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
@@ -2315,6 +2325,7 @@ function ensureOpencodeCliEnv() {
|
|||||||
const existing = typeof process.env.OPENCODE_BINARY === 'string' ? process.env.OPENCODE_BINARY.trim() : '';
|
const existing = typeof process.env.OPENCODE_BINARY === 'string' ? process.env.OPENCODE_BINARY.trim() : '';
|
||||||
if (existing && isExecutable(existing)) {
|
if (existing && isExecutable(existing)) {
|
||||||
resolvedOpencodeBinary = existing;
|
resolvedOpencodeBinary = existing;
|
||||||
|
resolvedOpencodeBinarySource = resolvedOpencodeBinarySource || 'env';
|
||||||
prependToPath(path.dirname(existing));
|
prependToPath(path.dirname(existing));
|
||||||
ensureOpencodeShimRuntime(existing);
|
ensureOpencodeShimRuntime(existing);
|
||||||
return resolvedOpencodeBinary;
|
return resolvedOpencodeBinary;
|
||||||
@@ -2326,6 +2337,7 @@ function ensureOpencodeCliEnv() {
|
|||||||
prependToPath(path.dirname(resolved));
|
prependToPath(path.dirname(resolved));
|
||||||
ensureOpencodeShimRuntime(resolved);
|
ensureOpencodeShimRuntime(resolved);
|
||||||
resolvedOpencodeBinary = resolved;
|
resolvedOpencodeBinary = resolved;
|
||||||
|
resolvedOpencodeBinarySource = resolvedOpencodeBinarySource || 'unknown';
|
||||||
console.log(`Resolved opencode CLI: ${resolved}`);
|
console.log(`Resolved opencode CLI: ${resolved}`);
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
@@ -3511,6 +3523,7 @@ function setupProxy(app) {
|
|||||||
req.path.startsWith('/themes/custom') ||
|
req.path.startsWith('/themes/custom') ||
|
||||||
req.path.startsWith('/push') ||
|
req.path.startsWith('/push') ||
|
||||||
req.path.startsWith('/config/agents') ||
|
req.path.startsWith('/config/agents') ||
|
||||||
|
req.path.startsWith('/config/opencode-resolution') ||
|
||||||
req.path.startsWith('/config/settings') ||
|
req.path.startsWith('/config/settings') ||
|
||||||
req.path.startsWith('/config/skills') ||
|
req.path.startsWith('/config/skills') ||
|
||||||
req.path === '/config/reload' ||
|
req.path === '/config/reload' ||
|
||||||
@@ -3544,6 +3557,7 @@ function setupProxy(app) {
|
|||||||
if (
|
if (
|
||||||
req.path.startsWith('/themes/custom') ||
|
req.path.startsWith('/themes/custom') ||
|
||||||
req.path.startsWith('/config/agents') ||
|
req.path.startsWith('/config/agents') ||
|
||||||
|
req.path.startsWith('/config/opencode-resolution') ||
|
||||||
req.path.startsWith('/config/settings') ||
|
req.path.startsWith('/config/settings') ||
|
||||||
req.path.startsWith('/config/skills') ||
|
req.path.startsWith('/config/skills') ||
|
||||||
req.path === '/health'
|
req.path === '/health'
|
||||||
@@ -3720,7 +3734,12 @@ async function main(options = {}) {
|
|||||||
openCodeApiPrefix: '',
|
openCodeApiPrefix: '',
|
||||||
openCodeApiPrefixDetected: true,
|
openCodeApiPrefixDetected: true,
|
||||||
isOpenCodeReady,
|
isOpenCodeReady,
|
||||||
lastOpenCodeError
|
lastOpenCodeError,
|
||||||
|
opencodeBinaryResolved: resolvedOpencodeBinary || null,
|
||||||
|
opencodeBinarySource: resolvedOpencodeBinarySource || null,
|
||||||
|
opencodeShimInterpreter: resolvedOpencodeBinary ? opencodeShimInterpreter(resolvedOpencodeBinary) : null,
|
||||||
|
nodeBinaryResolved: resolvedNodeBinary || null,
|
||||||
|
bunBinaryResolved: resolvedBunBinary || null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -4305,6 +4324,50 @@ async function main(options = {}) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/config/opencode-resolution', async (_req, res) => {
|
||||||
|
try {
|
||||||
|
const settings = await readSettingsFromDiskMigrated();
|
||||||
|
const configured = typeof settings?.opencodeBinary === 'string' ? settings.opencodeBinary : null;
|
||||||
|
|
||||||
|
const previousSource = resolvedOpencodeBinarySource;
|
||||||
|
const detectedNow = resolveOpencodeCliPath();
|
||||||
|
const rawDetectedSourceNow = resolvedOpencodeBinarySource;
|
||||||
|
resolvedOpencodeBinarySource = previousSource;
|
||||||
|
|
||||||
|
// Best-effort: apply configured override (if any) and resolve.
|
||||||
|
await applyOpencodeBinaryFromSettings();
|
||||||
|
ensureOpencodeCliEnv();
|
||||||
|
|
||||||
|
const resolved = resolvedOpencodeBinary || null;
|
||||||
|
const source = resolvedOpencodeBinarySource || null;
|
||||||
|
const detectedSourceNow =
|
||||||
|
detectedNow &&
|
||||||
|
resolved &&
|
||||||
|
detectedNow === resolved &&
|
||||||
|
rawDetectedSourceNow === 'env' &&
|
||||||
|
source &&
|
||||||
|
source !== 'env'
|
||||||
|
? source
|
||||||
|
: rawDetectedSourceNow;
|
||||||
|
const shim = resolved ? opencodeShimInterpreter(resolved) : null;
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
configured,
|
||||||
|
resolved,
|
||||||
|
resolvedDir: resolved ? path.dirname(resolved) : null,
|
||||||
|
source,
|
||||||
|
detectedNow,
|
||||||
|
detectedSourceNow,
|
||||||
|
shim,
|
||||||
|
node: resolvedNodeBinary || null,
|
||||||
|
bun: resolvedBunBinary || null,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to build opencode resolution snapshot:', error);
|
||||||
|
res.status(500).json({ error: error instanceof Error ? error.message : 'Failed to build snapshot' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/config/themes', async (_req, res) => {
|
app.get('/api/config/themes', async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
const customThemes = await readCustomThemesFromDisk();
|
const customThemes = await readCustomThemesFromDisk();
|
||||||
|
|||||||
Reference in New Issue
Block a user