summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/opencode/src/app/app.ts12
-rw-r--r--packages/opencode/src/cli/cmd/generate.ts1
-rw-r--r--packages/opencode/src/cli/cmd/run.ts2
-rw-r--r--packages/opencode/src/cli/cmd/scrap.ts12
-rw-r--r--packages/opencode/src/cli/cmd/upgrade.ts67
-rw-r--r--packages/opencode/src/cli/version.ts6
-rw-r--r--packages/opencode/src/external/ripgrep.ts1
-rw-r--r--packages/opencode/src/file/index.ts10
-rw-r--r--packages/opencode/src/index.ts111
-rw-r--r--packages/opencode/src/installation/index.ts14
-rw-r--r--packages/opencode/src/server/server.ts1
-rw-r--r--packages/opencode/src/storage/storage.ts2
-rw-r--r--packages/opencode/src/tool/patch.ts1
-rw-r--r--packages/opencode/src/util/error.ts19
-rw-r--r--packages/opencode/test/tool/tool.test.ts45
15 files changed, 123 insertions, 181 deletions
diff --git a/packages/opencode/src/app/app.ts b/packages/opencode/src/app/app.ts
index e240fa6bf..32ffea9e4 100644
--- a/packages/opencode/src/app/app.ts
+++ b/packages/opencode/src/app/app.ts
@@ -5,6 +5,7 @@ import { Global } from "../global"
import path from "path"
import os from "os"
import { z } from "zod"
+import { Installation } from "../installation"
export namespace App {
const log = Log.create({ service: "app" })
@@ -32,7 +33,7 @@ export namespace App {
const APP_JSON = "app.json"
- async function create(input: { cwd: string; version: string }) {
+ async function create(input: { cwd: string }) {
log.info("creating", {
cwd: input.cwd,
})
@@ -51,7 +52,7 @@ export namespace App {
initialized: number
version: string
}
- state.version = input.version
+ state.version = Installation.VERSION
await stateFile.write(JSON.stringify(state))
const services = new Map<
@@ -76,7 +77,6 @@ export namespace App {
},
}
const result = {
- version: input.version,
services,
info,
}
@@ -108,7 +108,7 @@ export namespace App {
}
export async function provide<T>(
- input: { cwd: string; version: string },
+ input: { cwd: string },
cb: (app: Info) => Promise<T>,
) {
const app = await create(input)
@@ -124,12 +124,12 @@ export namespace App {
}
export async function initialize() {
- const { info, version } = ctx.use()
+ const { info } = ctx.use()
info.time.initialized = Date.now()
await Bun.write(
path.join(info.path.data, APP_JSON),
JSON.stringify({
- version,
+ version: Installation.VERSION,
initialized: Date.now(),
}),
)
diff --git a/packages/opencode/src/cli/cmd/generate.ts b/packages/opencode/src/cli/cmd/generate.ts
index 2e7dcf8df..0cef10772 100644
--- a/packages/opencode/src/cli/cmd/generate.ts
+++ b/packages/opencode/src/cli/cmd/generate.ts
@@ -2,7 +2,6 @@ import { Server } from "../../server/server"
import fs from "fs/promises"
import path from "path"
import type { CommandModule } from "yargs"
-import { Config } from "../../config/config"
export const GenerateCommand = {
command: "generate",
diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts
index 16bd3f3b7..77e2a6873 100644
--- a/packages/opencode/src/cli/cmd/run.ts
+++ b/packages/opencode/src/cli/cmd/run.ts
@@ -6,7 +6,6 @@ import { Session } from "../../session"
import { Share } from "../../share/share"
import { Message } from "../../session/message"
import { UI } from "../ui"
-import { VERSION } from "../version"
import { cmd } from "./cmd"
import { GlobalConfig } from "../../global/config"
import { Flag } from "../../flag/flag"
@@ -48,7 +47,6 @@ export const RunCommand = cmd({
await App.provide(
{
cwd: process.cwd(),
- version: VERSION,
},
async () => {
await Share.init()
diff --git a/packages/opencode/src/cli/cmd/scrap.ts b/packages/opencode/src/cli/cmd/scrap.ts
index c0dbf73f4..03b69d4e8 100644
--- a/packages/opencode/src/cli/cmd/scrap.ts
+++ b/packages/opencode/src/cli/cmd/scrap.ts
@@ -1,6 +1,5 @@
import { App } from "../../app/app"
import { LSP } from "../../lsp"
-import { VERSION } from "../version"
import { cmd } from "./cmd"
export const ScrapCommand = cmd({
@@ -8,9 +7,12 @@ export const ScrapCommand = cmd({
builder: (yargs) =>
yargs.positional("file", { type: "string", demandOption: true }),
async handler(args) {
- await App.provide({ cwd: process.cwd(), version: VERSION }, async (app) => {
- await LSP.touchFile(args.file, true)
- console.log(await LSP.diagnostics())
- })
+ await App.provide(
+ { cwd: process.cwd() },
+ async () => {
+ await LSP.touchFile(args.file, true)
+ console.log(await LSP.diagnostics())
+ },
+ )
},
})
diff --git a/packages/opencode/src/cli/cmd/upgrade.ts b/packages/opencode/src/cli/cmd/upgrade.ts
index 2310becab..f2b0cf219 100644
--- a/packages/opencode/src/cli/cmd/upgrade.ts
+++ b/packages/opencode/src/cli/cmd/upgrade.ts
@@ -1,6 +1,5 @@
import type { Argv } from "yargs"
import { UI } from "../ui"
-import { VERSION } from "../version"
import * as prompts from "@clack/prompts"
import { Installation } from "../../installation"
@@ -27,7 +26,7 @@ export const UpgradeCommand = {
return
}
const target = args.target ?? (await Installation.latest())
- prompts.log.info(`From ${VERSION} → ${target}`)
+ prompts.log.info(`From ${Installation.VERSION} → ${target}`)
const spinner = prompts.spinner()
spinner.start("Upgrading...")
const err = await Installation.upgrade(method, target).catch((err) => err)
@@ -41,69 +40,5 @@ export const UpgradeCommand = {
}
spinner.stop("Upgrade complete")
prompts.outro("Done")
- return
-
- /*
- if (!process.execPath.includes(path.join(".opencode", "bin")) && false) {
- return
- }
-
- const release = args.target
- ? await specific(args.target).catch(() => {})
- : await latest().catch(() => {})
- if (!release) {
- prompts.log.error("Failed to fetch release information")
- prompts.outro("Done")
- return
- }
-
- const target = release.tag_name
-
- if (VERSION !== "dev" && compare(VERSION, target) >= 0) {
- prompts.log.success(`Already up to date`)
- prompts.outro("Done")
- return
- }
-
- prompts.log.info(`From ${VERSION} → ${target}`)
-
- const name = asset()
- const found = release.assets.find((a) => a.name === name)
-
- if (!found) {
- prompts.log.error(`No binary found for platform: ${name}`)
- prompts.outro("Done")
- return
- }
-
- const spinner = prompts.spinner()
- spinner.start("Downloading update...")
-
- const downloadPath = await download(found.browser_download_url).catch(
- () => {},
- )
- if (!downloadPath) {
- spinner.stop("Download failed")
- prompts.log.error("Download failed")
- prompts.outro("Done")
- return
- }
-
- spinner.stop("Download complete")
-
- const renamed = await fs
- .rename(downloadPath, process.execPath)
- .catch(() => {})
-
- if (renamed === undefined) {
- prompts.log.error("Install failed")
- await fs.unlink(downloadPath).catch(() => {})
- prompts.outro("Done")
- return
- }
-
- prompts.log.success(`Successfully upgraded to ${target}`)
- prompts.outro("Done")
- */
},
}
diff --git a/packages/opencode/src/cli/version.ts b/packages/opencode/src/cli/version.ts
deleted file mode 100644
index 43dc9745d..000000000
--- a/packages/opencode/src/cli/version.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-declare global {
- const OPENCODE_VERSION: string
-}
-
-export const VERSION =
- typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "dev"
diff --git a/packages/opencode/src/external/ripgrep.ts b/packages/opencode/src/external/ripgrep.ts
index 5d627dba5..4bc9519fb 100644
--- a/packages/opencode/src/external/ripgrep.ts
+++ b/packages/opencode/src/external/ripgrep.ts
@@ -1,4 +1,3 @@
-import { App } from "../app/app"
import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts
deleted file mode 100644
index b26a890ce..000000000
--- a/packages/opencode/src/file/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export namespace File {
- const glob = new Bun.Glob("**/*")
- export async function search(path: string, query: string) {
- for await (const entry of glob.scan({
- cwd: path,
- onlyFiles: true,
- })) {
- }
- }
-}
diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts
index cb4bffe00..287d6270e 100644
--- a/packages/opencode/src/index.ts
+++ b/packages/opencode/src/index.ts
@@ -9,7 +9,6 @@ import yargs from "yargs"
import { hideBin } from "yargs/helpers"
import { RunCommand } from "./cli/cmd/run"
import { GenerateCommand } from "./cli/cmd/generate"
-import { VERSION } from "./cli/version"
import { ScrapCommand } from "./cli/cmd/scrap"
import { Log } from "./util/log"
import { AuthCommand, AuthLoginCommand } from "./cli/cmd/auth"
@@ -18,21 +17,11 @@ import { Provider } from "./provider/provider"
import { UI } from "./cli/ui"
import { GlobalConfig } from "./global/config"
import { Installation } from "./installation"
-;(async () => {
- if (Installation.VERSION === "dev") return
- if (Installation.isSnapshot()) return
- const config = await GlobalConfig.get()
- if (config.autoupdate === false) return
- const latest = await Installation.latest()
- if (Installation.VERSION === latest) return
- const method = await Installation.method()
- if (method === "unknown") return
- await Installation.upgrade(method, latest).catch(() => {})
-})()
+import { Bus } from "./bus"
const cli = yargs(hideBin(process.argv))
.scriptName("opencode")
- .version(VERSION)
+ .version(Installation.VERSION)
.option("print-logs", {
describe: "Print logs to stderr",
type: "boolean",
@@ -40,7 +29,7 @@ const cli = yargs(hideBin(process.argv))
.middleware(async () => {
await Log.init({ print: process.argv.includes("--print-logs") })
Log.Default.info("opencode", {
- version: VERSION,
+ version: Installation.VERSION,
args: process.argv.slice(2),
})
})
@@ -57,52 +46,62 @@ const cli = yargs(hideBin(process.argv))
while (true) {
const cwd = args.project ? path.resolve(args.project) : process.cwd()
process.chdir(cwd)
- const result = await App.provide(
- { cwd, version: VERSION },
- async (app) => {
- const providers = await Provider.list()
- if (Object.keys(providers).length === 0) {
- return "needs_provider"
- }
+ const result = await App.provide({ cwd }, async (app) => {
+ const providers = await Provider.list()
+ if (Object.keys(providers).length === 0) {
+ return "needs_provider"
+ }
- await Share.init()
- const server = Server.listen()
+ await Share.init()
+ const server = Server.listen()
- let cmd = ["go", "run", "./main.go"]
- let cwd = new URL("../../tui/cmd/opencode", import.meta.url)
- .pathname
- if (Bun.embeddedFiles.length > 0) {
- const blob = Bun.embeddedFiles[0] as File
- const binary = path.join(Global.Path.cache, "tui", blob.name)
- const file = Bun.file(binary)
- if (!(await file.exists())) {
- await Bun.write(file, blob, { mode: 0o755 })
- await fs.chmod(binary, 0o755)
- }
- cwd = process.cwd()
- cmd = [binary]
+ let cmd = ["go", "run", "./main.go"]
+ let cwd = new URL("../../tui/cmd/opencode", import.meta.url).pathname
+ if (Bun.embeddedFiles.length > 0) {
+ const blob = Bun.embeddedFiles[0] as File
+ const binary = path.join(Global.Path.cache, "tui", blob.name)
+ const file = Bun.file(binary)
+ if (!(await file.exists())) {
+ await Bun.write(file, blob, { mode: 0o755 })
+ await fs.chmod(binary, 0o755)
}
- const proc = Bun.spawn({
- cmd: [...cmd, ...process.argv.slice(2)],
- cwd,
- stdout: "inherit",
- stderr: "inherit",
- stdin: "inherit",
- env: {
- ...process.env,
- OPENCODE_SERVER: server.url.toString(),
- OPENCODE_APP_INFO: JSON.stringify(app),
- },
- onExit: () => {
- server.stop()
- },
- })
- await proc.exited
- await server.stop()
+ cwd = process.cwd()
+ cmd = [binary]
+ }
+ const proc = Bun.spawn({
+ cmd: [...cmd, ...process.argv.slice(2)],
+ cwd,
+ stdout: "inherit",
+ stderr: "inherit",
+ stdin: "inherit",
+ env: {
+ ...process.env,
+ OPENCODE_SERVER: server.url.toString(),
+ OPENCODE_APP_INFO: JSON.stringify(app),
+ },
+ onExit: () => {
+ server.stop()
+ },
+ })
+
+ ;(async () => {
+ if (Installation.VERSION === "dev") return
+ if (Installation.isSnapshot()) return
+ const config = await GlobalConfig.get()
+ if (config.autoupdate === false) return
+ const latest = await Installation.latest()
+ if (Installation.VERSION === latest) return
+ const method = await Installation.method()
+ if (method === "unknown") return
+ await Installation.upgrade(method, latest).catch(() => {})
+ Bus.publish(Installation.Event.Updated, { version: latest })
+ })()
+
+ await proc.exited
+ await server.stop()
- return "done"
- },
- )
+ return "done"
+ })
if (result === "done") break
if (result === "needs_provider") {
UI.empty()
diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts
index 335a8adee..54d50cc37 100644
--- a/packages/opencode/src/installation/index.ts
+++ b/packages/opencode/src/installation/index.ts
@@ -2,10 +2,24 @@ import path from "path"
import { $ } from "bun"
import { z } from "zod"
import { NamedError } from "../util/error"
+import { Bus } from "../bus"
+
+declare global {
+ const OPENCODE_VERSION: string
+}
export namespace Installation {
export type Method = Awaited<ReturnType<typeof method>>
+ export const Event = {
+ Updated: Bus.event(
+ "installation.updated",
+ z.object({
+ version: z.string(),
+ }),
+ ),
+ }
+
export const Info = z
.object({
version: z.string(),
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index 30c761733..e28ae1d19 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -12,7 +12,6 @@ import { App } from "../app/app"
import { Global } from "../global"
import { mapValues } from "remeda"
import { NamedError } from "../util/error"
-import { Fzf } from "../external/fzf"
import { ModelsDev } from "../provider/models"
import { Ripgrep } from "../external/ripgrep"
import { Installation } from "../installation"
diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts
index ab185cafc..5dc3de85f 100644
--- a/packages/opencode/src/storage/storage.ts
+++ b/packages/opencode/src/storage/storage.ts
@@ -24,8 +24,6 @@ export namespace Storage {
}
})
- const locks = new Map<string, Promise<void>>()
-
export async function readJSON<T>(key: string) {
return Bun.file(path.join(state().dir, key + ".json")).json() as Promise<T>
}
diff --git a/packages/opencode/src/tool/patch.ts b/packages/opencode/src/tool/patch.ts
index 41f7a2cc8..5d6ebb590 100644
--- a/packages/opencode/src/tool/patch.ts
+++ b/packages/opencode/src/tool/patch.ts
@@ -4,7 +4,6 @@ import * as fs from "fs/promises"
import { Tool } from "./tool"
import { FileTimes } from "./util/file-times"
import DESCRIPTION from "./patch.txt"
-import { App } from "../app/app"
const PatchParams = z.object({
patchText: z
diff --git a/packages/opencode/src/util/error.ts b/packages/opencode/src/util/error.ts
index 3b2d164be..d8de15832 100644
--- a/packages/opencode/src/util/error.ts
+++ b/packages/opencode/src/util/error.ts
@@ -11,15 +11,16 @@ export abstract class NamedError extends Error {
name: Name,
data: Data,
) {
+ const schema = z
+ .object({
+ name: z.literal(name),
+ data,
+ })
+ .openapi({
+ ref: name,
+ })
const result = class extends NamedError {
- public static readonly Schema = z
- .object({
- name: z.literal(name),
- data: data,
- })
- .openapi({
- ref: name,
- })
+ public static readonly Schema = schema
public readonly name = name as Name
@@ -40,7 +41,7 @@ export abstract class NamedError extends Error {
}
schema() {
- return result.Schema
+ return schema
}
toObject() {
diff --git a/packages/opencode/test/tool/tool.test.ts b/packages/opencode/test/tool/tool.test.ts
index 749d4ae62..273e725c2 100644
--- a/packages/opencode/test/tool/tool.test.ts
+++ b/packages/opencode/test/tool/tool.test.ts
@@ -5,19 +5,33 @@ import { ListTool } from "../../src/tool/ls"
describe("tool.glob", () => {
test("truncate", async () => {
- await App.provide({ cwd: process.cwd(), version: "test" }, async () => {
+ await App.provide({ cwd: process.cwd() }, async () => {
let result = await GlobTool.execute(
- { pattern: "./node_modules/**/*" },
- { sessionID: "test" },
+ {
+ pattern: "./node_modules/**/*",
+ path: null,
+ },
+ {
+ sessionID: "test",
+ messageID: "",
+ abort: AbortSignal.any([]),
+ },
)
expect(result.metadata.truncated).toBe(true)
})
})
test("basic", async () => {
- await App.provide({ cwd: process.cwd(), version: "test" }, async () => {
+ await App.provide({ cwd: process.cwd() }, async () => {
let result = await GlobTool.execute(
- { pattern: "*.json" },
- { sessionID: "test" },
+ {
+ pattern: "*.json",
+ path: null,
+ },
+ {
+ sessionID: "test",
+ messageID: "",
+ abort: AbortSignal.any([]),
+ },
)
expect(result.metadata).toMatchObject({
truncated: false,
@@ -29,15 +43,16 @@ describe("tool.glob", () => {
describe("tool.ls", () => {
test("basic", async () => {
- const result = await App.provide(
- { cwd: process.cwd(), version: "test" },
- async () => {
- return await ListTool.execute(
- { path: "./example" },
- { sessionID: "test" },
- )
- },
- )
+ const result = await App.provide({ cwd: process.cwd() }, async () => {
+ return await ListTool.execute(
+ { path: "./example", ignore: [".git"] },
+ {
+ sessionID: "test",
+ messageID: "",
+ abort: AbortSignal.any([]),
+ },
+ )
+ })
expect(result.output).toMatchSnapshot()
})
})