{"version":3,"file":"index.cjs","names":["isRecord","hasProjectTrustOption","LAUNCHER_COMPOSITION_REQUEST_ENV","resolveLaunchPlan","spawn","piCliPath","forwardSignals","waitForExit","HARNESS_EVENT","BaseCommand"],"sources":["../../../../src/cli/commands/launch/index.ts"],"sourcesContent":["import { piCliPath } from '@agimon-ai/doompi-core/module-resolution';\nimport { isRecord } from '@agimon-ai/doompi-core/runtime-json';\nimport { HARNESS_EVENT, type HarnessTelemetry } from '@agimon-ai/doompi-core/runtime-log-sink-telemetry';\nimport spawn from 'cross-spawn';\n\nimport { LAUNCHER_COMPOSITION_REQUEST_ENV } from '../../../builders/cli/constants';\nimport type { HarnessContext } from '../../../builders/cli/harnessContext';\nimport { resolveLaunchPlan } from '../../../builders/cli/launchPlan';\nimport { hasProjectTrustOption } from '../../../composition/projectTrust';\nimport type { HarnessOptions } from '../../../composition/types/harness';\nimport { BaseCommand } from '../baseCommand';\nimport { forwardSignals, waitForExit } from '../compat/providers/process';\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 IGNORE_STDIO = 'ignore';\nconst PIPE_STDIO = 'pipe';\nconst INHERIT_STDIO = 'inherit';\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\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 async function runLaunch(context: HarnessContext, telemetry: HarnessTelemetry): Promise<number> {\n  const { options } = context;\n  // A caller that owns this process's lifetime, such as doompi-server, asks\n  // for a composition record so a mode switch reloads in place instead of\n  // needing a new process. Absent, the session composes as it always has.\n  const compositionRecordPath = context.environment[LAUNCHER_COMPOSITION_REQUEST_ENV]?.trim();\n  const plan = await resolveLaunchPlan(context, telemetry, compositionRecordPath ? { compositionRecordPath } : {});\n  const environment = plan.environment;\n  let piArgs = plan.piArgs;\n  const launchExtensions = plan.extensions;\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/** Compatibility API. Executables call the command function directly. */\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    return runLaunch(context, telemetry);\n  }\n}\n"],"mappings":"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"}