@agimon-ai/doompi 0.0.1-alpha.7 → 0.0.1-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../logSinkTelemetry.cjs`),n=require(`../utils/json.cjs`),r=require(`../utils/moduleResolution.cjs`);require(`../utils/index.cjs`);const i=require(`../config/projectTrust.cjs`);require(`../config/index.cjs`);const a=require(`./baseCommand.cjs`),o=require(`../services/compatibility/process.cjs`);let s=require(`cross-spawn`);s=e.__toESM(s,1);const c=`vibe-lint`,l=`pipe`;function u(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`Expected a JSON vibe-lint invocation on stdin`,{cause:e})}if(!n.isRecord(t)||typeof t.prompt!=`string`||typeof t.systemPrompt!=`string`)throw Error(`A vibe-lint invocation requires string prompt and systemPrompt fields`);if(t.maxTokens!==void 0&&typeof t.maxTokens!=`number`)throw Error(`A vibe-lint invocation maxTokens field must be a number`);if(t.screenshotPaths!==void 0&&(!Array.isArray(t.screenshotPaths)||!t.screenshotPaths.every(e=>typeof e==`string`)))throw Error(`A vibe-lint invocation screenshotPaths field must be an array of strings`);return{prompt:t.prompt,systemPrompt:t.systemPrompt,maxTokens:t.maxTokens,screenshotPaths:t.screenshotPaths}}function d(e,t){return[...e,`--print`,...i.hasProjectTrustOption(e)?[]:[`--approve`],`--no-session`,`--system-prompt`,t.systemPrompt,...(t.screenshotPaths??[]).map(e=>`@${e}`),t.prompt]}function f(e){return`${JSON.stringify({content:e.trim()})}\n`}function p(e,t){return[`--no-themes`,`--theme`,t,...e]}async function m(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf-8`)}var h=class extends a.BaseCommand{name=`launch`;matches(e){return!0}async execute(e,n){let{options:a,environment:h}=e,{buildRuntimeBundle:g,createRuntimeExtensionPlan:_}=await Promise.resolve().then(()=>require(`../services/runtimeBundle.cjs`)),{extensions:v,childExtensions:y}=_(e);h.DOOMPI_CHILD_EXTENSIONS=JSON.stringify(y);let b=v;try{b=[(await g(e,{extensions:v,childExtensions:y})).bundle],h.DOOMPI_EXTENSIONS_PROVIDED=`1`}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${t}\n`)}let x;try{x=i.loadDoomConfig(a.repoRoot)}catch(e){throw await n.recordError(t.HARNESS_EVENT.configLoadFailed,e,{"harness.phase":`load_config`}),e}n.recordEvent(t.HARNESS_EVENT.projectTrustResolved,{"harness.project_trust":x.projectTrust,"harness.project_trust.overridden":i.hasProjectTrustOption(a.piArgs)});let S=i.applyProjectTrust(a.piArgs,x);S=p(S,e.defaultThemePath);for(let e of b)S=[`--extension`,e,...S];if(a.outputFormat===c){let e=u(await m());S=d(S,e)}let C=Date.now(),w=(0,s.default)(process.execPath,[r.piCliPath(),...S],{cwd:a.cwd,env:h,stdio:a.outputFormat===c?[`ignore`,l,l]:`inherit`}),T=``;if(a.outputFormat===c){if(!w.stdout||!w.stderr)throw Error(`Failed to open Pi output streams`);w.stdout.on(`data`,e=>{T+=e.toString()}),w.stderr.on(`data`,e=>{process.stderr.write(e)})}let E=o.forwardSignals(w),D=await n.runInSpan(`doom_pi.pi_session`,{"harness.extension.count":b.length,"harness.mode":a.outputFormat},()=>o.waitForExit(w)).catch(async e=>{throw await n.recordError(t.HARNESS_EVENT.launchFailed,e,{"harness.duration_ms":Date.now()-C}),e}).finally(E);return n.recordEvent(t.HARNESS_EVENT.launchCompleted,{"harness.exit_code":D,"harness.duration_ms":Date.now()-C,"harness.mode":a.outputFormat??`default`}),a.outputFormat===c&&D===0&&process.stdout.write(f(T)),D}};exports.LaunchCommand=h,exports.buildVibeLintPiArgs=d,exports.formatVibeLintResponse=f,exports.overridePiThemes=p,exports.parseVibeLintInvocation=u;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../logSinkTelemetry.cjs`),n=require(`../utils/json.cjs`),r=require(`../utils/moduleResolution.cjs`);require(`../utils/index.cjs`);const i=require(`../config/projectTrust.cjs`);require(`../config/index.cjs`);const a=require(`./baseCommand.cjs`),o=require(`../services/compatibility/process.cjs`);let s=require(`node:crypto`),c=require(`cross-spawn`);c=e.__toESM(c,1);const l=`vibe-lint`,u=`pipe`,d=`ELICITATION_SESSION_ID`;function f(e){let t=e[d]?.trim()||(0,s.randomUUID)();return e[d]=t,t}function p(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`Expected a JSON vibe-lint invocation on stdin`,{cause:e})}if(!n.isRecord(t)||typeof t.prompt!=`string`||typeof t.systemPrompt!=`string`)throw Error(`A vibe-lint invocation requires string prompt and systemPrompt fields`);if(t.maxTokens!==void 0&&typeof t.maxTokens!=`number`)throw Error(`A vibe-lint invocation maxTokens field must be a number`);if(t.screenshotPaths!==void 0&&(!Array.isArray(t.screenshotPaths)||!t.screenshotPaths.every(e=>typeof e==`string`)))throw Error(`A vibe-lint invocation screenshotPaths field must be an array of strings`);return{prompt:t.prompt,systemPrompt:t.systemPrompt,maxTokens:t.maxTokens,screenshotPaths:t.screenshotPaths}}function m(e,t){return[...e,`--print`,...i.hasProjectTrustOption(e)?[]:[`--approve`],`--no-session`,`--system-prompt`,t.systemPrompt,...(t.screenshotPaths??[]).map(e=>`@${e}`),t.prompt]}function h(e){return`${JSON.stringify({content:e.trim()})}\n`}function g(e,t){return[`--no-themes`,`--theme`,t,...e]}async function _(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf-8`)}var v=class extends a.BaseCommand{name=`launch`;matches(e){return!0}async execute(e,n){let{options:a,environment:s}=e;f(s);let{buildRuntimeBundle:d,createRuntimeExtensionPlan:v}=await Promise.resolve().then(()=>require(`../services/runtimeBundle.cjs`)),{extensions:y,childExtensions:b}=v(e);s.DOOMPI_CHILD_EXTENSIONS=JSON.stringify(b);let x=y;try{x=[(await d(e,{extensions:y,childExtensions:b})).bundle],s.DOOMPI_EXTENSIONS_PROVIDED=`1`}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${t}\n`)}let S;try{S=i.loadDoomConfig(a.repoRoot)}catch(e){throw await n.recordError(t.HARNESS_EVENT.configLoadFailed,e,{"harness.phase":`load_config`}),e}n.recordEvent(t.HARNESS_EVENT.projectTrustResolved,{"harness.project_trust":S.projectTrust,"harness.project_trust.overridden":i.hasProjectTrustOption(a.piArgs)});let C=i.applyProjectTrust(a.piArgs,S);C=g(C,e.defaultThemePath);for(let e of x)C=[`--extension`,e,...C];if(a.outputFormat===l){let e=p(await _());C=m(C,e)}let w=Date.now(),T=(0,c.default)(process.execPath,[r.piCliPath(),...C],{cwd:a.cwd,env:s,stdio:a.outputFormat===l?[`ignore`,u,u]:`inherit`}),E=``;if(a.outputFormat===l){if(!T.stdout||!T.stderr)throw Error(`Failed to open Pi output streams`);T.stdout.on(`data`,e=>{E+=e.toString()}),T.stderr.on(`data`,e=>{process.stderr.write(e)})}let D=o.forwardSignals(T),O=await n.runInSpan(`doom_pi.pi_session`,{"harness.extension.count":x.length,"harness.mode":a.outputFormat},()=>o.waitForExit(T)).catch(async e=>{throw await n.recordError(t.HARNESS_EVENT.launchFailed,e,{"harness.duration_ms":Date.now()-w}),e}).finally(D);return n.recordEvent(t.HARNESS_EVENT.launchCompleted,{"harness.exit_code":O,"harness.duration_ms":Date.now()-w,"harness.mode":a.outputFormat??`default`}),a.outputFormat===l&&O===0&&process.stdout.write(h(E)),O}};exports.LaunchCommand=v,exports.buildVibeLintPiArgs=m,exports.ensureElicitationSessionId=f,exports.formatVibeLintResponse=h,exports.overridePiThemes=g,exports.parseVibeLintInvocation=p;
2
2
  //# sourceMappingURL=launchCommand.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"launchCommand.cjs","names":["isRecord","hasProjectTrustOption","BaseCommand","loadDoomConfig","HARNESS_EVENT","applyProjectTrust","piCliPath","forwardSignals","waitForExit"],"sources":["../../src/commands/launchCommand.ts"],"sourcesContent":["import spawn from 'cross-spawn';\nimport { applyProjectTrust, hasProjectTrustOption, loadDoomConfig, type DoomConfig } from '../config/index.ts';\nimport type { HarnessOptions } from '../interfaces/index.ts';\nimport { HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport type { HarnessContext } from '../services/index.ts';\nimport { forwardSignals, waitForExit } from '../services/compatibility/process.ts';\nimport { isRecord, piCliPath } from '../utils/index.ts';\nimport { BaseCommand } from './baseCommand.ts';\n\nconst VIBE_LINT_FORMAT = 'vibe-lint';\nconst PRINT_OPTION = '--print';\nconst APPROVE_OPTION = '--approve';\nconst NO_SESSION_OPTION = '--no-session';\nconst SYSTEM_PROMPT_OPTION = '--system-prompt';\nconst THEME_OPTION = '--theme';\nconst NO_THEMES_OPTION = '--no-themes';\nconst EXTENSION_OPTION = '--extension';\nconst IGNORE_STDIO = 'ignore';\nconst PIPE_STDIO = 'pipe';\nconst INHERIT_STDIO = 'inherit';\nconst EXTERNAL_EXTENSIONS_ENV = 'DOOMPI_EXTENSIONS_PROVIDED';\nconst ENABLED_ENV = '1';\n\nexport interface VibeLintInvocation {\n prompt: string;\n systemPrompt: string;\n maxTokens?: number;\n screenshotPaths?: string[];\n}\n\nexport function parseVibeLintInvocation(input: string): VibeLintInvocation {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch (error) {\n throw new Error('Expected a JSON vibe-lint invocation on stdin', { cause: error });\n }\n\n if (!isRecord(parsed) || typeof parsed.prompt !== 'string' || typeof parsed.systemPrompt !== 'string') {\n throw new Error('A vibe-lint invocation requires string prompt and systemPrompt fields');\n }\n if (parsed.maxTokens !== undefined && typeof parsed.maxTokens !== 'number') {\n throw new Error('A vibe-lint invocation maxTokens field must be a number');\n }\n if (\n parsed.screenshotPaths !== undefined &&\n (!Array.isArray(parsed.screenshotPaths) || !parsed.screenshotPaths.every((value) => typeof value === 'string'))\n ) {\n throw new Error('A vibe-lint invocation screenshotPaths field must be an array of strings');\n }\n\n return {\n prompt: parsed.prompt,\n systemPrompt: parsed.systemPrompt,\n maxTokens: parsed.maxTokens,\n screenshotPaths: parsed.screenshotPaths as string[] | undefined,\n };\n}\n\nexport function buildVibeLintPiArgs(piArgs: string[], invocation: VibeLintInvocation): string[] {\n return [\n ...piArgs,\n PRINT_OPTION,\n ...(!hasProjectTrustOption(piArgs) ? [APPROVE_OPTION] : []),\n // Reviews are disposable and must not appear in Pi's resume history.\n NO_SESSION_OPTION,\n SYSTEM_PROMPT_OPTION,\n invocation.systemPrompt,\n ...(invocation.screenshotPaths ?? []).map((screenshotPath) => `@${screenshotPath}`),\n invocation.prompt,\n ];\n}\n\nexport function formatVibeLintResponse(content: string): string {\n return `${JSON.stringify({ content: content.trim() })}\\n`;\n}\n\n/** Ignores configured themes and loads only themes explicitly passed to the launcher. */\nexport function overridePiThemes(piArgs: string[], themePath: string): string[] {\n return [NO_THEMES_OPTION, THEME_OPTION, themePath, ...piArgs];\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\n/**\n * Spawns Pi with the resolved extensions, environment, and theme.\n *\n * This is the default command: it matches whenever no diagnostic flag claimed\n * the run.\n */\nexport class LaunchCommand extends BaseCommand {\n readonly name = 'launch';\n\n matches(_options: HarnessOptions): boolean {\n return true;\n }\n\n async execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number> {\n const { options, environment } = context;\n\n const { buildRuntimeBundle, createRuntimeExtensionPlan } = await import('../services/runtimeBundle.ts');\n const { extensions, childExtensions } = createRuntimeExtensionPlan(context);\n environment.DOOMPI_CHILD_EXTENSIONS = JSON.stringify(childExtensions);\n\n // Pi normally imports each package entry separately. Flattening the exact\n // Pi load order into one graph removes repeated module resolution and parse\n // work. The graph manifest makes the common path a stat-only cache hit;\n // compilation failure keeps the historical extension list intact.\n let launchExtensions = extensions;\n try {\n const built = await buildRuntimeBundle(context, { extensions, childExtensions });\n launchExtensions = [built.bundle];\n // A synced repository also has the doom wrapper in project settings. It\n // must not compose the same factories after this aggregate has run.\n environment[EXTERNAL_EXTENSIONS_ENV] = ENABLED_ENV;\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${detail}\\n`);\n }\n\n // A malformed .doom/config.yaml aborts the launch, and the message only\n // reaches the terminal that ran it, so record it before it propagates.\n let doomConfig: DoomConfig;\n try {\n doomConfig = loadDoomConfig(options.repoRoot);\n } catch (error) {\n await telemetry.recordError(HARNESS_EVENT.configLoadFailed, error, { 'harness.phase': 'load_config' });\n throw error;\n }\n\n // Whether a session ran with repository approval is the single most useful\n // fact when reconstructing what an agent was allowed to do.\n void telemetry.recordEvent(HARNESS_EVENT.projectTrustResolved, {\n 'harness.project_trust': doomConfig.projectTrust,\n 'harness.project_trust.overridden': hasProjectTrustOption(options.piArgs),\n });\n\n let piArgs = applyProjectTrust(options.piArgs, doomConfig);\n piArgs = overridePiThemes(piArgs, context.defaultThemePath);\n for (const extension of launchExtensions) piArgs = [EXTENSION_OPTION, extension, ...piArgs];\n\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n const invocation = parseVibeLintInvocation(await readStdin());\n piArgs = buildVibeLintPiArgs(piArgs, invocation);\n }\n\n const startedAt = Date.now();\n const child = spawn(process.execPath, [piCliPath(), ...piArgs], {\n cwd: options.cwd,\n env: environment,\n stdio: options.outputFormat === VIBE_LINT_FORMAT ? [IGNORE_STDIO, PIPE_STDIO, PIPE_STDIO] : INHERIT_STDIO,\n });\n let stdout = '';\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n if (!child.stdout || !child.stderr) throw new Error('Failed to open Pi output streams');\n child.stdout.on('data', (chunk: string | Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: string | Buffer) => {\n process.stderr.write(chunk);\n });\n }\n\n // Shared with the compatibility providers, so a second Ctrl-C still reaches\n // the child and SIGHUP and SIGQUIT are forwarded too.\n const stopForwarding = forwardSignals(child);\n const result = await telemetry\n .runInSpan(\n 'doom_pi.pi_session',\n {\n 'harness.extension.count': launchExtensions.length,\n 'harness.mode': options.outputFormat,\n },\n () => waitForExit(child),\n )\n .catch(async (error: unknown) => {\n // A spawn error means Pi never started, which is invisible to the\n // session telemetry the child would otherwise have reported.\n await telemetry.recordError(HARNESS_EVENT.launchFailed, error, {\n 'harness.duration_ms': Date.now() - startedAt,\n });\n throw error;\n })\n .finally(stopForwarding);\n\n void telemetry.recordEvent(HARNESS_EVENT.launchCompleted, {\n 'harness.exit_code': result,\n 'harness.duration_ms': Date.now() - startedAt,\n 'harness.mode': options.outputFormat ?? 'default',\n });\n\n if (options.outputFormat === VIBE_LINT_FORMAT && result === 0) {\n process.stdout.write(formatVibeLintResponse(stdout));\n }\n return result;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"launchCommand.cjs","names":["isRecord","hasProjectTrustOption","BaseCommand","loadDoomConfig","HARNESS_EVENT","applyProjectTrust","piCliPath","forwardSignals","waitForExit"],"sources":["../../src/commands/launchCommand.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport spawn from 'cross-spawn';\nimport { applyProjectTrust, type DoomConfig, hasProjectTrustOption, loadDoomConfig } from '../config/index.ts';\nimport type { HarnessOptions } from '../interfaces/index.ts';\nimport { HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport { forwardSignals, waitForExit } from '../services/compatibility/process.ts';\nimport type { HarnessContext } from '../services/index.ts';\nimport { isRecord, piCliPath } from '../utils/index.ts';\nimport { BaseCommand } from './baseCommand.ts';\n\nconst VIBE_LINT_FORMAT = 'vibe-lint';\nconst PRINT_OPTION = '--print';\nconst APPROVE_OPTION = '--approve';\nconst NO_SESSION_OPTION = '--no-session';\nconst SYSTEM_PROMPT_OPTION = '--system-prompt';\nconst THEME_OPTION = '--theme';\nconst NO_THEMES_OPTION = '--no-themes';\nconst EXTENSION_OPTION = '--extension';\nconst IGNORE_STDIO = 'ignore';\nconst PIPE_STDIO = 'pipe';\nconst INHERIT_STDIO = 'inherit';\nconst EXTERNAL_EXTENSIONS_ENV = 'DOOMPI_EXTENSIONS_PROVIDED';\nconst ENABLED_ENV = '1';\nconst ELICITATION_SESSION_ENV = 'ELICITATION_SESSION_ID';\n\n/** Gives each Doompi launch a stable fallback identity without replacing one supplied by its caller. */\nexport function ensureElicitationSessionId(environment: NodeJS.ProcessEnv): string {\n const provided = environment[ELICITATION_SESSION_ENV]?.trim();\n const sessionId = provided || randomUUID();\n environment[ELICITATION_SESSION_ENV] = sessionId;\n return sessionId;\n}\n\nexport interface VibeLintInvocation {\n prompt: string;\n systemPrompt: string;\n maxTokens?: number;\n screenshotPaths?: string[];\n}\n\nexport function parseVibeLintInvocation(input: string): VibeLintInvocation {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch (error) {\n throw new Error('Expected a JSON vibe-lint invocation on stdin', { cause: error });\n }\n\n if (!isRecord(parsed) || typeof parsed.prompt !== 'string' || typeof parsed.systemPrompt !== 'string') {\n throw new Error('A vibe-lint invocation requires string prompt and systemPrompt fields');\n }\n if (parsed.maxTokens !== undefined && typeof parsed.maxTokens !== 'number') {\n throw new Error('A vibe-lint invocation maxTokens field must be a number');\n }\n if (\n parsed.screenshotPaths !== undefined &&\n (!Array.isArray(parsed.screenshotPaths) || !parsed.screenshotPaths.every((value) => typeof value === 'string'))\n ) {\n throw new Error('A vibe-lint invocation screenshotPaths field must be an array of strings');\n }\n\n return {\n prompt: parsed.prompt,\n systemPrompt: parsed.systemPrompt,\n maxTokens: parsed.maxTokens,\n screenshotPaths: parsed.screenshotPaths as string[] | undefined,\n };\n}\n\nexport function buildVibeLintPiArgs(piArgs: string[], invocation: VibeLintInvocation): string[] {\n return [\n ...piArgs,\n PRINT_OPTION,\n ...(!hasProjectTrustOption(piArgs) ? [APPROVE_OPTION] : []),\n // Reviews are disposable and must not appear in Pi's resume history.\n NO_SESSION_OPTION,\n SYSTEM_PROMPT_OPTION,\n invocation.systemPrompt,\n ...(invocation.screenshotPaths ?? []).map((screenshotPath) => `@${screenshotPath}`),\n invocation.prompt,\n ];\n}\n\nexport function formatVibeLintResponse(content: string): string {\n return `${JSON.stringify({ content: content.trim() })}\\n`;\n}\n\n/** Ignores configured themes and loads only themes explicitly passed to the launcher. */\nexport function overridePiThemes(piArgs: string[], themePath: string): string[] {\n return [NO_THEMES_OPTION, THEME_OPTION, themePath, ...piArgs];\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\n/**\n * Spawns Pi with the resolved extensions, environment, and theme.\n *\n * This is the default command: it matches whenever no diagnostic flag claimed\n * the run.\n */\nexport class LaunchCommand extends BaseCommand {\n readonly name = 'launch';\n\n matches(_options: HarnessOptions): boolean {\n return true;\n }\n\n async execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number> {\n const { options, environment } = context;\n ensureElicitationSessionId(environment);\n\n const { buildRuntimeBundle, createRuntimeExtensionPlan } = await import('../services/runtimeBundle.ts');\n const { extensions, childExtensions } = createRuntimeExtensionPlan(context);\n environment.DOOMPI_CHILD_EXTENSIONS = JSON.stringify(childExtensions);\n\n // Pi normally imports each package entry separately. Flattening the exact\n // Pi load order into one graph removes repeated module resolution and parse\n // work. The graph manifest makes the common path a stat-only cache hit;\n // compilation failure keeps the historical extension list intact.\n let launchExtensions = extensions;\n try {\n const built = await buildRuntimeBundle(context, { extensions, childExtensions });\n launchExtensions = [built.bundle];\n // A synced repository also has the doom wrapper in project settings. It\n // must not compose the same factories after this aggregate has run.\n environment[EXTERNAL_EXTENSIONS_ENV] = ENABLED_ENV;\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${detail}\\n`);\n }\n\n // A malformed .doom/config.yaml aborts the launch, and the message only\n // reaches the terminal that ran it, so record it before it propagates.\n let doomConfig: DoomConfig;\n try {\n doomConfig = loadDoomConfig(options.repoRoot);\n } catch (error) {\n await telemetry.recordError(HARNESS_EVENT.configLoadFailed, error, { 'harness.phase': 'load_config' });\n throw error;\n }\n\n // Whether a session ran with repository approval is the single most useful\n // fact when reconstructing what an agent was allowed to do.\n void telemetry.recordEvent(HARNESS_EVENT.projectTrustResolved, {\n 'harness.project_trust': doomConfig.projectTrust,\n 'harness.project_trust.overridden': hasProjectTrustOption(options.piArgs),\n });\n\n let piArgs = applyProjectTrust(options.piArgs, doomConfig);\n piArgs = overridePiThemes(piArgs, context.defaultThemePath);\n for (const extension of launchExtensions) piArgs = [EXTENSION_OPTION, extension, ...piArgs];\n\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n const invocation = parseVibeLintInvocation(await readStdin());\n piArgs = buildVibeLintPiArgs(piArgs, invocation);\n }\n\n const startedAt = Date.now();\n const child = spawn(process.execPath, [piCliPath(), ...piArgs], {\n cwd: options.cwd,\n env: environment,\n stdio: options.outputFormat === VIBE_LINT_FORMAT ? [IGNORE_STDIO, PIPE_STDIO, PIPE_STDIO] : INHERIT_STDIO,\n });\n let stdout = '';\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n if (!child.stdout || !child.stderr) throw new Error('Failed to open Pi output streams');\n child.stdout.on('data', (chunk: string | Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: string | Buffer) => {\n process.stderr.write(chunk);\n });\n }\n\n // Shared with the compatibility providers, so a second Ctrl-C still reaches\n // the child and SIGHUP and SIGQUIT are forwarded too.\n const stopForwarding = forwardSignals(child);\n const result = await telemetry\n .runInSpan(\n 'doom_pi.pi_session',\n {\n 'harness.extension.count': launchExtensions.length,\n 'harness.mode': options.outputFormat,\n },\n () => waitForExit(child),\n )\n .catch(async (error: unknown) => {\n // A spawn error means Pi never started, which is invisible to the\n // session telemetry the child would otherwise have reported.\n await telemetry.recordError(HARNESS_EVENT.launchFailed, error, {\n 'harness.duration_ms': Date.now() - startedAt,\n });\n throw error;\n })\n .finally(stopForwarding);\n\n void telemetry.recordEvent(HARNESS_EVENT.launchCompleted, {\n 'harness.exit_code': result,\n 'harness.duration_ms': Date.now() - startedAt,\n 'harness.mode': options.outputFormat ?? 'default',\n });\n\n if (options.outputFormat === VIBE_LINT_FORMAT && result === 0) {\n process.stdout.write(formatVibeLintResponse(stdout));\n }\n return result;\n }\n}\n"],"mappings":"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"}
