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

Fix: Error [ERR_DLOPEN_FAILED] (#1546)

Yuu Toriyama 6 месяцев назад
Родитель
Сommit
3f0f910f7b

+ 1 - 1
.github/workflows/deploy.yml

@@ -17,7 +17,7 @@ jobs:
 
       - uses: oven-sh/setup-bun@v1
         with:
-          bun-version: 1.2.17
+          bun-version: 1.2.19
 
       - run: bun install
 

+ 1 - 1
.github/workflows/publish-vscode.yml

@@ -21,7 +21,7 @@ jobs:
 
       - uses: oven-sh/setup-bun@v2
         with:
-          bun-version: 1.2.17
+          bun-version: 1.2.19
 
       - run: git fetch --force --tags
       - run: bun install -g @vscode/vsce

+ 6 - 0
bun.lock

@@ -113,6 +113,7 @@
         "tree-sitter-bash": "0.23.3",
         "turndown": "7.2.0",
         "vscode-jsonrpc": "8.2.1",
+        "web-tree-sitter": "0.22.6",
         "xdg-basedir": "5.1.0",
         "yargs": "18.0.0",
         "zod": "catalog:",
@@ -189,6 +190,9 @@
     "sharp",
     "esbuild",
     "protobufjs",
+    "tree-sitter",
+    "web-tree-sitter",
+    "tree-sitter-bash",
   ],
   "catalog": {
     "@hono/zod-validator": "0.4.2",
@@ -2481,6 +2485,8 @@
 
     "web-namespaces": ["[email protected]", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
 
+    "web-tree-sitter": ["[email protected]", "", {}, "sha512-hS87TH71Zd6mGAmYCvlgxeGDjqd9GTeqXNqTT+u0Gs51uIozNIaaq/kUAbV/Zf56jb2ZOyG8BxZs2GG9wbLi6Q=="],
+
     "webidl-conversions": ["[email protected]", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
 
     "whatwg-url": ["[email protected]", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],

+ 5 - 2
package.json

@@ -3,7 +3,7 @@
   "name": "opencode",
   "private": true,
   "type": "module",
-  "packageManager": "[email protected]4",
+  "packageManager": "[email protected]9",
   "scripts": {
     "dev": "bun run --conditions=development packages/opencode/src/index.ts",
     "typecheck": "bun run --filter='*' typecheck",
@@ -46,7 +46,10 @@
   "trustedDependencies": [
     "esbuild",
     "protobufjs",
-    "sharp"
+    "sharp",
+    "tree-sitter",
+    "tree-sitter-bash",
+    "web-tree-sitter"
   ],
   "patchedDependencies": {}
 }

+ 1 - 0
packages/opencode/package.json

@@ -52,6 +52,7 @@
     "remeda": "catalog:",
     "tree-sitter": "0.22.4",
     "tree-sitter-bash": "0.23.3",
+    "web-tree-sitter": "0.22.6",
     "turndown": "7.2.0",
     "vscode-jsonrpc": "8.2.1",
     "xdg-basedir": "5.1.0",

+ 22 - 5
packages/opencode/src/tool/bash.ts

@@ -19,11 +19,28 @@ const MAX_TIMEOUT = 10 * 60 * 1000
 const log = Log.create({ service: "bash-tool" })
 
 const parser = lazy(async () => {
-  const { default: Parser } = await import("tree-sitter")
-  const Bash = await import("tree-sitter-bash")
-  const p = new Parser()
-  p.setLanguage(Bash.language as any)
-  return p
+  try {
+    const { default: Parser } = await import("tree-sitter")
+    const Bash = await import("tree-sitter-bash")
+    const p = new Parser()
+    p.setLanguage(Bash.language as any)
+    return p
+  } catch (e) {
+    const { default: Parser } = await import("web-tree-sitter")
+    const { default: treeWasm } = await import("web-tree-sitter/tree-sitter.wasm" as string, { with: { type: "wasm" } })
+    await Parser.init({
+      locateFile() {
+        return treeWasm
+      },
+    })
+    const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, {
+      with: { type: "wasm" },
+    })
+    const bashLanguage = await Parser.Language.load(bashWasm)
+    const p = new Parser()
+    p.setLanguage(bashLanguage)
+    return p
+  }
 })
 
 export const BashTool = Tool.define("bash", {

+ 43 - 26
packages/opencode/src/tool/test.ts

@@ -1,53 +1,70 @@
-import Parser from "tree-sitter";
-import Bash from "tree-sitter-bash";
-
-const parser = new Parser();
-parser.setLanguage(Bash.language as any);
+const parser = async () => {
+  try {
+    const { default: Parser } = await import("tree-sitter")
+    const Bash = await import("tree-sitter-bash")
+    const p = new Parser()
+    p.setLanguage(Bash.language as any)
+    return p
+  } catch (e) {
+    const { default: Parser } = await import("web-tree-sitter")
+    const { default: treeWasm } = await import("web-tree-sitter/tree-sitter.wasm" as string, { with: { type: "wasm" } })
+    await Parser.init({
+      locateFile() {
+        return treeWasm
+      },
+    })
+    const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, {
+      with: { type: "wasm" },
+    })
+    const bashLanguage = await Parser.Language.load(bashWasm)
+    const p = new Parser()
+    p.setLanguage(bashLanguage)
+    return p
+  }
+}
 
-const sourceCode = `cd --foo foo/bar && echo "hello" && cd ../baz`;
+const sourceCode = `cd --foo foo/bar && echo "hello" && cd ../baz`
 
-const tree = parser.parse(sourceCode);
+const tree = await parser().then((p) => p.parse(sourceCode))
 
 // Function to extract commands and arguments
-function extractCommands(
-  node: any,
-): Array<{ command: string; args: string[] }> {
-  const commands: Array<{ command: string; args: string[] }> = [];
+function extractCommands(node: any): Array<{ command: string; args: string[] }> {
+  const commands: Array<{ command: string; args: string[] }> = []
 
   function traverse(node: any) {
     if (node.type === "command") {
-      const commandNode = node.child(0);
+      const commandNode = node.child(0)
       if (commandNode) {
-        const command = commandNode.text;
-        const args: string[] = [];
+        const command = commandNode.text
+        const args: string[] = []
 
         // Extract arguments
         for (let i = 1; i < node.childCount; i++) {
-          const child = node.child(i);
+          const child = node.child(i)
           if (child && child.type === "word") {
-            args.push(child.text);
+            args.push(child.text)
           }
         }
 
-        commands.push({ command, args });
+        commands.push({ command, args })
       }
     }
 
     // Traverse children
     for (let i = 0; i < node.childCount; i++) {
-      traverse(node.child(i));
+      traverse(node.child(i))
     }
   }
 
-  traverse(node);
-  return commands;
+  traverse(node)
+  return commands
 }
 
 // Extract and display commands
-console.log("Source code: " + sourceCode);
-const commands = extractCommands(tree.rootNode);
-console.log("Extracted commands:");
+console.log("Source code: " + sourceCode)
+const commands = extractCommands(tree.rootNode)
+console.log("Extracted commands:")
 commands.forEach((cmd, index) => {
-  console.log(`${index + 1}. Command: ${cmd.command}`);
-  console.log(`   Args: [${cmd.args.join(", ")}]`);
-});
+  console.log(`${index + 1}. Command: ${cmd.command}`)
+  console.log(`   Args: [${cmd.args.join(", ")}]`)
+})