glob.test.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { describe, expect } from "bun:test"
  2. import path from "path"
  3. import { Cause, Effect, Exit, Layer } from "effect"
  4. import { GlobTool } from "../../src/tool/glob"
  5. import { SessionID, MessageID } from "../../src/session/schema"
  6. import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
  7. import { Ripgrep } from "../../src/file/ripgrep"
  8. import { AppFileSystem } from "@opencode-ai/core/filesystem"
  9. import { Truncate } from "../../src/tool"
  10. import { Agent } from "../../src/agent/agent"
  11. import { provideTmpdirInstance } from "../fixture/fixture"
  12. import { testEffect } from "../lib/effect"
  13. const it = testEffect(
  14. Layer.mergeAll(
  15. CrossSpawnSpawner.defaultLayer,
  16. AppFileSystem.defaultLayer,
  17. Ripgrep.defaultLayer,
  18. Truncate.defaultLayer,
  19. Agent.defaultLayer,
  20. ),
  21. )
  22. const ctx = {
  23. sessionID: SessionID.make("ses_test"),
  24. messageID: MessageID.make(""),
  25. callID: "",
  26. agent: "build",
  27. abort: AbortSignal.any([]),
  28. messages: [],
  29. metadata: () => Effect.void,
  30. ask: () => Effect.void,
  31. }
  32. describe("tool.glob", () => {
  33. it.live("matches files from a directory path", () =>
  34. provideTmpdirInstance((dir) =>
  35. Effect.gen(function* () {
  36. yield* Effect.promise(() => Bun.write(path.join(dir, "a.ts"), "export const a = 1\n"))
  37. yield* Effect.promise(() => Bun.write(path.join(dir, "b.txt"), "hello\n"))
  38. const info = yield* GlobTool
  39. const glob = yield* info.init()
  40. const result = yield* glob.execute(
  41. {
  42. pattern: "*.ts",
  43. path: dir,
  44. },
  45. ctx,
  46. )
  47. expect(result.metadata.count).toBe(1)
  48. expect(result.output).toContain(path.join(dir, "a.ts"))
  49. expect(result.output).not.toContain(path.join(dir, "b.txt"))
  50. }),
  51. ),
  52. )
  53. it.live("rejects exact file paths", () =>
  54. provideTmpdirInstance((dir) =>
  55. Effect.gen(function* () {
  56. const file = path.join(dir, "a.ts")
  57. yield* Effect.promise(() => Bun.write(file, "export const a = 1\n"))
  58. const info = yield* GlobTool
  59. const glob = yield* info.init()
  60. const exit = yield* glob
  61. .execute(
  62. {
  63. pattern: "*.ts",
  64. path: file,
  65. },
  66. ctx,
  67. )
  68. .pipe(Effect.exit)
  69. expect(Exit.isFailure(exit)).toBe(true)
  70. if (Exit.isFailure(exit)) {
  71. const err = Cause.squash(exit.cause)
  72. expect(err instanceof Error ? err.message : String(err)).toContain("glob path must be a directory")
  73. }
  74. }),
  75. ),
  76. )
  77. })