瀏覽代碼

Merge branch 'dev' into migrate-config

Dax 2 月之前
父節點
當前提交
bc7d8fe030

+ 5 - 0
CONTRIBUTING.md

@@ -24,6 +24,11 @@ If you are unsure if a PR would be accepted, feel free to ask a maintainer or lo
 
 Want to take on an issue? Leave a comment and a maintainer may assign it to you unless it is something we are already working on.
 
+## Adding New Providers
+
+New providers shouldn't require many if ANY code changes, but if you want to add support for a new provider first make a PR to:
+https://github.com/anomalyco/models.dev
+
 ## Developing OpenCode
 
 - Requirements: Bun 1.3+

+ 2 - 2
bun.lock

@@ -289,7 +289,7 @@
         "@ai-sdk/vercel": "1.0.33",
         "@ai-sdk/xai": "2.0.51",
         "@clack/prompts": "1.0.0-alpha.1",
-        "@gitlab/gitlab-ai-provider": "3.5.1",
+        "@gitlab/gitlab-ai-provider": "3.6.0",
         "@gitlab/opencode-gitlab-auth": "1.3.3",
         "@hono/standard-validator": "0.1.5",
         "@hono/zod-validator": "catalog:",
@@ -992,7 +992,7 @@
 
     "@fontsource/inter": ["@fontsource/[email protected]", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="],
 
-    "@gitlab/gitlab-ai-provider": ["@gitlab/gitlab-ai-provider@3.5.1", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-I8+EGdUeKmGJSjAdFobHtqpxM9Fm00w0j7NJbtln/D/XQ1SKEGoZIuqJko4v0pV2mkhGUIs7qezljH/2kbXovA=="],
+    "@gitlab/gitlab-ai-provider": ["@gitlab/gitlab-ai-provider@3.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-8LmcIQ86xkMtC7L4P1/QYVEC+yKMTRerfPeniaaQGalnzXKtX6iMHLjLPOL9Rxp55lOXi6ed0WrFuJzZx+fNRg=="],
 
     "@gitlab/opencode-gitlab-auth": ["@gitlab/[email protected]", "", { "dependencies": { "@fastify/rate-limit": "^10.2.0", "@opencode-ai/plugin": "*", "fastify": "^5.2.0", "open": "^10.0.0" } }, "sha512-FT+KsCmAJjtqWr1YAq0MywGgL9kaLQ4apmsoowAXrPqHtoYf2i/nY10/A+L06kNj22EATeEDRpbB1NWXMto/SA=="],
 

+ 4 - 4
nix/hashes.json

@@ -1,8 +1,8 @@
 {
   "nodeModules": {
-    "x86_64-linux": "sha256-BqHdoRCZt6DJStmbUkMbKWU4MLl6+Y3xNx81oI6mSLk=",
-    "aarch64-linux": "sha256-YIDQCSkVTvfGtJ6Ymc65gRX1HyI/uTwjK3rs8EPp39Y=",
-    "aarch64-darwin": "sha256-TYwPqlMq90S8R8ldPJ9qLMLRvOfQUwbV2ow9A28c3Yc=",
-    "x86_64-darwin": "sha256-KdsMP04/vQ9x1WGY8tdsnjUPqMIjmU9c2GxN4l+6XJo="
+    "x86_64-linux": "sha256-5sXHoHbRdXbqM/zRJZiXt26sm/yyyZN/4OOHUtdofhk=",
+    "aarch64-linux": "sha256-JCMm5X7e27BBV4wyaknCMM4CBt4Lr72SSvaGxEeNsJE=",
+    "aarch64-darwin": "sha256-DBQJURlTPqFt0OYUHSvZZ4H0NUf020aic4zNX5CXzDc=",
+    "x86_64-darwin": "sha256-t2luVxqCcRSgq/WNWkm4ZpKXO22n2RnAWP6msoTOr+A="
   }
 }

+ 9 - 5
packages/app/src/context/server.tsx

@@ -21,11 +21,12 @@ export function serverDisplayName(conn?: ServerConnection.Any) {
   return conn.http.url.replace(/^https?:\/\//, "").replace(/\/+$/, "")
 }
 
-function projectsKey(url: string) {
-  if (!url) return ""
-  const host = url.replace(/^https?:\/\//, "").split(":")[0]
+function projectsKey(key: ServerConnection.Key) {
+  if (!key) return ""
+  if (key === "sidecar") return "local"
+  const host = key.replace(/^https?:\/\//, "").split(":")[0]
   if (host === "localhost" || host === "127.0.0.1") return "local"
-  return url
+  return key
 }
 
 export namespace ServerConnection {
@@ -187,10 +188,13 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
 
     const origin = createMemo(() => projectsKey(state.active))
     const projectsList = createMemo(() => store.projects[origin()] ?? [])
-    const isLocal = createMemo(() => origin() === "local")
     const current: Accessor<ServerConnection.Any | undefined> = createMemo(
       () => allServers().find((s) => ServerConnection.key(s) === state.active) ?? allServers()[0],
     )
+    const isLocal = createMemo(() => {
+      const c = current()
+      return c?.type === "sidecar" && c.variant === "base"
+    })
 
     return {
       ready: isReady,

+ 1 - 1
packages/opencode/package.json

@@ -75,7 +75,7 @@
     "@ai-sdk/vercel": "1.0.33",
     "@ai-sdk/xai": "2.0.51",
     "@clack/prompts": "1.0.0-alpha.1",
-    "@gitlab/gitlab-ai-provider": "3.5.1",
+    "@gitlab/gitlab-ai-provider": "3.6.0",
     "@gitlab/opencode-gitlab-auth": "1.3.3",
     "@hono/standard-validator": "0.1.5",
     "@hono/zod-validator": "catalog:",

+ 4 - 13
packages/opencode/src/cli/cmd/session.ts

@@ -85,26 +85,17 @@ export const SessionListCommand = cmd({
   },
   handler: async (args) => {
     await bootstrap(process.cwd(), async () => {
-      const sessions = []
-      for await (const session of Session.list()) {
-        if (!session.parentID) {
-          sessions.push(session)
-        }
-      }
-
-      sessions.sort((a, b) => b.time.updated - a.time.updated)
-
-      const limitedSessions = args.maxCount ? sessions.slice(0, args.maxCount) : sessions
+      const sessions = [...Session.list({ roots: true, limit: args.maxCount })]
 
-      if (limitedSessions.length === 0) {
+      if (sessions.length === 0) {
         return
       }
 
       let output: string
       if (args.format === "json") {
-        output = formatSessionJSON(limitedSessions)
+        output = formatSessionJSON(sessions)
       } else {
-        output = formatSessionTable(limitedSessions)
+        output = formatSessionTable(sessions)
       }
 
       const shouldPaginate = process.stdout.isTTY && !args.maxCount && args.format === "table"

+ 6 - 6
packages/opencode/src/file/ripgrep.ts

@@ -6,6 +6,7 @@ import z from "zod"
 import { NamedError } from "@opencode-ai/util/error"
 import { lazy } from "../util/lazy"
 import { $ } from "bun"
+import { Filesystem } from "../util/filesystem"
 
 import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js"
 import { Log } from "@/util/log"
@@ -131,8 +132,7 @@ export namespace Ripgrep {
     }
     const filepath = path.join(Global.Path.bin, "rg" + (process.platform === "win32" ? ".exe" : ""))
 
-    const file = Bun.file(filepath)
-    if (!(await file.exists())) {
+    if (!(await Filesystem.exists(filepath))) {
       const platformKey = `${process.arch}-${process.platform}` as keyof typeof PLATFORM
       const config = PLATFORM[platformKey]
       if (!config) throw new UnsupportedPlatformError({ platform: platformKey })
@@ -144,9 +144,9 @@ export namespace Ripgrep {
       const response = await fetch(url)
       if (!response.ok) throw new DownloadFailedError({ url, status: response.status })
 
-      const buffer = await response.arrayBuffer()
+      const arrayBuffer = await response.arrayBuffer()
       const archivePath = path.join(Global.Path.bin, filename)
-      await Bun.write(archivePath, buffer)
+      await Filesystem.write(archivePath, Buffer.from(arrayBuffer))
       if (config.extension === "tar.gz") {
         const args = ["tar", "-xzf", archivePath, "--strip-components=1"]
 
@@ -166,7 +166,7 @@ export namespace Ripgrep {
           })
       }
       if (config.extension === "zip") {
-        const zipFileReader = new ZipReader(new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()])))
+        const zipFileReader = new ZipReader(new BlobReader(new Blob([arrayBuffer])))
         const entries = await zipFileReader.getEntries()
         let rgEntry: any
         for (const entry of entries) {
@@ -190,7 +190,7 @@ export namespace Ripgrep {
             stderr: "Failed to extract rg.exe from zip archive",
           })
         }
-        await Bun.write(filepath, await rgBlob.arrayBuffer())
+        await Filesystem.write(filepath, Buffer.from(await rgBlob.arrayBuffer()))
         await zipFileReader.close()
       }
       await fs.unlink(archivePath)

+ 2 - 1
packages/opencode/src/index.ts

@@ -13,6 +13,7 @@ import { Installation } from "./installation"
 import { NamedError } from "@opencode-ai/util/error"
 import { FormatError } from "./cli/error"
 import { ServeCommand } from "./cli/cmd/serve"
+import { Filesystem } from "./util/filesystem"
 import { DebugCommand } from "./cli/cmd/debug"
 import { StatsCommand } from "./cli/cmd/stats"
 import { McpCommand } from "./cli/cmd/mcp"
@@ -81,7 +82,7 @@ const cli = yargs(hideBin(process.argv))
     })
 
     const marker = path.join(Global.Path.data, "opencode.db")
-    if (!(await Bun.file(marker).exists())) {
+    if (!(await Filesystem.exists(marker))) {
       const tty = process.stderr.isTTY
       process.stderr.write("Performing one time database migration, may take a few minutes..." + EOL)
       const width = 36

+ 1 - 0
packages/opencode/src/lsp/language.ts

@@ -44,6 +44,7 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
   ".htm": "html",
   ".ini": "ini",
   ".java": "java",
+  ".jl": "julia",
   ".js": "javascript",
   ".kt": "kotlin",
   ".kts": "kotlin",

+ 18 - 0
packages/opencode/src/lsp/server.ts

@@ -2043,4 +2043,22 @@ export namespace LSPServer {
       }
     },
   }
+
+  export const JuliaLS: Info = {
+    id: "julials",
+    extensions: [".jl"],
+    root: NearestRoot(["Project.toml", "Manifest.toml", "*.jl"]),
+    async spawn(root) {
+      const julia = Bun.which("julia")
+      if (!julia) {
+        log.info("julia not found, please install julia first (https://julialang.org/downloads/)")
+        return
+      }
+      return {
+        process: spawn(julia, ["--startup-file=no", "--history-file=no", "-e", "using LanguageServer; runserver()"], {
+          cwd: root,
+        }),
+      }
+    },
+  }
 }

+ 1 - 0
packages/web/src/content/docs/lsp.mdx

@@ -27,6 +27,7 @@ OpenCode comes with several built-in LSP servers for popular languages:
 | gopls              | .go                                                                 | `go` command available                                       |
 | hls                | .hs, .lhs                                                           | `haskell-language-server-wrapper` command available          |
 | jdtls              | .java                                                               | `Java SDK (version 21+)` installed                           |
+| julials            | .jl                                                                 | `julia` and `LanguageServer.jl` installed                    |
 | kotlin-ls          | .kt, .kts                                                           | Auto-installs for Kotlin projects                            |
 | lua-ls             | .lua                                                                | Auto-installs for Lua projects                               |
 | nixd               | .nix                                                                | `nixd` command available                                     |