@@ -4,6 +4,8 @@ import { HarnessContext } from "../services/harnessContext.cjs";
4
4
  import { BaseCommand } from "./baseCommand.cjs";
5
5
 
6
6
  //#region src/commands/launchCommand.d.ts
7
+ /** Gives each Doompi launch a stable fallback identity without replacing one supplied by its caller. */
8
+ declare function ensureElicitationSessionId(environment: NodeJS.ProcessEnv): string;
7
9
  interface VibeLintInvocation {
8
10
  prompt: string;
9
11
  systemPrompt: string;
@@ -27,5 +29,5 @@ declare class LaunchCommand extends BaseCommand {
27
29
  execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number>;
28
30
  }
29
31
  //#endregion
30
- export { LaunchCommand, VibeLintInvocation, buildVibeLintPiArgs, formatVibeLintResponse, overridePiThemes, parseVibeLintInvocation };
32
+ export { LaunchCommand, VibeLintInvocation, buildVibeLintPiArgs, ensureElicitationSessionId, formatVibeLintResponse, overridePiThemes, parseVibeLintInvocation };
31
33
  //# sourceMappingURL=launchCommand.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"launchCommand.d.cts","names":[],"sources":["../../src/commands/launchCommand.ts"],"mappings":";;;;;;UAuBiB,kBAAA;EACf,MAAA;EACA,YAAA;EACA,SAAA;EACA,eAAA;AAAA;AAAA,iBAGc,uBAAA,CAAwB,KAAA,WAAgB,kBAAA;AAAA,iBA6BxC,mBAAA,CAAoB,MAAA,YAAkB,UAAA,EAAY,kBAAA;AAAA,iBAclD,sBAAA,CAAuB,OAAA;;iBAKvB,gBAAA,CAAiB,MAAA,YAAkB,SAAA;;;AAhDnD;;;;cAkEa,aAAA,SAAsB,WAAA;EAAA,SACxB,IAAA;EAET,OAAA,CAAQ,QAAA,EAAU,cAAA;EAIZ,OAAA,CAAQ,OAAA,EAAS,cAAA,EAAgB,SAAA,EAAW,gBAAA,GAAmB,OAAA;AAAA"}
1
+ {"version":3,"file":"launchCommand.d.cts","names":[],"sources":["../../src/commands/launchCommand.ts"],"mappings":";;;;;;;iBA0BgB,0BAAA,CAA2B,WAAA,EAAa,MAAA,CAAO,UAAA;AAAA,UAO9C,kBAAA;EACf,MAAA;EACA,YAAA;EACA,SAAA;EACA,eAAA;AAAA;AAAA,iBAGc,uBAAA,CAAwB,KAAA,WAAgB,kBAAA;AAAA,iBA6BxC,mBAAA,CAAoB,MAAA,YAAkB,UAAA,EAAY,kBAAA;AAAA,iBAclD,sBAAA,CAAuB,OAAA;;iBAKvB,gBAAA,CAAiB,MAAA,YAAkB,SAAA;;;;;;;cAkBtC,aAAA,SAAsB,WAAA;EAAA,SACxB,IAAA;EAET,OAAA,CAAQ,QAAA,EAAU,cAAA;EAIZ,OAAA,CAAQ,OAAA,EAAS,cAAA,EAAgB,SAAA,EAAW,gBAAA,GAAmB,OAAA;AAAA"}
@@ -4,6 +4,8 @@ import { HarnessContext } from "../services/harnessContext.mjs";
4
4
  import { BaseCommand } from "./baseCommand.mjs";
5
5
 
6
6
  //#region src/commands/launchCommand.d.ts
7
+ /** Gives each Doompi launch a stable fallback identity without replacing one supplied by its caller. */
8
+ declare function ensureElicitationSessionId(environment: NodeJS.ProcessEnv): string;
7
9
  interface VibeLintInvocation {
8
10
  prompt: string;
9
11
  systemPrompt: string;
@@ -27,5 +29,5 @@ declare class LaunchCommand extends BaseCommand {
27
29
  execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number>;
28
30
  }
29
31
  //#endregion
30
- export { LaunchCommand, VibeLintInvocation, buildVibeLintPiArgs, formatVibeLintResponse, overridePiThemes, parseVibeLintInvocation };
32
+ export { LaunchCommand, VibeLintInvocation, buildVibeLintPiArgs, ensureElicitationSessionId, formatVibeLintResponse, overridePiThemes, parseVibeLintInvocation };
31
33
  //# sourceMappingURL=launchCommand.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"launchCommand.d.mts","names":[],"sources":["../../src/commands/launchCommand.ts"],"mappings":";;;;;;UAuBiB,kBAAA;EACf,MAAA;EACA,YAAA;EACA,SAAA;EACA,eAAA;AAAA;AAAA,iBAGc,uBAAA,CAAwB,KAAA,WAAgB,kBAAA;AAAA,iBA6BxC,mBAAA,CAAoB,MAAA,YAAkB,UAAA,EAAY,kBAAA;AAAA,iBAclD,sBAAA,CAAuB,OAAA;;iBAKvB,gBAAA,CAAiB,MAAA,YAAkB,SAAA;;;AAhDnD;;;;cAkEa,aAAA,SAAsB,WAAA;EAAA,SACxB,IAAA;EAET,OAAA,CAAQ,QAAA,EAAU,cAAA;EAIZ,OAAA,CAAQ,OAAA,EAAS,cAAA,EAAgB,SAAA,EAAW,gBAAA,GAAmB,OAAA;AAAA"}
1
+ {"version":3,"file":"launchCommand.d.mts","names":[],"sources":["../../src/commands/launchCommand.ts"],"mappings":";;;;;;;iBA0BgB,0BAAA,CAA2B,WAAA,EAAa,MAAA,CAAO,UAAA;AAAA,UAO9C,kBAAA;EACf,MAAA;EACA,YAAA;EACA,SAAA;EACA,eAAA;AAAA;AAAA,iBAGc,uBAAA,CAAwB,KAAA,WAAgB,kBAAA;AAAA,iBA6BxC,mBAAA,CAAoB,MAAA,YAAkB,UAAA,EAAY,kBAAA;AAAA,iBAclD,sBAAA,CAAuB,OAAA;;iBAKvB,gBAAA,CAAiB,MAAA,YAAkB,SAAA;;;;;;;cAkBtC,aAAA,SAAsB,WAAA;EAAA,SACxB,IAAA;EAET,OAAA,CAAQ,QAAA,EAAU,cAAA;EAIZ,OAAA,CAAQ,OAAA,EAAS,cAAA,EAAgB,SAAA,EAAW,gBAAA,GAAmB,OAAA;AAAA"}
@@ -1,2 +1,2 @@
1
- import{HARNESS_EVENT as e}from"../logSinkTelemetry.mjs";import{isRecord as t}from"../utils/json.mjs";import{piCliPath as n}from"../utils/moduleResolution.mjs";import"../utils/index.mjs";import{applyProjectTrust as r,hasProjectTrustOption as i,loadDoomConfig as a}from"../config/projectTrust.mjs";import"../config/index.mjs";import{BaseCommand as o}from"./baseCommand.mjs";import{forwardSignals as s,waitForExit as c}from"../services/compatibility/process.mjs";import l from"cross-spawn";const u=`vibe-lint`,d=`pipe`;function f(e){let n;try{n=JSON.parse(e)}catch(e){throw Error(`Expected a JSON vibe-lint invocation on stdin`,{cause:e})}if(!t(n)||typeof n.prompt!=`string`||typeof n.systemPrompt!=`string`)throw Error(`A vibe-lint invocation requires string prompt and systemPrompt fields`);if(n.maxTokens!==void 0&&typeof n.maxTokens!=`number`)throw Error(`A vibe-lint invocation maxTokens field must be a number`);if(n.screenshotPaths!==void 0&&(!Array.isArray(n.screenshotPaths)||!n.screenshotPaths.every(e=>typeof e==`string`)))throw Error(`A vibe-lint invocation screenshotPaths field must be an array of strings`);return{prompt:n.prompt,systemPrompt:n.systemPrompt,maxTokens:n.maxTokens,screenshotPaths:n.screenshotPaths}}function p(e,t){return[...e,`--print`,...i(e)?[]:[`--approve`],`--no-session`,`--system-prompt`,t.systemPrompt,...(t.screenshotPaths??[]).map(e=>`@${e}`),t.prompt]}function m(e){return`${JSON.stringify({content:e.trim()})}\n`}function h(e,t){return[`--no-themes`,`--theme`,t,...e]}async function g(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf-8`)}var _=class extends o{name=`launch`;matches(e){return!0}async execute(t,o){let{options:_,environment:v}=t,{buildRuntimeBundle:y,createRuntimeExtensionPlan:b}=await import(`../services/runtimeBundle.mjs`),{extensions:x,childExtensions:S}=b(t);v.DOOMPI_CHILD_EXTENSIONS=JSON.stringify(S);let C=x;try{C=[(await y(t,{extensions:x,childExtensions:S})).bundle],v.DOOMPI_EXTENSIONS_PROVIDED=`1`}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${t}\n`)}let w;try{w=a(_.repoRoot)}catch(t){throw await o.recordError(e.configLoadFailed,t,{"harness.phase":`load_config`}),t}o.recordEvent(e.projectTrustResolved,{"harness.project_trust":w.projectTrust,"harness.project_trust.overridden":i(_.piArgs)});let T=r(_.piArgs,w);T=h(T,t.defaultThemePath);for(let e of C)T=[`--extension`,e,...T];if(_.outputFormat===u){let e=f(await g());T=p(T,e)}let E=Date.now(),D=l(process.execPath,[n(),...T],{cwd:_.cwd,env:v,stdio:_.outputFormat===u?[`ignore`,d,d]:`inherit`}),O=``;if(_.outputFormat===u){if(!D.stdout||!D.stderr)throw Error(`Failed to open Pi output streams`);D.stdout.on(`data`,e=>{O+=e.toString()}),D.stderr.on(`data`,e=>{process.stderr.write(e)})}let k=s(D),A=await o.runInSpan(`doom_pi.pi_session`,{"harness.extension.count":C.length,"harness.mode":_.outputFormat},()=>c(D)).catch(async t=>{throw await o.recordError(e.launchFailed,t,{"harness.duration_ms":Date.now()-E}),t}).finally(k);return o.recordEvent(e.launchCompleted,{"harness.exit_code":A,"harness.duration_ms":Date.now()-E,"harness.mode":_.outputFormat??`default`}),_.outputFormat===u&&A===0&&process.stdout.write(m(O)),A}};export{_ as LaunchCommand,p as buildVibeLintPiArgs,m as formatVibeLintResponse,h as overridePiThemes,f as parseVibeLintInvocation};
1
+ import{HARNESS_EVENT as e}from"../logSinkTelemetry.mjs";import{isRecord as t}from"../utils/json.mjs";import{piCliPath as n}from"../utils/moduleResolution.mjs";import"../utils/index.mjs";import{applyProjectTrust as r,hasProjectTrustOption as i,loadDoomConfig as a}from"../config/projectTrust.mjs";import"../config/index.mjs";import{BaseCommand as o}from"./baseCommand.mjs";import{forwardSignals as s,waitForExit as c}from"../services/compatibility/process.mjs";import{randomUUID as l}from"node:crypto";import u from"cross-spawn";const d=`vibe-lint`,f=`pipe`,p=`ELICITATION_SESSION_ID`;function m(e){let t=e[p]?.trim()||l();return e[p]=t,t}function h(e){let n;try{n=JSON.parse(e)}catch(e){throw Error(`Expected a JSON vibe-lint invocation on stdin`,{cause:e})}if(!t(n)||typeof n.prompt!=`string`||typeof n.systemPrompt!=`string`)throw Error(`A vibe-lint invocation requires string prompt and systemPrompt fields`);if(n.maxTokens!==void 0&&typeof n.maxTokens!=`number`)throw Error(`A vibe-lint invocation maxTokens field must be a number`);if(n.screenshotPaths!==void 0&&(!Array.isArray(n.screenshotPaths)||!n.screenshotPaths.every(e=>typeof e==`string`)))throw Error(`A vibe-lint invocation screenshotPaths field must be an array of strings`);return{prompt:n.prompt,systemPrompt:n.systemPrompt,maxTokens:n.maxTokens,screenshotPaths:n.screenshotPaths}}function g(e,t){return[...e,`--print`,...i(e)?[]:[`--approve`],`--no-session`,`--system-prompt`,t.systemPrompt,...(t.screenshotPaths??[]).map(e=>`@${e}`),t.prompt]}function _(e){return`${JSON.stringify({content:e.trim()})}\n`}function v(e,t){return[`--no-themes`,`--theme`,t,...e]}async function y(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf-8`)}var b=class extends o{name=`launch`;matches(e){return!0}async execute(t,o){let{options:l,environment:p}=t;m(p);let{buildRuntimeBundle:b,createRuntimeExtensionPlan:x}=await import(`../services/runtimeBundle.mjs`),{extensions:S,childExtensions:C}=x(t);p.DOOMPI_CHILD_EXTENSIONS=JSON.stringify(C);let w=S;try{w=[(await b(t,{extensions:S,childExtensions:C})).bundle],p.DOOMPI_EXTENSIONS_PROVIDED=`1`}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${t}\n`)}let T;try{T=a(l.repoRoot)}catch(t){throw await o.recordError(e.configLoadFailed,t,{"harness.phase":`load_config`}),t}o.recordEvent(e.projectTrustResolved,{"harness.project_trust":T.projectTrust,"harness.project_trust.overridden":i(l.piArgs)});let E=r(l.piArgs,T);E=v(E,t.defaultThemePath);for(let e of w)E=[`--extension`,e,...E];if(l.outputFormat===d){let e=h(await y());E=g(E,e)}let D=Date.now(),O=u(process.execPath,[n(),...E],{cwd:l.cwd,env:p,stdio:l.outputFormat===d?[`ignore`,f,f]:`inherit`}),k=``;if(l.outputFormat===d){if(!O.stdout||!O.stderr)throw Error(`Failed to open Pi output streams`);O.stdout.on(`data`,e=>{k+=e.toString()}),O.stderr.on(`data`,e=>{process.stderr.write(e)})}let A=s(O),j=await o.runInSpan(`doom_pi.pi_session`,{"harness.extension.count":w.length,"harness.mode":l.outputFormat},()=>c(O)).catch(async t=>{throw await o.recordError(e.launchFailed,t,{"harness.duration_ms":Date.now()-D}),t}).finally(A);return o.recordEvent(e.launchCompleted,{"harness.exit_code":j,"harness.duration_ms":Date.now()-D,"harness.mode":l.outputFormat??`default`}),l.outputFormat===d&&j===0&&process.stdout.write(_(k)),j}};export{b as LaunchCommand,g as buildVibeLintPiArgs,m as ensureElicitationSessionId,_ as formatVibeLintResponse,v as overridePiThemes,h as parseVibeLintInvocation};
2
2
  //# sourceMappingURL=launchCommand.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"launchCommand.mjs","names":[],"sources":["../../src/commands/launchCommand.ts"],"sourcesContent":["import spawn from 'cross-spawn';\nimport { applyProjectTrust, hasProjectTrustOption, loadDoomConfig, type DoomConfig } from '../config/index.ts';\nimport type { HarnessOptions } from '../interfaces/index.ts';\nimport { HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport type { HarnessContext } from '../services/index.ts';\nimport { forwardSignals, waitForExit } from '../services/compatibility/process.ts';\nimport { isRecord, piCliPath } from '../utils/index.ts';\nimport { BaseCommand } from './baseCommand.ts';\n\nconst VIBE_LINT_FORMAT = 'vibe-lint';\nconst PRINT_OPTION = '--print';\nconst APPROVE_OPTION = '--approve';\nconst NO_SESSION_OPTION = '--no-session';\nconst SYSTEM_PROMPT_OPTION = '--system-prompt';\nconst THEME_OPTION = '--theme';\nconst NO_THEMES_OPTION = '--no-themes';\nconst EXTENSION_OPTION = '--extension';\nconst IGNORE_STDIO = 'ignore';\nconst PIPE_STDIO = 'pipe';\nconst INHERIT_STDIO = 'inherit';\nconst EXTERNAL_EXTENSIONS_ENV = 'DOOMPI_EXTENSIONS_PROVIDED';\nconst ENABLED_ENV = '1';\n\nexport interface VibeLintInvocation {\n prompt: string;\n systemPrompt: string;\n maxTokens?: number;\n screenshotPaths?: string[];\n}\n\nexport function parseVibeLintInvocation(input: string): VibeLintInvocation {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch (error) {\n throw new Error('Expected a JSON vibe-lint invocation on stdin', { cause: error });\n }\n\n if (!isRecord(parsed) || typeof parsed.prompt !== 'string' || typeof parsed.systemPrompt !== 'string') {\n throw new Error('A vibe-lint invocation requires string prompt and systemPrompt fields');\n }\n if (parsed.maxTokens !== undefined && typeof parsed.maxTokens !== 'number') {\n throw new Error('A vibe-lint invocation maxTokens field must be a number');\n }\n if (\n parsed.screenshotPaths !== undefined &&\n (!Array.isArray(parsed.screenshotPaths) || !parsed.screenshotPaths.every((value) => typeof value === 'string'))\n ) {\n throw new Error('A vibe-lint invocation screenshotPaths field must be an array of strings');\n }\n\n return {\n prompt: parsed.prompt,\n systemPrompt: parsed.systemPrompt,\n maxTokens: parsed.maxTokens,\n screenshotPaths: parsed.screenshotPaths as string[] | undefined,\n };\n}\n\nexport function buildVibeLintPiArgs(piArgs: string[], invocation: VibeLintInvocation): string[] {\n return [\n ...piArgs,\n PRINT_OPTION,\n ...(!hasProjectTrustOption(piArgs) ? [APPROVE_OPTION] : []),\n // Reviews are disposable and must not appear in Pi's resume history.\n NO_SESSION_OPTION,\n SYSTEM_PROMPT_OPTION,\n invocation.systemPrompt,\n ...(invocation.screenshotPaths ?? []).map((screenshotPath) => `@${screenshotPath}`),\n invocation.prompt,\n ];\n}\n\nexport function formatVibeLintResponse(content: string): string {\n return `${JSON.stringify({ content: content.trim() })}\\n`;\n}\n\n/** Ignores configured themes and loads only themes explicitly passed to the launcher. */\nexport function overridePiThemes(piArgs: string[], themePath: string): string[] {\n return [NO_THEMES_OPTION, THEME_OPTION, themePath, ...piArgs];\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\n/**\n * Spawns Pi with the resolved extensions, environment, and theme.\n *\n * This is the default command: it matches whenever no diagnostic flag claimed\n * the run.\n */\nexport class LaunchCommand extends BaseCommand {\n readonly name = 'launch';\n\n matches(_options: HarnessOptions): boolean {\n return true;\n }\n\n async execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number> {\n const { options, environment } = context;\n\n const { buildRuntimeBundle, createRuntimeExtensionPlan } = await import('../services/runtimeBundle.ts');\n const { extensions, childExtensions } = createRuntimeExtensionPlan(context);\n environment.DOOMPI_CHILD_EXTENSIONS = JSON.stringify(childExtensions);\n\n // Pi normally imports each package entry separately. Flattening the exact\n // Pi load order into one graph removes repeated module resolution and parse\n // work. The graph manifest makes the common path a stat-only cache hit;\n // compilation failure keeps the historical extension list intact.\n let launchExtensions = extensions;\n try {\n const built = await buildRuntimeBundle(context, { extensions, childExtensions });\n launchExtensions = [built.bundle];\n // A synced repository also has the doom wrapper in project settings. It\n // must not compose the same factories after this aggregate has run.\n environment[EXTERNAL_EXTENSIONS_ENV] = ENABLED_ENV;\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${detail}\\n`);\n }\n\n // A malformed .doom/config.yaml aborts the launch, and the message only\n // reaches the terminal that ran it, so record it before it propagates.\n let doomConfig: DoomConfig;\n try {\n doomConfig = loadDoomConfig(options.repoRoot);\n } catch (error) {\n await telemetry.recordError(HARNESS_EVENT.configLoadFailed, error, { 'harness.phase': 'load_config' });\n throw error;\n }\n\n // Whether a session ran with repository approval is the single most useful\n // fact when reconstructing what an agent was allowed to do.\n void telemetry.recordEvent(HARNESS_EVENT.projectTrustResolved, {\n 'harness.project_trust': doomConfig.projectTrust,\n 'harness.project_trust.overridden': hasProjectTrustOption(options.piArgs),\n });\n\n let piArgs = applyProjectTrust(options.piArgs, doomConfig);\n piArgs = overridePiThemes(piArgs, context.defaultThemePath);\n for (const extension of launchExtensions) piArgs = [EXTENSION_OPTION, extension, ...piArgs];\n\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n const invocation = parseVibeLintInvocation(await readStdin());\n piArgs = buildVibeLintPiArgs(piArgs, invocation);\n }\n\n const startedAt = Date.now();\n const child = spawn(process.execPath, [piCliPath(), ...piArgs], {\n cwd: options.cwd,\n env: environment,\n stdio: options.outputFormat === VIBE_LINT_FORMAT ? [IGNORE_STDIO, PIPE_STDIO, PIPE_STDIO] : INHERIT_STDIO,\n });\n let stdout = '';\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n if (!child.stdout || !child.stderr) throw new Error('Failed to open Pi output streams');\n child.stdout.on('data', (chunk: string | Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: string | Buffer) => {\n process.stderr.write(chunk);\n });\n }\n\n // Shared with the compatibility providers, so a second Ctrl-C still reaches\n // the child and SIGHUP and SIGQUIT are forwarded too.\n const stopForwarding = forwardSignals(child);\n const result = await telemetry\n .runInSpan(\n 'doom_pi.pi_session',\n {\n 'harness.extension.count': launchExtensions.length,\n 'harness.mode': options.outputFormat,\n },\n () => waitForExit(child),\n )\n .catch(async (error: unknown) => {\n // A spawn error means Pi never started, which is invisible to the\n // session telemetry the child would otherwise have reported.\n await telemetry.recordError(HARNESS_EVENT.launchFailed, error, {\n 'harness.duration_ms': Date.now() - startedAt,\n });\n throw error;\n })\n .finally(stopForwarding);\n\n void telemetry.recordEvent(HARNESS_EVENT.launchCompleted, {\n 'harness.exit_code': result,\n 'harness.duration_ms': Date.now() - startedAt,\n 'harness.mode': options.outputFormat ?? 'default',\n });\n\n if (options.outputFormat === VIBE_LINT_FORMAT && result === 0) {\n process.stdout.write(formatVibeLintResponse(stdout));\n }\n return result;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"launchCommand.mjs","names":[],"sources":["../../src/commands/launchCommand.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport spawn from 'cross-spawn';\nimport { applyProjectTrust, type DoomConfig, hasProjectTrustOption, loadDoomConfig } from '../config/index.ts';\nimport type { HarnessOptions } from '../interfaces/index.ts';\nimport { HARNESS_EVENT, type HarnessTelemetry } from '../logSinkTelemetry.ts';\nimport { forwardSignals, waitForExit } from '../services/compatibility/process.ts';\nimport type { HarnessContext } from '../services/index.ts';\nimport { isRecord, piCliPath } from '../utils/index.ts';\nimport { BaseCommand } from './baseCommand.ts';\n\nconst VIBE_LINT_FORMAT = 'vibe-lint';\nconst PRINT_OPTION = '--print';\nconst APPROVE_OPTION = '--approve';\nconst NO_SESSION_OPTION = '--no-session';\nconst SYSTEM_PROMPT_OPTION = '--system-prompt';\nconst THEME_OPTION = '--theme';\nconst NO_THEMES_OPTION = '--no-themes';\nconst EXTENSION_OPTION = '--extension';\nconst IGNORE_STDIO = 'ignore';\nconst PIPE_STDIO = 'pipe';\nconst INHERIT_STDIO = 'inherit';\nconst EXTERNAL_EXTENSIONS_ENV = 'DOOMPI_EXTENSIONS_PROVIDED';\nconst ENABLED_ENV = '1';\nconst ELICITATION_SESSION_ENV = 'ELICITATION_SESSION_ID';\n\n/** Gives each Doompi launch a stable fallback identity without replacing one supplied by its caller. */\nexport function ensureElicitationSessionId(environment: NodeJS.ProcessEnv): string {\n const provided = environment[ELICITATION_SESSION_ENV]?.trim();\n const sessionId = provided || randomUUID();\n environment[ELICITATION_SESSION_ENV] = sessionId;\n return sessionId;\n}\n\nexport interface VibeLintInvocation {\n prompt: string;\n systemPrompt: string;\n maxTokens?: number;\n screenshotPaths?: string[];\n}\n\nexport function parseVibeLintInvocation(input: string): VibeLintInvocation {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch (error) {\n throw new Error('Expected a JSON vibe-lint invocation on stdin', { cause: error });\n }\n\n if (!isRecord(parsed) || typeof parsed.prompt !== 'string' || typeof parsed.systemPrompt !== 'string') {\n throw new Error('A vibe-lint invocation requires string prompt and systemPrompt fields');\n }\n if (parsed.maxTokens !== undefined && typeof parsed.maxTokens !== 'number') {\n throw new Error('A vibe-lint invocation maxTokens field must be a number');\n }\n if (\n parsed.screenshotPaths !== undefined &&\n (!Array.isArray(parsed.screenshotPaths) || !parsed.screenshotPaths.every((value) => typeof value === 'string'))\n ) {\n throw new Error('A vibe-lint invocation screenshotPaths field must be an array of strings');\n }\n\n return {\n prompt: parsed.prompt,\n systemPrompt: parsed.systemPrompt,\n maxTokens: parsed.maxTokens,\n screenshotPaths: parsed.screenshotPaths as string[] | undefined,\n };\n}\n\nexport function buildVibeLintPiArgs(piArgs: string[], invocation: VibeLintInvocation): string[] {\n return [\n ...piArgs,\n PRINT_OPTION,\n ...(!hasProjectTrustOption(piArgs) ? [APPROVE_OPTION] : []),\n // Reviews are disposable and must not appear in Pi's resume history.\n NO_SESSION_OPTION,\n SYSTEM_PROMPT_OPTION,\n invocation.systemPrompt,\n ...(invocation.screenshotPaths ?? []).map((screenshotPath) => `@${screenshotPath}`),\n invocation.prompt,\n ];\n}\n\nexport function formatVibeLintResponse(content: string): string {\n return `${JSON.stringify({ content: content.trim() })}\\n`;\n}\n\n/** Ignores configured themes and loads only themes explicitly passed to the launcher. */\nexport function overridePiThemes(piArgs: string[], themePath: string): string[] {\n return [NO_THEMES_OPTION, THEME_OPTION, themePath, ...piArgs];\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\n/**\n * Spawns Pi with the resolved extensions, environment, and theme.\n *\n * This is the default command: it matches whenever no diagnostic flag claimed\n * the run.\n */\nexport class LaunchCommand extends BaseCommand {\n readonly name = 'launch';\n\n matches(_options: HarnessOptions): boolean {\n return true;\n }\n\n async execute(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number> {\n const { options, environment } = context;\n ensureElicitationSessionId(environment);\n\n const { buildRuntimeBundle, createRuntimeExtensionPlan } = await import('../services/runtimeBundle.ts');\n const { extensions, childExtensions } = createRuntimeExtensionPlan(context);\n environment.DOOMPI_CHILD_EXTENSIONS = JSON.stringify(childExtensions);\n\n // Pi normally imports each package entry separately. Flattening the exact\n // Pi load order into one graph removes repeated module resolution and parse\n // work. The graph manifest makes the common path a stat-only cache hit;\n // compilation failure keeps the historical extension list intact.\n let launchExtensions = extensions;\n try {\n const built = await buildRuntimeBundle(context, { extensions, childExtensions });\n launchExtensions = [built.bundle];\n // A synced repository also has the doom wrapper in project settings. It\n // must not compose the same factories after this aggregate has run.\n environment[EXTERNAL_EXTENSIONS_ENV] = ENABLED_ENV;\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi] extension bundle unavailable; using individual entries: ${detail}\\n`);\n }\n\n // A malformed .doom/config.yaml aborts the launch, and the message only\n // reaches the terminal that ran it, so record it before it propagates.\n let doomConfig: DoomConfig;\n try {\n doomConfig = loadDoomConfig(options.repoRoot);\n } catch (error) {\n await telemetry.recordError(HARNESS_EVENT.configLoadFailed, error, { 'harness.phase': 'load_config' });\n throw error;\n }\n\n // Whether a session ran with repository approval is the single most useful\n // fact when reconstructing what an agent was allowed to do.\n void telemetry.recordEvent(HARNESS_EVENT.projectTrustResolved, {\n 'harness.project_trust': doomConfig.projectTrust,\n 'harness.project_trust.overridden': hasProjectTrustOption(options.piArgs),\n });\n\n let piArgs = applyProjectTrust(options.piArgs, doomConfig);\n piArgs = overridePiThemes(piArgs, context.defaultThemePath);\n for (const extension of launchExtensions) piArgs = [EXTENSION_OPTION, extension, ...piArgs];\n\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n const invocation = parseVibeLintInvocation(await readStdin());\n piArgs = buildVibeLintPiArgs(piArgs, invocation);\n }\n\n const startedAt = Date.now();\n const child = spawn(process.execPath, [piCliPath(), ...piArgs], {\n cwd: options.cwd,\n env: environment,\n stdio: options.outputFormat === VIBE_LINT_FORMAT ? [IGNORE_STDIO, PIPE_STDIO, PIPE_STDIO] : INHERIT_STDIO,\n });\n let stdout = '';\n if (options.outputFormat === VIBE_LINT_FORMAT) {\n if (!child.stdout || !child.stderr) throw new Error('Failed to open Pi output streams');\n child.stdout.on('data', (chunk: string | Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: string | Buffer) => {\n process.stderr.write(chunk);\n });\n }\n\n // Shared with the compatibility providers, so a second Ctrl-C still reaches\n // the child and SIGHUP and SIGQUIT are forwarded too.\n const stopForwarding = forwardSignals(child);\n const result = await telemetry\n .runInSpan(\n 'doom_pi.pi_session',\n {\n 'harness.extension.count': launchExtensions.length,\n 'harness.mode': options.outputFormat,\n },\n () => waitForExit(child),\n )\n .catch(async (error: unknown) => {\n // A spawn error means Pi never started, which is invisible to the\n // session telemetry the child would otherwise have reported.\n await telemetry.recordError(HARNESS_EVENT.launchFailed, error, {\n 'harness.duration_ms': Date.now() - startedAt,\n });\n throw error;\n })\n .finally(stopForwarding);\n\n void telemetry.recordEvent(HARNESS_EVENT.launchCompleted, {\n 'harness.exit_code': result,\n 'harness.duration_ms': Date.now() - startedAt,\n 'harness.mode': options.outputFormat ?? 'default',\n });\n\n if (options.outputFormat === VIBE_LINT_FORMAT && result === 0) {\n process.stdout.write(formatVibeLintResponse(stdout));\n }\n return result;\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../utils/moduleResolution.cjs`);require(`../utils/index.cjs`);let n=require(`node:fs`);n=e.__toESM(n,1);let r=require(`node:url`),i=require(`node:path`);i=e.__toESM(i,1);let a=require(`node:crypto`),o=require(`node:module`);const s=[`.ts`,`.mts`,`.cts`],c=`.mjs`,l=`\0doompi-extension-set`,u=`@agimon-ai/doompi-ui/extensionName`,d={"@mariozechner/pi-coding-agent":`@earendil-works/pi-coding-agent`,"@mariozechner/pi-tui":`@earendil-works/pi-tui`,"@mariozechner/pi-ai":`@earendil-works/pi-ai`,"@sinclair/typebox":`typebox`};function f(e){return s.some(t=>e.endsWith(t))}function p(e){for(let[t,n]of Object.entries(d)){if(e===t)return n;if(e.startsWith(`${t}/`))return`${n}${e.slice(t.length)}`}return e}function m(e){let t=n.default.readFileSync(e);return(0,a.createHash)(`sha256`).update(`v3`).update(e).update(t).digest(`hex`).slice(0,16)}function h(e,t){let n=i.default.basename(e).replace(/\.[cm]?ts$/,``);return`${i.default.basename(i.default.dirname(e))}-${n}.${t}${c}`}const g=new Set([`@earendil-works/pi-coding-agent`,`@earendil-works/pi-tui`,`@earendil-works/pi-ai`]);function _(e){let n=t.optionalPackageEntry(`@earendil-works/pi-coding-agent`);if(n)try{return(0,o.createRequire)(n).resolve(e)}catch{return}}const v=new Set([`@parcel/watcher`,`@napi-rs/keyring`,`better-sqlite3`,`canvas`,`fsevents`,`isolated-vm`,`keytar`,`node-pty`,`onnxruntime-node`,`playwright`,`playwright-core`,`puppeteer`,`sharp`,`typescript`]),y=new Set(o.builtinModules.flatMap(e=>[e,`node:${e}`]));function b(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^[-.]+|[-.]+$/g,``)||`doom-set`}function x(e){let t=e.startsWith(`@`)?e.indexOf(`/`,e.indexOf(`/`)+1):e.indexOf(`/`);return t===-1?e:e.slice(0,t)}function S(e){let t=e.split(i.default.sep).join(`/`),n=t.lastIndexOf(`/node_modules/`);if(n===-1)return;let r=t.slice(n+14).split(`/`),a=r.lastIndexOf(`node_modules`),o=a===-1?r:r.slice(a+1);return o[0]?.startsWith(`@`)?o.slice(0,2).join(`/`):o[0]}function C(){return{name:`doom-external-absolute`,async resolveId(e,n,r){if(e.startsWith(`.`)||i.default.isAbsolute(e)||e.startsWith(`node:`))return null;let a=p(e),o=x(a);if(o&&g.has(o)){let e=t.optionalPackageEntry(a);if(e)return{id:e,external:!0}}let s=await this.resolve(a,n,r);return!s||f(s.id)?null:{id:s.id,external:!0}}}}function w(e){try{let t=n.default.statSync(e);return t.isFile()?{path:e,size:t.size,mtimeMs:t.mtimeMs}:void 0}catch{return}}function T(e,t){return e.version!==`v6`||JSON.stringify(e.entries)!==JSON.stringify(t)||!n.default.existsSync(e.output)?!1:e.inputs.every(e=>{let t=w(e.path);return t?.size===e.size&&t.mtimeMs===e.mtimeMs})}function E(e){try{let t=JSON.parse(n.default.readFileSync(e,`utf8`));return t&&Array.isArray(t.entries)&&Array.isArray(t.inputs)?t:void 0}catch{return}}function D(e,t){let r=`${e}.${process.pid}.${Date.now()}.tmp`;n.default.writeFileSync(r,t);try{n.default.renameSync(r,e)}catch(t){if(n.default.rmSync(r,{force:!0}),!n.default.existsSync(e))throw t}}function O(e){return(0,a.createHash)(`sha256`).update(`v6`).update(JSON.stringify(e.map(e=>i.default.resolve(e)))).digest(`hex`).slice(0,16)}function k(e){let n=t.optionalPackageEntry(u);if(!n)throw Error(`Cannot resolve ${u}`);let r=e.map(e=>`() => import(${JSON.stringify(A(e))})`),i=e.map(e=>JSON.stringify(e));return[`import { withExtensionSource } from ${JSON.stringify(A(n))};`,`const loaders = [${r.join(`,`)}];`,`const names = [${i.join(`,`)}];`,`function report(index, error) {`,` const detail = error instanceof Error ? error.message : String(error);`,` process.stderr.write("[doompi] " + names[index] + ": " + detail + "\\n");`,`}`,`export default async function doompiExtensionSet(pi) {`,` const loaded = await Promise.all(loaders.map(async (load, index) => {`,` try {`,` return await load();`,` } catch (error) {`,` report(index, error);`,` return undefined;`,` }`,` }));`,` for (let index = 0; index < loaded.length; index += 1) {`,` const extension = loaded[index];`,` if (!extension) continue;`,` try {`,` if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');`,` await extension.default(withExtensionSource(pi, names[index]));`,` } catch (error) {`,` report(index, error);`,` }`,` }`,`}`].join(`
