diff --git a/src/providers/opencode/provider.ts b/src/providers/opencode/provider.ts index 0c9a2ca..cfc26aa 100644 --- a/src/providers/opencode/provider.ts +++ b/src/providers/opencode/provider.ts @@ -1,4 +1,3 @@ -import betterSqlite3 from "better-sqlite3"; import { type DiscoveryInput, type DiscoveryResult, @@ -25,17 +24,25 @@ import { createOpenCodeDatabase, type OpenCodeDatabase, type SessionStats } from import type { SessionRow } from "./schemas"; import { createOpenCodeWatch } from "./watch"; +let betterSqlite3: any; + +try { + betterSqlite3 = require("better-sqlite3"); +} catch { + // Optional dependency not available +} + export interface OpenCodeOptions { dbPath?: string; sourceLabel?: string; sessionWindowMs?: number; watch?: false | { pollIntervalMs?: number }; /** @internal for testing — inject an open database */ - _testDb?: betterSqlite3.Database; + _testDb?: any; } interface ProviderState { - db: betterSqlite3.Database | undefined; + db: any; ocDb: OpenCodeDatabase | undefined; projectIds: string[] | undefined; workspaceKey: string | undefined; diff --git a/src/providers/shared/watch.ts b/src/providers/shared/watch.ts index e44e885..68f4256 100644 --- a/src/providers/shared/watch.ts +++ b/src/providers/shared/watch.ts @@ -33,12 +33,18 @@ export function createProviderWatch( ): { close(): void } { let watcher: FSWatcher; try { - watcher = fsWatch(watchPath, { recursive: true }, (_event, filename) => { - if (shouldEmit && typeof filename === "string" && !shouldEmit(filename)) { - return; - } - onEvent(); - }); + const isRecursiveSupported = process.platform === "darwin" || process.platform === "win32"; + + watcher = fsWatch( + watchPath, + isRecursiveSupported ? { recursive: true } : {}, + (_event, filename) => { + if (shouldEmit && typeof filename === "string" && !shouldEmit(filename)) { + return; + } + onEvent(); + }, + ); } catch (error) { throw toError(error); } diff --git a/tests/cursor-watch.test.ts b/tests/cursor-watch.test.ts index bb48b2a..864c7a4 100644 --- a/tests/cursor-watch.test.ts +++ b/tests/cursor-watch.test.ts @@ -4,6 +4,9 @@ import { afterEach, describe, expect, it } from "vitest"; import { CURSOR_WATCH_DEBOUNCE_MS, createCursorWatch } from "@/providers/cursor/watch"; import { delay, waitUntil } from "./helpers"; +const supportsRecursive = + process.platform === "darwin" || process.platform === "win32"; + function tmpDir(): string { return path.join( "/tmp", @@ -97,7 +100,8 @@ describe("createCursorWatch", () => { expect(eventCount).toBeGreaterThanOrEqual(1); }); - it("fires onEvent when a file in a subdirectory changes", async () => { + (supportsRecursive ? it : it.skip)( + "fires onEvent when a file in a subdirectory changes", async () => { const dir = tmpDir(); mkdirSync(dir, { recursive: true }); cleanupPaths.push(dir); diff --git a/tests/opencode-database.test.ts b/tests/opencode-database.test.ts index 72fa696..340de6f 100644 --- a/tests/opencode-database.test.ts +++ b/tests/opencode-database.test.ts @@ -1,10 +1,11 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { createOpenCodeDatabase, type OpenCodeDatabase } from "@/providers/opencode/database"; import { createTestDb, seedMessage, seedPart, seedProject, seedSession } from "./opencode-fixtures"; +import { hasSqlite } from "./opencode-fixtures"; const MS_PER_DAY = 86_400_000; -describe("opencode database", () => { +(hasSqlite ? describe : describe.skip)("opencode database", () => { let rawDb: ReturnType; let ocDb: OpenCodeDatabase; diff --git a/tests/opencode-fixtures.ts b/tests/opencode-fixtures.ts index a8b1d8d..2bdce3b 100644 --- a/tests/opencode-fixtures.ts +++ b/tests/opencode-fixtures.ts @@ -1,5 +1,13 @@ /** Shared test fixtures for OpenCode provider tests. */ -import Database from "better-sqlite3"; +let Database: any; + +try { + Database = require("better-sqlite3"); +} catch { + // optional dependency not available +} + +export const hasSqlite = !!Database; const OPENCODE_SCHEMA = ` CREATE TABLE project ( @@ -39,20 +47,20 @@ const OPENCODE_SCHEMA = ` ); `; -export function createTestDb(): Database.Database { +export function createTestDb(): any { const db = new Database(":memory:"); db.exec(OPENCODE_SCHEMA); return db; } -export function seedProject(db: Database.Database, id: string, worktree: string): void { +export function seedProject(db: any, id: string, worktree: string): void { db.prepare( "INSERT INTO project (id, worktree, time_created, time_updated) VALUES (?, ?, ?, ?)", ).run(id, worktree, Date.now(), Date.now()); } export function seedSession( - db: Database.Database, + db: any, id: string, projectId: string, opts: { parentId?: string; title?: string; directory?: string; timeUpdated?: number } = {}, @@ -73,7 +81,7 @@ export function seedSession( } export function seedMessage( - db: Database.Database, + db: any, id: string, sessionId: string, data: Record, @@ -86,7 +94,7 @@ export function seedMessage( } export function seedPart( - db: Database.Database, + db: any, id: string, messageId: string, sessionId: string, diff --git a/tests/opencode-provider.test.ts b/tests/opencode-provider.test.ts index d7c15b8..66f06ae 100644 --- a/tests/opencode-provider.test.ts +++ b/tests/opencode-provider.test.ts @@ -2,8 +2,9 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { PROVIDER_KINDS } from "@/core/providers"; import { openCode } from "@/providers/opencode/provider"; import { createTestDb, seedMessage, seedProject } from "./opencode-fixtures"; +import { hasSqlite } from "./opencode-fixtures"; -describe("opencode provider", () => { +(hasSqlite ? describe : describe.skip)("...", () => { let db: ReturnType; beforeEach(() => {