Skip to content

CLI Entry and Dispatch

源码版本v0.73.1

main.ts is the process entry point for the pi command. It parses command-line arguments into an AppMode, wires up an AgentSessionRuntime, and dispatches to one of three run modes: interactive TUI, one-shot print, or JSON-RPC. Beyond mode dispatch, it also handles migrations, session resolution, model selection, and file-argument preprocessing. Think of it as the front layer that translates a shell invocation into a runtime invocation.

Responsibilities

  1. Parse and dispatch: parseArgs produces Args, resolveAppMode computes AppMode, and that selects runRpcMode / InteractiveMode / runPrintMode. See packages/coding-agent/src/main.ts:98-109 and packages/coding-agent/src/main.ts:673-726.
  2. Session resolution: conflict checks and path resolution among --continue, --resume, --session <id|path>, --fork <id>, --no-session, locating the session identifier to its .jsonl on disk. See packages/coding-agent/src/main.ts:188-212 and packages/coding-agent/src/main.ts:147-172.
  3. Service wiring: calls createAgentSessionServices + createAgentSessionRuntime, threading together cwd, agentDir, authStorage, and extension/skill/theme paths. See packages/coding-agent/src/main.ts:522-560.
  4. Pre-run short-circuits: pi --version, pi --export, pi package ..., pi config ... bypass the runtime and call process.exit directly. See packages/coding-agent/src/main.ts:431-478.

Design Motivation

Why keep the entry point in its own file? CLI parsing, session selection, and migrations happen once, at process startup. Stuffing these into createAgentSession (the SDK entry) would hurt SDK reuse — SDK callers are usually programs that already have a runtime context, don't need to parse argv, and don't want process-level stdout takeover. So main.ts only takes on process-level chores: stdout takeover, signal handling, migrations, version checks, fork validation. Everything else is delegated to the SDK and runtime factories.

Key Files

resolveAppMode checks the --mode flag first, then falls back to whether stdin is a TTY, so piped usage like echo x | pi automatically goes to print mode:

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";
}

The three-way dispatch uses appMode to pick the branch; print and json share runPrintMode, with the difference in 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,
	});
	// ...
}

Data Flow

The dispatch path after argv arrives:

Edges and Failures

  • Fork conflicts: --fork cannot be combined with --session, --continue, --resume, or --no-session. See packages/coding-agent/src/main.ts:188-202.
  • stdout takeover: non-interactive modes call takeOverStdout(), redirecting console.log to an internal buffer to keep TUI escapes from polluting print/rpc output; restoreStdout runs on exit.
  • Missing session cwd: when --session points to another project, interactive mode prompts the user to choose, while print/rpc fail outright. See packages/coding-agent/src/main.ts:502-514.
  • Benchmark mode: under startupBenchmark, only interactiveMode.init() runs before stop() — the main loop is skipped.

Summary

main.ts is a thin shell: it translates argv and stdin into a runtime factory closure, then hands control to one of three modes. For the runtime factory internals, see createAgentSession Wiring; for interactive mode details, see TUI Interactive Mode; for non-interactive modes, see print and rpc Modes.