Skip to content

Entrée et dispatch CLI ​

源码版本v0.73.1

main.ts est le point d'entrée du processus pour la commande pi. Il parse les arguments en AppMode, assemble AgentSessionRuntime, puis dispatch vers l'un des trois modes d'exécution : TUI interactif, print one-shot, ou JSON-RPC. Au-delà du dispatch de mode, il gère aussi les migrations, la résolution de session, le choix du modèle et le pré-traitement des arguments de type fichier. C'est en quelque sorte la couche frontale qui « traduit l'invocation shell en appel runtime ».

Responsabilités ​

  1. Parsing et dispatch : parseArgs produit Args, resolveAppMode calcule AppMode, et on choisit entre runRpcMode / InteractiveMode / runPrintMode. Voir packages/coding-agent/src/main.ts:98-109 et packages/coding-agent/src/main.ts:673-726.
  2. Résolution de session : gestion des conflits entre --continue, --resume, --session <id|path>, --fork <id>, --no-session, et résolution du chemin pour localiser le .jsonl sur disque. Voir packages/coding-agent/src/main.ts:188-212 et packages/coding-agent/src/main.ts:147-172.
  3. Assemblage des services : appelle createAgentSessionServices + createAgentSessionRuntime pour relier cwd, agentDir, authStorage, et les chemins d'extensions/skills/thèmes. Voir packages/coding-agent/src/main.ts:522-560.
  4. Court-circuit pré-exécution : pi --version, pi --export, pi package ..., pi config ... ne passent pas par le runtime, ils font directement process.exit. Voir packages/coding-agent/src/main.ts:431-478.

Motivation de design ​

Pourquoi isoler l'entrée dans un fichier dédié ? Parce que le parsing CLI, le choix de session et les migrations n'arrivent qu'une seule fois, au démarrage du processus. Mettre tout ça dans createAgentSession (l'entrée SDK) polluerait sa réutilisabilité — un appelant SDK a généralement déjà un context runtime et n'a pas besoin de parser argv ni de prendre le contrôle de stdout au niveau processus. main.ts ne gère donc que les « trivialités de niveau processus » : prise en main de stdout, traitement des signaux, migrations, vérification de version, validation des forks ; tout le reste est délégué au SDK et à la factory runtime.

Fichiers clés ​

resolveAppMode regarde d'abord le flag --mode, puis retombe sur la détection TTY de stdin, de sorte que l'usage en pipe echo x | pi bascule automatiquement en mode 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";
}

Au point de dispatch triptyque, on choisit la branche directement depuis appMode ; print et json partagent runPrintMode, la différence se fait via 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,
	});
	// ...
}

Flux de données ​

Le chemin de dispatch une fois argv arrivé :

Limites et échecs ​

  • Conflit de fork : --fork ne peut pas être combiné avec --session, --continue, --resume, --no-session. Voir packages/coding-agent/src/main.ts:188-202.
  • Prise en main de stdout : en mode non interactif, on appelle takeOverStdout() pour rediriger console.log vers un pipe interne, afin que les séquences d'échappement du TUI ne polluent pas la sortie print/rpc ; restoreStdout est appelé à la sortie.
  • cwd de session absent : quand --session pointe vers un autre projet, le mode interactif ouvre un prompt pour laisser l'utilisateur choisir, tandis que print/rpc quittent en erreur. Voir packages/coding-agent/src/main.ts:502-514.
  • Mode benchmark : en startupBenchmark, on ne fait qu'appeler interactiveMode.init() puis stop() immédiatement, sans entrer dans la boucle principale.

Résumé ​

main.ts est une coquille fine : il traduit argv et stdin en une closure de factory runtime, puis confie le reste à l'un des trois modes. Pour le détail de l'assemblage interne de la factory runtime, voir Assemblage createAgentSession ; pour le mode interactif, voir Mode interactif TUI ; pour les modes non interactifs, voir Modes print et rpc.