@earendil-works/pi-coding-agent 0.99.1 → 1.0.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 +86 -0
- package/dist/bundle/chunks/anthropic-messages-UID2PALB.js +6 -0
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/{azure-openai-responses-EN5WOBET.js → azure-openai-responses-AFMVM6NP.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-AXPY26X7.js → chunk-2KTBZM5G.js} +14 -28
- package/dist/bundle/chunks/{chunk-LRS5S6EK.js → chunk-2VNGUWBO.js} +2 -2
- package/dist/bundle/chunks/chunk-33XOIQ5N.js +1204 -0
- package/dist/bundle/chunks/{chunk-W2DOMZSC.js → chunk-3LH3ZQKY.js} +1 -1
- package/dist/bundle/chunks/chunk-4KU537KD.js +2 -0
- package/dist/bundle/chunks/chunk-6D7LHLKG.js +2 -0
- package/dist/bundle/chunks/chunk-7FH3BDRG.js +82 -0
- package/dist/bundle/chunks/{chunk-LLMKQWZS.js → chunk-IBCPYVFK.js} +7 -9
- package/dist/bundle/chunks/chunk-KDN6RCEQ.js +4 -0
- package/dist/bundle/chunks/chunk-LD2P6SFZ.js +2 -0
- package/dist/bundle/chunks/{chunk-PEHWOV5U.js → chunk-LTXEMVMA.js} +18 -78
- package/dist/bundle/chunks/{chunk-J4CWPC4N.js → chunk-OSKPX3Z5.js} +1 -1
- package/dist/bundle/chunks/chunk-PRD6WYBT.js +16 -0
- package/dist/bundle/chunks/chunk-VIV3CWXG.js +2 -0
- package/dist/bundle/chunks/{cli-AZXNGIZH.js → cli-QOMC26IJ.js} +8 -6
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XJQQYGGU.js → cloudflare-workers-ai-system-one-NPQN263E.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +67 -8
- package/dist/bundle/chunks/execute-GVRSEGHL.js +367 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-CQAKKJTA.js → google-generative-ai-APTPZOQL.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-AE36YXJU.js → google-vertex-MXCOSOY3.js} +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-PJJYKPLD.js → llama-cpp-classify-XT44PI3C.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-KEYTXJM7.js → mistral-conversations-DKVFNQL6.js} +1 -1
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-JQTCOVEG.js → openai-codex-responses-GK67DQQJ.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-XW2Q5HVC.js → openai-completions-JXDDPZ23.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-6AXWFL75.js → openai-responses-CQDDLDQF.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-TPQ4V6OR.js → openrouter-images-ZVXWCSIM.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/pi-logo-animation-MPKZE4EK.js +2 -0
- package/dist/bundle/chunks/radius.js +1 -1
- package/dist/bundle/chunks/runtime-2SO2JDWM.js +2 -0
- package/dist/bundle/chunks/{typesafe-system-one-E7A4HNJI.js → typesafe-system-one-A4CZTQWZ.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-6ZMK7GDO.js +2 -0
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +5 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -13
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +15 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +51 -10
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +13 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/mcp-servers.d.ts +34 -7
- package/dist/core/mcp-servers.d.ts.map +1 -1
- package/dist/core/mcp-servers.js +52 -11
- package/dist/core/mcp-servers.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +4 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +6 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +22 -18
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +2 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +4 -9
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +11 -31
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/virtual-models.d.ts +2 -0
- package/dist/core/virtual-models.d.ts.map +1 -1
- package/dist/core/virtual-models.js +19 -12
- package/dist/core/virtual-models.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +197 -51
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/renderer.d.ts.map +1 -1
- package/dist/extensions/codemode/renderer.js +43 -25
- package/dist/extensions/codemode/renderer.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +12 -11
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +73 -129
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/codemode/worker.d.ts +1 -1
- package/dist/extensions/codemode/worker.js +1 -1
- package/dist/extensions/codemode/worker.js.map +1 -1
- package/dist/extensions/mcp/cli.d.ts.map +1 -1
- package/dist/extensions/mcp/cli.js +20 -5
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/config.d.ts +4 -2
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +14 -2
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts +32 -8
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +220 -56
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +10 -7
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +56 -31
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts +2 -0
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +16 -9
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +5 -4
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +33 -15
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +4 -2
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +5 -4
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +7 -28
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +24 -21
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/pi-logo-animation.d.ts +68 -0
- package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.js +1086 -0
- package/dist/modes/interactive/components/pi-logo-animation.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js +12 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -1
- package/dist/modes/interactive/components/pi-logo.js +13 -1
- package/dist/modes/interactive/components/pi-logo.js.map +1 -1
- package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
- package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/radius-login-selector.js +85 -0
- package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -3
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -5
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +5 -4
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +39 -6
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +153 -40
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/system-theme.d.ts +2 -1
- package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/system-theme.js +16 -5
- package/dist/modes/interactive/theme/system-theme.js.map +1 -1
- package/docs/cli.md +8 -18
- package/docs/codemode.md +207 -0
- package/docs/docs.json +5 -1
- package/docs/environment-variables.md +2 -2
- package/docs/extensions.md +3 -3
- package/docs/index.md +1 -1
- package/docs/mcp.md +142 -82
- package/docs/models.md +22 -1
- package/docs/providers.md +18 -6
- package/docs/sdk.md +2 -2
- package/docs/settings.md +5 -3
- package/docs/usage.md +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +16 -40
- 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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/minimal-mode.ts +24 -96
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/14-codemode-mcp.ts +2 -2
- package/npm-shrinkwrap.json +25 -30
- package/package.json +10 -10
- package/dist/bundle/chunks/anthropic-messages-A6EXUBG6.js +0 -6
- package/dist/bundle/chunks/chunk-GOPCREV2.js +0 -4
- package/dist/bundle/chunks/chunk-GUORCHFS.js +0 -1435
- package/dist/bundle/chunks/chunk-HSPCVFST.js +0 -2
- package/dist/bundle/chunks/chunk-IMTXZUO7.js +0 -82
- package/dist/bundle/chunks/chunk-SLDA2X2H.js +0 -2
- package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
- package/dist/bundle/chunks/execute-7XXPZAWW.js +0 -308
- package/dist/bundle/chunks/runtime-G5WJPRBM.js +0 -2
- package/dist/bundle/chunks/virtual-modules-CSWRO37N.js +0 -2
|
@@ -25,6 +25,7 @@ import { createCompactionSummaryMessage, createCustomMessage } from "../../core/
|
|
|
25
25
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScopeFromModels, } from "../../core/model-resolver.js";
|
|
26
26
|
import { CredentialSynchronizationError } from "../../core/model-runtime.js";
|
|
27
27
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
28
|
+
import { RADIUS_MCP_URL, RADIUS_PROVIDER_ID } from "../../core/radius.js";
|
|
28
29
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
29
30
|
import { SessionManager, sessionEntryToContextMessages, } from "../../core/session-manager.js";
|
|
30
31
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
@@ -32,6 +33,7 @@ import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
|
32
33
|
import { withBuiltInRenderers } from "../../core/tools/renderers/index.js";
|
|
33
34
|
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
34
35
|
import { getUsageCostBreakdown } from "../../core/usage-totals.js";
|
|
36
|
+
import { addMcpServerConfig, loadMcpConfig } from "../../extensions/mcp/config.js";
|
|
35
37
|
import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
|
|
36
38
|
import { copyToClipboard, readClipboardFilePaths, readClipboardText } from "../../utils/clipboard.js";
|
|
37
39
|
import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
|
|
@@ -63,8 +65,10 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
|
|
|
63
65
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
64
66
|
import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
|
|
65
67
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
66
|
-
import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
67
|
-
import { piLogoLines } from "./components/pi-logo.js";
|
|
68
|
+
import { formatAuthSelectorProviderStatus, formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
69
|
+
import { piLogoLines, piWordmark, supportsPiLogo } from "./components/pi-logo.js";
|
|
70
|
+
import { playPiLogoAnimation } from "./components/pi-logo-animation.lazy.js";
|
|
71
|
+
import { createLoginMenuSelector } from "./components/radius-login-selector.js";
|
|
68
72
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
69
73
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
70
74
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
@@ -106,6 +110,16 @@ class ExpandableText extends ThemedText {
|
|
|
106
110
|
this.invalidate();
|
|
107
111
|
}
|
|
108
112
|
}
|
|
113
|
+
/** The built-in header. Clicking its logo (the first two lines, after one column of padding) plays an easter egg. */
|
|
114
|
+
class BuiltInHeader extends ExpandableText {
|
|
115
|
+
onLogoClick;
|
|
116
|
+
handleMouse(event) {
|
|
117
|
+
if (event.type !== "click" || event.y > 1 || event.x < 1 || event.x > 4 || !this.onLogoClick)
|
|
118
|
+
return undefined;
|
|
119
|
+
this.onLogoClick(event.screenX - event.x + 1, event.screenY - event.y);
|
|
120
|
+
return { handled: true };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
109
123
|
function isCustomSessionEntry(item) {
|
|
110
124
|
return "type" in item && item.type === "custom";
|
|
111
125
|
}
|
|
@@ -175,6 +189,7 @@ function llamaCppPostLoginGuidance(actionLabel, loadedModelCount) {
|
|
|
175
189
|
? `${actionLabel}. No llama.cpp models are loaded. Use /llama to load a model, then /model to select it.`
|
|
176
190
|
: `${actionLabel}. Use /model to select a loaded llama.cpp model, or /llama to manage models.`;
|
|
177
191
|
}
|
|
192
|
+
const RADIUS_LOGIN_INTRO = "Radius is a service crafted for Pi by the builders of Pi, Earendil Works";
|
|
178
193
|
const AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };
|
|
179
194
|
function createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {
|
|
180
195
|
const filtered = fuzzyFilter(items, prefix, getSearchText);
|
|
@@ -197,18 +212,21 @@ function getLoginProviderCompletionOptions(providerOptions) {
|
|
|
197
212
|
id: provider.id,
|
|
198
213
|
name: provider.name,
|
|
199
214
|
authTypes: [provider.authType],
|
|
215
|
+
subscription: provider.subscription,
|
|
200
216
|
});
|
|
201
217
|
}
|
|
202
218
|
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
203
219
|
}
|
|
204
220
|
function getLoginProviderSearchText(provider) {
|
|
205
221
|
const authTypes = provider.authTypes
|
|
206
|
-
.map((authType) => `${authType} ${formatAuthSelectorProviderType(authType)}`)
|
|
222
|
+
.map((authType) => `${authType} ${formatAuthSelectorProviderType(authType, provider.subscription)}`)
|
|
207
223
|
.join(" ");
|
|
208
224
|
return `${provider.id} ${provider.name} ${authTypes}`;
|
|
209
225
|
}
|
|
210
226
|
function formatLoginProviderCompletionDescription(provider) {
|
|
211
|
-
const authTypes = provider.authTypes
|
|
227
|
+
const authTypes = provider.authTypes
|
|
228
|
+
.map((authType) => formatAuthSelectorProviderType(authType, provider.subscription))
|
|
229
|
+
.join("/");
|
|
212
230
|
return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
|
|
213
231
|
}
|
|
214
232
|
export class InteractiveMode {
|
|
@@ -635,7 +653,7 @@ export class InteractiveMode {
|
|
|
635
653
|
this.registerSignalHandlers();
|
|
636
654
|
// Load changelog (only show new entries, skip for resumed sessions)
|
|
637
655
|
this.changelogMarkdown = this.getChangelogForDisplay();
|
|
638
|
-
if (this.session.scopedModels.length > 0 &&
|
|
656
|
+
if (this.session.scopedModels.length > 0 && this.shouldShowStartupDetails()) {
|
|
639
657
|
const modelList = this.session.scopedModels
|
|
640
658
|
.map((sm) => {
|
|
641
659
|
const thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : "";
|
|
@@ -686,10 +704,15 @@ export class InteractiveMode {
|
|
|
686
704
|
// reported its colors. This ends at the terminal's DA1 reply, or after 100 ms if it answers nothing.
|
|
687
705
|
await this.themeController.waitForTerminalColors();
|
|
688
706
|
// Add header with keybindings from config (unless silenced)
|
|
689
|
-
if (this.
|
|
707
|
+
if (this.shouldShowStartupHeader()) {
|
|
708
|
+
const showDetails = this.shouldShowStartupDetails();
|
|
690
709
|
// Built on demand so the header follows theme changes. The logo's first line carries the version,
|
|
691
|
-
// its second line the first line of key hints.
|
|
710
|
+
// its second line the first line of key hints. Terminals that cannot render the logo get a
|
|
711
|
+
// "Pi vX" line instead, with the key hints below it.
|
|
712
|
+
const showLogo = supportsPiLogo();
|
|
692
713
|
const withLogo = (hints) => {
|
|
714
|
+
if (!showLogo)
|
|
715
|
+
return `${piWordmark()} ${theme.fg("dim", `v${this.version}`)}\n${hints}`;
|
|
693
716
|
const [top, bottom] = piLogoLines();
|
|
694
717
|
return `${top} ${theme.fg("dim", `v${this.version}`)}\n${bottom} ${hints}`;
|
|
695
718
|
};
|
|
@@ -723,9 +746,12 @@ export class InteractiveMode {
|
|
|
723
746
|
rawKeyHint("!", "bash"),
|
|
724
747
|
hint("app.tools.expand", "more"),
|
|
725
748
|
].join(theme.fg("muted", " · "));
|
|
726
|
-
const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
|
|
749
|
+
const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help${showDetails ? " and loaded resources" : ""}.`);
|
|
727
750
|
const onboarding = () => theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
|
|
728
|
-
|
|
751
|
+
const header = new BuiltInHeader(() => `${withLogo(compactInstructions())}\n${compactOnboarding()}\n\n${onboarding()}`, () => `${withLogo(expandedInstructions())}\n\n${onboarding()}`, this.getStartupExpansionState(), 1, 0);
|
|
752
|
+
if (showLogo)
|
|
753
|
+
header.onLogoClick = (column, row) => playPiLogoAnimation(this.renderer, column, row);
|
|
754
|
+
this.builtInHeader = header;
|
|
729
755
|
// Setup UI layout
|
|
730
756
|
this.headerContainer.addChild(new Spacer(1));
|
|
731
757
|
this.headerContainer.addChild(this.builtInHeader);
|
|
@@ -1024,6 +1050,14 @@ export class InteractiveMode {
|
|
|
1024
1050
|
getStartupExpansionState() {
|
|
1025
1051
|
return this.options.verbose || this.toolOutputExpanded;
|
|
1026
1052
|
}
|
|
1053
|
+
/** Startup header (logo, version, key hints). Hidden only by quietStartup: true. */
|
|
1054
|
+
shouldShowStartupHeader() {
|
|
1055
|
+
return this.options.verbose === true || this.settingsManager.getQuietStartup() !== true;
|
|
1056
|
+
}
|
|
1057
|
+
/** Startup details (model scope, loaded resources). Hidden by quietStartup: true or "header". */
|
|
1058
|
+
shouldShowStartupDetails() {
|
|
1059
|
+
return this.options.verbose === true || this.settingsManager.getQuietStartup() === false;
|
|
1060
|
+
}
|
|
1027
1061
|
/**
|
|
1028
1062
|
* Get a short path relative to the package root for display.
|
|
1029
1063
|
*/
|
|
@@ -1285,7 +1319,7 @@ export class InteractiveMode {
|
|
|
1285
1319
|
showLoadedResources(options) {
|
|
1286
1320
|
// Resource rendering is idempotent; chat clears no longer clear this separate container.
|
|
1287
1321
|
this.loadedResourcesContainer.clear();
|
|
1288
|
-
const showListing = options?.force || this.
|
|
1322
|
+
const showListing = options?.force || this.shouldShowStartupDetails();
|
|
1289
1323
|
const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
|
|
1290
1324
|
if (!showListing && !showDiagnostics) {
|
|
1291
1325
|
return;
|
|
@@ -4075,8 +4109,8 @@ export class InteractiveMode {
|
|
|
4075
4109
|
onEnableInstallTelemetryChange: (enabled) => {
|
|
4076
4110
|
this.settingsManager.setEnableInstallTelemetry(enabled);
|
|
4077
4111
|
},
|
|
4078
|
-
onQuietStartupChange: (
|
|
4079
|
-
this.settingsManager.setQuietStartup(
|
|
4112
|
+
onQuietStartupChange: (quiet) => {
|
|
4113
|
+
this.settingsManager.setQuietStartup(quiet);
|
|
4080
4114
|
},
|
|
4081
4115
|
onDefaultProjectTrustChange: (defaultProjectTrust) => {
|
|
4082
4116
|
this.settingsManager.setDefaultProjectTrust(defaultProjectTrust);
|
|
@@ -4728,6 +4762,7 @@ export class InteractiveMode {
|
|
|
4728
4762
|
source: authStatus.label ?? authStatus.source,
|
|
4729
4763
|
}
|
|
4730
4764
|
: undefined;
|
|
4765
|
+
const subscription = provider.auth.oauth?.isSubscription === true;
|
|
4731
4766
|
if ((!authType || authType === "oauth") && provider.auth.oauth) {
|
|
4732
4767
|
options.push({
|
|
4733
4768
|
id: provider.id,
|
|
@@ -4735,6 +4770,7 @@ export class InteractiveMode {
|
|
|
4735
4770
|
authType: "oauth",
|
|
4736
4771
|
method: provider.auth.oauth,
|
|
4737
4772
|
status,
|
|
4773
|
+
subscription,
|
|
4738
4774
|
});
|
|
4739
4775
|
}
|
|
4740
4776
|
if ((!authType || authType === "api_key") && provider.auth.apiKey) {
|
|
@@ -4744,6 +4780,7 @@ export class InteractiveMode {
|
|
|
4744
4780
|
authType: "api_key",
|
|
4745
4781
|
method: provider.auth.apiKey,
|
|
4746
4782
|
status,
|
|
4783
|
+
subscription,
|
|
4747
4784
|
});
|
|
4748
4785
|
}
|
|
4749
4786
|
}
|
|
@@ -4751,12 +4788,16 @@ export class InteractiveMode {
|
|
|
4751
4788
|
}
|
|
4752
4789
|
async getLogoutProviderOptions() {
|
|
4753
4790
|
return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
|
|
4754
|
-
.map(({ providerId, type }) =>
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4791
|
+
.map(({ providerId, type }) => {
|
|
4792
|
+
const provider = this.session.modelRuntime.getProvider(providerId);
|
|
4793
|
+
return {
|
|
4794
|
+
id: providerId,
|
|
4795
|
+
name: provider?.name ?? providerId,
|
|
4796
|
+
authType: type,
|
|
4797
|
+
status: { type, source: "stored credential" },
|
|
4798
|
+
subscription: provider?.auth.oauth?.isSubscription === true,
|
|
4799
|
+
};
|
|
4800
|
+
})
|
|
4760
4801
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
4761
4802
|
}
|
|
4762
4803
|
findLoginProviderOptions(providerRef) {
|
|
@@ -4786,18 +4827,25 @@ export class InteractiveMode {
|
|
|
4786
4827
|
}
|
|
4787
4828
|
this.showLoginProviderSelector(undefined, providerRef);
|
|
4788
4829
|
}
|
|
4789
|
-
|
|
4830
|
+
/** `onBack` reopens the selector the login was started from when the user cancels it. */
|
|
4831
|
+
async startProviderLogin(providerOption, onBack) {
|
|
4790
4832
|
if (providerOption.authType === "oauth") {
|
|
4791
|
-
await this.showLoginDialog(providerOption.id, providerOption.name);
|
|
4833
|
+
await this.showLoginDialog(providerOption.id, providerOption.name, onBack);
|
|
4792
4834
|
}
|
|
4793
4835
|
else if (providerOption.method?.login) {
|
|
4794
|
-
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);
|
|
4836
|
+
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name, onBack);
|
|
4795
4837
|
}
|
|
4796
4838
|
else {
|
|
4797
|
-
this.showAmbientAuthDialog(providerOption);
|
|
4839
|
+
this.showAmbientAuthDialog(providerOption, onBack);
|
|
4798
4840
|
}
|
|
4799
4841
|
}
|
|
4800
4842
|
showLoginAuthTypeSelector(providerOptions) {
|
|
4843
|
+
// The top-level selector offers Radius directly, as its last option.
|
|
4844
|
+
const radiusOption = providerOptions
|
|
4845
|
+
? undefined
|
|
4846
|
+
: this.getLoginProviderOptions("oauth").find((provider) => provider.id === RADIUS_PROVIDER_ID);
|
|
4847
|
+
const radiusText = radiusOption ? `Sign in with ${radiusOption.name}` : undefined;
|
|
4848
|
+
const radiusLabel = radiusOption ? `${radiusText}${formatAuthSelectorProviderStatus(radiusOption)}` : undefined;
|
|
4801
4849
|
const oauthProvider = providerOptions?.find((provider) => provider.authType === "oauth");
|
|
4802
4850
|
const oauthLoginLabel = oauthProvider?.method && "loginLabel" in oauthProvider.method ? oauthProvider.method.loginLabel : undefined;
|
|
4803
4851
|
const subscriptionLabel = oauthLoginLabel ?? "Sign in with an account";
|
|
@@ -4812,6 +4860,8 @@ export class InteractiveMode {
|
|
|
4812
4860
|
if (availableAuthTypes.has("api_key")) {
|
|
4813
4861
|
options.push(apiKeyLabel);
|
|
4814
4862
|
}
|
|
4863
|
+
if (radiusLabel)
|
|
4864
|
+
options.push(radiusLabel);
|
|
4815
4865
|
if (options.length === 0) {
|
|
4816
4866
|
this.showStatus("No login methods available.");
|
|
4817
4867
|
return;
|
|
@@ -4827,29 +4877,37 @@ export class InteractiveMode {
|
|
|
4827
4877
|
? `Select authentication method for ${providerOptions[0].name}:`
|
|
4828
4878
|
: "Select authentication method:";
|
|
4829
4879
|
this.showSelector((done) => {
|
|
4830
|
-
const
|
|
4880
|
+
const onSelect = (option) => {
|
|
4831
4881
|
done();
|
|
4882
|
+
if (radiusOption && option === radiusLabel) {
|
|
4883
|
+
void this.startProviderLogin(radiusOption, () => this.showLoginAuthTypeSelector());
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4832
4886
|
const authType = option === subscriptionLabel ? "oauth" : "api_key";
|
|
4833
4887
|
if (providerOptions) {
|
|
4834
4888
|
const providerOption = providerOptions.find((provider) => provider.authType === authType);
|
|
4835
4889
|
if (providerOption) {
|
|
4836
|
-
void this.startProviderLogin(providerOption);
|
|
4890
|
+
void this.startProviderLogin(providerOption, () => this.showLoginAuthTypeSelector(providerOptions));
|
|
4837
4891
|
}
|
|
4838
4892
|
return;
|
|
4839
4893
|
}
|
|
4840
4894
|
this.showLoginProviderSelector(authType);
|
|
4841
|
-
}
|
|
4895
|
+
};
|
|
4896
|
+
const onCancel = () => {
|
|
4842
4897
|
done();
|
|
4843
4898
|
this.ui.requestRender();
|
|
4844
|
-
}
|
|
4845
|
-
|
|
4899
|
+
};
|
|
4900
|
+
const selector = radiusLabel && radiusText
|
|
4901
|
+
? createLoginMenuSelector(this.ui, title, options, { label: radiusLabel, text: radiusText }, onSelect, onCancel)
|
|
4902
|
+
: new ExtensionSelectorComponent(title, options, onSelect, onCancel);
|
|
4903
|
+
return { component: selector, focus: selector, dispose: () => selector.dispose() };
|
|
4846
4904
|
});
|
|
4847
4905
|
}
|
|
4848
4906
|
showLoginProviderSelector(authType, initialSearchInput) {
|
|
4849
4907
|
const providerOptions = this.getLoginProviderOptions(authType);
|
|
4850
4908
|
if (providerOptions.length === 0) {
|
|
4851
4909
|
const message = authType === "oauth"
|
|
4852
|
-
? "No
|
|
4910
|
+
? "No account providers available."
|
|
4853
4911
|
: authType === "api_key"
|
|
4854
4912
|
? "No API key providers available."
|
|
4855
4913
|
: "No login providers available.";
|
|
@@ -4863,7 +4921,7 @@ export class InteractiveMode {
|
|
|
4863
4921
|
if (!providerOption) {
|
|
4864
4922
|
return;
|
|
4865
4923
|
}
|
|
4866
|
-
await this.startProviderLogin(providerOption);
|
|
4924
|
+
await this.startProviderLogin(providerOption, () => this.showLoginProviderSelector(authType, initialSearchInput));
|
|
4867
4925
|
}, () => {
|
|
4868
4926
|
done();
|
|
4869
4927
|
if (authType) {
|
|
@@ -5017,21 +5075,24 @@ export class InteractiveMode {
|
|
|
5017
5075
|
})
|
|
5018
5076
|
.finally(() => clearTimeout(timeout));
|
|
5019
5077
|
}
|
|
5020
|
-
showAmbientAuthDialog(providerOption) {
|
|
5078
|
+
showAmbientAuthDialog(providerOption, onBack) {
|
|
5021
5079
|
const restoreEditor = () => {
|
|
5022
5080
|
this.editorContainer.clear();
|
|
5023
5081
|
this.editorContainer.addChild(this.editor);
|
|
5024
5082
|
this.ui.setFocus(this.editor);
|
|
5025
5083
|
this.ui.requestRender();
|
|
5026
5084
|
};
|
|
5027
|
-
const dialog = new LoginDialogComponent(this.ui, providerOption.id, () =>
|
|
5085
|
+
const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => {
|
|
5086
|
+
restoreEditor();
|
|
5087
|
+
onBack?.();
|
|
5088
|
+
}, providerOption.name, `${providerOption.name} setup`);
|
|
5028
5089
|
dialog.showInfo(`${providerOption.method?.name ?? "Authentication"} is configured outside ${APP_NAME}.`, [], true);
|
|
5029
5090
|
this.editorContainer.clear();
|
|
5030
5091
|
this.editorContainer.addChild(dialog);
|
|
5031
5092
|
this.ui.setFocus(dialog);
|
|
5032
5093
|
this.ui.requestRender();
|
|
5033
5094
|
}
|
|
5034
|
-
async showApiKeyLoginDialog(providerId, providerName) {
|
|
5095
|
+
async showApiKeyLoginDialog(providerId, providerName, onBack) {
|
|
5035
5096
|
const previousModel = this.session.model;
|
|
5036
5097
|
const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {
|
|
5037
5098
|
// Completion handled below
|
|
@@ -5064,12 +5125,15 @@ export class InteractiveMode {
|
|
|
5064
5125
|
if (error instanceof CredentialSynchronizationError) {
|
|
5065
5126
|
this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
|
|
5066
5127
|
}
|
|
5067
|
-
else if (errorMsg
|
|
5128
|
+
else if (errorMsg === "Login cancelled") {
|
|
5129
|
+
onBack?.();
|
|
5130
|
+
}
|
|
5131
|
+
else {
|
|
5068
5132
|
this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
|
|
5069
5133
|
}
|
|
5070
5134
|
}
|
|
5071
5135
|
}
|
|
5072
|
-
showAuthSelect(dialog, prompt) {
|
|
5136
|
+
showAuthSelect(dialog, prompt, providerId) {
|
|
5073
5137
|
return new Promise((resolve, reject) => {
|
|
5074
5138
|
const restoreDialog = () => {
|
|
5075
5139
|
this.editorContainer.clear();
|
|
@@ -5088,17 +5152,17 @@ export class InteractiveMode {
|
|
|
5088
5152
|
}, () => {
|
|
5089
5153
|
restoreDialog();
|
|
5090
5154
|
reject(new Error("Login cancelled"));
|
|
5091
|
-
});
|
|
5155
|
+
}, { description: providerId === RADIUS_PROVIDER_ID ? RADIUS_LOGIN_INTRO : undefined });
|
|
5092
5156
|
this.editorContainer.clear();
|
|
5093
5157
|
this.editorContainer.addChild(selector);
|
|
5094
5158
|
this.ui.setFocus(selector);
|
|
5095
5159
|
this.ui.requestRender();
|
|
5096
5160
|
});
|
|
5097
5161
|
}
|
|
5098
|
-
async showAuthPrompt(dialog, prompt) {
|
|
5162
|
+
async showAuthPrompt(dialog, prompt, providerId) {
|
|
5099
5163
|
let response;
|
|
5100
5164
|
if (prompt.type === "select") {
|
|
5101
|
-
response = this.showAuthSelect(dialog, prompt);
|
|
5165
|
+
response = this.showAuthSelect(dialog, prompt, providerId);
|
|
5102
5166
|
}
|
|
5103
5167
|
else if (prompt.type === "manual_code") {
|
|
5104
5168
|
response = dialog.showManualInput(prompt.message);
|
|
@@ -5142,11 +5206,11 @@ export class InteractiveMode {
|
|
|
5142
5206
|
async loginProvider(dialog, providerId, method) {
|
|
5143
5207
|
await this.session.modelRuntime.login(providerId, method, {
|
|
5144
5208
|
signal: dialog.signal,
|
|
5145
|
-
prompt: (prompt) => this.showAuthPrompt(dialog, prompt),
|
|
5209
|
+
prompt: (prompt) => this.showAuthPrompt(dialog, prompt, providerId),
|
|
5146
5210
|
notify: (event) => this.notifyAuthDialog(dialog, event),
|
|
5147
5211
|
}, { getDeviceId: () => this.settingsManager.getOrCreateDeviceId() });
|
|
5148
5212
|
}
|
|
5149
|
-
async showLoginDialog(providerId, providerName) {
|
|
5213
|
+
async showLoginDialog(providerId, providerName, onBack) {
|
|
5150
5214
|
const previousModel = this.session.model;
|
|
5151
5215
|
const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => { }, providerName);
|
|
5152
5216
|
this.editorContainer.clear();
|
|
@@ -5163,6 +5227,8 @@ export class InteractiveMode {
|
|
|
5163
5227
|
await this.loginProvider(dialog, providerId, "oauth");
|
|
5164
5228
|
restoreEditor();
|
|
5165
5229
|
await this.completeProviderAuthentication(providerId, providerName, "oauth", previousModel);
|
|
5230
|
+
if (providerId === RADIUS_PROVIDER_ID)
|
|
5231
|
+
this.offerRadiusMcpServer(providerId, providerName);
|
|
5166
5232
|
}
|
|
5167
5233
|
catch (error) {
|
|
5168
5234
|
restoreEditor();
|
|
@@ -5170,11 +5236,58 @@ export class InteractiveMode {
|
|
|
5170
5236
|
if (error instanceof CredentialSynchronizationError) {
|
|
5171
5237
|
this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
|
|
5172
5238
|
}
|
|
5173
|
-
else if (errorMsg
|
|
5239
|
+
else if (errorMsg === "Login cancelled") {
|
|
5240
|
+
onBack?.();
|
|
5241
|
+
}
|
|
5242
|
+
else {
|
|
5174
5243
|
this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
|
|
5175
5244
|
}
|
|
5176
5245
|
}
|
|
5177
5246
|
}
|
|
5247
|
+
/**
|
|
5248
|
+
* Offer to point the Radius MCP server in the global mcp.json at the Radius login, adding the server
|
|
5249
|
+
* when missing. Nothing is asked when a global server already uses this login.
|
|
5250
|
+
*/
|
|
5251
|
+
offerRadiusMcpServer(providerId, providerName) {
|
|
5252
|
+
const mcpPath = path.join(getAgentDir(), "mcp.json");
|
|
5253
|
+
const normalizeUrl = (url) => url.replace(/\/+$/u, "");
|
|
5254
|
+
const { servers } = loadMcpConfig({
|
|
5255
|
+
agentDir: getAgentDir(),
|
|
5256
|
+
cwd: this.sessionManager.getCwd(),
|
|
5257
|
+
projectTrusted: false,
|
|
5258
|
+
});
|
|
5259
|
+
const existing = servers.find((server) => "url" in server.config && normalizeUrl(server.config.url) === normalizeUrl(RADIUS_MCP_URL));
|
|
5260
|
+
if (existing && "url" in existing.config && existing.config.auth?.provider === providerId)
|
|
5261
|
+
return;
|
|
5262
|
+
let name = existing?.name ?? "radius";
|
|
5263
|
+
if (!existing && servers.some((server) => server.name === name))
|
|
5264
|
+
name = "radius-mcp";
|
|
5265
|
+
const config = existing && "url" in existing.config
|
|
5266
|
+
? { ...existing.config, auth: { provider: providerId } }
|
|
5267
|
+
: { url: RADIUS_MCP_URL, auth: { provider: providerId } };
|
|
5268
|
+
// `auth` replaces the MCP OAuth sign-in.
|
|
5269
|
+
delete config.oauth;
|
|
5270
|
+
this.showSelector((done) => {
|
|
5271
|
+
const selector = new ExtensionSelectorComponent(`Configure ${providerName} MCP in ${mcpPath}?`, ["Yes", "No"], (option) => {
|
|
5272
|
+
done();
|
|
5273
|
+
if (option !== "Yes")
|
|
5274
|
+
return;
|
|
5275
|
+
try {
|
|
5276
|
+
addMcpServerConfig(mcpPath, name, config);
|
|
5277
|
+
}
|
|
5278
|
+
catch (error) {
|
|
5279
|
+
this.showError(`Could not update ${mcpPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
5280
|
+
return;
|
|
5281
|
+
}
|
|
5282
|
+
// The MCP extension reads mcp.json when the session starts.
|
|
5283
|
+
void this.handleReloadCommand();
|
|
5284
|
+
}, () => {
|
|
5285
|
+
done();
|
|
5286
|
+
this.ui.requestRender();
|
|
5287
|
+
});
|
|
5288
|
+
return { component: selector, focus: selector };
|
|
5289
|
+
});
|
|
5290
|
+
}
|
|
5178
5291
|
// =========================================================================
|
|
5179
5292
|
// Command handlers
|
|
5180
5293
|
// =========================================================================
|