mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-21 17:54:23 +01:00
Fix shutdown handling, error management, and process lifecycle issues
🤖 Generated with [OpenCode](https://opencode.ai) Co-Authored-By: OpenCode <noreply@opencode.ai>
This commit is contained in:
@@ -97,7 +97,7 @@ export namespace App {
|
|||||||
log.info("registering service", { name: key })
|
log.info("registering service", { name: key })
|
||||||
services.set(key, {
|
services.set(key, {
|
||||||
state: init(app.info),
|
state: init(app.info),
|
||||||
shutdown: shutdown,
|
shutdown,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return services.get(key)?.state as State
|
return services.get(key)?.state as State
|
||||||
@@ -108,14 +108,15 @@ export namespace App {
|
|||||||
return ctx.use().info
|
return ctx.use().info
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function provide<T extends (app: Info) => any>(
|
export async function provide<T>(
|
||||||
input: { cwd: string; version: string },
|
input: { cwd: string; version: string },
|
||||||
cb: T,
|
cb: (app: Info) => Promise<T>,
|
||||||
) {
|
) {
|
||||||
const app = await create(input)
|
const app = await create(input)
|
||||||
return ctx.provide(app, async () => {
|
return ctx.provide(app, async () => {
|
||||||
const result = await cb(app.info)
|
const result = await cb(app.info)
|
||||||
for (const [key, entry] of app.services.entries()) {
|
for (const [key, entry] of app.services.entries()) {
|
||||||
|
if (!entry.shutdown) continue
|
||||||
log.info("shutdown", { name: key })
|
log.info("shutdown", { name: key })
|
||||||
await entry.shutdown?.(await entry.state)
|
await entry.shutdown?.(await entry.state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import * as prompts from "@clack/prompts"
|
|||||||
import open from "open"
|
import open from "open"
|
||||||
import { VERSION } from "../version"
|
import { VERSION } from "../version"
|
||||||
import { Provider } from "../../provider/provider"
|
import { Provider } from "../../provider/provider"
|
||||||
|
import { UI } from "../ui"
|
||||||
|
|
||||||
export const ProviderCommand = cmd({
|
export const ProviderCommand = cmd({
|
||||||
command: "provider",
|
command: "provider",
|
||||||
@@ -62,7 +63,7 @@ export const ProviderAddCommand = cmd({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(provider)) return
|
if (prompts.isCancel(provider)) throw new UI.CancelledError({})
|
||||||
|
|
||||||
if (provider === "anthropic") {
|
if (provider === "anthropic") {
|
||||||
const method = await prompts.select({
|
const method = await prompts.select({
|
||||||
@@ -78,7 +79,7 @@ export const ProviderAddCommand = cmd({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(method)) return
|
if (prompts.isCancel(method)) throw new UI.CancelledError({})
|
||||||
|
|
||||||
if (method === "oauth") {
|
if (method === "oauth") {
|
||||||
// some weird bug where program exits without this
|
// some weird bug where program exits without this
|
||||||
@@ -92,7 +93,8 @@ export const ProviderAddCommand = cmd({
|
|||||||
message: "Paste the authorization code here: ",
|
message: "Paste the authorization code here: ",
|
||||||
validate: (x) => (x.length > 0 ? undefined : "Required"),
|
validate: (x) => (x.length > 0 ? undefined : "Required"),
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(code)) return
|
if (prompts.isCancel(code)) throw new UI.CancelledError({})
|
||||||
|
|
||||||
await AuthAnthropic.exchange(code, verifier)
|
await AuthAnthropic.exchange(code, verifier)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
prompts.log.success("Login successful")
|
prompts.log.success("Login successful")
|
||||||
@@ -109,7 +111,7 @@ export const ProviderAddCommand = cmd({
|
|||||||
message: "Enter your API key",
|
message: "Enter your API key",
|
||||||
validate: (x) => (x.length > 0 ? undefined : "Required"),
|
validate: (x) => (x.length > 0 ? undefined : "Required"),
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(key)) return
|
if (prompts.isCancel(key)) throw new UI.CancelledError({})
|
||||||
await AuthKeys.set(provider, key)
|
await AuthKeys.set(provider, key)
|
||||||
|
|
||||||
prompts.outro("Done")
|
prompts.outro("Done")
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { VERSION } from "./version"
|
import { z } from "zod"
|
||||||
|
import { NamedError } from "../util/error"
|
||||||
|
|
||||||
export namespace UI {
|
export namespace UI {
|
||||||
const LOGO = [
|
const LOGO = [
|
||||||
@@ -7,6 +8,11 @@ export namespace UI {
|
|||||||
`▀▀▀▀ █▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀`,
|
`▀▀▀▀ █▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀`,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const CancelledError = NamedError.create(
|
||||||
|
"UICancelledError",
|
||||||
|
z.object({}),
|
||||||
|
)
|
||||||
|
|
||||||
export const Style = {
|
export const Style = {
|
||||||
TEXT_HIGHLIGHT: "\x1b[96m",
|
TEXT_HIGHLIGHT: "\x1b[96m",
|
||||||
TEXT_HIGHLIGHT_BOLD: "\x1b[96m\x1b[1m",
|
TEXT_HIGHLIGHT_BOLD: "\x1b[96m\x1b[1m",
|
||||||
|
|||||||
@@ -21,30 +21,29 @@ import { UI } from "./cli/ui"
|
|||||||
|
|
||||||
await Log.init({ print: process.argv.includes("--print-logs") })
|
await Log.init({ print: process.argv.includes("--print-logs") })
|
||||||
|
|
||||||
yargs(hideBin(process.argv))
|
try {
|
||||||
|
await yargs(hideBin(process.argv))
|
||||||
.scriptName("opencode")
|
.scriptName("opencode")
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.command({
|
.command({
|
||||||
command: "$0",
|
command: "$0",
|
||||||
describe: "Start OpenCode TUI",
|
describe: "Start OpenCode TUI",
|
||||||
builder: (yargs) =>
|
|
||||||
yargs.option("print-logs", {
|
|
||||||
type: "boolean",
|
|
||||||
}),
|
|
||||||
handler: async (args) => {
|
handler: async (args) => {
|
||||||
UI.logo()
|
while (true) {
|
||||||
await App.provide({ cwd: process.cwd(), version: VERSION }, async () => {
|
const result = await App.provide(
|
||||||
|
{ cwd: process.cwd(), version: VERSION },
|
||||||
|
async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
if (Object.keys(providers).length === 0) {
|
if (Object.keys(providers).length === 0) {
|
||||||
await ProviderAddCommand.handler(args)
|
return "needs_provider"
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Share.init()
|
await Share.init()
|
||||||
const server = Server.listen()
|
const server = Server.listen()
|
||||||
|
|
||||||
let cmd = ["go", "run", "./main.go"]
|
let cmd = ["go", "run", "./main.go"]
|
||||||
let cwd = new URL("../../tui/cmd/opencode", import.meta.url).pathname
|
let cwd = new URL("../../tui/cmd/opencode", import.meta.url)
|
||||||
|
.pathname
|
||||||
if (Bun.embeddedFiles.length > 0) {
|
if (Bun.embeddedFiles.length > 0) {
|
||||||
const blob = Bun.embeddedFiles[0] as File
|
const blob = Bun.embeddedFiles[0] as File
|
||||||
const binary = path.join(Global.Path.cache, "tui", blob.name)
|
const binary = path.join(Global.Path.cache, "tui", blob.name)
|
||||||
@@ -72,11 +71,26 @@ yargs(hideBin(process.argv))
|
|||||||
})
|
})
|
||||||
await proc.exited
|
await proc.exited
|
||||||
await server.stop()
|
await server.stop()
|
||||||
})
|
|
||||||
|
return "done"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (result === "done") break
|
||||||
|
if (result === "needs_provider") {
|
||||||
|
UI.logo()
|
||||||
|
await ProviderAddCommand.handler(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.command(RunCommand)
|
.command(RunCommand)
|
||||||
.command(GenerateCommand)
|
.command(GenerateCommand)
|
||||||
.command(ScrapCommand)
|
.command(ScrapCommand)
|
||||||
.command(ProviderCommand)
|
.command(ProviderCommand)
|
||||||
|
.fail((msg, err) => {
|
||||||
|
Log.Default.error(msg)
|
||||||
|
})
|
||||||
.parse()
|
.parse()
|
||||||
|
} catch (e) {
|
||||||
|
Log.Default.error(e)
|
||||||
|
}
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export namespace LSPClient {
|
|||||||
log.info("shutting down")
|
log.info("shutting down")
|
||||||
connection.end()
|
connection.end()
|
||||||
connection.dispose()
|
connection.dispose()
|
||||||
server.process.kill()
|
server.process.kill("SIGKILL")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export namespace LSPServer {
|
|||||||
".cts",
|
".cts",
|
||||||
],
|
],
|
||||||
async spawn(app) {
|
async spawn(app) {
|
||||||
const tsserver = Bun.resolve(
|
const tsserver = await Bun.resolve(
|
||||||
"typescript/lib/tsserver.js",
|
"typescript/lib/tsserver.js",
|
||||||
app.path.cwd,
|
app.path.cwd,
|
||||||
).catch(() => {})
|
).catch(() => {})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import path from "path"
|
|||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
export namespace Log {
|
export namespace Log {
|
||||||
const Default = create()
|
export const Default = create()
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
print: boolean
|
print: boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user