@codex-infinity/pi-infinity 0.64.2 → 0.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -34
- package/README.md +5 -3
- package/dist/cli/args.d.ts +7 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +37 -15
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +51 -102
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +103 -138
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +86 -0
- package/dist/core/agent-session-services.d.ts.map +1 -0
- package/dist/core/agent-session-services.js +116 -0
- package/dist/core/agent-session-services.js.map +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -13
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +10 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +4 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +3 -14
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/package-manager.d.ts +20 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +32 -0
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +21 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +2 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +202 -456
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +20 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +56 -29
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts +2 -2
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -15
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts +4 -0
- package/dist/package-manager-cli.d.ts.map +1 -0
- package/dist/package-manager-cli.js +234 -0
- package/dist/package-manager-cli.js.map +1 -0
- package/docs/extensions.md +34 -26
- package/docs/sdk.md +109 -46
- package/docs/settings.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/hello.ts +18 -17
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/13-session-runtime.ts +30 -12
- package/examples/sdk/README.md +2 -0
- package/package.json +4 -4
package/dist/main.js
CHANGED
|
@@ -9,21 +9,17 @@ import { modelsAreEqual, supportsXhigh } from "@mariozechner/pi-ai";
|
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import { createInterface } from "readline";
|
|
11
11
|
import { parseArgs, printHelp } from "./cli/args.js";
|
|
12
|
-
import { selectConfig } from "./cli/config-selector.js";
|
|
13
12
|
import { processFileArguments } from "./cli/file-processor.js";
|
|
14
13
|
import { buildInitialMessage } from "./cli/initial-message.js";
|
|
15
14
|
import { listModels } from "./cli/list-models.js";
|
|
16
15
|
import { selectSession } from "./cli/session-picker.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
16
|
+
import { getAgentDir, getModelsPath, VERSION } from "./config.js";
|
|
17
|
+
import { createAgentSessionRuntime } from "./core/agent-session-runtime.js";
|
|
18
|
+
import { createAgentSessionFromServices, createAgentSessionServices, } from "./core/agent-session-services.js";
|
|
19
19
|
import { AuthStorage } from "./core/auth-storage.js";
|
|
20
20
|
import { exportFromFile } from "./core/export-html/index.js";
|
|
21
|
-
import { migrateKeybindingsConfigFile } from "./core/keybindings.js";
|
|
22
|
-
import { ModelRegistry } from "./core/model-registry.js";
|
|
23
21
|
import { resolveCliModel, resolveModelScope } from "./core/model-resolver.js";
|
|
24
22
|
import { restoreStdout, takeOverStdout } from "./core/output-guard.js";
|
|
25
|
-
import { DefaultPackageManager } from "./core/package-manager.js";
|
|
26
|
-
import { DefaultResourceLoader } from "./core/resource-loader.js";
|
|
27
23
|
import { SessionManager } from "./core/session-manager.js";
|
|
28
24
|
import { SettingsManager } from "./core/settings-manager.js";
|
|
29
25
|
import { printTimings, resetTimings, time } from "./core/timings.js";
|
|
@@ -31,6 +27,7 @@ import { allTools } from "./core/tools/index.js";
|
|
|
31
27
|
import { runMigrations, showDeprecationWarnings } from "./migrations.js";
|
|
32
28
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
|
|
33
29
|
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
|
|
30
|
+
import { handleConfigCommand, handlePackageCommand } from "./package-manager-cli.js";
|
|
34
31
|
/**
|
|
35
32
|
* Read all content from piped stdin.
|
|
36
33
|
* Returns undefined if stdin is a TTY (interactive terminal).
|
|
@@ -52,13 +49,17 @@ async function readPipedStdin() {
|
|
|
52
49
|
process.stdin.resume();
|
|
53
50
|
});
|
|
54
51
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
function collectSettingsDiagnostics(settingsManager, context) {
|
|
53
|
+
return settingsManager.drainErrors().map(({ scope, error }) => ({
|
|
54
|
+
type: "warning",
|
|
55
|
+
message: `(${context}, ${scope} settings) ${error.message}`,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
function reportDiagnostics(diagnostics) {
|
|
59
|
+
for (const diagnostic of diagnostics) {
|
|
60
|
+
const color = diagnostic.type === "error" ? chalk.red : diagnostic.type === "warning" ? chalk.yellow : chalk.dim;
|
|
61
|
+
const prefix = diagnostic.type === "error" ? "Error: " : diagnostic.type === "warning" ? "Warning: " : "";
|
|
62
|
+
console.error(color(`${prefix}${diagnostic.message}`));
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
function isTruthyEnvFlag(value) {
|
|
@@ -66,212 +67,20 @@ function isTruthyEnvFlag(value) {
|
|
|
66
67
|
return false;
|
|
67
68
|
return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
|
|
68
69
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return `${APP_NAME} install <source> [-l]`;
|
|
73
|
-
case "remove":
|
|
74
|
-
return `${APP_NAME} remove <source> [-l]`;
|
|
75
|
-
case "update":
|
|
76
|
-
return `${APP_NAME} update [source]`;
|
|
77
|
-
case "list":
|
|
78
|
-
return `${APP_NAME} list`;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function printPackageCommandHelp(command) {
|
|
82
|
-
switch (command) {
|
|
83
|
-
case "install":
|
|
84
|
-
console.log(`${chalk.bold("Usage:")}
|
|
85
|
-
${getPackageCommandUsage("install")}
|
|
86
|
-
|
|
87
|
-
Install a package and add it to settings.
|
|
88
|
-
|
|
89
|
-
Options:
|
|
90
|
-
-l, --local Install project-locally (.pi/settings.json)
|
|
91
|
-
|
|
92
|
-
Examples:
|
|
93
|
-
${APP_NAME} install npm:@foo/bar
|
|
94
|
-
${APP_NAME} install git:github.com/user/repo
|
|
95
|
-
${APP_NAME} install git:git@github.com:user/repo
|
|
96
|
-
${APP_NAME} install https://github.com/user/repo
|
|
97
|
-
${APP_NAME} install ssh://git@github.com/user/repo
|
|
98
|
-
${APP_NAME} install ./local/path
|
|
99
|
-
`);
|
|
100
|
-
return;
|
|
101
|
-
case "remove":
|
|
102
|
-
console.log(`${chalk.bold("Usage:")}
|
|
103
|
-
${getPackageCommandUsage("remove")}
|
|
104
|
-
|
|
105
|
-
Remove a package and its source from settings.
|
|
106
|
-
Alias: ${APP_NAME} uninstall <source> [-l]
|
|
107
|
-
|
|
108
|
-
Options:
|
|
109
|
-
-l, --local Remove from project settings (.pi/settings.json)
|
|
110
|
-
|
|
111
|
-
Examples:
|
|
112
|
-
${APP_NAME} remove npm:@foo/bar
|
|
113
|
-
${APP_NAME} uninstall npm:@foo/bar
|
|
114
|
-
`);
|
|
115
|
-
return;
|
|
116
|
-
case "update":
|
|
117
|
-
console.log(`${chalk.bold("Usage:")}
|
|
118
|
-
${getPackageCommandUsage("update")}
|
|
119
|
-
|
|
120
|
-
Update installed packages.
|
|
121
|
-
If <source> is provided, only that package is updated.
|
|
122
|
-
`);
|
|
123
|
-
return;
|
|
124
|
-
case "list":
|
|
125
|
-
console.log(`${chalk.bold("Usage:")}
|
|
126
|
-
${getPackageCommandUsage("list")}
|
|
127
|
-
|
|
128
|
-
List installed packages from user and project settings.
|
|
129
|
-
`);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
function parsePackageCommand(args) {
|
|
134
|
-
const [rawCommand, ...rest] = args;
|
|
135
|
-
let command;
|
|
136
|
-
if (rawCommand === "uninstall") {
|
|
137
|
-
command = "remove";
|
|
70
|
+
function resolveAppMode(parsed, stdinIsTTY) {
|
|
71
|
+
if (parsed.mode === "rpc") {
|
|
72
|
+
return "rpc";
|
|
138
73
|
}
|
|
139
|
-
|
|
140
|
-
|
|
74
|
+
if (parsed.mode === "json") {
|
|
75
|
+
return "json";
|
|
141
76
|
}
|
|
142
|
-
if (!
|
|
143
|
-
return
|
|
144
|
-
}
|
|
145
|
-
let local = false;
|
|
146
|
-
let help = false;
|
|
147
|
-
let invalidOption;
|
|
148
|
-
let source;
|
|
149
|
-
for (const arg of rest) {
|
|
150
|
-
if (arg === "-h" || arg === "--help") {
|
|
151
|
-
help = true;
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (arg === "-l" || arg === "--local") {
|
|
155
|
-
if (command === "install" || command === "remove") {
|
|
156
|
-
local = true;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
invalidOption = invalidOption ?? arg;
|
|
160
|
-
}
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (arg.startsWith("-")) {
|
|
164
|
-
invalidOption = invalidOption ?? arg;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (!source) {
|
|
168
|
-
source = arg;
|
|
169
|
-
}
|
|
77
|
+
if (parsed.print || !stdinIsTTY) {
|
|
78
|
+
return "print";
|
|
170
79
|
}
|
|
171
|
-
return
|
|
80
|
+
return "interactive";
|
|
172
81
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!options) {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
if (options.help) {
|
|
179
|
-
printPackageCommandHelp(options.command);
|
|
180
|
-
return true;
|
|
181
|
-
}
|
|
182
|
-
if (options.invalidOption) {
|
|
183
|
-
console.error(chalk.red(`Unknown option ${options.invalidOption} for "${options.command}".`));
|
|
184
|
-
console.error(chalk.dim(`Use "${APP_NAME} --help" or "${getPackageCommandUsage(options.command)}".`));
|
|
185
|
-
process.exitCode = 1;
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
const source = options.source;
|
|
189
|
-
if ((options.command === "install" || options.command === "remove") && !source) {
|
|
190
|
-
console.error(chalk.red(`Missing ${options.command} source.`));
|
|
191
|
-
console.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));
|
|
192
|
-
process.exitCode = 1;
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
const cwd = process.cwd();
|
|
196
|
-
const agentDir = getAgentDir();
|
|
197
|
-
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
198
|
-
reportSettingsErrors(settingsManager, "package command");
|
|
199
|
-
const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
|
|
200
|
-
packageManager.setProgressCallback((event) => {
|
|
201
|
-
if (event.type === "start") {
|
|
202
|
-
process.stdout.write(chalk.dim(`${event.message}\n`));
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
try {
|
|
206
|
-
switch (options.command) {
|
|
207
|
-
case "install":
|
|
208
|
-
await packageManager.install(source, { local: options.local });
|
|
209
|
-
packageManager.addSourceToSettings(source, { local: options.local });
|
|
210
|
-
console.log(chalk.green(`Installed ${source}`));
|
|
211
|
-
return true;
|
|
212
|
-
case "remove": {
|
|
213
|
-
await packageManager.remove(source, { local: options.local });
|
|
214
|
-
const removed = packageManager.removeSourceFromSettings(source, { local: options.local });
|
|
215
|
-
if (!removed) {
|
|
216
|
-
console.error(chalk.red(`No matching package found for ${source}`));
|
|
217
|
-
process.exitCode = 1;
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
console.log(chalk.green(`Removed ${source}`));
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
case "list": {
|
|
224
|
-
const globalSettings = settingsManager.getGlobalSettings();
|
|
225
|
-
const projectSettings = settingsManager.getProjectSettings();
|
|
226
|
-
const globalPackages = globalSettings.packages ?? [];
|
|
227
|
-
const projectPackages = projectSettings.packages ?? [];
|
|
228
|
-
if (globalPackages.length === 0 && projectPackages.length === 0) {
|
|
229
|
-
console.log(chalk.dim("No packages installed."));
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
const formatPackage = (pkg, scope) => {
|
|
233
|
-
const source = typeof pkg === "string" ? pkg : pkg.source;
|
|
234
|
-
const filtered = typeof pkg === "object";
|
|
235
|
-
const display = filtered ? `${source} (filtered)` : source;
|
|
236
|
-
console.log(` ${display}`);
|
|
237
|
-
const path = packageManager.getInstalledPath(source, scope);
|
|
238
|
-
if (path) {
|
|
239
|
-
console.log(chalk.dim(` ${path}`));
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
if (globalPackages.length > 0) {
|
|
243
|
-
console.log(chalk.bold("User packages:"));
|
|
244
|
-
for (const pkg of globalPackages) {
|
|
245
|
-
formatPackage(pkg, "user");
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (projectPackages.length > 0) {
|
|
249
|
-
if (globalPackages.length > 0)
|
|
250
|
-
console.log();
|
|
251
|
-
console.log(chalk.bold("Project packages:"));
|
|
252
|
-
for (const pkg of projectPackages) {
|
|
253
|
-
formatPackage(pkg, "project");
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
case "update":
|
|
259
|
-
await packageManager.update(source);
|
|
260
|
-
if (source) {
|
|
261
|
-
console.log(chalk.green(`Updated ${source}`));
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
console.log(chalk.green("Updated packages"));
|
|
265
|
-
}
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
catch (error) {
|
|
270
|
-
const message = error instanceof Error ? error.message : "Unknown package command error";
|
|
271
|
-
console.error(chalk.red(`Error: ${message}`));
|
|
272
|
-
process.exitCode = 1;
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
82
|
+
function toPrintOutputMode(appMode) {
|
|
83
|
+
return appMode === "json" ? "json" : "text";
|
|
275
84
|
}
|
|
276
85
|
async function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {
|
|
277
86
|
if (parsed.fileArgs.length === 0) {
|
|
@@ -323,29 +132,6 @@ async function promptConfirm(message) {
|
|
|
323
132
|
});
|
|
324
133
|
});
|
|
325
134
|
}
|
|
326
|
-
/** Helper to call CLI-only session_directory handlers before the initial session manager is created */
|
|
327
|
-
async function callSessionDirectoryHook(extensions, cwd) {
|
|
328
|
-
let customSessionDir;
|
|
329
|
-
for (const ext of extensions.extensions) {
|
|
330
|
-
const handlers = ext.handlers.get("session_directory");
|
|
331
|
-
if (!handlers || handlers.length === 0)
|
|
332
|
-
continue;
|
|
333
|
-
for (const handler of handlers) {
|
|
334
|
-
try {
|
|
335
|
-
const event = { type: "session_directory", cwd };
|
|
336
|
-
const result = (await handler(event));
|
|
337
|
-
if (result?.sessionDir) {
|
|
338
|
-
customSessionDir = result.sessionDir;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
catch (err) {
|
|
342
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
343
|
-
console.error(chalk.red(`Extension "${ext.path}" session_directory handler failed: ${message}`));
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return customSessionDir;
|
|
348
|
-
}
|
|
349
135
|
function validateForkFlags(parsed) {
|
|
350
136
|
if (!parsed.fork)
|
|
351
137
|
return;
|
|
@@ -370,62 +156,65 @@ function forkSessionOrExit(sourcePath, cwd, sessionDir) {
|
|
|
370
156
|
process.exit(1);
|
|
371
157
|
}
|
|
372
158
|
}
|
|
373
|
-
async function createSessionManager(parsed, cwd,
|
|
159
|
+
async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
374
160
|
if (parsed.noSession) {
|
|
375
161
|
return SessionManager.inMemory();
|
|
376
162
|
}
|
|
377
|
-
// Priority: CLI flag > settings.json > extension hook
|
|
378
|
-
const effectiveSessionDir = parsed.sessionDir ?? settingsManager.getSessionDir() ?? (await callSessionDirectoryHook(extensions, cwd));
|
|
379
163
|
if (parsed.fork) {
|
|
380
|
-
const resolved = await resolveSessionPath(parsed.fork, cwd,
|
|
164
|
+
const resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);
|
|
381
165
|
switch (resolved.type) {
|
|
382
166
|
case "path":
|
|
383
167
|
case "local":
|
|
384
168
|
case "global":
|
|
385
|
-
return forkSessionOrExit(resolved.path, cwd,
|
|
169
|
+
return forkSessionOrExit(resolved.path, cwd, sessionDir);
|
|
386
170
|
case "not_found":
|
|
387
171
|
console.error(chalk.red(`No session found matching '${resolved.arg}'`));
|
|
388
172
|
process.exit(1);
|
|
389
173
|
}
|
|
390
174
|
}
|
|
391
175
|
if (parsed.session) {
|
|
392
|
-
const resolved = await resolveSessionPath(parsed.session, cwd,
|
|
176
|
+
const resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);
|
|
393
177
|
switch (resolved.type) {
|
|
394
178
|
case "path":
|
|
395
179
|
case "local":
|
|
396
|
-
return SessionManager.open(resolved.path,
|
|
180
|
+
return SessionManager.open(resolved.path, sessionDir);
|
|
397
181
|
case "global": {
|
|
398
|
-
// Session found in different project - ask user if they want to fork
|
|
399
182
|
console.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));
|
|
400
183
|
const shouldFork = await promptConfirm("Fork this session into current directory?");
|
|
401
184
|
if (!shouldFork) {
|
|
402
185
|
console.log(chalk.dim("Aborted."));
|
|
403
186
|
process.exit(0);
|
|
404
187
|
}
|
|
405
|
-
return forkSessionOrExit(resolved.path, cwd,
|
|
188
|
+
return forkSessionOrExit(resolved.path, cwd, sessionDir);
|
|
406
189
|
}
|
|
407
190
|
case "not_found":
|
|
408
191
|
console.error(chalk.red(`No session found matching '${resolved.arg}'`));
|
|
409
192
|
process.exit(1);
|
|
410
193
|
}
|
|
411
194
|
}
|
|
412
|
-
if (parsed.
|
|
413
|
-
|
|
195
|
+
if (parsed.resume) {
|
|
196
|
+
initTheme(settingsManager.getTheme(), true);
|
|
197
|
+
try {
|
|
198
|
+
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), SessionManager.listAll);
|
|
199
|
+
if (!selectedPath) {
|
|
200
|
+
console.log(chalk.dim("No session selected"));
|
|
201
|
+
process.exit(0);
|
|
202
|
+
}
|
|
203
|
+
return SessionManager.open(selectedPath, sessionDir);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
stopThemeWatcher();
|
|
207
|
+
}
|
|
414
208
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (effectiveSessionDir) {
|
|
418
|
-
return SessionManager.create(cwd, effectiveSessionDir);
|
|
209
|
+
if (parsed.continue) {
|
|
210
|
+
return SessionManager.continueRecent(cwd, sessionDir);
|
|
419
211
|
}
|
|
420
|
-
|
|
421
|
-
return undefined;
|
|
212
|
+
return SessionManager.create(cwd, sessionDir);
|
|
422
213
|
}
|
|
423
|
-
function buildSessionOptions(parsed, scopedModels,
|
|
214
|
+
function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegistry, settingsManager) {
|
|
424
215
|
const options = {};
|
|
216
|
+
const diagnostics = [];
|
|
425
217
|
let cliThinkingFromModel = false;
|
|
426
|
-
if (sessionManager) {
|
|
427
|
-
options.sessionManager = sessionManager;
|
|
428
|
-
}
|
|
429
218
|
// Model from CLI
|
|
430
219
|
// - supports --provider <name> --model <pattern>
|
|
431
220
|
// - supports --model <provider>/<pattern>
|
|
@@ -436,11 +225,10 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
436
225
|
modelRegistry,
|
|
437
226
|
});
|
|
438
227
|
if (resolved.warning) {
|
|
439
|
-
|
|
228
|
+
diagnostics.push({ type: "warning", message: resolved.warning });
|
|
440
229
|
}
|
|
441
230
|
if (resolved.error) {
|
|
442
|
-
|
|
443
|
-
process.exit(1);
|
|
231
|
+
diagnostics.push({ type: "error", message: resolved.error });
|
|
444
232
|
}
|
|
445
233
|
if (resolved.model) {
|
|
446
234
|
options.model = resolved.model;
|
|
@@ -452,7 +240,7 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
452
240
|
}
|
|
453
241
|
}
|
|
454
242
|
}
|
|
455
|
-
if (!options.model && scopedModels.length > 0 && !
|
|
243
|
+
if (!options.model && scopedModels.length > 0 && !hasExistingSession) {
|
|
456
244
|
// Check if saved default is in scoped models - use it if so, otherwise first scoped model
|
|
457
245
|
const savedProvider = settingsManager.getDefaultProvider();
|
|
458
246
|
const savedModelId = settingsManager.getDefaultModel();
|
|
@@ -509,52 +297,11 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
509
297
|
if (parsed.autoNextIdea) {
|
|
510
298
|
options.autoNextIdea = true;
|
|
511
299
|
}
|
|
512
|
-
return { options, cliThinkingFromModel };
|
|
300
|
+
return { options, cliThinkingFromModel, diagnostics };
|
|
513
301
|
}
|
|
514
302
|
function resolveCliPaths(cwd, paths) {
|
|
515
303
|
return paths?.map((value) => resolve(cwd, value));
|
|
516
304
|
}
|
|
517
|
-
function buildRuntimeBootstrap(parsed, cwd, agentDir, authStorage, sessionOptions) {
|
|
518
|
-
return {
|
|
519
|
-
agentDir,
|
|
520
|
-
authStorage,
|
|
521
|
-
model: sessionOptions.model,
|
|
522
|
-
thinkingLevel: sessionOptions.thinkingLevel,
|
|
523
|
-
scopedModels: sessionOptions.scopedModels,
|
|
524
|
-
tools: sessionOptions.tools,
|
|
525
|
-
customTools: sessionOptions.customTools,
|
|
526
|
-
resourceLoader: {
|
|
527
|
-
additionalExtensionPaths: resolveCliPaths(cwd, parsed.extensions),
|
|
528
|
-
additionalSkillPaths: resolveCliPaths(cwd, parsed.skills),
|
|
529
|
-
additionalPromptTemplatePaths: resolveCliPaths(cwd, parsed.promptTemplates),
|
|
530
|
-
additionalThemePaths: resolveCliPaths(cwd, parsed.themes),
|
|
531
|
-
noExtensions: parsed.noExtensions,
|
|
532
|
-
noSkills: parsed.noSkills,
|
|
533
|
-
noPromptTemplates: parsed.noPromptTemplates,
|
|
534
|
-
noThemes: parsed.noThemes,
|
|
535
|
-
systemPrompt: parsed.systemPrompt,
|
|
536
|
-
appendSystemPrompt: parsed.appendSystemPrompt,
|
|
537
|
-
},
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
async function handleConfigCommand(args) {
|
|
541
|
-
if (args[0] !== "config") {
|
|
542
|
-
return false;
|
|
543
|
-
}
|
|
544
|
-
const cwd = process.cwd();
|
|
545
|
-
const agentDir = getAgentDir();
|
|
546
|
-
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
547
|
-
reportSettingsErrors(settingsManager, "config command");
|
|
548
|
-
const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
|
|
549
|
-
const resolvedPaths = await packageManager.resolve();
|
|
550
|
-
await selectConfig({
|
|
551
|
-
resolvedPaths,
|
|
552
|
-
settingsManager,
|
|
553
|
-
cwd,
|
|
554
|
-
agentDir,
|
|
555
|
-
});
|
|
556
|
-
process.exit(0);
|
|
557
|
-
}
|
|
558
305
|
export async function main(args) {
|
|
559
306
|
resetTimings();
|
|
560
307
|
const offlineMode = args.includes("--offline") || isTruthyEnvFlag(process.env.PI_OFFLINE);
|
|
@@ -568,93 +315,26 @@ export async function main(args) {
|
|
|
568
315
|
if (await handleConfigCommand(args)) {
|
|
569
316
|
return;
|
|
570
317
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
takeOverStdout();
|
|
577
|
-
}
|
|
578
|
-
// Run migrations (pass cwd for project-local migrations)
|
|
579
|
-
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
|
580
|
-
time("runMigrations");
|
|
581
|
-
// Early load extensions to discover their CLI flags
|
|
582
|
-
const cwd = process.cwd();
|
|
583
|
-
const agentDir = getAgentDir();
|
|
584
|
-
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
585
|
-
reportSettingsErrors(settingsManager, "startup");
|
|
586
|
-
const authStorage = AuthStorage.create();
|
|
587
|
-
const modelRegistry = ModelRegistry.create(authStorage, getModelsPath());
|
|
588
|
-
const resourceLoader = new DefaultResourceLoader({
|
|
589
|
-
cwd,
|
|
590
|
-
agentDir,
|
|
591
|
-
settingsManager,
|
|
592
|
-
additionalExtensionPaths: firstPass.extensions,
|
|
593
|
-
additionalSkillPaths: firstPass.skills,
|
|
594
|
-
additionalPromptTemplatePaths: firstPass.promptTemplates,
|
|
595
|
-
additionalThemePaths: firstPass.themes,
|
|
596
|
-
noExtensions: firstPass.noExtensions,
|
|
597
|
-
noSkills: firstPass.noSkills,
|
|
598
|
-
noPromptTemplates: firstPass.noPromptTemplates,
|
|
599
|
-
noThemes: firstPass.noThemes,
|
|
600
|
-
systemPrompt: firstPass.systemPrompt,
|
|
601
|
-
appendSystemPrompt: firstPass.appendSystemPrompt,
|
|
602
|
-
});
|
|
603
|
-
time("createResourceLoader");
|
|
604
|
-
await resourceLoader.reload();
|
|
605
|
-
time("resourceLoader.reload");
|
|
606
|
-
const extensionsResult = resourceLoader.getExtensions();
|
|
607
|
-
for (const { path, error } of extensionsResult.errors) {
|
|
608
|
-
console.error(chalk.red(`Failed to load extension "${path}": ${error}`));
|
|
609
|
-
}
|
|
610
|
-
// Apply pending provider registrations from extensions immediately
|
|
611
|
-
// so they're available for model resolution before AgentSession is created
|
|
612
|
-
for (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {
|
|
613
|
-
try {
|
|
614
|
-
modelRegistry.registerProvider(name, config);
|
|
318
|
+
const parsed = parseArgs(args);
|
|
319
|
+
if (parsed.diagnostics.length > 0) {
|
|
320
|
+
for (const d of parsed.diagnostics) {
|
|
321
|
+
const color = d.type === "error" ? chalk.red : chalk.yellow;
|
|
322
|
+
console.error(color(`${d.type === "error" ? "Error" : "Warning"}: ${d.message}`));
|
|
615
323
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
console.error(chalk.red(`Extension "${extensionPath}" error: ${message}`));
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
622
|
-
const extensionFlags = new Map();
|
|
623
|
-
for (const ext of extensionsResult.extensions) {
|
|
624
|
-
for (const [name, flag] of ext.flags) {
|
|
625
|
-
extensionFlags.set(name, { type: flag.type });
|
|
324
|
+
if (parsed.diagnostics.some((d) => d.type === "error")) {
|
|
325
|
+
process.exit(1);
|
|
626
326
|
}
|
|
627
327
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
extensionsResult.runtime.flagValues.set(name, value);
|
|
328
|
+
time("parseArgs");
|
|
329
|
+
let appMode = resolveAppMode(parsed, process.stdin.isTTY);
|
|
330
|
+
const shouldTakeOverStdout = appMode !== "interactive";
|
|
331
|
+
if (shouldTakeOverStdout) {
|
|
332
|
+
takeOverStdout();
|
|
634
333
|
}
|
|
635
334
|
if (parsed.version) {
|
|
636
335
|
console.log(VERSION);
|
|
637
336
|
process.exit(0);
|
|
638
337
|
}
|
|
639
|
-
if (parsed.help) {
|
|
640
|
-
printHelp();
|
|
641
|
-
process.exit(0);
|
|
642
|
-
}
|
|
643
|
-
if (parsed.listModels !== undefined) {
|
|
644
|
-
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
|
|
645
|
-
await listModels(modelRegistry, searchPattern);
|
|
646
|
-
process.exit(0);
|
|
647
|
-
}
|
|
648
|
-
// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC
|
|
649
|
-
let stdinContent;
|
|
650
|
-
if (parsed.mode !== "rpc") {
|
|
651
|
-
stdinContent = await readPipedStdin();
|
|
652
|
-
if (stdinContent !== undefined) {
|
|
653
|
-
// Force print mode since interactive mode requires a TTY for keyboard input
|
|
654
|
-
parsed.print = true;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
time("readPipedStdin");
|
|
658
338
|
if (parsed.export) {
|
|
659
339
|
let result;
|
|
660
340
|
try {
|
|
@@ -669,97 +349,163 @@ export async function main(args) {
|
|
|
669
349
|
console.log(`Exported to: ${result}`);
|
|
670
350
|
process.exit(0);
|
|
671
351
|
}
|
|
672
|
-
migrateKeybindingsConfigFile(agentDir);
|
|
673
|
-
time("migrateKeybindingsConfigFile");
|
|
674
352
|
if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) {
|
|
675
353
|
console.error(chalk.red("Error: @file arguments are not supported in RPC mode"));
|
|
676
354
|
process.exit(1);
|
|
677
355
|
}
|
|
678
356
|
validateForkFlags(parsed);
|
|
357
|
+
// Run migrations (pass cwd for project-local migrations)
|
|
358
|
+
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
|
359
|
+
time("runMigrations");
|
|
360
|
+
const cwd = process.cwd();
|
|
361
|
+
const agentDir = getAgentDir();
|
|
362
|
+
const startupSettingsManager = SettingsManager.create(cwd, agentDir);
|
|
363
|
+
reportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, "startup session lookup"));
|
|
364
|
+
// Decide the final runtime cwd before creating cwd-bound runtime services.
|
|
365
|
+
// --session and --resume may select a session from another project, so project-local
|
|
366
|
+
// settings, resources, provider registrations, and models must be resolved only after
|
|
367
|
+
// the target session cwd is known. The startup-cwd settings manager is used only for
|
|
368
|
+
// sessionDir lookup during session selection.
|
|
369
|
+
const sessionManager = await createSessionManager(parsed, cwd, parsed.sessionDir ?? startupSettingsManager.getSessionDir(), startupSettingsManager);
|
|
370
|
+
time("createSessionManager");
|
|
371
|
+
const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);
|
|
372
|
+
const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
|
|
373
|
+
const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);
|
|
374
|
+
const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);
|
|
375
|
+
const authStorage = AuthStorage.create();
|
|
376
|
+
const createRuntime = async ({ cwd, agentDir, sessionManager, sessionStartEvent, }) => {
|
|
377
|
+
const services = await createAgentSessionServices({
|
|
378
|
+
cwd,
|
|
379
|
+
agentDir,
|
|
380
|
+
authStorage,
|
|
381
|
+
extensionFlagValues: parsed.unknownFlags,
|
|
382
|
+
resourceLoaderOptions: {
|
|
383
|
+
additionalExtensionPaths: resolvedExtensionPaths,
|
|
384
|
+
additionalSkillPaths: resolvedSkillPaths,
|
|
385
|
+
additionalPromptTemplatePaths: resolvedPromptTemplatePaths,
|
|
386
|
+
additionalThemePaths: resolvedThemePaths,
|
|
387
|
+
noExtensions: parsed.noExtensions,
|
|
388
|
+
noSkills: parsed.noSkills,
|
|
389
|
+
noPromptTemplates: parsed.noPromptTemplates,
|
|
390
|
+
noThemes: parsed.noThemes,
|
|
391
|
+
systemPrompt: parsed.systemPrompt,
|
|
392
|
+
appendSystemPrompt: parsed.appendSystemPrompt,
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
const { settingsManager, modelRegistry, resourceLoader } = services;
|
|
396
|
+
const diagnostics = [
|
|
397
|
+
...services.diagnostics,
|
|
398
|
+
...collectSettingsDiagnostics(settingsManager, "runtime creation"),
|
|
399
|
+
...resourceLoader.getExtensions().errors.map(({ path, error }) => ({
|
|
400
|
+
type: "error",
|
|
401
|
+
message: `Failed to load extension "${path}": ${error}`,
|
|
402
|
+
})),
|
|
403
|
+
];
|
|
404
|
+
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
|
|
405
|
+
const scopedModels = modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];
|
|
406
|
+
const { options: sessionOptions, cliThinkingFromModel, diagnostics: sessionOptionDiagnostics, } = buildSessionOptions(parsed, scopedModels, sessionManager.buildSessionContext().messages.length > 0, modelRegistry, settingsManager);
|
|
407
|
+
diagnostics.push(...sessionOptionDiagnostics);
|
|
408
|
+
if (parsed.apiKey) {
|
|
409
|
+
if (!sessionOptions.model) {
|
|
410
|
+
diagnostics.push({
|
|
411
|
+
type: "error",
|
|
412
|
+
message: "--api-key requires a model to be specified via --model, --provider/--model, or --models",
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const created = await createAgentSessionFromServices({
|
|
420
|
+
services,
|
|
421
|
+
sessionManager,
|
|
422
|
+
sessionStartEvent,
|
|
423
|
+
model: sessionOptions.model,
|
|
424
|
+
thinkingLevel: sessionOptions.thinkingLevel,
|
|
425
|
+
scopedModels: sessionOptions.scopedModels,
|
|
426
|
+
tools: sessionOptions.tools,
|
|
427
|
+
customTools: sessionOptions.customTools,
|
|
428
|
+
});
|
|
429
|
+
const cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;
|
|
430
|
+
if (created.session.model && cliThinkingOverride) {
|
|
431
|
+
let effectiveThinking = created.session.thinkingLevel;
|
|
432
|
+
if (!created.session.model.reasoning) {
|
|
433
|
+
effectiveThinking = "off";
|
|
434
|
+
}
|
|
435
|
+
else if (effectiveThinking === "xhigh" && !supportsXhigh(created.session.model)) {
|
|
436
|
+
effectiveThinking = "high";
|
|
437
|
+
}
|
|
438
|
+
if (effectiveThinking !== created.session.thinkingLevel) {
|
|
439
|
+
created.session.setThinkingLevel(effectiveThinking);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
...created,
|
|
444
|
+
services,
|
|
445
|
+
diagnostics,
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
time("createRuntime");
|
|
449
|
+
const runtime = await createAgentSessionRuntime(createRuntime, {
|
|
450
|
+
cwd: sessionManager.getCwd(),
|
|
451
|
+
agentDir,
|
|
452
|
+
sessionManager,
|
|
453
|
+
});
|
|
454
|
+
const { services, session, modelFallbackMessage } = runtime;
|
|
455
|
+
const { settingsManager, modelRegistry, resourceLoader } = services;
|
|
456
|
+
if (parsed.help) {
|
|
457
|
+
const extensionFlags = resourceLoader
|
|
458
|
+
.getExtensions()
|
|
459
|
+
.extensions.flatMap((extension) => Array.from(extension.flags.values()));
|
|
460
|
+
printHelp(extensionFlags);
|
|
461
|
+
process.exit(0);
|
|
462
|
+
}
|
|
463
|
+
if (parsed.listModels !== undefined) {
|
|
464
|
+
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
|
|
465
|
+
await listModels(modelRegistry, searchPattern);
|
|
466
|
+
process.exit(0);
|
|
467
|
+
}
|
|
468
|
+
// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC
|
|
469
|
+
let stdinContent;
|
|
470
|
+
if (appMode !== "rpc") {
|
|
471
|
+
stdinContent = await readPipedStdin();
|
|
472
|
+
if (stdinContent !== undefined) {
|
|
473
|
+
appMode = "print";
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
time("readPipedStdin");
|
|
679
477
|
const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize(), stdinContent);
|
|
680
478
|
time("prepareInitialMessage");
|
|
681
|
-
|
|
682
|
-
const startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);
|
|
683
|
-
if (startupBenchmark && !isInteractive) {
|
|
684
|
-
console.error(chalk.red("Error: PI_STARTUP_BENCHMARK only supports interactive mode"));
|
|
685
|
-
process.exit(1);
|
|
686
|
-
}
|
|
687
|
-
const mode = parsed.mode || "text";
|
|
688
|
-
initTheme(settingsManager.getTheme(), isInteractive);
|
|
479
|
+
initTheme(settingsManager.getTheme(), appMode === "interactive");
|
|
689
480
|
time("initTheme");
|
|
690
481
|
// Show deprecation warnings in interactive mode
|
|
691
|
-
if (
|
|
482
|
+
if (appMode === "interactive" && deprecationWarnings.length > 0) {
|
|
692
483
|
await showDeprecationWarnings(deprecationWarnings);
|
|
693
484
|
}
|
|
694
|
-
|
|
695
|
-
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
|
|
696
|
-
if (modelPatterns && modelPatterns.length > 0) {
|
|
697
|
-
scopedModels = await resolveModelScope(modelPatterns, modelRegistry);
|
|
698
|
-
}
|
|
485
|
+
const scopedModels = [...session.scopedModels];
|
|
699
486
|
time("resolveModelScope");
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
// Handle --resume: show session picker
|
|
704
|
-
if (parsed.resume) {
|
|
705
|
-
// Compute effective session dir for resume (same logic as createSessionManager)
|
|
706
|
-
const effectiveSessionDir = parsed.sessionDir ??
|
|
707
|
-
settingsManager.getSessionDir() ??
|
|
708
|
-
(await callSessionDirectoryHook(extensionsResult, cwd));
|
|
709
|
-
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, effectiveSessionDir, onProgress), SessionManager.listAll);
|
|
710
|
-
if (!selectedPath) {
|
|
711
|
-
console.log(chalk.dim("No session selected"));
|
|
712
|
-
stopThemeWatcher();
|
|
713
|
-
process.exit(0);
|
|
714
|
-
}
|
|
715
|
-
sessionManager = SessionManager.open(selectedPath, effectiveSessionDir);
|
|
716
|
-
}
|
|
717
|
-
const { options: sessionOptions, cliThinkingFromModel } = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager);
|
|
718
|
-
if (parsed.apiKey) {
|
|
719
|
-
if (!sessionOptions.model) {
|
|
720
|
-
console.error(chalk.red("--api-key requires a model to be specified via --model, --provider/--model, or --models"));
|
|
721
|
-
process.exit(1);
|
|
722
|
-
}
|
|
723
|
-
authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);
|
|
724
|
-
}
|
|
725
|
-
const runtimeBootstrap = buildRuntimeBootstrap(parsed, cwd, agentDir, authStorage, sessionOptions);
|
|
726
|
-
const runtime = await createAgentSessionRuntime(runtimeBootstrap, {
|
|
727
|
-
cwd: sessionManager?.getCwd() ?? cwd,
|
|
728
|
-
sessionManager,
|
|
729
|
-
});
|
|
730
|
-
if (process.cwd() !== runtime.cwd) {
|
|
731
|
-
process.chdir(runtime.cwd);
|
|
487
|
+
reportDiagnostics(runtime.diagnostics);
|
|
488
|
+
if (runtime.diagnostics.some((diagnostic) => diagnostic.type === "error")) {
|
|
489
|
+
process.exit(1);
|
|
732
490
|
}
|
|
733
|
-
const runtimeHost = new AgentSessionRuntimeHost(runtimeBootstrap, runtime);
|
|
734
|
-
const { session, modelFallbackMessage } = runtime;
|
|
735
491
|
time("createAgentSession");
|
|
736
|
-
if (
|
|
492
|
+
if (appMode !== "interactive" && !session.model) {
|
|
737
493
|
console.error(chalk.red("No models available."));
|
|
738
494
|
console.error(chalk.yellow("\nSet an API key environment variable:"));
|
|
739
495
|
console.error(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.");
|
|
740
496
|
console.error(chalk.yellow(`\nOr create ${getModelsPath()}`));
|
|
741
497
|
process.exit(1);
|
|
742
498
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
let effectiveThinking = session.thinkingLevel;
|
|
748
|
-
if (!session.model.reasoning) {
|
|
749
|
-
effectiveThinking = "off";
|
|
750
|
-
}
|
|
751
|
-
else if (effectiveThinking === "xhigh" && !supportsXhigh(session.model)) {
|
|
752
|
-
effectiveThinking = "high";
|
|
753
|
-
}
|
|
754
|
-
if (effectiveThinking !== session.thinkingLevel) {
|
|
755
|
-
session.setThinkingLevel(effectiveThinking);
|
|
756
|
-
}
|
|
499
|
+
const startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);
|
|
500
|
+
if (startupBenchmark && appMode !== "interactive") {
|
|
501
|
+
console.error(chalk.red("Error: PI_STARTUP_BENCHMARK only supports interactive mode"));
|
|
502
|
+
process.exit(1);
|
|
757
503
|
}
|
|
758
|
-
if (
|
|
504
|
+
if (appMode === "rpc") {
|
|
759
505
|
printTimings();
|
|
760
|
-
await runRpcMode(
|
|
506
|
+
await runRpcMode(runtime);
|
|
761
507
|
}
|
|
762
|
-
else if (
|
|
508
|
+
else if (appMode === "interactive") {
|
|
763
509
|
if (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {
|
|
764
510
|
const modelList = scopedModels
|
|
765
511
|
.map((sm) => {
|
|
@@ -769,7 +515,7 @@ export async function main(args) {
|
|
|
769
515
|
.join(", ");
|
|
770
516
|
console.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray("(Ctrl+P to cycle)")}`));
|
|
771
517
|
}
|
|
772
|
-
const interactiveMode = new InteractiveMode(
|
|
518
|
+
const interactiveMode = new InteractiveMode(runtime, {
|
|
773
519
|
migratedProviders,
|
|
774
520
|
modelFallbackMessage,
|
|
775
521
|
initialMessage,
|
|
@@ -796,8 +542,8 @@ export async function main(args) {
|
|
|
796
542
|
}
|
|
797
543
|
else {
|
|
798
544
|
printTimings();
|
|
799
|
-
const exitCode = await runPrintMode(
|
|
800
|
-
mode,
|
|
545
|
+
const exitCode = await runPrintMode(runtime, {
|
|
546
|
+
mode: toPrintOutputMode(appMode),
|
|
801
547
|
messages: parsed.messages,
|
|
802
548
|
initialMessage,
|
|
803
549
|
initialImages,
|