|
|
@@ -0,0 +1,81 @@
|
|
|
+import { describe, expect } from "bun:test"
|
|
|
+import path from "path"
|
|
|
+import { Cause, Effect, Exit, Layer } from "effect"
|
|
|
+import { GlobTool } from "../../src/tool/glob"
|
|
|
+import { SessionID, MessageID } from "../../src/session/schema"
|
|
|
+import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
|
|
|
+import { Ripgrep } from "../../src/file/ripgrep"
|
|
|
+import { AppFileSystem } from "../../src/filesystem"
|
|
|
+import { Truncate } from "../../src/tool/truncate"
|
|
|
+import { Agent } from "../../src/agent/agent"
|
|
|
+import { provideTmpdirInstance } from "../fixture/fixture"
|
|
|
+import { testEffect } from "../lib/effect"
|
|
|
+
|
|
|
+const it = testEffect(
|
|
|
+ Layer.mergeAll(
|
|
|
+ CrossSpawnSpawner.defaultLayer,
|
|
|
+ AppFileSystem.defaultLayer,
|
|
|
+ Ripgrep.defaultLayer,
|
|
|
+ Truncate.defaultLayer,
|
|
|
+ Agent.defaultLayer,
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+const ctx = {
|
|
|
+ sessionID: SessionID.make("ses_test"),
|
|
|
+ messageID: MessageID.make(""),
|
|
|
+ callID: "",
|
|
|
+ agent: "build",
|
|
|
+ abort: AbortSignal.any([]),
|
|
|
+ messages: [],
|
|
|
+ metadata: () => Effect.void,
|
|
|
+ ask: () => Effect.void,
|
|
|
+}
|
|
|
+
|
|
|
+describe("tool.glob", () => {
|
|
|
+ it.live("matches files from a directory path", () =>
|
|
|
+ provideTmpdirInstance((dir) =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ yield* Effect.promise(() => Bun.write(path.join(dir, "a.ts"), "export const a = 1\n"))
|
|
|
+ yield* Effect.promise(() => Bun.write(path.join(dir, "b.txt"), "hello\n"))
|
|
|
+ const info = yield* GlobTool
|
|
|
+ const glob = yield* info.init()
|
|
|
+ const result = yield* glob.execute(
|
|
|
+ {
|
|
|
+ pattern: "*.ts",
|
|
|
+ path: dir,
|
|
|
+ },
|
|
|
+ ctx,
|
|
|
+ )
|
|
|
+ expect(result.metadata.count).toBe(1)
|
|
|
+ expect(result.output).toContain(path.join(dir, "a.ts"))
|
|
|
+ expect(result.output).not.toContain(path.join(dir, "b.txt"))
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("rejects exact file paths", () =>
|
|
|
+ provideTmpdirInstance((dir) =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const file = path.join(dir, "a.ts")
|
|
|
+ yield* Effect.promise(() => Bun.write(file, "export const a = 1\n"))
|
|
|
+ const info = yield* GlobTool
|
|
|
+ const glob = yield* info.init()
|
|
|
+ const exit = yield* glob
|
|
|
+ .execute(
|
|
|
+ {
|
|
|
+ pattern: "*.ts",
|
|
|
+ path: file,
|
|
|
+ },
|
|
|
+ ctx,
|
|
|
+ )
|
|
|
+ .pipe(Effect.exit)
|
|
|
+ expect(Exit.isFailure(exit)).toBe(true)
|
|
|
+ if (Exit.isFailure(exit)) {
|
|
|
+ const err = Cause.squash(exit.cause)
|
|
|
+ expect(err instanceof Error ? err.message : String(err)).toContain("glob path must be a directory")
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+})
|