@earendil-works/pi-coding-agent 0.99.2 → 1.0.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 +90 -0
- package/README.md +32 -7
- package/dist/bundle/chunks/{anthropic-messages-UID2PALB.js → anthropic-messages-GXHZP2HL.js} +3 -3
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/{azure-openai-responses-TLHNIYZK.js → azure-openai-responses-AFMVM6NP.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/chunk-2KAZSACP.js +2 -0
- package/dist/bundle/chunks/{chunk-R5J3MOBF.js → chunk-2VNGUWBO.js} +1 -1
- package/dist/bundle/chunks/chunk-5OEJBNHG.js +1203 -0
- package/dist/bundle/chunks/{chunk-7QSPBJKW.js → chunk-6FX7UEPL.js} +16 -30
- package/dist/bundle/chunks/chunk-F5ZABL6Z.js +20 -0
- package/dist/bundle/chunks/chunk-FDW3AYMM.js +2 -0
- package/dist/bundle/chunks/chunk-OYBSLV7Y.js +16 -0
- package/dist/bundle/chunks/{chunk-45SXDISG.js → chunk-PDFMCAOZ.js} +5 -5
- package/dist/bundle/chunks/{chunk-G3UZ5FWD.js → chunk-SYF2TF6W.js} +11 -60
- package/dist/bundle/chunks/chunk-WCQZGZ6I.js +82 -0
- package/dist/bundle/chunks/chunk-ZSI3BL5Q.js +4 -0
- package/dist/bundle/chunks/{cli-ALNBTL3U.js → cli-KILDDGW3.js} +4 -4
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-NPQN263E.js → cloudflare-workers-ai-system-one-X5PVWWYJ.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +68 -8
- package/dist/bundle/chunks/easter-egg-3d-T5FFWIBR.js +2 -0
- package/dist/bundle/chunks/execute-RYVK27GT.js +388 -0
- package/dist/bundle/chunks/node-N5BSDOA5.js +16 -0
- package/dist/bundle/chunks/openai-chatgpt.js +2 -2
- package/dist/bundle/chunks/{openai-codex-responses-3GKGNXC4.js → openai-codex-responses-GK67DQQJ.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-responses-S7GKCCDG.js → openai-responses-CQDDLDQF.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/radius.js +1 -1
- package/dist/bundle/chunks/runtime-D5I2NTIF.js +2 -0
- package/dist/bundle/chunks/virtual-modules-OO3V5ZPE.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.d.ts.map +1 -1
- package/dist/cli/args.js +6 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +8 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +38 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts +3 -3
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +3 -3
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +9 -0
- 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 +12 -0
- package/dist/core/mcp-servers.d.ts.map +1 -1
- package/dist/core/mcp-servers.js +18 -0
- 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-resolver.js +1 -1
- package/dist/core/model-resolver.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/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/index.d.ts +2 -2
- package/dist/core/tools/renderers/index.d.ts.map +1 -1
- package/dist/core/tools/renderers/index.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +154 -47
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +7 -7
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +55 -102
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/mcp/cli.d.ts.map +1 -1
- package/dist/extensions/mcp/cli.js +5 -2
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/config.d.ts +15 -3
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +46 -10
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts +4 -1
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +97 -51
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +12 -8
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +104 -35
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +3 -1
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +3 -1
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +19 -13
- 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 +8 -4
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/index.d.ts +2 -2
- 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/armin.d.ts +3 -0
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +7 -5
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/auth-url.d.ts +14 -0
- package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
- package/dist/modes/interactive/components/auth-url.js +37 -0
- package/dist/modes/interactive/components/auth-url.js.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
- package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.js +1139 -0
- package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.js +23 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +11 -5
- package/dist/modes/interactive/components/login-dialog.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.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/tool-execution.d.ts +6 -18
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +22 -45
- package/dist/modes/interactive/components/tool-execution.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/interactive-mode.d.ts +12 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +166 -55
- 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/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +12 -0
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/image-convert.d.ts +12 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +45 -6
- package/dist/utils/image-convert.js.map +1 -1
- package/docs/cli.md +8 -16
- package/docs/codemode.md +207 -0
- package/docs/docs.json +5 -1
- package/docs/environment-variables.md +2 -2
- package/docs/extensions.md +4 -0
- package/docs/index.md +1 -1
- package/docs/keybindings.md +1 -1
- package/docs/mcp.md +40 -1
- package/docs/models.md +24 -3
- package/docs/providers.md +16 -6
- package/docs/quickstart.md +16 -2
- package/docs/sdk.md +1 -1
- package/docs/settings.md +3 -3
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- 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/package.json +13 -14
- package/dist/bundle/chunks/chunk-3KYEVQKX.js +0 -82
- package/dist/bundle/chunks/chunk-3NVH2HQH.js +0 -4
- package/dist/bundle/chunks/chunk-3YAHQSW6.js +0 -1438
- package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
- package/dist/bundle/chunks/chunk-ECRK44UV.js +0 -2
- package/dist/bundle/chunks/execute-RC7W4ML3.js +0 -328
- package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
- package/dist/bundle/chunks/runtime-NJPX4ID2.js +0 -2
- package/dist/bundle/chunks/virtual-modules-5UGH4HRZ.js +0 -2
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
- package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
- package/dist/modes/interactive/components/daxnuts.js +0 -140
- package/dist/modes/interactive/components/daxnuts.js.map +0 -1
- package/npm-shrinkwrap.json +0 -1957
|
@@ -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,10 +33,12 @@ 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";
|
|
38
40
|
import { parseGitUrl } from "../../utils/git.js";
|
|
41
|
+
import { ensurePngTranscoder } from "../../utils/image-convert.js";
|
|
39
42
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
40
43
|
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
41
44
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
@@ -52,9 +55,9 @@ import { CompactionSummaryMessageComponent } from "./components/compaction-summa
|
|
|
52
55
|
import { CustomEditor } from "./components/custom-editor.js";
|
|
53
56
|
import { CustomEntryComponent } from "./components/custom-entry.js";
|
|
54
57
|
import { CustomMessageComponent } from "./components/custom-message.js";
|
|
55
|
-
import { DaxnutsComponent } from "./components/daxnuts.js";
|
|
56
58
|
import { DynamicBorder } from "./components/dynamic-border.js";
|
|
57
59
|
import { EarendilAnnouncementComponent } from "./components/earendil-announcement.js";
|
|
60
|
+
import { playArmin3d, playPiLogo3d } from "./components/easter-egg-3d.lazy.js";
|
|
58
61
|
import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
59
62
|
import { ExtensionInputComponent } from "./components/extension-input.js";
|
|
60
63
|
import { ExtensionSelectorComponent } from "./components/extension-selector.js";
|
|
@@ -63,8 +66,9 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
|
|
|
63
66
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
64
67
|
import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
|
|
65
68
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
66
|
-
import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
67
|
-
import { piLogoLines } from "./components/pi-logo.js";
|
|
69
|
+
import { formatAuthSelectorProviderStatus, formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
70
|
+
import { piLogoLines, piWordmark, supportsPiLogo } from "./components/pi-logo.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}` : "";
|
|
@@ -681,15 +699,21 @@ export class InteractiveMode {
|
|
|
681
699
|
// Start the UI before initializing extensions so session_start handlers can use interactive dialogs
|
|
682
700
|
this.ui.start();
|
|
683
701
|
this.isInitialized = true;
|
|
702
|
+
this.ensurePngTranscoder();
|
|
684
703
|
this.themeController.applyFromSettings();
|
|
685
704
|
// The header and startup notices bake theme colors into their text, so build them once the terminal
|
|
686
705
|
// reported its colors. This ends at the terminal's DA1 reply, or after 100 ms if it answers nothing.
|
|
687
706
|
await this.themeController.waitForTerminalColors();
|
|
688
707
|
// Add header with keybindings from config (unless silenced)
|
|
689
|
-
if (this.
|
|
708
|
+
if (this.shouldShowStartupHeader()) {
|
|
709
|
+
const showDetails = this.shouldShowStartupDetails();
|
|
690
710
|
// 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.
|
|
711
|
+
// its second line the first line of key hints. Terminals that cannot render the logo get a
|
|
712
|
+
// "Pi vX" line instead, with the key hints below it.
|
|
713
|
+
const showLogo = supportsPiLogo();
|
|
692
714
|
const withLogo = (hints) => {
|
|
715
|
+
if (!showLogo)
|
|
716
|
+
return `${piWordmark()} ${theme.fg("dim", `v${this.version}`)}\n${hints}`;
|
|
693
717
|
const [top, bottom] = piLogoLines();
|
|
694
718
|
return `${top} ${theme.fg("dim", `v${this.version}`)}\n${bottom} ${hints}`;
|
|
695
719
|
};
|
|
@@ -723,9 +747,12 @@ export class InteractiveMode {
|
|
|
723
747
|
rawKeyHint("!", "bash"),
|
|
724
748
|
hint("app.tools.expand", "more"),
|
|
725
749
|
].join(theme.fg("muted", " · "));
|
|
726
|
-
const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
|
|
750
|
+
const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help${showDetails ? " and loaded resources" : ""}.`);
|
|
727
751
|
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
|
-
|
|
752
|
+
const header = new BuiltInHeader(() => `${withLogo(compactInstructions())}\n${compactOnboarding()}\n\n${onboarding()}`, () => `${withLogo(expandedInstructions())}\n\n${onboarding()}`, this.getStartupExpansionState(), 1, 0);
|
|
753
|
+
if (showLogo)
|
|
754
|
+
header.onLogoClick = (column, row) => playPiLogo3d(this.renderer, column, row);
|
|
755
|
+
this.builtInHeader = header;
|
|
729
756
|
// Setup UI layout
|
|
730
757
|
this.headerContainer.addChild(new Spacer(1));
|
|
731
758
|
this.headerContainer.addChild(this.builtInHeader);
|
|
@@ -1024,6 +1051,14 @@ export class InteractiveMode {
|
|
|
1024
1051
|
getStartupExpansionState() {
|
|
1025
1052
|
return this.options.verbose || this.toolOutputExpanded;
|
|
1026
1053
|
}
|
|
1054
|
+
/** Startup header (logo, version, key hints). Hidden only by quietStartup: true. */
|
|
1055
|
+
shouldShowStartupHeader() {
|
|
1056
|
+
return this.options.verbose === true || this.settingsManager.getQuietStartup() !== true;
|
|
1057
|
+
}
|
|
1058
|
+
/** Startup details (model scope, loaded resources). Hidden by quietStartup: true or "header". */
|
|
1059
|
+
shouldShowStartupDetails() {
|
|
1060
|
+
return this.options.verbose === true || this.settingsManager.getQuietStartup() === false;
|
|
1061
|
+
}
|
|
1027
1062
|
/**
|
|
1028
1063
|
* Get a short path relative to the package root for display.
|
|
1029
1064
|
*/
|
|
@@ -1285,7 +1320,7 @@ export class InteractiveMode {
|
|
|
1285
1320
|
showLoadedResources(options) {
|
|
1286
1321
|
// Resource rendering is idempotent; chat clears no longer clear this separate container.
|
|
1287
1322
|
this.loadedResourcesContainer.clear();
|
|
1288
|
-
const showListing = options?.force || this.
|
|
1323
|
+
const showListing = options?.force || this.shouldShowStartupDetails();
|
|
1289
1324
|
const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
|
|
1290
1325
|
if (!showListing && !showDiagnostics) {
|
|
1291
1326
|
return;
|
|
@@ -1507,8 +1542,16 @@ export class InteractiveMode {
|
|
|
1507
1542
|
applyFullscreenScrollbarSetting() {
|
|
1508
1543
|
this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
|
|
1509
1544
|
}
|
|
1545
|
+
/** Lets extension images use the PNG transcoder; tool results register it themselves. */
|
|
1546
|
+
ensurePngTranscoder() {
|
|
1547
|
+
ensurePngTranscoder(() => {
|
|
1548
|
+
this.ui.invalidate();
|
|
1549
|
+
this.ui.requestRender();
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1510
1552
|
applyRuntimeSettings() {
|
|
1511
1553
|
setCapabilityOverrides(this.settingsManager.getTerminalCapabilityOverrides());
|
|
1554
|
+
this.ensurePngTranscoder();
|
|
1512
1555
|
configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
|
|
1513
1556
|
this.applyFullscreenScrollbarSetting();
|
|
1514
1557
|
if (this.renderer instanceof TuiAltScreen) {
|
|
@@ -1628,7 +1671,7 @@ export class InteractiveMode {
|
|
|
1628
1671
|
* whatever this returns, so they never reach into the tool registry themselves.
|
|
1629
1672
|
*/
|
|
1630
1673
|
getRegisteredToolDefinition(toolName) {
|
|
1631
|
-
return withBuiltInRenderers(toolName, this.session.getToolDefinition(toolName));
|
|
1674
|
+
return this.session.extensionRunner.resolveToolRenderers(toolName, () => withBuiltInRenderers(toolName, this.session.getToolDefinition(toolName)));
|
|
1632
1675
|
}
|
|
1633
1676
|
getMarkdownTransformers() {
|
|
1634
1677
|
return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
|
|
@@ -4075,8 +4118,8 @@ export class InteractiveMode {
|
|
|
4075
4118
|
onEnableInstallTelemetryChange: (enabled) => {
|
|
4076
4119
|
this.settingsManager.setEnableInstallTelemetry(enabled);
|
|
4077
4120
|
},
|
|
4078
|
-
onQuietStartupChange: (
|
|
4079
|
-
this.settingsManager.setQuietStartup(
|
|
4121
|
+
onQuietStartupChange: (quiet) => {
|
|
4122
|
+
this.settingsManager.setQuietStartup(quiet);
|
|
4080
4123
|
},
|
|
4081
4124
|
onDefaultProjectTrustChange: (defaultProjectTrust) => {
|
|
4082
4125
|
this.settingsManager.setDefaultProjectTrust(defaultProjectTrust);
|
|
@@ -4224,7 +4267,6 @@ export class InteractiveMode {
|
|
|
4224
4267
|
this.updateEditorBorderColor();
|
|
4225
4268
|
this.showStatus(`Model: ${model.id}`);
|
|
4226
4269
|
void this.maybeWarnAboutAnthropicSubscriptionAuth(model);
|
|
4227
|
-
this.checkDaxnutsEasterEgg(model);
|
|
4228
4270
|
}
|
|
4229
4271
|
catch (error) {
|
|
4230
4272
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
@@ -4357,7 +4399,6 @@ export class InteractiveMode {
|
|
|
4357
4399
|
done();
|
|
4358
4400
|
this.showStatus(persist ? `Default model: ${model.provider}/${model.id}` : `Model: ${model.id}`);
|
|
4359
4401
|
void this.maybeWarnAboutAnthropicSubscriptionAuth(model);
|
|
4360
|
-
this.checkDaxnutsEasterEgg(model);
|
|
4361
4402
|
}
|
|
4362
4403
|
catch (error) {
|
|
4363
4404
|
done();
|
|
@@ -4728,6 +4769,7 @@ export class InteractiveMode {
|
|
|
4728
4769
|
source: authStatus.label ?? authStatus.source,
|
|
4729
4770
|
}
|
|
4730
4771
|
: undefined;
|
|
4772
|
+
const subscription = provider.auth.oauth?.isSubscription === true;
|
|
4731
4773
|
if ((!authType || authType === "oauth") && provider.auth.oauth) {
|
|
4732
4774
|
options.push({
|
|
4733
4775
|
id: provider.id,
|
|
@@ -4735,6 +4777,7 @@ export class InteractiveMode {
|
|
|
4735
4777
|
authType: "oauth",
|
|
4736
4778
|
method: provider.auth.oauth,
|
|
4737
4779
|
status,
|
|
4780
|
+
subscription,
|
|
4738
4781
|
});
|
|
4739
4782
|
}
|
|
4740
4783
|
if ((!authType || authType === "api_key") && provider.auth.apiKey) {
|
|
@@ -4744,6 +4787,7 @@ export class InteractiveMode {
|
|
|
4744
4787
|
authType: "api_key",
|
|
4745
4788
|
method: provider.auth.apiKey,
|
|
4746
4789
|
status,
|
|
4790
|
+
subscription,
|
|
4747
4791
|
});
|
|
4748
4792
|
}
|
|
4749
4793
|
}
|
|
@@ -4751,12 +4795,16 @@ export class InteractiveMode {
|
|
|
4751
4795
|
}
|
|
4752
4796
|
async getLogoutProviderOptions() {
|
|
4753
4797
|
return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
|
|
4754
|
-
.map(({ providerId, type }) =>
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4798
|
+
.map(({ providerId, type }) => {
|
|
4799
|
+
const provider = this.session.modelRuntime.getProvider(providerId);
|
|
4800
|
+
return {
|
|
4801
|
+
id: providerId,
|
|
4802
|
+
name: provider?.name ?? providerId,
|
|
4803
|
+
authType: type,
|
|
4804
|
+
status: { type, source: "stored credential" },
|
|
4805
|
+
subscription: provider?.auth.oauth?.isSubscription === true,
|
|
4806
|
+
};
|
|
4807
|
+
})
|
|
4760
4808
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
4761
4809
|
}
|
|
4762
4810
|
findLoginProviderOptions(providerRef) {
|
|
@@ -4786,18 +4834,25 @@ export class InteractiveMode {
|
|
|
4786
4834
|
}
|
|
4787
4835
|
this.showLoginProviderSelector(undefined, providerRef);
|
|
4788
4836
|
}
|
|
4789
|
-
|
|
4837
|
+
/** `onBack` reopens the selector the login was started from when the user cancels it. */
|
|
4838
|
+
async startProviderLogin(providerOption, onBack) {
|
|
4790
4839
|
if (providerOption.authType === "oauth") {
|
|
4791
|
-
await this.showLoginDialog(providerOption.id, providerOption.name);
|
|
4840
|
+
await this.showLoginDialog(providerOption.id, providerOption.name, onBack);
|
|
4792
4841
|
}
|
|
4793
4842
|
else if (providerOption.method?.login) {
|
|
4794
|
-
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);
|
|
4843
|
+
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name, onBack);
|
|
4795
4844
|
}
|
|
4796
4845
|
else {
|
|
4797
|
-
this.showAmbientAuthDialog(providerOption);
|
|
4846
|
+
this.showAmbientAuthDialog(providerOption, onBack);
|
|
4798
4847
|
}
|
|
4799
4848
|
}
|
|
4800
4849
|
showLoginAuthTypeSelector(providerOptions) {
|
|
4850
|
+
// The top-level selector offers Radius directly, as its last option.
|
|
4851
|
+
const radiusOption = providerOptions
|
|
4852
|
+
? undefined
|
|
4853
|
+
: this.getLoginProviderOptions("oauth").find((provider) => provider.id === RADIUS_PROVIDER_ID);
|
|
4854
|
+
const radiusText = radiusOption ? `Sign in with ${radiusOption.name}` : undefined;
|
|
4855
|
+
const radiusLabel = radiusOption ? `${radiusText}${formatAuthSelectorProviderStatus(radiusOption)}` : undefined;
|
|
4801
4856
|
const oauthProvider = providerOptions?.find((provider) => provider.authType === "oauth");
|
|
4802
4857
|
const oauthLoginLabel = oauthProvider?.method && "loginLabel" in oauthProvider.method ? oauthProvider.method.loginLabel : undefined;
|
|
4803
4858
|
const subscriptionLabel = oauthLoginLabel ?? "Sign in with an account";
|
|
@@ -4812,6 +4867,8 @@ export class InteractiveMode {
|
|
|
4812
4867
|
if (availableAuthTypes.has("api_key")) {
|
|
4813
4868
|
options.push(apiKeyLabel);
|
|
4814
4869
|
}
|
|
4870
|
+
if (radiusLabel)
|
|
4871
|
+
options.push(radiusLabel);
|
|
4815
4872
|
if (options.length === 0) {
|
|
4816
4873
|
this.showStatus("No login methods available.");
|
|
4817
4874
|
return;
|
|
@@ -4827,29 +4884,37 @@ export class InteractiveMode {
|
|
|
4827
4884
|
? `Select authentication method for ${providerOptions[0].name}:`
|
|
4828
4885
|
: "Select authentication method:";
|
|
4829
4886
|
this.showSelector((done) => {
|
|
4830
|
-
const
|
|
4887
|
+
const onSelect = (option) => {
|
|
4831
4888
|
done();
|
|
4889
|
+
if (radiusOption && option === radiusLabel) {
|
|
4890
|
+
void this.startProviderLogin(radiusOption, () => this.showLoginAuthTypeSelector());
|
|
4891
|
+
return;
|
|
4892
|
+
}
|
|
4832
4893
|
const authType = option === subscriptionLabel ? "oauth" : "api_key";
|
|
4833
4894
|
if (providerOptions) {
|
|
4834
4895
|
const providerOption = providerOptions.find((provider) => provider.authType === authType);
|
|
4835
4896
|
if (providerOption) {
|
|
4836
|
-
void this.startProviderLogin(providerOption);
|
|
4897
|
+
void this.startProviderLogin(providerOption, () => this.showLoginAuthTypeSelector(providerOptions));
|
|
4837
4898
|
}
|
|
4838
4899
|
return;
|
|
4839
4900
|
}
|
|
4840
4901
|
this.showLoginProviderSelector(authType);
|
|
4841
|
-
}
|
|
4902
|
+
};
|
|
4903
|
+
const onCancel = () => {
|
|
4842
4904
|
done();
|
|
4843
4905
|
this.ui.requestRender();
|
|
4844
|
-
}
|
|
4845
|
-
|
|
4906
|
+
};
|
|
4907
|
+
const selector = radiusLabel && radiusText
|
|
4908
|
+
? createLoginMenuSelector(this.ui, title, options, { label: radiusLabel, text: radiusText }, onSelect, onCancel)
|
|
4909
|
+
: new ExtensionSelectorComponent(title, options, onSelect, onCancel);
|
|
4910
|
+
return { component: selector, focus: selector, dispose: () => selector.dispose() };
|
|
4846
4911
|
});
|
|
4847
4912
|
}
|
|
4848
4913
|
showLoginProviderSelector(authType, initialSearchInput) {
|
|
4849
4914
|
const providerOptions = this.getLoginProviderOptions(authType);
|
|
4850
4915
|
if (providerOptions.length === 0) {
|
|
4851
4916
|
const message = authType === "oauth"
|
|
4852
|
-
? "No
|
|
4917
|
+
? "No account providers available."
|
|
4853
4918
|
: authType === "api_key"
|
|
4854
4919
|
? "No API key providers available."
|
|
4855
4920
|
: "No login providers available.";
|
|
@@ -4863,7 +4928,7 @@ export class InteractiveMode {
|
|
|
4863
4928
|
if (!providerOption) {
|
|
4864
4929
|
return;
|
|
4865
4930
|
}
|
|
4866
|
-
await this.startProviderLogin(providerOption);
|
|
4931
|
+
await this.startProviderLogin(providerOption, () => this.showLoginProviderSelector(authType, initialSearchInput));
|
|
4867
4932
|
}, () => {
|
|
4868
4933
|
done();
|
|
4869
4934
|
if (authType) {
|
|
@@ -4975,7 +5040,6 @@ export class InteractiveMode {
|
|
|
4975
5040
|
if (selectedModel) {
|
|
4976
5041
|
this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);
|
|
4977
5042
|
void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);
|
|
4978
|
-
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4979
5043
|
}
|
|
4980
5044
|
else {
|
|
4981
5045
|
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);
|
|
@@ -5017,21 +5081,24 @@ export class InteractiveMode {
|
|
|
5017
5081
|
})
|
|
5018
5082
|
.finally(() => clearTimeout(timeout));
|
|
5019
5083
|
}
|
|
5020
|
-
showAmbientAuthDialog(providerOption) {
|
|
5084
|
+
showAmbientAuthDialog(providerOption, onBack) {
|
|
5021
5085
|
const restoreEditor = () => {
|
|
5022
5086
|
this.editorContainer.clear();
|
|
5023
5087
|
this.editorContainer.addChild(this.editor);
|
|
5024
5088
|
this.ui.setFocus(this.editor);
|
|
5025
5089
|
this.ui.requestRender();
|
|
5026
5090
|
};
|
|
5027
|
-
const dialog = new LoginDialogComponent(this.ui, providerOption.id, () =>
|
|
5091
|
+
const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => {
|
|
5092
|
+
restoreEditor();
|
|
5093
|
+
onBack?.();
|
|
5094
|
+
}, providerOption.name, `${providerOption.name} setup`);
|
|
5028
5095
|
dialog.showInfo(`${providerOption.method?.name ?? "Authentication"} is configured outside ${APP_NAME}.`, [], true);
|
|
5029
5096
|
this.editorContainer.clear();
|
|
5030
5097
|
this.editorContainer.addChild(dialog);
|
|
5031
5098
|
this.ui.setFocus(dialog);
|
|
5032
5099
|
this.ui.requestRender();
|
|
5033
5100
|
}
|
|
5034
|
-
async showApiKeyLoginDialog(providerId, providerName) {
|
|
5101
|
+
async showApiKeyLoginDialog(providerId, providerName, onBack) {
|
|
5035
5102
|
const previousModel = this.session.model;
|
|
5036
5103
|
const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {
|
|
5037
5104
|
// Completion handled below
|
|
@@ -5064,12 +5131,15 @@ export class InteractiveMode {
|
|
|
5064
5131
|
if (error instanceof CredentialSynchronizationError) {
|
|
5065
5132
|
this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
|
|
5066
5133
|
}
|
|
5067
|
-
else if (errorMsg
|
|
5134
|
+
else if (errorMsg === "Login cancelled") {
|
|
5135
|
+
onBack?.();
|
|
5136
|
+
}
|
|
5137
|
+
else {
|
|
5068
5138
|
this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
|
|
5069
5139
|
}
|
|
5070
5140
|
}
|
|
5071
5141
|
}
|
|
5072
|
-
showAuthSelect(dialog, prompt) {
|
|
5142
|
+
showAuthSelect(dialog, prompt, providerId) {
|
|
5073
5143
|
return new Promise((resolve, reject) => {
|
|
5074
5144
|
const restoreDialog = () => {
|
|
5075
5145
|
this.editorContainer.clear();
|
|
@@ -5088,17 +5158,17 @@ export class InteractiveMode {
|
|
|
5088
5158
|
}, () => {
|
|
5089
5159
|
restoreDialog();
|
|
5090
5160
|
reject(new Error("Login cancelled"));
|
|
5091
|
-
});
|
|
5161
|
+
}, { description: providerId === RADIUS_PROVIDER_ID ? RADIUS_LOGIN_INTRO : undefined });
|
|
5092
5162
|
this.editorContainer.clear();
|
|
5093
5163
|
this.editorContainer.addChild(selector);
|
|
5094
5164
|
this.ui.setFocus(selector);
|
|
5095
5165
|
this.ui.requestRender();
|
|
5096
5166
|
});
|
|
5097
5167
|
}
|
|
5098
|
-
async showAuthPrompt(dialog, prompt) {
|
|
5168
|
+
async showAuthPrompt(dialog, prompt, providerId) {
|
|
5099
5169
|
let response;
|
|
5100
5170
|
if (prompt.type === "select") {
|
|
5101
|
-
response = this.showAuthSelect(dialog, prompt);
|
|
5171
|
+
response = this.showAuthSelect(dialog, prompt, providerId);
|
|
5102
5172
|
}
|
|
5103
5173
|
else if (prompt.type === "manual_code") {
|
|
5104
5174
|
response = dialog.showManualInput(prompt.message);
|
|
@@ -5142,11 +5212,11 @@ export class InteractiveMode {
|
|
|
5142
5212
|
async loginProvider(dialog, providerId, method) {
|
|
5143
5213
|
await this.session.modelRuntime.login(providerId, method, {
|
|
5144
5214
|
signal: dialog.signal,
|
|
5145
|
-
prompt: (prompt) => this.showAuthPrompt(dialog, prompt),
|
|
5215
|
+
prompt: (prompt) => this.showAuthPrompt(dialog, prompt, providerId),
|
|
5146
5216
|
notify: (event) => this.notifyAuthDialog(dialog, event),
|
|
5147
5217
|
}, { getDeviceId: () => this.settingsManager.getOrCreateDeviceId() });
|
|
5148
5218
|
}
|
|
5149
|
-
async showLoginDialog(providerId, providerName) {
|
|
5219
|
+
async showLoginDialog(providerId, providerName, onBack) {
|
|
5150
5220
|
const previousModel = this.session.model;
|
|
5151
5221
|
const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => { }, providerName);
|
|
5152
5222
|
this.editorContainer.clear();
|
|
@@ -5163,6 +5233,8 @@ export class InteractiveMode {
|
|
|
5163
5233
|
await this.loginProvider(dialog, providerId, "oauth");
|
|
5164
5234
|
restoreEditor();
|
|
5165
5235
|
await this.completeProviderAuthentication(providerId, providerName, "oauth", previousModel);
|
|
5236
|
+
if (providerId === RADIUS_PROVIDER_ID)
|
|
5237
|
+
this.offerRadiusMcpServer(providerId, providerName);
|
|
5166
5238
|
}
|
|
5167
5239
|
catch (error) {
|
|
5168
5240
|
restoreEditor();
|
|
@@ -5170,11 +5242,58 @@ export class InteractiveMode {
|
|
|
5170
5242
|
if (error instanceof CredentialSynchronizationError) {
|
|
5171
5243
|
this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
|
|
5172
5244
|
}
|
|
5173
|
-
else if (errorMsg
|
|
5245
|
+
else if (errorMsg === "Login cancelled") {
|
|
5246
|
+
onBack?.();
|
|
5247
|
+
}
|
|
5248
|
+
else {
|
|
5174
5249
|
this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
|
|
5175
5250
|
}
|
|
5176
5251
|
}
|
|
5177
5252
|
}
|
|
5253
|
+
/**
|
|
5254
|
+
* Offer to point the Radius MCP server in the global mcp.json at the Radius login, adding the server
|
|
5255
|
+
* when missing. Nothing is asked when a global server already uses this login.
|
|
5256
|
+
*/
|
|
5257
|
+
offerRadiusMcpServer(providerId, providerName) {
|
|
5258
|
+
const mcpPath = path.join(getAgentDir(), "mcp.json");
|
|
5259
|
+
const normalizeUrl = (url) => url.replace(/\/+$/u, "");
|
|
5260
|
+
const { servers } = loadMcpConfig({
|
|
5261
|
+
agentDir: getAgentDir(),
|
|
5262
|
+
cwd: this.sessionManager.getCwd(),
|
|
5263
|
+
projectTrusted: false,
|
|
5264
|
+
});
|
|
5265
|
+
const existing = servers.find((server) => "url" in server.config && normalizeUrl(server.config.url) === normalizeUrl(RADIUS_MCP_URL));
|
|
5266
|
+
if (existing && "url" in existing.config && existing.config.auth?.provider === providerId)
|
|
5267
|
+
return;
|
|
5268
|
+
let name = existing?.name ?? "radius";
|
|
5269
|
+
if (!existing && servers.some((server) => server.name === name))
|
|
5270
|
+
name = "radius-mcp";
|
|
5271
|
+
const config = existing && "url" in existing.config
|
|
5272
|
+
? { ...existing.config, auth: { provider: providerId } }
|
|
5273
|
+
: { url: RADIUS_MCP_URL, auth: { provider: providerId } };
|
|
5274
|
+
// `auth` replaces the MCP OAuth sign-in.
|
|
5275
|
+
delete config.oauth;
|
|
5276
|
+
this.showSelector((done) => {
|
|
5277
|
+
const selector = new ExtensionSelectorComponent(`Configure ${providerName} MCP in ${mcpPath}?`, ["Yes", "No"], (option) => {
|
|
5278
|
+
done();
|
|
5279
|
+
if (option !== "Yes")
|
|
5280
|
+
return;
|
|
5281
|
+
try {
|
|
5282
|
+
addMcpServerConfig(mcpPath, name, config);
|
|
5283
|
+
}
|
|
5284
|
+
catch (error) {
|
|
5285
|
+
this.showError(`Could not update ${mcpPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
5286
|
+
return;
|
|
5287
|
+
}
|
|
5288
|
+
// The MCP extension reads mcp.json when the session starts.
|
|
5289
|
+
void this.handleReloadCommand();
|
|
5290
|
+
}, () => {
|
|
5291
|
+
done();
|
|
5292
|
+
this.ui.requestRender();
|
|
5293
|
+
});
|
|
5294
|
+
return { component: selector, focus: selector };
|
|
5295
|
+
});
|
|
5296
|
+
}
|
|
5178
5297
|
// =========================================================================
|
|
5179
5298
|
// Command handlers
|
|
5180
5299
|
// =========================================================================
|
|
@@ -5667,6 +5786,8 @@ export class InteractiveMode {
|
|
|
5667
5786
|
this.ui.requestRender();
|
|
5668
5787
|
}
|
|
5669
5788
|
handleArminSaysHi() {
|
|
5789
|
+
if (playArmin3d(this.renderer))
|
|
5790
|
+
return;
|
|
5670
5791
|
this.chatContainer.addChild(new Spacer(1));
|
|
5671
5792
|
this.chatContainer.addChild(new ArminComponent(this.ui));
|
|
5672
5793
|
this.ui.requestRender();
|
|
@@ -5676,16 +5797,6 @@ export class InteractiveMode {
|
|
|
5676
5797
|
this.chatContainer.addChild(new EarendilAnnouncementComponent());
|
|
5677
5798
|
this.ui.requestRender();
|
|
5678
5799
|
}
|
|
5679
|
-
handleDaxnuts() {
|
|
5680
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
5681
|
-
this.chatContainer.addChild(new DaxnutsComponent(this.ui));
|
|
5682
|
-
this.ui.requestRender();
|
|
5683
|
-
}
|
|
5684
|
-
checkDaxnutsEasterEgg(model) {
|
|
5685
|
-
if (model.provider === "opencode" && model.id.toLowerCase().includes("kimi-k2.5")) {
|
|
5686
|
-
this.handleDaxnuts();
|
|
5687
|
-
}
|
|
5688
|
-
}
|
|
5689
5800
|
async handleBashCommand(command, excludeFromContext = false) {
|
|
5690
5801
|
const extensionRunner = this.session.extensionRunner;
|
|
5691
5802
|
// Emit user_bash event to let extensions intercept
|