2
- `)}function A(e){return i.default.resolve(e).split(i.default.sep).join(`/`)}function j(e){return{name:`doom-set-external`,async resolveId(n,r,a){if(n===l)return null;if(y.has(n)||n.startsWith(`node:`))return{id:n,external:!0};if(i.default.isAbsolute(n)){let t=S(n);return t&&(g.has(t)||v.has(t))?(e.add(n),{id:n,external:!0}):null}if(n.startsWith(`.`))return null;let o=p(n),s=x(o);if(s&&g.has(s)){let n=t.optionalPackageEntry(o);if(n)return e.add(n),{id:n,external:!0}}if(s===`typebox`){let t=_(o);if(t)return e.add(t),{id:t,external:!1}}if(s&&v.has(s)){let t=await this.resolve(o,r,a);if(t)return e.add(t.id),{id:t.id,external:!0}}return null}}}function M(e){return{name:`doom-set-inputs`,load(t){return i.default.isAbsolute(t)&&n.default.existsSync(t)&&e.add(t),null}}}function N(e,t,n){t.code===`UNRESOLVED_IMPORT`&&n(`error`,t)}function P(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function F(e,t){if(Array.isArray(e)){for(let n of e)F(n,t);return}if(!P(e))return;let n=e.object,r=e.property;if(e.type===`MemberExpression`&&e.computed===!1&&typeof e.start==`number`&&typeof e.end==`number`&&P(n)&&n.type===`MetaProperty`&&P(n.meta)&&n.meta.name===`import`&&P(n.property)&&n.property.name===`meta`&&P(r)&&r.name===`url`){t.push({start:e.start,end:e.end});return}for(let n of Object.values(e))F(n,t)}function I(){return{name:`doom-original-import-meta-url`,transform(e,t){if(!i.default.isAbsolute(t)||!e.includes(`import.meta.url`))return null;let n=i.default.extname(t).toLowerCase(),a=n===`.tsx`?`tsx`:n===`.jsx`?`jsx`:f(t)?`ts`:`js`,o=[];if(F(this.parse(e,{lang:a}),o),o.length===0)return null;let s=JSON.stringify((0,r.pathToFileURL)(t).href),c=e;for(let e of o.sort((e,t)=>t.start-e.start))c=`${c.slice(0,e.start)}${s}${c.slice(e.end)}`;return c}}}async function L(e,t,r={}){if(e.length===0)throw Error(`Cannot compile an empty extension set`);let o=e.map(e=>i.default.resolve(e)),s=i.default.join(t,`sets`);n.default.mkdirSync(s,{recursive:!0});let u=O(o),d=i.default.resolve(r.outputDirectory??s),f=b(r.outputName??`doom-set`);n.default.mkdirSync(d,{recursive:!0});let p=(0,a.createHash)(`sha256`).update(d).update(f).digest(`hex`).slice(0,16),m=i.default.join(s,`${u}.${p}.json`),h=E(m);if(h&&T(h,o))return h.output;let g=new Set(o),_=k(o),{rolldown:v}=await import(`rolldown`),y=await v({input:l,platform:`node`,plugins:[{name:`doom-set-entry`,resolveId(e){return e===l?e:null},load(e){return e===l?_:null}},j(g),I(),M(g)],onLog:N}),x;try{let e=(await y.generate({format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!1})).output.find(e=>e.type===`chunk`);if(!e||e.type!==`chunk`)throw Error(`Rolldown produced no extension bundle`);x=e.code}finally{await y.close()}let S=(0,a.createHash)(`sha256`).update(`v6`).update(x).digest(`hex`).slice(0,16),C=i.default.join(d,`${f}.${S}${c}`);n.default.existsSync(C)||D(C,x);let A=[...g].map(w).filter(e=>e!==void 0).sort((e,t)=>e.path.localeCompare(t.path));return D(m,`${JSON.stringify({version:`v6`,entries:o,output:C,inputs:A},null,2)}\n`),C}async function R(e,t){if(!f(e))return e;let r=i.default.join(t,h(e,m(e)));if(n.default.existsSync(r))return r;let{rolldown:a}=await import(`rolldown`),o=await a({input:e,platform:`node`,plugins:[C(),I()],onLog:N});try{await o.write({file:r,format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!1})}finally{await o.close()}return r}async function z(e,t){n.default.mkdirSync(t,{recursive:!0});let r={};for(let[n,i]of Object.entries(e))try{r[n]=await R(i,t)}catch{r[n]=i}return r}exports.compileExtensionSet=L,exports.compileResolvedEntries=z,exports.extensionSetKey=O;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../utils/moduleResolution.cjs`);require(`../utils/index.cjs`);let n=require(`node:fs`);n=e.__toESM(n,1);let r=require(`node:url`),i=require(`node:path`);i=e.__toESM(i,1);let a=require(`node:crypto`),o=require(`node:module`);const s=[`.ts`,`.mts`,`.cts`],c=`.mjs`,l=`.json`,u=`\0doompi-extension-set`,d=`@agimon-ai/doompi-ui/extensionName`,f={"@mariozechner/pi-coding-agent":`@earendil-works/pi-coding-agent`,"@mariozechner/pi-tui":`@earendil-works/pi-tui`,"@mariozechner/pi-ai":`@earendil-works/pi-ai`,"@sinclair/typebox":`typebox`};function p(e){return s.some(t=>e.endsWith(t))}function m(e){for(let[t,n]of Object.entries(f)){if(e===t)return n;if(e.startsWith(`${t}/`))return`${n}${e.slice(t.length)}`}return e}function h(e){let t=n.default.readFileSync(e);return(0,a.createHash)(`sha256`).update(`v4`).update(e).update(t).digest(`hex`).slice(0,16)}function g(e,t){let n=i.default.basename(e).replace(/\.[cm]?ts$/,``);return`${i.default.basename(i.default.dirname(e))}-${n}.${t}${c}`}const _=new Set([`@earendil-works/pi-coding-agent`,`@earendil-works/pi-tui`,`@earendil-works/pi-ai`]);function v(e){let n=t.optionalPackageEntry(`@earendil-works/pi-coding-agent`);if(n)try{return(0,o.createRequire)(n).resolve(e)}catch{return}}const y=new Set([`@parcel/watcher`,`@napi-rs/keyring`,`better-sqlite3`,`canvas`,`fsevents`,`isolated-vm`,`keytar`,`node-pty`,`onnxruntime-node`,`playwright`,`playwright-core`,`puppeteer`,`sharp`,`typescript`]),b=new Set(o.builtinModules.flatMap(e=>[e,`node:${e}`]));function x(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^[-.]+|[-.]+$/g,``)||`doom-set`}function S(e){let t=e.startsWith(`@`)?e.indexOf(`/`,e.indexOf(`/`)+1):e.indexOf(`/`);return t===-1?e:e.slice(0,t)}function C(e){let t=e.split(i.default.sep).join(`/`),n=t.lastIndexOf(`/node_modules/`);if(n===-1)return;let r=t.slice(n+14).split(`/`),a=r.lastIndexOf(`node_modules`),o=a===-1?r:r.slice(a+1);return o[0]?.startsWith(`@`)?o.slice(0,2).join(`/`):o[0]}function w(){return{name:`doom-external-absolute`,async resolveId(e,n,r){if(e.startsWith(`.`)||i.default.isAbsolute(e)||e.startsWith(`node:`))return null;let a=m(e),o=S(a);if(o&&_.has(o)){let e=t.optionalPackageEntry(a);if(e)return{id:e,external:!0}}let s=await this.resolve(a,n,r);return!s||p(s.id)?null:{id:s.id,external:!0}}}}function T(e){try{let t=n.default.statSync(e);return t.isFile()?{path:e,size:t.size,mtimeMs:t.mtimeMs}:void 0}catch{return}}function E(e,t,r){return e.version===t&&e.output===r&&n.default.existsSync(r)&&e.artifacts.every(e=>n.default.existsSync(e))}function D(e,t){return!E(e,`v7`,e.output)||JSON.stringify(e.entries)!==JSON.stringify(t)?!1:e.inputs.every(e=>{let t=T(e.path);return t?.size===e.size&&t.mtimeMs===e.mtimeMs})}function O(e){try{let t=JSON.parse(n.default.readFileSync(e,`utf8`));return t&&typeof t.output==`string`&&Array.isArray(t.artifacts)?t:void 0}catch{return}}function k(e){let t=O(e);return t&&Array.isArray(t.entries)&&Array.isArray(t.inputs)?t:void 0}function A(e,t){n.default.mkdirSync(i.default.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${Date.now()}.tmp`;n.default.writeFileSync(r,t);try{n.default.renameSync(r,e)}catch(t){if(n.default.rmSync(r,{force:!0}),!n.default.existsSync(e))throw t}}function j(e){return{format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!0,hashCharacters:`hex`,entryFileNames:e,chunkFileNames:`chunks/[name].[hash:16]${c}`,assetFileNames:`assets/[name].[hash:16][extname]`}}function M(e,t){let n=i.default.resolve(e,t.fileName),r=i.default.relative(e,n);if(r.startsWith(`..`)||i.default.isAbsolute(r))throw Error(`Rolldown emitted an artifact outside the output directory: ${t.fileName}`);return n}function N(e,t){let r=e.output.find(e=>e.type===`chunk`&&e.isEntry);if(!r||r.type!==`chunk`)throw Error(`Rolldown produced no extension entry`);let a=i.default.resolve(t),o=e.output.filter(e=>e!==r);for(let e of[...o,r]){let t=e.type===`chunk`?e.code:e.source,r=M(a,e);n.default.existsSync(r)||A(r,t)}return{entry:M(a,r),artifacts:e.output.map(e=>M(a,e)).sort()}}function P(e){return(0,a.createHash)(`sha256`).update(`v7`).update(JSON.stringify(e.map(e=>i.default.resolve(e)))).digest(`hex`).slice(0,16)}function F(e){let n=t.optionalPackageEntry(d);if(!n)throw Error(`Cannot resolve ${d}`);let r=e.map(e=>`() => import(${JSON.stringify(I(e))})`),i=e.map(e=>JSON.stringify(e));return[`import { withExtensionSource } from ${JSON.stringify(I(n))};`,`const loaders = [${r.join(`,`)}];`,`const names = [${i.join(`,`)}];`,`function report(index, error) {`,` const detail = error instanceof Error ? error.message : String(error);`,` process.stderr.write("[doompi] " + names[index] + ": " + detail + "\\n");`,`}`,`export default async function doompiExtensionSet(pi) {`,` const loaded = await Promise.all(loaders.map(async (load, index) => {`,` try {`,` return await load();`,` } catch (error) {`,` report(index, error);`,` return undefined;`,` }`,` }));`,` for (let index = 0; index < loaded.length; index += 1) {`,` const extension = loaded[index];`,` if (!extension) continue;`,` try {`,` if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');`,` await extension.default(withExtensionSource(pi, names[index]));`,` } catch (error) {`,` report(index, error);`,` }`,` }`,`}`].join(`
2
+ `)}function I(e){return i.default.resolve(e).split(i.default.sep).join(`/`)}function L(e){return{name:`doom-set-external`,async resolveId(n,r,a){if(n===u)return null;if(b.has(n)||n.startsWith(`node:`))return{id:n,external:!0};if(i.default.isAbsolute(n)){let t=C(n);return t&&(_.has(t)||y.has(t))?(e.add(n),{id:n,external:!0}):null}if(n.startsWith(`.`))return null;let o=m(n),s=S(o);if(s&&_.has(s)){let n=t.optionalPackageEntry(o);if(n)return e.add(n),{id:n,external:!0}}if(s===`typebox`){let t=v(o);if(t)return e.add(t),{id:t,external:!1}}if(s&&y.has(s)){let t=await this.resolve(o,r,a);if(t)return e.add(t.id),{id:t.id,external:!0}}return null}}}function R(e){return{name:`doom-set-inputs`,load(t){return i.default.isAbsolute(t)&&n.default.existsSync(t)&&e.add(t),null}}}function z(e,t,n){t.code===`UNRESOLVED_IMPORT`&&n(`error`,t)}function B(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function V(e,t){if(Array.isArray(e)){for(let n of e)V(n,t);return}if(!B(e))return;let n=e.object,r=e.property;if(e.type===`MemberExpression`&&e.computed===!1&&typeof e.start==`number`&&typeof e.end==`number`&&B(n)&&n.type===`MetaProperty`&&B(n.meta)&&n.meta.name===`import`&&B(n.property)&&n.property.name===`meta`&&B(r)&&r.name===`url`){t.push({start:e.start,end:e.end});return}for(let n of Object.values(e))V(n,t)}function H(){return{name:`doom-original-import-meta-url`,transform(e,t){if(!i.default.isAbsolute(t)||!e.includes(`import.meta.url`))return null;let n=i.default.extname(t).toLowerCase(),a=n===`.tsx`?`tsx`:n===`.jsx`?`jsx`:p(t)?`ts`:`js`,o=[];if(V(this.parse(e,{lang:a}),o),o.length===0)return null;let s=JSON.stringify((0,r.pathToFileURL)(t).href),c=e;for(let e of o.sort((e,t)=>t.start-e.start))c=`${c.slice(0,e.start)}${s}${c.slice(e.end)}`;return c}}}async function U(e,t,r={}){if(e.length===0)throw Error(`Cannot compile an empty extension set`);let o=e.map(e=>i.default.resolve(e)),s=i.default.join(t,`sets`);n.default.mkdirSync(s,{recursive:!0});let d=P(o),f=i.default.resolve(r.outputDirectory??s),p=x(r.outputName??`doom-set`);n.default.mkdirSync(f,{recursive:!0});let m=(0,a.createHash)(`sha256`).update(f).update(p).digest(`hex`).slice(0,16),h=i.default.join(s,`${d}.${m}${l}`),g=k(h);if(g&&D(g,o))return g.output;let _=new Set(o),v=F(o),{rolldown:y}=await import(`rolldown`),b=await y({input:u,platform:`node`,plugins:[{name:`doom-set-entry`,resolveId(e){return e===u?e:null},load(e){return e===u?v:null}},L(_),H(),R(_)],onLog:z}),S;try{S=N(await b.generate(j(`${p}.[hash:16]${c}`)),f)}finally{await b.close()}let C=S.entry,w=[..._].map(T).filter(e=>e!==void 0).sort((e,t)=>e.path.localeCompare(t.path));return A(h,`${JSON.stringify({version:`v7`,entries:o,output:C,artifacts:S.artifacts,inputs:w},null,2)}\n`),C}async function W(e,t){if(!p(e))return e;n.default.mkdirSync(t,{recursive:!0});let r=g(e,h(e)),a=i.default.join(t,r),o=`${a}${l}`,s=O(o);if(s&&E(s,`v4`,a))return a;let{rolldown:c}=await import(`rolldown`),u=await c({input:e,platform:`node`,plugins:[w(),H()],onLog:z}),d;try{d=N(await u.generate(j(r)),t)}finally{await u.close()}return A(o,`${JSON.stringify({version:`v4`,output:a,artifacts:d.artifacts},null,2)}\n`),a}async function G(e,t){n.default.mkdirSync(t,{recursive:!0});let r={};for(let[n,i]of Object.entries(e))try{r[n]=await W(i,t)}catch{r[n]=i}return r}exports.compileExtensionSet=U,exports.compileResolvedEntries=G,exports.extensionSetKey=P;
3
3
  //# sourceMappingURL=extensionCompiler.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensionCompiler.cjs","names":["fs","path","optionalPackageEntry","builtinModules"],"sources":["../../src/services/extensionCompiler.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport { builtinModules, createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { LogLevel, LogOrStringHandler, RolldownLog } from 'rolldown';\nimport { optionalPackageEntry } from '../utils/index.ts';\n\n/**\n * Compiles TypeScript extensions into plain ESM ahead of the session.\n *\n * Pi loads extensions through jiti, which transpiles TypeScript at import time.\n * That works, but it costs a transform per module on a cold cache and makes Node\n * complain about type stripping under node_modules on every launch. Resolution\n * already knows the full extension list, so each TypeScript entry is bundled to\n * a single `.mjs` here and Pi imports it natively.\n *\n * Mode artifacts bundle their JavaScript dependencies. Node built-ins, native\n * packages, and Pi's shared runtime stay external; those imports are rewritten\n * to absolute paths so an artifact under `.pi/doom/dist` never relies on that\n * directory having its own `node_modules` tree.\n */\n\nconst TYPESCRIPT_SUFFIXES = ['.ts', '.mts', '.cts'] as const;\nconst COMPILED_SUFFIX = '.mjs';\nconst CACHE_VERSION = 'v3';\nconst SET_CACHE_VERSION = 'v6';\nconst HASH_LENGTH = 16;\nconst SET_DIRECTORY = 'sets';\nconst MANIFEST_SUFFIX = '.json';\nconst VIRTUAL_SET_ENTRY = '\\0doompi-extension-set';\nconst EXTENSION_SOURCE_HELPER = '@agimon-ai/doompi-ui/extensionName';\n\n/** Pi's former npm scope. The packages are the same, published under a new name. */\nconst PI_SCOPE_RENAMES: Readonly<Record<string, string>> = {\n '@mariozechner/pi-coding-agent': '@earendil-works/pi-coding-agent',\n '@mariozechner/pi-tui': '@earendil-works/pi-tui',\n '@mariozechner/pi-ai': '@earendil-works/pi-ai',\n '@sinclair/typebox': 'typebox',\n};\n\nexport function isTypeScriptEntry(entry: string): boolean {\n return TYPESCRIPT_SUFFIXES.some((suffix) => entry.endsWith(suffix));\n}\n\nfunction renameScope(specifier: string): string {\n for (const [before, after] of Object.entries(PI_SCOPE_RENAMES)) {\n if (specifier === before) return after;\n if (specifier.startsWith(`${before}/`)) return `${after}${specifier.slice(before.length)}`;\n }\n return specifier;\n}\n\n/**\n * Cache key for a compiled entry.\n *\n * The entry's own bytes are the only cheap signal that the extension changed; a\n * dependency edit is not visible without walking the graph, so an upgrade that\n * leaves the entry byte-identical is served from cache until the version below\n * is raised.\n */\nfunction cacheKey(entry: string): string {\n const source = fs.readFileSync(entry);\n return createHash('sha256').update(CACHE_VERSION).update(entry).update(source).digest('hex').slice(0, HASH_LENGTH);\n}\n\nfunction compiledName(entry: string, key: string): string {\n const base = path.basename(entry).replace(/\\.[cm]?ts$/, '');\n const parent = path.basename(path.dirname(entry));\n return `${parent}-${base}.${key}${COMPILED_SUFFIX}`;\n}\n\n/**\n * Packages that must resolve to the copy this harness runs, never to a second\n * one bundled into an extension. Pi owns the TUI and the session state, so a\n * duplicate renders into a different screen and mutates a different store.\n */\nconst HOSTED_PACKAGES = new Set(['@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', '@earendil-works/pi-ai']);\n\n/**\n * Resolves packages Pi exposes to extensions as compatibility aliases.\n *\n * Extensions do not need to declare TypeBox themselves because Pi's loader\n * provides it as a virtual module. A dist bundle bypasses that loader, so it\n * resolves the same package against Pi's dependency tree and bundles it.\n */\nfunction piExtensionDependencyEntry(specifier: string): string | undefined {\n const piEntry = optionalPackageEntry('@earendil-works/pi-coding-agent');\n if (!piEntry) return undefined;\n try {\n return createRequire(piEntry).resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Packages whose native binaries or runtime discovery cannot be rolled up. */\nconst NATIVE_PACKAGES = new Set([\n '@parcel/watcher',\n '@napi-rs/keyring',\n 'better-sqlite3',\n 'canvas',\n 'fsevents',\n 'isolated-vm',\n 'keytar',\n 'node-pty',\n 'onnxruntime-node',\n 'playwright',\n 'playwright-core',\n 'puppeteer',\n 'sharp',\n // TypeScript's Node system adapter reads CommonJS globals such as\n // __filename. Rolldown does not provide those globals when it folds the\n // adapter into the aggregate ESM extension, so keep the installed runtime\n // intact and import it by its resolved absolute path.\n 'typescript',\n]);\nconst NODE_BUILTINS = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface ExtensionSetManifest {\n version: string;\n entries: string[];\n output: string;\n inputs: InputFingerprint[];\n}\n\nexport interface CompileExtensionSetOptions {\n /** Persistent artifact directory. Compiler manifests remain in cacheDirectory. */\n outputDirectory?: string;\n /** Human-readable artifact prefix, normally the major-mode name. */\n outputName?: string;\n}\n\nfunction safeOutputName(value: string): string {\n const normalized = value\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '');\n return normalized || 'doom-set';\n}\n\nfunction packageRootOf(specifier: string): string | undefined {\n const slash = specifier.startsWith('@') ? specifier.indexOf('/', specifier.indexOf('/') + 1) : specifier.indexOf('/');\n return slash === -1 ? specifier : specifier.slice(0, slash);\n}\n\nfunction packageRootFromPath(target: string): string | undefined {\n const normalized = target.split(path.sep).join('/');\n const marker = '/node_modules/';\n const offset = normalized.lastIndexOf(marker);\n if (offset === -1) return undefined;\n const parts = normalized.slice(offset + marker.length).split('/');\n // pnpm's first segment is a store key; the second node_modules marker names\n // the package that owns the file.\n const nested = parts.lastIndexOf('node_modules');\n const packageParts = nested === -1 ? parts : parts.slice(nested + 1);\n return packageParts[0]?.startsWith('@') ? packageParts.slice(0, 2).join('/') : packageParts[0];\n}\n\nfunction externalResolver() {\n return {\n name: 'doom-external-absolute',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier.startsWith('.') || path.isAbsolute(specifier) || specifier.startsWith('node:')) return null;\n const renamed = renameScope(specifier);\n\n // Host packages are resolved from this module, the way the rest of the\n // harness resolves them, because an extension written against Pi's former\n // scope does not have the current one in its own dependency tree.\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) return { id: hosted, external: true };\n }\n\n // Rolldown's resolver rather than `createRequire`, which cannot see an\n // ESM-only package that publishes no `require` condition and would send\n // Pi's own core into the bundle.\n const resolved = await this.resolve(renamed, importer, options);\n if (!resolved) return null;\n // A dependency that is itself TypeScript cannot be handed to Node either,\n // so it is bundled rather than externalised.\n if (isTypeScriptEntry(resolved.id)) return null;\n return { id: resolved.id, external: true };\n },\n };\n}\n\nfunction fingerprint(target: string): InputFingerprint | undefined {\n try {\n const stat = fs.statSync(target);\n if (!stat.isFile()) return undefined;\n return { path: target, size: stat.size, mtimeMs: stat.mtimeMs };\n } catch {\n return undefined;\n }\n}\n\nfunction manifestIsFresh(manifest: ExtensionSetManifest, entries: string[]): boolean {\n if (\n manifest.version !== SET_CACHE_VERSION ||\n JSON.stringify(manifest.entries) !== JSON.stringify(entries) ||\n !fs.existsSync(manifest.output)\n ) {\n return false;\n }\n return manifest.inputs.every((previous) => {\n const current = fingerprint(previous.path);\n return current?.size === previous.size && current.mtimeMs === previous.mtimeMs;\n });\n}\n\nfunction readSetManifest(manifestPath: string): ExtensionSetManifest | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as ExtensionSetManifest;\n return parsed && Array.isArray(parsed.entries) && Array.isArray(parsed.inputs) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction writeAtomic(target: string, contents: string): void {\n const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, contents);\n try {\n fs.renameSync(temporary, target);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(target)) throw error;\n }\n}\n\n/** Stable lookup key for one exact Pi load order. */\nexport function extensionSetKey(entries: readonly string[]): string {\n return createHash('sha256')\n .update(SET_CACHE_VERSION)\n .update(JSON.stringify(entries.map((entry) => path.resolve(entry))))\n .digest('hex')\n .slice(0, HASH_LENGTH);\n}\n\nfunction extensionSetSource(entries: readonly string[]): string {\n const helper = optionalPackageEntry(EXTENSION_SOURCE_HELPER);\n if (!helper) throw new Error(`Cannot resolve ${EXTENSION_SOURCE_HELPER}`);\n const loaders = entries.map((entry) => `() => import(${JSON.stringify(pathToImportSpecifier(entry))})`);\n const names = entries.map((entry) => JSON.stringify(entry));\n return [\n `import { withExtensionSource } from ${JSON.stringify(pathToImportSpecifier(helper))};`,\n `const loaders = [${loaders.join(',')}];`,\n `const names = [${names.join(',')}];`,\n 'function report(index, error) {',\n ' const detail = error instanceof Error ? error.message : String(error);',\n ' process.stderr.write(\"[doompi] \" + names[index] + \": \" + detail + \"\\\\n\");',\n '}',\n 'export default async function doompiExtensionSet(pi) {',\n ' const loaded = await Promise.all(loaders.map(async (load, index) => {',\n ' try {',\n ' return await load();',\n ' } catch (error) {',\n ' report(index, error);',\n ' return undefined;',\n ' }',\n ' }));',\n ' for (let index = 0; index < loaded.length; index += 1) {',\n ' const extension = loaded[index];',\n ' if (!extension) continue;',\n ' try {',\n \" if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');\",\n ' await extension.default(withExtensionSource(pi, names[index]));',\n ' } catch (error) {',\n ' report(index, error);',\n ' }',\n ' }',\n '}',\n ].join('\\n');\n}\n\nfunction pathToImportSpecifier(target: string): string {\n // Rolldown accepts absolute POSIX paths directly. Windows needs a file URL,\n // but replacing separators is enough for its platform-independent parser.\n return path.resolve(target).split(path.sep).join('/');\n}\n\nfunction setExternalResolver(inputs: Set<string>) {\n return {\n name: 'doom-set-external',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier === VIRTUAL_SET_ENTRY) return null;\n if (NODE_BUILTINS.has(specifier) || specifier.startsWith('node:')) {\n return { id: specifier, external: true };\n }\n\n if (path.isAbsolute(specifier)) {\n const root = packageRootFromPath(specifier);\n if (root && (HOSTED_PACKAGES.has(root) || NATIVE_PACKAGES.has(root))) {\n inputs.add(specifier);\n return { id: specifier, external: true };\n }\n return null;\n }\n if (specifier.startsWith('.')) return null;\n\n const renamed = renameScope(specifier);\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) {\n inputs.add(hosted);\n return { id: hosted, external: true };\n }\n }\n if (root === 'typebox') {\n const typebox = piExtensionDependencyEntry(renamed);\n if (typebox) {\n inputs.add(typebox);\n return { id: typebox, external: false };\n }\n }\n if (root && NATIVE_PACKAGES.has(root)) {\n const resolved = await this.resolve(renamed, importer, options);\n if (resolved) {\n inputs.add(resolved.id);\n return { id: resolved.id, external: true };\n }\n }\n return null;\n },\n };\n}\n\nfunction inputCollector(inputs: Set<string>) {\n return {\n name: 'doom-set-inputs',\n load(id: string): null {\n if (path.isAbsolute(id) && fs.existsSync(id)) inputs.add(id);\n return null;\n },\n };\n}\n\n/** An unresolved bare import would otherwise become a broken dist external. */\nfunction failUnresolvedImport(_level: LogLevel, log: RolldownLog, handler: LogOrStringHandler): void {\n if (log.code === 'UNRESOLVED_IMPORT') handler('error', log);\n}\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectImportMetaUrlRanges(value: unknown, ranges: SourceRange[]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectImportMetaUrlRanges(item, ranges);\n return;\n }\n if (!isRecord(value)) return;\n\n const object = value.object;\n const property = value.property;\n if (\n value.type === 'MemberExpression' &&\n value.computed === false &&\n typeof value.start === 'number' &&\n typeof value.end === 'number' &&\n isRecord(object) &&\n object.type === 'MetaProperty' &&\n isRecord(object.meta) &&\n object.meta.name === 'import' &&\n isRecord(object.property) &&\n object.property.name === 'meta' &&\n isRecord(property) &&\n property.name === 'url'\n ) {\n ranges.push({ start: value.start, end: value.end });\n return;\n }\n\n for (const child of Object.values(value)) collectImportMetaUrlRanges(child, ranges);\n}\n\n/** Keeps package-owned resource lookup anchored to each original source file. */\nfunction preserveImportMetaUrl() {\n return {\n name: 'doom-original-import-meta-url',\n transform(\n this: {\n parse: (source: string, options?: { lang?: 'js' | 'jsx' | 'ts' | 'tsx' }) => unknown;\n },\n source: string,\n id: string,\n ): string | null {\n if (!path.isAbsolute(id) || !source.includes('import.meta.url')) return null;\n const extension = path.extname(id).toLowerCase();\n const lang = extension === '.tsx' ? 'tsx' : extension === '.jsx' ? 'jsx' : isTypeScriptEntry(id) ? 'ts' : 'js';\n const ranges: SourceRange[] = [];\n collectImportMetaUrlRanges(this.parse(source, { lang }), ranges);\n if (ranges.length === 0) return null;\n const replacement = JSON.stringify(pathToFileURL(id).href);\n let transformed = source;\n for (const range of ranges.sort((left, right) => right.start - left.start)) {\n transformed = `${transformed.slice(0, range.start)}${replacement}${transformed.slice(range.end)}`;\n }\n return transformed;\n },\n };\n}\n\n/**\n * Compiles an ordered extension set into one native ESM entry.\n *\n * The generated entry starts every module load together, then invokes factories\n * sequentially in activation order. Its manifest records every loaded module,\n * so a dependency edit invalidates the cache without running the compiler.\n */\nexport async function compileExtensionSet(\n entries: readonly string[],\n cacheDirectory: string,\n options: CompileExtensionSetOptions = {},\n): Promise<string> {\n if (entries.length === 0) throw new Error('Cannot compile an empty extension set');\n const normalized = entries.map((entry) => path.resolve(entry));\n const setDirectory = path.join(cacheDirectory, SET_DIRECTORY);\n fs.mkdirSync(setDirectory, { recursive: true });\n const key = extensionSetKey(normalized);\n const outputDirectory = path.resolve(options.outputDirectory ?? setDirectory);\n const outputName = safeOutputName(options.outputName ?? 'doom-set');\n fs.mkdirSync(outputDirectory, { recursive: true });\n // One graph can be emitted under several named mode artifacts. Keep their\n // cache records separate without changing extensionSetKey, which is the\n // runtime lookup key for an exact activation order.\n const outputKey = createHash('sha256').update(outputDirectory).update(outputName).digest('hex').slice(0, HASH_LENGTH);\n const manifestPath = path.join(setDirectory, `${key}.${outputKey}${MANIFEST_SUFFIX}`);\n const previous = readSetManifest(manifestPath);\n if (previous && manifestIsFresh(previous, normalized)) return previous.output;\n\n const inputs = new Set(normalized);\n const source = extensionSetSource(normalized);\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: VIRTUAL_SET_ENTRY,\n platform: 'node',\n plugins: [\n {\n name: 'doom-set-entry',\n resolveId(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? id : null;\n },\n load(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? source : null;\n },\n },\n setExternalResolver(inputs),\n preserveImportMetaUrl(),\n inputCollector(inputs),\n ],\n onLog: failUnresolvedImport,\n });\n let code: string;\n try {\n const generated = await build.generate({ format: 'esm', sourcemap: false, minify: true, codeSplitting: false });\n const chunk = generated.output.find((output) => output.type === 'chunk');\n if (!chunk || chunk.type !== 'chunk') throw new Error('Rolldown produced no extension bundle');\n code = chunk.code;\n } finally {\n await build.close();\n }\n\n const contentKey = createHash('sha256').update(SET_CACHE_VERSION).update(code).digest('hex').slice(0, HASH_LENGTH);\n const output = path.join(outputDirectory, `${outputName}.${contentKey}${COMPILED_SUFFIX}`);\n if (!fs.existsSync(output)) writeAtomic(output, code);\n const inputFingerprints = [...inputs]\n .map(fingerprint)\n .filter((value): value is InputFingerprint => value !== undefined)\n .sort((left, right) => left.path.localeCompare(right.path));\n writeAtomic(\n manifestPath,\n `${JSON.stringify({ version: SET_CACHE_VERSION, entries: normalized, output, inputs: inputFingerprints }, null, 2)}\\n`,\n );\n return output;\n}\n\n/**\n * Bundles `entry` into `cacheDirectory` and returns the compiled path.\n *\n * Non-TypeScript entries are returned untouched. A cache hit skips the build.\n */\nexport async function compileExtension(entry: string, cacheDirectory: string): Promise<string> {\n if (!isTypeScriptEntry(entry)) return entry;\n\n const output = path.join(cacheDirectory, compiledName(entry, cacheKey(entry)));\n if (fs.existsSync(output)) return output;\n\n // Rolldown loads a native module and a sizeable parser graph. Sync is the\n // only command that needs it, and a cache hit does not, so keep it off every\n // other CLI startup path.\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: entry,\n platform: 'node',\n plugins: [externalResolver(), preserveImportMetaUrl()],\n onLog: failUnresolvedImport,\n });\n try {\n // One file per extension. Several of them import lazily, and code splitting\n // would emit sibling chunks that a single output path cannot describe.\n await build.write({ file: output, format: 'esm', sourcemap: false, minify: true, codeSplitting: false });\n } finally {\n await build.close();\n }\n return output;\n}\n\n/**\n * Compiles every TypeScript entry in a resolution map, leaving the rest as-is.\n *\n * A failure is not fatal: the original path is kept so Pi falls back to loading\n * the TypeScript through jiti, which is what it did before this existed.\n */\nexport async function compileResolvedEntries(\n resolved: Record<string, string>,\n cacheDirectory: string,\n): Promise<Record<string, string>> {\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const compiled: Record<string, string> = {};\n for (const [key, target] of Object.entries(resolved)) {\n try {\n compiled[key] = await compileExtension(target, cacheDirectory);\n } catch {\n compiled[key] = target;\n }\n }\n return compiled;\n}\n"],"mappings":"gSAuBA,MAAM,EAAsB,CAAC,MAAO,OAAQ,OAAO,CAC7C,EAAkB,OAMlB,EAAoB,yBACpB,EAA0B,qCAG1B,EAAqD,CACzD,gCAAiC,kCACjC,uBAAwB,yBACxB,sBAAuB,wBACvB,oBAAqB,UACtB,CAED,SAAgB,EAAkB,EAAwB,CACxD,OAAO,EAAoB,KAAM,GAAW,EAAM,SAAS,EAAO,CAAC,CAGrE,SAAS,EAAY,EAA2B,CAC9C,IAAK,GAAM,CAAC,EAAQ,KAAU,OAAO,QAAQ,EAAiB,CAAE,CAC9D,GAAI,IAAc,EAAQ,OAAO,EACjC,GAAI,EAAU,WAAW,GAAG,EAAO,GAAG,CAAE,MAAO,GAAG,IAAQ,EAAU,MAAM,EAAO,OAAO,GAE1F,OAAO,EAWT,SAAS,EAAS,EAAuB,CACvC,IAAM,EAASA,EAAAA,QAAG,aAAa,EAAM,CACrC,OAAA,EAAA,EAAA,YAAkB,SAAS,CAAC,OAAO,KAAc,CAAC,OAAO,EAAM,CAAC,OAAO,EAAO,CAAC,OAAO,MAAM,CAAC,MAAM,EAAG,GAAY,CAGpH,SAAS,EAAa,EAAe,EAAqB,CACxD,IAAM,EAAOC,EAAAA,QAAK,SAAS,EAAM,CAAC,QAAQ,aAAc,GAAG,CAE3D,MAAO,GADQA,EAAAA,QAAK,SAASA,EAAAA,QAAK,QAAQ,EAAM,CAChC,CAAC,GAAG,EAAK,GAAG,IAAM,IAQpC,MAAM,EAAkB,IAAI,IAAI,CAAC,kCAAmC,yBAA0B,wBAAwB,CAAC,CASvH,SAAS,EAA2B,EAAuC,CACzE,IAAM,EAAUC,EAAAA,qBAAqB,kCAAkC,CAClE,KACL,GAAI,CACF,OAAA,EAAA,EAAA,eAAqB,EAAQ,CAAC,QAAQ,EAAU,MAC1C,CACN,QAKJ,MAAM,EAAkB,IAAI,IAAI,CAC9B,kBACA,mBACA,iBACA,SACA,WACA,cACA,SACA,WACA,mBACA,aACA,kBACA,YACA,QAKA,aACD,CAAC,CACI,EAAgB,IAAI,IAAIC,EAAAA,eAAe,QAAS,GAAS,CAAC,EAAM,QAAQ,IAAO,CAAC,CAAC,CAsBvF,SAAS,EAAe,EAAuB,CAK7C,OAJmB,EAChB,MAAM,CACN,QAAQ,oBAAqB,IAAI,CACjC,QAAQ,iBAAkB,GACZ,EAAI,WAGvB,SAAS,EAAc,EAAuC,CAC5D,IAAM,EAAQ,EAAU,WAAW,IAAI,CAAG,EAAU,QAAQ,IAAK,EAAU,QAAQ,IAAI,CAAG,EAAE,CAAG,EAAU,QAAQ,IAAI,CACrH,OAAO,IAAU,GAAK,EAAY,EAAU,MAAM,EAAG,EAAM,CAG7D,SAAS,EAAoB,EAAoC,CAC/D,IAAM,EAAa,EAAO,MAAMF,EAAAA,QAAK,IAAI,CAAC,KAAK,IAAI,CAE7C,EAAS,EAAW,YAAY,iBAAO,CAC7C,GAAI,IAAW,GAAI,OACnB,IAAM,EAAQ,EAAW,MAAM,EAAS,GAAc,CAAC,MAAM,IAAI,CAG3D,EAAS,EAAM,YAAY,eAAe,CAC1C,EAAe,IAAW,GAAK,EAAQ,EAAM,MAAM,EAAS,EAAE,CACpE,OAAO,EAAa,IAAI,WAAW,IAAI,CAAG,EAAa,MAAM,EAAG,EAAE,CAAC,KAAK,IAAI,CAAG,EAAa,GAG9F,SAAS,GAAmB,CAC1B,MAAO,CACL,KAAM,yBACN,MAAM,UAEJ,EACA,EACA,EACmD,CACnD,GAAI,EAAU,WAAW,IAAI,EAAIA,EAAAA,QAAK,WAAW,EAAU,EAAI,EAAU,WAAW,QAAQ,CAAE,OAAO,KACrG,IAAM,EAAU,EAAY,EAAU,CAKhC,EAAO,EAAc,EAAQ,CACnC,GAAI,GAAQ,EAAgB,IAAI,EAAK,CAAE,CACrC,IAAM,EAASC,EAAAA,qBAAqB,EAAQ,CAC5C,GAAI,EAAQ,MAAO,CAAE,GAAI,EAAQ,SAAU,GAAM,CAMnD,IAAM,EAAW,MAAM,KAAK,QAAQ,EAAS,EAAU,EAAQ,CAK/D,MAJI,CAAC,GAGD,EAAkB,EAAS,GAAG,CAAS,KACpC,CAAE,GAAI,EAAS,GAAI,SAAU,GAAM,EAE7C,CAGH,SAAS,EAAY,EAA8C,CACjE,GAAI,CACF,IAAM,EAAOF,EAAAA,QAAG,SAAS,EAAO,CAEhC,OADK,EAAK,QAAQ,CACX,CAAE,KAAM,EAAQ,KAAM,EAAK,KAAM,QAAS,EAAK,QAAS,CAD3C,YAEd,CACN,QAIJ,SAAS,EAAgB,EAAgC,EAA4B,CAQnF,OANE,EAAS,UAAY,MACrB,KAAK,UAAU,EAAS,QAAQ,GAAK,KAAK,UAAU,EAAQ,EAC5D,CAACA,EAAAA,QAAG,WAAW,EAAS,OAAO,CAExB,GAEF,EAAS,OAAO,MAAO,GAAa,CACzC,IAAM,EAAU,EAAY,EAAS,KAAK,CAC1C,OAAO,GAAS,OAAS,EAAS,MAAQ,EAAQ,UAAY,EAAS,SACvE,CAGJ,SAAS,EAAgB,EAAwD,CAC/E,GAAI,CACF,IAAM,EAAS,KAAK,MAAMA,EAAAA,QAAG,aAAa,EAAc,OAAO,CAAC,CAChE,OAAO,GAAU,MAAM,QAAQ,EAAO,QAAQ,EAAI,MAAM,QAAQ,EAAO,OAAO,CAAG,EAAS,IAAA,QACpF,CACN,QAIJ,SAAS,EAAY,EAAgB,EAAwB,CAC3D,IAAM,EAAY,GAAG,EAAO,GAAG,QAAQ,IAAI,GAAG,KAAK,KAAK,CAAC,MACzD,EAAA,QAAG,cAAc,EAAW,EAAS,CACrC,GAAI,CACF,EAAA,QAAG,WAAW,EAAW,EAAO,OACzB,EAAO,CAEd,GADA,EAAA,QAAG,OAAO,EAAW,CAAE,MAAO,GAAM,CAAC,CACjC,CAACA,EAAAA,QAAG,WAAW,EAAO,CAAE,MAAM,GAKtC,SAAgB,EAAgB,EAAoC,CAClE,OAAA,EAAA,EAAA,YAAkB,SAAS,CACxB,OAAO,KAAkB,CACzB,OAAO,KAAK,UAAU,EAAQ,IAAK,GAAUC,EAAAA,QAAK,QAAQ,EAAM,CAAC,CAAC,CAAC,CACnE,OAAO,MAAM,CACb,MAAM,EAAG,GAAY,CAG1B,SAAS,EAAmB,EAAoC,CAC9D,IAAM,EAASC,EAAAA,qBAAqB,EAAwB,CAC5D,GAAI,CAAC,EAAQ,MAAU,MAAM,kBAAkB,IAA0B,CACzE,IAAM,EAAU,EAAQ,IAAK,GAAU,gBAAgB,KAAK,UAAU,EAAsB,EAAM,CAAC,CAAC,GAAG,CACjG,EAAQ,EAAQ,IAAK,GAAU,KAAK,UAAU,EAAM,CAAC,CAC3D,MAAO,CACL,uCAAuC,KAAK,UAAU,EAAsB,EAAO,CAAC,CAAC,GACrF,oBAAoB,EAAQ,KAAK,IAAI,CAAC,IACtC,kBAAkB,EAAM,KAAK,IAAI,CAAC,IAClC,kCACA,2EACA,8EACA,IACA,yDACA,0EACA,YACA,6BACA,wBACA,8BACA,0BACA,QACA,SACA,6DACA,uCACA,gCACA,YACA,8GACA,wEACA,wBACA,8BACA,QACA,MACA,IACD,CAAC,KAAK;EAAK,CAGd,SAAS,EAAsB,EAAwB,CAGrD,OAAOD,EAAAA,QAAK,QAAQ,EAAO,CAAC,MAAMA,EAAAA,QAAK,IAAI,CAAC,KAAK,IAAI,CAGvD,SAAS,EAAoB,EAAqB,CAChD,MAAO,CACL,KAAM,oBACN,MAAM,UAEJ,EACA,EACA,EACmD,CACnD,GAAI,IAAc,EAAmB,OAAO,KAC5C,GAAI,EAAc,IAAI,EAAU,EAAI,EAAU,WAAW,QAAQ,CAC/D,MAAO,CAAE,GAAI,EAAW,SAAU,GAAM,CAG1C,GAAIA,EAAAA,QAAK,WAAW,EAAU,CAAE,CAC9B,IAAM,EAAO,EAAoB,EAAU,CAK3C,OAJI,IAAS,EAAgB,IAAI,EAAK,EAAI,EAAgB,IAAI,EAAK,GACjE,EAAO,IAAI,EAAU,CACd,CAAE,GAAI,EAAW,SAAU,GAAM,EAEnC,KAET,GAAI,EAAU,WAAW,IAAI,CAAE,OAAO,KAEtC,IAAM,EAAU,EAAY,EAAU,CAChC,EAAO,EAAc,EAAQ,CACnC,GAAI,GAAQ,EAAgB,IAAI,EAAK,CAAE,CACrC,IAAM,EAASC,EAAAA,qBAAqB,EAAQ,CAC5C,GAAI,EAEF,OADA,EAAO,IAAI,EAAO,CACX,CAAE,GAAI,EAAQ,SAAU,GAAM,CAGzC,GAAI,IAAS,UAAW,CACtB,IAAM,EAAU,EAA2B,EAAQ,CACnD,GAAI,EAEF,OADA,EAAO,IAAI,EAAQ,CACZ,CAAE,GAAI,EAAS,SAAU,GAAO,CAG3C,GAAI,GAAQ,EAAgB,IAAI,EAAK,CAAE,CACrC,IAAM,EAAW,MAAM,KAAK,QAAQ,EAAS,EAAU,EAAQ,CAC/D,GAAI,EAEF,OADA,EAAO,IAAI,EAAS,GAAG,CAChB,CAAE,GAAI,EAAS,GAAI,SAAU,GAAM,CAG9C,OAAO,MAEV,CAGH,SAAS,EAAe,EAAqB,CAC3C,MAAO,CACL,KAAM,kBACN,KAAK,EAAkB,CAErB,OADID,EAAAA,QAAK,WAAW,EAAG,EAAID,EAAAA,QAAG,WAAW,EAAG,EAAE,EAAO,IAAI,EAAG,CACrD,MAEV,CAIH,SAAS,EAAqB,EAAkB,EAAkB,EAAmC,CAC/F,EAAI,OAAS,qBAAqB,EAAQ,QAAS,EAAI,CAQ7D,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,EAAM,CAG7E,SAAS,EAA2B,EAAgB,EAA6B,CAC/E,GAAI,MAAM,QAAQ,EAAM,CAAE,CACxB,IAAK,IAAM,KAAQ,EAAO,EAA2B,EAAM,EAAO,CAClE,OAEF,GAAI,CAAC,EAAS,EAAM,CAAE,OAEtB,IAAM,EAAS,EAAM,OACf,EAAW,EAAM,SACvB,GACE,EAAM,OAAS,oBACf,EAAM,WAAa,IACnB,OAAO,EAAM,OAAU,UACvB,OAAO,EAAM,KAAQ,UACrB,EAAS,EAAO,EAChB,EAAO,OAAS,gBAChB,EAAS,EAAO,KAAK,EACrB,EAAO,KAAK,OAAS,UACrB,EAAS,EAAO,SAAS,EACzB,EAAO,SAAS,OAAS,QACzB,EAAS,EAAS,EAClB,EAAS,OAAS,MAClB,CACA,EAAO,KAAK,CAAE,MAAO,EAAM,MAAO,IAAK,EAAM,IAAK,CAAC,CACnD,OAGF,IAAK,IAAM,KAAS,OAAO,OAAO,EAAM,CAAE,EAA2B,EAAO,EAAO,CAIrF,SAAS,GAAwB,CAC/B,MAAO,CACL,KAAM,gCACN,UAIE,EACA,EACe,CACf,GAAI,CAACC,EAAAA,QAAK,WAAW,EAAG,EAAI,CAAC,EAAO,SAAS,kBAAkB,CAAE,OAAO,KACxE,IAAM,EAAYA,EAAAA,QAAK,QAAQ,EAAG,CAAC,aAAa,CAC1C,EAAO,IAAc,OAAS,MAAQ,IAAc,OAAS,MAAQ,EAAkB,EAAG,CAAG,KAAO,KACpG,EAAwB,EAAE,CAEhC,GADA,EAA2B,KAAK,MAAM,EAAQ,CAAE,OAAM,CAAC,CAAE,EAAO,CAC5D,EAAO,SAAW,EAAG,OAAO,KAChC,IAAM,EAAc,KAAK,WAAA,EAAA,EAAA,eAAwB,EAAG,CAAC,KAAK,CACtD,EAAc,EAClB,IAAK,IAAM,KAAS,EAAO,MAAM,EAAM,IAAU,EAAM,MAAQ,EAAK,MAAM,CACxE,EAAc,GAAG,EAAY,MAAM,EAAG,EAAM,MAAM,GAAG,IAAc,EAAY,MAAM,EAAM,IAAI,GAEjG,OAAO,GAEV,CAUH,eAAsB,EACpB,EACA,EACA,EAAsC,EAAE,CACvB,CACjB,GAAI,EAAQ,SAAW,EAAG,MAAU,MAAM,wCAAwC,CAClF,IAAM,EAAa,EAAQ,IAAK,GAAUA,EAAAA,QAAK,QAAQ,EAAM,CAAC,CACxD,EAAeA,EAAAA,QAAK,KAAK,EAAgB,OAAc,CAC7D,EAAA,QAAG,UAAU,EAAc,CAAE,UAAW,GAAM,CAAC,CAC/C,IAAM,EAAM,EAAgB,EAAW,CACjC,EAAkBA,EAAAA,QAAK,QAAQ,EAAQ,iBAAmB,EAAa,CACvE,EAAa,EAAe,EAAQ,YAAc,WAAW,CACnE,EAAA,QAAG,UAAU,EAAiB,CAAE,UAAW,GAAM,CAAC,CAIlD,IAAM,GAAA,EAAA,EAAA,YAAuB,SAAS,CAAC,OAAO,EAAgB,CAAC,OAAO,EAAW,CAAC,OAAO,MAAM,CAAC,MAAM,EAAG,GAAY,CAC/G,EAAeA,EAAAA,QAAK,KAAK,EAAc,GAAG,EAAI,GAAG,SAA8B,CAC/E,EAAW,EAAgB,EAAa,CAC9C,GAAI,GAAY,EAAgB,EAAU,EAAW,CAAE,OAAO,EAAS,OAEvE,IAAM,EAAS,IAAI,IAAI,EAAW,CAC5B,EAAS,EAAmB,EAAW,CACvC,CAAE,YAAa,MAAM,OAAO,YAC5B,EAAQ,MAAM,EAAS,CAC3B,MAAO,EACP,SAAU,OACV,QAAS,CACP,CACE,KAAM,iBACN,UAAU,EAA2B,CACnC,OAAO,IAAO,EAAoB,EAAK,MAEzC,KAAK,EAA2B,CAC9B,OAAO,IAAO,EAAoB,EAAS,MAE9C,CACD,EAAoB,EAAO,CAC3B,GAAuB,CACvB,EAAe,EAAO,CACvB,CACD,MAAO,EACR,CAAC,CACE,EACJ,GAAI,CAEF,IAAM,GAAQ,MADU,EAAM,SAAS,CAAE,OAAQ,MAAO,UAAW,GAAO,OAAQ,GAAM,cAAe,GAAO,CAAC,EACvF,OAAO,KAAM,GAAW,EAAO,OAAS,QAAQ,CACxE,GAAI,CAAC,GAAS,EAAM,OAAS,QAAS,MAAU,MAAM,wCAAwC,CAC9F,EAAO,EAAM,YACL,CACR,MAAM,EAAM,OAAO,CAGrB,IAAM,GAAA,EAAA,EAAA,YAAwB,SAAS,CAAC,OAAO,KAAkB,CAAC,OAAO,EAAK,CAAC,OAAO,MAAM,CAAC,MAAM,EAAG,GAAY,CAC5G,EAASA,EAAAA,QAAK,KAAK,EAAiB,GAAG,EAAW,GAAG,IAAa,IAAkB,CACrFD,EAAAA,QAAG,WAAW,EAAO,EAAE,EAAY,EAAQ,EAAK,CACrD,IAAM,EAAoB,CAAC,GAAG,EAAO,CAClC,IAAI,EAAY,CAChB,OAAQ,GAAqC,IAAU,IAAA,GAAU,CACjE,MAAM,EAAM,IAAU,EAAK,KAAK,cAAc,EAAM,KAAK,CAAC,CAK7D,OAJA,EACE,EACA,GAAG,KAAK,UAAU,CAAE,QAAS,KAAmB,QAAS,EAAY,SAAQ,OAAQ,EAAmB,CAAE,KAAM,EAAE,CAAC,IACpH,CACM,EAQT,eAAsB,EAAiB,EAAe,EAAyC,CAC7F,GAAI,CAAC,EAAkB,EAAM,CAAE,OAAO,EAEtC,IAAM,EAASC,EAAAA,QAAK,KAAK,EAAgB,EAAa,EAAO,EAAS,EAAM,CAAC,CAAC,CAC9E,GAAID,EAAAA,QAAG,WAAW,EAAO,CAAE,OAAO,EAKlC,GAAM,CAAE,YAAa,MAAM,OAAO,YAC5B,EAAQ,MAAM,EAAS,CAC3B,MAAO,EACP,SAAU,OACV,QAAS,CAAC,GAAkB,CAAE,GAAuB,CAAC,CACtD,MAAO,EACR,CAAC,CACF,GAAI,CAGF,MAAM,EAAM,MAAM,CAAE,KAAM,EAAQ,OAAQ,MAAO,UAAW,GAAO,OAAQ,GAAM,cAAe,GAAO,CAAC,QAChG,CACR,MAAM,EAAM,OAAO,CAErB,OAAO,EAST,eAAsB,EACpB,EACA,EACiC,CACjC,EAAA,QAAG,UAAU,EAAgB,CAAE,UAAW,GAAM,CAAC,CACjD,IAAM,EAAmC,EAAE,CAC3C,IAAK,GAAM,CAAC,EAAK,KAAW,OAAO,QAAQ,EAAS,CAClD,GAAI,CACF,EAAS,GAAO,MAAM,EAAiB,EAAQ,EAAe,MACxD,CACN,EAAS,GAAO,EAGpB,OAAO"}
1
+ {"version":3,"file":"extensionCompiler.cjs","names":["fs","path","optionalPackageEntry","builtinModules"],"sources":["../../src/services/extensionCompiler.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport { builtinModules, createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { LogLevel, LogOrStringHandler, OutputAsset, OutputChunk, RolldownLog, RolldownOutput } from 'rolldown';\nimport { optionalPackageEntry } from '../utils/index.ts';\n\n/**\n * Compiles TypeScript extensions into plain ESM ahead of the session.\n *\n * Pi loads extensions through jiti, which transpiles TypeScript at import time.\n * That works, but it costs a transform per module on a cold cache and makes Node\n * complain about type stripping under node_modules on every launch. Resolution\n * already knows the full extension list, so each TypeScript graph is compiled\n * to native ESM here and Pi imports it without a runtime transform. Lazy imports\n * remain separate content-addressed chunks so their evaluation semantics survive\n * compilation.\n *\n * Mode artifacts bundle their JavaScript dependencies. Node built-ins, native\n * packages, and Pi's shared runtime stay external; those imports are rewritten\n * to absolute paths so an artifact under `.pi/doom/dist` never relies on that\n * directory having its own `node_modules` tree.\n */\n\nconst TYPESCRIPT_SUFFIXES = ['.ts', '.mts', '.cts'] as const;\nconst COMPILED_SUFFIX = '.mjs';\nconst CACHE_VERSION = 'v4';\nconst SET_CACHE_VERSION = 'v7';\nconst HASH_LENGTH = 16;\nconst SET_DIRECTORY = 'sets';\nconst MANIFEST_SUFFIX = '.json';\nconst VIRTUAL_SET_ENTRY = '\\0doompi-extension-set';\nconst EXTENSION_SOURCE_HELPER = '@agimon-ai/doompi-ui/extensionName';\n\n/** Pi's former npm scope. The packages are the same, published under a new name. */\nconst PI_SCOPE_RENAMES: Readonly<Record<string, string>> = {\n '@mariozechner/pi-coding-agent': '@earendil-works/pi-coding-agent',\n '@mariozechner/pi-tui': '@earendil-works/pi-tui',\n '@mariozechner/pi-ai': '@earendil-works/pi-ai',\n '@sinclair/typebox': 'typebox',\n};\n\nexport function isTypeScriptEntry(entry: string): boolean {\n return TYPESCRIPT_SUFFIXES.some((suffix) => entry.endsWith(suffix));\n}\n\nfunction renameScope(specifier: string): string {\n for (const [before, after] of Object.entries(PI_SCOPE_RENAMES)) {\n if (specifier === before) return after;\n if (specifier.startsWith(`${before}/`)) return `${after}${specifier.slice(before.length)}`;\n }\n return specifier;\n}\n\n/**\n * Cache key for a compiled entry.\n *\n * The entry's own bytes are the only cheap signal that the extension changed; a\n * dependency edit is not visible without walking the graph, so an upgrade that\n * leaves the entry byte-identical is served from cache until the version below\n * is raised.\n */\nfunction cacheKey(entry: string): string {\n const source = fs.readFileSync(entry);\n return createHash('sha256').update(CACHE_VERSION).update(entry).update(source).digest('hex').slice(0, HASH_LENGTH);\n}\n\nfunction compiledName(entry: string, key: string): string {\n const base = path.basename(entry).replace(/\\.[cm]?ts$/, '');\n const parent = path.basename(path.dirname(entry));\n return `${parent}-${base}.${key}${COMPILED_SUFFIX}`;\n}\n\n/**\n * Packages that must resolve to the copy this harness runs, never to a second\n * one bundled into an extension. Pi owns the TUI and the session state, so a\n * duplicate renders into a different screen and mutates a different store.\n */\nconst HOSTED_PACKAGES = new Set(['@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', '@earendil-works/pi-ai']);\n\n/**\n * Resolves packages Pi exposes to extensions as compatibility aliases.\n *\n * Extensions do not need to declare TypeBox themselves because Pi's loader\n * provides it as a virtual module. A dist bundle bypasses that loader, so it\n * resolves the same package against Pi's dependency tree and bundles it.\n */\nfunction piExtensionDependencyEntry(specifier: string): string | undefined {\n const piEntry = optionalPackageEntry('@earendil-works/pi-coding-agent');\n if (!piEntry) return undefined;\n try {\n return createRequire(piEntry).resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Packages whose native binaries or runtime discovery cannot be rolled up. */\nconst NATIVE_PACKAGES = new Set([\n '@parcel/watcher',\n '@napi-rs/keyring',\n 'better-sqlite3',\n 'canvas',\n 'fsevents',\n 'isolated-vm',\n 'keytar',\n 'node-pty',\n 'onnxruntime-node',\n 'playwright',\n 'playwright-core',\n 'puppeteer',\n 'sharp',\n // TypeScript's Node system adapter reads CommonJS globals such as\n // __filename. Rolldown does not provide those globals when it folds the\n // adapter into the aggregate ESM extension, so keep the installed runtime\n // intact and import it by its resolved absolute path.\n 'typescript',\n]);\nconst NODE_BUILTINS = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompiledExtensionManifest {\n version: string;\n output: string;\n artifacts: string[];\n}\n\ninterface ExtensionSetManifest extends CompiledExtensionManifest {\n entries: string[];\n inputs: InputFingerprint[];\n}\n\nexport interface CompileExtensionSetOptions {\n /** Persistent artifact directory. Compiler manifests remain in cacheDirectory. */\n outputDirectory?: string;\n /** Human-readable artifact prefix, normally the major-mode name. */\n outputName?: string;\n}\n\nfunction safeOutputName(value: string): string {\n const normalized = value\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '');\n return normalized || 'doom-set';\n}\n\nfunction packageRootOf(specifier: string): string | undefined {\n const slash = specifier.startsWith('@') ? specifier.indexOf('/', specifier.indexOf('/') + 1) : specifier.indexOf('/');\n return slash === -1 ? specifier : specifier.slice(0, slash);\n}\n\nfunction packageRootFromPath(target: string): string | undefined {\n const normalized = target.split(path.sep).join('/');\n const marker = '/node_modules/';\n const offset = normalized.lastIndexOf(marker);\n if (offset === -1) return undefined;\n const parts = normalized.slice(offset + marker.length).split('/');\n // pnpm's first segment is a store key; the second node_modules marker names\n // the package that owns the file.\n const nested = parts.lastIndexOf('node_modules');\n const packageParts = nested === -1 ? parts : parts.slice(nested + 1);\n return packageParts[0]?.startsWith('@') ? packageParts.slice(0, 2).join('/') : packageParts[0];\n}\n\nfunction externalResolver() {\n return {\n name: 'doom-external-absolute',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier.startsWith('.') || path.isAbsolute(specifier) || specifier.startsWith('node:')) return null;\n const renamed = renameScope(specifier);\n\n // Host packages are resolved from this module, the way the rest of the\n // harness resolves them, because an extension written against Pi's former\n // scope does not have the current one in its own dependency tree.\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) return { id: hosted, external: true };\n }\n\n // Rolldown's resolver rather than `createRequire`, which cannot see an\n // ESM-only package that publishes no `require` condition and would send\n // Pi's own core into the bundle.\n const resolved = await this.resolve(renamed, importer, options);\n if (!resolved) return null;\n // A dependency that is itself TypeScript cannot be handed to Node either,\n // so it is bundled rather than externalised.\n if (isTypeScriptEntry(resolved.id)) return null;\n return { id: resolved.id, external: true };\n },\n };\n}\n\nfunction fingerprint(target: string): InputFingerprint | undefined {\n try {\n const stat = fs.statSync(target);\n if (!stat.isFile()) return undefined;\n return { path: target, size: stat.size, mtimeMs: stat.mtimeMs };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactsAreFresh(manifest: CompiledExtensionManifest, version: string, output: string): boolean {\n return (\n manifest.version === version &&\n manifest.output === output &&\n fs.existsSync(output) &&\n manifest.artifacts.every((artifact) => fs.existsSync(artifact))\n );\n}\n\nfunction manifestIsFresh(manifest: ExtensionSetManifest, entries: string[]): boolean {\n if (!artifactsAreFresh(manifest, SET_CACHE_VERSION, manifest.output)) return false;\n if (JSON.stringify(manifest.entries) !== JSON.stringify(entries)) {\n return false;\n }\n return manifest.inputs.every((previous) => {\n const current = fingerprint(previous.path);\n return current?.size === previous.size && current.mtimeMs === previous.mtimeMs;\n });\n}\n\nfunction readCompiledExtensionManifest(manifestPath: string): CompiledExtensionManifest | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as CompiledExtensionManifest;\n return parsed && typeof parsed.output === 'string' && Array.isArray(parsed.artifacts) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readSetManifest(manifestPath: string): ExtensionSetManifest | undefined {\n const parsed = readCompiledExtensionManifest(manifestPath) as ExtensionSetManifest | undefined;\n return parsed && Array.isArray(parsed.entries) && Array.isArray(parsed.inputs) ? parsed : undefined;\n}\n\nfunction writeAtomic(target: string, contents: string | Uint8Array): void {\n fs.mkdirSync(path.dirname(target), { recursive: true });\n const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, contents);\n try {\n fs.renameSync(temporary, target);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(target)) throw error;\n }\n}\n\ninterface CompiledGraph {\n entry: string;\n artifacts: string[];\n}\n\nfunction splitOutputOptions(entryFileNames: string) {\n return {\n format: 'esm' as const,\n sourcemap: false,\n minify: true,\n codeSplitting: true,\n hashCharacters: 'hex' as const,\n entryFileNames,\n chunkFileNames: `chunks/[name].[hash:${HASH_LENGTH}]${COMPILED_SUFFIX}`,\n assetFileNames: `assets/[name].[hash:${HASH_LENGTH}][extname]`,\n };\n}\n\nfunction artifactTarget(outputDirectory: string, artifact: OutputAsset | OutputChunk): string {\n const target = path.resolve(outputDirectory, artifact.fileName);\n const relative = path.relative(outputDirectory, target);\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error(`Rolldown emitted an artifact outside the output directory: ${artifact.fileName}`);\n }\n return target;\n}\n\n/** Writes referenced chunks first so a visible entry always has a complete graph. */\nfunction writeCompiledGraph(generated: RolldownOutput, outputDirectory: string): CompiledGraph {\n const entry = generated.output.find((artifact) => artifact.type === 'chunk' && artifact.isEntry);\n if (!entry || entry.type !== 'chunk') throw new Error('Rolldown produced no extension entry');\n const root = path.resolve(outputDirectory);\n const remaining = generated.output.filter((artifact) => artifact !== entry);\n for (const artifact of [...remaining, entry]) {\n const contents = artifact.type === 'chunk' ? artifact.code : artifact.source;\n const target = artifactTarget(root, artifact);\n if (!fs.existsSync(target)) writeAtomic(target, contents);\n }\n return {\n entry: artifactTarget(root, entry),\n artifacts: generated.output.map((artifact) => artifactTarget(root, artifact)).sort(),\n };\n}\n\n/** Stable lookup key for one exact Pi load order. */\nexport function extensionSetKey(entries: readonly string[]): string {\n return createHash('sha256')\n .update(SET_CACHE_VERSION)\n .update(JSON.stringify(entries.map((entry) => path.resolve(entry))))\n .digest('hex')\n .slice(0, HASH_LENGTH);\n}\n\nfunction extensionSetSource(entries: readonly string[]): string {\n const helper = optionalPackageEntry(EXTENSION_SOURCE_HELPER);\n if (!helper) throw new Error(`Cannot resolve ${EXTENSION_SOURCE_HELPER}`);\n const loaders = entries.map((entry) => `() => import(${JSON.stringify(pathToImportSpecifier(entry))})`);\n const names = entries.map((entry) => JSON.stringify(entry));\n return [\n `import { withExtensionSource } from ${JSON.stringify(pathToImportSpecifier(helper))};`,\n `const loaders = [${loaders.join(',')}];`,\n `const names = [${names.join(',')}];`,\n 'function report(index, error) {',\n ' const detail = error instanceof Error ? error.message : String(error);',\n ' process.stderr.write(\"[doompi] \" + names[index] + \": \" + detail + \"\\\\n\");',\n '}',\n 'export default async function doompiExtensionSet(pi) {',\n ' const loaded = await Promise.all(loaders.map(async (load, index) => {',\n ' try {',\n ' return await load();',\n ' } catch (error) {',\n ' report(index, error);',\n ' return undefined;',\n ' }',\n ' }));',\n ' for (let index = 0; index < loaded.length; index += 1) {',\n ' const extension = loaded[index];',\n ' if (!extension) continue;',\n ' try {',\n \" if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');\",\n ' await extension.default(withExtensionSource(pi, names[index]));',\n ' } catch (error) {',\n ' report(index, error);',\n ' }',\n ' }',\n '}',\n ].join('\\n');\n}\n\nfunction pathToImportSpecifier(target: string): string {\n // Rolldown accepts absolute POSIX paths directly. Windows needs a file URL,\n // but replacing separators is enough for its platform-independent parser.\n return path.resolve(target).split(path.sep).join('/');\n}\n\nfunction setExternalResolver(inputs: Set<string>) {\n return {\n name: 'doom-set-external',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier === VIRTUAL_SET_ENTRY) return null;\n if (NODE_BUILTINS.has(specifier) || specifier.startsWith('node:')) {\n return { id: specifier, external: true };\n }\n\n if (path.isAbsolute(specifier)) {\n const root = packageRootFromPath(specifier);\n if (root && (HOSTED_PACKAGES.has(root) || NATIVE_PACKAGES.has(root))) {\n inputs.add(specifier);\n return { id: specifier, external: true };\n }\n return null;\n }\n if (specifier.startsWith('.')) return null;\n\n const renamed = renameScope(specifier);\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) {\n inputs.add(hosted);\n return { id: hosted, external: true };\n }\n }\n if (root === 'typebox') {\n const typebox = piExtensionDependencyEntry(renamed);\n if (typebox) {\n inputs.add(typebox);\n return { id: typebox, external: false };\n }\n }\n if (root && NATIVE_PACKAGES.has(root)) {\n const resolved = await this.resolve(renamed, importer, options);\n if (resolved) {\n inputs.add(resolved.id);\n return { id: resolved.id, external: true };\n }\n }\n return null;\n },\n };\n}\n\nfunction inputCollector(inputs: Set<string>) {\n return {\n name: 'doom-set-inputs',\n load(id: string): null {\n if (path.isAbsolute(id) && fs.existsSync(id)) inputs.add(id);\n return null;\n },\n };\n}\n\n/** An unresolved bare import would otherwise become a broken dist external. */\nfunction failUnresolvedImport(_level: LogLevel, log: RolldownLog, handler: LogOrStringHandler): void {\n if (log.code === 'UNRESOLVED_IMPORT') handler('error', log);\n}\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectImportMetaUrlRanges(value: unknown, ranges: SourceRange[]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectImportMetaUrlRanges(item, ranges);\n return;\n }\n if (!isRecord(value)) return;\n\n const object = value.object;\n const property = value.property;\n if (\n value.type === 'MemberExpression' &&\n value.computed === false &&\n typeof value.start === 'number' &&\n typeof value.end === 'number' &&\n isRecord(object) &&\n object.type === 'MetaProperty' &&\n isRecord(object.meta) &&\n object.meta.name === 'import' &&\n isRecord(object.property) &&\n object.property.name === 'meta' &&\n isRecord(property) &&\n property.name === 'url'\n ) {\n ranges.push({ start: value.start, end: value.end });\n return;\n }\n\n for (const child of Object.values(value)) collectImportMetaUrlRanges(child, ranges);\n}\n\n/** Keeps package-owned resource lookup anchored to each original source file. */\nfunction preserveImportMetaUrl() {\n return {\n name: 'doom-original-import-meta-url',\n transform(\n this: {\n parse: (source: string, options?: { lang?: 'js' | 'jsx' | 'ts' | 'tsx' }) => unknown;\n },\n source: string,\n id: string,\n ): string | null {\n if (!path.isAbsolute(id) || !source.includes('import.meta.url')) return null;\n const extension = path.extname(id).toLowerCase();\n const lang = extension === '.tsx' ? 'tsx' : extension === '.jsx' ? 'jsx' : isTypeScriptEntry(id) ? 'ts' : 'js';\n const ranges: SourceRange[] = [];\n collectImportMetaUrlRanges(this.parse(source, { lang }), ranges);\n if (ranges.length === 0) return null;\n const replacement = JSON.stringify(pathToFileURL(id).href);\n let transformed = source;\n for (const range of ranges.sort((left, right) => right.start - left.start)) {\n transformed = `${transformed.slice(0, range.start)}${replacement}${transformed.slice(range.end)}`;\n }\n return transformed;\n },\n };\n}\n\n/**\n * Compiles an ordered extension set into one native ESM entry.\n *\n * The generated entry starts every module load together, then invokes factories\n * sequentially in activation order. Its manifest records every loaded module,\n * so a dependency edit invalidates the cache without running the compiler.\n */\nexport async function compileExtensionSet(\n entries: readonly string[],\n cacheDirectory: string,\n options: CompileExtensionSetOptions = {},\n): Promise<string> {\n if (entries.length === 0) throw new Error('Cannot compile an empty extension set');\n const normalized = entries.map((entry) => path.resolve(entry));\n const setDirectory = path.join(cacheDirectory, SET_DIRECTORY);\n fs.mkdirSync(setDirectory, { recursive: true });\n const key = extensionSetKey(normalized);\n const outputDirectory = path.resolve(options.outputDirectory ?? setDirectory);\n const outputName = safeOutputName(options.outputName ?? 'doom-set');\n fs.mkdirSync(outputDirectory, { recursive: true });\n // One graph can be emitted under several named mode artifacts. Keep their\n // cache records separate without changing extensionSetKey, which is the\n // runtime lookup key for an exact activation order.\n const outputKey = createHash('sha256').update(outputDirectory).update(outputName).digest('hex').slice(0, HASH_LENGTH);\n const manifestPath = path.join(setDirectory, `${key}.${outputKey}${MANIFEST_SUFFIX}`);\n const previous = readSetManifest(manifestPath);\n if (previous && manifestIsFresh(previous, normalized)) return previous.output;\n\n const inputs = new Set(normalized);\n const source = extensionSetSource(normalized);\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: VIRTUAL_SET_ENTRY,\n platform: 'node',\n plugins: [\n {\n name: 'doom-set-entry',\n resolveId(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? id : null;\n },\n load(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? source : null;\n },\n },\n setExternalResolver(inputs),\n preserveImportMetaUrl(),\n inputCollector(inputs),\n ],\n onLog: failUnresolvedImport,\n });\n let compiled: CompiledGraph;\n try {\n const generated = await build.generate(splitOutputOptions(`${outputName}.[hash:${HASH_LENGTH}]${COMPILED_SUFFIX}`));\n compiled = writeCompiledGraph(generated, outputDirectory);\n } finally {\n await build.close();\n }\n\n const output = compiled.entry;\n const inputFingerprints = [...inputs]\n .map(fingerprint)\n .filter((value): value is InputFingerprint => value !== undefined)\n .sort((left, right) => left.path.localeCompare(right.path));\n writeAtomic(\n manifestPath,\n `${JSON.stringify(\n {\n version: SET_CACHE_VERSION,\n entries: normalized,\n output,\n artifacts: compiled.artifacts,\n inputs: inputFingerprints,\n },\n null,\n 2,\n )}\\n`,\n );\n return output;\n}\n\n/**\n * Bundles `entry` into `cacheDirectory` and returns the compiled path.\n *\n * Non-TypeScript entries are returned untouched. A cache hit skips the build.\n */\nexport async function compileExtension(entry: string, cacheDirectory: string): Promise<string> {\n if (!isTypeScriptEntry(entry)) return entry;\n\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const outputName = compiledName(entry, cacheKey(entry));\n const output = path.join(cacheDirectory, outputName);\n const manifestPath = `${output}${MANIFEST_SUFFIX}`;\n const previous = readCompiledExtensionManifest(manifestPath);\n if (previous && artifactsAreFresh(previous, CACHE_VERSION, output)) return output;\n\n // Rolldown loads a native module and a sizeable parser graph. Sync is the\n // only command that needs it, and a cache hit does not, so keep it off every\n // other CLI startup path.\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: entry,\n platform: 'node',\n plugins: [externalResolver(), preserveImportMetaUrl()],\n onLog: failUnresolvedImport,\n });\n let compiled: CompiledGraph;\n try {\n const generated = await build.generate(splitOutputOptions(outputName));\n compiled = writeCompiledGraph(generated, cacheDirectory);\n } finally {\n await build.close();\n }\n writeAtomic(\n manifestPath,\n `${JSON.stringify({ version: CACHE_VERSION, output, artifacts: compiled.artifacts }, null, 2)}\\n`,\n );\n return output;\n}\n\n/**\n * Compiles every TypeScript entry in a resolution map, leaving the rest as-is.\n *\n * A failure is not fatal: the original path is kept so Pi falls back to loading\n * the TypeScript through jiti, which is what it did before this existed.\n */\nexport async function compileResolvedEntries(\n resolved: Record<string, string>,\n cacheDirectory: string,\n): Promise<Record<string, string>> {\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const compiled: Record<string, string> = {};\n for (const [key, target] of Object.entries(resolved)) {\n try {\n compiled[key] = await compileExtension(target, cacheDirectory);\n } catch {\n compiled[key] = target;\n }\n }\n return compiled;\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import{optionalPackageEntry as e}from"../utils/moduleResolution.mjs";import"../utils/index.mjs";import{builtinModules as t,createRequire as n}from"node:module";import r from"node:fs";import{pathToFileURL as i}from"node:url";import a from"node:path";import{createHash as o}from"node:crypto";const s=[`.ts`,`.mts`,`.cts`],c=`.mjs`,l=`\0doompi-extension-set`,u=`@agimon-ai/doompi-ui/extensionName`,d={"@mariozechner/pi-coding-agent":`@earendil-works/pi-coding-agent`,"@mariozechner/pi-tui":`@earendil-works/pi-tui`,"@mariozechner/pi-ai":`@earendil-works/pi-ai`,"@sinclair/typebox":`typebox`};function f(e){return s.some(t=>e.endsWith(t))}function p(e){for(let[t,n]of Object.entries(d)){if(e===t)return n;if(e.startsWith(`${t}/`))return`${n}${e.slice(t.length)}`}return e}function m(e){let t=r.readFileSync(e);return o(`sha256`).update(`v3`).update(e).update(t).digest(`hex`).slice(0,16)}function h(e,t){let n=a.basename(e).replace(/\.[cm]?ts$/,``);return`${a.basename(a.dirname(e))}-${n}.${t}${c}`}const g=new Set([`@earendil-works/pi-coding-agent`,`@earendil-works/pi-tui`,`@earendil-works/pi-ai`]);function _(t){let r=e(`@earendil-works/pi-coding-agent`);if(r)try{return n(r).resolve(t)}catch{return}}const v=new Set([`@parcel/watcher`,`@napi-rs/keyring`,`better-sqlite3`,`canvas`,`fsevents`,`isolated-vm`,`keytar`,`node-pty`,`onnxruntime-node`,`playwright`,`playwright-core`,`puppeteer`,`sharp`,`typescript`]),y=new Set(t.flatMap(e=>[e,`node:${e}`]));function b(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^[-.]+|[-.]+$/g,``)||`doom-set`}function x(e){let t=e.startsWith(`@`)?e.indexOf(`/`,e.indexOf(`/`)+1):e.indexOf(`/`);return t===-1?e:e.slice(0,t)}function S(e){let t=e.split(a.sep).join(`/`),n=t.lastIndexOf(`/node_modules/`);if(n===-1)return;let r=t.slice(n+14).split(`/`),i=r.lastIndexOf(`node_modules`),o=i===-1?r:r.slice(i+1);return o[0]?.startsWith(`@`)?o.slice(0,2).join(`/`):o[0]}function C(){return{name:`doom-external-absolute`,async resolveId(t,n,r){if(t.startsWith(`.`)||a.isAbsolute(t)||t.startsWith(`node:`))return null;let i=p(t),o=x(i);if(o&&g.has(o)){let t=e(i);if(t)return{id:t,external:!0}}let s=await this.resolve(i,n,r);return!s||f(s.id)?null:{id:s.id,external:!0}}}}function w(e){try{let t=r.statSync(e);return t.isFile()?{path:e,size:t.size,mtimeMs:t.mtimeMs}:void 0}catch{return}}function T(e,t){return e.version!==`v6`||JSON.stringify(e.entries)!==JSON.stringify(t)||!r.existsSync(e.output)?!1:e.inputs.every(e=>{let t=w(e.path);return t?.size===e.size&&t.mtimeMs===e.mtimeMs})}function E(e){try{let t=JSON.parse(r.readFileSync(e,`utf8`));return t&&Array.isArray(t.entries)&&Array.isArray(t.inputs)?t:void 0}catch{return}}function D(e,t){let n=`${e}.${process.pid}.${Date.now()}.tmp`;r.writeFileSync(n,t);try{r.renameSync(n,e)}catch(t){if(r.rmSync(n,{force:!0}),!r.existsSync(e))throw t}}function O(e){return o(`sha256`).update(`v6`).update(JSON.stringify(e.map(e=>a.resolve(e)))).digest(`hex`).slice(0,16)}function k(t){let n=e(u);if(!n)throw Error(`Cannot resolve ${u}`);let r=t.map(e=>`() => import(${JSON.stringify(A(e))})`),i=t.map(e=>JSON.stringify(e));return[`import { withExtensionSource } from ${JSON.stringify(A(n))};`,`const loaders = [${r.join(`,`)}];`,`const names = [${i.join(`,`)}];`,`function report(index, error) {`,` const detail = error instanceof Error ? error.message : String(error);`,` process.stderr.write("[doompi] " + names[index] + ": " + detail + "\\n");`,`}`,`export default async function doompiExtensionSet(pi) {`,` const loaded = await Promise.all(loaders.map(async (load, index) => {`,` try {`,` return await load();`,` } catch (error) {`,` report(index, error);`,` return undefined;`,` }`,` }));`,` for (let index = 0; index < loaded.length; index += 1) {`,` const extension = loaded[index];`,` if (!extension) continue;`,` try {`,` if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');`,` await extension.default(withExtensionSource(pi, names[index]));`,` } catch (error) {`,` report(index, error);`,` }`,` }`,`}`].join(`
2
- `)}function A(e){return a.resolve(e).split(a.sep).join(`/`)}function j(t){return{name:`doom-set-external`,async resolveId(n,r,i){if(n===l)return null;if(y.has(n)||n.startsWith(`node:`))return{id:n,external:!0};if(a.isAbsolute(n)){let e=S(n);return e&&(g.has(e)||v.has(e))?(t.add(n),{id:n,external:!0}):null}if(n.startsWith(`.`))return null;let o=p(n),s=x(o);if(s&&g.has(s)){let n=e(o);if(n)return t.add(n),{id:n,external:!0}}if(s===`typebox`){let e=_(o);if(e)return t.add(e),{id:e,external:!1}}if(s&&v.has(s)){let e=await this.resolve(o,r,i);if(e)return t.add(e.id),{id:e.id,external:!0}}return null}}}function M(e){return{name:`doom-set-inputs`,load(t){return a.isAbsolute(t)&&r.existsSync(t)&&e.add(t),null}}}function N(e,t,n){t.code===`UNRESOLVED_IMPORT`&&n(`error`,t)}function P(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function F(e,t){if(Array.isArray(e)){for(let n of e)F(n,t);return}if(!P(e))return;let n=e.object,r=e.property;if(e.type===`MemberExpression`&&e.computed===!1&&typeof e.start==`number`&&typeof e.end==`number`&&P(n)&&n.type===`MetaProperty`&&P(n.meta)&&n.meta.name===`import`&&P(n.property)&&n.property.name===`meta`&&P(r)&&r.name===`url`){t.push({start:e.start,end:e.end});return}for(let n of Object.values(e))F(n,t)}function I(){return{name:`doom-original-import-meta-url`,transform(e,t){if(!a.isAbsolute(t)||!e.includes(`import.meta.url`))return null;let n=a.extname(t).toLowerCase(),r=n===`.tsx`?`tsx`:n===`.jsx`?`jsx`:f(t)?`ts`:`js`,o=[];if(F(this.parse(e,{lang:r}),o),o.length===0)return null;let s=JSON.stringify(i(t).href),c=e;for(let e of o.sort((e,t)=>t.start-e.start))c=`${c.slice(0,e.start)}${s}${c.slice(e.end)}`;return c}}}async function L(e,t,n={}){if(e.length===0)throw Error(`Cannot compile an empty extension set`);let i=e.map(e=>a.resolve(e)),s=a.join(t,`sets`);r.mkdirSync(s,{recursive:!0});let u=O(i),d=a.resolve(n.outputDirectory??s),f=b(n.outputName??`doom-set`);r.mkdirSync(d,{recursive:!0});let p=o(`sha256`).update(d).update(f).digest(`hex`).slice(0,16),m=a.join(s,`${u}.${p}.json`),h=E(m);if(h&&T(h,i))return h.output;let g=new Set(i),_=k(i),{rolldown:v}=await import(`rolldown`),y=await v({input:l,platform:`node`,plugins:[{name:`doom-set-entry`,resolveId(e){return e===l?e:null},load(e){return e===l?_:null}},j(g),I(),M(g)],onLog:N}),x;try{let e=(await y.generate({format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!1})).output.find(e=>e.type===`chunk`);if(!e||e.type!==`chunk`)throw Error(`Rolldown produced no extension bundle`);x=e.code}finally{await y.close()}let S=o(`sha256`).update(`v6`).update(x).digest(`hex`).slice(0,16),C=a.join(d,`${f}.${S}${c}`);r.existsSync(C)||D(C,x);let A=[...g].map(w).filter(e=>e!==void 0).sort((e,t)=>e.path.localeCompare(t.path));return D(m,`${JSON.stringify({version:`v6`,entries:i,output:C,inputs:A},null,2)}\n`),C}async function R(e,t){if(!f(e))return e;let n=a.join(t,h(e,m(e)));if(r.existsSync(n))return n;let{rolldown:i}=await import(`rolldown`),o=await i({input:e,platform:`node`,plugins:[C(),I()],onLog:N});try{await o.write({file:n,format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!1})}finally{await o.close()}return n}async function z(e,t){r.mkdirSync(t,{recursive:!0});let n={};for(let[r,i]of Object.entries(e))try{n[r]=await R(i,t)}catch{n[r]=i}return n}export{L as compileExtensionSet,z as compileResolvedEntries,O as extensionSetKey};
1
+ import{optionalPackageEntry as e}from"../utils/moduleResolution.mjs";import"../utils/index.mjs";import{builtinModules as t,createRequire as n}from"node:module";import r from"node:fs";import{pathToFileURL as i}from"node:url";import a from"node:path";import{createHash as o}from"node:crypto";const s=[`.ts`,`.mts`,`.cts`],c=`.mjs`,l=`.json`,u=`\0doompi-extension-set`,d=`@agimon-ai/doompi-ui/extensionName`,f={"@mariozechner/pi-coding-agent":`@earendil-works/pi-coding-agent`,"@mariozechner/pi-tui":`@earendil-works/pi-tui`,"@mariozechner/pi-ai":`@earendil-works/pi-ai`,"@sinclair/typebox":`typebox`};function p(e){return s.some(t=>e.endsWith(t))}function m(e){for(let[t,n]of Object.entries(f)){if(e===t)return n;if(e.startsWith(`${t}/`))return`${n}${e.slice(t.length)}`}return e}function h(e){let t=r.readFileSync(e);return o(`sha256`).update(`v4`).update(e).update(t).digest(`hex`).slice(0,16)}function g(e,t){let n=a.basename(e).replace(/\.[cm]?ts$/,``);return`${a.basename(a.dirname(e))}-${n}.${t}${c}`}const _=new Set([`@earendil-works/pi-coding-agent`,`@earendil-works/pi-tui`,`@earendil-works/pi-ai`]);function v(t){let r=e(`@earendil-works/pi-coding-agent`);if(r)try{return n(r).resolve(t)}catch{return}}const y=new Set([`@parcel/watcher`,`@napi-rs/keyring`,`better-sqlite3`,`canvas`,`fsevents`,`isolated-vm`,`keytar`,`node-pty`,`onnxruntime-node`,`playwright`,`playwright-core`,`puppeteer`,`sharp`,`typescript`]),b=new Set(t.flatMap(e=>[e,`node:${e}`]));function x(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^[-.]+|[-.]+$/g,``)||`doom-set`}function S(e){let t=e.startsWith(`@`)?e.indexOf(`/`,e.indexOf(`/`)+1):e.indexOf(`/`);return t===-1?e:e.slice(0,t)}function C(e){let t=e.split(a.sep).join(`/`),n=t.lastIndexOf(`/node_modules/`);if(n===-1)return;let r=t.slice(n+14).split(`/`),i=r.lastIndexOf(`node_modules`),o=i===-1?r:r.slice(i+1);return o[0]?.startsWith(`@`)?o.slice(0,2).join(`/`):o[0]}function w(){return{name:`doom-external-absolute`,async resolveId(t,n,r){if(t.startsWith(`.`)||a.isAbsolute(t)||t.startsWith(`node:`))return null;let i=m(t),o=S(i);if(o&&_.has(o)){let t=e(i);if(t)return{id:t,external:!0}}let s=await this.resolve(i,n,r);return!s||p(s.id)?null:{id:s.id,external:!0}}}}function T(e){try{let t=r.statSync(e);return t.isFile()?{path:e,size:t.size,mtimeMs:t.mtimeMs}:void 0}catch{return}}function E(e,t,n){return e.version===t&&e.output===n&&r.existsSync(n)&&e.artifacts.every(e=>r.existsSync(e))}function D(e,t){return!E(e,`v7`,e.output)||JSON.stringify(e.entries)!==JSON.stringify(t)?!1:e.inputs.every(e=>{let t=T(e.path);return t?.size===e.size&&t.mtimeMs===e.mtimeMs})}function O(e){try{let t=JSON.parse(r.readFileSync(e,`utf8`));return t&&typeof t.output==`string`&&Array.isArray(t.artifacts)?t:void 0}catch{return}}function k(e){let t=O(e);return t&&Array.isArray(t.entries)&&Array.isArray(t.inputs)?t:void 0}function A(e,t){r.mkdirSync(a.dirname(e),{recursive:!0});let n=`${e}.${process.pid}.${Date.now()}.tmp`;r.writeFileSync(n,t);try{r.renameSync(n,e)}catch(t){if(r.rmSync(n,{force:!0}),!r.existsSync(e))throw t}}function j(e){return{format:`esm`,sourcemap:!1,minify:!0,codeSplitting:!0,hashCharacters:`hex`,entryFileNames:e,chunkFileNames:`chunks/[name].[hash:16]${c}`,assetFileNames:`assets/[name].[hash:16][extname]`}}function M(e,t){let n=a.resolve(e,t.fileName),r=a.relative(e,n);if(r.startsWith(`..`)||a.isAbsolute(r))throw Error(`Rolldown emitted an artifact outside the output directory: ${t.fileName}`);return n}function N(e,t){let n=e.output.find(e=>e.type===`chunk`&&e.isEntry);if(!n||n.type!==`chunk`)throw Error(`Rolldown produced no extension entry`);let i=a.resolve(t),o=e.output.filter(e=>e!==n);for(let e of[...o,n]){let t=e.type===`chunk`?e.code:e.source,n=M(i,e);r.existsSync(n)||A(n,t)}return{entry:M(i,n),artifacts:e.output.map(e=>M(i,e)).sort()}}function P(e){return o(`sha256`).update(`v7`).update(JSON.stringify(e.map(e=>a.resolve(e)))).digest(`hex`).slice(0,16)}function F(t){let n=e(d);if(!n)throw Error(`Cannot resolve ${d}`);let r=t.map(e=>`() => import(${JSON.stringify(I(e))})`),i=t.map(e=>JSON.stringify(e));return[`import { withExtensionSource } from ${JSON.stringify(I(n))};`,`const loaders = [${r.join(`,`)}];`,`const names = [${i.join(`,`)}];`,`function report(index, error) {`,` const detail = error instanceof Error ? error.message : String(error);`,` process.stderr.write("[doompi] " + names[index] + ": " + detail + "\\n");`,`}`,`export default async function doompiExtensionSet(pi) {`,` const loaded = await Promise.all(loaders.map(async (load, index) => {`,` try {`,` return await load();`,` } catch (error) {`,` report(index, error);`,` return undefined;`,` }`,` }));`,` for (let index = 0; index < loaded.length; index += 1) {`,` const extension = loaded[index];`,` if (!extension) continue;`,` try {`,` if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');`,` await extension.default(withExtensionSource(pi, names[index]));`,` } catch (error) {`,` report(index, error);`,` }`,` }`,`}`].join(`
2
+ `)}function I(e){return a.resolve(e).split(a.sep).join(`/`)}function L(t){return{name:`doom-set-external`,async resolveId(n,r,i){if(n===u)return null;if(b.has(n)||n.startsWith(`node:`))return{id:n,external:!0};if(a.isAbsolute(n)){let e=C(n);return e&&(_.has(e)||y.has(e))?(t.add(n),{id:n,external:!0}):null}if(n.startsWith(`.`))return null;let o=m(n),s=S(o);if(s&&_.has(s)){let n=e(o);if(n)return t.add(n),{id:n,external:!0}}if(s===`typebox`){let e=v(o);if(e)return t.add(e),{id:e,external:!1}}if(s&&y.has(s)){let e=await this.resolve(o,r,i);if(e)return t.add(e.id),{id:e.id,external:!0}}return null}}}function R(e){return{name:`doom-set-inputs`,load(t){return a.isAbsolute(t)&&r.existsSync(t)&&e.add(t),null}}}function z(e,t,n){t.code===`UNRESOLVED_IMPORT`&&n(`error`,t)}function B(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function V(e,t){if(Array.isArray(e)){for(let n of e)V(n,t);return}if(!B(e))return;let n=e.object,r=e.property;if(e.type===`MemberExpression`&&e.computed===!1&&typeof e.start==`number`&&typeof e.end==`number`&&B(n)&&n.type===`MetaProperty`&&B(n.meta)&&n.meta.name===`import`&&B(n.property)&&n.property.name===`meta`&&B(r)&&r.name===`url`){t.push({start:e.start,end:e.end});return}for(let n of Object.values(e))V(n,t)}function H(){return{name:`doom-original-import-meta-url`,transform(e,t){if(!a.isAbsolute(t)||!e.includes(`import.meta.url`))return null;let n=a.extname(t).toLowerCase(),r=n===`.tsx`?`tsx`:n===`.jsx`?`jsx`:p(t)?`ts`:`js`,o=[];if(V(this.parse(e,{lang:r}),o),o.length===0)return null;let s=JSON.stringify(i(t).href),c=e;for(let e of o.sort((e,t)=>t.start-e.start))c=`${c.slice(0,e.start)}${s}${c.slice(e.end)}`;return c}}}async function U(e,t,n={}){if(e.length===0)throw Error(`Cannot compile an empty extension set`);let i=e.map(e=>a.resolve(e)),s=a.join(t,`sets`);r.mkdirSync(s,{recursive:!0});let d=P(i),f=a.resolve(n.outputDirectory??s),p=x(n.outputName??`doom-set`);r.mkdirSync(f,{recursive:!0});let m=o(`sha256`).update(f).update(p).digest(`hex`).slice(0,16),h=a.join(s,`${d}.${m}${l}`),g=k(h);if(g&&D(g,i))return g.output;let _=new Set(i),v=F(i),{rolldown:y}=await import(`rolldown`),b=await y({input:u,platform:`node`,plugins:[{name:`doom-set-entry`,resolveId(e){return e===u?e:null},load(e){return e===u?v:null}},L(_),H(),R(_)],onLog:z}),S;try{S=N(await b.generate(j(`${p}.[hash:16]${c}`)),f)}finally{await b.close()}let C=S.entry,w=[..._].map(T).filter(e=>e!==void 0).sort((e,t)=>e.path.localeCompare(t.path));return A(h,`${JSON.stringify({version:`v7`,entries:i,output:C,artifacts:S.artifacts,inputs:w},null,2)}\n`),C}async function W(e,t){if(!p(e))return e;r.mkdirSync(t,{recursive:!0});let n=g(e,h(e)),i=a.join(t,n),o=`${i}${l}`,s=O(o);if(s&&E(s,`v4`,i))return i;let{rolldown:c}=await import(`rolldown`),u=await c({input:e,platform:`node`,plugins:[w(),H()],onLog:z}),d;try{d=N(await u.generate(j(n)),t)}finally{await u.close()}return A(o,`${JSON.stringify({version:`v4`,output:i,artifacts:d.artifacts},null,2)}\n`),i}async function G(e,t){r.mkdirSync(t,{recursive:!0});let n={};for(let[r,i]of Object.entries(e))try{n[r]=await W(i,t)}catch{n[r]=i}return n}export{U as compileExtensionSet,G as compileResolvedEntries,P as extensionSetKey};
3
3
  //# sourceMappingURL=extensionCompiler.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensionCompiler.mjs","names":[],"sources":["../../src/services/extensionCompiler.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport { builtinModules, createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { LogLevel, LogOrStringHandler, RolldownLog } from 'rolldown';\nimport { optionalPackageEntry } from '../utils/index.ts';\n\n/**\n * Compiles TypeScript extensions into plain ESM ahead of the session.\n *\n * Pi loads extensions through jiti, which transpiles TypeScript at import time.\n * That works, but it costs a transform per module on a cold cache and makes Node\n * complain about type stripping under node_modules on every launch. Resolution\n * already knows the full extension list, so each TypeScript entry is bundled to\n * a single `.mjs` here and Pi imports it natively.\n *\n * Mode artifacts bundle their JavaScript dependencies. Node built-ins, native\n * packages, and Pi's shared runtime stay external; those imports are rewritten\n * to absolute paths so an artifact under `.pi/doom/dist` never relies on that\n * directory having its own `node_modules` tree.\n */\n\nconst TYPESCRIPT_SUFFIXES = ['.ts', '.mts', '.cts'] as const;\nconst COMPILED_SUFFIX = '.mjs';\nconst CACHE_VERSION = 'v3';\nconst SET_CACHE_VERSION = 'v6';\nconst HASH_LENGTH = 16;\nconst SET_DIRECTORY = 'sets';\nconst MANIFEST_SUFFIX = '.json';\nconst VIRTUAL_SET_ENTRY = '\\0doompi-extension-set';\nconst EXTENSION_SOURCE_HELPER = '@agimon-ai/doompi-ui/extensionName';\n\n/** Pi's former npm scope. The packages are the same, published under a new name. */\nconst PI_SCOPE_RENAMES: Readonly<Record<string, string>> = {\n '@mariozechner/pi-coding-agent': '@earendil-works/pi-coding-agent',\n '@mariozechner/pi-tui': '@earendil-works/pi-tui',\n '@mariozechner/pi-ai': '@earendil-works/pi-ai',\n '@sinclair/typebox': 'typebox',\n};\n\nexport function isTypeScriptEntry(entry: string): boolean {\n return TYPESCRIPT_SUFFIXES.some((suffix) => entry.endsWith(suffix));\n}\n\nfunction renameScope(specifier: string): string {\n for (const [before, after] of Object.entries(PI_SCOPE_RENAMES)) {\n if (specifier === before) return after;\n if (specifier.startsWith(`${before}/`)) return `${after}${specifier.slice(before.length)}`;\n }\n return specifier;\n}\n\n/**\n * Cache key for a compiled entry.\n *\n * The entry's own bytes are the only cheap signal that the extension changed; a\n * dependency edit is not visible without walking the graph, so an upgrade that\n * leaves the entry byte-identical is served from cache until the version below\n * is raised.\n */\nfunction cacheKey(entry: string): string {\n const source = fs.readFileSync(entry);\n return createHash('sha256').update(CACHE_VERSION).update(entry).update(source).digest('hex').slice(0, HASH_LENGTH);\n}\n\nfunction compiledName(entry: string, key: string): string {\n const base = path.basename(entry).replace(/\\.[cm]?ts$/, '');\n const parent = path.basename(path.dirname(entry));\n return `${parent}-${base}.${key}${COMPILED_SUFFIX}`;\n}\n\n/**\n * Packages that must resolve to the copy this harness runs, never to a second\n * one bundled into an extension. Pi owns the TUI and the session state, so a\n * duplicate renders into a different screen and mutates a different store.\n */\nconst HOSTED_PACKAGES = new Set(['@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', '@earendil-works/pi-ai']);\n\n/**\n * Resolves packages Pi exposes to extensions as compatibility aliases.\n *\n * Extensions do not need to declare TypeBox themselves because Pi's loader\n * provides it as a virtual module. A dist bundle bypasses that loader, so it\n * resolves the same package against Pi's dependency tree and bundles it.\n */\nfunction piExtensionDependencyEntry(specifier: string): string | undefined {\n const piEntry = optionalPackageEntry('@earendil-works/pi-coding-agent');\n if (!piEntry) return undefined;\n try {\n return createRequire(piEntry).resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Packages whose native binaries or runtime discovery cannot be rolled up. */\nconst NATIVE_PACKAGES = new Set([\n '@parcel/watcher',\n '@napi-rs/keyring',\n 'better-sqlite3',\n 'canvas',\n 'fsevents',\n 'isolated-vm',\n 'keytar',\n 'node-pty',\n 'onnxruntime-node',\n 'playwright',\n 'playwright-core',\n 'puppeteer',\n 'sharp',\n // TypeScript's Node system adapter reads CommonJS globals such as\n // __filename. Rolldown does not provide those globals when it folds the\n // adapter into the aggregate ESM extension, so keep the installed runtime\n // intact and import it by its resolved absolute path.\n 'typescript',\n]);\nconst NODE_BUILTINS = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface ExtensionSetManifest {\n version: string;\n entries: string[];\n output: string;\n inputs: InputFingerprint[];\n}\n\nexport interface CompileExtensionSetOptions {\n /** Persistent artifact directory. Compiler manifests remain in cacheDirectory. */\n outputDirectory?: string;\n /** Human-readable artifact prefix, normally the major-mode name. */\n outputName?: string;\n}\n\nfunction safeOutputName(value: string): string {\n const normalized = value\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '');\n return normalized || 'doom-set';\n}\n\nfunction packageRootOf(specifier: string): string | undefined {\n const slash = specifier.startsWith('@') ? specifier.indexOf('/', specifier.indexOf('/') + 1) : specifier.indexOf('/');\n return slash === -1 ? specifier : specifier.slice(0, slash);\n}\n\nfunction packageRootFromPath(target: string): string | undefined {\n const normalized = target.split(path.sep).join('/');\n const marker = '/node_modules/';\n const offset = normalized.lastIndexOf(marker);\n if (offset === -1) return undefined;\n const parts = normalized.slice(offset + marker.length).split('/');\n // pnpm's first segment is a store key; the second node_modules marker names\n // the package that owns the file.\n const nested = parts.lastIndexOf('node_modules');\n const packageParts = nested === -1 ? parts : parts.slice(nested + 1);\n return packageParts[0]?.startsWith('@') ? packageParts.slice(0, 2).join('/') : packageParts[0];\n}\n\nfunction externalResolver() {\n return {\n name: 'doom-external-absolute',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier.startsWith('.') || path.isAbsolute(specifier) || specifier.startsWith('node:')) return null;\n const renamed = renameScope(specifier);\n\n // Host packages are resolved from this module, the way the rest of the\n // harness resolves them, because an extension written against Pi's former\n // scope does not have the current one in its own dependency tree.\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) return { id: hosted, external: true };\n }\n\n // Rolldown's resolver rather than `createRequire`, which cannot see an\n // ESM-only package that publishes no `require` condition and would send\n // Pi's own core into the bundle.\n const resolved = await this.resolve(renamed, importer, options);\n if (!resolved) return null;\n // A dependency that is itself TypeScript cannot be handed to Node either,\n // so it is bundled rather than externalised.\n if (isTypeScriptEntry(resolved.id)) return null;\n return { id: resolved.id, external: true };\n },\n };\n}\n\nfunction fingerprint(target: string): InputFingerprint | undefined {\n try {\n const stat = fs.statSync(target);\n if (!stat.isFile()) return undefined;\n return { path: target, size: stat.size, mtimeMs: stat.mtimeMs };\n } catch {\n return undefined;\n }\n}\n\nfunction manifestIsFresh(manifest: ExtensionSetManifest, entries: string[]): boolean {\n if (\n manifest.version !== SET_CACHE_VERSION ||\n JSON.stringify(manifest.entries) !== JSON.stringify(entries) ||\n !fs.existsSync(manifest.output)\n ) {\n return false;\n }\n return manifest.inputs.every((previous) => {\n const current = fingerprint(previous.path);\n return current?.size === previous.size && current.mtimeMs === previous.mtimeMs;\n });\n}\n\nfunction readSetManifest(manifestPath: string): ExtensionSetManifest | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as ExtensionSetManifest;\n return parsed && Array.isArray(parsed.entries) && Array.isArray(parsed.inputs) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction writeAtomic(target: string, contents: string): void {\n const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, contents);\n try {\n fs.renameSync(temporary, target);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(target)) throw error;\n }\n}\n\n/** Stable lookup key for one exact Pi load order. */\nexport function extensionSetKey(entries: readonly string[]): string {\n return createHash('sha256')\n .update(SET_CACHE_VERSION)\n .update(JSON.stringify(entries.map((entry) => path.resolve(entry))))\n .digest('hex')\n .slice(0, HASH_LENGTH);\n}\n\nfunction extensionSetSource(entries: readonly string[]): string {\n const helper = optionalPackageEntry(EXTENSION_SOURCE_HELPER);\n if (!helper) throw new Error(`Cannot resolve ${EXTENSION_SOURCE_HELPER}`);\n const loaders = entries.map((entry) => `() => import(${JSON.stringify(pathToImportSpecifier(entry))})`);\n const names = entries.map((entry) => JSON.stringify(entry));\n return [\n `import { withExtensionSource } from ${JSON.stringify(pathToImportSpecifier(helper))};`,\n `const loaders = [${loaders.join(',')}];`,\n `const names = [${names.join(',')}];`,\n 'function report(index, error) {',\n ' const detail = error instanceof Error ? error.message : String(error);',\n ' process.stderr.write(\"[doompi] \" + names[index] + \": \" + detail + \"\\\\n\");',\n '}',\n 'export default async function doompiExtensionSet(pi) {',\n ' const loaded = await Promise.all(loaders.map(async (load, index) => {',\n ' try {',\n ' return await load();',\n ' } catch (error) {',\n ' report(index, error);',\n ' return undefined;',\n ' }',\n ' }));',\n ' for (let index = 0; index < loaded.length; index += 1) {',\n ' const extension = loaded[index];',\n ' if (!extension) continue;',\n ' try {',\n \" if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');\",\n ' await extension.default(withExtensionSource(pi, names[index]));',\n ' } catch (error) {',\n ' report(index, error);',\n ' }',\n ' }',\n '}',\n ].join('\\n');\n}\n\nfunction pathToImportSpecifier(target: string): string {\n // Rolldown accepts absolute POSIX paths directly. Windows needs a file URL,\n // but replacing separators is enough for its platform-independent parser.\n return path.resolve(target).split(path.sep).join('/');\n}\n\nfunction setExternalResolver(inputs: Set<string>) {\n return {\n name: 'doom-set-external',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier === VIRTUAL_SET_ENTRY) return null;\n if (NODE_BUILTINS.has(specifier) || specifier.startsWith('node:')) {\n return { id: specifier, external: true };\n }\n\n if (path.isAbsolute(specifier)) {\n const root = packageRootFromPath(specifier);\n if (root && (HOSTED_PACKAGES.has(root) || NATIVE_PACKAGES.has(root))) {\n inputs.add(specifier);\n return { id: specifier, external: true };\n }\n return null;\n }\n if (specifier.startsWith('.')) return null;\n\n const renamed = renameScope(specifier);\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) {\n inputs.add(hosted);\n return { id: hosted, external: true };\n }\n }\n if (root === 'typebox') {\n const typebox = piExtensionDependencyEntry(renamed);\n if (typebox) {\n inputs.add(typebox);\n return { id: typebox, external: false };\n }\n }\n if (root && NATIVE_PACKAGES.has(root)) {\n const resolved = await this.resolve(renamed, importer, options);\n if (resolved) {\n inputs.add(resolved.id);\n return { id: resolved.id, external: true };\n }\n }\n return null;\n },\n };\n}\n\nfunction inputCollector(inputs: Set<string>) {\n return {\n name: 'doom-set-inputs',\n load(id: string): null {\n if (path.isAbsolute(id) && fs.existsSync(id)) inputs.add(id);\n return null;\n },\n };\n}\n\n/** An unresolved bare import would otherwise become a broken dist external. */\nfunction failUnresolvedImport(_level: LogLevel, log: RolldownLog, handler: LogOrStringHandler): void {\n if (log.code === 'UNRESOLVED_IMPORT') handler('error', log);\n}\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectImportMetaUrlRanges(value: unknown, ranges: SourceRange[]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectImportMetaUrlRanges(item, ranges);\n return;\n }\n if (!isRecord(value)) return;\n\n const object = value.object;\n const property = value.property;\n if (\n value.type === 'MemberExpression' &&\n value.computed === false &&\n typeof value.start === 'number' &&\n typeof value.end === 'number' &&\n isRecord(object) &&\n object.type === 'MetaProperty' &&\n isRecord(object.meta) &&\n object.meta.name === 'import' &&\n isRecord(object.property) &&\n object.property.name === 'meta' &&\n isRecord(property) &&\n property.name === 'url'\n ) {\n ranges.push({ start: value.start, end: value.end });\n return;\n }\n\n for (const child of Object.values(value)) collectImportMetaUrlRanges(child, ranges);\n}\n\n/** Keeps package-owned resource lookup anchored to each original source file. */\nfunction preserveImportMetaUrl() {\n return {\n name: 'doom-original-import-meta-url',\n transform(\n this: {\n parse: (source: string, options?: { lang?: 'js' | 'jsx' | 'ts' | 'tsx' }) => unknown;\n },\n source: string,\n id: string,\n ): string | null {\n if (!path.isAbsolute(id) || !source.includes('import.meta.url')) return null;\n const extension = path.extname(id).toLowerCase();\n const lang = extension === '.tsx' ? 'tsx' : extension === '.jsx' ? 'jsx' : isTypeScriptEntry(id) ? 'ts' : 'js';\n const ranges: SourceRange[] = [];\n collectImportMetaUrlRanges(this.parse(source, { lang }), ranges);\n if (ranges.length === 0) return null;\n const replacement = JSON.stringify(pathToFileURL(id).href);\n let transformed = source;\n for (const range of ranges.sort((left, right) => right.start - left.start)) {\n transformed = `${transformed.slice(0, range.start)}${replacement}${transformed.slice(range.end)}`;\n }\n return transformed;\n },\n };\n}\n\n/**\n * Compiles an ordered extension set into one native ESM entry.\n *\n * The generated entry starts every module load together, then invokes factories\n * sequentially in activation order. Its manifest records every loaded module,\n * so a dependency edit invalidates the cache without running the compiler.\n */\nexport async function compileExtensionSet(\n entries: readonly string[],\n cacheDirectory: string,\n options: CompileExtensionSetOptions = {},\n): Promise<string> {\n if (entries.length === 0) throw new Error('Cannot compile an empty extension set');\n const normalized = entries.map((entry) => path.resolve(entry));\n const setDirectory = path.join(cacheDirectory, SET_DIRECTORY);\n fs.mkdirSync(setDirectory, { recursive: true });\n const key = extensionSetKey(normalized);\n const outputDirectory = path.resolve(options.outputDirectory ?? setDirectory);\n const outputName = safeOutputName(options.outputName ?? 'doom-set');\n fs.mkdirSync(outputDirectory, { recursive: true });\n // One graph can be emitted under several named mode artifacts. Keep their\n // cache records separate without changing extensionSetKey, which is the\n // runtime lookup key for an exact activation order.\n const outputKey = createHash('sha256').update(outputDirectory).update(outputName).digest('hex').slice(0, HASH_LENGTH);\n const manifestPath = path.join(setDirectory, `${key}.${outputKey}${MANIFEST_SUFFIX}`);\n const previous = readSetManifest(manifestPath);\n if (previous && manifestIsFresh(previous, normalized)) return previous.output;\n\n const inputs = new Set(normalized);\n const source = extensionSetSource(normalized);\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: VIRTUAL_SET_ENTRY,\n platform: 'node',\n plugins: [\n {\n name: 'doom-set-entry',\n resolveId(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? id : null;\n },\n load(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? source : null;\n },\n },\n setExternalResolver(inputs),\n preserveImportMetaUrl(),\n inputCollector(inputs),\n ],\n onLog: failUnresolvedImport,\n });\n let code: string;\n try {\n const generated = await build.generate({ format: 'esm', sourcemap: false, minify: true, codeSplitting: false });\n const chunk = generated.output.find((output) => output.type === 'chunk');\n if (!chunk || chunk.type !== 'chunk') throw new Error('Rolldown produced no extension bundle');\n code = chunk.code;\n } finally {\n await build.close();\n }\n\n const contentKey = createHash('sha256').update(SET_CACHE_VERSION).update(code).digest('hex').slice(0, HASH_LENGTH);\n const output = path.join(outputDirectory, `${outputName}.${contentKey}${COMPILED_SUFFIX}`);\n if (!fs.existsSync(output)) writeAtomic(output, code);\n const inputFingerprints = [...inputs]\n .map(fingerprint)\n .filter((value): value is InputFingerprint => value !== undefined)\n .sort((left, right) => left.path.localeCompare(right.path));\n writeAtomic(\n manifestPath,\n `${JSON.stringify({ version: SET_CACHE_VERSION, entries: normalized, output, inputs: inputFingerprints }, null, 2)}\\n`,\n );\n return output;\n}\n\n/**\n * Bundles `entry` into `cacheDirectory` and returns the compiled path.\n *\n * Non-TypeScript entries are returned untouched. A cache hit skips the build.\n */\nexport async function compileExtension(entry: string, cacheDirectory: string): Promise<string> {\n if (!isTypeScriptEntry(entry)) return entry;\n\n const output = path.join(cacheDirectory, compiledName(entry, cacheKey(entry)));\n if (fs.existsSync(output)) return output;\n\n // Rolldown loads a native module and a sizeable parser graph. Sync is the\n // only command that needs it, and a cache hit does not, so keep it off every\n // other CLI startup path.\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: entry,\n platform: 'node',\n plugins: [externalResolver(), preserveImportMetaUrl()],\n onLog: failUnresolvedImport,\n });\n try {\n // One file per extension. Several of them import lazily, and code splitting\n // would emit sibling chunks that a single output path cannot describe.\n await build.write({ file: output, format: 'esm', sourcemap: false, minify: true, codeSplitting: false });\n } finally {\n await build.close();\n }\n return output;\n}\n\n/**\n * Compiles every TypeScript entry in a resolution map, leaving the rest as-is.\n *\n * A failure is not fatal: the original path is kept so Pi falls back to loading\n * the TypeScript through jiti, which is what it did before this existed.\n */\nexport async function compileResolvedEntries(\n resolved: Record<string, string>,\n cacheDirectory: string,\n): Promise<Record<string, string>> {\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const compiled: Record<string, string> = {};\n for (const [key, target] of Object.entries(resolved)) {\n try {\n compiled[key] = await compileExtension(target, cacheDirectory);\n } catch {\n compiled[key] = target;\n }\n }\n return compiled;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extensionCompiler.mjs","names":[],"sources":["../../src/services/extensionCompiler.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport { builtinModules, createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { LogLevel, LogOrStringHandler, OutputAsset, OutputChunk, RolldownLog, RolldownOutput } from 'rolldown';\nimport { optionalPackageEntry } from '../utils/index.ts';\n\n/**\n * Compiles TypeScript extensions into plain ESM ahead of the session.\n *\n * Pi loads extensions through jiti, which transpiles TypeScript at import time.\n * That works, but it costs a transform per module on a cold cache and makes Node\n * complain about type stripping under node_modules on every launch. Resolution\n * already knows the full extension list, so each TypeScript graph is compiled\n * to native ESM here and Pi imports it without a runtime transform. Lazy imports\n * remain separate content-addressed chunks so their evaluation semantics survive\n * compilation.\n *\n * Mode artifacts bundle their JavaScript dependencies. Node built-ins, native\n * packages, and Pi's shared runtime stay external; those imports are rewritten\n * to absolute paths so an artifact under `.pi/doom/dist` never relies on that\n * directory having its own `node_modules` tree.\n */\n\nconst TYPESCRIPT_SUFFIXES = ['.ts', '.mts', '.cts'] as const;\nconst COMPILED_SUFFIX = '.mjs';\nconst CACHE_VERSION = 'v4';\nconst SET_CACHE_VERSION = 'v7';\nconst HASH_LENGTH = 16;\nconst SET_DIRECTORY = 'sets';\nconst MANIFEST_SUFFIX = '.json';\nconst VIRTUAL_SET_ENTRY = '\\0doompi-extension-set';\nconst EXTENSION_SOURCE_HELPER = '@agimon-ai/doompi-ui/extensionName';\n\n/** Pi's former npm scope. The packages are the same, published under a new name. */\nconst PI_SCOPE_RENAMES: Readonly<Record<string, string>> = {\n '@mariozechner/pi-coding-agent': '@earendil-works/pi-coding-agent',\n '@mariozechner/pi-tui': '@earendil-works/pi-tui',\n '@mariozechner/pi-ai': '@earendil-works/pi-ai',\n '@sinclair/typebox': 'typebox',\n};\n\nexport function isTypeScriptEntry(entry: string): boolean {\n return TYPESCRIPT_SUFFIXES.some((suffix) => entry.endsWith(suffix));\n}\n\nfunction renameScope(specifier: string): string {\n for (const [before, after] of Object.entries(PI_SCOPE_RENAMES)) {\n if (specifier === before) return after;\n if (specifier.startsWith(`${before}/`)) return `${after}${specifier.slice(before.length)}`;\n }\n return specifier;\n}\n\n/**\n * Cache key for a compiled entry.\n *\n * The entry's own bytes are the only cheap signal that the extension changed; a\n * dependency edit is not visible without walking the graph, so an upgrade that\n * leaves the entry byte-identical is served from cache until the version below\n * is raised.\n */\nfunction cacheKey(entry: string): string {\n const source = fs.readFileSync(entry);\n return createHash('sha256').update(CACHE_VERSION).update(entry).update(source).digest('hex').slice(0, HASH_LENGTH);\n}\n\nfunction compiledName(entry: string, key: string): string {\n const base = path.basename(entry).replace(/\\.[cm]?ts$/, '');\n const parent = path.basename(path.dirname(entry));\n return `${parent}-${base}.${key}${COMPILED_SUFFIX}`;\n}\n\n/**\n * Packages that must resolve to the copy this harness runs, never to a second\n * one bundled into an extension. Pi owns the TUI and the session state, so a\n * duplicate renders into a different screen and mutates a different store.\n */\nconst HOSTED_PACKAGES = new Set(['@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', '@earendil-works/pi-ai']);\n\n/**\n * Resolves packages Pi exposes to extensions as compatibility aliases.\n *\n * Extensions do not need to declare TypeBox themselves because Pi's loader\n * provides it as a virtual module. A dist bundle bypasses that loader, so it\n * resolves the same package against Pi's dependency tree and bundles it.\n */\nfunction piExtensionDependencyEntry(specifier: string): string | undefined {\n const piEntry = optionalPackageEntry('@earendil-works/pi-coding-agent');\n if (!piEntry) return undefined;\n try {\n return createRequire(piEntry).resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Packages whose native binaries or runtime discovery cannot be rolled up. */\nconst NATIVE_PACKAGES = new Set([\n '@parcel/watcher',\n '@napi-rs/keyring',\n 'better-sqlite3',\n 'canvas',\n 'fsevents',\n 'isolated-vm',\n 'keytar',\n 'node-pty',\n 'onnxruntime-node',\n 'playwright',\n 'playwright-core',\n 'puppeteer',\n 'sharp',\n // TypeScript's Node system adapter reads CommonJS globals such as\n // __filename. Rolldown does not provide those globals when it folds the\n // adapter into the aggregate ESM extension, so keep the installed runtime\n // intact and import it by its resolved absolute path.\n 'typescript',\n]);\nconst NODE_BUILTINS = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));\n\ninterface InputFingerprint {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\ninterface CompiledExtensionManifest {\n version: string;\n output: string;\n artifacts: string[];\n}\n\ninterface ExtensionSetManifest extends CompiledExtensionManifest {\n entries: string[];\n inputs: InputFingerprint[];\n}\n\nexport interface CompileExtensionSetOptions {\n /** Persistent artifact directory. Compiler manifests remain in cacheDirectory. */\n outputDirectory?: string;\n /** Human-readable artifact prefix, normally the major-mode name. */\n outputName?: string;\n}\n\nfunction safeOutputName(value: string): string {\n const normalized = value\n .trim()\n .replace(/[^a-zA-Z0-9._-]+/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '');\n return normalized || 'doom-set';\n}\n\nfunction packageRootOf(specifier: string): string | undefined {\n const slash = specifier.startsWith('@') ? specifier.indexOf('/', specifier.indexOf('/') + 1) : specifier.indexOf('/');\n return slash === -1 ? specifier : specifier.slice(0, slash);\n}\n\nfunction packageRootFromPath(target: string): string | undefined {\n const normalized = target.split(path.sep).join('/');\n const marker = '/node_modules/';\n const offset = normalized.lastIndexOf(marker);\n if (offset === -1) return undefined;\n const parts = normalized.slice(offset + marker.length).split('/');\n // pnpm's first segment is a store key; the second node_modules marker names\n // the package that owns the file.\n const nested = parts.lastIndexOf('node_modules');\n const packageParts = nested === -1 ? parts : parts.slice(nested + 1);\n return packageParts[0]?.startsWith('@') ? packageParts.slice(0, 2).join('/') : packageParts[0];\n}\n\nfunction externalResolver() {\n return {\n name: 'doom-external-absolute',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier.startsWith('.') || path.isAbsolute(specifier) || specifier.startsWith('node:')) return null;\n const renamed = renameScope(specifier);\n\n // Host packages are resolved from this module, the way the rest of the\n // harness resolves them, because an extension written against Pi's former\n // scope does not have the current one in its own dependency tree.\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) return { id: hosted, external: true };\n }\n\n // Rolldown's resolver rather than `createRequire`, which cannot see an\n // ESM-only package that publishes no `require` condition and would send\n // Pi's own core into the bundle.\n const resolved = await this.resolve(renamed, importer, options);\n if (!resolved) return null;\n // A dependency that is itself TypeScript cannot be handed to Node either,\n // so it is bundled rather than externalised.\n if (isTypeScriptEntry(resolved.id)) return null;\n return { id: resolved.id, external: true };\n },\n };\n}\n\nfunction fingerprint(target: string): InputFingerprint | undefined {\n try {\n const stat = fs.statSync(target);\n if (!stat.isFile()) return undefined;\n return { path: target, size: stat.size, mtimeMs: stat.mtimeMs };\n } catch {\n return undefined;\n }\n}\n\nfunction artifactsAreFresh(manifest: CompiledExtensionManifest, version: string, output: string): boolean {\n return (\n manifest.version === version &&\n manifest.output === output &&\n fs.existsSync(output) &&\n manifest.artifacts.every((artifact) => fs.existsSync(artifact))\n );\n}\n\nfunction manifestIsFresh(manifest: ExtensionSetManifest, entries: string[]): boolean {\n if (!artifactsAreFresh(manifest, SET_CACHE_VERSION, manifest.output)) return false;\n if (JSON.stringify(manifest.entries) !== JSON.stringify(entries)) {\n return false;\n }\n return manifest.inputs.every((previous) => {\n const current = fingerprint(previous.path);\n return current?.size === previous.size && current.mtimeMs === previous.mtimeMs;\n });\n}\n\nfunction readCompiledExtensionManifest(manifestPath: string): CompiledExtensionManifest | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as CompiledExtensionManifest;\n return parsed && typeof parsed.output === 'string' && Array.isArray(parsed.artifacts) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readSetManifest(manifestPath: string): ExtensionSetManifest | undefined {\n const parsed = readCompiledExtensionManifest(manifestPath) as ExtensionSetManifest | undefined;\n return parsed && Array.isArray(parsed.entries) && Array.isArray(parsed.inputs) ? parsed : undefined;\n}\n\nfunction writeAtomic(target: string, contents: string | Uint8Array): void {\n fs.mkdirSync(path.dirname(target), { recursive: true });\n const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, contents);\n try {\n fs.renameSync(temporary, target);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(target)) throw error;\n }\n}\n\ninterface CompiledGraph {\n entry: string;\n artifacts: string[];\n}\n\nfunction splitOutputOptions(entryFileNames: string) {\n return {\n format: 'esm' as const,\n sourcemap: false,\n minify: true,\n codeSplitting: true,\n hashCharacters: 'hex' as const,\n entryFileNames,\n chunkFileNames: `chunks/[name].[hash:${HASH_LENGTH}]${COMPILED_SUFFIX}`,\n assetFileNames: `assets/[name].[hash:${HASH_LENGTH}][extname]`,\n };\n}\n\nfunction artifactTarget(outputDirectory: string, artifact: OutputAsset | OutputChunk): string {\n const target = path.resolve(outputDirectory, artifact.fileName);\n const relative = path.relative(outputDirectory, target);\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error(`Rolldown emitted an artifact outside the output directory: ${artifact.fileName}`);\n }\n return target;\n}\n\n/** Writes referenced chunks first so a visible entry always has a complete graph. */\nfunction writeCompiledGraph(generated: RolldownOutput, outputDirectory: string): CompiledGraph {\n const entry = generated.output.find((artifact) => artifact.type === 'chunk' && artifact.isEntry);\n if (!entry || entry.type !== 'chunk') throw new Error('Rolldown produced no extension entry');\n const root = path.resolve(outputDirectory);\n const remaining = generated.output.filter((artifact) => artifact !== entry);\n for (const artifact of [...remaining, entry]) {\n const contents = artifact.type === 'chunk' ? artifact.code : artifact.source;\n const target = artifactTarget(root, artifact);\n if (!fs.existsSync(target)) writeAtomic(target, contents);\n }\n return {\n entry: artifactTarget(root, entry),\n artifacts: generated.output.map((artifact) => artifactTarget(root, artifact)).sort(),\n };\n}\n\n/** Stable lookup key for one exact Pi load order. */\nexport function extensionSetKey(entries: readonly string[]): string {\n return createHash('sha256')\n .update(SET_CACHE_VERSION)\n .update(JSON.stringify(entries.map((entry) => path.resolve(entry))))\n .digest('hex')\n .slice(0, HASH_LENGTH);\n}\n\nfunction extensionSetSource(entries: readonly string[]): string {\n const helper = optionalPackageEntry(EXTENSION_SOURCE_HELPER);\n if (!helper) throw new Error(`Cannot resolve ${EXTENSION_SOURCE_HELPER}`);\n const loaders = entries.map((entry) => `() => import(${JSON.stringify(pathToImportSpecifier(entry))})`);\n const names = entries.map((entry) => JSON.stringify(entry));\n return [\n `import { withExtensionSource } from ${JSON.stringify(pathToImportSpecifier(helper))};`,\n `const loaders = [${loaders.join(',')}];`,\n `const names = [${names.join(',')}];`,\n 'function report(index, error) {',\n ' const detail = error instanceof Error ? error.message : String(error);',\n ' process.stderr.write(\"[doompi] \" + names[index] + \": \" + detail + \"\\\\n\");',\n '}',\n 'export default async function doompiExtensionSet(pi) {',\n ' const loaded = await Promise.all(loaders.map(async (load, index) => {',\n ' try {',\n ' return await load();',\n ' } catch (error) {',\n ' report(index, error);',\n ' return undefined;',\n ' }',\n ' }));',\n ' for (let index = 0; index < loaded.length; index += 1) {',\n ' const extension = loaded[index];',\n ' if (!extension) continue;',\n ' try {',\n \" if (typeof extension.default !== 'function') throw new Error('does not export an extension factory');\",\n ' await extension.default(withExtensionSource(pi, names[index]));',\n ' } catch (error) {',\n ' report(index, error);',\n ' }',\n ' }',\n '}',\n ].join('\\n');\n}\n\nfunction pathToImportSpecifier(target: string): string {\n // Rolldown accepts absolute POSIX paths directly. Windows needs a file URL,\n // but replacing separators is enough for its platform-independent parser.\n return path.resolve(target).split(path.sep).join('/');\n}\n\nfunction setExternalResolver(inputs: Set<string>) {\n return {\n name: 'doom-set-external',\n async resolveId(\n this: { resolve: (id: string, importer?: string, options?: unknown) => Promise<{ id: string } | null> },\n specifier: string,\n importer: string | undefined,\n options: unknown,\n ): Promise<{ id: string; external: boolean } | null> {\n if (specifier === VIRTUAL_SET_ENTRY) return null;\n if (NODE_BUILTINS.has(specifier) || specifier.startsWith('node:')) {\n return { id: specifier, external: true };\n }\n\n if (path.isAbsolute(specifier)) {\n const root = packageRootFromPath(specifier);\n if (root && (HOSTED_PACKAGES.has(root) || NATIVE_PACKAGES.has(root))) {\n inputs.add(specifier);\n return { id: specifier, external: true };\n }\n return null;\n }\n if (specifier.startsWith('.')) return null;\n\n const renamed = renameScope(specifier);\n const root = packageRootOf(renamed);\n if (root && HOSTED_PACKAGES.has(root)) {\n const hosted = optionalPackageEntry(renamed);\n if (hosted) {\n inputs.add(hosted);\n return { id: hosted, external: true };\n }\n }\n if (root === 'typebox') {\n const typebox = piExtensionDependencyEntry(renamed);\n if (typebox) {\n inputs.add(typebox);\n return { id: typebox, external: false };\n }\n }\n if (root && NATIVE_PACKAGES.has(root)) {\n const resolved = await this.resolve(renamed, importer, options);\n if (resolved) {\n inputs.add(resolved.id);\n return { id: resolved.id, external: true };\n }\n }\n return null;\n },\n };\n}\n\nfunction inputCollector(inputs: Set<string>) {\n return {\n name: 'doom-set-inputs',\n load(id: string): null {\n if (path.isAbsolute(id) && fs.existsSync(id)) inputs.add(id);\n return null;\n },\n };\n}\n\n/** An unresolved bare import would otherwise become a broken dist external. */\nfunction failUnresolvedImport(_level: LogLevel, log: RolldownLog, handler: LogOrStringHandler): void {\n if (log.code === 'UNRESOLVED_IMPORT') handler('error', log);\n}\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectImportMetaUrlRanges(value: unknown, ranges: SourceRange[]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectImportMetaUrlRanges(item, ranges);\n return;\n }\n if (!isRecord(value)) return;\n\n const object = value.object;\n const property = value.property;\n if (\n value.type === 'MemberExpression' &&\n value.computed === false &&\n typeof value.start === 'number' &&\n typeof value.end === 'number' &&\n isRecord(object) &&\n object.type === 'MetaProperty' &&\n isRecord(object.meta) &&\n object.meta.name === 'import' &&\n isRecord(object.property) &&\n object.property.name === 'meta' &&\n isRecord(property) &&\n property.name === 'url'\n ) {\n ranges.push({ start: value.start, end: value.end });\n return;\n }\n\n for (const child of Object.values(value)) collectImportMetaUrlRanges(child, ranges);\n}\n\n/** Keeps package-owned resource lookup anchored to each original source file. */\nfunction preserveImportMetaUrl() {\n return {\n name: 'doom-original-import-meta-url',\n transform(\n this: {\n parse: (source: string, options?: { lang?: 'js' | 'jsx' | 'ts' | 'tsx' }) => unknown;\n },\n source: string,\n id: string,\n ): string | null {\n if (!path.isAbsolute(id) || !source.includes('import.meta.url')) return null;\n const extension = path.extname(id).toLowerCase();\n const lang = extension === '.tsx' ? 'tsx' : extension === '.jsx' ? 'jsx' : isTypeScriptEntry(id) ? 'ts' : 'js';\n const ranges: SourceRange[] = [];\n collectImportMetaUrlRanges(this.parse(source, { lang }), ranges);\n if (ranges.length === 0) return null;\n const replacement = JSON.stringify(pathToFileURL(id).href);\n let transformed = source;\n for (const range of ranges.sort((left, right) => right.start - left.start)) {\n transformed = `${transformed.slice(0, range.start)}${replacement}${transformed.slice(range.end)}`;\n }\n return transformed;\n },\n };\n}\n\n/**\n * Compiles an ordered extension set into one native ESM entry.\n *\n * The generated entry starts every module load together, then invokes factories\n * sequentially in activation order. Its manifest records every loaded module,\n * so a dependency edit invalidates the cache without running the compiler.\n */\nexport async function compileExtensionSet(\n entries: readonly string[],\n cacheDirectory: string,\n options: CompileExtensionSetOptions = {},\n): Promise<string> {\n if (entries.length === 0) throw new Error('Cannot compile an empty extension set');\n const normalized = entries.map((entry) => path.resolve(entry));\n const setDirectory = path.join(cacheDirectory, SET_DIRECTORY);\n fs.mkdirSync(setDirectory, { recursive: true });\n const key = extensionSetKey(normalized);\n const outputDirectory = path.resolve(options.outputDirectory ?? setDirectory);\n const outputName = safeOutputName(options.outputName ?? 'doom-set');\n fs.mkdirSync(outputDirectory, { recursive: true });\n // One graph can be emitted under several named mode artifacts. Keep their\n // cache records separate without changing extensionSetKey, which is the\n // runtime lookup key for an exact activation order.\n const outputKey = createHash('sha256').update(outputDirectory).update(outputName).digest('hex').slice(0, HASH_LENGTH);\n const manifestPath = path.join(setDirectory, `${key}.${outputKey}${MANIFEST_SUFFIX}`);\n const previous = readSetManifest(manifestPath);\n if (previous && manifestIsFresh(previous, normalized)) return previous.output;\n\n const inputs = new Set(normalized);\n const source = extensionSetSource(normalized);\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: VIRTUAL_SET_ENTRY,\n platform: 'node',\n plugins: [\n {\n name: 'doom-set-entry',\n resolveId(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? id : null;\n },\n load(id: string): string | null {\n return id === VIRTUAL_SET_ENTRY ? source : null;\n },\n },\n setExternalResolver(inputs),\n preserveImportMetaUrl(),\n inputCollector(inputs),\n ],\n onLog: failUnresolvedImport,\n });\n let compiled: CompiledGraph;\n try {\n const generated = await build.generate(splitOutputOptions(`${outputName}.[hash:${HASH_LENGTH}]${COMPILED_SUFFIX}`));\n compiled = writeCompiledGraph(generated, outputDirectory);\n } finally {\n await build.close();\n }\n\n const output = compiled.entry;\n const inputFingerprints = [...inputs]\n .map(fingerprint)\n .filter((value): value is InputFingerprint => value !== undefined)\n .sort((left, right) => left.path.localeCompare(right.path));\n writeAtomic(\n manifestPath,\n `${JSON.stringify(\n {\n version: SET_CACHE_VERSION,\n entries: normalized,\n output,\n artifacts: compiled.artifacts,\n inputs: inputFingerprints,\n },\n null,\n 2,\n )}\\n`,\n );\n return output;\n}\n\n/**\n * Bundles `entry` into `cacheDirectory` and returns the compiled path.\n *\n * Non-TypeScript entries are returned untouched. A cache hit skips the build.\n */\nexport async function compileExtension(entry: string, cacheDirectory: string): Promise<string> {\n if (!isTypeScriptEntry(entry)) return entry;\n\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const outputName = compiledName(entry, cacheKey(entry));\n const output = path.join(cacheDirectory, outputName);\n const manifestPath = `${output}${MANIFEST_SUFFIX}`;\n const previous = readCompiledExtensionManifest(manifestPath);\n if (previous && artifactsAreFresh(previous, CACHE_VERSION, output)) return output;\n\n // Rolldown loads a native module and a sizeable parser graph. Sync is the\n // only command that needs it, and a cache hit does not, so keep it off every\n // other CLI startup path.\n const { rolldown } = await import('rolldown');\n const build = await rolldown({\n input: entry,\n platform: 'node',\n plugins: [externalResolver(), preserveImportMetaUrl()],\n onLog: failUnresolvedImport,\n });\n let compiled: CompiledGraph;\n try {\n const generated = await build.generate(splitOutputOptions(outputName));\n compiled = writeCompiledGraph(generated, cacheDirectory);\n } finally {\n await build.close();\n }\n writeAtomic(\n manifestPath,\n `${JSON.stringify({ version: CACHE_VERSION, output, artifacts: compiled.artifacts }, null, 2)}\\n`,\n );\n return output;\n}\n\n/**\n * Compiles every TypeScript entry in a resolution map, leaving the rest as-is.\n *\n * A failure is not fatal: the original path is kept so Pi falls back to loading\n * the TypeScript through jiti, which is what it did before this existed.\n */\nexport async function compileResolvedEntries(\n resolved: Record<string, string>,\n cacheDirectory: string,\n): Promise<Record<string, string>> {\n fs.mkdirSync(cacheDirectory, { recursive: true });\n const compiled: Record<string, string> = {};\n for (const [key, target] of Object.entries(resolved)) {\n try {\n compiled[key] = await compileExtension(target, cacheDirectory);\n } catch {\n compiled[key] = target;\n }\n }\n return compiled;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi",
3
- "version": "0.0.1-alpha.7",
3
+ "version": "0.0.1-alpha.8",
4
4
  "description": "Pi-based agent harness for repository automations and developer workflows",
5
5
  "homepage": "https://agimon.ai",
6
6
  "license": "MIT",
@@ -327,21 +327,21 @@
327
327
  "protobufjs": "8.0.1",
328
328
  "rolldown": "1.0.0-rc.17",
329
329
  "yaml": "2.9.0",
330
- "@agimon-ai/doompi-config": "0.0.1-alpha.7",
331
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.7",
332
- "@agimon-ai/doompi-autocompact": "0.0.1-alpha.7",
333
- "@agimon-ai/doompi-file-edit": "0.0.1-alpha.7",
334
- "@agimon-ai/doompi-log": "0.0.1-alpha.7",
335
- "@agimon-ai/doompi-loop": "0.0.1-alpha.7",
336
- "@agimon-ai/doompi-runner": "0.0.1-alpha.7",
337
- "@agimon-ai/doompi-mcp": "0.0.1-alpha.7",
338
- "@agimon-ai/doompi-voice": "0.0.1-alpha.7",
339
- "@agimon-ai/doompi-team": "0.0.1-alpha.7",
340
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.7",
341
- "@agimon-ai/doompi-workflow": "0.0.1-alpha.7",
342
- "@agimon-ai/doompi-plan": "0.0.1-alpha.7",
343
- "@agimon-ai/doompi-ui": "0.0.1-alpha.7",
344
- "@agimon-ai/doompi-task": "0.0.1-alpha.7"
330
+ "@agimon-ai/doompi-autocompact": "0.0.1-alpha.8",
331
+ "@agimon-ai/doompi-config": "0.0.1-alpha.8",
332
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.8",
333
+ "@agimon-ai/doompi-loop": "0.0.1-alpha.8",
334
+ "@agimon-ai/doompi-log": "0.0.1-alpha.8",
335
+ "@agimon-ai/doompi-plan": "0.0.1-alpha.8",
336
+ "@agimon-ai/doompi-runner": "0.0.1-alpha.8",
337
+ "@agimon-ai/doompi-file-edit": "0.0.1-alpha.8",
338
+ "@agimon-ai/doompi-team": "0.0.1-alpha.8",
339
+ "@agimon-ai/doompi-task": "0.0.1-alpha.8",
340
+ "@agimon-ai/doompi-mcp": "0.0.1-alpha.8",
341
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.8",
342
+ "@agimon-ai/doompi-voice": "0.0.1-alpha.8",
343
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.8",
344
+ "@agimon-ai/doompi-workflow": "0.0.1-alpha.8"
345
345
  },
346
346
  "devDependencies": {
347
347
  "@earendil-works/pi-ai": "0.84.1",