hoomanjs 1.43.1 → 1.45.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/dist/acp/acp-agent.d.ts +2 -1
- package/dist/acp/acp-agent.js +116 -7
- package/dist/acp/acp-agent.js.map +1 -1
- package/dist/chat/app.js +74 -14
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/components/RetryEvent.d.ts +4 -0
- package/dist/chat/components/RetryEvent.js +11 -0
- package/dist/chat/components/RetryEvent.js.map +1 -0
- package/dist/chat/components/Transcript.js +2 -1
- package/dist/chat/components/Transcript.js.map +1 -1
- package/dist/chat/types.d.ts +5 -1
- package/dist/cli.js +5 -6
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.js +469 -105
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/components/MenuScreen.d.ts +3 -2
- package/dist/configure/components/MenuScreen.js +6 -2
- package/dist/configure/components/MenuScreen.js.map +1 -1
- package/dist/configure/index.js +4 -3
- package/dist/configure/index.js.map +1 -1
- package/dist/configure/types.d.ts +15 -0
- package/dist/core/agent/default-retry-strategy.d.ts +7 -0
- package/dist/core/agent/default-retry-strategy.js +197 -0
- package/dist/core/agent/default-retry-strategy.js.map +1 -0
- package/dist/core/agent/index.js +2 -0
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/agent/retry-progress.d.ts +14 -0
- package/dist/core/agent/retry-progress.js +18 -0
- package/dist/core/agent/retry-progress.js.map +1 -0
- package/dist/core/approvals/intervention.js +10 -4
- package/dist/core/approvals/intervention.js.map +1 -1
- package/dist/core/mcp/config.d.ts +26 -3
- package/dist/core/mcp/config.js +126 -34
- package/dist/core/mcp/config.js.map +1 -1
- package/dist/core/prompts/modes/agent.md +6 -0
- package/dist/core/prompts/modes/plan.md +17 -0
- package/dist/core/prompts/session-mode-appendix.js +2 -1
- package/dist/core/prompts/session-mode-appendix.js.map +1 -1
- package/dist/core/prompts/static/todo.md +2 -0
- package/dist/core/runtime-config.js +4 -0
- package/dist/core/runtime-config.js.map +1 -1
- package/dist/core/sessions/flat-file-storage.d.ts +5 -0
- package/dist/core/sessions/flat-file-storage.js +42 -0
- package/dist/core/sessions/flat-file-storage.js.map +1 -1
- package/dist/core/state/tool-approvals.d.ts +5 -4
- package/dist/core/state/tool-approvals.js +18 -7
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/tools/plan.js +10 -2
- package/dist/core/tools/plan.js.map +1 -1
- package/dist/exec/approvals.js +7 -3
- package/dist/exec/approvals.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/configure/app.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { z } from "zod";
|
|
4
5
|
import { Box, Text, useApp, useInput } from "ink";
|
|
5
6
|
import { LlmProvider, } from "../core/config.js";
|
|
6
7
|
import { McpOAuthConfigSchema } from "../core/mcp/oauth/types.js";
|
|
@@ -58,7 +59,7 @@ const MCP_REMOTE_BASE_FIELDS = [
|
|
|
58
59
|
},
|
|
59
60
|
{
|
|
60
61
|
key: "oauthEnabled",
|
|
61
|
-
label: "Enable OAuth
|
|
62
|
+
label: "Enable OAuth",
|
|
62
63
|
placeholder: "no",
|
|
63
64
|
note: "Choose yes for servers that use OAuth 2.0/2.1 or dynamic client registration.",
|
|
64
65
|
},
|
|
@@ -270,7 +271,7 @@ const PROVIDER_FIELD_DEFINITIONS = {
|
|
|
270
271
|
label: "Deployment-based URLs",
|
|
271
272
|
kind: "optionalBoolean",
|
|
272
273
|
placeholder: "false",
|
|
273
|
-
note: "
|
|
274
|
+
note: "Toggle between yes and no. Leave unset to use the AI SDK default.",
|
|
274
275
|
},
|
|
275
276
|
{
|
|
276
277
|
key: "reasoningEffort",
|
|
@@ -739,6 +740,26 @@ function formatPromptCacheSummary(value) {
|
|
|
739
740
|
}
|
|
740
741
|
/** On/off display for tool rows (`Tool • Yes` / `Tool • No`). */
|
|
741
742
|
const yesNo = (on) => (on ? "Yes" : "No");
|
|
743
|
+
function formatMcpScope(scope) {
|
|
744
|
+
return scope === "global" ? "global" : "project";
|
|
745
|
+
}
|
|
746
|
+
function formatMcpWriteTargetLabel(path) {
|
|
747
|
+
return truncate(path, 72);
|
|
748
|
+
}
|
|
749
|
+
function formatMcpDeleteDescription(name, sourcePath, scope) {
|
|
750
|
+
return `Remove "${name}" from ${formatMcpScope(scope)} mcp.json (${truncate(sourcePath, 64)})? This cannot be undone from here.`;
|
|
751
|
+
}
|
|
752
|
+
function formatConfigureError(error) {
|
|
753
|
+
if (error instanceof z.ZodError) {
|
|
754
|
+
const issue = error.issues[0];
|
|
755
|
+
if (!issue) {
|
|
756
|
+
return "Invalid value.";
|
|
757
|
+
}
|
|
758
|
+
const path = issue.path.map(String).join(".");
|
|
759
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
760
|
+
}
|
|
761
|
+
return error instanceof Error ? error.message : String(error);
|
|
762
|
+
}
|
|
742
763
|
export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, }) {
|
|
743
764
|
const { exit } = useApp();
|
|
744
765
|
const [screen, setScreen] = useState({ kind: "home" });
|
|
@@ -747,27 +768,33 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
747
768
|
const [busyMessage, setBusyMessage] = useState(null);
|
|
748
769
|
const [revision, setRevision] = useState(0);
|
|
749
770
|
const [mcpDraft, setMcpDraft] = useState(null);
|
|
771
|
+
const [providerDraft, setProviderDraft] = useState(null);
|
|
772
|
+
const [providerDraftType, setProviderDraftType] = useState(null);
|
|
773
|
+
const [llmDraft, setLlmDraft] = useState(null);
|
|
750
774
|
const [installedSkills, setInstalledSkills] = useState([]);
|
|
751
775
|
const [searchResults, setSearchResults] = useState([]);
|
|
752
776
|
const [mcpAuthStatuses, setMcpAuthStatuses] = useState({});
|
|
753
777
|
const refresh = useCallback(() => {
|
|
754
778
|
setRevision((value) => value + 1);
|
|
755
779
|
}, []);
|
|
780
|
+
const handleActionError = useCallback((error) => {
|
|
781
|
+
setNotice({
|
|
782
|
+
kind: "error",
|
|
783
|
+
text: formatConfigureError(error),
|
|
784
|
+
});
|
|
785
|
+
}, []);
|
|
756
786
|
const runTask = useCallback(async (label, task) => {
|
|
757
787
|
setBusyMessage(label);
|
|
758
788
|
try {
|
|
759
789
|
await task();
|
|
760
790
|
}
|
|
761
791
|
catch (error) {
|
|
762
|
-
|
|
763
|
-
kind: "error",
|
|
764
|
-
text: error instanceof Error ? error.message : String(error),
|
|
765
|
-
});
|
|
792
|
+
handleActionError(error);
|
|
766
793
|
}
|
|
767
794
|
finally {
|
|
768
795
|
setBusyMessage(null);
|
|
769
796
|
}
|
|
770
|
-
}, []);
|
|
797
|
+
}, [handleActionError]);
|
|
771
798
|
const refreshSkills = useCallback(async (label = "Loading installed skills...") => {
|
|
772
799
|
await runTask(label, async () => {
|
|
773
800
|
const next = await skills.list();
|
|
@@ -808,7 +835,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
808
835
|
compaction: config.compaction,
|
|
809
836
|
reasoning: config.reasoning,
|
|
810
837
|
}), [config, revision]);
|
|
811
|
-
const mcpServers = useMemo(() => mcpConfig.
|
|
838
|
+
const mcpServers = useMemo(() => mcpConfig.listWithSources(), [mcpConfig, revision]);
|
|
812
839
|
useInput((input, key) => {
|
|
813
840
|
if (key.ctrl && input.toLowerCase() === "c") {
|
|
814
841
|
onExit();
|
|
@@ -829,7 +856,27 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
829
856
|
setScreen({ kind: "mcp" });
|
|
830
857
|
return;
|
|
831
858
|
}
|
|
832
|
-
if (screen.kind === "
|
|
859
|
+
if (screen.kind === "config-provider-create") {
|
|
860
|
+
setProviderDraft(null);
|
|
861
|
+
setProviderDraftType(null);
|
|
862
|
+
setScreen({ kind: "config-providers" });
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (screen.kind === "config-provider-create-type") {
|
|
866
|
+
setScreen({ kind: "config-provider-create" });
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (screen.kind === "config-llm-create") {
|
|
870
|
+
setLlmDraft(null);
|
|
871
|
+
setScreen({ kind: "config-llms" });
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
if (screen.kind === "config-llm-create-provider") {
|
|
875
|
+
setScreen({ kind: "config-llm-create" });
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (screen.kind === "mcp-delete-confirm" ||
|
|
879
|
+
screen.kind === "mcp-save-target") {
|
|
833
880
|
setScreen({ kind: "mcp" });
|
|
834
881
|
return;
|
|
835
882
|
}
|
|
@@ -857,6 +904,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
857
904
|
setScreen({ kind: "config-providers" });
|
|
858
905
|
return;
|
|
859
906
|
}
|
|
907
|
+
if (screen.kind === "config-providers" || screen.kind === "config-llms") {
|
|
908
|
+
setScreen({ kind: "config" });
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
860
911
|
if (screen.kind !== "home") {
|
|
861
912
|
setScreen({ kind: "home" });
|
|
862
913
|
return;
|
|
@@ -905,22 +956,8 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
905
956
|
: m), [config]);
|
|
906
957
|
const renameLlm = useCallback((oldName, newName) => config.llms.map((m) => m.name === oldName ? { ...m, name: newName } : m), [config]);
|
|
907
958
|
const setDefaultLlm = useCallback((name) => config.llms.map((m) => ({ ...m, default: m.name === name })), [config]);
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
const providerType = config.providers.find((provider) => provider.name === providerName)
|
|
911
|
-
?.provider ?? LlmProvider.LlamaCpp;
|
|
912
|
-
return [
|
|
913
|
-
...config.llms,
|
|
914
|
-
{
|
|
915
|
-
name,
|
|
916
|
-
provider: providerName,
|
|
917
|
-
options: {
|
|
918
|
-
model: defaultModelForProviderType(providerType),
|
|
919
|
-
},
|
|
920
|
-
default: false,
|
|
921
|
-
},
|
|
922
|
-
];
|
|
923
|
-
}, [config]);
|
|
959
|
+
const addLlmEntry = useCallback((entry) => [...config.llms, entry], [config]);
|
|
960
|
+
const addProviderEntry = useCallback((entry) => [...config.providers, entry], [config]);
|
|
924
961
|
const removeLlm = useCallback((name) => config.llms.filter((m) => m.name !== name), [config]);
|
|
925
962
|
const patchProvider = useCallback((name, patch) => config.providers.map((provider) => provider.name === name
|
|
926
963
|
? {
|
|
@@ -951,6 +988,12 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
951
988
|
},
|
|
952
989
|
], [config]);
|
|
953
990
|
const removeProvider = useCallback((name) => config.providers.filter((provider) => provider.name !== name), [config]);
|
|
991
|
+
const updateProviderDraftField = useCallback((key, value) => {
|
|
992
|
+
setProviderDraft((current) => current ? { ...current, [key]: value } : current);
|
|
993
|
+
}, []);
|
|
994
|
+
const updateLlmDraftField = useCallback((key, value) => {
|
|
995
|
+
setLlmDraft((current) => current ? { ...current, [key]: value } : current);
|
|
996
|
+
}, []);
|
|
954
997
|
const promptValue = useCallback((state) => {
|
|
955
998
|
setPrompt(state);
|
|
956
999
|
}, []);
|
|
@@ -962,31 +1005,33 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
962
1005
|
await prompt.onSubmit(value);
|
|
963
1006
|
}
|
|
964
1007
|
catch (error) {
|
|
965
|
-
|
|
966
|
-
kind: "error",
|
|
967
|
-
text: error instanceof Error ? error.message : String(error),
|
|
968
|
-
});
|
|
1008
|
+
handleActionError(error);
|
|
969
1009
|
}
|
|
970
|
-
}, [prompt]);
|
|
971
|
-
const persistMcpTransport = useCallback((currentName, nextName, transport) => {
|
|
1010
|
+
}, [handleActionError, prompt]);
|
|
1011
|
+
const persistMcpTransport = useCallback((currentName, nextName, transport, targetPath) => {
|
|
972
1012
|
if (!nextName) {
|
|
973
1013
|
throw new Error("Server name is required.");
|
|
974
1014
|
}
|
|
975
|
-
if (currentName && currentName !== nextName && mcpConfig.get(nextName)) {
|
|
976
|
-
throw new Error(`MCP server "${nextName}" already exists.`);
|
|
977
|
-
}
|
|
978
1015
|
if (!currentName) {
|
|
979
|
-
|
|
1016
|
+
if (!targetPath) {
|
|
1017
|
+
throw new Error("Save target is required for a new MCP server.");
|
|
1018
|
+
}
|
|
1019
|
+
mcpConfig.addToPath(targetPath, nextName, transport);
|
|
980
1020
|
setSuccess(`Added MCP server "${nextName}".`);
|
|
981
1021
|
}
|
|
982
|
-
else if (currentName === nextName) {
|
|
983
|
-
mcpConfig.update(currentName, transport);
|
|
984
|
-
setSuccess(`Updated MCP server "${currentName}".`);
|
|
985
|
-
}
|
|
986
1022
|
else {
|
|
987
|
-
mcpConfig.
|
|
988
|
-
|
|
989
|
-
|
|
1023
|
+
const currentEntry = mcpConfig.getEntry(currentName);
|
|
1024
|
+
if (!currentEntry) {
|
|
1025
|
+
throw new Error(`MCP server "${currentName}" does not exist.`);
|
|
1026
|
+
}
|
|
1027
|
+
if (currentName === nextName) {
|
|
1028
|
+
mcpConfig.updateInPath(currentEntry.sourcePath, currentName, transport);
|
|
1029
|
+
setSuccess(`Updated MCP server "${currentName}".`);
|
|
1030
|
+
}
|
|
1031
|
+
else {
|
|
1032
|
+
mcpConfig.renameInPath(currentEntry.sourcePath, currentName, nextName, transport);
|
|
1033
|
+
setSuccess(`Renamed MCP server "${currentName}" to "${nextName}".`);
|
|
1034
|
+
}
|
|
990
1035
|
}
|
|
991
1036
|
setMcpDraft(null);
|
|
992
1037
|
setScreen({ kind: "mcp" });
|
|
@@ -1046,7 +1091,32 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1046
1091
|
},
|
|
1047
1092
|
});
|
|
1048
1093
|
}, [promptValue, updateMcpDraftField]);
|
|
1049
|
-
const
|
|
1094
|
+
const editProviderDraftField = useCallback((definition, initialValue) => {
|
|
1095
|
+
promptValue({
|
|
1096
|
+
title: `Update ${definition.label}`,
|
|
1097
|
+
label: definition.label,
|
|
1098
|
+
initialValue,
|
|
1099
|
+
placeholder: definition.placeholder,
|
|
1100
|
+
note: definition.note,
|
|
1101
|
+
onSubmit: async (value) => {
|
|
1102
|
+
updateProviderDraftField(definition.key, value);
|
|
1103
|
+
setPrompt(null);
|
|
1104
|
+
},
|
|
1105
|
+
});
|
|
1106
|
+
}, [promptValue, updateProviderDraftField]);
|
|
1107
|
+
const editLlmDraftField = useCallback((label, key, initialValue, note) => {
|
|
1108
|
+
promptValue({
|
|
1109
|
+
title: `Update ${label}`,
|
|
1110
|
+
label,
|
|
1111
|
+
initialValue,
|
|
1112
|
+
note,
|
|
1113
|
+
onSubmit: async (value) => {
|
|
1114
|
+
updateLlmDraftField(key, value);
|
|
1115
|
+
setPrompt(null);
|
|
1116
|
+
},
|
|
1117
|
+
});
|
|
1118
|
+
}, [promptValue, updateLlmDraftField]);
|
|
1119
|
+
const buildMcpStdioDraft = useCallback(() => {
|
|
1050
1120
|
const values = mcpDraft ?? {};
|
|
1051
1121
|
const name = (values.name ?? "").trim();
|
|
1052
1122
|
const command = (values.command ?? "").trim();
|
|
@@ -1066,9 +1136,9 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1066
1136
|
...(env && Object.keys(env).length > 0 ? { env } : {}),
|
|
1067
1137
|
...(cwd ? { cwd } : {}),
|
|
1068
1138
|
});
|
|
1069
|
-
|
|
1070
|
-
}, [mcpDraft
|
|
1071
|
-
const
|
|
1139
|
+
return { name, transport };
|
|
1140
|
+
}, [mcpDraft]);
|
|
1141
|
+
const buildMcpRemoteDraft = useCallback((transportType) => {
|
|
1072
1142
|
const values = mcpDraft ?? {};
|
|
1073
1143
|
const name = (values.name ?? "").trim();
|
|
1074
1144
|
const url = (values.url ?? "").trim();
|
|
@@ -1133,8 +1203,24 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1133
1203
|
...(headers && Object.keys(headers).length > 0 ? { headers } : {}),
|
|
1134
1204
|
...(oauth ? { oauth } : {}),
|
|
1135
1205
|
});
|
|
1206
|
+
return { name, transport };
|
|
1207
|
+
}, [mcpDraft]);
|
|
1208
|
+
const saveMcpStdioDraft = useCallback((originalName) => {
|
|
1209
|
+
const { name, transport } = buildMcpStdioDraft();
|
|
1210
|
+
if (!originalName) {
|
|
1211
|
+
setScreen({ kind: "mcp-save-target", transportType: "stdio" });
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1136
1214
|
persistMcpTransport(originalName, name, transport);
|
|
1137
|
-
}, [
|
|
1215
|
+
}, [buildMcpStdioDraft, persistMcpTransport]);
|
|
1216
|
+
const saveMcpRemoteDraft = useCallback((transportType, originalName) => {
|
|
1217
|
+
const { name, transport } = buildMcpRemoteDraft(transportType);
|
|
1218
|
+
if (!originalName) {
|
|
1219
|
+
setScreen({ kind: "mcp-save-target", transportType });
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
persistMcpTransport(originalName, name, transport);
|
|
1223
|
+
}, [buildMcpRemoteDraft, persistMcpTransport]);
|
|
1138
1224
|
const llmSummary = useCallback((entry) => {
|
|
1139
1225
|
const compactModelId = (model) => {
|
|
1140
1226
|
if (model.length <= 23) {
|
|
@@ -1172,10 +1258,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1172
1258
|
setSuccess("Updated instructions.md.");
|
|
1173
1259
|
}
|
|
1174
1260
|
catch (error) {
|
|
1175
|
-
|
|
1176
|
-
kind: "error",
|
|
1177
|
-
text: error instanceof Error ? error.message : String(error),
|
|
1178
|
-
});
|
|
1261
|
+
handleActionError(error);
|
|
1179
1262
|
}
|
|
1180
1263
|
},
|
|
1181
1264
|
},
|
|
@@ -1199,7 +1282,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1199
1282
|
},
|
|
1200
1283
|
},
|
|
1201
1284
|
];
|
|
1202
|
-
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" }));
|
|
1285
|
+
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", onActionError: handleActionError }));
|
|
1203
1286
|
};
|
|
1204
1287
|
const renderGeneralMenu = () => {
|
|
1205
1288
|
const enabledPrompts = Object.values(configData.prompts).filter(Boolean).length;
|
|
@@ -1287,7 +1370,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1287
1370
|
value: () => setScreen({ kind: "home" }),
|
|
1288
1371
|
},
|
|
1289
1372
|
];
|
|
1290
|
-
return (_jsx(MenuScreen, { title: "General", description: "Manage app-wide settings loaded from ~/.hooman/config.json.", items: items }));
|
|
1373
|
+
return (_jsx(MenuScreen, { title: "General", description: "Manage app-wide settings loaded from ~/.hooman/config.json.", items: items, onActionError: handleActionError }));
|
|
1291
1374
|
};
|
|
1292
1375
|
const renderConfigMenu = () => {
|
|
1293
1376
|
const defaultLlm = config.llms.find((m) => m.default) ?? config.llms[0];
|
|
@@ -1421,30 +1504,145 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1421
1504
|
const items = [
|
|
1422
1505
|
{
|
|
1423
1506
|
label: "Add provider",
|
|
1424
|
-
value: () =>
|
|
1425
|
-
|
|
1507
|
+
value: () => {
|
|
1508
|
+
setProviderDraft({ name: "" });
|
|
1509
|
+
setProviderDraftType(SUPPORTED_PROVIDER_TYPES[0]);
|
|
1510
|
+
setScreen({ kind: "config-provider-create" });
|
|
1511
|
+
},
|
|
1512
|
+
},
|
|
1513
|
+
...providerItems,
|
|
1514
|
+
{
|
|
1515
|
+
label: "Back",
|
|
1516
|
+
value: () => setScreen({ kind: "config" }),
|
|
1517
|
+
},
|
|
1518
|
+
];
|
|
1519
|
+
return (_jsx(MenuScreen, { title: "Providers", description: "Configure reusable provider credentials and shared params.", items: items }));
|
|
1520
|
+
};
|
|
1521
|
+
const renderProviderCreateMenu = () => {
|
|
1522
|
+
if (screen.kind !== "config-provider-create" || !providerDraft) {
|
|
1523
|
+
return null;
|
|
1524
|
+
}
|
|
1525
|
+
const providerType = providerDraftType ?? SUPPORTED_PROVIDER_TYPES[0];
|
|
1526
|
+
const providerFields = PROVIDER_FIELD_DEFINITIONS[providerType];
|
|
1527
|
+
const items = [
|
|
1528
|
+
{
|
|
1529
|
+
label: `Name • ${providerDraft.name?.trim() ? providerDraft.name : "not set"}`,
|
|
1530
|
+
value: () => editProviderDraftField({
|
|
1531
|
+
key: "name",
|
|
1426
1532
|
label: "Name",
|
|
1533
|
+
kind: "string",
|
|
1427
1534
|
placeholder: "openai-prod",
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1535
|
+
}, providerDraft.name ?? ""),
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
label: `Type • ${providerType}`,
|
|
1539
|
+
value: () => setScreen({ kind: "config-provider-create-type" }),
|
|
1540
|
+
},
|
|
1541
|
+
...providerFields.map((definition) => ({
|
|
1542
|
+
key: `provider-create-field:${definition.key}`,
|
|
1543
|
+
label: `${definition.label} • ${formatDraftFieldValue({
|
|
1544
|
+
key: definition.key,
|
|
1545
|
+
label: definition.label,
|
|
1546
|
+
placeholder: definition.placeholder,
|
|
1547
|
+
note: definition.note,
|
|
1548
|
+
}, providerDraft[definition.key])}`,
|
|
1549
|
+
value: () => {
|
|
1550
|
+
if (definition.kind === "optionalBoolean") {
|
|
1551
|
+
updateProviderDraftField(definition.key, isTruthyToggle(providerDraft[definition.key]) ? "no" : "yes");
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
editProviderDraftField(definition, providerDraft[definition.key] ?? "");
|
|
1555
|
+
},
|
|
1556
|
+
})),
|
|
1557
|
+
{
|
|
1558
|
+
label: "Save",
|
|
1559
|
+
value: () => {
|
|
1560
|
+
const name = (providerDraft.name ?? "").trim();
|
|
1561
|
+
if (!name) {
|
|
1562
|
+
throw new Error("Name is required.");
|
|
1563
|
+
}
|
|
1564
|
+
if (config.providers.some((provider) => provider.name === name)) {
|
|
1565
|
+
throw new Error(`A provider named "${name}" already exists.`);
|
|
1566
|
+
}
|
|
1567
|
+
const options = providerOptionsTemplate(providerType);
|
|
1568
|
+
for (const definition of providerFields) {
|
|
1569
|
+
if (definition.key === "openaiApi") {
|
|
1570
|
+
const nextValue = parseTypedFieldValue(providerDraft[definition.key] ?? "", definition);
|
|
1571
|
+
options.api = nextValue;
|
|
1572
|
+
continue;
|
|
1432
1573
|
}
|
|
1433
|
-
if (
|
|
1434
|
-
|
|
1574
|
+
if (definition.kind === "reasoningEffort") {
|
|
1575
|
+
const effort = parseTypedFieldValue(providerDraft[definition.key] ?? "", definition);
|
|
1576
|
+
const reasoning = {
|
|
1577
|
+
...(options.reasoning ?? {}),
|
|
1578
|
+
effort,
|
|
1579
|
+
};
|
|
1580
|
+
options.reasoning = Object.values(reasoning).some((value) => value !== undefined)
|
|
1581
|
+
? reasoning
|
|
1582
|
+
: undefined;
|
|
1583
|
+
continue;
|
|
1435
1584
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1585
|
+
if (definition.kind === "reasoningSummary") {
|
|
1586
|
+
const summary = parseTypedFieldValue(providerDraft[definition.key] ?? "", definition);
|
|
1587
|
+
const reasoning = {
|
|
1588
|
+
...(options.reasoning ?? {}),
|
|
1589
|
+
summary,
|
|
1590
|
+
};
|
|
1591
|
+
options.reasoning = Object.values(reasoning).some((value) => value !== undefined)
|
|
1592
|
+
? reasoning
|
|
1593
|
+
: undefined;
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
if (definition.kind === "reasoningDisplay") {
|
|
1597
|
+
const display = parseTypedFieldValue(providerDraft[definition.key] ?? "", definition);
|
|
1598
|
+
const reasoning = {
|
|
1599
|
+
...(options.reasoning ?? {}),
|
|
1600
|
+
display,
|
|
1601
|
+
};
|
|
1602
|
+
options.reasoning = Object.values(reasoning).some((value) => value !== undefined)
|
|
1603
|
+
? reasoning
|
|
1604
|
+
: undefined;
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
if (definition.kind === "bedrockCredentials") {
|
|
1608
|
+
const accessKeyId = normalizeOptional(providerDraft.accessKeyId ?? "");
|
|
1609
|
+
const secretAccessKey = normalizeOptional(providerDraft.secretAccessKey ?? "");
|
|
1610
|
+
if ((accessKeyId === undefined) !==
|
|
1611
|
+
(secretAccessKey === undefined)) {
|
|
1612
|
+
throw new Error("Access key ID and secret access key must be provided together.");
|
|
1613
|
+
}
|
|
1614
|
+
options.accessKeyId = accessKeyId;
|
|
1615
|
+
options.secretAccessKey = secretAccessKey;
|
|
1616
|
+
continue;
|
|
1617
|
+
}
|
|
1618
|
+
if (definition.kind === "promptCache") {
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
options[definition.key] = parseTypedFieldValue(providerDraft[definition.key] ?? "", definition);
|
|
1622
|
+
}
|
|
1623
|
+
if (updateConfig({
|
|
1624
|
+
providers: addProviderEntry({
|
|
1625
|
+
name,
|
|
1626
|
+
provider: providerType,
|
|
1627
|
+
options: options,
|
|
1628
|
+
}),
|
|
1629
|
+
}, `Added provider "${name}" as "${providerType}".`)) {
|
|
1630
|
+
setProviderDraft(null);
|
|
1631
|
+
setProviderDraftType(null);
|
|
1632
|
+
setScreen({ kind: "config-provider-edit", name });
|
|
1633
|
+
}
|
|
1634
|
+
},
|
|
1440
1635
|
},
|
|
1441
|
-
...providerItems,
|
|
1442
1636
|
{
|
|
1443
1637
|
label: "Back",
|
|
1444
|
-
value: () =>
|
|
1638
|
+
value: () => {
|
|
1639
|
+
setProviderDraft(null);
|
|
1640
|
+
setProviderDraftType(null);
|
|
1641
|
+
setScreen({ kind: "config-providers" });
|
|
1642
|
+
},
|
|
1445
1643
|
},
|
|
1446
1644
|
];
|
|
1447
|
-
return (_jsx(MenuScreen, { title: "
|
|
1645
|
+
return (_jsx(MenuScreen, { title: "Add a new provider", description: "Select a field to edit, then save when you're done.", items: items, onActionError: handleActionError }));
|
|
1448
1646
|
};
|
|
1449
1647
|
const renderProviderEditMenu = () => {
|
|
1450
1648
|
if (screen.kind !== "config-provider-edit") {
|
|
@@ -1537,6 +1735,16 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1537
1735
|
});
|
|
1538
1736
|
return;
|
|
1539
1737
|
}
|
|
1738
|
+
if (definition.kind === "optionalBoolean") {
|
|
1739
|
+
const currentValue = providerOptions[definition.key];
|
|
1740
|
+
const nextValue = currentValue === true ? false : true;
|
|
1741
|
+
updateConfig({
|
|
1742
|
+
providers: patchProvider(entry.name, {
|
|
1743
|
+
[definition.key]: nextValue,
|
|
1744
|
+
}),
|
|
1745
|
+
}, `Updated ${definition.label.toLowerCase()} for "${entry.name}" to ${nextValue ? "yes" : "no"}.`);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1540
1748
|
if (definition.kind === "bedrockCredentials") {
|
|
1541
1749
|
promptValue({
|
|
1542
1750
|
title: "Update static credentials",
|
|
@@ -1858,27 +2066,22 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1858
2066
|
const items = [
|
|
1859
2067
|
{
|
|
1860
2068
|
label: "Add LLM",
|
|
1861
|
-
value: () =>
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
setPrompt(null);
|
|
1878
|
-
setScreen({ kind: "config-llm-edit", name });
|
|
1879
|
-
}
|
|
1880
|
-
},
|
|
1881
|
-
}),
|
|
2069
|
+
value: () => {
|
|
2070
|
+
if (config.providers.length === 0) {
|
|
2071
|
+
throw new Error("Add at least one provider first so the model can reference it.");
|
|
2072
|
+
}
|
|
2073
|
+
const providerName = config.providers[0].name;
|
|
2074
|
+
const providerType = config.providers[0].provider;
|
|
2075
|
+
setLlmDraft({
|
|
2076
|
+
name: "",
|
|
2077
|
+
provider: providerName,
|
|
2078
|
+
model: defaultModelForProviderType(providerType),
|
|
2079
|
+
temperature: "",
|
|
2080
|
+
maxTokens: "",
|
|
2081
|
+
context: "",
|
|
2082
|
+
});
|
|
2083
|
+
setScreen({ kind: "config-llm-create" });
|
|
2084
|
+
},
|
|
1882
2085
|
},
|
|
1883
2086
|
...llmItems,
|
|
1884
2087
|
{
|
|
@@ -1888,6 +2091,86 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
1888
2091
|
];
|
|
1889
2092
|
return (_jsx(MenuScreen, { title: "LLMs", description: "Add, edit, or remove named LLM configurations. The default is used for new sessions.", items: items }));
|
|
1890
2093
|
};
|
|
2094
|
+
const renderLlmCreateMenu = () => {
|
|
2095
|
+
if (screen.kind !== "config-llm-create" || !llmDraft) {
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
const provider = config.providers.find((candidate) => candidate.name === llmDraft.provider);
|
|
2099
|
+
const providerType = provider?.provider;
|
|
2100
|
+
const items = [
|
|
2101
|
+
{
|
|
2102
|
+
label: `Name • ${llmDraft.name?.trim() ? llmDraft.name : "not set"}`,
|
|
2103
|
+
value: () => editLlmDraftField("Name", "name", llmDraft.name ?? ""),
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
label: `Provider • ${llmDraft.provider ?? "not set"}`,
|
|
2107
|
+
value: () => setScreen({ kind: "config-llm-create-provider" }),
|
|
2108
|
+
},
|
|
2109
|
+
{
|
|
2110
|
+
label: `Model • ${llmDraft.model?.trim() ? llmDraft.model : "not set"}`,
|
|
2111
|
+
value: () => editLlmDraftField("Model", "model", llmDraft.model ?? "", providerType
|
|
2112
|
+
? `Suggested default for ${providerType}: ${defaultModelForProviderType(providerType)}`
|
|
2113
|
+
: undefined),
|
|
2114
|
+
},
|
|
2115
|
+
...LLM_FIELD_DEFINITIONS.map((definition) => ({
|
|
2116
|
+
key: `llm-create-field:${definition.key}`,
|
|
2117
|
+
label: `${definition.label} • ${formatDraftFieldValue({
|
|
2118
|
+
key: definition.key,
|
|
2119
|
+
label: definition.label,
|
|
2120
|
+
placeholder: definition.placeholder,
|
|
2121
|
+
note: definition.note,
|
|
2122
|
+
}, llmDraft[definition.key])}`,
|
|
2123
|
+
value: () => editLlmDraftField(definition.label, definition.key, llmDraft[definition.key] ?? "", definition.note),
|
|
2124
|
+
})),
|
|
2125
|
+
{
|
|
2126
|
+
label: "Save",
|
|
2127
|
+
value: () => {
|
|
2128
|
+
const name = (llmDraft.name ?? "").trim();
|
|
2129
|
+
if (!name) {
|
|
2130
|
+
throw new Error("Name is required.");
|
|
2131
|
+
}
|
|
2132
|
+
if (config.llms.some((llm) => llm.name === name)) {
|
|
2133
|
+
throw new Error(`An LLM named "${name}" already exists.`);
|
|
2134
|
+
}
|
|
2135
|
+
const providerName = (llmDraft.provider ?? "").trim();
|
|
2136
|
+
if (!providerName) {
|
|
2137
|
+
throw new Error("Provider is required.");
|
|
2138
|
+
}
|
|
2139
|
+
const selectedProvider = config.providers.find((candidate) => candidate.name === providerName);
|
|
2140
|
+
if (!selectedProvider) {
|
|
2141
|
+
throw new Error(`Provider "${providerName}" does not exist.`);
|
|
2142
|
+
}
|
|
2143
|
+
const model = (llmDraft.model ?? "").trim();
|
|
2144
|
+
if (!model) {
|
|
2145
|
+
throw new Error("Model is required.");
|
|
2146
|
+
}
|
|
2147
|
+
const options = { model };
|
|
2148
|
+
for (const definition of LLM_FIELD_DEFINITIONS) {
|
|
2149
|
+
options[definition.key] = parseTypedFieldValue(llmDraft[definition.key] ?? "", definition);
|
|
2150
|
+
}
|
|
2151
|
+
if (updateConfig({
|
|
2152
|
+
llms: addLlmEntry({
|
|
2153
|
+
name,
|
|
2154
|
+
provider: providerName,
|
|
2155
|
+
options: options,
|
|
2156
|
+
default: false,
|
|
2157
|
+
}),
|
|
2158
|
+
}, `Added LLM "${name}".`)) {
|
|
2159
|
+
setLlmDraft(null);
|
|
2160
|
+
setScreen({ kind: "config-llm-edit", name });
|
|
2161
|
+
}
|
|
2162
|
+
},
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
label: "Back",
|
|
2166
|
+
value: () => {
|
|
2167
|
+
setLlmDraft(null);
|
|
2168
|
+
setScreen({ kind: "config-llms" });
|
|
2169
|
+
},
|
|
2170
|
+
},
|
|
2171
|
+
];
|
|
2172
|
+
return (_jsx(MenuScreen, { title: "Add a new LLM", description: "Select a field to edit, then save when you're done.", items: items, onActionError: handleActionError }));
|
|
2173
|
+
};
|
|
1891
2174
|
const renderLlmEditMenu = () => {
|
|
1892
2175
|
if (screen.kind !== "config-llm-edit") {
|
|
1893
2176
|
return null;
|
|
@@ -2008,6 +2291,33 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2008
2291
|
? "This is the default LLM. Set another as default to enable deletion."
|
|
2009
2292
|
: "Edit fields, set as default, or delete this LLM.", items: items }));
|
|
2010
2293
|
};
|
|
2294
|
+
const renderLlmCreateProviderMenu = () => {
|
|
2295
|
+
if (screen.kind !== "config-llm-create-provider" || !llmDraft) {
|
|
2296
|
+
return null;
|
|
2297
|
+
}
|
|
2298
|
+
const items = [
|
|
2299
|
+
...config.providers.map((provider) => ({
|
|
2300
|
+
label: provider.name === llmDraft.provider
|
|
2301
|
+
? `${provider.name} • current`
|
|
2302
|
+
: `${provider.name} • ${provider.provider}`,
|
|
2303
|
+
value: () => {
|
|
2304
|
+
setLlmDraft((current) => current
|
|
2305
|
+
? {
|
|
2306
|
+
...current,
|
|
2307
|
+
provider: provider.name,
|
|
2308
|
+
model: defaultModelForProviderType(provider.provider),
|
|
2309
|
+
}
|
|
2310
|
+
: current);
|
|
2311
|
+
setScreen({ kind: "config-llm-create" });
|
|
2312
|
+
},
|
|
2313
|
+
})),
|
|
2314
|
+
{
|
|
2315
|
+
label: "Back",
|
|
2316
|
+
value: () => setScreen({ kind: "config-llm-create" }),
|
|
2317
|
+
},
|
|
2318
|
+
];
|
|
2319
|
+
return (_jsx(MenuScreen, { title: "Choose provider", description: "Pick which shared provider config this LLM should use.", items: items, onActionError: handleActionError }));
|
|
2320
|
+
};
|
|
2011
2321
|
const renderLlmProviderMenu = () => {
|
|
2012
2322
|
if (screen.kind !== "config-llm-provider") {
|
|
2013
2323
|
return null;
|
|
@@ -2254,7 +2564,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2254
2564
|
},
|
|
2255
2565
|
},
|
|
2256
2566
|
];
|
|
2257
|
-
return (_jsx(MenuScreen, { title: `${screen.originalName ? "Edit" : "Add"} stdio server`, description: "Select a field to edit, then save when you're done.", items: items }));
|
|
2567
|
+
return (_jsx(MenuScreen, { title: `${screen.originalName ? "Edit" : "Add"} stdio server`, description: "Select a field to edit, then save when you're done.", items: items, onActionError: handleActionError }));
|
|
2258
2568
|
};
|
|
2259
2569
|
const renderMcpRemoteEditMenu = () => {
|
|
2260
2570
|
if (screen.kind !== "mcp-remote-edit" || !mcpDraft) {
|
|
@@ -2268,7 +2578,13 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2268
2578
|
...fields.map((field) => ({
|
|
2269
2579
|
key: `mcp-remote:${field.key}`,
|
|
2270
2580
|
label: `${field.label} • ${formatDraftFieldValue(field, mcpDraft[field.key])}`,
|
|
2271
|
-
value: () =>
|
|
2581
|
+
value: () => {
|
|
2582
|
+
if (field.key === "oauthEnabled") {
|
|
2583
|
+
updateMcpDraftField(field.key, isTruthyToggle(mcpDraft[field.key]) ? "no" : "yes");
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
editMcpDraftField(field, mcpDraft[field.key] ?? "");
|
|
2587
|
+
},
|
|
2272
2588
|
})),
|
|
2273
2589
|
{
|
|
2274
2590
|
label: "Save",
|
|
@@ -2282,14 +2598,47 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2282
2598
|
},
|
|
2283
2599
|
},
|
|
2284
2600
|
];
|
|
2285
|
-
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 }));
|
|
2601
|
+
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, onActionError: handleActionError }));
|
|
2602
|
+
};
|
|
2603
|
+
const renderMcpSaveTargetMenu = () => {
|
|
2604
|
+
if (screen.kind !== "mcp-save-target") {
|
|
2605
|
+
return null;
|
|
2606
|
+
}
|
|
2607
|
+
const targets = mcpConfig.writableTargets();
|
|
2608
|
+
const saveToTarget = (path) => {
|
|
2609
|
+
try {
|
|
2610
|
+
if (screen.transportType === "stdio") {
|
|
2611
|
+
const { name, transport } = buildMcpStdioDraft();
|
|
2612
|
+
persistMcpTransport(undefined, name, transport, path);
|
|
2613
|
+
}
|
|
2614
|
+
else {
|
|
2615
|
+
const { name, transport } = buildMcpRemoteDraft(screen.transportType);
|
|
2616
|
+
persistMcpTransport(undefined, name, transport, path);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
catch (error) {
|
|
2620
|
+
handleActionError(error);
|
|
2621
|
+
}
|
|
2622
|
+
};
|
|
2623
|
+
const items = [
|
|
2624
|
+
...targets.map((target) => ({
|
|
2625
|
+
key: `mcp-save-target:${target.path}`,
|
|
2626
|
+
label: `${target.scope === "global" ? "Global" : "Project"} • ${formatMcpWriteTargetLabel(target.path)}`,
|
|
2627
|
+
value: () => saveToTarget(target.path),
|
|
2628
|
+
})),
|
|
2629
|
+
{
|
|
2630
|
+
label: "Back",
|
|
2631
|
+
value: () => setScreen({ kind: "mcp" }),
|
|
2632
|
+
},
|
|
2633
|
+
];
|
|
2634
|
+
return (_jsx(MenuScreen, { title: "Choose save target", description: "Select where to save this new MCP server.", items: items, onActionError: handleActionError }));
|
|
2286
2635
|
};
|
|
2287
2636
|
const renderMcpMenu = () => {
|
|
2288
2637
|
const serverItems = mcpServers.map((server) => {
|
|
2289
2638
|
const oauthStatus = mcpAuthStatuses[server.name];
|
|
2290
2639
|
return {
|
|
2291
2640
|
key: `mcp-server:${server.name}`,
|
|
2292
|
-
label: `Edit ${server.name} • ${formatMcpServerLabel(server.transport, oauthStatus)}`,
|
|
2641
|
+
label: `Edit ${server.name} • ${formatMcpServerLabel(server.transport, oauthStatus)} • ${formatMcpScope(server.scope)}`,
|
|
2293
2642
|
boldSubstring: server.name,
|
|
2294
2643
|
oauthStatus: oauthStatus === "authenticated" ||
|
|
2295
2644
|
oauthStatus === "expired" ||
|
|
@@ -2325,7 +2674,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2325
2674
|
value: () => {
|
|
2326
2675
|
mcpConfig.reload();
|
|
2327
2676
|
refresh();
|
|
2328
|
-
setNotice({
|
|
2677
|
+
setNotice({
|
|
2678
|
+
kind: "info",
|
|
2679
|
+
text: "Reloaded merged MCP config from disk.",
|
|
2680
|
+
});
|
|
2329
2681
|
},
|
|
2330
2682
|
},
|
|
2331
2683
|
{
|
|
@@ -2333,7 +2685,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2333
2685
|
value: () => setScreen({ kind: "home" }),
|
|
2334
2686
|
},
|
|
2335
2687
|
];
|
|
2336
|
-
return (_jsx(MenuScreen, { title: "MCP Servers", description: "Add, edit, or remove named MCP transports from
|
|
2688
|
+
return (_jsx(MenuScreen, { title: "MCP Servers", description: "Add, edit, or remove named MCP transports from merged MCP config (global + project overlays).", items: items, footerHint: (item) => formatMcpFooterHint(item, mcpServers, mcpAuthStatuses), onActionError: handleActionError, onShortcut: async (input, item) => {
|
|
2337
2689
|
const server = findMcpServerFromMenuItem(item, mcpServers);
|
|
2338
2690
|
if (!server) {
|
|
2339
2691
|
return;
|
|
@@ -2341,7 +2693,12 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2341
2693
|
const status = mcpAuthStatuses[server.name];
|
|
2342
2694
|
const key = input.toLowerCase();
|
|
2343
2695
|
if (key === "d") {
|
|
2344
|
-
setScreen({
|
|
2696
|
+
setScreen({
|
|
2697
|
+
kind: "mcp-delete-confirm",
|
|
2698
|
+
name: server.name,
|
|
2699
|
+
sourcePath: server.sourcePath,
|
|
2700
|
+
scope: server.scope,
|
|
2701
|
+
});
|
|
2345
2702
|
return;
|
|
2346
2703
|
}
|
|
2347
2704
|
if (key === "r" &&
|
|
@@ -2433,7 +2790,7 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2433
2790
|
if (screen.kind !== "mcp-delete-confirm") {
|
|
2434
2791
|
return null;
|
|
2435
2792
|
}
|
|
2436
|
-
const { name } = screen;
|
|
2793
|
+
const { name, sourcePath, scope } = screen;
|
|
2437
2794
|
const items = [
|
|
2438
2795
|
{
|
|
2439
2796
|
key: `mcp-del-cancel:${name}`,
|
|
@@ -2442,24 +2799,21 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2442
2799
|
},
|
|
2443
2800
|
{
|
|
2444
2801
|
key: `mcp-del-confirm:${name}`,
|
|
2445
|
-
label:
|
|
2802
|
+
label: `Yes — remove from ${formatMcpScope(scope)} mcp.json`,
|
|
2446
2803
|
value: () => {
|
|
2447
2804
|
try {
|
|
2448
|
-
mcpConfig.
|
|
2805
|
+
mcpConfig.removeFromPath(sourcePath, name);
|
|
2449
2806
|
refresh();
|
|
2450
|
-
setSuccess(`Deleted MCP server "${name}".`);
|
|
2807
|
+
setSuccess(`Deleted MCP server "${name}" from ${formatMcpScope(scope)} mcp.json.`);
|
|
2451
2808
|
}
|
|
2452
2809
|
catch (error) {
|
|
2453
|
-
|
|
2454
|
-
kind: "error",
|
|
2455
|
-
text: error instanceof Error ? error.message : String(error),
|
|
2456
|
-
});
|
|
2810
|
+
handleActionError(error);
|
|
2457
2811
|
}
|
|
2458
2812
|
setScreen({ kind: "mcp" });
|
|
2459
2813
|
},
|
|
2460
2814
|
},
|
|
2461
2815
|
];
|
|
2462
|
-
return (_jsx(MenuScreen, { title: "Delete MCP server?", description:
|
|
2816
|
+
return (_jsx(MenuScreen, { title: "Delete MCP server?", description: formatMcpDeleteDescription(name, sourcePath, scope), items: items, onActionError: handleActionError }));
|
|
2463
2817
|
};
|
|
2464
2818
|
const renderSkillsDeleteConfirm = () => {
|
|
2465
2819
|
if (screen.kind !== "skills-delete-confirm") {
|
|
@@ -2525,6 +2879,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2525
2879
|
return renderConfigMenu();
|
|
2526
2880
|
case "config-providers":
|
|
2527
2881
|
return renderProvidersMenu();
|
|
2882
|
+
case "config-provider-create":
|
|
2883
|
+
return renderProviderCreateMenu();
|
|
2884
|
+
case "config-provider-create-type":
|
|
2885
|
+
return renderProviderAddTypeMenu();
|
|
2528
2886
|
case "config-provider-add-type":
|
|
2529
2887
|
return renderProviderAddTypeMenu();
|
|
2530
2888
|
case "config-provider-edit":
|
|
@@ -2545,6 +2903,10 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2545
2903
|
return renderProviderDeleteConfirm();
|
|
2546
2904
|
case "config-llms":
|
|
2547
2905
|
return renderLlmsMenu();
|
|
2906
|
+
case "config-llm-create":
|
|
2907
|
+
return renderLlmCreateMenu();
|
|
2908
|
+
case "config-llm-create-provider":
|
|
2909
|
+
return renderLlmCreateProviderMenu();
|
|
2548
2910
|
case "config-llm-edit":
|
|
2549
2911
|
return renderLlmEditMenu();
|
|
2550
2912
|
case "config-llm-provider":
|
|
@@ -2561,6 +2923,8 @@ export function ConfigureApp({ config, mcpConfig, mcpManager, skills, onExit, })
|
|
|
2561
2923
|
return renderSearchProviderMenu();
|
|
2562
2924
|
case "mcp":
|
|
2563
2925
|
return renderMcpMenu();
|
|
2926
|
+
case "mcp-save-target":
|
|
2927
|
+
return renderMcpSaveTargetMenu();
|
|
2564
2928
|
case "mcp-stdio-edit":
|
|
2565
2929
|
return renderMcpStdioEditMenu();
|
|
2566
2930
|
case "mcp-remote-edit":
|