Compare commits
1 Commits
v0.11.3-de
...
v0.11.3-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e84adebe61 |
@@ -1,7 +1,6 @@
|
|||||||
import { FastifyInstance } from "fastify"
|
import { FastifyInstance } from "fastify"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { spawnSync } from "child_process"
|
import { probeBinaryVersion } from "../../workspaces/runtime"
|
||||||
import { buildSpawnSpec } from "../../workspaces/runtime"
|
|
||||||
import type { SettingsService } from "../../settings/service"
|
import type { SettingsService } from "../../settings/service"
|
||||||
import type { Logger } from "../../logger"
|
import type { Logger } from "../../logger"
|
||||||
|
|
||||||
@@ -15,37 +14,8 @@ const ValidateBinarySchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
function validateBinaryPath(binaryPath: string): { valid: boolean; version?: string; error?: string } {
|
function validateBinaryPath(binaryPath: string): { valid: boolean; version?: string; error?: string } {
|
||||||
if (!binaryPath) {
|
const result = probeBinaryVersion(binaryPath)
|
||||||
return { valid: false, error: "Missing binary path" }
|
return { valid: result.valid, version: result.version, error: result.error }
|
||||||
}
|
|
||||||
|
|
||||||
const spec = buildSpawnSpec(binaryPath, ["--version"])
|
|
||||||
try {
|
|
||||||
const result = spawnSync(spec.command, spec.args, {
|
|
||||||
encoding: "utf8",
|
|
||||||
windowsVerbatimArguments: Boolean((spec.options as { windowsVerbatimArguments?: boolean }).windowsVerbatimArguments),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (result.error) {
|
|
||||||
return { valid: false, error: result.error.message }
|
|
||||||
}
|
|
||||||
if (result.status !== 0) {
|
|
||||||
const stderr = result.stderr?.trim()
|
|
||||||
const stdout = result.stdout?.trim()
|
|
||||||
const combined = stderr || stdout
|
|
||||||
const error = combined ? `Exited with code ${result.status}: ${combined}` : `Exited with code ${result.status}`
|
|
||||||
return { valid: false, error }
|
|
||||||
}
|
|
||||||
|
|
||||||
const stdout = (result.stdout ?? "").trim()
|
|
||||||
const firstLine = stdout.split(/\r?\n/).find((line) => line.trim().length > 0)
|
|
||||||
const normalized = firstLine?.trim()
|
|
||||||
const versionMatch = normalized?.match(/([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/)
|
|
||||||
const version = versionMatch?.[1]
|
|
||||||
return { valid: true, version }
|
|
||||||
} catch (error) {
|
|
||||||
return { valid: false, error: error instanceof Error ? error.message : String(error) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerSettingsRoutes(app: FastifyInstance, deps: RouteDeps) {
|
export function registerSettingsRoutes(app: FastifyInstance, deps: RouteDeps) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { FileSystemBrowser } from "../filesystem/browser"
|
|||||||
import { searchWorkspaceFiles, WorkspaceFileSearchOptions } from "../filesystem/search"
|
import { searchWorkspaceFiles, WorkspaceFileSearchOptions } from "../filesystem/search"
|
||||||
import { clearWorkspaceSearchCache } from "../filesystem/search-cache"
|
import { clearWorkspaceSearchCache } from "../filesystem/search-cache"
|
||||||
import { WorkspaceDescriptor, WorkspaceFileResponse, FileSystemEntry } from "../api-types"
|
import { WorkspaceDescriptor, WorkspaceFileResponse, FileSystemEntry } from "../api-types"
|
||||||
import { WorkspaceRuntime, ProcessExitInfo } from "./runtime"
|
import { WorkspaceRuntime, ProcessExitInfo, probeBinaryVersion } from "./runtime"
|
||||||
import { Logger } from "../logger"
|
import { Logger } from "../logger"
|
||||||
import { getOpencodeConfigDir } from "../opencode-config.js"
|
import { getOpencodeConfigDir } from "../opencode-config.js"
|
||||||
import {
|
import {
|
||||||
@@ -283,28 +283,22 @@ export class WorkspaceManager {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const result = probeBinaryVersion(resolvedPath)
|
||||||
const result = spawnSync(resolvedPath, ["--version"], { encoding: "utf8" })
|
if (result.valid) {
|
||||||
if (result.status === 0 && result.stdout) {
|
if (result.version) {
|
||||||
const line = result.stdout.split(/\r?\n/).find((entry) => entry.trim().length > 0)
|
this.options.logger.debug({ binary: resolvedPath, version: result.version }, "Detected binary version")
|
||||||
if (line) {
|
return result.version
|
||||||
const normalized = line.trim()
|
|
||||||
const versionMatch = normalized.match(/([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/)
|
|
||||||
if (versionMatch) {
|
|
||||||
const version = versionMatch[1]
|
|
||||||
this.options.logger.debug({ binary: resolvedPath, version }, "Detected binary version")
|
|
||||||
return version
|
|
||||||
}
|
}
|
||||||
this.options.logger.debug({ binary: resolvedPath, reported: normalized }, "Binary reported version string")
|
if (result.reported) {
|
||||||
return normalized
|
this.options.logger.debug({ binary: resolvedPath, reported: result.reported }, "Binary reported version string")
|
||||||
|
return result.reported
|
||||||
}
|
}
|
||||||
} else if (result.error) {
|
return undefined
|
||||||
this.options.logger.warn({ binary: resolvedPath, err: result.error }, "Failed to read binary version")
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.options.logger.warn({ binary: resolvedPath, err: error }, "Failed to detect binary version")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
this.options.logger.warn({ binary: resolvedPath, err: result.error }, "Failed to detect binary version")
|
||||||
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { Logger } from "../logger"
|
|||||||
export const WINDOWS_CMD_EXTENSIONS = new Set([".cmd", ".bat"])
|
export const WINDOWS_CMD_EXTENSIONS = new Set([".cmd", ".bat"])
|
||||||
export const WINDOWS_POWERSHELL_EXTENSIONS = new Set([".ps1"])
|
export const WINDOWS_POWERSHELL_EXTENSIONS = new Set([".ps1"])
|
||||||
|
|
||||||
|
const VERSION_REGEX = /([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/
|
||||||
|
|
||||||
export function buildSpawnSpec(binaryPath: string, args: string[]) {
|
export function buildSpawnSpec(binaryPath: string, args: string[]) {
|
||||||
if (process.platform !== "win32") {
|
if (process.platform !== "win32") {
|
||||||
return { command: binaryPath, args, options: {} as const }
|
return { command: binaryPath, args, options: {} as const }
|
||||||
@@ -40,6 +42,61 @@ export function buildSpawnSpec(binaryPath: string, args: string[]) {
|
|||||||
return { command: binaryPath, args, options: {} as const }
|
return { command: binaryPath, args, options: {} as const }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function probeBinaryVersion(binaryPath: string): {
|
||||||
|
valid: boolean
|
||||||
|
version?: string
|
||||||
|
reported?: string
|
||||||
|
error?: string
|
||||||
|
} {
|
||||||
|
if (!binaryPath) {
|
||||||
|
return { valid: false, error: "Missing binary path" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const spec = buildSpawnSpec(binaryPath, ["--version"])
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = spawnSync(spec.command, spec.args, {
|
||||||
|
encoding: "utf8",
|
||||||
|
windowsVerbatimArguments: Boolean(
|
||||||
|
(spec.options as { windowsVerbatimArguments?: boolean }).windowsVerbatimArguments,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
return { valid: false, error: result.error.message }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status !== 0) {
|
||||||
|
const stderr = result.stderr?.trim()
|
||||||
|
const stdout = result.stdout?.trim()
|
||||||
|
const combined = stderr || stdout
|
||||||
|
const error = combined ? `Exited with code ${result.status}: ${combined}` : `Exited with code ${result.status}`
|
||||||
|
return { valid: false, error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdoutLines = String(result.stdout ?? "")
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter((line) => line.length > 0)
|
||||||
|
const stderrLines = String(result.stderr ?? "")
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter((line) => line.length > 0)
|
||||||
|
|
||||||
|
// Prefer stdout; fall back to stderr (some tools report version there).
|
||||||
|
const reported = stdoutLines[0] ?? stderrLines[0]
|
||||||
|
if (!reported) {
|
||||||
|
return { valid: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionMatch = reported.match(VERSION_REGEX)
|
||||||
|
const version = versionMatch?.[1]
|
||||||
|
return { valid: true, version, reported }
|
||||||
|
} catch (error) {
|
||||||
|
return { valid: false, error: error instanceof Error ? error.message : String(error) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const SENSITIVE_ENV_KEY = /(PASSWORD|TOKEN|SECRET)/i
|
const SENSITIVE_ENV_KEY = /(PASSWORD|TOKEN|SECRET)/i
|
||||||
|
|
||||||
function redactEnvironment(env: Record<string, string | undefined>): Record<string, string | undefined> {
|
function redactEnvironment(env: Record<string, string | undefined>): Record<string, string | undefined> {
|
||||||
|
|||||||
Reference in New Issue
Block a user