@oh-my-pi/pi-coding-agent 11.0.3 → 11.2.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 +199 -49
- package/README.md +1 -1
- package/docs/config-usage.md +3 -4
- package/docs/sdk.md +6 -5
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/README.md +1 -1
- package/package.json +19 -11
- package/src/cli/args.ts +11 -94
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/oclif-help.ts +26 -0
- package/src/cli/web-search-cli.ts +148 -0
- package/src/cli.ts +8 -2
- package/src/commands/commit.ts +36 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/grep.ts +41 -0
- package/src/commands/index/index.ts +136 -0
- package/src/commands/jupyter.ts +32 -0
- package/src/commands/plugin.ts +70 -0
- package/src/commands/setup.ts +39 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/web-search.ts +50 -0
- package/src/commit/agentic/index.ts +3 -2
- package/src/commit/agentic/tools/analyze-file.ts +1 -3
- package/src/commit/git/errors.ts +4 -6
- package/src/commit/pipeline.ts +3 -2
- package/src/config/keybindings.ts +1 -3
- package/src/config/model-registry.ts +89 -162
- package/src/config/settings-schema.ts +10 -0
- package/src/config.ts +202 -132
- package/src/exa/mcp-client.ts +8 -41
- package/src/export/html/index.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -10
- package/src/extensibility/extensions/runner.ts +5 -15
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/runner.ts +6 -9
- package/src/index.ts +0 -1
- package/src/ipy/kernel.ts +10 -22
- package/src/lsp/clients/biome-client.ts +4 -7
- package/src/lsp/clients/lsp-linter-client.ts +4 -6
- package/src/lsp/index.ts +5 -4
- package/src/lsp/utils.ts +18 -0
- package/src/main.ts +86 -181
- package/src/mcp/json-rpc.ts +2 -2
- package/src/mcp/transports/http.ts +12 -49
- package/src/modes/components/armin.ts +1 -3
- package/src/modes/components/assistant-message.ts +4 -4
- package/src/modes/components/bash-execution.ts +5 -3
- package/src/modes/components/branch-summary-message.ts +1 -3
- package/src/modes/components/compaction-summary-message.ts +1 -3
- package/src/modes/components/custom-message.ts +4 -5
- package/src/modes/components/extensions/extension-dashboard.ts +10 -16
- package/src/modes/components/extensions/extension-list.ts +5 -5
- package/src/modes/components/footer.ts +1 -4
- package/src/modes/components/hook-editor.ts +7 -32
- package/src/modes/components/hook-message.ts +4 -5
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/plugin-settings.ts +16 -20
- package/src/modes/components/python-execution.ts +5 -5
- package/src/modes/components/session-selector.ts +6 -7
- package/src/modes/components/settings-defs.ts +49 -40
- package/src/modes/components/settings-selector.ts +8 -17
- package/src/modes/components/skill-message.ts +1 -3
- package/src/modes/components/status-line-segment-editor.ts +1 -3
- package/src/modes/components/status-line.ts +1 -3
- package/src/modes/components/todo-reminder.ts +5 -7
- package/src/modes/components/tree-selector.ts +10 -12
- package/src/modes/components/ttsr-notification.ts +1 -3
- package/src/modes/components/user-message-selector.ts +2 -4
- package/src/modes/components/welcome.ts +6 -18
- package/src/modes/controllers/event-controller.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/input-controller.ts +7 -34
- package/src/modes/controllers/selector-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +27 -1
- package/src/modes/rpc/rpc-client.ts +2 -5
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/theme/theme.ts +2 -6
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -1
- package/src/patch/index.ts +1 -4
- package/src/prompts/agents/explore.md +1 -0
- package/src/prompts/agents/frontmatter.md +2 -1
- package/src/prompts/agents/init.md +1 -0
- package/src/prompts/agents/plan.md +1 -0
- package/src/prompts/agents/reviewer.md +1 -0
- package/src/prompts/system/subagent-submit-reminder.md +2 -0
- package/src/prompts/system/subagent-system-prompt.md +2 -0
- package/src/prompts/system/subagent-user-prompt.md +8 -0
- package/src/prompts/system/system-prompt.md +5 -3
- package/src/prompts/system/web-search.md +6 -4
- package/src/prompts/tools/task.md +216 -163
- package/src/sdk.ts +11 -110
- package/src/session/agent-session.ts +117 -83
- package/src/session/auth-storage.ts +10 -51
- package/src/session/messages.ts +17 -3
- package/src/session/session-manager.ts +30 -30
- package/src/session/streaming-output.ts +1 -1
- package/src/ssh/ssh-executor.ts +6 -3
- package/src/task/agents.ts +2 -0
- package/src/task/discovery.ts +1 -1
- package/src/task/executor.ts +5 -10
- package/src/task/index.ts +43 -23
- package/src/task/render.ts +67 -64
- package/src/task/template.ts +17 -34
- package/src/task/types.ts +49 -22
- package/src/tools/ask.ts +1 -3
- package/src/tools/bash.ts +1 -4
- package/src/tools/browser.ts +5 -7
- package/src/tools/exit-plan-mode.ts +1 -4
- package/src/tools/fetch.ts +1 -3
- package/src/tools/find.ts +4 -3
- package/src/tools/gemini-image.ts +24 -55
- package/src/tools/grep.ts +4 -4
- package/src/tools/index.ts +12 -14
- package/src/tools/notebook.ts +1 -5
- package/src/tools/python.ts +4 -3
- package/src/tools/read.ts +2 -4
- package/src/tools/render-utils.ts +23 -0
- package/src/tools/ssh.ts +8 -12
- package/src/tools/todo-write.ts +1 -4
- package/src/tools/tool-errors.ts +1 -4
- package/src/tools/write.ts +1 -3
- package/src/utils/external-editor.ts +59 -0
- package/src/utils/file-mentions.ts +39 -1
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +4 -4
- package/src/web/search/auth.ts +3 -33
- package/src/web/search/index.ts +73 -139
- package/src/web/search/provider.ts +58 -0
- package/src/web/search/providers/anthropic.ts +53 -14
- package/src/web/search/providers/base.ts +22 -0
- package/src/web/search/providers/codex.ts +38 -16
- package/src/web/search/providers/exa.ts +30 -6
- package/src/web/search/providers/gemini.ts +56 -20
- package/src/web/search/providers/jina.ts +28 -5
- package/src/web/search/providers/perplexity.ts +103 -36
- package/src/web/search/render.ts +84 -74
- package/src/web/search/types.ts +285 -59
- package/src/migrations.ts +0 -175
- package/src/session/storage-migration.ts +0 -173
package/src/lsp/index.ts
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
formatLocation,
|
|
51
51
|
formatSymbolInformation,
|
|
52
52
|
formatWorkspaceEdit,
|
|
53
|
+
sortDiagnostics,
|
|
53
54
|
symbolKindToIcon,
|
|
54
55
|
} from "./utils";
|
|
55
56
|
|
|
@@ -458,6 +459,7 @@ async function getDiagnosticsForFile(
|
|
|
458
459
|
}
|
|
459
460
|
}
|
|
460
461
|
|
|
462
|
+
sortDiagnostics(uniqueDiagnostics);
|
|
461
463
|
const formatted = uniqueDiagnostics.map(d => formatDiagnostic(d, relPath));
|
|
462
464
|
const limited = limitDiagnosticMessages(formatted);
|
|
463
465
|
const summary = formatDiagnosticsSummary(uniqueDiagnostics);
|
|
@@ -858,10 +860,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
858
860
|
public readonly mergeCallAndResult = true;
|
|
859
861
|
public readonly inline = true;
|
|
860
862
|
|
|
861
|
-
private readonly session: ToolSession
|
|
862
|
-
|
|
863
|
-
constructor(session: ToolSession) {
|
|
864
|
-
this.session = session;
|
|
863
|
+
constructor(private readonly session: ToolSession) {
|
|
865
864
|
this.description = renderPromptTemplate(lspDescription);
|
|
866
865
|
}
|
|
867
866
|
|
|
@@ -966,6 +965,8 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
966
965
|
}
|
|
967
966
|
}
|
|
968
967
|
|
|
968
|
+
sortDiagnostics(uniqueDiagnostics);
|
|
969
|
+
|
|
969
970
|
if (!detailed && targets.length === 1) {
|
|
970
971
|
if (uniqueDiagnostics.length === 0) {
|
|
971
972
|
return {
|
package/src/lsp/utils.ts
CHANGED
|
@@ -205,6 +205,24 @@ export function severityToString(severity?: DiagnosticSeverity): string {
|
|
|
205
205
|
return SEVERITY_NAMES[severity ?? 1] ?? "unknown";
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Sort diagnostics by severity, then by location and message.
|
|
210
|
+
*/
|
|
211
|
+
export function sortDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] {
|
|
212
|
+
return diagnostics.sort((a, b) => {
|
|
213
|
+
const aSeverity = a.severity ?? 1;
|
|
214
|
+
const bSeverity = b.severity ?? 1;
|
|
215
|
+
if (aSeverity !== bSeverity) return aSeverity - bSeverity;
|
|
216
|
+
const aLine = a.range.start.line;
|
|
217
|
+
const bLine = b.range.start.line;
|
|
218
|
+
if (aLine !== bLine) return aLine - bLine;
|
|
219
|
+
const aCol = a.range.start.character;
|
|
220
|
+
const bCol = b.range.start.character;
|
|
221
|
+
if (aCol !== bCol) return aCol - bCol;
|
|
222
|
+
return a.message.localeCompare(b.message);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
208
226
|
/**
|
|
209
227
|
* Get icon for diagnostic severity.
|
|
210
228
|
*/
|
package/src/main.ts
CHANGED
|
@@ -8,34 +8,24 @@ import * as fs from "node:fs/promises";
|
|
|
8
8
|
import * as os from "node:os";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { createInterface } from "node:readline/promises";
|
|
11
|
+
import { run } from "@oclif/core";
|
|
11
12
|
import { type ImageContent, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
12
13
|
import { $env, postmortem } from "@oh-my-pi/pi-utils";
|
|
13
14
|
import chalk from "chalk";
|
|
14
|
-
import {
|
|
15
|
-
import { parseConfigArgs, printConfigHelp, runConfigCommand } from "./cli/config-cli";
|
|
15
|
+
import type { Args } from "./cli/args";
|
|
16
16
|
import { processFileArguments } from "./cli/file-processor";
|
|
17
|
-
import { parseGrepArgs, printGrepHelp, runGrepCommand } from "./cli/grep-cli";
|
|
18
|
-
import { parseJupyterArgs, printJupyterHelp, runJupyterCommand } from "./cli/jupyter-cli";
|
|
19
17
|
import { listModels } from "./cli/list-models";
|
|
20
|
-
import { parsePluginArgs, printPluginHelp, runPluginCommand } from "./cli/plugin-cli";
|
|
21
18
|
import { selectSession } from "./cli/session-picker";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { parseStatsArgs, printStatsHelp, runStatsCommand } from "./cli/stats-cli";
|
|
25
|
-
import { parseUpdateArgs, printUpdateHelp, runUpdateCommand } from "./cli/update-cli";
|
|
26
|
-
import { runCommitCommand } from "./commit";
|
|
27
|
-
import { parseCommitArgs, printCommitHelp } from "./commit/cli";
|
|
28
|
-
import { findConfigFile, getModelsPath, VERSION } from "./config";
|
|
29
|
-
import type { ModelRegistry } from "./config/model-registry";
|
|
19
|
+
import { findConfigFile, VERSION } from "./config";
|
|
20
|
+
import { ModelRegistry, ModelsConfigFile } from "./config/model-registry";
|
|
30
21
|
import { parseModelPattern, parseModelString, resolveModelScope, type ScopedModel } from "./config/model-resolver";
|
|
31
22
|
import { Settings, settings } from "./config/settings";
|
|
32
23
|
import { initializeWithSettings } from "./discovery";
|
|
33
24
|
import { exportFromFile } from "./export/html";
|
|
34
25
|
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
|
35
|
-
import { runMigrations, showDeprecationWarnings } from "./migrations";
|
|
36
26
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes";
|
|
37
27
|
import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
|
|
38
|
-
import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage
|
|
28
|
+
import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage } from "./sdk";
|
|
39
29
|
import type { AgentSession } from "./session/agent-session";
|
|
40
30
|
import { type SessionInfo, SessionManager } from "./session/session-manager";
|
|
41
31
|
import { resolvePromptInput } from "./system-prompt";
|
|
@@ -82,13 +72,16 @@ async function readPipedInput(): Promise<string | undefined> {
|
|
|
82
72
|
}
|
|
83
73
|
}
|
|
84
74
|
|
|
75
|
+
export interface InteractiveModeNotify {
|
|
76
|
+
kind: "warn" | "error" | "info";
|
|
77
|
+
message: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
85
80
|
async function runInteractiveMode(
|
|
86
81
|
session: AgentSession,
|
|
87
82
|
version: string,
|
|
88
83
|
changelogMarkdown: string | undefined,
|
|
89
|
-
|
|
90
|
-
modelsJsonError: string | undefined,
|
|
91
|
-
migratedProviders: string[],
|
|
84
|
+
notifs: (InteractiveModeNotify | null)[],
|
|
92
85
|
versionCheckPromise: Promise<string | undefined>,
|
|
93
86
|
initialMessages: string[],
|
|
94
87
|
setExtensionUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void,
|
|
@@ -111,16 +104,17 @@ async function runInteractiveMode(
|
|
|
111
104
|
|
|
112
105
|
mode.renderInitialMessages();
|
|
113
106
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
107
|
+
for (const notify of notifs) {
|
|
108
|
+
if (!notify) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (notify.kind === "warn") {
|
|
112
|
+
mode.showWarning(notify.message);
|
|
113
|
+
} else if (notify.kind === "error") {
|
|
114
|
+
mode.showError(notify.message);
|
|
115
|
+
} else if (notify.kind === "info") {
|
|
116
|
+
mode.showStatus(notify.message);
|
|
117
|
+
}
|
|
124
118
|
}
|
|
125
119
|
|
|
126
120
|
if (initialMessage) {
|
|
@@ -477,7 +471,7 @@ async function buildSessionOptions(
|
|
|
477
471
|
return options;
|
|
478
472
|
}
|
|
479
473
|
|
|
480
|
-
export async function
|
|
474
|
+
export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<void> {
|
|
481
475
|
time("start");
|
|
482
476
|
debugStartup("main:entry");
|
|
483
477
|
|
|
@@ -486,140 +480,34 @@ export async function main(args: string[]) {
|
|
|
486
480
|
await initTheme();
|
|
487
481
|
debugStartup("main:initTheme");
|
|
488
482
|
|
|
489
|
-
|
|
490
|
-
const pluginCmd = parsePluginArgs(args);
|
|
491
|
-
if (pluginCmd) {
|
|
492
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
493
|
-
printPluginHelp();
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
await runPluginCommand(pluginCmd);
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Handle update subcommand
|
|
501
|
-
const updateCmd = parseUpdateArgs(args);
|
|
502
|
-
if (updateCmd) {
|
|
503
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
504
|
-
printUpdateHelp();
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
await runUpdateCommand(updateCmd);
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Handle config subcommand
|
|
512
|
-
const configCmd = parseConfigArgs(args);
|
|
513
|
-
if (configCmd) {
|
|
514
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
515
|
-
printConfigHelp();
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
await runConfigCommand(configCmd);
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// Handle setup subcommand
|
|
523
|
-
const setupCmd = parseSetupArgs(args);
|
|
524
|
-
if (setupCmd) {
|
|
525
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
526
|
-
printSetupHelp();
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
await runSetupCommand(setupCmd);
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Handle jupyter subcommand
|
|
534
|
-
const jupyterCmd = parseJupyterArgs(args);
|
|
535
|
-
if (jupyterCmd) {
|
|
536
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
537
|
-
printJupyterHelp();
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
await runJupyterCommand(jupyterCmd);
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Handle stats subcommand
|
|
545
|
-
const statsCmd = parseStatsArgs(args);
|
|
546
|
-
if (statsCmd) {
|
|
547
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
548
|
-
printStatsHelp();
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
await runStatsCommand(statsCmd);
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// Handle grep subcommand (for testing grep tool)
|
|
556
|
-
const grepCmd = parseGrepArgs(args);
|
|
557
|
-
if (grepCmd) {
|
|
558
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
559
|
-
printGrepHelp();
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
await runGrepCommand(grepCmd);
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Handle shell subcommand (for testing brush-core shell)
|
|
567
|
-
const shellCmd = parseShellArgs(args);
|
|
568
|
-
if (shellCmd) {
|
|
569
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
570
|
-
printShellHelp();
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
await runShellCommand(shellCmd);
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Handle commit subcommand
|
|
578
|
-
const commitCmd = parseCommitArgs(args);
|
|
579
|
-
if (commitCmd) {
|
|
580
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
581
|
-
printCommitHelp();
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
await runCommitCommand(commitCmd);
|
|
585
|
-
process.exit(0);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
const parsed = parseArgs(args);
|
|
483
|
+
const parsedArgs = parsed;
|
|
589
484
|
debugStartup("main:parseArgs");
|
|
590
485
|
time("parseArgs");
|
|
591
|
-
await maybeAutoChdir(
|
|
486
|
+
await maybeAutoChdir(parsedArgs);
|
|
592
487
|
|
|
593
|
-
|
|
594
|
-
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = await runMigrations(process.cwd());
|
|
595
|
-
debugStartup("main:runMigrations");
|
|
488
|
+
const notifs: (InteractiveModeNotify | null)[] = [];
|
|
596
489
|
|
|
597
490
|
// Create AuthStorage and ModelRegistry upfront
|
|
598
491
|
const authStorage = await discoverAuthStorage();
|
|
599
|
-
const modelRegistry =
|
|
492
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
600
493
|
debugStartup("main:discoverModels");
|
|
601
494
|
time("discoverModels");
|
|
602
495
|
|
|
603
|
-
if (
|
|
496
|
+
if (parsedArgs.version) {
|
|
604
497
|
writeStdout(VERSION);
|
|
605
498
|
return;
|
|
606
499
|
}
|
|
607
500
|
|
|
608
|
-
if (
|
|
609
|
-
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (parsed.listModels !== undefined) {
|
|
614
|
-
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
|
|
501
|
+
if (parsedArgs.listModels !== undefined) {
|
|
502
|
+
const searchPattern = typeof parsedArgs.listModels === "string" ? parsedArgs.listModels : undefined;
|
|
615
503
|
await listModels(modelRegistry, searchPattern);
|
|
616
504
|
return;
|
|
617
505
|
}
|
|
618
506
|
|
|
619
|
-
if (
|
|
507
|
+
if (parsedArgs.export) {
|
|
620
508
|
try {
|
|
621
|
-
const outputPath =
|
|
622
|
-
const result = await exportFromFile(
|
|
509
|
+
const outputPath = parsedArgs.messages.length > 0 ? parsedArgs.messages[0] : undefined;
|
|
510
|
+
const result = await exportFromFile(parsedArgs.export, outputPath);
|
|
623
511
|
writeStdout(`Exported to: ${result}`);
|
|
624
512
|
return;
|
|
625
513
|
} catch (error: unknown) {
|
|
@@ -629,7 +517,7 @@ export async function main(args: string[]) {
|
|
|
629
517
|
}
|
|
630
518
|
}
|
|
631
519
|
|
|
632
|
-
if (
|
|
520
|
+
if (parsedArgs.mode === "rpc" && parsedArgs.fileArgs.length > 0) {
|
|
633
521
|
writeStderr(chalk.red("Error: @file arguments are not supported in RPC mode"));
|
|
634
522
|
process.exit(1);
|
|
635
523
|
}
|
|
@@ -639,23 +527,23 @@ export async function main(args: string[]) {
|
|
|
639
527
|
debugStartup("main:Settings.init");
|
|
640
528
|
time("Settings.init");
|
|
641
529
|
const pipedInput = await readPipedInput();
|
|
642
|
-
let { initialMessage, initialImages } = await prepareInitialMessage(
|
|
530
|
+
let { initialMessage, initialImages } = await prepareInitialMessage(parsedArgs, settings.get("images.autoResize"));
|
|
643
531
|
if (pipedInput) {
|
|
644
532
|
initialMessage = initialMessage ? `${initialMessage}\n${pipedInput}` : pipedInput;
|
|
645
533
|
}
|
|
646
534
|
time("prepareInitialMessage");
|
|
647
|
-
const autoPrint = pipedInput !== undefined && !
|
|
648
|
-
const isInteractive = !
|
|
649
|
-
const mode =
|
|
535
|
+
const autoPrint = pipedInput !== undefined && !parsedArgs.print && parsedArgs.mode === undefined;
|
|
536
|
+
const isInteractive = !parsedArgs.print && !autoPrint && parsedArgs.mode === undefined;
|
|
537
|
+
const mode = parsedArgs.mode || "text";
|
|
650
538
|
|
|
651
539
|
// Initialize discovery system with settings for provider persistence
|
|
652
540
|
initializeWithSettings(settings);
|
|
653
541
|
time("initializeWithSettings");
|
|
654
542
|
|
|
655
543
|
// Apply model role overrides from CLI args or env vars (ephemeral, not persisted)
|
|
656
|
-
const smolModel =
|
|
657
|
-
const slowModel =
|
|
658
|
-
const planModel =
|
|
544
|
+
const smolModel = parsedArgs.smol ?? $env.PI_SMOL_MODEL;
|
|
545
|
+
const slowModel = parsedArgs.slow ?? $env.PI_SLOW_MODEL;
|
|
546
|
+
const planModel = parsedArgs.plan ?? $env.PI_PLAN_MODEL;
|
|
659
547
|
if (smolModel || slowModel || planModel) {
|
|
660
548
|
settings.overrideModelRoles({
|
|
661
549
|
smol: smolModel,
|
|
@@ -668,13 +556,8 @@ export async function main(args: string[]) {
|
|
|
668
556
|
debugStartup("main:initTheme2");
|
|
669
557
|
time("initTheme");
|
|
670
558
|
|
|
671
|
-
// Show deprecation warnings in interactive mode
|
|
672
|
-
if (isInteractive && deprecationWarnings.length > 0) {
|
|
673
|
-
await showDeprecationWarnings(deprecationWarnings);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
559
|
let scopedModels: ScopedModel[] = [];
|
|
677
|
-
const modelPatterns =
|
|
560
|
+
const modelPatterns = parsedArgs.models ?? settings.get("enabledModels");
|
|
678
561
|
const modelMatchPreferences = {
|
|
679
562
|
usageOrder: settings.getStorage()?.getModelUsageOrder(),
|
|
680
563
|
};
|
|
@@ -684,13 +567,13 @@ export async function main(args: string[]) {
|
|
|
684
567
|
}
|
|
685
568
|
|
|
686
569
|
// Create session manager based on CLI flags
|
|
687
|
-
let sessionManager = await createSessionManager(
|
|
570
|
+
let sessionManager = await createSessionManager(parsedArgs, cwd);
|
|
688
571
|
debugStartup("main:createSessionManager");
|
|
689
572
|
time("createSessionManager");
|
|
690
573
|
|
|
691
574
|
// Handle --resume: show session picker
|
|
692
|
-
if (
|
|
693
|
-
const sessions = await SessionManager.list(cwd,
|
|
575
|
+
if (parsedArgs.resume) {
|
|
576
|
+
const sessions = await SessionManager.list(cwd, parsedArgs.sessionDir);
|
|
694
577
|
time("SessionManager.list");
|
|
695
578
|
if (sessions.length === 0) {
|
|
696
579
|
writeStdout(chalk.dim("No sessions found"));
|
|
@@ -705,19 +588,19 @@ export async function main(args: string[]) {
|
|
|
705
588
|
sessionManager = await SessionManager.open(selectedPath);
|
|
706
589
|
}
|
|
707
590
|
|
|
708
|
-
const sessionOptions = await buildSessionOptions(
|
|
591
|
+
const sessionOptions = await buildSessionOptions(parsedArgs, scopedModels, sessionManager, modelRegistry);
|
|
709
592
|
debugStartup("main:buildSessionOptions");
|
|
710
593
|
sessionOptions.authStorage = authStorage;
|
|
711
594
|
sessionOptions.modelRegistry = modelRegistry;
|
|
712
595
|
sessionOptions.hasUI = isInteractive;
|
|
713
596
|
|
|
714
597
|
// Handle CLI --api-key as runtime override (not persisted)
|
|
715
|
-
if (
|
|
598
|
+
if (parsedArgs.apiKey) {
|
|
716
599
|
if (!sessionOptions.model) {
|
|
717
600
|
writeStderr(chalk.red("--api-key requires a model to be specified via --provider/--model or -m/--models"));
|
|
718
601
|
process.exit(1);
|
|
719
602
|
}
|
|
720
|
-
authStorage.setRuntimeApiKey(sessionOptions.model.provider,
|
|
603
|
+
authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsedArgs.apiKey);
|
|
721
604
|
}
|
|
722
605
|
|
|
723
606
|
time("buildSessionOptions");
|
|
@@ -726,17 +609,36 @@ export async function main(args: string[]) {
|
|
|
726
609
|
debugStartup("main:createAgentSession");
|
|
727
610
|
time("createAgentSession");
|
|
728
611
|
|
|
612
|
+
if (modelFallbackMessage) {
|
|
613
|
+
notifs.push({ kind: "warn", message: modelFallbackMessage });
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const modelRegistryError = modelRegistry.getError();
|
|
617
|
+
if (modelRegistryError) {
|
|
618
|
+
notifs.push({ kind: "error", message: modelRegistryError.message });
|
|
619
|
+
}
|
|
620
|
+
|
|
729
621
|
// Re-parse CLI args with extension flags and apply values
|
|
730
622
|
if (session.extensionRunner) {
|
|
731
623
|
const extFlags = session.extensionRunner.getFlags();
|
|
732
624
|
if (extFlags.size > 0) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
625
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
626
|
+
const arg = rawArgs[i];
|
|
627
|
+
if (!arg.startsWith("--")) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
const flagName = arg.slice(2);
|
|
631
|
+
const extFlag = extFlags.get(flagName);
|
|
632
|
+
if (!extFlag) {
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
if (extFlag.type === "boolean") {
|
|
636
|
+
session.extensionRunner.setFlagValue(flagName, true);
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (i + 1 < rawArgs.length) {
|
|
640
|
+
session.extensionRunner.setFlagValue(flagName, rawArgs[++i]);
|
|
641
|
+
}
|
|
740
642
|
}
|
|
741
643
|
}
|
|
742
644
|
}
|
|
@@ -747,13 +649,13 @@ export async function main(args: string[]) {
|
|
|
747
649
|
writeStderr(chalk.red("No models available."));
|
|
748
650
|
writeStderr(chalk.yellow("\nSet an API key environment variable:"));
|
|
749
651
|
writeStderr(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.");
|
|
750
|
-
writeStderr(chalk.yellow(`\nOr create ${
|
|
652
|
+
writeStderr(chalk.yellow(`\nOr create ${ModelsConfigFile.path()}`));
|
|
751
653
|
process.exit(1);
|
|
752
654
|
}
|
|
753
655
|
|
|
754
656
|
// Clamp thinking level to model capabilities (for CLI override case)
|
|
755
|
-
if (session.model &&
|
|
756
|
-
let effectiveThinking =
|
|
657
|
+
if (session.model && parsedArgs.thinking) {
|
|
658
|
+
let effectiveThinking = parsedArgs.thinking;
|
|
757
659
|
if (!session.model.reasoning) {
|
|
758
660
|
effectiveThinking = "off";
|
|
759
661
|
} else if (effectiveThinking === "xhigh" && !supportsXhigh(session.model)) {
|
|
@@ -768,7 +670,7 @@ export async function main(args: string[]) {
|
|
|
768
670
|
await runRpcMode(session);
|
|
769
671
|
} else if (isInteractive) {
|
|
770
672
|
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
|
|
771
|
-
const changelogMarkdown = await getChangelogForDisplay(
|
|
673
|
+
const changelogMarkdown = await getChangelogForDisplay(parsedArgs);
|
|
772
674
|
|
|
773
675
|
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
|
|
774
676
|
if (scopedModelsForDisplay.length > 0) {
|
|
@@ -787,11 +689,9 @@ export async function main(args: string[]) {
|
|
|
787
689
|
session,
|
|
788
690
|
VERSION,
|
|
789
691
|
changelogMarkdown,
|
|
790
|
-
|
|
791
|
-
modelRegistry.getError(),
|
|
792
|
-
migratedProviders,
|
|
692
|
+
notifs,
|
|
793
693
|
versionCheckPromise,
|
|
794
|
-
|
|
694
|
+
parsedArgs.messages,
|
|
795
695
|
setToolUIContext,
|
|
796
696
|
lspServers,
|
|
797
697
|
mcpManager,
|
|
@@ -801,7 +701,7 @@ export async function main(args: string[]) {
|
|
|
801
701
|
} else {
|
|
802
702
|
await runPrintMode(session, {
|
|
803
703
|
mode,
|
|
804
|
-
messages:
|
|
704
|
+
messages: parsedArgs.messages,
|
|
805
705
|
initialMessage,
|
|
806
706
|
initialImages,
|
|
807
707
|
});
|
|
@@ -810,3 +710,8 @@ export async function main(args: string[]) {
|
|
|
810
710
|
await postmortem.quit(0);
|
|
811
711
|
}
|
|
812
712
|
}
|
|
713
|
+
|
|
714
|
+
export async function main(args: string[]): Promise<void> {
|
|
715
|
+
const argv = args.length === 0 ? ["index"] : args;
|
|
716
|
+
await run(argv, import.meta.url);
|
|
717
|
+
}
|
package/src/mcp/json-rpc.ts
CHANGED
|
@@ -13,8 +13,8 @@ export function parseSSE(text: string): unknown {
|
|
|
13
13
|
if (line.startsWith("data: ")) {
|
|
14
14
|
const data = line.slice(6).trim();
|
|
15
15
|
if (data === "[DONE]") continue;
|
|
16
|
-
const result =
|
|
17
|
-
if (result
|
|
16
|
+
const result = JSON.parse(data) as unknown;
|
|
17
|
+
if (result) return result;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
// Fallback: try parsing entire response as JSON
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements JSON-RPC 2.0 over HTTP POST with optional SSE streaming.
|
|
5
5
|
* Based on MCP spec 2025-03-26.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { readSseJson } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import type {
|
|
9
9
|
JsonRpcMessage,
|
|
10
10
|
JsonRpcResponse,
|
|
@@ -86,26 +86,11 @@ export class HttpTransport implements MCPTransport {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
let buffer = "";
|
|
90
89
|
// Read SSE stream
|
|
91
|
-
for await (const
|
|
90
|
+
for await (const message of readSseJson<JsonRpcMessage>(response.body, this.sseConnection.signal)) {
|
|
92
91
|
if (!this._connected) break;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
buffer += data;
|
|
96
|
-
if (!data.endsWith("\n")) {
|
|
97
|
-
buffer += "\n";
|
|
98
|
-
}
|
|
99
|
-
const result = Bun.JSONL.parseChunk(buffer);
|
|
100
|
-
buffer = buffer.slice(result.read);
|
|
101
|
-
if (result.error) {
|
|
102
|
-
buffer = "";
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
for (const message of result.values as JsonRpcMessage[]) {
|
|
106
|
-
if ("method" in message && !("id" in message)) {
|
|
107
|
-
this.onNotification?.(message.method, message.params);
|
|
108
|
-
}
|
|
92
|
+
if ("method" in message && !("id" in message)) {
|
|
93
|
+
this.onNotification?.(message.method, message.params);
|
|
109
94
|
}
|
|
110
95
|
}
|
|
111
96
|
} catch (error) {
|
|
@@ -182,40 +167,18 @@ export class HttpTransport implements MCPTransport {
|
|
|
182
167
|
const timeout = this.config.timeout ?? 30000;
|
|
183
168
|
|
|
184
169
|
const parse = async (): Promise<T> => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
buffer += data;
|
|
190
|
-
if (!data.endsWith("\n")) {
|
|
191
|
-
buffer += "\n";
|
|
192
|
-
}
|
|
193
|
-
const result = Bun.JSONL.parseChunk(buffer);
|
|
194
|
-
buffer = buffer.slice(result.read);
|
|
195
|
-
if (result.error) {
|
|
196
|
-
buffer = "";
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
for (const message of result.values as JsonRpcMessage[]) {
|
|
201
|
-
if (
|
|
202
|
-
"id" in message &&
|
|
203
|
-
(message as JsonRpcResponse).id === expectedId &&
|
|
204
|
-
("result" in message || "error" in message)
|
|
205
|
-
) {
|
|
206
|
-
const response = message as JsonRpcResponse;
|
|
207
|
-
if (response.error) {
|
|
208
|
-
throw new Error(`MCP error ${response.error.code}: ${response.error.message}`);
|
|
209
|
-
}
|
|
210
|
-
return response.result as T;
|
|
170
|
+
for await (const message of readSseJson<JsonRpcMessage>(response.body!)) {
|
|
171
|
+
if ("id" in message && message.id === expectedId && ("result" in message || "error" in message)) {
|
|
172
|
+
if (message.error) {
|
|
173
|
+
throw new Error(`MCP error ${message.error.code}: ${message.error.message}`);
|
|
211
174
|
}
|
|
175
|
+
return message.result as T;
|
|
176
|
+
}
|
|
212
177
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
178
|
+
if ("method" in message && !("id" in message)) {
|
|
179
|
+
this.onNotification?.(message.method, message.params);
|
|
216
180
|
}
|
|
217
181
|
}
|
|
218
|
-
|
|
219
182
|
throw new Error(`No response received for request ID ${expectedId}`);
|
|
220
183
|
};
|
|
221
184
|
|
|
@@ -57,7 +57,6 @@ function buildFinalGrid(): string[][] {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export class ArminComponent implements Component {
|
|
60
|
-
private ui: TUI;
|
|
61
60
|
private interval: ReturnType<typeof setInterval> | null = null;
|
|
62
61
|
private effect: Effect;
|
|
63
62
|
private finalGrid: string[][];
|
|
@@ -68,8 +67,7 @@ export class ArminComponent implements Component {
|
|
|
68
67
|
private gridVersion = 0;
|
|
69
68
|
private cachedVersion = -1;
|
|
70
69
|
|
|
71
|
-
constructor(ui: TUI) {
|
|
72
|
-
this.ui = ui;
|
|
70
|
+
constructor(private readonly ui: TUI) {
|
|
73
71
|
this.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];
|
|
74
72
|
this.finalGrid = buildFinalGrid();
|
|
75
73
|
this.currentGrid = this.createEmptyGrid();
|
|
@@ -8,15 +8,15 @@ import { getMarkdownTheme, theme } from "../../modes/theme/theme";
|
|
|
8
8
|
*/
|
|
9
9
|
export class AssistantMessageComponent extends Container {
|
|
10
10
|
private contentContainer: Container;
|
|
11
|
-
private hideThinkingBlock: boolean;
|
|
12
11
|
private lastMessage?: AssistantMessage;
|
|
13
12
|
private prerenderInFlight = false;
|
|
14
13
|
|
|
15
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
message?: AssistantMessage,
|
|
16
|
+
private hideThinkingBlock = false,
|
|
17
|
+
) {
|
|
16
18
|
super();
|
|
17
19
|
|
|
18
|
-
this.hideThinkingBlock = hideThinkingBlock;
|
|
19
|
-
|
|
20
20
|
// Container for text/thinking content
|
|
21
21
|
this.contentContainer = new Container();
|
|
22
22
|
this.addChild(this.contentContainer);
|
|
@@ -12,7 +12,6 @@ import { truncateToVisualLines } from "./visual-truncate";
|
|
|
12
12
|
const PREVIEW_LINES = 20;
|
|
13
13
|
|
|
14
14
|
export class BashExecutionComponent extends Container {
|
|
15
|
-
private command: string;
|
|
16
15
|
private outputLines: string[] = [];
|
|
17
16
|
private status: "running" | "complete" | "cancelled" | "error" = "running";
|
|
18
17
|
private exitCode: number | undefined = undefined;
|
|
@@ -21,9 +20,12 @@ export class BashExecutionComponent extends Container {
|
|
|
21
20
|
private expanded = false;
|
|
22
21
|
private contentContainer: Container;
|
|
23
22
|
|
|
24
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
private readonly command: string,
|
|
25
|
+
ui: TUI,
|
|
26
|
+
excludeFromContext = false,
|
|
27
|
+
) {
|
|
25
28
|
super();
|
|
26
|
-
this.command = command;
|
|
27
29
|
|
|
28
30
|
// Use dim border for excluded-from-context commands (!! prefix)
|
|
29
31
|
const colorKey = excludeFromContext ? "dim" : "bashMode";
|
|
@@ -8,11 +8,9 @@ import type { BranchSummaryMessage } from "../../session/messages";
|
|
|
8
8
|
*/
|
|
9
9
|
export class BranchSummaryMessageComponent extends Box {
|
|
10
10
|
private expanded = false;
|
|
11
|
-
private message: BranchSummaryMessage;
|
|
12
11
|
|
|
13
|
-
constructor(message: BranchSummaryMessage) {
|
|
12
|
+
constructor(private readonly message: BranchSummaryMessage) {
|
|
14
13
|
super(1, 1, t => theme.bg("customMessageBg", t));
|
|
15
|
-
this.message = message;
|
|
16
14
|
this.updateDisplay();
|
|
17
15
|
}
|
|
18
16
|
|