core: cleaner error output and more flexible custom tool directories
- Removed debug console.log when dependency installation fails so users see clean warning messages instead of raw error dumps - Fixed database connection cleanup to prevent resource leaks between sessions - Added support for loading custom tools from both .opencode/tool (singular) and .opencode/tools (plural) directories, matching common naming conventions
This commit is contained in:
parent
5f277d1e62
commit
21e72cbf42
3 changed files with 112 additions and 42 deletions
|
|
@ -288,7 +288,6 @@ export namespace Config {
|
||||||
// Install any additional dependencies defined in the package.json
|
// Install any additional dependencies defined in the package.json
|
||||||
// This allows local plugins and custom tools to use external packages
|
// This allows local plugins and custom tools to use external packages
|
||||||
await Npm.install(dir).catch((err: any) => {
|
await Npm.install(dir).catch((err: any) => {
|
||||||
console.log(err)
|
|
||||||
log.warn("failed to install dependencies", { dir, error: err.message })
|
log.warn("failed to install dependencies", { dir, error: err.message })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ export namespace Database {
|
||||||
|
|
||||||
export function close() {
|
export function close() {
|
||||||
Client().$client.close()
|
Client().$client.close()
|
||||||
|
Client.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TxOrDb = Transaction | Client
|
export type TxOrDb = Transaction | Client
|
||||||
|
|
|
||||||
|
|
@ -5,48 +5,118 @@ import { tmpdir } from "../fixture/fixture"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { ToolRegistry } from "../../src/tool/registry"
|
import { ToolRegistry } from "../../src/tool/registry"
|
||||||
|
|
||||||
test("loads tools with external dependencies without crashing", async () => {
|
describe("tool.registry", () => {
|
||||||
await using tmp = await tmpdir({
|
test("loads tools from .opencode/tool (singular)", async () => {
|
||||||
init: async (dir) => {
|
await using tmp = await tmpdir({
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
init: async (dir) => {
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
const opencodeDir = path.join(dir, ".opencode")
|
||||||
|
await fs.mkdir(opencodeDir, { recursive: true })
|
||||||
|
|
||||||
const toolsDir = path.join(opencodeDir, "tools")
|
const toolDir = path.join(opencodeDir, "tool")
|
||||||
await fs.mkdir(toolsDir, { recursive: true })
|
await fs.mkdir(toolDir, { recursive: true })
|
||||||
|
|
||||||
await Bun.write(
|
await Bun.write(
|
||||||
path.join(opencodeDir, "package.json"),
|
path.join(toolDir, "hello.ts"),
|
||||||
JSON.stringify({
|
[
|
||||||
name: "custom-tools",
|
"export default {",
|
||||||
dependencies: {
|
" description: 'hello tool',",
|
||||||
"@opencode-ai/plugin": "^0.0.0",
|
" args: {},",
|
||||||
cowsay: "^1.6.0",
|
" execute: async () => {",
|
||||||
},
|
" return 'hello world'",
|
||||||
}),
|
" },",
|
||||||
)
|
"}",
|
||||||
|
"",
|
||||||
|
].join("\n"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
await Bun.write(
|
await Instance.provide({
|
||||||
path.join(toolsDir, "cowsay.ts"),
|
directory: tmp.path,
|
||||||
[
|
fn: async () => {
|
||||||
"import { say } from 'cowsay'",
|
const ids = await ToolRegistry.ids()
|
||||||
"export default {",
|
expect(ids).toContain("hello")
|
||||||
" description: 'tool that imports cowsay at top level',",
|
},
|
||||||
" args: { text: { type: 'string' } },",
|
})
|
||||||
" execute: async ({ text }: { text: string }) => {",
|
|
||||||
" return say({ text })",
|
|
||||||
" },",
|
|
||||||
"}",
|
|
||||||
"",
|
|
||||||
].join("\n"),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await Instance.provide({
|
test("loads tools from .opencode/tools (plural)", async () => {
|
||||||
directory: tmp.path,
|
await using tmp = await tmpdir({
|
||||||
fn: async () => {
|
init: async (dir) => {
|
||||||
const ids = await ToolRegistry.ids()
|
const opencodeDir = path.join(dir, ".opencode")
|
||||||
expect(ids).toContain("cowsay")
|
await fs.mkdir(opencodeDir, { recursive: true })
|
||||||
},
|
|
||||||
|
const toolsDir = path.join(opencodeDir, "tools")
|
||||||
|
await fs.mkdir(toolsDir, { recursive: true })
|
||||||
|
|
||||||
|
await Bun.write(
|
||||||
|
path.join(toolsDir, "hello.ts"),
|
||||||
|
[
|
||||||
|
"export default {",
|
||||||
|
" description: 'hello tool',",
|
||||||
|
" args: {},",
|
||||||
|
" execute: async () => {",
|
||||||
|
" return 'hello world'",
|
||||||
|
" },",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
].join("\n"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const ids = await ToolRegistry.ids()
|
||||||
|
expect(ids).toContain("hello")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("loads tools with external dependencies without crashing", async () => {
|
||||||
|
await using tmp = await tmpdir({
|
||||||
|
init: async (dir) => {
|
||||||
|
const opencodeDir = path.join(dir, ".opencode")
|
||||||
|
await fs.mkdir(opencodeDir, { recursive: true })
|
||||||
|
|
||||||
|
const toolsDir = path.join(opencodeDir, "tools")
|
||||||
|
await fs.mkdir(toolsDir, { recursive: true })
|
||||||
|
|
||||||
|
await Bun.write(
|
||||||
|
path.join(opencodeDir, "package.json"),
|
||||||
|
JSON.stringify({
|
||||||
|
name: "custom-tools",
|
||||||
|
dependencies: {
|
||||||
|
"@opencode-ai/plugin": "^0.0.0",
|
||||||
|
cowsay: "^1.6.0",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
await Bun.write(
|
||||||
|
path.join(toolsDir, "cowsay.ts"),
|
||||||
|
[
|
||||||
|
"import { say } from 'cowsay'",
|
||||||
|
"export default {",
|
||||||
|
" description: 'tool that imports cowsay at top level',",
|
||||||
|
" args: { text: { type: 'string' } },",
|
||||||
|
" execute: async ({ text }: { text: string }) => {",
|
||||||
|
" return say({ text })",
|
||||||
|
" },",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
].join("\n"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const ids = await ToolRegistry.ids()
|
||||||
|
expect(ids).toContain("cowsay")
|
||||||
|
},
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue