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