Skip to content

Entrada y dispatch del CLI

源码版本v0.73.1

main.ts es la entrada de proceso del comando pi. Parsea los argumentos de línea de comandos a AppMode, ensambla AgentSessionRuntime, y despacha a tres modos: TUI interactivo, print one-shot, y JSON-RPC. Además del dispatch, se ocupa de migraciones, resolución de sesión, selección de modelo y preprocesamiento de argumentos tipo archivo. Se puede entender como la capa previa que "traduce invocaciones del shell en invocaciones del runtime".

Responsabilidades

  1. Parseo y dispatch: parseArgs produce Args, resolveAppMode calcula AppMode, y en función de eso se elige runRpcMode / InteractiveMode / runPrintMode. Ver packages/coding-agent/src/main.ts:98-109 y packages/coding-agent/src/main.ts:673-726.
  2. Resolución de sesión: validación de conflictos y resolución de rutas entre --continue, --resume, --session <id|path>, --fork <id>, --no-session, localizando el identificador de sesión al .jsonl en disco. Ver packages/coding-agent/src/main.ts:188-212 y packages/coding-agent/src/main.ts:147-172.
  3. Ensamblaje de servicios: invoca createAgentSessionServices + createAgentSessionRuntime para atar cwd, agentDir, authStorage y rutas de extensiones/skills/temas. Ver packages/coding-agent/src/main.ts:522-560.
  4. Cortocircuito pre-run: pi --version, pi --export, pi package ..., pi config ... no entran al runtime y hacen process.exit directamente. Ver packages/coding-agent/src/main.ts:431-478.

Motivación de diseño

¿Por qué separar la entrada en su propio archivo? Porque el parseo del CLI, la selección de sesión y las migraciones ocurren una sola vez, y sólo al arrancar el proceso. Meter todo eso en createAgentSession (entrada del SDK) contaminaría la reutilización del SDK: el llamador del SDK suele ser un programa que ya tiene contexto de runtime, no necesita parsear argv ni tomar control del stdout a nivel de proceso. main.ts sólo carga "tareas de proceso": toma de stdout, gestión de señales, migraciones, comprobación de versión, validación de fork; el resto se delega al SDK y a las fábricas de runtime.

Archivos clave

resolveAppMode prioriza el flag --mode y cae a si stdin es TTY, de modo que el uso con pipe echo x | pi entra automáticamente en print:

typescript
// packages/coding-agent/src/main.ts:98-109
function resolveAppMode(parsed: Args, stdinIsTTY: boolean): AppMode {
	if (parsed.mode === "rpc") {
		return "rpc";
	}
	if (parsed.mode === "json") {
		return "json";
	}
	if (parsed.print || !stdinIsTTY) {
		return "print";
	}
	return "interactive";
}

La bifurcación elige rama según appMode; print y json comparten runPrintMode, la diferencia está en toPrintOutputMode(appMode):

typescript
// packages/coding-agent/src/main.ts:673-726
if (appMode === "rpc") {
	printTimings();
	await runRpcMode(runtime);
} else if (appMode === "interactive") {
	// ...
	const interactiveMode = new InteractiveMode(runtime, {
		migratedProviders,
		modelFallbackMessage,
		initialMessage,
		initialImages,
		initialMessages: parsed.messages,
		verbose: parsed.verbose,
	});
	// ...
	await interactiveMode.run();
} else {
	printTimings();
	const exitCode = await runPrintMode(runtime, {
		mode: toPrintOutputMode(appMode),
		messages: parsed.messages,
		initialMessage,
		initialImages,
	});
	// ...
}

Flujo de datos

Camino de dispatch al entrar argv:

Límites y fallos

  • Conflicto de fork: --fork no se puede combinar con --session, --continue, --resume, --no-session. Ver packages/coding-agent/src/main.ts:188-202.
  • Toma de stdout: en modo no interactivo se invoca takeOverStdout(), redirigiendo console.log a un pipe interno para evitar que el escape TUI contamine la salida print/rpc; al salir, restoreStdout.
  • Cwd de sesión ausente: si --session apunta a otro proyecto, interactive abre un prompt para que el usuario elija; print/rpc fallan y salen. Ver packages/coding-agent/src/main.ts:502-514.
  • Modo benchmark: en startupBenchmark sólo se llama interactiveMode.init() y luego stop(), sin entrar al bucle principal.

Resumen

main.ts es una capa fina: traduce argv y stdin en un closure de fábrica de runtime, y se lo pasa a uno de los tres modos. Cómo se ensambla el runtime por dentro en ensamblaje createAgentSession; el modo interactivo en modo interactivo TUI; los modos no interactivos en modos print y rpc.