Просмотр исходного кода

Fix TypeScript compilation errors and consolidate version handling

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
Dax Raad 8 месяцев назад
Родитель
Сommit
68e1b3c46c

+ 6 - 6
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(),
       }),
     )

+ 0 - 1
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",

+ 0 - 2
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()

+ 7 - 5
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())
+      },
+    )
   },
 })

+ 1 - 66
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")
-    */
   },
 }

+ 0 - 6
packages/opencode/src/cli/version.ts

@@ -1,6 +0,0 @@
-declare global {
-  const OPENCODE_VERSION: string
-}
-
-export const VERSION =
-  typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "dev"

+ 0 - 1
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"

+ 0 - 10
packages/opencode/src/file/index.ts

@@ -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,
-    })) {
-    }
-  }
-}

+ 55 - 56
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()

+ 14 - 0
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(),

+ 0 - 1
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"

+ 0 - 2
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>
   }

+ 0 - 1
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

+ 10 - 9
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() {

+ 30 - 15
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()
   })
 })