Compare commits

...
Author SHA1 Message Date
Aiden Cline eb65363435 fix(cli): print the thrown connect error
Stop matching error message text. Unwrap to the error that was thrown and print its message.
2026-09-18 22:38:50 -05:00
Aiden Cline e812c1303c fix(cli): print the connect error instead of the effect stack
Effect.tryPromise was wrapping Unable to connect as UnknownError. Print that message, and the two versions when a mismatch caused the restart.
2026-09-18 22:35:02 -05:00
Aiden Cline 616f6d1542 fix(cli): simplify version mismatch startup error
Drop the extra module. The handler already knows the server version it is replacing, so print that and exit.
2026-09-18 22:30:09 -05:00
Aiden Cline 1d9e6827b7 fix(cli): report version mismatch on startup connect failure
A failed background-server connection after an update was printed as a nested UnknownError stack. Name both versions when the client is replacing a mismatched server.
2026-09-18 22:21:49 -05:00
+39 -4
View File
@@ -5,6 +5,7 @@ import { Commands } from "../commands"
import { Runtime } from "../../framework/runtime"
import { Config } from "../../config"
import { Context, Effect, Fiber, FileSystem, Option, Queue } from "effect"
import { ClientError } from "@opencode/client/promise"
import { ServerConnection } from "../../services/server-connection"
import { Updater } from "../../services/updater"
import { UpdatePreflight } from "../../services/update-preflight"
@@ -19,6 +20,7 @@ export default Runtime.handler(Commands, (input) =>
if (requestedDirectory !== undefined) process.chdir(requestedDirectory)
const preflight = UpdatePreflight.make()
yield* Effect.addFinalizer(() => Effect.promise(() => preflight.close()))
const replaced: { version?: string } = {}
const serviceStarts = yield* Queue.unbounded<{
readonly reason: "missing" | "version-mismatch"
readonly previousVersion?: string
@@ -33,6 +35,7 @@ export default Runtime.handler(Commands, (input) =>
standalone: input.standalone,
mismatch: "replace",
onStart: (reason, previousVersion) => {
if (reason === "version-mismatch") replaced.version = previousVersion
Queue.offerUnsafe(serviceStarts, { reason, previousVersion })
if (reason === "version-mismatch" && preflight.begin(previousVersion)) return
process.stderr.write(
@@ -42,9 +45,13 @@ export default Runtime.handler(Commands, (input) =>
)
},
}).pipe(
Effect.tapError(() =>
Effect.promise(() => preflight.fail("OpenCode update could not start the new background service")),
),
Effect.catch((error) => {
const shown = showConnectError(error, replaced.version, preflight)
if (shown) return shown
return Effect.promise(() => preflight.fail("OpenCode update could not start the new background service")).pipe(
Effect.andThen(Effect.fail(error)),
)
}),
)
const updater = yield* Updater.Service
let installing: string | undefined
@@ -124,6 +131,34 @@ export default Runtime.handler(Commands, (input) =>
: Effect.logInfo(message, tags)
runFork(effect)
},
}).pipe(Effect.provide(LayerNode.compile(Global.node)))
}).pipe(
Effect.provide(LayerNode.compile(Global.node)),
Effect.catch((error) => showConnectError(error, replaced.version, preflight) ?? Effect.fail(error)),
)
}),
)
function showConnectError(
error: unknown,
previousVersion: string | undefined,
preflight: ReturnType<typeof UpdatePreflight.make>,
) {
if (previousVersion === undefined && !isTransport(error)) return undefined
const detail = errorText(error)
const message = previousVersion
? `Version mismatch: background server ${previousVersion}, this client ${OPENCODE_VERSION}. ${detail}`
: detail
process.stderr.write(message + "\n")
return Effect.promise(() => preflight.fail(message)).pipe(Effect.andThen(Effect.sync(() => process.exit(1))))
}
function isTransport(error: unknown): boolean {
if (error instanceof ClientError) return error.reason === "Transport"
return error instanceof Error && isTransport(error.cause)
}
function errorText(error: unknown): string {
if (error instanceof Error && error.cause instanceof Error) return errorText(error.cause)
if (error instanceof Error) return error.message
return String(error)
}