fix(ultrawork): handle bun:sqlite import failure directly

Use the lazy bun:sqlite importer inside the deferred override microtask and keep the unavailable-runtime test on the rejected-import path.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-05 18:59:57 +09:00
parent f4a225b6cd
commit c537e840ee
2 changed files with 23 additions and 30 deletions
@@ -1,9 +1,9 @@
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test" import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"
import * as sharedModule from "../shared" import * as loggerModule from "../shared/logger"
import { import {
scheduleDeferredModelOverride, scheduleDeferredModelOverride,
__setBunSqliteImporterForTesting,
__resetBunSqliteImporterForTesting, __resetBunSqliteImporterForTesting,
__setBunSqliteImporterForTesting,
} from "./ultrawork-db-model-override" } from "./ultrawork-db-model-override"
function flushMicrotasks(depth: number): Promise<void> { function flushMicrotasks(depth: number): Promise<void> {
@@ -25,22 +25,22 @@ describe("scheduleDeferredModelOverride bun:sqlite unavailable", () => {
let logCalls: Array<[string, Record<string, unknown>?]> = [] let logCalls: Array<[string, Record<string, unknown>?]> = []
beforeEach(() => { beforeEach(() => {
// Simulate non-Bun runtime (Node/Electron): bun:sqlite import returns null spyOn(loggerModule, "log").mockImplementation((message: string, metadata?: Record<string, unknown>) => {
__setBunSqliteImporterForTesting(async () => null)
spyOn(sharedModule, "log").mockImplementation((message: string, metadata?: Record<string, unknown>) => {
logCalls.push([message, metadata]) logCalls.push([message, metadata])
}) })
}) })
afterEach(() => { afterEach(() => {
__resetBunSqliteImporterForTesting() __resetBunSqliteImporterForTesting()
mock.restore()
logCalls = [] logCalls = []
}) })
test("#given non-Bun runtime #when scheduleDeferredModelOverride is called #then it returns without throwing", async () => { test("#given bun:sqlite import fails #when scheduleDeferredModelOverride is called #then it returns without throwing", async () => {
//#given //#given
__setBunSqliteImporterForTesting(async () => {
throw new Error("bun:sqlite unavailable")
})
//#when //#when
expect(() => { expect(() => {
scheduleDeferredModelOverride("msg_unavailable", { scheduleDeferredModelOverride("msg_unavailable", {
@@ -52,9 +52,9 @@ describe("scheduleDeferredModelOverride bun:sqlite unavailable", () => {
await flushMicrotasks(5) await flushMicrotasks(5)
//#then //#then
const logMessages = logCalls.map(([msg]) => msg) expect(logCalls).toContainEqual([
expect(logMessages).toContain( "[ultrawork-db-override] bun:sqlite unavailable (non-Bun runtime), skipping",
"[ultrawork-db-override] bun:sqlite unavailable (non-Bun runtime), skipping deferred override", undefined,
) ])
}) })
}) })
+10 -17
View File
@@ -6,20 +6,16 @@ import { log } from "../shared"
type BunDatabase = import("bun:sqlite").Database type BunDatabase = import("bun:sqlite").Database
type SqliteModule = { Database: new (path: string) => BunDatabase } type SqliteModule = { Database: new (path: string) => BunDatabase }
/** @internal test-only seam: override to simulate non-Bun runtime */ let bunSqliteImporter: () => Promise<SqliteModule> = () => import("bun:sqlite")
let _bunSqliteImporter: () => Promise<SqliteModule | null> = () =>
import("bun:sqlite").catch(() => null) as Promise<SqliteModule | null>
/** @internal test-only */
export function __setBunSqliteImporterForTesting( export function __setBunSqliteImporterForTesting(
impl: () => Promise<SqliteModule | null>, importer: () => Promise<SqliteModule>,
): void { ): void {
_bunSqliteImporter = impl bunSqliteImporter = importer
} }
/** @internal test-only */
export function __resetBunSqliteImporterForTesting(): void { export function __resetBunSqliteImporterForTesting(): void {
_bunSqliteImporter = () => import("bun:sqlite").catch(() => null) as Promise<SqliteModule | null> bunSqliteImporter = () => import("bun:sqlite")
} }
function getDbPath(): string { function getDbPath(): string {
@@ -124,7 +120,6 @@ function retryViaMicrotask(
* Session.updateMessage() to save the message first, then overwrites the model. * Session.updateMessage() to save the message first, then overwrites the model.
* *
* Falls back to setTimeout(fn, 0) after 10 microtask attempts. * Falls back to setTimeout(fn, 0) after 10 microtask attempts.
*
*/ */
export function scheduleDeferredModelOverride( export function scheduleDeferredModelOverride(
messageId: string, messageId: string,
@@ -132,16 +127,14 @@ export function scheduleDeferredModelOverride(
variant?: string, variant?: string,
): void { ): void {
queueMicrotask(async () => { queueMicrotask(async () => {
// Lazy-load bun:sqlite so this module can be imported under Node/Electron let DatabaseCtor: (new (path: string) => import("bun:sqlite").Database) | undefined
// without crashing the ESM loader (bun: protocol is Bun-only). try {
const sqliteModule = await _bunSqliteImporter() DatabaseCtor = (await bunSqliteImporter()).Database
if (sqliteModule === null) { } catch {
log("[ultrawork-db-override] bun:sqlite unavailable (non-Bun runtime), skipping deferred override") log("[ultrawork-db-override] bun:sqlite unavailable (non-Bun runtime), skipping")
return return
} }
const { Database } = sqliteModule
const dbPath = getDbPath() const dbPath = getDbPath()
if (!existsSync(dbPath)) { if (!existsSync(dbPath)) {
log("[ultrawork-db-override] DB not found, skipping deferred override") log("[ultrawork-db-override] DB not found, skipping deferred override")
@@ -150,7 +143,7 @@ export function scheduleDeferredModelOverride(
let db: BunDatabase let db: BunDatabase
try { try {
db = new Database(dbPath) db = new DatabaseCtor(dbPath)
} catch (error) { } catch (error) {
log("[ultrawork-db-override] Failed to open DB, skipping deferred override", { log("[ultrawork-db-override] Failed to open DB, skipping deferred override", {
messageId, messageId,