@mariozechner/pi-coding-agent 0.64.0 → 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 +110 -0
- package/README.md +12 -6
- 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 +236 -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/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +19 -7
- package/dist/core/bash-executor.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 +55 -9
- 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 +25 -3
- 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-cwd.d.ts +19 -0
- package/dist/core/session-cwd.d.ts.map +1 -0
- package/dist/core/session-cwd.js +38 -0
- package/dist/core/session-cwd.js.map +1 -0
- package/dist/core/session-manager.d.ts +5 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +16 -8
- 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/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +19 -9
- package/dist/core/tools/bash.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 +245 -426
- 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 +10 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +160 -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 +15 -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-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 +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/dist/utils/paths.d.ts +7 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +19 -0
- package/dist/utils/paths.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/doom-overlay/doom/build.sh +2 -2
- 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,32 +4,35 @@
|
|
|
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";
|
|
9
|
+
import { ProcessTerminal, setKeybindings, TUI } from "@mariozechner/pi-tui";
|
|
8
10
|
import chalk from "chalk";
|
|
9
11
|
import { createInterface } from "readline";
|
|
10
12
|
import { parseArgs, printHelp } from "./cli/args.js";
|
|
11
|
-
import { selectConfig } from "./cli/config-selector.js";
|
|
12
13
|
import { processFileArguments } from "./cli/file-processor.js";
|
|
13
14
|
import { buildInitialMessage } from "./cli/initial-message.js";
|
|
14
15
|
import { listModels } from "./cli/list-models.js";
|
|
15
16
|
import { selectSession } from "./cli/session-picker.js";
|
|
16
|
-
import {
|
|
17
|
+
import { getAgentDir, getModelsPath, VERSION } from "./config.js";
|
|
18
|
+
import { createAgentSessionRuntime } from "./core/agent-session-runtime.js";
|
|
19
|
+
import { createAgentSessionFromServices, createAgentSessionServices, } from "./core/agent-session-services.js";
|
|
17
20
|
import { AuthStorage } from "./core/auth-storage.js";
|
|
18
21
|
import { exportFromFile } from "./core/export-html/index.js";
|
|
19
|
-
import {
|
|
20
|
-
import { ModelRegistry } from "./core/model-registry.js";
|
|
22
|
+
import { KeybindingsManager } from "./core/keybindings.js";
|
|
21
23
|
import { resolveCliModel, resolveModelScope } from "./core/model-resolver.js";
|
|
22
24
|
import { restoreStdout, takeOverStdout } from "./core/output-guard.js";
|
|
23
|
-
import {
|
|
24
|
-
import { DefaultResourceLoader } from "./core/resource-loader.js";
|
|
25
|
-
import { createAgentSession } from "./core/sdk.js";
|
|
25
|
+
import { formatMissingSessionCwdPrompt, getMissingSessionCwdIssue, MissingSessionCwdError, } from "./core/session-cwd.js";
|
|
26
26
|
import { SessionManager } from "./core/session-manager.js";
|
|
27
27
|
import { SettingsManager } from "./core/settings-manager.js";
|
|
28
28
|
import { printTimings, resetTimings, time } from "./core/timings.js";
|
|
29
29
|
import { allTools } from "./core/tools/index.js";
|
|
30
30
|
import { runMigrations, showDeprecationWarnings } from "./migrations.js";
|
|
31
31
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
|
|
32
|
+
import { ExtensionSelectorComponent } from "./modes/interactive/components/extension-selector.js";
|
|
32
33
|
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
|
|
34
|
+
import { handleConfigCommand, handlePackageCommand } from "./package-manager-cli.js";
|
|
35
|
+
import { isLocalPath } from "./utils/paths.js";
|
|
33
36
|
/**
|
|
34
37
|
* Read all content from piped stdin.
|
|
35
38
|
* Returns undefined if stdin is a TTY (interactive terminal).
|
|
@@ -51,13 +54,17 @@ async function readPipedStdin() {
|
|
|
51
54
|
process.stdin.resume();
|
|
52
55
|
});
|
|
53
56
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
function collectSettingsDiagnostics(settingsManager, context) {
|
|
58
|
+
return settingsManager.drainErrors().map(({ scope, error }) => ({
|
|
59
|
+
type: "warning",
|
|
60
|
+
message: `(${context}, ${scope} settings) ${error.message}`,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
function reportDiagnostics(diagnostics) {
|
|
64
|
+
for (const diagnostic of diagnostics) {
|
|
65
|
+
const color = diagnostic.type === "error" ? chalk.red : diagnostic.type === "warning" ? chalk.yellow : chalk.dim;
|
|
66
|
+
const prefix = diagnostic.type === "error" ? "Error: " : diagnostic.type === "warning" ? "Warning: " : "";
|
|
67
|
+
console.error(color(`${prefix}${diagnostic.message}`));
|
|
61
68
|
}
|
|
62
69
|
}
|
|
63
70
|
function isTruthyEnvFlag(value) {
|
|
@@ -65,212 +72,20 @@ function isTruthyEnvFlag(value) {
|
|
|
65
72
|
return false;
|
|
66
73
|
return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
|
|
67
74
|
}
|
|
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";
|
|
75
|
+
function resolveAppMode(parsed, stdinIsTTY) {
|
|
76
|
+
if (parsed.mode === "rpc") {
|
|
77
|
+
return "rpc";
|
|
137
78
|
}
|
|
138
|
-
|
|
139
|
-
|
|
79
|
+
if (parsed.mode === "json") {
|
|
80
|
+
return "json";
|
|
140
81
|
}
|
|
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
|
-
}
|
|
82
|
+
if (parsed.print || !stdinIsTTY) {
|
|
83
|
+
return "print";
|
|
169
84
|
}
|
|
170
|
-
return
|
|
85
|
+
return "interactive";
|
|
171
86
|
}
|
|
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
|
-
}
|
|
87
|
+
function toPrintOutputMode(appMode) {
|
|
88
|
+
return appMode === "json" ? "json" : "text";
|
|
274
89
|
}
|
|
275
90
|
async function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {
|
|
276
91
|
if (parsed.fileArgs.length === 0) {
|
|
@@ -322,29 +137,6 @@ async function promptConfirm(message) {
|
|
|
322
137
|
});
|
|
323
138
|
});
|
|
324
139
|
}
|
|
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
140
|
function validateForkFlags(parsed) {
|
|
349
141
|
if (!parsed.fork)
|
|
350
142
|
return;
|
|
@@ -369,62 +161,65 @@ function forkSessionOrExit(sourcePath, cwd, sessionDir) {
|
|
|
369
161
|
process.exit(1);
|
|
370
162
|
}
|
|
371
163
|
}
|
|
372
|
-
async function createSessionManager(parsed, cwd,
|
|
164
|
+
async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
373
165
|
if (parsed.noSession) {
|
|
374
166
|
return SessionManager.inMemory();
|
|
375
167
|
}
|
|
376
|
-
// Priority: CLI flag > settings.json > extension hook
|
|
377
|
-
const effectiveSessionDir = parsed.sessionDir ?? settingsManager.getSessionDir() ?? (await callSessionDirectoryHook(extensions, cwd));
|
|
378
168
|
if (parsed.fork) {
|
|
379
|
-
const resolved = await resolveSessionPath(parsed.fork, cwd,
|
|
169
|
+
const resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);
|
|
380
170
|
switch (resolved.type) {
|
|
381
171
|
case "path":
|
|
382
172
|
case "local":
|
|
383
173
|
case "global":
|
|
384
|
-
return forkSessionOrExit(resolved.path, cwd,
|
|
174
|
+
return forkSessionOrExit(resolved.path, cwd, sessionDir);
|
|
385
175
|
case "not_found":
|
|
386
176
|
console.error(chalk.red(`No session found matching '${resolved.arg}'`));
|
|
387
177
|
process.exit(1);
|
|
388
178
|
}
|
|
389
179
|
}
|
|
390
180
|
if (parsed.session) {
|
|
391
|
-
const resolved = await resolveSessionPath(parsed.session, cwd,
|
|
181
|
+
const resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);
|
|
392
182
|
switch (resolved.type) {
|
|
393
183
|
case "path":
|
|
394
184
|
case "local":
|
|
395
|
-
return SessionManager.open(resolved.path,
|
|
185
|
+
return SessionManager.open(resolved.path, sessionDir);
|
|
396
186
|
case "global": {
|
|
397
|
-
// Session found in different project - ask user if they want to fork
|
|
398
187
|
console.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));
|
|
399
188
|
const shouldFork = await promptConfirm("Fork this session into current directory?");
|
|
400
189
|
if (!shouldFork) {
|
|
401
190
|
console.log(chalk.dim("Aborted."));
|
|
402
191
|
process.exit(0);
|
|
403
192
|
}
|
|
404
|
-
return forkSessionOrExit(resolved.path, cwd,
|
|
193
|
+
return forkSessionOrExit(resolved.path, cwd, sessionDir);
|
|
405
194
|
}
|
|
406
195
|
case "not_found":
|
|
407
196
|
console.error(chalk.red(`No session found matching '${resolved.arg}'`));
|
|
408
197
|
process.exit(1);
|
|
409
198
|
}
|
|
410
199
|
}
|
|
411
|
-
if (parsed.
|
|
412
|
-
|
|
200
|
+
if (parsed.resume) {
|
|
201
|
+
initTheme(settingsManager.getTheme(), true);
|
|
202
|
+
try {
|
|
203
|
+
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), SessionManager.listAll);
|
|
204
|
+
if (!selectedPath) {
|
|
205
|
+
console.log(chalk.dim("No session selected"));
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
return SessionManager.open(selectedPath, sessionDir);
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
stopThemeWatcher();
|
|
212
|
+
}
|
|
413
213
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (effectiveSessionDir) {
|
|
417
|
-
return SessionManager.create(cwd, effectiveSessionDir);
|
|
214
|
+
if (parsed.continue) {
|
|
215
|
+
return SessionManager.continueRecent(cwd, sessionDir);
|
|
418
216
|
}
|
|
419
|
-
|
|
420
|
-
return undefined;
|
|
217
|
+
return SessionManager.create(cwd, sessionDir);
|
|
421
218
|
}
|
|
422
|
-
function buildSessionOptions(parsed, scopedModels,
|
|
219
|
+
function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegistry, settingsManager) {
|
|
423
220
|
const options = {};
|
|
221
|
+
const diagnostics = [];
|
|
424
222
|
let cliThinkingFromModel = false;
|
|
425
|
-
if (sessionManager) {
|
|
426
|
-
options.sessionManager = sessionManager;
|
|
427
|
-
}
|
|
428
223
|
// Model from CLI
|
|
429
224
|
// - supports --provider <name> --model <pattern>
|
|
430
225
|
// - supports --model <provider>/<pattern>
|
|
@@ -435,11 +230,10 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
435
230
|
modelRegistry,
|
|
436
231
|
});
|
|
437
232
|
if (resolved.warning) {
|
|
438
|
-
|
|
233
|
+
diagnostics.push({ type: "warning", message: resolved.warning });
|
|
439
234
|
}
|
|
440
235
|
if (resolved.error) {
|
|
441
|
-
|
|
442
|
-
process.exit(1);
|
|
236
|
+
diagnostics.push({ type: "error", message: resolved.error });
|
|
443
237
|
}
|
|
444
238
|
if (resolved.model) {
|
|
445
239
|
options.model = resolved.model;
|
|
@@ -451,7 +245,7 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
451
245
|
}
|
|
452
246
|
}
|
|
453
247
|
}
|
|
454
|
-
if (!options.model && scopedModels.length > 0 && !
|
|
248
|
+
if (!options.model && scopedModels.length > 0 && !hasExistingSession) {
|
|
455
249
|
// Check if saved default is in scoped models - use it if so, otherwise first scoped model
|
|
456
250
|
const savedProvider = settingsManager.getDefaultProvider();
|
|
457
251
|
const savedModelId = settingsManager.getDefaultModel();
|
|
@@ -501,25 +295,31 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
501
295
|
else if (parsed.tools) {
|
|
502
296
|
options.tools = parsed.tools.map((name) => allTools[name]);
|
|
503
297
|
}
|
|
504
|
-
return { options, cliThinkingFromModel };
|
|
298
|
+
return { options, cliThinkingFromModel, diagnostics };
|
|
505
299
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
300
|
+
function resolveCliPaths(cwd, paths) {
|
|
301
|
+
return paths?.map((value) => (isLocalPath(value) ? resolve(cwd, value) : value));
|
|
302
|
+
}
|
|
303
|
+
async function promptForMissingSessionCwd(issue, settingsManager) {
|
|
304
|
+
initTheme(settingsManager.getTheme());
|
|
305
|
+
setKeybindings(KeybindingsManager.create());
|
|
306
|
+
return new Promise((resolve) => {
|
|
307
|
+
const ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());
|
|
308
|
+
ui.setClearOnShrink(settingsManager.getClearOnShrink());
|
|
309
|
+
let settled = false;
|
|
310
|
+
const finish = (result) => {
|
|
311
|
+
if (settled) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
settled = true;
|
|
315
|
+
ui.stop();
|
|
316
|
+
resolve(result);
|
|
317
|
+
};
|
|
318
|
+
const selector = new ExtensionSelectorComponent(formatMissingSessionCwdPrompt(issue), ["Continue", "Cancel"], (option) => finish(option === "Continue" ? issue.fallbackCwd : undefined), () => finish(undefined), { tui: ui });
|
|
319
|
+
ui.addChild(selector);
|
|
320
|
+
ui.setFocus(selector);
|
|
321
|
+
ui.start();
|
|
521
322
|
});
|
|
522
|
-
process.exit(0);
|
|
523
323
|
}
|
|
524
324
|
export async function main(args) {
|
|
525
325
|
resetTimings();
|
|
@@ -534,93 +334,26 @@ export async function main(args) {
|
|
|
534
334
|
if (await handleConfigCommand(args)) {
|
|
535
335
|
return;
|
|
536
336
|
}
|
|
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);
|
|
337
|
+
const parsed = parseArgs(args);
|
|
338
|
+
if (parsed.diagnostics.length > 0) {
|
|
339
|
+
for (const d of parsed.diagnostics) {
|
|
340
|
+
const color = d.type === "error" ? chalk.red : chalk.yellow;
|
|
341
|
+
console.error(color(`${d.type === "error" ? "Error" : "Warning"}: ${d.message}`));
|
|
581
342
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
console.error(chalk.red(`Extension "${extensionPath}" error: ${message}`));
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
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 });
|
|
343
|
+
if (parsed.diagnostics.some((d) => d.type === "error")) {
|
|
344
|
+
process.exit(1);
|
|
592
345
|
}
|
|
593
346
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
extensionsResult.runtime.flagValues.set(name, value);
|
|
347
|
+
time("parseArgs");
|
|
348
|
+
let appMode = resolveAppMode(parsed, process.stdin.isTTY);
|
|
349
|
+
const shouldTakeOverStdout = appMode !== "interactive";
|
|
350
|
+
if (shouldTakeOverStdout) {
|
|
351
|
+
takeOverStdout();
|
|
600
352
|
}
|
|
601
353
|
if (parsed.version) {
|
|
602
354
|
console.log(VERSION);
|
|
603
355
|
process.exit(0);
|
|
604
356
|
}
|
|
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
357
|
if (parsed.export) {
|
|
625
358
|
let result;
|
|
626
359
|
try {
|
|
@@ -635,92 +368,178 @@ export async function main(args) {
|
|
|
635
368
|
console.log(`Exported to: ${result}`);
|
|
636
369
|
process.exit(0);
|
|
637
370
|
}
|
|
638
|
-
migrateKeybindingsConfigFile(agentDir);
|
|
639
|
-
time("migrateKeybindingsConfigFile");
|
|
640
371
|
if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) {
|
|
641
372
|
console.error(chalk.red("Error: @file arguments are not supported in RPC mode"));
|
|
642
373
|
process.exit(1);
|
|
643
374
|
}
|
|
644
375
|
validateForkFlags(parsed);
|
|
376
|
+
// Run migrations (pass cwd for project-local migrations)
|
|
377
|
+
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
|
378
|
+
time("runMigrations");
|
|
379
|
+
const cwd = process.cwd();
|
|
380
|
+
const agentDir = getAgentDir();
|
|
381
|
+
const startupSettingsManager = SettingsManager.create(cwd, agentDir);
|
|
382
|
+
reportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, "startup session lookup"));
|
|
383
|
+
// Decide the final runtime cwd before creating cwd-bound runtime services.
|
|
384
|
+
// --session and --resume may select a session from another project, so project-local
|
|
385
|
+
// settings, resources, provider registrations, and models must be resolved only after
|
|
386
|
+
// the target session cwd is known. The startup-cwd settings manager is used only for
|
|
387
|
+
// sessionDir lookup during session selection.
|
|
388
|
+
const sessionDir = parsed.sessionDir ?? startupSettingsManager.getSessionDir();
|
|
389
|
+
let sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager);
|
|
390
|
+
const missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);
|
|
391
|
+
if (missingSessionCwdIssue) {
|
|
392
|
+
if (appMode === "interactive") {
|
|
393
|
+
const selectedCwd = await promptForMissingSessionCwd(missingSessionCwdIssue, startupSettingsManager);
|
|
394
|
+
if (!selectedCwd) {
|
|
395
|
+
process.exit(0);
|
|
396
|
+
}
|
|
397
|
+
sessionManager = SessionManager.open(missingSessionCwdIssue.sessionFile, sessionDir, selectedCwd);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
console.error(chalk.red(new MissingSessionCwdError(missingSessionCwdIssue).message));
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
time("createSessionManager");
|
|
405
|
+
const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);
|
|
406
|
+
const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
|
|
407
|
+
const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);
|
|
408
|
+
const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);
|
|
409
|
+
const authStorage = AuthStorage.create();
|
|
410
|
+
const createRuntime = async ({ cwd, agentDir, sessionManager, sessionStartEvent, }) => {
|
|
411
|
+
const services = await createAgentSessionServices({
|
|
412
|
+
cwd,
|
|
413
|
+
agentDir,
|
|
414
|
+
authStorage,
|
|
415
|
+
extensionFlagValues: parsed.unknownFlags,
|
|
416
|
+
resourceLoaderOptions: {
|
|
417
|
+
additionalExtensionPaths: resolvedExtensionPaths,
|
|
418
|
+
additionalSkillPaths: resolvedSkillPaths,
|
|
419
|
+
additionalPromptTemplatePaths: resolvedPromptTemplatePaths,
|
|
420
|
+
additionalThemePaths: resolvedThemePaths,
|
|
421
|
+
noExtensions: parsed.noExtensions,
|
|
422
|
+
noSkills: parsed.noSkills,
|
|
423
|
+
noPromptTemplates: parsed.noPromptTemplates,
|
|
424
|
+
noThemes: parsed.noThemes,
|
|
425
|
+
systemPrompt: parsed.systemPrompt,
|
|
426
|
+
appendSystemPrompt: parsed.appendSystemPrompt,
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
const { settingsManager, modelRegistry, resourceLoader } = services;
|
|
430
|
+
const diagnostics = [
|
|
431
|
+
...services.diagnostics,
|
|
432
|
+
...collectSettingsDiagnostics(settingsManager, "runtime creation"),
|
|
433
|
+
...resourceLoader.getExtensions().errors.map(({ path, error }) => ({
|
|
434
|
+
type: "error",
|
|
435
|
+
message: `Failed to load extension "${path}": ${error}`,
|
|
436
|
+
})),
|
|
437
|
+
];
|
|
438
|
+
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
|
|
439
|
+
const scopedModels = modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];
|
|
440
|
+
const { options: sessionOptions, cliThinkingFromModel, diagnostics: sessionOptionDiagnostics, } = buildSessionOptions(parsed, scopedModels, sessionManager.buildSessionContext().messages.length > 0, modelRegistry, settingsManager);
|
|
441
|
+
diagnostics.push(...sessionOptionDiagnostics);
|
|
442
|
+
if (parsed.apiKey) {
|
|
443
|
+
if (!sessionOptions.model) {
|
|
444
|
+
diagnostics.push({
|
|
445
|
+
type: "error",
|
|
446
|
+
message: "--api-key requires a model to be specified via --model, --provider/--model, or --models",
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const created = await createAgentSessionFromServices({
|
|
454
|
+
services,
|
|
455
|
+
sessionManager,
|
|
456
|
+
sessionStartEvent,
|
|
457
|
+
model: sessionOptions.model,
|
|
458
|
+
thinkingLevel: sessionOptions.thinkingLevel,
|
|
459
|
+
scopedModels: sessionOptions.scopedModels,
|
|
460
|
+
tools: sessionOptions.tools,
|
|
461
|
+
customTools: sessionOptions.customTools,
|
|
462
|
+
});
|
|
463
|
+
const cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;
|
|
464
|
+
if (created.session.model && cliThinkingOverride) {
|
|
465
|
+
let effectiveThinking = created.session.thinkingLevel;
|
|
466
|
+
if (!created.session.model.reasoning) {
|
|
467
|
+
effectiveThinking = "off";
|
|
468
|
+
}
|
|
469
|
+
else if (effectiveThinking === "xhigh" && !supportsXhigh(created.session.model)) {
|
|
470
|
+
effectiveThinking = "high";
|
|
471
|
+
}
|
|
472
|
+
if (effectiveThinking !== created.session.thinkingLevel) {
|
|
473
|
+
created.session.setThinkingLevel(effectiveThinking);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
...created,
|
|
478
|
+
services,
|
|
479
|
+
diagnostics,
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
time("createRuntime");
|
|
483
|
+
const runtime = await createAgentSessionRuntime(createRuntime, {
|
|
484
|
+
cwd: sessionManager.getCwd(),
|
|
485
|
+
agentDir,
|
|
486
|
+
sessionManager,
|
|
487
|
+
});
|
|
488
|
+
const { services, session, modelFallbackMessage } = runtime;
|
|
489
|
+
const { settingsManager, modelRegistry, resourceLoader } = services;
|
|
490
|
+
if (parsed.help) {
|
|
491
|
+
const extensionFlags = resourceLoader
|
|
492
|
+
.getExtensions()
|
|
493
|
+
.extensions.flatMap((extension) => Array.from(extension.flags.values()));
|
|
494
|
+
printHelp(extensionFlags);
|
|
495
|
+
process.exit(0);
|
|
496
|
+
}
|
|
497
|
+
if (parsed.listModels !== undefined) {
|
|
498
|
+
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
|
|
499
|
+
await listModels(modelRegistry, searchPattern);
|
|
500
|
+
process.exit(0);
|
|
501
|
+
}
|
|
502
|
+
// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC
|
|
503
|
+
let stdinContent;
|
|
504
|
+
if (appMode !== "rpc") {
|
|
505
|
+
stdinContent = await readPipedStdin();
|
|
506
|
+
if (stdinContent !== undefined && appMode === "interactive") {
|
|
507
|
+
appMode = "print";
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
time("readPipedStdin");
|
|
645
511
|
const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize(), stdinContent);
|
|
646
512
|
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);
|
|
513
|
+
initTheme(settingsManager.getTheme(), appMode === "interactive");
|
|
655
514
|
time("initTheme");
|
|
656
515
|
// Show deprecation warnings in interactive mode
|
|
657
|
-
if (
|
|
516
|
+
if (appMode === "interactive" && deprecationWarnings.length > 0) {
|
|
658
517
|
await showDeprecationWarnings(deprecationWarnings);
|
|
659
518
|
}
|
|
660
|
-
|
|
661
|
-
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
|
|
662
|
-
if (modelPatterns && modelPatterns.length > 0) {
|
|
663
|
-
scopedModels = await resolveModelScope(modelPatterns, modelRegistry);
|
|
664
|
-
}
|
|
519
|
+
const scopedModels = [...session.scopedModels];
|
|
665
520
|
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);
|
|
521
|
+
reportDiagnostics(runtime.diagnostics);
|
|
522
|
+
if (runtime.diagnostics.some((diagnostic) => diagnostic.type === "error")) {
|
|
523
|
+
process.exit(1);
|
|
694
524
|
}
|
|
695
|
-
const { session, modelFallbackMessage } = await createAgentSession(sessionOptions);
|
|
696
525
|
time("createAgentSession");
|
|
697
|
-
if (
|
|
526
|
+
if (appMode !== "interactive" && !session.model) {
|
|
698
527
|
console.error(chalk.red("No models available."));
|
|
699
528
|
console.error(chalk.yellow("\nSet an API key environment variable:"));
|
|
700
529
|
console.error(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.");
|
|
701
530
|
console.error(chalk.yellow(`\nOr create ${getModelsPath()}`));
|
|
702
531
|
process.exit(1);
|
|
703
532
|
}
|
|
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
|
-
}
|
|
533
|
+
const startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);
|
|
534
|
+
if (startupBenchmark && appMode !== "interactive") {
|
|
535
|
+
console.error(chalk.red("Error: PI_STARTUP_BENCHMARK only supports interactive mode"));
|
|
536
|
+
process.exit(1);
|
|
718
537
|
}
|
|
719
|
-
if (
|
|
538
|
+
if (appMode === "rpc") {
|
|
720
539
|
printTimings();
|
|
721
|
-
await runRpcMode(
|
|
540
|
+
await runRpcMode(runtime);
|
|
722
541
|
}
|
|
723
|
-
else if (
|
|
542
|
+
else if (appMode === "interactive") {
|
|
724
543
|
if (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {
|
|
725
544
|
const modelList = scopedModels
|
|
726
545
|
.map((sm) => {
|
|
@@ -730,7 +549,7 @@ export async function main(args) {
|
|
|
730
549
|
.join(", ");
|
|
731
550
|
console.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray("(Ctrl+P to cycle)")}`));
|
|
732
551
|
}
|
|
733
|
-
const interactiveMode = new InteractiveMode(
|
|
552
|
+
const interactiveMode = new InteractiveMode(runtime, {
|
|
734
553
|
migratedProviders,
|
|
735
554
|
modelFallbackMessage,
|
|
736
555
|
initialMessage,
|
|
@@ -757,8 +576,8 @@ export async function main(args) {
|
|
|
757
576
|
}
|
|
758
577
|
else {
|
|
759
578
|
printTimings();
|
|
760
|
-
const exitCode = await runPrintMode(
|
|
761
|
-
mode,
|
|
579
|
+
const exitCode = await runPrintMode(runtime, {
|
|
580
|
+
mode: toPrintOutputMode(appMode),
|
|
762
581
|
messages: parsed.messages,
|
|
763
582
|
initialMessage,
|
|
764
583
|
initialImages,
|