pi-codemcp 1.2.1 → 1.3.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 +6 -3
- package/extensions/index.ts +67 -77
- package/package.json +1 -1
- package/sidecar/chains.py +17 -44
- package/sidecar/cli.py +27 -7
- package/sidecar/executor.py +207 -35
- package/sidecar/gateway.py +505 -141
- package/sidecar/mcp_config.py +27 -2
- package/sidecar/refinement_cache.py +154 -0
- package/sidecar/sandbox_api.py +44 -0
- package/sidecar/stats.py +801 -194
- package/sidecar/tool_catalog.py +1 -9
- package/src/chains.ts +63 -34
- package/src/config.ts +8 -39
- package/src/mcp-client.ts +2 -1
- package/src/modal.ts +87 -248
- package/src/prompts.ts +3 -3
- package/src/tools.ts +37 -17
package/src/modal.ts
CHANGED
|
@@ -13,13 +13,7 @@ import {
|
|
|
13
13
|
} from "@earendil-works/pi-tui";
|
|
14
14
|
import type { ChainScope, SavedChainView } from "./chains.js";
|
|
15
15
|
import { summarizeError } from "./errors.js";
|
|
16
|
-
import {
|
|
17
|
-
type CodeMcpSettings,
|
|
18
|
-
type EditableSettingKey,
|
|
19
|
-
type EditableSettingValue,
|
|
20
|
-
setEditableSetting,
|
|
21
|
-
setToolEnabled,
|
|
22
|
-
} from "./settings.js";
|
|
16
|
+
import type { CodeMcpSettings, EditableSettingKey, EditableSettingValue } from "./settings.js";
|
|
23
17
|
|
|
24
18
|
export interface ToolModalState {
|
|
25
19
|
name: string;
|
|
@@ -78,6 +72,7 @@ export interface StatsModalState {
|
|
|
78
72
|
p95Ms: number;
|
|
79
73
|
maxMs: number;
|
|
80
74
|
}>;
|
|
75
|
+
outcomes: Array<{ name: string; count: number }>;
|
|
81
76
|
failures: Array<{ stage: string; count: number }>;
|
|
82
77
|
upstreamOutputBytes: number;
|
|
83
78
|
cacheHits: number;
|
|
@@ -104,26 +99,6 @@ interface Keybindings {
|
|
|
104
99
|
matches(data: string, id: "tui.select.up" | "tui.select.down" | "tui.select.cancel"): boolean;
|
|
105
100
|
}
|
|
106
101
|
|
|
107
|
-
export interface ServerEnabledChange {
|
|
108
|
-
name: string;
|
|
109
|
-
previousEnabled: boolean;
|
|
110
|
-
enabled: boolean;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export interface ChainEnabledChange {
|
|
114
|
-
name: string;
|
|
115
|
-
scope: ChainScope;
|
|
116
|
-
previousEnabled: boolean;
|
|
117
|
-
enabled: boolean;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
interface ManagerSaveResult {
|
|
121
|
-
settings: CodeMcpSettings;
|
|
122
|
-
servers: ServerModalState[];
|
|
123
|
-
chains: ChainModalState[];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
type UnsavedAction = "save" | "discard" | "cancel";
|
|
127
102
|
export type ServerManagerResult = "report-problem" | undefined;
|
|
128
103
|
|
|
129
104
|
interface ServerManagerOptions {
|
|
@@ -131,13 +106,15 @@ interface ServerManagerOptions {
|
|
|
131
106
|
chains: ChainModalState[];
|
|
132
107
|
settings: CodeMcpSettings;
|
|
133
108
|
stats: StatsModalState;
|
|
109
|
+
onSetServerEnabled(server: ServerModalState, enabled: boolean): Promise<ServerModalState>;
|
|
134
110
|
onDiscover(server: ServerModalState): Promise<ServerModalState>;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
): Promise<
|
|
140
|
-
|
|
111
|
+
onSetToolEnabled(
|
|
112
|
+
server: ServerModalState,
|
|
113
|
+
tool: ToolModalState,
|
|
114
|
+
enabled: boolean,
|
|
115
|
+
): Promise<ServerModalState>;
|
|
116
|
+
onSetSetting(key: EditableSettingKey, value: EditableSettingValue): Promise<CodeMcpSettings>;
|
|
117
|
+
onSetChainEnabled(chain: ChainModalState, enabled: boolean): Promise<ChainModalState[]>;
|
|
141
118
|
onRevalidateChain(chain: ChainModalState): Promise<ChainModalState[]>;
|
|
142
119
|
onDeleteChain(chain: ChainModalState): Promise<ChainModalState[]>;
|
|
143
120
|
}
|
|
@@ -282,6 +259,10 @@ export function statsStateFromSnapshot(snapshot: Record<string, unknown>): Stats
|
|
|
282
259
|
},
|
|
283
260
|
];
|
|
284
261
|
});
|
|
262
|
+
const rawOutcomes = isRecord(snapshot.outcomes) ? snapshot.outcomes : {};
|
|
263
|
+
const outcomes = Object.entries(rawOutcomes)
|
|
264
|
+
.flatMap(([name, count]) => (typeof count === "number" && count >= 0 ? [{ name, count }] : []))
|
|
265
|
+
.sort((left, right) => right.count - left.count || left.name.localeCompare(right.name));
|
|
285
266
|
const rawFailures = isRecord(snapshot.failures) ? snapshot.failures : {};
|
|
286
267
|
const failures = Object.entries(rawFailures)
|
|
287
268
|
.flatMap(([stage, count]) =>
|
|
@@ -302,6 +283,7 @@ export function statsStateFromSnapshot(snapshot: Record<string, unknown>): Stats
|
|
|
302
283
|
recent,
|
|
303
284
|
operations,
|
|
304
285
|
phases,
|
|
286
|
+
outcomes,
|
|
305
287
|
failures,
|
|
306
288
|
upstreamOutputBytes,
|
|
307
289
|
cacheHits: numberField(cache, "hits"),
|
|
@@ -345,12 +327,6 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
345
327
|
private selectedToolIndex = 0;
|
|
346
328
|
private selectedChainIndex = 0;
|
|
347
329
|
private selectedSettingIndex = 0;
|
|
348
|
-
private savedSettings: CodeMcpSettings;
|
|
349
|
-
private draftSettings: CodeMcpSettings;
|
|
350
|
-
private savedServerEnabled: Map<string, boolean>;
|
|
351
|
-
private savedChainEnabled: Map<string, boolean>;
|
|
352
|
-
private settingsBusy = false;
|
|
353
|
-
private closePromptBusy = false;
|
|
354
330
|
private settingsError: string | undefined;
|
|
355
331
|
private _focused = false;
|
|
356
332
|
|
|
@@ -360,13 +336,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
360
336
|
private readonly keybindings: Keybindings,
|
|
361
337
|
private readonly close: (result?: ServerManagerResult) => void,
|
|
362
338
|
private readonly requestRender: () => void,
|
|
363
|
-
) {
|
|
364
|
-
this.savedSettings = cloneSettings(options.settings);
|
|
365
|
-
this.draftSettings = cloneSettings(options.settings);
|
|
366
|
-
this.savedServerEnabled = serverEnabledMap(options.servers);
|
|
367
|
-
this.savedChainEnabled = chainEnabledMap(options.chains);
|
|
368
|
-
this.applyDraftToolPolicy();
|
|
369
|
-
}
|
|
339
|
+
) {}
|
|
370
340
|
|
|
371
341
|
get focused(): boolean {
|
|
372
342
|
return this._focused;
|
|
@@ -401,12 +371,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
401
371
|
}
|
|
402
372
|
|
|
403
373
|
handleInput(data: string): void {
|
|
404
|
-
if (
|
|
405
|
-
this.saveDraft();
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
if (this.settingsBusy || this.closePromptBusy) return;
|
|
409
|
-
if (data === "R") {
|
|
374
|
+
if (data === "R" && this.activeTab !== "chains") {
|
|
410
375
|
this.focusProblemReport();
|
|
411
376
|
this.requestRender();
|
|
412
377
|
return;
|
|
@@ -418,8 +383,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
418
383
|
this.requestRender();
|
|
419
384
|
return;
|
|
420
385
|
}
|
|
421
|
-
|
|
422
|
-
else this.close();
|
|
386
|
+
this.close();
|
|
423
387
|
return;
|
|
424
388
|
}
|
|
425
389
|
if (matchesKey(data, Key.tab)) {
|
|
@@ -443,7 +407,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
443
407
|
}
|
|
444
408
|
|
|
445
409
|
private handleServerInput(data: string): void {
|
|
446
|
-
if (data === "
|
|
410
|
+
if (data === "D") {
|
|
447
411
|
this.discoverSelected();
|
|
448
412
|
return;
|
|
449
413
|
}
|
|
@@ -490,7 +454,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
490
454
|
);
|
|
491
455
|
return;
|
|
492
456
|
}
|
|
493
|
-
if (data === "
|
|
457
|
+
if (data === "R") {
|
|
494
458
|
this.revalidateSelectedChain();
|
|
495
459
|
return;
|
|
496
460
|
}
|
|
@@ -510,7 +474,6 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
510
474
|
}
|
|
511
475
|
|
|
512
476
|
private handleSettingsInput(data: string): void {
|
|
513
|
-
if (this.settingsBusy) return;
|
|
514
477
|
if (this.keybindings.matches(data, "tui.select.up") || matchesKey(data, Key.up)) {
|
|
515
478
|
this.selectedSettingIndex = cycleIndex(
|
|
516
479
|
this.selectedSettingIndex,
|
|
@@ -613,7 +576,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
613
576
|
this.theme.fg("dim", `${server.transport}${server.auth ? ` · ${server.auth}` : ""}`),
|
|
614
577
|
server.busy
|
|
615
578
|
? this.theme.fg("warning", "Working…")
|
|
616
|
-
: `${this.theme.fg("accent", "[
|
|
579
|
+
: `${this.theme.fg("accent", "[D]")} Discover tools ${this.theme.fg("accent", "[space]")} ${server.enabled ? "Disable server" : "Enable server"}`,
|
|
617
580
|
...(server.error ? [this.theme.fg("warning", `Error: ${server.error}`)] : []),
|
|
618
581
|
this.theme.fg("dim", "─".repeat(Math.max(1, width))),
|
|
619
582
|
this.theme.fg("dim", this.theme.bold("TOOLS")),
|
|
@@ -729,7 +692,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
729
692
|
this.theme.fg("muted", `${chain.scope} · ${chain.status} · ${chain.nativeTool}`),
|
|
730
693
|
chain.busy
|
|
731
694
|
? this.theme.fg("warning", "Working…")
|
|
732
|
-
: `${this.theme.fg("accent", "[space]")} ${chain.enabled ? "Disable" : "Enable"} ${this.theme.fg("accent", "[
|
|
695
|
+
: `${this.theme.fg("accent", "[space]")} ${chain.enabled ? "Disable" : "Enable"} ${this.theme.fg("accent", "[R]")} Revalidate ${this.theme.fg("accent", "[del]")} Delete`,
|
|
733
696
|
...(chain.error ? [this.theme.fg("warning", `Error: ${chain.error}`)] : []),
|
|
734
697
|
"",
|
|
735
698
|
...wrapPlainText(chain.description, width).map((line) => this.theme.fg("muted", line)),
|
|
@@ -798,6 +761,11 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
798
761
|
),
|
|
799
762
|
);
|
|
800
763
|
}
|
|
764
|
+
lines.push("", this.theme.fg("dim", this.theme.bold("OUTCOMES")));
|
|
765
|
+
if (stats.outcomes.length === 0) lines.push(this.theme.fg("muted", "No outcomes yet"));
|
|
766
|
+
for (const outcome of stats.outcomes) {
|
|
767
|
+
lines.push(`${outcome.name.padEnd(22)} ${outcome.count.toLocaleString().padStart(8)}`);
|
|
768
|
+
}
|
|
801
769
|
lines.push("", this.theme.fg("dim", this.theme.bold("FAILURE STAGES")));
|
|
802
770
|
if (stats.failures.length === 0) lines.push(this.theme.fg("muted", "No failures yet"));
|
|
803
771
|
for (const failure of stats.failures) {
|
|
@@ -824,7 +792,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
824
792
|
for (const [index, definition] of SETTING_DEFINITIONS.entries()) {
|
|
825
793
|
const selected = index === this.selectedSettingIndex;
|
|
826
794
|
const prefix = selected ? this.theme.fg("accent", "→") : " ";
|
|
827
|
-
const value = settingLabel(definition, this.
|
|
795
|
+
const value = settingLabel(definition, this.options.settings[definition.key]);
|
|
828
796
|
const reserved = visibleWidth(prefix) + visibleWidth(value) + 3;
|
|
829
797
|
const label = truncateToWidth(definition.label, Math.max(4, leftWidth - reserved), "…");
|
|
830
798
|
const gap = " ".repeat(Math.max(1, leftWidth - reserved - visibleWidth(label) + 1));
|
|
@@ -862,18 +830,13 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
862
830
|
: definition
|
|
863
831
|
? [
|
|
864
832
|
this.theme.fg("accent", this.theme.bold(definition.label)),
|
|
865
|
-
this.theme.fg("muted", settingLabel(definition, this.
|
|
833
|
+
this.theme.fg("muted", settingLabel(definition, this.options.settings[definition.key])),
|
|
866
834
|
"",
|
|
867
835
|
...wrapPlainText(definition.description, rightWidth).map((line) =>
|
|
868
836
|
this.theme.fg("muted", line),
|
|
869
837
|
),
|
|
870
838
|
"",
|
|
871
|
-
this.theme.fg("dim", "←/→ change · enter next
|
|
872
|
-
...(this.settingsBusy
|
|
873
|
-
? ["", this.theme.fg("warning", "Saving staged changes…")]
|
|
874
|
-
: this.hasUnsavedChanges()
|
|
875
|
-
? ["", this.theme.fg("warning", "Unsaved changes")]
|
|
876
|
-
: []),
|
|
839
|
+
this.theme.fg("dim", "←/→ change · enter next"),
|
|
877
840
|
...(this.settingsError
|
|
878
841
|
? ["", this.theme.fg("warning", `Error: ${this.settingsError}`)]
|
|
879
842
|
: []),
|
|
@@ -889,18 +852,17 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
889
852
|
}
|
|
890
853
|
|
|
891
854
|
private footer(): string {
|
|
892
|
-
const pending = this.hasUnsavedChanges() ? " · * unsaved · ctrl+s save" : "";
|
|
893
855
|
const report = ` · ${PROBLEM_REPORT_SHORTCUT}`;
|
|
894
856
|
if (this.activeTab === "settings") {
|
|
895
|
-
return `tab servers · ↑/↓ navigate · ←/→ change · enter select ·
|
|
857
|
+
return `tab servers · ↑/↓ navigate · ←/→ change · enter select · esc close${report}`;
|
|
896
858
|
}
|
|
897
859
|
if (this.activeTab === "chains") {
|
|
898
|
-
return
|
|
860
|
+
return "tab stats · ↑/↓ navigate · space toggle · R revalidate · del delete · esc close";
|
|
899
861
|
}
|
|
900
862
|
if (this.activeTab === "stats") {
|
|
901
|
-
return `tab settings · bounded local rollups · esc close${
|
|
863
|
+
return `tab settings · bounded local rollups · esc close${report}`;
|
|
902
864
|
}
|
|
903
|
-
return `tab chains · ←/→ pane · ↑/↓ navigate · space toggle ·
|
|
865
|
+
return `tab chains · ←/→ pane · ↑/↓ navigate · space toggle · D discover · esc close${report}`;
|
|
904
866
|
}
|
|
905
867
|
|
|
906
868
|
private moveSelection(direction: -1 | 1): void {
|
|
@@ -923,31 +885,31 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
923
885
|
|
|
924
886
|
private toggleSelectedServer(): void {
|
|
925
887
|
const server = this.selectedServer();
|
|
926
|
-
if (!server || server.busy
|
|
927
|
-
|
|
888
|
+
if (!server || server.busy) return;
|
|
889
|
+
const enabled = !server.enabled;
|
|
890
|
+
server.busy = true;
|
|
928
891
|
delete server.error;
|
|
892
|
+
void this.options
|
|
893
|
+
.onSetServerEnabled(server, enabled)
|
|
894
|
+
.then((updated) => applyServerUpdate(server, updated))
|
|
895
|
+
.catch((error: unknown) => {
|
|
896
|
+
server.error = summarizeError(error);
|
|
897
|
+
})
|
|
898
|
+
.finally(() => {
|
|
899
|
+
server.busy = false;
|
|
900
|
+
this.requestRender();
|
|
901
|
+
});
|
|
929
902
|
}
|
|
930
903
|
|
|
931
904
|
private discoverSelected(): void {
|
|
932
905
|
const server = this.selectedServer();
|
|
933
|
-
if (!server || server.busy
|
|
934
|
-
if (server.enabled !== this.savedServerEnabled.get(server.name)) {
|
|
935
|
-
server.error = "Save this server change before discovering tools";
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
if (!server.enabled) {
|
|
939
|
-
server.error = "Enable and save this server before discovering tools";
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
906
|
+
if (!server || server.busy) return;
|
|
942
907
|
server.busy = true;
|
|
943
908
|
delete server.error;
|
|
944
909
|
this.requestRender();
|
|
945
910
|
void this.options
|
|
946
911
|
.onDiscover(server)
|
|
947
|
-
.then((updated) =>
|
|
948
|
-
applyServerUpdate(server, updated);
|
|
949
|
-
this.applyDraftToolPolicy();
|
|
950
|
-
})
|
|
912
|
+
.then((updated) => applyServerUpdate(server, updated))
|
|
951
913
|
.catch((error: unknown) => {
|
|
952
914
|
server.error = summarizeError(error);
|
|
953
915
|
})
|
|
@@ -959,31 +921,43 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
959
921
|
|
|
960
922
|
private toggleSelectedTool(): void {
|
|
961
923
|
const server = this.selectedServer();
|
|
962
|
-
if (!server || server.busy
|
|
924
|
+
if (!server || server.busy) return;
|
|
963
925
|
const tools = this.filteredTools(server);
|
|
964
926
|
const tool = tools[this.selectedToolIndex];
|
|
965
927
|
if (!tool || tool.busy) return;
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
928
|
+
tool.busy = true;
|
|
929
|
+
void this.options
|
|
930
|
+
.onSetToolEnabled(server, tool, !tool.enabled)
|
|
931
|
+
.then((updated) => applyServerUpdate(server, updated))
|
|
932
|
+
.catch((error: unknown) => {
|
|
933
|
+
server.error = summarizeError(error);
|
|
934
|
+
})
|
|
935
|
+
.finally(() => {
|
|
936
|
+
tool.busy = false;
|
|
937
|
+
this.requestRender();
|
|
938
|
+
});
|
|
971
939
|
}
|
|
972
940
|
|
|
973
941
|
private toggleSelectedChain(): void {
|
|
974
942
|
const chain = this.selectedChain();
|
|
975
|
-
if (!chain || chain.busy
|
|
976
|
-
|
|
943
|
+
if (!chain || chain.busy) return;
|
|
944
|
+
chain.busy = true;
|
|
977
945
|
delete chain.error;
|
|
946
|
+
void this.options
|
|
947
|
+
.onSetChainEnabled(chain, !chain.enabled)
|
|
948
|
+
.then((updated) => this.replaceChains(updated, chain))
|
|
949
|
+
.catch((error: unknown) => {
|
|
950
|
+
chain.error = summarizeError(error);
|
|
951
|
+
})
|
|
952
|
+
.finally(() => {
|
|
953
|
+
chain.busy = false;
|
|
954
|
+
this.requestRender();
|
|
955
|
+
});
|
|
978
956
|
}
|
|
979
957
|
|
|
980
958
|
private revalidateSelectedChain(): void {
|
|
981
959
|
const chain = this.selectedChain();
|
|
982
|
-
if (!chain || chain.busy
|
|
983
|
-
if (chain.enabled !== this.savedChainEnabled.get(chainKey(chain))) {
|
|
984
|
-
chain.error = "Save this chain change before revalidation";
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
960
|
+
if (!chain || chain.busy) return;
|
|
987
961
|
chain.busy = true;
|
|
988
962
|
delete chain.error;
|
|
989
963
|
void this.options
|
|
@@ -998,20 +972,8 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
998
972
|
});
|
|
999
973
|
}
|
|
1000
974
|
|
|
1001
|
-
private replaceChains(
|
|
1002
|
-
updated: ChainModalState[],
|
|
1003
|
-
selected?: ChainModalState,
|
|
1004
|
-
preserveDrafts = true,
|
|
1005
|
-
): void {
|
|
1006
|
-
const drafts = preserveDrafts ? this.chainEnabledChanges() : [];
|
|
975
|
+
private replaceChains(updated: ChainModalState[], selected?: ChainModalState): void {
|
|
1007
976
|
this.options.chains.splice(0, this.options.chains.length, ...updated);
|
|
1008
|
-
this.savedChainEnabled = chainEnabledMap(updated);
|
|
1009
|
-
for (const draft of drafts) {
|
|
1010
|
-
const chain = this.options.chains.find(
|
|
1011
|
-
(candidate) => candidate.name === draft.name && candidate.scope === draft.scope,
|
|
1012
|
-
);
|
|
1013
|
-
if (chain) applyChainEnabled(chain, draft.enabled);
|
|
1014
|
-
}
|
|
1015
977
|
if (selected) {
|
|
1016
978
|
const index = this.filteredChains().findIndex(
|
|
1017
979
|
(chain) => chain.name === selected.name && chain.scope === selected.scope,
|
|
@@ -1043,8 +1005,8 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
1043
1005
|
|
|
1044
1006
|
private cycleSelectedSetting(direction: -1 | 1): void {
|
|
1045
1007
|
const definition = SETTING_DEFINITIONS[this.selectedSettingIndex];
|
|
1046
|
-
if (!definition
|
|
1047
|
-
const current = this.
|
|
1008
|
+
if (!definition) return;
|
|
1009
|
+
const current = this.options.settings[definition.key];
|
|
1048
1010
|
const currentIndex = Math.max(
|
|
1049
1011
|
0,
|
|
1050
1012
|
definition.choices.findIndex((choice) => choice.value === current),
|
|
@@ -1053,43 +1015,15 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
1053
1015
|
definition.choices[cycleIndex(currentIndex, direction, definition.choices.length)];
|
|
1054
1016
|
if (!choice) return;
|
|
1055
1017
|
this.settingsError = undefined;
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
private async persistDraft(): Promise<boolean> {
|
|
1068
|
-
if (this.settingsBusy) return false;
|
|
1069
|
-
if (!this.hasUnsavedChanges()) return true;
|
|
1070
|
-
this.settingsBusy = true;
|
|
1071
|
-
this.settingsError = undefined;
|
|
1072
|
-
this.requestRender();
|
|
1073
|
-
try {
|
|
1074
|
-
const result = await this.options.onSaveChanges(
|
|
1075
|
-
cloneSettings(this.draftSettings),
|
|
1076
|
-
this.serverEnabledChanges(),
|
|
1077
|
-
this.chainEnabledChanges(),
|
|
1078
|
-
);
|
|
1079
|
-
this.savedSettings = cloneSettings(result.settings);
|
|
1080
|
-
this.draftSettings = cloneSettings(result.settings);
|
|
1081
|
-
this.options.servers.splice(0, this.options.servers.length, ...result.servers);
|
|
1082
|
-
this.savedServerEnabled = serverEnabledMap(result.servers);
|
|
1083
|
-
this.replaceChains(result.chains, undefined, false);
|
|
1084
|
-
this.applyDraftToolPolicy();
|
|
1085
|
-
return true;
|
|
1086
|
-
} catch (error) {
|
|
1087
|
-
this.settingsError = summarizeError(error);
|
|
1088
|
-
return false;
|
|
1089
|
-
} finally {
|
|
1090
|
-
this.settingsBusy = false;
|
|
1091
|
-
this.requestRender();
|
|
1092
|
-
}
|
|
1018
|
+
void this.options
|
|
1019
|
+
.onSetSetting(definition.key, choice.value)
|
|
1020
|
+
.then((settings) => {
|
|
1021
|
+
this.options.settings = settings;
|
|
1022
|
+
})
|
|
1023
|
+
.catch((error: unknown) => {
|
|
1024
|
+
this.settingsError = summarizeError(error);
|
|
1025
|
+
})
|
|
1026
|
+
.finally(() => this.requestRender());
|
|
1093
1027
|
}
|
|
1094
1028
|
|
|
1095
1029
|
private focusProblemReport(): void {
|
|
@@ -1100,70 +1034,7 @@ class ServerManagerModal implements Component, Focusable {
|
|
|
1100
1034
|
}
|
|
1101
1035
|
|
|
1102
1036
|
private openProblemReport(): void {
|
|
1103
|
-
|
|
1104
|
-
else this.close("report-problem");
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
private resolveUnsavedClose(result?: ServerManagerResult): void {
|
|
1108
|
-
if (this.closePromptBusy || this.settingsBusy) return;
|
|
1109
|
-
this.closePromptBusy = true;
|
|
1110
|
-
void this.options
|
|
1111
|
-
.onResolveUnsaved()
|
|
1112
|
-
.then(async (action) => {
|
|
1113
|
-
if (action === "discard") {
|
|
1114
|
-
this.close(result);
|
|
1115
|
-
return;
|
|
1116
|
-
}
|
|
1117
|
-
if (action === "save" && (await this.persistDraft())) this.close(result);
|
|
1118
|
-
})
|
|
1119
|
-
.catch((error: unknown) => {
|
|
1120
|
-
this.settingsError = summarizeError(error);
|
|
1121
|
-
})
|
|
1122
|
-
.finally(() => {
|
|
1123
|
-
this.closePromptBusy = false;
|
|
1124
|
-
this.requestRender();
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
private hasUnsavedChanges(): boolean {
|
|
1129
|
-
return (
|
|
1130
|
-
!settingsEqual(this.savedSettings, this.draftSettings) ||
|
|
1131
|
-
this.serverEnabledChanges().length > 0 ||
|
|
1132
|
-
this.chainEnabledChanges().length > 0
|
|
1133
|
-
);
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
private serverEnabledChanges(): ServerEnabledChange[] {
|
|
1137
|
-
return this.options.servers.flatMap((server) => {
|
|
1138
|
-
const previousEnabled = this.savedServerEnabled.get(server.name);
|
|
1139
|
-
return previousEnabled === undefined || previousEnabled === server.enabled
|
|
1140
|
-
? []
|
|
1141
|
-
: [{ name: server.name, previousEnabled, enabled: server.enabled }];
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
private chainEnabledChanges(): ChainEnabledChange[] {
|
|
1146
|
-
return this.options.chains.flatMap((chain) => {
|
|
1147
|
-
const previousEnabled = this.savedChainEnabled.get(chainKey(chain));
|
|
1148
|
-
return previousEnabled === undefined || previousEnabled === chain.enabled
|
|
1149
|
-
? []
|
|
1150
|
-
: [
|
|
1151
|
-
{
|
|
1152
|
-
name: chain.name,
|
|
1153
|
-
scope: chain.scope,
|
|
1154
|
-
previousEnabled,
|
|
1155
|
-
enabled: chain.enabled,
|
|
1156
|
-
},
|
|
1157
|
-
];
|
|
1158
|
-
});
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
private applyDraftToolPolicy(): void {
|
|
1162
|
-
for (const server of this.options.servers) {
|
|
1163
|
-
const disabled = new Set(this.draftSettings.disabledTools[server.name] ?? []);
|
|
1164
|
-
for (const tool of server.tools) tool.enabled = !disabled.has(tool.name);
|
|
1165
|
-
server.toolCount = server.tools.filter((tool) => tool.enabled).length;
|
|
1166
|
-
}
|
|
1037
|
+
this.close("report-problem");
|
|
1167
1038
|
}
|
|
1168
1039
|
|
|
1169
1040
|
private filteredServers(): ServerModalState[] {
|
|
@@ -1389,38 +1260,6 @@ function serverIcon(server: ServerModalState, theme: Theme): string {
|
|
|
1389
1260
|
return theme.fg("warning", "◌");
|
|
1390
1261
|
}
|
|
1391
1262
|
|
|
1392
|
-
function serverEnabledMap(servers: readonly ServerModalState[]): Map<string, boolean> {
|
|
1393
|
-
return new Map(servers.map((server) => [server.name, server.enabled]));
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
function chainEnabledMap(chains: readonly ChainModalState[]): Map<string, boolean> {
|
|
1397
|
-
return new Map(chains.map((chain) => [chainKey(chain), chain.enabled]));
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
function chainKey(chain: Pick<ChainModalState, "name" | "scope">): string {
|
|
1401
|
-
return `${chain.scope}:${chain.name}`;
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
function applyChainEnabled(chain: ChainModalState, enabled: boolean): void {
|
|
1405
|
-
const shadowed = chain.status === "shadowed";
|
|
1406
|
-
chain.enabled = enabled;
|
|
1407
|
-
if (shadowed) return;
|
|
1408
|
-
chain.status = enabled ? (chain.staleDependencies.length > 0 ? "stale" : "ready") : "disabled";
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
function cloneSettings(settings: CodeMcpSettings): CodeMcpSettings {
|
|
1412
|
-
return {
|
|
1413
|
-
...settings,
|
|
1414
|
-
disabledTools: Object.fromEntries(
|
|
1415
|
-
Object.entries(settings.disabledTools).map(([server, tools]) => [server, [...tools]]),
|
|
1416
|
-
),
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
function settingsEqual(left: CodeMcpSettings, right: CodeMcpSettings): boolean {
|
|
1421
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
1263
|
function settingLabel(definition: SettingDefinition, value: EditableSettingValue): string {
|
|
1425
1264
|
return definition.choices.find((choice) => choice.value === value)?.label ?? String(value);
|
|
1426
1265
|
}
|
package/src/prompts.ts
CHANGED
|
@@ -8,10 +8,10 @@ export const INSPECT_PROMPT_GUIDELINES = [
|
|
|
8
8
|
] as const;
|
|
9
9
|
|
|
10
10
|
export const EXECUTE_PROMPT_GUIDELINES = [
|
|
11
|
-
"Use
|
|
11
|
+
"Use bounded execution to deterministically filter, aggregate, sample, join, or reduce upstream data in the sandbox; do not return raw payloads.",
|
|
12
12
|
"Keep a model turn between calls when an intermediate result changes the semantic decision or user approval is required.",
|
|
13
|
-
"Return the smallest
|
|
14
|
-
"SDK facades are prebound globals and must not be imported.
|
|
13
|
+
"Return the smallest answer. If an oversized result provides result_ref, refine it via inputRef instead of repeating upstream calls.",
|
|
14
|
+
"SDK facades are prebound globals and must not be imported. Use `import asyncio` for `asyncio.gather`; other imports, classes, `asyncio.create_task`, and `__import__` are unsupported.",
|
|
15
15
|
] as const;
|
|
16
16
|
|
|
17
17
|
export const SAVE_CHAIN_PROMPT_GUIDELINES = [
|