From 54d662f17f05ae3f8590195d39b3b3b9dc9eae41 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 18 Mar 2026 10:34:18 -0400 Subject: [PATCH] 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 --- src/headless-query.ts | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/headless-query.ts b/src/headless-query.ts index ac6803063..1bb371008 100644 --- a/src/headless-query.ts +++ b/src/headless-query.ts @@ -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, + resolveDispatch: dispatchModule.resolveDispatch as (opts: any) => Promise, + 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 { + const { deriveState, resolveDispatch, readAllSessionStatuses, loadEffectiveGSDPreferences } = await loadExtensionModules() const state = await deriveState(basePath) // Derive next dispatch action