fix(headless-query): use jiti to load extension .ts modules (#1143)

headless-query.ts imported extension modules with .js extensions, but
those files only exist as .ts (never compiled). Other code paths work
because they go through the extension loader's jiti setup, but
headless-query bypasses that as a performance optimization.

Fix: use createJiti() to dynamically import the 4 extension modules,
matching the pattern used by the extension loader. The modules are
loaded lazily in handleQuery() so the jiti overhead only applies when
the query command is actually used.

Fixes #1137
This commit is contained in:
Tom Boucher 2026-03-18 10:34:18 -04:00 committed by GitHub
parent 45af9f7f9d
commit 54d662f17f

View file

@ -8,14 +8,33 @@
* state deriveState() output (phase, milestones, progress, blockers)
* next dry-run dispatch preview (what auto-mode would do next)
* cost aggregated parallel worker costs
*
* Note: Extension modules are .ts files loaded via jiti (not compiled to .js).
* We use createJiti() here because this module is imported directly from cli.ts,
* bypassing the extension loader's jiti setup (#1137).
*/
import { deriveState } from './resources/extensions/gsd/state.js'
import { resolveDispatch } from './resources/extensions/gsd/auto-dispatch.js'
import { readAllSessionStatuses } from './resources/extensions/gsd/session-status-io.js'
import { loadEffectiveGSDPreferences } from './resources/extensions/gsd/preferences.js'
import { createJiti } from '@mariozechner/jiti'
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
import type { GSDState } from './resources/extensions/gsd/types.js'
const __dirname = dirname(fileURLToPath(import.meta.url))
const jiti = createJiti(fileURLToPath(import.meta.url), { interopDefault: true, debug: false })
async function loadExtensionModules() {
const stateModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/state.ts'), {}) as any
const dispatchModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/auto-dispatch.ts'), {}) as any
const sessionModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/session-status-io.ts'), {}) as any
const prefsModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/preferences.ts'), {}) as any
return {
deriveState: stateModule.deriveState as (basePath: string) => Promise<GSDState>,
resolveDispatch: dispatchModule.resolveDispatch as (opts: any) => Promise<any>,
readAllSessionStatuses: sessionModule.readAllSessionStatuses as (basePath: string) => any[],
loadEffectiveGSDPreferences: prefsModule.loadEffectiveGSDPreferences as () => any,
}
}
// ─── Types ──────────────────────────────────────────────────────────────────
export interface QuerySnapshot {
@ -46,6 +65,7 @@ export interface QueryResult {
// ─── Implementation ─────────────────────────────────────────────────────────
export async function handleQuery(basePath: string): Promise<QueryResult> {
const { deriveState, resolveDispatch, readAllSessionStatuses, loadEffectiveGSDPreferences } = await loadExtensionModules()
const state = await deriveState(basePath)
// Derive next dispatch action