registry.test.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { describe, expect, test } from "bun:test"
  2. import path from "path"
  3. import fs from "fs/promises"
  4. import { tmpdir } from "../fixture/fixture"
  5. import { Instance } from "../../src/project/instance"
  6. import { ToolRegistry } from "../../src/tool/registry"
  7. describe("tool.registry", () => {
  8. test("loads tools from .opencode/tool (singular)", async () => {
  9. await using tmp = await tmpdir({
  10. init: async (dir) => {
  11. const opencodeDir = path.join(dir, ".opencode")
  12. await fs.mkdir(opencodeDir, { recursive: true })
  13. const toolDir = path.join(opencodeDir, "tool")
  14. await fs.mkdir(toolDir, { recursive: true })
  15. await Bun.write(
  16. path.join(toolDir, "hello.ts"),
  17. [
  18. "export default {",
  19. " description: 'hello tool',",
  20. " args: {},",
  21. " execute: async () => {",
  22. " return 'hello world'",
  23. " },",
  24. "}",
  25. "",
  26. ].join("\n"),
  27. )
  28. },
  29. })
  30. await Instance.provide({
  31. directory: tmp.path,
  32. fn: async () => {
  33. const ids = await ToolRegistry.ids()
  34. expect(ids).toContain("hello")
  35. },
  36. })
  37. })
  38. test("loads tools from .opencode/tools (plural)", async () => {
  39. await using tmp = await tmpdir({
  40. init: async (dir) => {
  41. const opencodeDir = path.join(dir, ".opencode")
  42. await fs.mkdir(opencodeDir, { recursive: true })
  43. const toolsDir = path.join(opencodeDir, "tools")
  44. await fs.mkdir(toolsDir, { recursive: true })
  45. await Bun.write(
  46. path.join(toolsDir, "hello.ts"),
  47. [
  48. "export default {",
  49. " description: 'hello tool',",
  50. " args: {},",
  51. " execute: async () => {",
  52. " return 'hello world'",
  53. " },",
  54. "}",
  55. "",
  56. ].join("\n"),
  57. )
  58. },
  59. })
  60. await Instance.provide({
  61. directory: tmp.path,
  62. fn: async () => {
  63. const ids = await ToolRegistry.ids()
  64. expect(ids).toContain("hello")
  65. },
  66. })
  67. })
  68. test("loads tools with external dependencies without crashing", async () => {
  69. await using tmp = await tmpdir({
  70. init: async (dir) => {
  71. const opencodeDir = path.join(dir, ".opencode")
  72. await fs.mkdir(opencodeDir, { recursive: true })
  73. const toolsDir = path.join(opencodeDir, "tools")
  74. await fs.mkdir(toolsDir, { recursive: true })
  75. await Bun.write(
  76. path.join(opencodeDir, "package.json"),
  77. JSON.stringify({
  78. name: "custom-tools",
  79. dependencies: {
  80. "@opencode-ai/plugin": "^0.0.0",
  81. cowsay: "^1.6.0",
  82. },
  83. }),
  84. )
  85. await Bun.write(
  86. path.join(toolsDir, "cowsay.ts"),
  87. [
  88. "import { say } from 'cowsay'",
  89. "export default {",
  90. " description: 'tool that imports cowsay at top level',",
  91. " args: { text: { type: 'string' } },",
  92. " execute: async ({ text }: { text: string }) => {",
  93. " return say({ text })",
  94. " },",
  95. "}",
  96. "",
  97. ].join("\n"),
  98. )
  99. },
  100. })
  101. await Instance.provide({
  102. directory: tmp.path,
  103. fn: async () => {
  104. const ids = await ToolRegistry.ids()
  105. expect(ids).toContain("cowsay")
  106. },
  107. })
  108. })
  109. })