chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
63
third_party/pi/packages/coding-agent/src/main.ts
vendored
63
third_party/pi/packages/coding-agent/src/main.ts
vendored
@@ -62,10 +62,11 @@ import { SettingsManager } from "./core/settings-manager.ts";
|
||||
import { printTimings, resetTimings, time } from "./core/timings.ts";
|
||||
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "./core/trust-manager.ts";
|
||||
import { builtInExtensions } from "./extensions/index.ts";
|
||||
import { loadMcpCommand } from "./extensions/mcp/cli.lazy.ts";
|
||||
import { runMigrations, showDeprecationWarnings } from "./migrations.ts";
|
||||
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.ts";
|
||||
import { initTheme, setThemeJsonValidator, stopThemeWatcher } from "./modes/interactive/theme/theme.ts";
|
||||
import { validateThemeJson } from "./modes/interactive/theme/theme-json.ts";
|
||||
import { validateThemeJson } from "./modes/interactive/theme/theme-schema.ts";
|
||||
import { cleanupManagedInstall, handleConfigCommand, handlePackageCommand } from "./package-manager-cli.ts";
|
||||
import { isLocalPath, normalizePath, resolvePath } from "./utils/paths.ts";
|
||||
import { cleanupWindowsSelfUpdateQuarantine } from "./utils/windows-self-update.ts";
|
||||
@@ -209,7 +210,6 @@ async function runAuthCommand(args: string[]): Promise<boolean> {
|
||||
|
||||
async function prepareInitialMessage(
|
||||
parsed: Args,
|
||||
autoResizeImages: boolean,
|
||||
stdinContent?: string,
|
||||
): Promise<{
|
||||
initialMessage?: string;
|
||||
@@ -219,7 +219,8 @@ async function prepareInitialMessage(
|
||||
return buildInitialMessage({ parsed, stdinContent });
|
||||
}
|
||||
|
||||
const { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });
|
||||
// AgentSession resizes these after extension hooks select the request model.
|
||||
const { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages: false });
|
||||
return buildInitialMessage({
|
||||
parsed,
|
||||
fileText: text,
|
||||
@@ -239,14 +240,13 @@ type ResolvedSession =
|
||||
* Resolve a session argument to a file path.
|
||||
* If it looks like a path, use as-is. Otherwise try to match as session ID prefix.
|
||||
*/
|
||||
async function findLocalSessionByExactId(
|
||||
function findLocalSessionByExactId(
|
||||
sessionId: string,
|
||||
cwd: string,
|
||||
sessionDir?: string,
|
||||
): Promise<{ type: "local"; path: string } | undefined> {
|
||||
const localSessions = await SessionManager.list(cwd, sessionDir);
|
||||
const localMatch = localSessions.find((s) => s.id === sessionId);
|
||||
return localMatch ? { type: "local", path: localMatch.path } : undefined;
|
||||
): { type: "local"; path: string } | undefined {
|
||||
const path = SessionManager.findById(cwd, sessionId, sessionDir);
|
||||
return path ? { type: "local", path } : undefined;
|
||||
}
|
||||
|
||||
async function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?: string): Promise<ResolvedSession> {
|
||||
@@ -255,10 +255,15 @@ async function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?:
|
||||
return { type: "path", path: resolvePath(sessionArg, cwd) };
|
||||
}
|
||||
|
||||
// Try to match as session ID in current project first
|
||||
// Exact IDs only require reading session headers. Fall back to the full
|
||||
// metadata listing for prefix matches.
|
||||
const exactLocalMatch = findLocalSessionByExactId(sessionArg, cwd, sessionDir);
|
||||
if (exactLocalMatch) {
|
||||
return exactLocalMatch;
|
||||
}
|
||||
|
||||
const localSessions = await SessionManager.list(cwd, sessionDir);
|
||||
const localMatch =
|
||||
localSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));
|
||||
const localMatch = localSessions.find((s) => s.id.startsWith(sessionArg));
|
||||
|
||||
if (localMatch) {
|
||||
return { type: "local", path: localMatch.path };
|
||||
@@ -362,7 +367,7 @@ export async function createSessionManager(
|
||||
|
||||
if (parsed.fork) {
|
||||
if (parsed.sessionId) {
|
||||
const existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
||||
const existingTarget = findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
||||
if (existingTarget) {
|
||||
console.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));
|
||||
process.exit(1);
|
||||
@@ -410,8 +415,8 @@ export async function createSessionManager(
|
||||
if (parsed.resume) {
|
||||
try {
|
||||
const selectedPath = await selectSession(
|
||||
(onProgress) => SessionManager.list(cwd, sessionDir, onProgress),
|
||||
(onProgress) => SessionManager.listAll(sessionDir, onProgress),
|
||||
(onProgress, signal) => SessionManager.list(cwd, sessionDir, onProgress, signal),
|
||||
(onProgress, signal) => SessionManager.listAll(sessionDir, onProgress, signal),
|
||||
settingsManager,
|
||||
);
|
||||
if (!selectedPath) {
|
||||
@@ -429,7 +434,7 @@ export async function createSessionManager(
|
||||
}
|
||||
|
||||
if (parsed.sessionId) {
|
||||
const existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
||||
const existingSession = findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
||||
if (existingSession) {
|
||||
return SessionManager.open(existingSession.path, sessionDir);
|
||||
}
|
||||
@@ -461,11 +466,18 @@ function buildSessionOptions(
|
||||
// Model from CLI
|
||||
// - supports --provider <name> --model <pattern>
|
||||
// - supports --model <provider>/<pattern>
|
||||
if (parsed.provider && !parsed.model) {
|
||||
diagnostics.push({
|
||||
type: "error",
|
||||
message: `--provider requires --model (for example: --provider ${parsed.provider} --model <pattern>)`,
|
||||
});
|
||||
}
|
||||
if (parsed.model) {
|
||||
const resolved = resolveCliModel({
|
||||
cliProvider: parsed.provider,
|
||||
cliModel: parsed.model,
|
||||
cliThinking: parsed.thinking,
|
||||
inlineApiKey: Boolean(parsed.apiKey),
|
||||
modelRuntime,
|
||||
});
|
||||
if (resolved.warning) {
|
||||
@@ -561,6 +573,8 @@ export interface MainOptions {
|
||||
|
||||
export async function main(args: string[], options?: MainOptions) {
|
||||
resetTimings();
|
||||
// Commands and startup selectors can load user-authored themes before runtime creation.
|
||||
setThemeJsonValidator(validateThemeJson);
|
||||
const extensionFactories = [...builtInExtensions, ...(options?.extensionFactories ?? [])];
|
||||
const offlineMode = args.includes("--offline") || isTruthyEnvFlag(process.env.PI_OFFLINE);
|
||||
if (offlineMode) {
|
||||
@@ -600,6 +614,12 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0] === "mcp") {
|
||||
const { runMcpCommand } = await loadMcpCommand();
|
||||
process.exitCode = await runMcpCommand(args.slice(1), { cwd, agentDir });
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = parseArgs(args);
|
||||
if (parsed.diagnostics.length > 0) {
|
||||
for (const d of parsed.diagnostics) {
|
||||
@@ -765,6 +785,7 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
additionalPromptTemplatePaths: resolvedPromptTemplatePaths,
|
||||
additionalThemePaths: resolvedThemePaths,
|
||||
noExtensions: parsed.noExtensions,
|
||||
disabledBuiltinExtensions: parsed.noMcp ? ["mcp"] : undefined,
|
||||
noSkills: parsed.noSkills,
|
||||
noPromptTemplates: parsed.noPromptTemplates,
|
||||
noThemes: parsed.noThemes,
|
||||
@@ -783,6 +804,10 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
type: "error" as const,
|
||||
message: `Failed to load extension "${path}": ${error}`,
|
||||
})),
|
||||
...(resourceLoader.getExtensions().warnings ?? []).map(({ path, warning }) => ({
|
||||
type: "warning" as const,
|
||||
message: `Extension package "${path}": ${warning}`,
|
||||
})),
|
||||
];
|
||||
|
||||
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
|
||||
@@ -876,14 +901,8 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
}
|
||||
time("readPipedStdin");
|
||||
|
||||
const { initialMessage, initialImages } = await prepareInitialMessage(
|
||||
parsed,
|
||||
settingsManager.getImageAutoResize(),
|
||||
stdinContent,
|
||||
);
|
||||
const { initialMessage, initialImages } = await prepareInitialMessage(parsed, stdinContent);
|
||||
time("prepareInitialMessage");
|
||||
// pi reads user-authored themes, so it opts into full validation before any theme loads.
|
||||
setThemeJsonValidator(validateThemeJson);
|
||||
initTheme(settingsManager.getTheme(), appMode === "interactive");
|
||||
time("initTheme");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user