hoomanjs 1.32.0 → 1.34.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/README.md +81 -264
- package/dist/acp/sessions/options.js +2 -2
- package/dist/acp/sessions/options.js.map +1 -1
- package/dist/acp/utils/tool-kind.js +1 -1
- package/dist/acp/utils/tool-kind.js.map +1 -1
- package/dist/acp/utils/tool-locations.js +1 -1
- package/dist/acp/utils/tool-locations.js.map +1 -1
- package/dist/chat/app.js +5 -19
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/components/ChromePicker.js +1 -1
- package/dist/chat/components/ChromePicker.js.map +1 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/configure/app.js +1000 -387
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/index.js.map +1 -1
- package/dist/configure/types.d.ts +18 -0
- package/dist/core/agent/index.js +6 -4
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/config.d.ts +310 -80
- package/dist/core/config.js +93 -209
- package/dist/core/config.js.map +1 -1
- package/dist/core/mcp/manager.js +1 -1
- package/dist/core/mcp/manager.js.map +1 -1
- package/dist/core/mcp/oauth/provider.js.map +1 -1
- package/dist/core/mcp/prefixed-mcp-tool.d.ts +0 -1
- package/dist/core/mcp/prefixed-mcp-tool.js +0 -2
- package/dist/core/mcp/prefixed-mcp-tool.js.map +1 -1
- package/dist/core/models/anthropic.d.ts +3 -12
- package/dist/core/models/anthropic.js +20 -91
- package/dist/core/models/anthropic.js.map +1 -1
- package/dist/core/models/azure.d.ts +4 -0
- package/dist/core/models/azure.js +26 -0
- package/dist/core/models/azure.js.map +1 -0
- package/dist/core/models/bedrock.d.ts +3 -20
- package/dist/core/models/bedrock.js +22 -18
- package/dist/core/models/bedrock.js.map +1 -1
- package/dist/core/models/google.d.ts +2 -9
- package/dist/core/models/google.js +12 -31
- package/dist/core/models/google.js.map +1 -1
- package/dist/core/models/groq.d.ts +2 -9
- package/dist/core/models/groq.js +15 -25
- package/dist/core/models/groq.js.map +1 -1
- package/dist/core/models/index.d.ts +2 -1
- package/dist/core/models/index.js +3 -0
- package/dist/core/models/index.js.map +1 -1
- package/dist/core/models/minimax.d.ts +2 -0
- package/dist/core/models/minimax.js +11 -0
- package/dist/core/models/minimax.js.map +1 -0
- package/dist/core/models/moonshot.d.ts +2 -10
- package/dist/core/models/moonshot.js +23 -38
- package/dist/core/models/moonshot.js.map +1 -1
- package/dist/core/models/ollama/index.d.ts +2 -1
- package/dist/core/models/ollama/index.js +14 -3
- package/dist/core/models/ollama/index.js.map +1 -1
- package/dist/core/models/openai.d.ts +3 -4
- package/dist/core/models/openai.js +20 -3
- package/dist/core/models/openai.js.map +1 -1
- package/dist/core/models/openrouter.d.ts +4 -0
- package/dist/core/models/openrouter.js +23 -0
- package/dist/core/models/openrouter.js.map +1 -0
- package/dist/core/models/types.d.ts +346 -0
- package/dist/core/models/types.js +220 -0
- package/dist/core/models/types.js.map +1 -0
- package/dist/core/models/xai.d.ts +2 -9
- package/dist/core/models/xai.js +15 -25
- package/dist/core/models/xai.js.map +1 -1
- package/dist/core/modes/definitions.js +2 -2
- package/dist/core/modes/definitions.js.map +1 -1
- package/dist/core/prompts/harness/behaviour.md +10 -16
- package/dist/core/prompts/harness/communication.md +10 -19
- package/dist/core/prompts/harness/execution.md +8 -22
- package/dist/core/prompts/harness/guardrails.md +11 -18
- package/dist/core/prompts/modes/ask.md +6 -17
- package/dist/core/prompts/modes/plan.md +8 -25
- package/dist/core/prompts/runtime.js +2 -1
- package/dist/core/prompts/runtime.js.map +1 -1
- package/dist/core/prompts/static/filesystem.md +6 -36
- package/dist/core/prompts/static/planning.md +9 -32
- package/dist/core/prompts/static/shell.md +7 -30
- package/dist/core/prompts/static/skills.md +5 -16
- package/dist/core/prompts/static/web-search.md +6 -41
- package/dist/core/ripgrep/bootstrap.d.ts +1 -0
- package/dist/core/ripgrep/bootstrap.js +191 -0
- package/dist/core/ripgrep/bootstrap.js.map +1 -0
- package/dist/core/ripgrep/exec.d.ts +38 -0
- package/dist/core/ripgrep/exec.js +320 -0
- package/dist/core/ripgrep/exec.js.map +1 -0
- package/dist/core/ripgrep/index.d.ts +2 -0
- package/dist/core/ripgrep/index.js +3 -0
- package/dist/core/ripgrep/index.js.map +1 -0
- package/dist/core/ripgrep/tool.d.ts +18 -0
- package/dist/core/ripgrep/tool.js +101 -0
- package/dist/core/ripgrep/tool.js.map +1 -0
- package/dist/core/skills/built-in/hooman-config/SKILL.md +87 -193
- package/dist/core/state/tool-approvals.js +1 -1
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/subagents/research.js +1 -1
- package/dist/core/subagents/research.js.map +1 -1
- package/dist/core/subagents/runner.js +1 -1
- package/dist/core/subagents/runner.js.map +1 -1
- package/dist/core/tools/filesystem.d.ts +0 -5
- package/dist/core/tools/filesystem.js +4 -69
- package/dist/core/tools/filesystem.js.map +1 -1
- package/dist/core/tools/grep.d.ts +1 -0
- package/dist/core/tools/grep.js +2 -0
- package/dist/core/tools/grep.js.map +1 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/shell.js.map +1 -1
- package/dist/core/utils/paths.d.ts +3 -0
- package/dist/core/utils/paths.js +3 -0
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/core/utils/ripgrep.d.ts +1 -0
- package/dist/core/utils/ripgrep.js +2 -0
- package/dist/core/utils/ripgrep.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/configure/app.js
CHANGED
|
@@ -3,14 +3,14 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { Box, Text, useApp, useInput } from "ink";
|
|
5
5
|
import { LlmProvider, } from "../core/config.js";
|
|
6
|
-
import { McpOAuthConfigSchema
|
|
6
|
+
import { McpOAuthConfigSchema } from "../core/mcp/oauth/types.js";
|
|
7
7
|
import { McpTransportSchema, } from "../core/mcp/types.js";
|
|
8
|
-
import { instructionsMdPath
|
|
8
|
+
import { instructionsMdPath } from "../core/utils/paths.js";
|
|
9
9
|
import { BusyScreen } from "./components/BusyScreen.js";
|
|
10
10
|
import { MenuScreen } from "./components/MenuScreen.js";
|
|
11
11
|
import { PromptForm } from "./components/PromptForm.js";
|
|
12
12
|
import { openFileInEditor } from "./open-in-editor.js";
|
|
13
|
-
import { DEFAULT_INSTRUCTIONS, compactJson, folderNameForSkill, paramsPreview, normalizeOptional, noticeColor, parseOptionalBoolean, parseNumber,
|
|
13
|
+
import { DEFAULT_INSTRUCTIONS, compactJson, folderNameForSkill, paramsPreview, normalizeOptional, noticeColor, parseOptionalBoolean, parseNumber, maskSensitiveParamsForDisplay, parseStringArray, parseStringRecord, transportSummary, truncate, } from "./utils.js";
|
|
14
14
|
const PROMPT_LABELS = {
|
|
15
15
|
behaviour: "Behaviour",
|
|
16
16
|
communication: "Communication",
|
|
@@ -24,36 +24,496 @@ const SEARCH_PROVIDER_LABELS = {
|
|
|
24
24
|
serper: "Serper",
|
|
25
25
|
tavily: "Tavily",
|
|
26
26
|
};
|
|
27
|
+
const MCP_STDIO_FIELDS = [
|
|
28
|
+
{ key: "name", label: "Server name", placeholder: "filesystem" },
|
|
29
|
+
{ key: "command", label: "Command", placeholder: "npx" },
|
|
30
|
+
{
|
|
31
|
+
key: "args",
|
|
32
|
+
label: "Arguments",
|
|
33
|
+
placeholder: '["-y", "@modelcontextprotocol/server-filesystem"]',
|
|
34
|
+
note: "Provide a JSON array of strings, or leave as [].",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: "env",
|
|
38
|
+
label: "Environment variables",
|
|
39
|
+
placeholder: '{"API_KEY":"..."}',
|
|
40
|
+
note: "Optional JSON object with string values.",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "cwd",
|
|
44
|
+
label: "Working directory",
|
|
45
|
+
placeholder: "/absolute/path",
|
|
46
|
+
note: "Optional working directory for the subprocess.",
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
const MCP_REMOTE_BASE_FIELDS = [
|
|
50
|
+
{ key: "name", label: "Server name", placeholder: "my-remote-server" },
|
|
51
|
+
{ key: "url", label: "URL", placeholder: "https://example.com/mcp" },
|
|
52
|
+
{
|
|
53
|
+
key: "headers",
|
|
54
|
+
label: "Headers",
|
|
55
|
+
placeholder: '{"Authorization":"Bearer ..."}',
|
|
56
|
+
note: "Optional JSON object with string values.",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
key: "oauthEnabled",
|
|
60
|
+
label: "Enable OAuth? (yes/no)",
|
|
61
|
+
placeholder: "no",
|
|
62
|
+
note: "Choose yes for servers that use OAuth 2.0/2.1 or dynamic client registration.",
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
const MCP_REMOTE_OAUTH_FIELDS = [
|
|
66
|
+
{ key: "clientId", label: "OAuth client ID", placeholder: "client-id" },
|
|
67
|
+
{
|
|
68
|
+
key: "clientSecret",
|
|
69
|
+
label: "OAuth client secret",
|
|
70
|
+
placeholder: "secret",
|
|
71
|
+
note: "Stored in mcp.json only if you enter a value.",
|
|
72
|
+
},
|
|
73
|
+
{ key: "scopes", label: "OAuth scopes", placeholder: '["read","write"]' },
|
|
74
|
+
{
|
|
75
|
+
key: "audiences",
|
|
76
|
+
label: "OAuth audiences",
|
|
77
|
+
placeholder: '["https://api.example.com"]',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: "callbackPort",
|
|
81
|
+
label: "OAuth callback port",
|
|
82
|
+
placeholder: "19876",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key: "redirectUri",
|
|
86
|
+
label: "OAuth redirect URI",
|
|
87
|
+
placeholder: "http://127.0.0.1:19876/mcp/oauth/callback",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
key: "issuer",
|
|
91
|
+
label: "OAuth issuer",
|
|
92
|
+
placeholder: "https://auth.example.com",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "authorizationUrl",
|
|
96
|
+
label: "OAuth authorization URL override",
|
|
97
|
+
placeholder: "https://auth.example.com/authorize",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: "tokenUrl",
|
|
101
|
+
label: "OAuth token URL override",
|
|
102
|
+
placeholder: "https://auth.example.com/token",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
key: "registrationUrl",
|
|
106
|
+
label: "OAuth registration URL override",
|
|
107
|
+
placeholder: "https://auth.example.com/register",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: "tokenParamName",
|
|
111
|
+
label: "OAuth token param name",
|
|
112
|
+
placeholder: "access_token",
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
function isTruthyToggle(value) {
|
|
116
|
+
const normalized = value?.trim().toLowerCase();
|
|
117
|
+
return normalized !== undefined
|
|
118
|
+
? ["y", "yes", "true", "1", "on"].includes(normalized)
|
|
119
|
+
: false;
|
|
120
|
+
}
|
|
121
|
+
function formatDraftFieldValue(field, value) {
|
|
122
|
+
const normalized = value ?? "";
|
|
123
|
+
if (!normalized.trim()) {
|
|
124
|
+
return "not set";
|
|
125
|
+
}
|
|
126
|
+
if (field.key === "clientSecret" ||
|
|
127
|
+
field.key === "env" ||
|
|
128
|
+
field.key === "headers") {
|
|
129
|
+
return paramsPreview(normalized);
|
|
130
|
+
}
|
|
131
|
+
return truncate(normalized, 44);
|
|
132
|
+
}
|
|
27
133
|
const SUPPORTED_PROVIDER_TYPES = [
|
|
28
134
|
LlmProvider.Anthropic,
|
|
135
|
+
LlmProvider.Azure,
|
|
29
136
|
LlmProvider.Bedrock,
|
|
30
137
|
LlmProvider.Google,
|
|
31
138
|
LlmProvider.Groq,
|
|
139
|
+
LlmProvider.Minimax,
|
|
32
140
|
LlmProvider.Moonshot,
|
|
33
141
|
LlmProvider.Ollama,
|
|
34
142
|
LlmProvider.OpenAI,
|
|
143
|
+
LlmProvider.OpenRouter,
|
|
35
144
|
LlmProvider.Xai,
|
|
36
145
|
];
|
|
37
|
-
|
|
146
|
+
const DEFAULT_MODEL_BY_PROVIDER = {
|
|
147
|
+
[LlmProvider.Anthropic]: "claude-sonnet-4-6",
|
|
148
|
+
[LlmProvider.Azure]: "gpt-5.4-mini",
|
|
149
|
+
[LlmProvider.Bedrock]: "anthropic.claude-sonnet-4-6",
|
|
150
|
+
[LlmProvider.Google]: "gemini-2.5-flash",
|
|
151
|
+
[LlmProvider.Groq]: "openai/gpt-oss-20b",
|
|
152
|
+
[LlmProvider.Minimax]: "MiniMax-M3",
|
|
153
|
+
[LlmProvider.Moonshot]: "kimi-k2.7-code",
|
|
154
|
+
[LlmProvider.Ollama]: "gemma4:e4b",
|
|
155
|
+
[LlmProvider.OpenAI]: "gpt-5.5",
|
|
156
|
+
[LlmProvider.OpenRouter]: "google/gemma-4-26b-a4b-it:free",
|
|
157
|
+
[LlmProvider.Xai]: "grok-4.3",
|
|
158
|
+
};
|
|
159
|
+
function defaultModelForProviderType(provider) {
|
|
160
|
+
return DEFAULT_MODEL_BY_PROVIDER[provider];
|
|
161
|
+
}
|
|
162
|
+
function providerOptionsTemplate(provider) {
|
|
38
163
|
switch (provider) {
|
|
39
164
|
case LlmProvider.Anthropic:
|
|
40
165
|
return { apiKey: "" };
|
|
166
|
+
case LlmProvider.Azure:
|
|
167
|
+
return {};
|
|
41
168
|
case LlmProvider.Bedrock:
|
|
42
169
|
return { region: "us-west-2" };
|
|
43
170
|
case LlmProvider.Google:
|
|
44
171
|
return { apiKey: "" };
|
|
45
172
|
case LlmProvider.Groq:
|
|
46
173
|
return { apiKey: "" };
|
|
174
|
+
case LlmProvider.Minimax:
|
|
175
|
+
return { apiKey: "" };
|
|
47
176
|
case LlmProvider.Moonshot:
|
|
48
177
|
return { apiKey: "" };
|
|
49
178
|
case LlmProvider.Ollama:
|
|
50
179
|
return {};
|
|
51
180
|
case LlmProvider.OpenAI:
|
|
52
181
|
return { apiKey: "" };
|
|
182
|
+
case LlmProvider.OpenRouter:
|
|
183
|
+
return { apiKey: "" };
|
|
53
184
|
case LlmProvider.Xai:
|
|
54
185
|
return { apiKey: "" };
|
|
55
186
|
}
|
|
56
187
|
}
|
|
188
|
+
const PROVIDER_FIELD_DEFINITIONS = {
|
|
189
|
+
[LlmProvider.Anthropic]: [
|
|
190
|
+
{
|
|
191
|
+
key: "apiKey",
|
|
192
|
+
label: "API key",
|
|
193
|
+
kind: "string",
|
|
194
|
+
placeholder: "sk-ant-...",
|
|
195
|
+
sensitive: true,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: "baseURL",
|
|
199
|
+
label: "Base URL",
|
|
200
|
+
kind: "string",
|
|
201
|
+
placeholder: "https://api.anthropic.com",
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
key: "headers",
|
|
205
|
+
label: "Headers",
|
|
206
|
+
kind: "stringRecord",
|
|
207
|
+
placeholder: '{"x-my-header":"value"}',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "thinking",
|
|
211
|
+
label: "Thinking",
|
|
212
|
+
kind: "anthropicThinking",
|
|
213
|
+
placeholder: "adaptive",
|
|
214
|
+
note: 'Allowed: "disabled", "adaptive", or blank to clear.',
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
[LlmProvider.Azure]: [
|
|
218
|
+
{
|
|
219
|
+
key: "resourceName",
|
|
220
|
+
label: "Resource name",
|
|
221
|
+
kind: "string",
|
|
222
|
+
placeholder: "your-resource-name",
|
|
223
|
+
note: "Used to build the Azure OpenAI base URL when `baseURL` is not set.",
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
key: "baseURL",
|
|
227
|
+
label: "Base URL",
|
|
228
|
+
kind: "string",
|
|
229
|
+
placeholder: "https://your-resource-name.openai.azure.com/openai",
|
|
230
|
+
note: "Optional override for the Azure OpenAI endpoint prefix. When set, it takes precedence over `resourceName`.",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
key: "apiKey",
|
|
234
|
+
label: "API key",
|
|
235
|
+
kind: "string",
|
|
236
|
+
placeholder: "...",
|
|
237
|
+
sensitive: true,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: "headers",
|
|
241
|
+
label: "Headers",
|
|
242
|
+
kind: "stringRecord",
|
|
243
|
+
placeholder: '{"x-my-header":"value"}',
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
key: "apiVersion",
|
|
247
|
+
label: "API version",
|
|
248
|
+
kind: "string",
|
|
249
|
+
placeholder: "preview",
|
|
250
|
+
note: "Leave blank to use the AI SDK default API version.",
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
key: "useDeploymentBasedUrls",
|
|
254
|
+
label: "Deployment-based URLs",
|
|
255
|
+
kind: "optionalBoolean",
|
|
256
|
+
placeholder: "false",
|
|
257
|
+
note: "Allowed: yes/no/true/false. Leave blank to use the AI SDK default.",
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
[LlmProvider.Bedrock]: [
|
|
261
|
+
{
|
|
262
|
+
key: "region",
|
|
263
|
+
label: "Region",
|
|
264
|
+
kind: "string",
|
|
265
|
+
placeholder: "us-west-2",
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
key: "credentials",
|
|
269
|
+
label: "Static credentials",
|
|
270
|
+
kind: "bedrockCredentials",
|
|
271
|
+
note: "Set both access key ID and secret access key together, or leave blank to rely on the AWS default credential chain.",
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
key: "sessionToken",
|
|
275
|
+
label: "Session token",
|
|
276
|
+
kind: "string",
|
|
277
|
+
placeholder: "...",
|
|
278
|
+
sensitive: true,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
key: "apiKey",
|
|
282
|
+
label: "API key",
|
|
283
|
+
kind: "string",
|
|
284
|
+
placeholder: "...",
|
|
285
|
+
sensitive: true,
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
[LlmProvider.Google]: [
|
|
289
|
+
{
|
|
290
|
+
key: "apiKey",
|
|
291
|
+
label: "API key",
|
|
292
|
+
kind: "string",
|
|
293
|
+
placeholder: "...",
|
|
294
|
+
sensitive: true,
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
[LlmProvider.Groq]: [
|
|
298
|
+
{
|
|
299
|
+
key: "apiKey",
|
|
300
|
+
label: "API key",
|
|
301
|
+
kind: "string",
|
|
302
|
+
placeholder: "gsk_...",
|
|
303
|
+
sensitive: true,
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
key: "baseURL",
|
|
307
|
+
label: "Base URL",
|
|
308
|
+
kind: "string",
|
|
309
|
+
placeholder: "https://api.groq.com/openai/v1",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
key: "headers",
|
|
313
|
+
label: "Headers",
|
|
314
|
+
kind: "stringRecord",
|
|
315
|
+
placeholder: '{"x-my-header":"value"}',
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
[LlmProvider.Minimax]: [
|
|
319
|
+
{
|
|
320
|
+
key: "apiKey",
|
|
321
|
+
label: "API key",
|
|
322
|
+
kind: "string",
|
|
323
|
+
placeholder: "...",
|
|
324
|
+
sensitive: true,
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
key: "headers",
|
|
328
|
+
label: "Headers",
|
|
329
|
+
kind: "stringRecord",
|
|
330
|
+
placeholder: '{"x-my-header":"value"}',
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
key: "thinking",
|
|
334
|
+
label: "Thinking",
|
|
335
|
+
kind: "anthropicThinking",
|
|
336
|
+
placeholder: "adaptive",
|
|
337
|
+
note: 'Allowed: "disabled", "adaptive", or blank to clear.',
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
[LlmProvider.Moonshot]: [
|
|
341
|
+
{
|
|
342
|
+
key: "apiKey",
|
|
343
|
+
label: "API key",
|
|
344
|
+
kind: "string",
|
|
345
|
+
placeholder: "...",
|
|
346
|
+
sensitive: true,
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
key: "baseURL",
|
|
350
|
+
label: "Base URL",
|
|
351
|
+
kind: "string",
|
|
352
|
+
placeholder: "https://api.moonshot.ai/v1",
|
|
353
|
+
note: "Leave blank to use the default Moonshot API base URL.",
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
key: "headers",
|
|
357
|
+
label: "Headers",
|
|
358
|
+
kind: "stringRecord",
|
|
359
|
+
placeholder: '{"x-my-header":"value"}',
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
[LlmProvider.Ollama]: [
|
|
363
|
+
{
|
|
364
|
+
key: "baseURL",
|
|
365
|
+
label: "Base URL",
|
|
366
|
+
kind: "string",
|
|
367
|
+
placeholder: "http://127.0.0.1:11434",
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
key: "thinking",
|
|
371
|
+
label: "Thinking",
|
|
372
|
+
kind: "ollamaThinking",
|
|
373
|
+
placeholder: "medium",
|
|
374
|
+
note: 'Allowed: yes/no/true/false or "high", "medium", "low". Leave blank to clear.',
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
[LlmProvider.OpenAI]: [
|
|
378
|
+
{
|
|
379
|
+
key: "apiKey",
|
|
380
|
+
label: "API key",
|
|
381
|
+
kind: "string",
|
|
382
|
+
placeholder: "sk-...",
|
|
383
|
+
sensitive: true,
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
key: "baseURL",
|
|
387
|
+
label: "Base URL",
|
|
388
|
+
kind: "string",
|
|
389
|
+
placeholder: "https://api.openai.com/v1",
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
key: "headers",
|
|
393
|
+
label: "Headers",
|
|
394
|
+
kind: "stringRecord",
|
|
395
|
+
placeholder: '{"x-my-header":"value"}',
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
[LlmProvider.OpenRouter]: [
|
|
399
|
+
{
|
|
400
|
+
key: "apiKey",
|
|
401
|
+
label: "API key",
|
|
402
|
+
kind: "string",
|
|
403
|
+
placeholder: "sk-or-...",
|
|
404
|
+
sensitive: true,
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
key: "baseURL",
|
|
408
|
+
label: "Base URL",
|
|
409
|
+
kind: "string",
|
|
410
|
+
placeholder: "https://openrouter.ai/api/v1",
|
|
411
|
+
note: "Leave blank to use the default OpenRouter API base URL.",
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
key: "headers",
|
|
415
|
+
label: "Headers",
|
|
416
|
+
kind: "stringRecord",
|
|
417
|
+
placeholder: '{"HTTP-Referer":"https://example.com","X-Title":"Hooman"}',
|
|
418
|
+
note: "Optional extra headers such as attribution metadata for OpenRouter.",
|
|
419
|
+
},
|
|
420
|
+
],
|
|
421
|
+
[LlmProvider.Xai]: [
|
|
422
|
+
{
|
|
423
|
+
key: "apiKey",
|
|
424
|
+
label: "API key",
|
|
425
|
+
kind: "string",
|
|
426
|
+
placeholder: "...",
|
|
427
|
+
sensitive: true,
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
key: "baseURL",
|
|
431
|
+
label: "Base URL",
|
|
432
|
+
kind: "string",
|
|
433
|
+
placeholder: "https://api.x.ai/v1",
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
key: "headers",
|
|
437
|
+
label: "Headers",
|
|
438
|
+
kind: "stringRecord",
|
|
439
|
+
placeholder: '{"x-my-header":"value"}',
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
};
|
|
443
|
+
const LLM_FIELD_DEFINITIONS = [
|
|
444
|
+
{
|
|
445
|
+
key: "temperature",
|
|
446
|
+
label: "Temperature",
|
|
447
|
+
kind: "optionalNumber",
|
|
448
|
+
placeholder: "0.7",
|
|
449
|
+
note: "Leave blank to clear.",
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
key: "maxTokens",
|
|
453
|
+
label: "Max tokens",
|
|
454
|
+
kind: "optionalInteger",
|
|
455
|
+
placeholder: "4096",
|
|
456
|
+
note: "Leave blank to clear.",
|
|
457
|
+
},
|
|
458
|
+
];
|
|
459
|
+
function formatTypedFieldValue(definition, value) {
|
|
460
|
+
if (value === undefined) {
|
|
461
|
+
return "not set";
|
|
462
|
+
}
|
|
463
|
+
if (definition.sensitive) {
|
|
464
|
+
return "[REDACTED]";
|
|
465
|
+
}
|
|
466
|
+
if (definition.kind === "bedrockCredentials") {
|
|
467
|
+
return value ? "[REDACTED]" : "not set";
|
|
468
|
+
}
|
|
469
|
+
if (definition.kind === "stringRecord") {
|
|
470
|
+
return paramsPreview(value);
|
|
471
|
+
}
|
|
472
|
+
return truncate(String(value), 44);
|
|
473
|
+
}
|
|
474
|
+
function parseTypedFieldValue(input, definition) {
|
|
475
|
+
switch (definition.kind) {
|
|
476
|
+
case "string":
|
|
477
|
+
return normalizeOptional(input);
|
|
478
|
+
case "stringRecord":
|
|
479
|
+
return parseStringRecord(input, definition.label);
|
|
480
|
+
case "optionalBoolean":
|
|
481
|
+
return parseOptionalBoolean(input, definition.label);
|
|
482
|
+
case "optionalNumber":
|
|
483
|
+
return normalizeOptional(input) === undefined
|
|
484
|
+
? undefined
|
|
485
|
+
: parseNumber(input, definition.label);
|
|
486
|
+
case "optionalInteger":
|
|
487
|
+
return normalizeOptional(input) === undefined
|
|
488
|
+
? undefined
|
|
489
|
+
: parseNumber(input, definition.label, {
|
|
490
|
+
integer: true,
|
|
491
|
+
min: 1,
|
|
492
|
+
});
|
|
493
|
+
case "bedrockCredentials":
|
|
494
|
+
return undefined;
|
|
495
|
+
case "anthropicThinking": {
|
|
496
|
+
const value = normalizeOptional(input);
|
|
497
|
+
if (value === undefined) {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
if (value === "disabled" || value === "adaptive") {
|
|
501
|
+
return value;
|
|
502
|
+
}
|
|
503
|
+
throw new Error(`${definition.label} must be "disabled" or "adaptive".`);
|
|
504
|
+
}
|
|
505
|
+
case "ollamaThinking": {
|
|
506
|
+
const value = normalizeOptional(input);
|
|
507
|
+
if (value === undefined) {
|
|
508
|
+
return undefined;
|
|
509
|
+
}
|
|
510
|
+
if (value === "high" || value === "medium" || value === "low") {
|
|
511
|
+
return value;
|
|
512
|
+
}
|
|
513
|
+
return parseOptionalBoolean(value, definition.label);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
57
517
|
/** On/off display for tool rows (`Tool • Yes` / `Tool • No`). */
|
|
58
518
|
const yesNo = (on) => (on ? "Yes" : "No");
|
|
59
519
|
export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, }) {
|
|
@@ -63,6 +523,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
63
523
|
const [notice, setNotice] = useState(null);
|
|
64
524
|
const [busyMessage, setBusyMessage] = useState(null);
|
|
65
525
|
const [revision, setRevision] = useState(0);
|
|
526
|
+
const [mcpDraft, setMcpDraft] = useState(null);
|
|
66
527
|
const [installedSkills, setInstalledSkills] = useState([]);
|
|
67
528
|
const [searchResults, setSearchResults] = useState([]);
|
|
68
529
|
const [mcpAuthStatuses, setMcpAuthStatuses] = useState({});
|
|
@@ -138,6 +599,12 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
138
599
|
setPrompt(null);
|
|
139
600
|
return;
|
|
140
601
|
}
|
|
602
|
+
if (screen.kind === "mcp-stdio-edit" ||
|
|
603
|
+
screen.kind === "mcp-remote-edit") {
|
|
604
|
+
setMcpDraft(null);
|
|
605
|
+
setScreen({ kind: "mcp" });
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
141
608
|
if (screen.kind === "mcp-delete-confirm") {
|
|
142
609
|
setScreen({ kind: "mcp" });
|
|
143
610
|
return;
|
|
@@ -154,9 +621,21 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
154
621
|
setScreen({ kind: "config-provider-edit", name: screen.name });
|
|
155
622
|
return;
|
|
156
623
|
}
|
|
624
|
+
if (screen.kind === "config-provider-anthropic-thinking" ||
|
|
625
|
+
screen.kind === "config-provider-ollama-thinking") {
|
|
626
|
+
setScreen({ kind: "config-provider-edit", name: screen.name });
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (screen.kind === "config-provider-add-type") {
|
|
630
|
+
setScreen({ kind: "config-providers" });
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
157
633
|
if (screen.kind !== "home") {
|
|
158
634
|
setScreen({ kind: "home" });
|
|
635
|
+
return;
|
|
159
636
|
}
|
|
637
|
+
onExit();
|
|
638
|
+
exit();
|
|
160
639
|
}, { isActive: true });
|
|
161
640
|
const setSuccess = useCallback((text) => {
|
|
162
641
|
setNotice({ kind: "success", text });
|
|
@@ -180,21 +659,33 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
180
659
|
refresh();
|
|
181
660
|
setSuccess(message);
|
|
182
661
|
}, [config, refresh, setSuccess]);
|
|
183
|
-
const patchLlm = useCallback((name, patch) => config.llms.map((m) => m.name === name
|
|
662
|
+
const patchLlm = useCallback((name, patch) => config.llms.map((m) => m.name === name
|
|
663
|
+
? {
|
|
664
|
+
...m,
|
|
665
|
+
options: {
|
|
666
|
+
...m.options,
|
|
667
|
+
...patch,
|
|
668
|
+
},
|
|
669
|
+
}
|
|
670
|
+
: m), [config]);
|
|
184
671
|
const renameLlm = useCallback((oldName, newName) => config.llms.map((m) => m.name === oldName ? { ...m, name: newName } : m), [config]);
|
|
185
672
|
const setDefaultLlm = useCallback((name) => config.llms.map((m) => ({ ...m, default: m.name === name })), [config]);
|
|
186
|
-
const addLlm = useCallback((name) =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
673
|
+
const addLlm = useCallback((name) => {
|
|
674
|
+
const providerName = config.providers[0]?.name ?? "Ollama";
|
|
675
|
+
const providerType = config.providers.find((provider) => provider.name === providerName)
|
|
676
|
+
?.provider ?? LlmProvider.Ollama;
|
|
677
|
+
return [
|
|
678
|
+
...config.llms,
|
|
679
|
+
{
|
|
680
|
+
name,
|
|
681
|
+
provider: providerName,
|
|
682
|
+
options: {
|
|
683
|
+
model: defaultModelForProviderType(providerType),
|
|
684
|
+
},
|
|
685
|
+
default: false,
|
|
194
686
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
], [config]);
|
|
687
|
+
];
|
|
688
|
+
}, [config]);
|
|
198
689
|
const removeLlm = useCallback((name) => config.llms.filter((m) => m.name !== name), [config]);
|
|
199
690
|
const patchProvider = useCallback((name, patch) => config.providers.map((provider) => provider.name === name
|
|
200
691
|
? {
|
|
@@ -202,29 +693,25 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
202
693
|
options: {
|
|
203
694
|
...provider.options,
|
|
204
695
|
...patch,
|
|
205
|
-
params: patch.params ?? provider.options.params,
|
|
206
696
|
},
|
|
207
697
|
}
|
|
208
698
|
: provider), [config]);
|
|
209
699
|
const renameProvider = useCallback((oldName, newName) => ({
|
|
210
700
|
providers: config.providers.map((provider) => provider.name === oldName ? { ...provider, name: newName } : provider),
|
|
211
|
-
llms: config.llms.map((llm) => llm.
|
|
701
|
+
llms: config.llms.map((llm) => llm.provider === oldName
|
|
212
702
|
? {
|
|
213
703
|
...llm,
|
|
214
|
-
|
|
215
|
-
...llm.options,
|
|
216
|
-
provider: newName,
|
|
217
|
-
},
|
|
704
|
+
provider: newName,
|
|
218
705
|
}
|
|
219
706
|
: llm),
|
|
220
707
|
}), [config]);
|
|
221
|
-
const addProvider = useCallback((name) => [
|
|
708
|
+
const addProvider = useCallback((name, provider) => [
|
|
222
709
|
...config.providers,
|
|
223
710
|
{
|
|
224
711
|
name,
|
|
712
|
+
provider,
|
|
225
713
|
options: {
|
|
226
|
-
provider
|
|
227
|
-
params: providerParamsTemplate(LlmProvider.Ollama),
|
|
714
|
+
...providerOptionsTemplate(provider),
|
|
228
715
|
},
|
|
229
716
|
},
|
|
230
717
|
], [config]);
|
|
@@ -246,307 +733,173 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
246
733
|
});
|
|
247
734
|
}
|
|
248
735
|
}, [prompt]);
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
placeholder: "/absolute/path",
|
|
281
|
-
onSubmit: async (cwdValue) => {
|
|
282
|
-
const transport = McpTransportSchema.parse({
|
|
283
|
-
type: "stdio",
|
|
284
|
-
command,
|
|
285
|
-
...(args.length > 0 ? { args } : {}),
|
|
286
|
-
...(env && Object.keys(env).length > 0 ? { env } : {}),
|
|
287
|
-
...(normalizeOptional(cwdValue)
|
|
288
|
-
? { cwd: normalizeOptional(cwdValue) }
|
|
289
|
-
: {}),
|
|
290
|
-
});
|
|
291
|
-
if (initial) {
|
|
292
|
-
mcpConfig.update(name, transport);
|
|
293
|
-
setSuccess(`Updated MCP server "${name}".`);
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
mcpConfig.add(name, transport);
|
|
297
|
-
setSuccess(`Added MCP server "${name}".`);
|
|
298
|
-
}
|
|
299
|
-
setPrompt(null);
|
|
300
|
-
setScreen({ kind: "mcp" });
|
|
301
|
-
refresh();
|
|
302
|
-
},
|
|
303
|
-
});
|
|
304
|
-
},
|
|
305
|
-
});
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
},
|
|
736
|
+
const persistMcpTransport = useCallback((currentName, nextName, transport) => {
|
|
737
|
+
if (!nextName) {
|
|
738
|
+
throw new Error("Server name is required.");
|
|
739
|
+
}
|
|
740
|
+
if (currentName && currentName !== nextName && mcpConfig.get(nextName)) {
|
|
741
|
+
throw new Error(`MCP server "${nextName}" already exists.`);
|
|
742
|
+
}
|
|
743
|
+
if (!currentName) {
|
|
744
|
+
mcpConfig.add(nextName, transport);
|
|
745
|
+
setSuccess(`Added MCP server "${nextName}".`);
|
|
746
|
+
}
|
|
747
|
+
else if (currentName === nextName) {
|
|
748
|
+
mcpConfig.update(currentName, transport);
|
|
749
|
+
setSuccess(`Updated MCP server "${currentName}".`);
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
mcpConfig.add(nextName, transport);
|
|
753
|
+
mcpConfig.remove(currentName);
|
|
754
|
+
setSuccess(`Renamed MCP server "${currentName}" to "${nextName}".`);
|
|
755
|
+
}
|
|
756
|
+
setMcpDraft(null);
|
|
757
|
+
setScreen({ kind: "mcp" });
|
|
758
|
+
refresh();
|
|
759
|
+
}, [mcpConfig, refresh, setSuccess]);
|
|
760
|
+
const openMcpStdioEditor = useCallback((currentName, initial) => {
|
|
761
|
+
setMcpDraft({
|
|
762
|
+
name: currentName ?? "",
|
|
763
|
+
command: initial?.command ?? "",
|
|
764
|
+
args: compactJson(initial?.args ?? []),
|
|
765
|
+
env: initial?.env ? compactJson(initial.env) : "",
|
|
766
|
+
cwd: initial?.cwd ?? "",
|
|
309
767
|
});
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
title: `${mode} ${type} server`,
|
|
339
|
-
label: "OAuth client ID (optional)",
|
|
340
|
-
initialValue: initial?.oauth?.clientId ?? "",
|
|
341
|
-
placeholder: "client-id",
|
|
342
|
-
onSubmit: async (clientIdValue) => {
|
|
343
|
-
promptValue({
|
|
344
|
-
title: `${mode} ${type} server`,
|
|
345
|
-
label: "OAuth client secret (optional)",
|
|
346
|
-
initialValue: initial?.oauth?.clientSecret ?? "",
|
|
347
|
-
placeholder: "secret",
|
|
348
|
-
note: "Stored in mcp.json only if you enter a value.",
|
|
349
|
-
onSubmit: async (clientSecretValue) => {
|
|
350
|
-
promptValue({
|
|
351
|
-
title: `${mode} ${type} server`,
|
|
352
|
-
label: "OAuth scopes (optional)",
|
|
353
|
-
initialValue: initial?.oauth?.scopes
|
|
354
|
-
? compactJson(initial.oauth.scopes)
|
|
355
|
-
: "",
|
|
356
|
-
placeholder: '["read","write"]',
|
|
357
|
-
onSubmit: async (scopesValue) => {
|
|
358
|
-
promptValue({
|
|
359
|
-
title: `${mode} ${type} server`,
|
|
360
|
-
label: "OAuth audiences (optional)",
|
|
361
|
-
initialValue: initial?.oauth?.audiences
|
|
362
|
-
? compactJson(initial.oauth.audiences)
|
|
363
|
-
: "",
|
|
364
|
-
placeholder: '["https://api.example.com"]',
|
|
365
|
-
onSubmit: async (audiencesValue) => {
|
|
366
|
-
promptValue({
|
|
367
|
-
title: `${mode} ${type} server`,
|
|
368
|
-
label: "OAuth callback port (optional)",
|
|
369
|
-
initialValue: initial?.oauth?.callbackPort !== undefined
|
|
370
|
-
? String(initial.oauth.callbackPort)
|
|
371
|
-
: "",
|
|
372
|
-
placeholder: "19876",
|
|
373
|
-
onSubmit: async (callbackPortValue) => {
|
|
374
|
-
promptValue({
|
|
375
|
-
title: `${mode} ${type} server`,
|
|
376
|
-
label: "OAuth redirect URI (optional)",
|
|
377
|
-
initialValue: initial?.oauth?.redirectUri ?? "",
|
|
378
|
-
placeholder: "http://127.0.0.1:19876/mcp/oauth/callback",
|
|
379
|
-
onSubmit: async (redirectUriValue) => {
|
|
380
|
-
promptValue({
|
|
381
|
-
title: `${mode} ${type} server`,
|
|
382
|
-
label: "OAuth issuer (optional)",
|
|
383
|
-
initialValue: initial?.oauth?.issuer ?? "",
|
|
384
|
-
placeholder: "https://auth.example.com",
|
|
385
|
-
onSubmit: async (issuerValue) => {
|
|
386
|
-
promptValue({
|
|
387
|
-
title: `${mode} ${type} server`,
|
|
388
|
-
label: "OAuth authorization URL override (optional)",
|
|
389
|
-
initialValue: initial?.oauth?.authorizationUrl ?? "",
|
|
390
|
-
placeholder: "https://auth.example.com/authorize",
|
|
391
|
-
onSubmit: async (authorizationUrlValue) => {
|
|
392
|
-
promptValue({
|
|
393
|
-
title: `${mode} ${type} server`,
|
|
394
|
-
label: "OAuth token URL override (optional)",
|
|
395
|
-
initialValue: initial?.oauth?.tokenUrl ?? "",
|
|
396
|
-
placeholder: "https://auth.example.com/token",
|
|
397
|
-
onSubmit: async (tokenUrlValue) => {
|
|
398
|
-
promptValue({
|
|
399
|
-
title: `${mode} ${type} server`,
|
|
400
|
-
label: "OAuth registration URL override (optional)",
|
|
401
|
-
initialValue: initial?.oauth
|
|
402
|
-
?.registrationUrl ?? "",
|
|
403
|
-
placeholder: "https://auth.example.com/register",
|
|
404
|
-
onSubmit: async (registrationUrlValue) => {
|
|
405
|
-
promptValue({
|
|
406
|
-
title: `${mode} ${type} server`,
|
|
407
|
-
label: "OAuth token param name (optional)",
|
|
408
|
-
initialValue: initial?.oauth
|
|
409
|
-
?.tokenParamName ?? "",
|
|
410
|
-
placeholder: "access_token",
|
|
411
|
-
onSubmit: async (tokenParamNameValue) => {
|
|
412
|
-
const scopes = parseStringArray(scopesValue, "OAuth scopes");
|
|
413
|
-
const audiences = parseStringArray(audiencesValue, "OAuth audiences");
|
|
414
|
-
const callbackPort = normalizeOptional(callbackPortValue) !== undefined
|
|
415
|
-
? parseNumber(callbackPortValue, "OAuth callback port", {
|
|
416
|
-
integer: true,
|
|
417
|
-
min: 1,
|
|
418
|
-
max: 65535,
|
|
419
|
-
})
|
|
420
|
-
: undefined;
|
|
421
|
-
const oauth = McpOAuthConfigSchema.parse({
|
|
422
|
-
enabled: true,
|
|
423
|
-
...(normalizeOptional(clientIdValue)
|
|
424
|
-
? {
|
|
425
|
-
clientId: normalizeOptional(clientIdValue),
|
|
426
|
-
}
|
|
427
|
-
: {}),
|
|
428
|
-
...(normalizeOptional(clientSecretValue)
|
|
429
|
-
? {
|
|
430
|
-
clientSecret: normalizeOptional(clientSecretValue),
|
|
431
|
-
}
|
|
432
|
-
: {}),
|
|
433
|
-
...(scopes.length > 0
|
|
434
|
-
? { scopes }
|
|
435
|
-
: {}),
|
|
436
|
-
...(audiences.length >
|
|
437
|
-
0
|
|
438
|
-
? { audiences }
|
|
439
|
-
: {}),
|
|
440
|
-
...(callbackPort !==
|
|
441
|
-
undefined
|
|
442
|
-
? { callbackPort }
|
|
443
|
-
: {}),
|
|
444
|
-
...(normalizeOptional(redirectUriValue)
|
|
445
|
-
? {
|
|
446
|
-
redirectUri: normalizeOptional(redirectUriValue),
|
|
447
|
-
}
|
|
448
|
-
: {}),
|
|
449
|
-
...(normalizeOptional(issuerValue)
|
|
450
|
-
? {
|
|
451
|
-
issuer: normalizeOptional(issuerValue),
|
|
452
|
-
}
|
|
453
|
-
: {}),
|
|
454
|
-
...(normalizeOptional(authorizationUrlValue)
|
|
455
|
-
? {
|
|
456
|
-
authorizationUrl: normalizeOptional(authorizationUrlValue),
|
|
457
|
-
}
|
|
458
|
-
: {}),
|
|
459
|
-
...(normalizeOptional(tokenUrlValue)
|
|
460
|
-
? {
|
|
461
|
-
tokenUrl: normalizeOptional(tokenUrlValue),
|
|
462
|
-
}
|
|
463
|
-
: {}),
|
|
464
|
-
...(normalizeOptional(registrationUrlValue)
|
|
465
|
-
? {
|
|
466
|
-
registrationUrl: normalizeOptional(registrationUrlValue),
|
|
467
|
-
}
|
|
468
|
-
: {}),
|
|
469
|
-
...(normalizeOptional(tokenParamNameValue)
|
|
470
|
-
? {
|
|
471
|
-
tokenParamName: normalizeOptional(tokenParamNameValue),
|
|
472
|
-
}
|
|
473
|
-
: {}),
|
|
474
|
-
});
|
|
475
|
-
persistRemote(url, headers, oauth);
|
|
476
|
-
},
|
|
477
|
-
});
|
|
478
|
-
},
|
|
479
|
-
});
|
|
480
|
-
},
|
|
481
|
-
});
|
|
482
|
-
},
|
|
483
|
-
});
|
|
484
|
-
},
|
|
485
|
-
});
|
|
486
|
-
},
|
|
487
|
-
});
|
|
488
|
-
},
|
|
489
|
-
});
|
|
490
|
-
},
|
|
491
|
-
});
|
|
492
|
-
},
|
|
493
|
-
});
|
|
494
|
-
},
|
|
495
|
-
});
|
|
496
|
-
},
|
|
497
|
-
});
|
|
498
|
-
};
|
|
499
|
-
promptValue({
|
|
500
|
-
title: `${mode} ${type} server`,
|
|
501
|
-
label: "URL",
|
|
502
|
-
initialValue: initial?.url ?? "",
|
|
503
|
-
placeholder: "https://example.com/mcp",
|
|
504
|
-
onSubmit: async (urlValue) => {
|
|
505
|
-
const url = urlValue.trim();
|
|
506
|
-
if (!url) {
|
|
507
|
-
throw new Error("URL is required.");
|
|
508
|
-
}
|
|
509
|
-
promptValue({
|
|
510
|
-
title: `${mode} ${type} server`,
|
|
511
|
-
label: "Headers (optional)",
|
|
512
|
-
initialValue: initial?.headers ? compactJson(initial.headers) : "",
|
|
513
|
-
placeholder: '{"Authorization":"Bearer ..."}',
|
|
514
|
-
onSubmit: async (headersValue) => {
|
|
515
|
-
const headers = parseStringRecord(headersValue, "Headers");
|
|
516
|
-
promptValue({
|
|
517
|
-
title: `${mode} ${type} server`,
|
|
518
|
-
label: "Enable OAuth? (yes/no)",
|
|
519
|
-
initialValue: initial?.oauth ? "yes" : "no",
|
|
520
|
-
placeholder: "no",
|
|
521
|
-
note: "Choose yes for servers that use OAuth 2.0/2.1 or dynamic client registration.",
|
|
522
|
-
onSubmit: async (oauthEnabledValue) => {
|
|
523
|
-
const oauthEnabled = parseOptionalBoolean(oauthEnabledValue, "Enable OAuth");
|
|
524
|
-
promptForOAuthDetails(url, headers, oauthEnabled);
|
|
525
|
-
},
|
|
526
|
-
});
|
|
527
|
-
},
|
|
528
|
-
});
|
|
529
|
-
},
|
|
768
|
+
setScreen({ kind: "mcp-stdio-edit", originalName: currentName });
|
|
769
|
+
}, []);
|
|
770
|
+
const openMcpRemoteEditor = useCallback((type, currentName, initial) => {
|
|
771
|
+
setMcpDraft({
|
|
772
|
+
name: currentName ?? "",
|
|
773
|
+
url: initial?.url ?? "",
|
|
774
|
+
headers: initial?.headers ? compactJson(initial.headers) : "",
|
|
775
|
+
oauthEnabled: initial?.oauth ? "yes" : "no",
|
|
776
|
+
clientId: initial?.oauth?.clientId ?? "",
|
|
777
|
+
clientSecret: initial?.oauth?.clientSecret ?? "",
|
|
778
|
+
scopes: initial?.oauth?.scopes ? compactJson(initial.oauth.scopes) : "",
|
|
779
|
+
audiences: initial?.oauth?.audiences
|
|
780
|
+
? compactJson(initial.oauth.audiences)
|
|
781
|
+
: "",
|
|
782
|
+
callbackPort: initial?.oauth?.callbackPort !== undefined
|
|
783
|
+
? String(initial.oauth.callbackPort)
|
|
784
|
+
: "",
|
|
785
|
+
redirectUri: initial?.oauth?.redirectUri ?? "",
|
|
786
|
+
issuer: initial?.oauth?.issuer ?? "",
|
|
787
|
+
authorizationUrl: initial?.oauth?.authorizationUrl ?? "",
|
|
788
|
+
tokenUrl: initial?.oauth?.tokenUrl ?? "",
|
|
789
|
+
registrationUrl: initial?.oauth?.registrationUrl ?? "",
|
|
790
|
+
tokenParamName: initial?.oauth?.tokenParamName ?? "",
|
|
791
|
+
});
|
|
792
|
+
setScreen({
|
|
793
|
+
kind: "mcp-remote-edit",
|
|
794
|
+
transportType: type,
|
|
795
|
+
originalName: currentName,
|
|
530
796
|
});
|
|
531
|
-
}, [
|
|
532
|
-
const
|
|
797
|
+
}, []);
|
|
798
|
+
const updateMcpDraftField = useCallback((key, value) => {
|
|
799
|
+
setMcpDraft((current) => current ? { ...current, [key]: value } : current);
|
|
800
|
+
}, []);
|
|
801
|
+
const editMcpDraftField = useCallback((field, initialValue) => {
|
|
533
802
|
promptValue({
|
|
534
|
-
title: `
|
|
535
|
-
label:
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (type === "stdio") {
|
|
543
|
-
promptForStdio(name);
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
promptForRemote(name, type);
|
|
803
|
+
title: `Update ${field.label}`,
|
|
804
|
+
label: field.label,
|
|
805
|
+
initialValue,
|
|
806
|
+
placeholder: field.placeholder,
|
|
807
|
+
note: field.note,
|
|
808
|
+
onSubmit: async (value) => {
|
|
809
|
+
updateMcpDraftField(field.key, value);
|
|
810
|
+
setPrompt(null);
|
|
547
811
|
},
|
|
548
812
|
});
|
|
549
|
-
}, [
|
|
813
|
+
}, [promptValue, updateMcpDraftField]);
|
|
814
|
+
const saveMcpStdioDraft = useCallback((originalName) => {
|
|
815
|
+
const values = mcpDraft ?? {};
|
|
816
|
+
const name = (values.name ?? "").trim();
|
|
817
|
+
const command = (values.command ?? "").trim();
|
|
818
|
+
if (!name) {
|
|
819
|
+
throw new Error("Server name is required.");
|
|
820
|
+
}
|
|
821
|
+
if (!command) {
|
|
822
|
+
throw new Error("Command is required.");
|
|
823
|
+
}
|
|
824
|
+
const args = parseStringArray(values.args ?? "", "Arguments");
|
|
825
|
+
const env = parseStringRecord(values.env ?? "", "Environment variables");
|
|
826
|
+
const cwd = normalizeOptional(values.cwd ?? "");
|
|
827
|
+
const transport = McpTransportSchema.parse({
|
|
828
|
+
type: "stdio",
|
|
829
|
+
command,
|
|
830
|
+
...(args.length > 0 ? { args } : {}),
|
|
831
|
+
...(env && Object.keys(env).length > 0 ? { env } : {}),
|
|
832
|
+
...(cwd ? { cwd } : {}),
|
|
833
|
+
});
|
|
834
|
+
persistMcpTransport(originalName, name, transport);
|
|
835
|
+
}, [mcpDraft, persistMcpTransport]);
|
|
836
|
+
const saveMcpRemoteDraft = useCallback((transportType, originalName) => {
|
|
837
|
+
const values = mcpDraft ?? {};
|
|
838
|
+
const name = (values.name ?? "").trim();
|
|
839
|
+
const url = (values.url ?? "").trim();
|
|
840
|
+
if (!name) {
|
|
841
|
+
throw new Error("Server name is required.");
|
|
842
|
+
}
|
|
843
|
+
if (!url) {
|
|
844
|
+
throw new Error("URL is required.");
|
|
845
|
+
}
|
|
846
|
+
const headers = parseStringRecord(values.headers ?? "", "Headers");
|
|
847
|
+
const oauthEnabled = parseOptionalBoolean(values.oauthEnabled ?? "", "Enable OAuth");
|
|
848
|
+
const scopes = parseStringArray(values.scopes ?? "", "OAuth scopes");
|
|
849
|
+
const audiences = parseStringArray(values.audiences ?? "", "OAuth audiences");
|
|
850
|
+
const callbackPort = normalizeOptional(values.callbackPort ?? "") !== undefined
|
|
851
|
+
? parseNumber(values.callbackPort ?? "", "OAuth callback port", {
|
|
852
|
+
integer: true,
|
|
853
|
+
min: 1,
|
|
854
|
+
max: 65535,
|
|
855
|
+
})
|
|
856
|
+
: undefined;
|
|
857
|
+
const oauth = oauthEnabled
|
|
858
|
+
? McpOAuthConfigSchema.parse({
|
|
859
|
+
enabled: true,
|
|
860
|
+
...(normalizeOptional(values.clientId ?? "")
|
|
861
|
+
? { clientId: normalizeOptional(values.clientId ?? "") }
|
|
862
|
+
: {}),
|
|
863
|
+
...(normalizeOptional(values.clientSecret ?? "")
|
|
864
|
+
? { clientSecret: normalizeOptional(values.clientSecret ?? "") }
|
|
865
|
+
: {}),
|
|
866
|
+
...(scopes.length > 0 ? { scopes } : {}),
|
|
867
|
+
...(audiences.length > 0 ? { audiences } : {}),
|
|
868
|
+
...(callbackPort !== undefined ? { callbackPort } : {}),
|
|
869
|
+
...(normalizeOptional(values.redirectUri ?? "")
|
|
870
|
+
? { redirectUri: normalizeOptional(values.redirectUri ?? "") }
|
|
871
|
+
: {}),
|
|
872
|
+
...(normalizeOptional(values.issuer ?? "")
|
|
873
|
+
? { issuer: normalizeOptional(values.issuer ?? "") }
|
|
874
|
+
: {}),
|
|
875
|
+
...(normalizeOptional(values.authorizationUrl ?? "")
|
|
876
|
+
? {
|
|
877
|
+
authorizationUrl: normalizeOptional(values.authorizationUrl ?? ""),
|
|
878
|
+
}
|
|
879
|
+
: {}),
|
|
880
|
+
...(normalizeOptional(values.tokenUrl ?? "")
|
|
881
|
+
? { tokenUrl: normalizeOptional(values.tokenUrl ?? "") }
|
|
882
|
+
: {}),
|
|
883
|
+
...(normalizeOptional(values.registrationUrl ?? "")
|
|
884
|
+
? {
|
|
885
|
+
registrationUrl: normalizeOptional(values.registrationUrl ?? ""),
|
|
886
|
+
}
|
|
887
|
+
: {}),
|
|
888
|
+
...(normalizeOptional(values.tokenParamName ?? "")
|
|
889
|
+
? {
|
|
890
|
+
tokenParamName: normalizeOptional(values.tokenParamName ?? ""),
|
|
891
|
+
}
|
|
892
|
+
: {}),
|
|
893
|
+
})
|
|
894
|
+
: undefined;
|
|
895
|
+
const transport = McpTransportSchema.parse({
|
|
896
|
+
type: transportType,
|
|
897
|
+
url,
|
|
898
|
+
...(headers && Object.keys(headers).length > 0 ? { headers } : {}),
|
|
899
|
+
...(oauth ? { oauth } : {}),
|
|
900
|
+
});
|
|
901
|
+
persistMcpTransport(originalName, name, transport);
|
|
902
|
+
}, [mcpDraft, persistMcpTransport]);
|
|
550
903
|
const llmSummary = useCallback((entry) => {
|
|
551
904
|
const compactModelId = (model) => {
|
|
552
905
|
if (model.length <= 23) {
|
|
@@ -556,16 +909,17 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
556
909
|
};
|
|
557
910
|
const resolved = config.resolveLlm(entry.name);
|
|
558
911
|
if (!resolved) {
|
|
559
|
-
return `${entry.
|
|
912
|
+
return `${entry.provider}/${compactModelId(entry.options.model)}`;
|
|
560
913
|
}
|
|
561
|
-
return `${entry.
|
|
914
|
+
return `${entry.provider} -> ${resolved.provider}/${compactModelId(resolved.llmOptions.model)}`;
|
|
562
915
|
}, [config]);
|
|
563
|
-
const providerUsageCount = useCallback((name) => config.llms.filter((llm) => llm.
|
|
916
|
+
const providerUsageCount = useCallback((name) => config.llms.filter((llm) => llm.provider === name).length, [config]);
|
|
564
917
|
const renderHome = () => {
|
|
918
|
+
const defaultLlm = config.llms.find((m) => m.default) ?? config.llms[0];
|
|
565
919
|
const items = [
|
|
566
920
|
{
|
|
567
|
-
label: "
|
|
568
|
-
value: () => setScreen({ kind: "config" }),
|
|
921
|
+
label: "General",
|
|
922
|
+
value: () => setScreen({ kind: "config-general" }),
|
|
569
923
|
},
|
|
570
924
|
{
|
|
571
925
|
label: "Instructions • edit instructions.md",
|
|
@@ -590,6 +944,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
590
944
|
}
|
|
591
945
|
},
|
|
592
946
|
},
|
|
947
|
+
{
|
|
948
|
+
label: defaultLlm ? `Models • ${defaultLlm.name}` : "Models",
|
|
949
|
+
value: () => setScreen({ kind: "config" }),
|
|
950
|
+
},
|
|
593
951
|
{
|
|
594
952
|
label: `MCP servers • ${mcpServers.length} configured`,
|
|
595
953
|
value: () => setScreen({ kind: "mcp" }),
|
|
@@ -599,16 +957,16 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
599
957
|
value: () => setScreen({ kind: "skills" }),
|
|
600
958
|
},
|
|
601
959
|
{
|
|
602
|
-
label: "
|
|
960
|
+
label: "Back",
|
|
603
961
|
value: () => {
|
|
604
962
|
onExit();
|
|
605
963
|
exit();
|
|
606
964
|
},
|
|
607
965
|
},
|
|
608
966
|
];
|
|
609
|
-
return (_jsx(MenuScreen, { title: configData.name, description: `
|
|
967
|
+
return (_jsx(MenuScreen, { title: configData.name, description: `models: ${llmSummary(config.llms.find((m) => m.default) ?? config.llms[0])}`, items: items, footerHint: "enter: select | esc: back" }));
|
|
610
968
|
};
|
|
611
|
-
const
|
|
969
|
+
const renderGeneralMenu = () => {
|
|
612
970
|
const enabledPrompts = Object.values(configData.prompts).filter(Boolean).length;
|
|
613
971
|
const totalPrompts = Object.keys(configData.prompts).length;
|
|
614
972
|
const items = [
|
|
@@ -628,17 +986,6 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
628
986
|
},
|
|
629
987
|
}),
|
|
630
988
|
},
|
|
631
|
-
{
|
|
632
|
-
label: (() => {
|
|
633
|
-
const def = config.llms.find((m) => m.default) ?? config.llms[0];
|
|
634
|
-
return `LLMs • ${config.llms.length} configured (default: ${def.name})`;
|
|
635
|
-
})(),
|
|
636
|
-
value: () => setScreen({ kind: "config-llms" }),
|
|
637
|
-
},
|
|
638
|
-
{
|
|
639
|
-
label: `Providers • ${config.providers.length} configured`,
|
|
640
|
-
value: () => setScreen({ kind: "config-providers" }),
|
|
641
|
-
},
|
|
642
989
|
{
|
|
643
990
|
label: `Prompts • ${enabledPrompts}/${totalPrompts} enabled`,
|
|
644
991
|
value: () => setScreen({ kind: "config-prompts" }),
|
|
@@ -694,7 +1041,25 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
694
1041
|
value: () => setScreen({ kind: "home" }),
|
|
695
1042
|
},
|
|
696
1043
|
];
|
|
697
|
-
return (_jsx(MenuScreen, { title: "
|
|
1044
|
+
return (_jsx(MenuScreen, { title: "General", description: "Manage app-wide settings loaded from ~/.hooman/config.json.", items: items }));
|
|
1045
|
+
};
|
|
1046
|
+
const renderConfigMenu = () => {
|
|
1047
|
+
const defaultLlm = config.llms.find((m) => m.default) ?? config.llms[0];
|
|
1048
|
+
const items = [
|
|
1049
|
+
{
|
|
1050
|
+
label: `LLMs • ${config.llms.length} configured (default: ${defaultLlm.name})`,
|
|
1051
|
+
value: () => setScreen({ kind: "config-llms" }),
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
label: `Providers • ${config.providers.length} configured`,
|
|
1055
|
+
value: () => setScreen({ kind: "config-providers" }),
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
label: "Back",
|
|
1059
|
+
value: () => setScreen({ kind: "home" }),
|
|
1060
|
+
},
|
|
1061
|
+
];
|
|
1062
|
+
return (_jsx(MenuScreen, { title: "Models", description: "Manage configured providers and LLMs from ~/.hooman/config.json.", items: items }));
|
|
698
1063
|
};
|
|
699
1064
|
const renderToolsConfigMenu = () => {
|
|
700
1065
|
const items = [
|
|
@@ -789,7 +1154,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
789
1154
|
},
|
|
790
1155
|
{
|
|
791
1156
|
label: "Back",
|
|
792
|
-
value: () => setScreen({ kind: "config" }),
|
|
1157
|
+
value: () => setScreen({ kind: "config-general" }),
|
|
793
1158
|
},
|
|
794
1159
|
];
|
|
795
1160
|
return (_jsx(MenuScreen, { title: "Tools", description: "Enable, disable, and configure built-in tools.", items: items }));
|
|
@@ -797,7 +1162,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
797
1162
|
const renderProvidersMenu = () => {
|
|
798
1163
|
const providerItems = config.providers.map((provider) => ({
|
|
799
1164
|
key: `provider:${provider.name}`,
|
|
800
|
-
label: `${provider.name} • ${provider.
|
|
1165
|
+
label: `${provider.name} • ${provider.provider} • ${providerUsageCount(provider.name)} model(s)`,
|
|
801
1166
|
boldSubstring: provider.name,
|
|
802
1167
|
value: () => setScreen({ kind: "config-provider-edit", name: provider.name }),
|
|
803
1168
|
}));
|
|
@@ -816,9 +1181,8 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
816
1181
|
if (config.providers.some((provider) => provider.name === name)) {
|
|
817
1182
|
throw new Error(`A provider named "${name}" already exists.`);
|
|
818
1183
|
}
|
|
819
|
-
updateConfig({ providers: addProvider(name) }, `Added provider "${name}" with an Ollama scaffold.`);
|
|
820
1184
|
setPrompt(null);
|
|
821
|
-
setScreen({ kind: "config-provider-
|
|
1185
|
+
setScreen({ kind: "config-provider-add-type", name });
|
|
822
1186
|
},
|
|
823
1187
|
}),
|
|
824
1188
|
},
|
|
@@ -840,6 +1204,8 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
840
1204
|
return null;
|
|
841
1205
|
}
|
|
842
1206
|
const usageCount = providerUsageCount(entry.name);
|
|
1207
|
+
const providerFields = PROVIDER_FIELD_DEFINITIONS[entry.provider];
|
|
1208
|
+
const providerOptions = entry.options;
|
|
843
1209
|
const items = [
|
|
844
1210
|
{
|
|
845
1211
|
label: `Name • ${entry.name}`,
|
|
@@ -866,23 +1232,90 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
866
1232
|
}),
|
|
867
1233
|
},
|
|
868
1234
|
{
|
|
869
|
-
label: `Type • ${entry.
|
|
1235
|
+
label: `Type • ${entry.provider}`,
|
|
870
1236
|
value: () => setScreen({ kind: "config-provider-type", name: entry.name }),
|
|
871
1237
|
},
|
|
872
|
-
{
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1238
|
+
...providerFields.map((definition) => ({
|
|
1239
|
+
key: `provider-field:${entry.name}:${definition.key}`,
|
|
1240
|
+
label: `${definition.label} • ${formatTypedFieldValue(definition, definition.kind === "bedrockCredentials"
|
|
1241
|
+
? providerOptions.accessKeyId && providerOptions.secretAccessKey
|
|
1242
|
+
: providerOptions[definition.key])}`,
|
|
1243
|
+
value: () => {
|
|
1244
|
+
if (definition.kind === "anthropicThinking") {
|
|
1245
|
+
setScreen({
|
|
1246
|
+
kind: "config-provider-anthropic-thinking",
|
|
1247
|
+
name: entry.name,
|
|
1248
|
+
});
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
if (definition.kind === "ollamaThinking") {
|
|
1252
|
+
setScreen({
|
|
1253
|
+
kind: "config-provider-ollama-thinking",
|
|
1254
|
+
name: entry.name,
|
|
1255
|
+
});
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
if (definition.kind === "bedrockCredentials") {
|
|
1259
|
+
promptValue({
|
|
1260
|
+
title: "Update static credentials",
|
|
1261
|
+
label: "Access key ID",
|
|
1262
|
+
initialValue: typeof providerOptions.accessKeyId === "string"
|
|
1263
|
+
? providerOptions.accessKeyId
|
|
1264
|
+
: "",
|
|
1265
|
+
placeholder: "AKIA...",
|
|
1266
|
+
note: definition.note,
|
|
1267
|
+
onSubmit: async (accessKeyIdValue) => {
|
|
1268
|
+
promptValue({
|
|
1269
|
+
title: "Update static credentials",
|
|
1270
|
+
label: "Secret access key",
|
|
1271
|
+
initialValue: typeof providerOptions.secretAccessKey === "string"
|
|
1272
|
+
? providerOptions.secretAccessKey
|
|
1273
|
+
: "",
|
|
1274
|
+
placeholder: "...",
|
|
1275
|
+
onSubmit: async (secretAccessKeyValue) => {
|
|
1276
|
+
const accessKeyId = normalizeOptional(accessKeyIdValue);
|
|
1277
|
+
const secretAccessKey = normalizeOptional(secretAccessKeyValue);
|
|
1278
|
+
if ((accessKeyId === undefined) !==
|
|
1279
|
+
(secretAccessKey === undefined)) {
|
|
1280
|
+
throw new Error("Access key ID and secret access key must be provided together.");
|
|
1281
|
+
}
|
|
1282
|
+
updateConfig({
|
|
1283
|
+
providers: patchProvider(entry.name, {
|
|
1284
|
+
accessKeyId,
|
|
1285
|
+
secretAccessKey,
|
|
1286
|
+
}),
|
|
1287
|
+
}, `Updated static credentials for "${entry.name}".`);
|
|
1288
|
+
setPrompt(null);
|
|
1289
|
+
},
|
|
1290
|
+
});
|
|
1291
|
+
},
|
|
1292
|
+
});
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
promptValue({
|
|
1296
|
+
title: `Update ${definition.label}`,
|
|
1297
|
+
label: definition.label,
|
|
1298
|
+
initialValue: definition.kind === "stringRecord"
|
|
1299
|
+
? providerOptions[definition.key]
|
|
1300
|
+
? compactJson(providerOptions[definition.key])
|
|
1301
|
+
: ""
|
|
1302
|
+
: providerOptions[definition.key] !== undefined
|
|
1303
|
+
? String(providerOptions[definition.key])
|
|
1304
|
+
: "",
|
|
1305
|
+
placeholder: definition.placeholder,
|
|
1306
|
+
note: definition.note,
|
|
1307
|
+
onSubmit: async (value) => {
|
|
1308
|
+
const nextValue = parseTypedFieldValue(value, definition);
|
|
1309
|
+
updateConfig({
|
|
1310
|
+
providers: patchProvider(entry.name, {
|
|
1311
|
+
[definition.key]: nextValue,
|
|
1312
|
+
}),
|
|
1313
|
+
}, `Updated ${definition.label.toLowerCase()} for "${entry.name}".`);
|
|
1314
|
+
setPrompt(null);
|
|
1315
|
+
},
|
|
1316
|
+
});
|
|
1317
|
+
},
|
|
1318
|
+
})),
|
|
886
1319
|
...(usageCount > 0
|
|
887
1320
|
? []
|
|
888
1321
|
: [
|
|
@@ -904,6 +1337,75 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
904
1337
|
? `Used by ${usageCount} model(s). Rename updates references automatically; delete is disabled while in use.`
|
|
905
1338
|
: "Edit shared provider settings or delete this provider.", items: items }));
|
|
906
1339
|
};
|
|
1340
|
+
const renderAnthropicThinkingMenu = () => {
|
|
1341
|
+
if (screen.kind !== "config-provider-anthropic-thinking") {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1344
|
+
const entry = config.providers.find((provider) => provider.name === screen.name);
|
|
1345
|
+
if (!entry) {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
const current = "thinking" in entry.options ? entry.options.thinking : undefined;
|
|
1349
|
+
const items = [
|
|
1350
|
+
{
|
|
1351
|
+
label: current === undefined ? "Not set • current" : "Not set (clear value)",
|
|
1352
|
+
value: () => {
|
|
1353
|
+
updateConfig({ providers: patchProvider(entry.name, { thinking: undefined }) }, `Cleared thinking for "${entry.name}".`);
|
|
1354
|
+
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
1355
|
+
},
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
label: current === "disabled" ? "disabled • current" : "disabled",
|
|
1359
|
+
value: () => {
|
|
1360
|
+
updateConfig({ providers: patchProvider(entry.name, { thinking: "disabled" }) }, `Updated thinking for "${entry.name}" to "disabled".`);
|
|
1361
|
+
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
1362
|
+
},
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
label: current === "adaptive" ? "adaptive • current" : "adaptive",
|
|
1366
|
+
value: () => {
|
|
1367
|
+
updateConfig({ providers: patchProvider(entry.name, { thinking: "adaptive" }) }, `Updated thinking for "${entry.name}" to "adaptive".`);
|
|
1368
|
+
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
{
|
|
1372
|
+
label: "Back",
|
|
1373
|
+
value: () => setScreen({ kind: "config-provider-edit", name: entry.name }),
|
|
1374
|
+
},
|
|
1375
|
+
];
|
|
1376
|
+
return (_jsx(MenuScreen, { title: `Choose Thinking • ${entry.name}`, description: 'Pick one of the allowed values: "disabled", "adaptive", or clear it.', items: items }));
|
|
1377
|
+
};
|
|
1378
|
+
const renderOllamaThinkingMenu = () => {
|
|
1379
|
+
if (screen.kind !== "config-provider-ollama-thinking") {
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1382
|
+
const entry = config.providers.find((provider) => provider.name === screen.name);
|
|
1383
|
+
if (!entry) {
|
|
1384
|
+
return null;
|
|
1385
|
+
}
|
|
1386
|
+
const current = "thinking" in entry.options ? entry.options.thinking : undefined;
|
|
1387
|
+
const items = [
|
|
1388
|
+
{
|
|
1389
|
+
label: current === undefined ? "Not set • current" : "Not set (clear value)",
|
|
1390
|
+
value: () => {
|
|
1391
|
+
updateConfig({ providers: patchProvider(entry.name, { thinking: undefined }) }, `Cleared thinking for "${entry.name}".`);
|
|
1392
|
+
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
1393
|
+
},
|
|
1394
|
+
},
|
|
1395
|
+
...[false, true, "low", "medium", "high"].map((value) => ({
|
|
1396
|
+
label: current === value ? `${String(value)} • current` : String(value),
|
|
1397
|
+
value: () => {
|
|
1398
|
+
updateConfig({ providers: patchProvider(entry.name, { thinking: value }) }, `Updated thinking for "${entry.name}" to "${String(value)}".`);
|
|
1399
|
+
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
1400
|
+
},
|
|
1401
|
+
})),
|
|
1402
|
+
{
|
|
1403
|
+
label: "Back",
|
|
1404
|
+
value: () => setScreen({ kind: "config-provider-edit", name: entry.name }),
|
|
1405
|
+
},
|
|
1406
|
+
];
|
|
1407
|
+
return (_jsx(MenuScreen, { title: `Choose Thinking • ${entry.name}`, description: 'Pick one of the allowed values: clear, false, true, "low", "medium", or "high".', items: items }));
|
|
1408
|
+
};
|
|
907
1409
|
const renderProviderTypeMenu = () => {
|
|
908
1410
|
if (screen.kind !== "config-provider-type") {
|
|
909
1411
|
return null;
|
|
@@ -915,16 +1417,17 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
915
1417
|
}
|
|
916
1418
|
const items = [
|
|
917
1419
|
...SUPPORTED_PROVIDER_TYPES.map((provider) => ({
|
|
918
|
-
label: provider === entry.
|
|
919
|
-
? `${provider} • current`
|
|
920
|
-
: provider,
|
|
1420
|
+
label: provider === entry.provider ? `${provider} • current` : provider,
|
|
921
1421
|
value: () => {
|
|
922
1422
|
updateConfig({
|
|
923
|
-
providers:
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1423
|
+
providers: config.providers.map((item) => item.name === entry.name
|
|
1424
|
+
? {
|
|
1425
|
+
...item,
|
|
1426
|
+
provider,
|
|
1427
|
+
options: providerOptionsTemplate(provider),
|
|
1428
|
+
}
|
|
1429
|
+
: item),
|
|
1430
|
+
}, `Updated provider type for "${entry.name}" to "${provider}" and scaffolded options.`);
|
|
928
1431
|
setScreen({ kind: "config-provider-edit", name: entry.name });
|
|
929
1432
|
},
|
|
930
1433
|
})),
|
|
@@ -935,6 +1438,26 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
935
1438
|
];
|
|
936
1439
|
return (_jsx(MenuScreen, { title: `Choose Provider Type • ${entry.name}`, description: "Pick which runtime provider this shared config targets.", items: items }));
|
|
937
1440
|
};
|
|
1441
|
+
const renderProviderAddTypeMenu = () => {
|
|
1442
|
+
if (screen.kind !== "config-provider-add-type") {
|
|
1443
|
+
return null;
|
|
1444
|
+
}
|
|
1445
|
+
const { name } = screen;
|
|
1446
|
+
const items = [
|
|
1447
|
+
...SUPPORTED_PROVIDER_TYPES.map((provider) => ({
|
|
1448
|
+
label: provider,
|
|
1449
|
+
value: () => {
|
|
1450
|
+
updateConfig({ providers: addProvider(name, provider) }, `Added provider "${name}" as "${provider}".`);
|
|
1451
|
+
setScreen({ kind: "config-provider-edit", name });
|
|
1452
|
+
},
|
|
1453
|
+
})),
|
|
1454
|
+
{
|
|
1455
|
+
label: "Back",
|
|
1456
|
+
value: () => setScreen({ kind: "config-providers" }),
|
|
1457
|
+
},
|
|
1458
|
+
];
|
|
1459
|
+
return (_jsx(MenuScreen, { title: `Choose Provider Type • ${name}`, description: "Pick the runtime provider before creating this shared config.", items: items }));
|
|
1460
|
+
};
|
|
938
1461
|
const renderProviderDeleteConfirm = () => {
|
|
939
1462
|
if (screen.kind !== "config-provider-delete-confirm") {
|
|
940
1463
|
return null;
|
|
@@ -1007,6 +1530,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1007
1530
|
}
|
|
1008
1531
|
const isOnly = config.llms.length === 1;
|
|
1009
1532
|
const isDefault = entry.default;
|
|
1533
|
+
const llmOptions = entry.options;
|
|
1010
1534
|
const items = [
|
|
1011
1535
|
{
|
|
1012
1536
|
label: `Name • ${entry.name}`,
|
|
@@ -1033,7 +1557,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1033
1557
|
}),
|
|
1034
1558
|
},
|
|
1035
1559
|
{
|
|
1036
|
-
label: `Provider • ${entry.
|
|
1560
|
+
label: `Provider • ${entry.provider}`,
|
|
1037
1561
|
value: () => setScreen({ kind: "config-llm-provider", name: entry.name }),
|
|
1038
1562
|
},
|
|
1039
1563
|
{
|
|
@@ -1042,6 +1566,12 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1042
1566
|
title: "Update model id",
|
|
1043
1567
|
label: "Model",
|
|
1044
1568
|
initialValue: entry.options.model,
|
|
1569
|
+
note: (() => {
|
|
1570
|
+
const providerType = config.providers.find((provider) => provider.name === entry.provider)?.provider;
|
|
1571
|
+
return providerType
|
|
1572
|
+
? `Suggested default for ${providerType}: ${defaultModelForProviderType(providerType)}`
|
|
1573
|
+
: undefined;
|
|
1574
|
+
})(),
|
|
1045
1575
|
onSubmit: async (value) => {
|
|
1046
1576
|
const model = value.trim();
|
|
1047
1577
|
if (!model) {
|
|
@@ -1052,20 +1582,28 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1052
1582
|
},
|
|
1053
1583
|
}),
|
|
1054
1584
|
},
|
|
1055
|
-
{
|
|
1056
|
-
|
|
1585
|
+
...LLM_FIELD_DEFINITIONS.map((definition) => ({
|
|
1586
|
+
key: `llm-field:${entry.name}:${definition.key}`,
|
|
1587
|
+
label: `${definition.label} • ${formatTypedFieldValue(definition, llmOptions[definition.key])}`,
|
|
1057
1588
|
value: () => promptValue({
|
|
1058
|
-
title:
|
|
1059
|
-
label:
|
|
1060
|
-
initialValue:
|
|
1061
|
-
|
|
1589
|
+
title: `Update ${definition.label}`,
|
|
1590
|
+
label: definition.label,
|
|
1591
|
+
initialValue: llmOptions[definition.key] !== undefined
|
|
1592
|
+
? String(llmOptions[definition.key])
|
|
1593
|
+
: "",
|
|
1594
|
+
placeholder: definition.placeholder,
|
|
1595
|
+
note: definition.note,
|
|
1062
1596
|
onSubmit: async (value) => {
|
|
1063
|
-
const
|
|
1064
|
-
updateConfig({
|
|
1597
|
+
const nextValue = parseTypedFieldValue(value, definition);
|
|
1598
|
+
updateConfig({
|
|
1599
|
+
llms: patchLlm(entry.name, {
|
|
1600
|
+
[definition.key]: nextValue,
|
|
1601
|
+
}),
|
|
1602
|
+
}, `Updated ${definition.label.toLowerCase()} for "${entry.name}".`);
|
|
1065
1603
|
setPrompt(null);
|
|
1066
1604
|
},
|
|
1067
1605
|
}),
|
|
1068
|
-
},
|
|
1606
|
+
})),
|
|
1069
1607
|
{
|
|
1070
1608
|
label: isDefault ? "Default • yes" : "Set as default",
|
|
1071
1609
|
value: () => {
|
|
@@ -1109,11 +1647,22 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1109
1647
|
}
|
|
1110
1648
|
const items = [
|
|
1111
1649
|
...config.providers.map((provider) => ({
|
|
1112
|
-
label: provider.name === entry.
|
|
1650
|
+
label: provider.name === entry.provider
|
|
1113
1651
|
? `${provider.name} • current`
|
|
1114
|
-
: `${provider.name} • ${provider.
|
|
1652
|
+
: `${provider.name} • ${provider.provider}`,
|
|
1115
1653
|
value: () => {
|
|
1116
|
-
updateConfig({
|
|
1654
|
+
updateConfig({
|
|
1655
|
+
llms: config.llms.map((llm) => llm.name === entry.name
|
|
1656
|
+
? {
|
|
1657
|
+
...llm,
|
|
1658
|
+
provider: provider.name,
|
|
1659
|
+
options: {
|
|
1660
|
+
...llm.options,
|
|
1661
|
+
model: defaultModelForProviderType(provider.provider),
|
|
1662
|
+
},
|
|
1663
|
+
}
|
|
1664
|
+
: llm),
|
|
1665
|
+
}, `Updated provider for "${entry.name}" to "${provider.name}" and scaffolded its default model.`);
|
|
1117
1666
|
setScreen({ kind: "config-llm-edit", name: entry.name });
|
|
1118
1667
|
},
|
|
1119
1668
|
})),
|
|
@@ -1167,7 +1716,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1167
1716
|
}),
|
|
1168
1717
|
{
|
|
1169
1718
|
label: "Back",
|
|
1170
|
-
value: () => setScreen({ kind: "config-
|
|
1719
|
+
value: () => setScreen({ kind: "config-general" }),
|
|
1171
1720
|
},
|
|
1172
1721
|
];
|
|
1173
1722
|
return (_jsx(MenuScreen, { title: "Prompts", description: "Choose which bundled harness prompt sections are included in future sessions.", items: items }));
|
|
@@ -1248,6 +1797,58 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1248
1797
|
];
|
|
1249
1798
|
return (_jsx(MenuScreen, { title: "Search", description: "Configure web search provider and credentials.", items: items }));
|
|
1250
1799
|
};
|
|
1800
|
+
const renderMcpStdioEditMenu = () => {
|
|
1801
|
+
if (screen.kind !== "mcp-stdio-edit" || !mcpDraft) {
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
const items = [
|
|
1805
|
+
...MCP_STDIO_FIELDS.map((field) => ({
|
|
1806
|
+
key: `mcp-stdio:${field.key}`,
|
|
1807
|
+
label: `${field.label} • ${formatDraftFieldValue(field, mcpDraft[field.key])}`,
|
|
1808
|
+
value: () => editMcpDraftField(field, mcpDraft[field.key] ?? ""),
|
|
1809
|
+
})),
|
|
1810
|
+
{
|
|
1811
|
+
label: "Save",
|
|
1812
|
+
value: () => saveMcpStdioDraft(screen.originalName),
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
label: "Back",
|
|
1816
|
+
value: () => {
|
|
1817
|
+
setMcpDraft(null);
|
|
1818
|
+
setScreen({ kind: "mcp" });
|
|
1819
|
+
},
|
|
1820
|
+
},
|
|
1821
|
+
];
|
|
1822
|
+
return (_jsx(MenuScreen, { title: `${screen.originalName ? "Edit" : "Add"} stdio server`, description: "Select a field to edit, then save when you're done.", items: items }));
|
|
1823
|
+
};
|
|
1824
|
+
const renderMcpRemoteEditMenu = () => {
|
|
1825
|
+
if (screen.kind !== "mcp-remote-edit" || !mcpDraft) {
|
|
1826
|
+
return null;
|
|
1827
|
+
}
|
|
1828
|
+
const fields = [
|
|
1829
|
+
...MCP_REMOTE_BASE_FIELDS,
|
|
1830
|
+
...(isTruthyToggle(mcpDraft.oauthEnabled) ? MCP_REMOTE_OAUTH_FIELDS : []),
|
|
1831
|
+
];
|
|
1832
|
+
const items = [
|
|
1833
|
+
...fields.map((field) => ({
|
|
1834
|
+
key: `mcp-remote:${field.key}`,
|
|
1835
|
+
label: `${field.label} • ${formatDraftFieldValue(field, mcpDraft[field.key])}`,
|
|
1836
|
+
value: () => editMcpDraftField(field, mcpDraft[field.key] ?? ""),
|
|
1837
|
+
})),
|
|
1838
|
+
{
|
|
1839
|
+
label: "Save",
|
|
1840
|
+
value: () => saveMcpRemoteDraft(screen.transportType, screen.originalName),
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
label: "Back",
|
|
1844
|
+
value: () => {
|
|
1845
|
+
setMcpDraft(null);
|
|
1846
|
+
setScreen({ kind: "mcp" });
|
|
1847
|
+
},
|
|
1848
|
+
},
|
|
1849
|
+
];
|
|
1850
|
+
return (_jsx(MenuScreen, { title: `${screen.originalName ? "Edit" : "Add"} ${screen.transportType} server`, description: "Select a field to edit, then save when you're done.", items: items }));
|
|
1851
|
+
};
|
|
1251
1852
|
const renderMcpMenu = () => {
|
|
1252
1853
|
const serverItems = mcpServers.map((server) => {
|
|
1253
1854
|
const oauthStatus = mcpAuthStatuses[server.name];
|
|
@@ -1262,10 +1863,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1262
1863
|
: undefined,
|
|
1263
1864
|
value: () => {
|
|
1264
1865
|
if (server.transport.type === "stdio") {
|
|
1265
|
-
|
|
1866
|
+
openMcpStdioEditor(server.name, server.transport);
|
|
1266
1867
|
}
|
|
1267
1868
|
else {
|
|
1268
|
-
|
|
1869
|
+
openMcpRemoteEditor(server.transport.type, server.name, server.transport);
|
|
1269
1870
|
}
|
|
1270
1871
|
},
|
|
1271
1872
|
};
|
|
@@ -1273,15 +1874,15 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1273
1874
|
const items = [
|
|
1274
1875
|
{
|
|
1275
1876
|
label: "Add stdio server",
|
|
1276
|
-
value: () =>
|
|
1877
|
+
value: () => openMcpStdioEditor(),
|
|
1277
1878
|
},
|
|
1278
1879
|
{
|
|
1279
1880
|
label: "Add streamable HTTP server",
|
|
1280
|
-
value: () =>
|
|
1881
|
+
value: () => openMcpRemoteEditor("streamable-http"),
|
|
1281
1882
|
},
|
|
1282
1883
|
{
|
|
1283
1884
|
label: "Add SSE server",
|
|
1284
|
-
value: () =>
|
|
1885
|
+
value: () => openMcpRemoteEditor("sse"),
|
|
1285
1886
|
},
|
|
1286
1887
|
...serverItems,
|
|
1287
1888
|
{
|
|
@@ -1483,14 +2084,22 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1483
2084
|
switch (screen.kind) {
|
|
1484
2085
|
case "home":
|
|
1485
2086
|
return renderHome();
|
|
2087
|
+
case "config-general":
|
|
2088
|
+
return renderGeneralMenu();
|
|
1486
2089
|
case "config":
|
|
1487
2090
|
return renderConfigMenu();
|
|
1488
2091
|
case "config-providers":
|
|
1489
2092
|
return renderProvidersMenu();
|
|
2093
|
+
case "config-provider-add-type":
|
|
2094
|
+
return renderProviderAddTypeMenu();
|
|
1490
2095
|
case "config-provider-edit":
|
|
1491
2096
|
return renderProviderEditMenu();
|
|
1492
2097
|
case "config-provider-type":
|
|
1493
2098
|
return renderProviderTypeMenu();
|
|
2099
|
+
case "config-provider-anthropic-thinking":
|
|
2100
|
+
return renderAnthropicThinkingMenu();
|
|
2101
|
+
case "config-provider-ollama-thinking":
|
|
2102
|
+
return renderOllamaThinkingMenu();
|
|
1494
2103
|
case "config-provider-delete-confirm":
|
|
1495
2104
|
return renderProviderDeleteConfirm();
|
|
1496
2105
|
case "config-llms":
|
|
@@ -1511,6 +2120,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1511
2120
|
return renderSearchProviderMenu();
|
|
1512
2121
|
case "mcp":
|
|
1513
2122
|
return renderMcpMenu();
|
|
2123
|
+
case "mcp-stdio-edit":
|
|
2124
|
+
return renderMcpStdioEditMenu();
|
|
2125
|
+
case "mcp-remote-edit":
|
|
2126
|
+
return renderMcpRemoteEditMenu();
|
|
1514
2127
|
case "mcp-delete-confirm":
|
|
1515
2128
|
return renderMcpDeleteConfirm();
|
|
1516
2129
|
case "skills":
|