mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 19:17:28 +00:00
63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
import { existsSync } from 'node:fs'
|
|
import { stat } from 'node:fs/promises'
|
|
import { Worker } from 'node:worker_threads'
|
|
import { currentWorkerEntryLayout } from '../worker-thread-entry-path'
|
|
import type { CursorDesktopProfileReadResult } from './cursor-profile-result'
|
|
import { ForeignSqliteReaderClient } from './foreign-sqlite-reader-client'
|
|
import { resolveForeignSqliteReaderEntryPath } from './foreign-sqlite-reader-entry-path'
|
|
import type { BinderSessionRow, OpenCodeSessionCursor } from './opencode-binder-sessions-result'
|
|
|
|
// Why: owns the process-wide client and the real worker factory, so the client
|
|
// class stays testable with a fake factory and callers see only plain functions.
|
|
|
|
function defaultWorkerFactory(): Worker {
|
|
const workerPath = resolveForeignSqliteReaderEntryPath(currentWorkerEntryLayout(__dirname))
|
|
// A missing entry (e.g. a host whose build omits it) throws here so reads fail closed.
|
|
if (!existsSync(workerPath)) {
|
|
throw new Error(`Foreign SQLite reader entry not found: ${workerPath}`)
|
|
}
|
|
return new Worker(workerPath)
|
|
}
|
|
|
|
let sharedClient: ForeignSqliteReaderClient | null = null
|
|
|
|
function getSharedClient(): ForeignSqliteReaderClient {
|
|
sharedClient ??= new ForeignSqliteReaderClient({ workerFactory: defaultWorkerFactory })
|
|
return sharedClient
|
|
}
|
|
|
|
/**
|
|
* Read the Cursor IDE's stored session on the foreign SQLite reader worker.
|
|
* @param dbPath - Cursor's state.vscdb.
|
|
* @returns `missing`, `ok`, or `error` (also when the worker cannot answer).
|
|
*/
|
|
export function readCursorDesktopProfile(dbPath: string): Promise<CursorDesktopProfileReadResult> {
|
|
return getSharedClient().readCursorProfile(dbPath)
|
|
}
|
|
|
|
/**
|
|
* List OpenCode 1 sessions newer than `cursor` on the foreign SQLite reader worker.
|
|
* @param dbPath - The shared server's opencode.db.
|
|
* @param cursor - Store position the binder has handled up to.
|
|
* @returns Rows oldest first; `[]` when the store or the worker cannot answer.
|
|
*/
|
|
export async function readOpenCodeBinderSessions(
|
|
dbPath: string,
|
|
cursor: OpenCodeSessionCursor
|
|
): Promise<BinderSessionRow[]> {
|
|
try {
|
|
// Missing stores must not keep an otherwise unused reader worker alive on every binder poll.
|
|
await stat(dbPath)
|
|
} catch (error) {
|
|
if (
|
|
error instanceof Error &&
|
|
'code' in error &&
|
|
(error.code === 'ENOENT' || error.code === 'ENOTDIR')
|
|
) {
|
|
return []
|
|
}
|
|
// The worker still owns reporting other failures and checking for changes after this probe.
|
|
}
|
|
return getSharedClient().readOpenCodeBinderSessions(dbPath, cursor)
|
|
}
|