@wrongstack/tui 0.282.1 → 0.282.2
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/index.d.ts +66 -0
- package/dist/index.js +1062 -22
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1667,6 +1667,11 @@ function closePanels(state) {
|
|
|
1667
1667
|
settingsPicker: { ...state.settingsPicker, open: false },
|
|
1668
1668
|
statuslinePicker: { ...state.statuslinePicker, open: false },
|
|
1669
1669
|
pluginPicker: { ...state.pluginPicker, open: false },
|
|
1670
|
+
mcpPicker: { ...state.mcpPicker, open: false },
|
|
1671
|
+
toolsPicker: { ...state.toolsPicker, open: false },
|
|
1672
|
+
brainPanel: { ...state.brainPanel, open: false },
|
|
1673
|
+
helpPanel: { ...state.helpPanel, open: false },
|
|
1674
|
+
shadowPanel: { ...state.shadowPanel, open: false },
|
|
1670
1675
|
authPanel: { ...state.authPanel, open: false, busy: false },
|
|
1671
1676
|
projectPicker: { ...state.projectPicker, open: false },
|
|
1672
1677
|
fKeyPicker: { ...state.fKeyPicker, open: false },
|
|
@@ -3168,6 +3173,181 @@ function reducer(state, action) {
|
|
|
3168
3173
|
return { ...state, pluginPicker: { ...state.pluginPicker, busy: action.busy } };
|
|
3169
3174
|
case "pluginPickerHint":
|
|
3170
3175
|
return { ...state, pluginPicker: { ...state.pluginPicker, hint: action.text } };
|
|
3176
|
+
case "mcpPickerOpen": {
|
|
3177
|
+
const items = action.items ?? state.mcpPicker.items;
|
|
3178
|
+
return {
|
|
3179
|
+
...state,
|
|
3180
|
+
...closePanels(state),
|
|
3181
|
+
mcpPicker: {
|
|
3182
|
+
open: true,
|
|
3183
|
+
items,
|
|
3184
|
+
selected: Math.min(state.mcpPicker.selected, Math.max(0, items.length - 1)),
|
|
3185
|
+
busy: items.length === 0,
|
|
3186
|
+
hint: void 0
|
|
3187
|
+
}
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
case "mcpPickerClose":
|
|
3191
|
+
return { ...state, mcpPicker: { ...state.mcpPicker, open: false, busy: false } };
|
|
3192
|
+
case "mcpPickerMove": {
|
|
3193
|
+
const count = state.mcpPicker.items.length;
|
|
3194
|
+
if (count === 0) return state;
|
|
3195
|
+
return {
|
|
3196
|
+
...state,
|
|
3197
|
+
mcpPicker: {
|
|
3198
|
+
...state.mcpPicker,
|
|
3199
|
+
selected: (state.mcpPicker.selected + action.delta + count) % count,
|
|
3200
|
+
hint: void 0
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
}
|
|
3204
|
+
case "mcpPickerSetItems":
|
|
3205
|
+
return {
|
|
3206
|
+
...state,
|
|
3207
|
+
mcpPicker: {
|
|
3208
|
+
...state.mcpPicker,
|
|
3209
|
+
items: action.items,
|
|
3210
|
+
selected: Math.min(state.mcpPicker.selected, Math.max(0, action.items.length - 1)),
|
|
3211
|
+
busy: false
|
|
3212
|
+
}
|
|
3213
|
+
};
|
|
3214
|
+
case "mcpPickerBusy":
|
|
3215
|
+
return { ...state, mcpPicker: { ...state.mcpPicker, busy: action.busy } };
|
|
3216
|
+
case "mcpPickerHint":
|
|
3217
|
+
return { ...state, mcpPicker: { ...state.mcpPicker, hint: action.text } };
|
|
3218
|
+
case "toolsPickerOpen": {
|
|
3219
|
+
const items = action.items ?? state.toolsPicker.items;
|
|
3220
|
+
return {
|
|
3221
|
+
...state,
|
|
3222
|
+
...closePanels(state),
|
|
3223
|
+
toolsPicker: {
|
|
3224
|
+
open: true,
|
|
3225
|
+
items,
|
|
3226
|
+
selected: Math.min(state.toolsPicker.selected, Math.max(0, items.length - 1)),
|
|
3227
|
+
busy: items.length === 0,
|
|
3228
|
+
hint: void 0,
|
|
3229
|
+
filter: void 0
|
|
3230
|
+
}
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
case "toolsPickerClose":
|
|
3234
|
+
return { ...state, toolsPicker: { ...state.toolsPicker, open: false, busy: false, filter: void 0 } };
|
|
3235
|
+
case "toolsPickerMove": {
|
|
3236
|
+
const count = state.toolsPicker.items.length;
|
|
3237
|
+
if (count === 0) return state;
|
|
3238
|
+
return {
|
|
3239
|
+
...state,
|
|
3240
|
+
toolsPicker: {
|
|
3241
|
+
...state.toolsPicker,
|
|
3242
|
+
selected: (state.toolsPicker.selected + action.delta + count) % count,
|
|
3243
|
+
hint: void 0
|
|
3244
|
+
}
|
|
3245
|
+
};
|
|
3246
|
+
}
|
|
3247
|
+
case "toolsPickerSetItems":
|
|
3248
|
+
return {
|
|
3249
|
+
...state,
|
|
3250
|
+
toolsPicker: {
|
|
3251
|
+
...state.toolsPicker,
|
|
3252
|
+
items: action.items,
|
|
3253
|
+
selected: Math.min(state.toolsPicker.selected, Math.max(0, action.items.length - 1)),
|
|
3254
|
+
busy: false
|
|
3255
|
+
}
|
|
3256
|
+
};
|
|
3257
|
+
case "toolsPickerToggle":
|
|
3258
|
+
return state;
|
|
3259
|
+
case "toolsPickerBusy":
|
|
3260
|
+
return { ...state, toolsPicker: { ...state.toolsPicker, busy: action.busy } };
|
|
3261
|
+
case "toolsPickerHint":
|
|
3262
|
+
return { ...state, toolsPicker: { ...state.toolsPicker, hint: action.text } };
|
|
3263
|
+
case "toolsPickerFilter":
|
|
3264
|
+
return { ...state, toolsPicker: { ...state.toolsPicker, filter: action.filter } };
|
|
3265
|
+
case "brainOpen": {
|
|
3266
|
+
return {
|
|
3267
|
+
...state,
|
|
3268
|
+
...closePanels(state),
|
|
3269
|
+
brainPanel: {
|
|
3270
|
+
open: true,
|
|
3271
|
+
riskLevel: action.riskLevel,
|
|
3272
|
+
log: action.log,
|
|
3273
|
+
selected: 0,
|
|
3274
|
+
hint: void 0
|
|
3275
|
+
}
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
case "brainClose":
|
|
3279
|
+
return { ...state, brainPanel: { ...state.brainPanel, open: false } };
|
|
3280
|
+
case "brainMove": {
|
|
3281
|
+
const count = state.brainPanel.log.length;
|
|
3282
|
+
if (count === 0) return state;
|
|
3283
|
+
return {
|
|
3284
|
+
...state,
|
|
3285
|
+
brainPanel: {
|
|
3286
|
+
...state.brainPanel,
|
|
3287
|
+
selected: (state.brainPanel.selected + action.delta + count) % count,
|
|
3288
|
+
hint: void 0
|
|
3289
|
+
}
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
case "brainRiskChange": {
|
|
3293
|
+
const levels = ["off", "low", "medium", "high", "all"];
|
|
3294
|
+
const cur = levels.indexOf(state.brainPanel.riskLevel);
|
|
3295
|
+
const next = (cur + action.delta + levels.length) % levels.length;
|
|
3296
|
+
return {
|
|
3297
|
+
...state,
|
|
3298
|
+
brainPanel: {
|
|
3299
|
+
...state.brainPanel,
|
|
3300
|
+
riskLevel: levels[next]
|
|
3301
|
+
}
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
case "brainSetLog":
|
|
3305
|
+
return {
|
|
3306
|
+
...state,
|
|
3307
|
+
brainPanel: {
|
|
3308
|
+
...state.brainPanel,
|
|
3309
|
+
log: action.log,
|
|
3310
|
+
selected: Math.min(state.brainPanel.selected, Math.max(0, action.log.length - 1))
|
|
3311
|
+
}
|
|
3312
|
+
};
|
|
3313
|
+
case "brainHint":
|
|
3314
|
+
return { ...state, brainPanel: { ...state.brainPanel, hint: action.text } };
|
|
3315
|
+
case "helpOpen":
|
|
3316
|
+
return {
|
|
3317
|
+
...state,
|
|
3318
|
+
...closePanels(state),
|
|
3319
|
+
helpPanel: { open: true, entries: action.entries, selected: 0, filter: "", hint: void 0 }
|
|
3320
|
+
};
|
|
3321
|
+
case "helpClose":
|
|
3322
|
+
return { ...state, helpPanel: { ...state.helpPanel, open: false, filter: "" } };
|
|
3323
|
+
case "helpMove": {
|
|
3324
|
+
const count = state.helpPanel.entries.length;
|
|
3325
|
+
if (count === 0) return state;
|
|
3326
|
+
return {
|
|
3327
|
+
...state,
|
|
3328
|
+
helpPanel: {
|
|
3329
|
+
...state.helpPanel,
|
|
3330
|
+
selected: (state.helpPanel.selected + action.delta + count) % count,
|
|
3331
|
+
hint: void 0
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
case "helpFilter":
|
|
3336
|
+
return { ...state, helpPanel: { ...state.helpPanel, filter: action.filter, selected: 0 } };
|
|
3337
|
+
case "helpHint":
|
|
3338
|
+
return { ...state, helpPanel: { ...state.helpPanel, hint: action.text } };
|
|
3339
|
+
case "shadowOpen":
|
|
3340
|
+
return {
|
|
3341
|
+
...state,
|
|
3342
|
+
...closePanels(state),
|
|
3343
|
+
shadowPanel: { open: true, shadow: action.shadow, hint: void 0 }
|
|
3344
|
+
};
|
|
3345
|
+
case "shadowClose":
|
|
3346
|
+
return { ...state, shadowPanel: { ...state.shadowPanel, open: false } };
|
|
3347
|
+
case "shadowUpdate":
|
|
3348
|
+
return { ...state, shadowPanel: { ...state.shadowPanel, shadow: action.shadow } };
|
|
3349
|
+
case "shadowHint":
|
|
3350
|
+
return { ...state, shadowPanel: { ...state.shadowPanel, hint: action.text } };
|
|
3171
3351
|
case "authOpen":
|
|
3172
3352
|
return {
|
|
3173
3353
|
...state,
|
|
@@ -12599,7 +12779,135 @@ function PlanRow({ item }) {
|
|
|
12599
12779
|
] }) : null
|
|
12600
12780
|
] });
|
|
12601
12781
|
}
|
|
12602
|
-
var CHROME_ROWS2 =
|
|
12782
|
+
var CHROME_ROWS2 = 14;
|
|
12783
|
+
var RISK_DESCS = {
|
|
12784
|
+
off: "Human decides everything",
|
|
12785
|
+
low: "Auto-decide low risk only",
|
|
12786
|
+
medium: "Auto-decide up to medium risk",
|
|
12787
|
+
high: "Auto-decide up to high risk",
|
|
12788
|
+
all: "Auto-decide everything"
|
|
12789
|
+
};
|
|
12790
|
+
var RISK_COLORS2 = {
|
|
12791
|
+
off: "gray",
|
|
12792
|
+
low: "green",
|
|
12793
|
+
medium: "yellow",
|
|
12794
|
+
high: "red",
|
|
12795
|
+
all: "magenta"
|
|
12796
|
+
};
|
|
12797
|
+
function BrainPanel({
|
|
12798
|
+
riskLevel,
|
|
12799
|
+
log,
|
|
12800
|
+
selected,
|
|
12801
|
+
hint
|
|
12802
|
+
}) {
|
|
12803
|
+
const { stdout } = useStdout();
|
|
12804
|
+
const termRows = stdout?.rows ?? 24;
|
|
12805
|
+
const maxVisible = Math.max(4, termRows - CHROME_ROWS2);
|
|
12806
|
+
const total = log.length;
|
|
12807
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12808
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12809
|
+
const above = windowStart;
|
|
12810
|
+
const below = total - windowEnd;
|
|
12811
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
12812
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "\u2501\u2501 Brain \u2501\u2501" }),
|
|
12813
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate log \xB7 \u2190/\u2192 change risk \xB7 Esc close" }),
|
|
12814
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12815
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
12816
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Risk ceiling: " }),
|
|
12817
|
+
/* @__PURE__ */ jsx(Text, { color: RISK_COLORS2[riskLevel], bold: true, children: riskLevel.toUpperCase() }),
|
|
12818
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${RISK_DESCS[riskLevel]}` })
|
|
12819
|
+
] }),
|
|
12820
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12821
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "Recent decisions" }),
|
|
12822
|
+
total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No decisions recorded yet this session." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12823
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12824
|
+
log.slice(windowStart, windowEnd).map((entry, i) => {
|
|
12825
|
+
const index = windowStart + i;
|
|
12826
|
+
const focused = index === selected;
|
|
12827
|
+
return /* @__PURE__ */ jsxs(
|
|
12828
|
+
Text,
|
|
12829
|
+
{
|
|
12830
|
+
inverse: focused,
|
|
12831
|
+
...focused ? { color: "magenta" } : {},
|
|
12832
|
+
wrap: "truncate-end",
|
|
12833
|
+
children: [
|
|
12834
|
+
focused ? "\u203A " : " ",
|
|
12835
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.age.padEnd(8) }),
|
|
12836
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: entry.kind.padEnd(12) }),
|
|
12837
|
+
/* @__PURE__ */ jsx(Text, { children: entry.question.length > 60 ? `${entry.question.slice(0, 57)}\u2026` : entry.question }),
|
|
12838
|
+
entry.outcome ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2192 ${entry.outcome.length > 20 ? `${entry.outcome.slice(0, 17)}\u2026` : entry.outcome}` }) : null
|
|
12839
|
+
]
|
|
12840
|
+
},
|
|
12841
|
+
`${entry.kind}-${i}`
|
|
12842
|
+
);
|
|
12843
|
+
}),
|
|
12844
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
12845
|
+
] })
|
|
12846
|
+
] })
|
|
12847
|
+
] }),
|
|
12848
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12849
|
+
] });
|
|
12850
|
+
}
|
|
12851
|
+
var CHROME_ROWS3 = 17;
|
|
12852
|
+
function statusBadge(status, enabled) {
|
|
12853
|
+
if (!enabled) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disabled" });
|
|
12854
|
+
switch (status) {
|
|
12855
|
+
case "connected":
|
|
12856
|
+
return /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF connected" });
|
|
12857
|
+
case "connecting":
|
|
12858
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D0 connecting" });
|
|
12859
|
+
case "reconnecting":
|
|
12860
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D1 reconnecting" });
|
|
12861
|
+
case "disconnected":
|
|
12862
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disconnected" });
|
|
12863
|
+
case "failed":
|
|
12864
|
+
return /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 failed" });
|
|
12865
|
+
default:
|
|
12866
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: status });
|
|
12867
|
+
}
|
|
12868
|
+
}
|
|
12869
|
+
function McpPicker({
|
|
12870
|
+
items,
|
|
12871
|
+
selected,
|
|
12872
|
+
busy = false,
|
|
12873
|
+
hint
|
|
12874
|
+
}) {
|
|
12875
|
+
const { stdout } = useStdout();
|
|
12876
|
+
const rows = stdout?.rows ?? 24;
|
|
12877
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS3);
|
|
12878
|
+
const total = items.length;
|
|
12879
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12880
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12881
|
+
const above = windowStart;
|
|
12882
|
+
const below = total - windowEnd;
|
|
12883
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
12884
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MCP Servers" }),
|
|
12885
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle enable \xB7 r restart \xB7 Esc close" }),
|
|
12886
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: busy ? "Loading servers\u2026" : "No MCP servers configured." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12887
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12888
|
+
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
12889
|
+
const index = windowStart + i;
|
|
12890
|
+
const focused = index === selected;
|
|
12891
|
+
const marker = focused ? "\u203A" : " ";
|
|
12892
|
+
return /* @__PURE__ */ jsxs(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
12893
|
+
marker,
|
|
12894
|
+
" ",
|
|
12895
|
+
statusBadge(item.status, item.enabled),
|
|
12896
|
+
" ",
|
|
12897
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.name.padEnd(18) }),
|
|
12898
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12899
|
+
item.transport.padEnd(14),
|
|
12900
|
+
item.toolCount > 0 ? `${item.toolCount} tools` : "",
|
|
12901
|
+
item.lazy ? " lazy" : ""
|
|
12902
|
+
] })
|
|
12903
|
+
] }, item.name);
|
|
12904
|
+
}),
|
|
12905
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
12906
|
+
] }) }),
|
|
12907
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12908
|
+
] });
|
|
12909
|
+
}
|
|
12910
|
+
var CHROME_ROWS4 = 17;
|
|
12603
12911
|
function PluginPicker({
|
|
12604
12912
|
items,
|
|
12605
12913
|
selected,
|
|
@@ -12608,7 +12916,7 @@ function PluginPicker({
|
|
|
12608
12916
|
}) {
|
|
12609
12917
|
const { stdout } = useStdout();
|
|
12610
12918
|
const rows = stdout?.rows ?? 24;
|
|
12611
|
-
const maxVisible = Math.max(4, rows -
|
|
12919
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS4);
|
|
12612
12920
|
const total = items.length;
|
|
12613
12921
|
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12614
12922
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
@@ -12654,6 +12962,334 @@ function PluginPicker({
|
|
|
12654
12962
|
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12655
12963
|
] });
|
|
12656
12964
|
}
|
|
12965
|
+
var CHROME_ROWS5 = 15;
|
|
12966
|
+
function formatCount(noun, count) {
|
|
12967
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
12968
|
+
}
|
|
12969
|
+
function toolActionLabel(enabled) {
|
|
12970
|
+
return enabled ? "Enter disables this tool" : "Enter re-enables this tool";
|
|
12971
|
+
}
|
|
12972
|
+
function statusBadge2(enabled) {
|
|
12973
|
+
return enabled ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF active" }) : /* @__PURE__ */ jsx(Text, { color: "red", children: "\u25CB disabled" });
|
|
12974
|
+
}
|
|
12975
|
+
function rwBadge(mutating) {
|
|
12976
|
+
return mutating ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "mut" }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: "ro" });
|
|
12977
|
+
}
|
|
12978
|
+
function displayCategory(cat) {
|
|
12979
|
+
if (!cat || cat.trim() === "") return "Other";
|
|
12980
|
+
return cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
12981
|
+
}
|
|
12982
|
+
function buildRows(items) {
|
|
12983
|
+
const rows = [];
|
|
12984
|
+
let lastCat = "";
|
|
12985
|
+
for (let i = 0; i < items.length; i++) {
|
|
12986
|
+
const item = items[i];
|
|
12987
|
+
const cat = displayCategory(item.category);
|
|
12988
|
+
if (cat !== lastCat) {
|
|
12989
|
+
lastCat = cat;
|
|
12990
|
+
rows.push({ type: "header", category: cat });
|
|
12991
|
+
}
|
|
12992
|
+
rows.push({ type: "item", item, index: i });
|
|
12993
|
+
}
|
|
12994
|
+
return rows;
|
|
12995
|
+
}
|
|
12996
|
+
function windowRows(rows, focus, max) {
|
|
12997
|
+
if (rows.length <= max) {
|
|
12998
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
12999
|
+
}
|
|
13000
|
+
let start = focus - Math.floor(max / 2);
|
|
13001
|
+
if (start < 0) start = 0;
|
|
13002
|
+
let end = start + max;
|
|
13003
|
+
if (end > rows.length) {
|
|
13004
|
+
end = rows.length;
|
|
13005
|
+
start = end - max;
|
|
13006
|
+
}
|
|
13007
|
+
let contextHeader = null;
|
|
13008
|
+
if (start > 0) {
|
|
13009
|
+
const first = rows[start];
|
|
13010
|
+
if (first && first.type === "item") {
|
|
13011
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
13012
|
+
const r = rows[i];
|
|
13013
|
+
if (r && r.type === "header") {
|
|
13014
|
+
contextHeader = r.category;
|
|
13015
|
+
break;
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
13018
|
+
}
|
|
13019
|
+
}
|
|
13020
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
13021
|
+
}
|
|
13022
|
+
function ToolsPicker({
|
|
13023
|
+
items,
|
|
13024
|
+
selected,
|
|
13025
|
+
busy = false,
|
|
13026
|
+
hint,
|
|
13027
|
+
filter
|
|
13028
|
+
}) {
|
|
13029
|
+
const { stdout } = useStdout();
|
|
13030
|
+
const termRows = stdout?.rows ?? 24;
|
|
13031
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS5);
|
|
13032
|
+
const total = items.length;
|
|
13033
|
+
let visibleItems;
|
|
13034
|
+
let visibleSelected;
|
|
13035
|
+
const filterActive = Boolean(filter && filter.length > 0);
|
|
13036
|
+
if (filterActive) {
|
|
13037
|
+
const q = filter.toLowerCase();
|
|
13038
|
+
visibleItems = items.filter(
|
|
13039
|
+
(it) => it.name.toLowerCase().includes(q) || it.owner.toLowerCase().includes(q) || it.description.toLowerCase().includes(q)
|
|
13040
|
+
);
|
|
13041
|
+
const rawSelected = items[selected];
|
|
13042
|
+
visibleSelected = rawSelected ? visibleItems.indexOf(rawSelected) : 0;
|
|
13043
|
+
if (visibleSelected < 0) visibleSelected = 0;
|
|
13044
|
+
} else {
|
|
13045
|
+
visibleItems = items;
|
|
13046
|
+
visibleSelected = selected;
|
|
13047
|
+
}
|
|
13048
|
+
const rows = buildRows(visibleItems);
|
|
13049
|
+
const enabledCount = items.filter((item) => item.enabled).length;
|
|
13050
|
+
const disabledCount = total - enabledCount;
|
|
13051
|
+
const selectedItem = visibleItems[visibleSelected];
|
|
13052
|
+
let displayRows;
|
|
13053
|
+
let hiddenAbove = 0;
|
|
13054
|
+
let hiddenBelow = 0;
|
|
13055
|
+
let contextHeader = null;
|
|
13056
|
+
if (filterActive) {
|
|
13057
|
+
displayRows = rows;
|
|
13058
|
+
} else {
|
|
13059
|
+
const selectedRowIdx = rows.findIndex(
|
|
13060
|
+
(r) => r.type === "item" && r.index === visibleSelected
|
|
13061
|
+
);
|
|
13062
|
+
const win = windowRows(
|
|
13063
|
+
rows,
|
|
13064
|
+
selectedRowIdx < 0 ? 0 : selectedRowIdx,
|
|
13065
|
+
maxVisible
|
|
13066
|
+
);
|
|
13067
|
+
displayRows = win.rows;
|
|
13068
|
+
hiddenAbove = win.start;
|
|
13069
|
+
hiddenBelow = rows.length - win.end;
|
|
13070
|
+
contextHeader = win.contextHeader;
|
|
13071
|
+
}
|
|
13072
|
+
const hasFilter = filterActive;
|
|
13073
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
|
|
13074
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "\u2501\u2501 Tools \u2501\u2501" }),
|
|
13075
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${visibleItems.length} match${visibleItems.length === 1 ? "" : "es"}) \xB7 Backspace edit \xB7 Esc clear` : `\u2191/\u2193 select \xB7 type to filter \xB7 Enter toggles \xB7 Esc close \xB7 ${formatCount("active", enabledCount)} / ${formatCount("disabled", disabledCount)}` }),
|
|
13076
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Disabled tools stay listed here so you can select them and re-enable them later." }),
|
|
13077
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: busy ? "Loading tools\u2026" : "No tools registered." }) : visibleItems.length === 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13078
|
+
'No tools match "',
|
|
13079
|
+
filter,
|
|
13080
|
+
'".'
|
|
13081
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13082
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13083
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13084
|
+
" ",
|
|
13085
|
+
contextHeader
|
|
13086
|
+
] }) : null,
|
|
13087
|
+
displayRows.map((row) => {
|
|
13088
|
+
if (row.type === "header") {
|
|
13089
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13090
|
+
" ",
|
|
13091
|
+
row.category
|
|
13092
|
+
] }, `cat-${row.category}`);
|
|
13093
|
+
}
|
|
13094
|
+
const { item, index } = row;
|
|
13095
|
+
const focused = index === visibleSelected;
|
|
13096
|
+
return /* @__PURE__ */ jsxs(
|
|
13097
|
+
Text,
|
|
13098
|
+
{
|
|
13099
|
+
inverse: focused,
|
|
13100
|
+
...focused ? { color: "green" } : {},
|
|
13101
|
+
wrap: "truncate-end",
|
|
13102
|
+
children: [
|
|
13103
|
+
focused ? "\u203A " : " ",
|
|
13104
|
+
statusBadge2(item.enabled),
|
|
13105
|
+
" ",
|
|
13106
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.name.padEnd(20) }),
|
|
13107
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13108
|
+
`[${item.owner}]`.padEnd(22),
|
|
13109
|
+
rwBadge(item.mutating),
|
|
13110
|
+
" ",
|
|
13111
|
+
" ",
|
|
13112
|
+
item.permission.padEnd(6),
|
|
13113
|
+
" ",
|
|
13114
|
+
" ",
|
|
13115
|
+
/* @__PURE__ */ jsxs(Text, { color: item.descMode === "simple" ? "yellow" : void 0, children: [
|
|
13116
|
+
"desc:",
|
|
13117
|
+
item.descMode
|
|
13118
|
+
] })
|
|
13119
|
+
] })
|
|
13120
|
+
]
|
|
13121
|
+
},
|
|
13122
|
+
item.name
|
|
13123
|
+
);
|
|
13124
|
+
}),
|
|
13125
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13126
|
+
] }) }),
|
|
13127
|
+
selectedItem ? /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13128
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
13129
|
+
/* @__PURE__ */ jsx(Text, { color: selectedItem.enabled ? "green" : "red", children: toolActionLabel(selectedItem.enabled) }),
|
|
13130
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${selectedItem.mutating ? "Mutating" : "Read-only"} \xB7 permission: ${selectedItem.permission} \xB7 descriptions: ${selectedItem.descMode}` })
|
|
13131
|
+
] }),
|
|
13132
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: selectedItem.description || "No description provided." })
|
|
13133
|
+
] }) : null,
|
|
13134
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13135
|
+
] });
|
|
13136
|
+
}
|
|
13137
|
+
var CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
13138
|
+
var CHROME_ROWS6 = 7;
|
|
13139
|
+
function normalizeQuery(raw) {
|
|
13140
|
+
return raw.trim().toLowerCase();
|
|
13141
|
+
}
|
|
13142
|
+
function buildRows2(entries) {
|
|
13143
|
+
const rows = [];
|
|
13144
|
+
let lastCat = "";
|
|
13145
|
+
for (let i = 0; i < entries.length; i++) {
|
|
13146
|
+
const e = entries[i];
|
|
13147
|
+
const cat = e.category || "App";
|
|
13148
|
+
if (cat !== lastCat) {
|
|
13149
|
+
lastCat = cat;
|
|
13150
|
+
rows.push({ type: "header", category: cat });
|
|
13151
|
+
}
|
|
13152
|
+
rows.push({ type: "item", entry: e, index: i });
|
|
13153
|
+
}
|
|
13154
|
+
return rows;
|
|
13155
|
+
}
|
|
13156
|
+
function windowRows2(rows, focus, max) {
|
|
13157
|
+
if (rows.length <= max) {
|
|
13158
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13159
|
+
}
|
|
13160
|
+
let start = focus - Math.floor(max / 2);
|
|
13161
|
+
if (start < 0) start = 0;
|
|
13162
|
+
let end = start + max;
|
|
13163
|
+
if (end > rows.length) {
|
|
13164
|
+
end = rows.length;
|
|
13165
|
+
start = end - max;
|
|
13166
|
+
}
|
|
13167
|
+
let contextHeader = null;
|
|
13168
|
+
if (start > 0) {
|
|
13169
|
+
const first = rows[start];
|
|
13170
|
+
if (first && first.type === "item") {
|
|
13171
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
13172
|
+
const r = rows[i];
|
|
13173
|
+
if (r && r.type === "header") {
|
|
13174
|
+
contextHeader = r.category;
|
|
13175
|
+
break;
|
|
13176
|
+
}
|
|
13177
|
+
}
|
|
13178
|
+
}
|
|
13179
|
+
}
|
|
13180
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
13181
|
+
}
|
|
13182
|
+
function HelpPanel({
|
|
13183
|
+
entries,
|
|
13184
|
+
filter,
|
|
13185
|
+
selected,
|
|
13186
|
+
hint
|
|
13187
|
+
}) {
|
|
13188
|
+
const { stdout } = useStdout();
|
|
13189
|
+
const termRows = stdout?.rows ?? 24;
|
|
13190
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS6);
|
|
13191
|
+
const query = normalizeQuery(filter);
|
|
13192
|
+
const filtered = query ? entries.filter(
|
|
13193
|
+
(e) => e.name.toLowerCase().includes(query) || e.description.toLowerCase().includes(query) || e.category.toLowerCase().includes(query) || (e.aliases ?? []).some((a) => a.toLowerCase().includes(query))
|
|
13194
|
+
) : entries;
|
|
13195
|
+
filtered.sort((a, b) => {
|
|
13196
|
+
const ai = CATEGORY_ORDER.indexOf(a.category);
|
|
13197
|
+
const bi = CATEGORY_ORDER.indexOf(b.category);
|
|
13198
|
+
if (ai !== bi) return ai - bi;
|
|
13199
|
+
return a.name.localeCompare(b.name);
|
|
13200
|
+
});
|
|
13201
|
+
const rows = buildRows2(filtered);
|
|
13202
|
+
const focus = Math.min(selected, Math.max(0, filtered.length - 1));
|
|
13203
|
+
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === focus);
|
|
13204
|
+
const win = windowRows2(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, maxVisible);
|
|
13205
|
+
const { rows: visible, start, end, contextHeader } = win;
|
|
13206
|
+
const hiddenAbove = start;
|
|
13207
|
+
const hiddenBelow = rows.length - end;
|
|
13208
|
+
const hasFilter = query.length > 0;
|
|
13209
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
13210
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2501\u2501 Help / Command Palette \u2501\u2501" }),
|
|
13211
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${filtered.length} match${filtered.length === 1 ? "" : "es"})` : "\u2191/\u2193 navigate \xB7 Enter run \xB7 Tab fill \xB7 type to filter \xB7 Esc close" }),
|
|
13212
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13213
|
+
'No commands match "',
|
|
13214
|
+
filter,
|
|
13215
|
+
'".'
|
|
13216
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13217
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13218
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13219
|
+
" ",
|
|
13220
|
+
contextHeader
|
|
13221
|
+
] }) : null,
|
|
13222
|
+
visible.map((row) => {
|
|
13223
|
+
if (row.type === "header") {
|
|
13224
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13225
|
+
" ",
|
|
13226
|
+
row.category
|
|
13227
|
+
] }, `cat-${row.category}`);
|
|
13228
|
+
}
|
|
13229
|
+
const { entry, index } = row;
|
|
13230
|
+
const isSelected = index === focus;
|
|
13231
|
+
return /* @__PURE__ */ jsxs(
|
|
13232
|
+
Text,
|
|
13233
|
+
{
|
|
13234
|
+
inverse: isSelected,
|
|
13235
|
+
...isSelected ? { color: "cyan" } : {},
|
|
13236
|
+
wrap: "truncate-end",
|
|
13237
|
+
children: [
|
|
13238
|
+
isSelected ? "\u203A " : " ",
|
|
13239
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
13240
|
+
"/",
|
|
13241
|
+
entry.name
|
|
13242
|
+
] }),
|
|
13243
|
+
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13244
|
+
" (",
|
|
13245
|
+
entry.aliases.map((a) => `/${a}`).join(", "),
|
|
13246
|
+
")"
|
|
13247
|
+
] }) : null,
|
|
13248
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13249
|
+
" \u2014 ",
|
|
13250
|
+
entry.description
|
|
13251
|
+
] }),
|
|
13252
|
+
entry.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13253
|
+
" ",
|
|
13254
|
+
entry.argsHint
|
|
13255
|
+
] }) : null
|
|
13256
|
+
]
|
|
13257
|
+
},
|
|
13258
|
+
entry.name
|
|
13259
|
+
);
|
|
13260
|
+
}),
|
|
13261
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13262
|
+
] }) }),
|
|
13263
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13264
|
+
] });
|
|
13265
|
+
}
|
|
13266
|
+
function ShadowPanel({
|
|
13267
|
+
shadow,
|
|
13268
|
+
hint
|
|
13269
|
+
}) {
|
|
13270
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
13271
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "\u2501\u2501 Shadow Agent \u2501\u2501" }),
|
|
13272
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "s start \xB7 t stop \xB7 i cycle interval \xB7 m cycle model \xB7 Esc close" }),
|
|
13273
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13274
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
13275
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Status: " }),
|
|
13276
|
+
shadow.running ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF running" }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u25CB stopped" }),
|
|
13277
|
+
shadow.activeId ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${shadow.activeId.slice(0, 12)}\u2026` }) : null
|
|
13278
|
+
] }),
|
|
13279
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13280
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Model: " }),
|
|
13281
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: shadow.model })
|
|
13282
|
+
] }),
|
|
13283
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13284
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Interval: " }),
|
|
13285
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: shadow.intervalMs >= 1e3 ? `${shadow.intervalMs / 1e3}s` : `${shadow.intervalMs}ms` }),
|
|
13286
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (min 5s)" })
|
|
13287
|
+
] }),
|
|
13288
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: shadow.running ? "Press t to stop the Shadow Agent" : "Press s to start the Shadow Agent" }) })
|
|
13289
|
+
] }),
|
|
13290
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13291
|
+
] });
|
|
13292
|
+
}
|
|
12657
13293
|
function ProcessListMonitor() {
|
|
12658
13294
|
const [, setTick] = useState(0);
|
|
12659
13295
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
@@ -13336,7 +13972,7 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13336
13972
|
rows.push({ type: "item", match: m, index: i });
|
|
13337
13973
|
}
|
|
13338
13974
|
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === selected);
|
|
13339
|
-
const visible =
|
|
13975
|
+
const visible = windowRows3(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, MAX_VISIBLE_ITEMS);
|
|
13340
13976
|
const hiddenAbove = visible.start;
|
|
13341
13977
|
const hiddenBelow = rows.length - visible.end;
|
|
13342
13978
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
@@ -13388,7 +14024,7 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13388
14024
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500 \u2191\u2193 nav \xB7 Enter run \xB7 Tab fill \xB7 Esc close" })
|
|
13389
14025
|
] });
|
|
13390
14026
|
}
|
|
13391
|
-
function
|
|
14027
|
+
function windowRows3(rows, focus, max) {
|
|
13392
14028
|
if (rows.length <= max) {
|
|
13393
14029
|
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13394
14030
|
}
|
|
@@ -13921,6 +14557,11 @@ function createInitialState(options) {
|
|
|
13921
14557
|
hint: void 0
|
|
13922
14558
|
},
|
|
13923
14559
|
pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14560
|
+
mcpPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14561
|
+
toolsPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0, filter: void 0 },
|
|
14562
|
+
brainPanel: { open: false, riskLevel: "medium", log: [], selected: 0, hint: void 0 },
|
|
14563
|
+
helpPanel: { open: false, entries: [], selected: 0, filter: "", hint: void 0 },
|
|
14564
|
+
shadowPanel: { open: false, shadow: { activeId: null, running: false, model: "", intervalMs: 3e4 }, hint: void 0 },
|
|
13924
14565
|
authPanel: AUTH_PANEL_INITIAL,
|
|
13925
14566
|
projectPicker: {
|
|
13926
14567
|
open: false,
|
|
@@ -15474,6 +16115,145 @@ function usePickerKeys(host) {
|
|
|
15474
16115
|
}
|
|
15475
16116
|
return true;
|
|
15476
16117
|
}
|
|
16118
|
+
if (state.mcpPicker.open) {
|
|
16119
|
+
if (key.escape) {
|
|
16120
|
+
dispatch({ type: "mcpPickerClose" });
|
|
16121
|
+
return true;
|
|
16122
|
+
}
|
|
16123
|
+
if (key.mouse?.kind === "wheel") {
|
|
16124
|
+
dispatch({ type: "mcpPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16125
|
+
return true;
|
|
16126
|
+
}
|
|
16127
|
+
if (key.upArrow) {
|
|
16128
|
+
dispatch({ type: "mcpPickerMove", delta: -1 });
|
|
16129
|
+
return true;
|
|
16130
|
+
}
|
|
16131
|
+
if (key.downArrow) {
|
|
16132
|
+
dispatch({ type: "mcpPickerMove", delta: 1 });
|
|
16133
|
+
return true;
|
|
16134
|
+
}
|
|
16135
|
+
if (input === "r" || input === "R") {
|
|
16136
|
+
void host.onMcpPickerRestart?.();
|
|
16137
|
+
return true;
|
|
16138
|
+
}
|
|
16139
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16140
|
+
if (debouncedEnter(host)) return true;
|
|
16141
|
+
void host.onMcpPickerToggle?.();
|
|
16142
|
+
return true;
|
|
16143
|
+
}
|
|
16144
|
+
return true;
|
|
16145
|
+
}
|
|
16146
|
+
if (state.toolsPicker.open) {
|
|
16147
|
+
if (key.escape) {
|
|
16148
|
+
if (state.toolsPicker.filter) {
|
|
16149
|
+
dispatch({ type: "toolsPickerFilter", filter: "" });
|
|
16150
|
+
} else {
|
|
16151
|
+
dispatch({ type: "toolsPickerClose" });
|
|
16152
|
+
}
|
|
16153
|
+
return true;
|
|
16154
|
+
}
|
|
16155
|
+
if (key.mouse?.kind === "wheel") {
|
|
16156
|
+
dispatch({ type: "toolsPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16157
|
+
return true;
|
|
16158
|
+
}
|
|
16159
|
+
if (key.upArrow) {
|
|
16160
|
+
dispatch({ type: "toolsPickerMove", delta: -1 });
|
|
16161
|
+
return true;
|
|
16162
|
+
}
|
|
16163
|
+
if (key.downArrow) {
|
|
16164
|
+
dispatch({ type: "toolsPickerMove", delta: 1 });
|
|
16165
|
+
return true;
|
|
16166
|
+
}
|
|
16167
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16168
|
+
if (debouncedEnter(host)) return true;
|
|
16169
|
+
void host.onToolsPickerToggle?.();
|
|
16170
|
+
return true;
|
|
16171
|
+
}
|
|
16172
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16173
|
+
dispatch({ type: "toolsPickerFilter", filter: (state.toolsPicker.filter ?? "") + input });
|
|
16174
|
+
return true;
|
|
16175
|
+
}
|
|
16176
|
+
if (key.backspace) {
|
|
16177
|
+
const cur = state.toolsPicker.filter ?? "";
|
|
16178
|
+
dispatch({ type: "toolsPickerFilter", filter: cur.length > 0 ? cur.slice(0, -1) : "" });
|
|
16179
|
+
return true;
|
|
16180
|
+
}
|
|
16181
|
+
return true;
|
|
16182
|
+
}
|
|
16183
|
+
if (state.helpPanel.open) {
|
|
16184
|
+
if (key.escape) {
|
|
16185
|
+
dispatch({ type: "helpClose" });
|
|
16186
|
+
return true;
|
|
16187
|
+
}
|
|
16188
|
+
if (key.mouse?.kind === "wheel") {
|
|
16189
|
+
dispatch({ type: "helpMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16190
|
+
return true;
|
|
16191
|
+
}
|
|
16192
|
+
if (key.upArrow) {
|
|
16193
|
+
dispatch({ type: "helpMove", delta: -1 });
|
|
16194
|
+
return true;
|
|
16195
|
+
}
|
|
16196
|
+
if (key.downArrow) {
|
|
16197
|
+
dispatch({ type: "helpMove", delta: 1 });
|
|
16198
|
+
return true;
|
|
16199
|
+
}
|
|
16200
|
+
if (key.backspace && state.helpPanel.filter) {
|
|
16201
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter.slice(0, -1) });
|
|
16202
|
+
return true;
|
|
16203
|
+
}
|
|
16204
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16205
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter + input });
|
|
16206
|
+
return true;
|
|
16207
|
+
}
|
|
16208
|
+
if (isEnter) {
|
|
16209
|
+
if (debouncedEnter(host)) return true;
|
|
16210
|
+
host.onHelpPanelEnter?.();
|
|
16211
|
+
return true;
|
|
16212
|
+
}
|
|
16213
|
+
return true;
|
|
16214
|
+
}
|
|
16215
|
+
if (state.brainPanel.open) {
|
|
16216
|
+
if (key.escape) {
|
|
16217
|
+
dispatch({ type: "brainClose" });
|
|
16218
|
+
return true;
|
|
16219
|
+
}
|
|
16220
|
+
if (key.mouse?.kind === "wheel") {
|
|
16221
|
+
dispatch({ type: "brainMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16222
|
+
return true;
|
|
16223
|
+
}
|
|
16224
|
+
if (key.upArrow) {
|
|
16225
|
+
dispatch({ type: "brainMove", delta: -1 });
|
|
16226
|
+
return true;
|
|
16227
|
+
}
|
|
16228
|
+
if (key.downArrow) {
|
|
16229
|
+
dispatch({ type: "brainMove", delta: 1 });
|
|
16230
|
+
return true;
|
|
16231
|
+
}
|
|
16232
|
+
if (key.leftArrow) {
|
|
16233
|
+
host.onBrainRiskChange?.(-1);
|
|
16234
|
+
return true;
|
|
16235
|
+
}
|
|
16236
|
+
if (key.rightArrow) {
|
|
16237
|
+
host.onBrainRiskChange?.(1);
|
|
16238
|
+
return true;
|
|
16239
|
+
}
|
|
16240
|
+
return true;
|
|
16241
|
+
}
|
|
16242
|
+
if (state.shadowPanel.open) {
|
|
16243
|
+
if (key.escape) {
|
|
16244
|
+
dispatch({ type: "shadowClose" });
|
|
16245
|
+
return true;
|
|
16246
|
+
}
|
|
16247
|
+
if (input === "s" || input === "S") {
|
|
16248
|
+
void host.onShadowStart?.();
|
|
16249
|
+
return true;
|
|
16250
|
+
}
|
|
16251
|
+
if (input === "t" || input === "T") {
|
|
16252
|
+
void host.onShadowStop?.();
|
|
16253
|
+
return true;
|
|
16254
|
+
}
|
|
16255
|
+
return true;
|
|
16256
|
+
}
|
|
15477
16257
|
if (state.statuslinePicker.open) {
|
|
15478
16258
|
if (key.escape) {
|
|
15479
16259
|
dispatch({ type: "statuslineClose" });
|
|
@@ -16634,6 +17414,12 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16634
17414
|
case "pluginPickerOpen":
|
|
16635
17415
|
dispatch({ type: "pluginPickerOpen" });
|
|
16636
17416
|
return true;
|
|
17417
|
+
case "mcpPickerOpen":
|
|
17418
|
+
dispatch({ type: "mcpPickerOpen" });
|
|
17419
|
+
return true;
|
|
17420
|
+
case "toolsPickerOpen":
|
|
17421
|
+
dispatch({ type: "toolsPickerOpen" });
|
|
17422
|
+
return true;
|
|
16637
17423
|
case "projectPickerOpen":
|
|
16638
17424
|
void openProjectPicker();
|
|
16639
17425
|
return true;
|
|
@@ -16646,6 +17432,24 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16646
17432
|
return true;
|
|
16647
17433
|
}
|
|
16648
17434
|
return false;
|
|
17435
|
+
case "brainOpen":
|
|
17436
|
+
if (deps.openBrainPanel) {
|
|
17437
|
+
void deps.openBrainPanel();
|
|
17438
|
+
return true;
|
|
17439
|
+
}
|
|
17440
|
+
return false;
|
|
17441
|
+
case "shadowOpen":
|
|
17442
|
+
if (deps.openShadowPanel) {
|
|
17443
|
+
void deps.openShadowPanel();
|
|
17444
|
+
return true;
|
|
17445
|
+
}
|
|
17446
|
+
return false;
|
|
17447
|
+
case "helpOpen":
|
|
17448
|
+
if (deps.openHelpPanel) {
|
|
17449
|
+
void deps.openHelpPanel();
|
|
17450
|
+
return true;
|
|
17451
|
+
}
|
|
17452
|
+
return false;
|
|
16649
17453
|
case "toggleMonitor":
|
|
16650
17454
|
dispatch({ type: "toggleMonitor" });
|
|
16651
17455
|
return true;
|
|
@@ -16761,7 +17565,7 @@ function renderList3() {
|
|
|
16761
17565
|
}
|
|
16762
17566
|
|
|
16763
17567
|
// src/slash-command-search.ts
|
|
16764
|
-
var
|
|
17568
|
+
var CATEGORY_ORDER2 = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
16765
17569
|
function buildSlashCommandMatches(entries, rawQuery) {
|
|
16766
17570
|
const query = normalizeSlashQuery(rawQuery);
|
|
16767
17571
|
const matches = [];
|
|
@@ -16772,7 +17576,7 @@ function buildSlashCommandMatches(entries, rawQuery) {
|
|
|
16772
17576
|
}
|
|
16773
17577
|
return matches.sort((a, b) => {
|
|
16774
17578
|
if (a.rank !== b.rank) return a.rank - b.rank;
|
|
16775
|
-
const catDiff =
|
|
17579
|
+
const catDiff = CATEGORY_ORDER2.indexOf(a.category) - CATEGORY_ORDER2.indexOf(b.category);
|
|
16776
17580
|
if (catDiff !== 0) return catDiff;
|
|
16777
17581
|
return a.name.localeCompare(b.name);
|
|
16778
17582
|
}).map(({ rank: _rank, ...match }) => match);
|
|
@@ -16969,24 +17773,38 @@ function rehydrateHistory(messages, startId, toolCalls) {
|
|
|
16969
17773
|
outputTokens: tc.outputTokens,
|
|
16970
17774
|
outputLines: tc.outputLines
|
|
16971
17775
|
});
|
|
17776
|
+
const pushAssistantText = (parts) => {
|
|
17777
|
+
const text = parts.join("").trim();
|
|
17778
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
17779
|
+
parts.length = 0;
|
|
17780
|
+
};
|
|
16972
17781
|
for (const msg of messages) {
|
|
16973
17782
|
if (msg.role === "system") continue;
|
|
16974
|
-
const text = textOf(msg).trim();
|
|
16975
17783
|
if (msg.role === "user") {
|
|
17784
|
+
const text = textOf(msg).trim();
|
|
16976
17785
|
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
16977
17786
|
continue;
|
|
16978
17787
|
}
|
|
16979
17788
|
if (msg.role === "assistant") {
|
|
16980
|
-
if (
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
17789
|
+
if (!Array.isArray(msg.content)) {
|
|
17790
|
+
const text = textOf(msg).trim();
|
|
17791
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
17792
|
+
continue;
|
|
17793
|
+
}
|
|
17794
|
+
const textParts = [];
|
|
17795
|
+
for (const block of msg.content) {
|
|
17796
|
+
if (block.type === "text") {
|
|
17797
|
+
textParts.push(block.text);
|
|
17798
|
+
continue;
|
|
16988
17799
|
}
|
|
17800
|
+
if (block.type !== "tool_use") continue;
|
|
17801
|
+
pushAssistantText(textParts);
|
|
17802
|
+
const tc = toolCallsById.get(block.id);
|
|
17803
|
+
if (!tc) continue;
|
|
17804
|
+
entries.push(toolEntryFor(tc));
|
|
17805
|
+
consumed.add(block.id);
|
|
16989
17806
|
}
|
|
17807
|
+
pushAssistantText(textParts);
|
|
16990
17808
|
}
|
|
16991
17809
|
}
|
|
16992
17810
|
if (toolCalls) {
|
|
@@ -17086,6 +17904,16 @@ function App({
|
|
|
17086
17904
|
saveSettings,
|
|
17087
17905
|
getPluginItems,
|
|
17088
17906
|
onPluginToggle,
|
|
17907
|
+
getMcpServers,
|
|
17908
|
+
onMcpToggle,
|
|
17909
|
+
onMcpRestart,
|
|
17910
|
+
getToolsItems,
|
|
17911
|
+
onToolToggle,
|
|
17912
|
+
getBrainData,
|
|
17913
|
+
onBrainRiskLevel,
|
|
17914
|
+
getShadowData,
|
|
17915
|
+
onShadowStart,
|
|
17916
|
+
onShadowStop,
|
|
17089
17917
|
authHost,
|
|
17090
17918
|
predictNext,
|
|
17091
17919
|
onSuggestionsParsed,
|
|
@@ -17262,6 +18090,71 @@ function App({
|
|
|
17262
18090
|
});
|
|
17263
18091
|
const { openPromptPicker } = usePromptPicker({ projectRoot, dispatch });
|
|
17264
18092
|
const { openModePicker } = useModePicker({ dispatch, getModes });
|
|
18093
|
+
const openBrainPanel = React5.useCallback(() => {
|
|
18094
|
+
if (!getBrainData) return;
|
|
18095
|
+
const data = getBrainData();
|
|
18096
|
+
dispatch({ type: "brainOpen", riskLevel: data.riskLevel, log: data.log });
|
|
18097
|
+
}, [getBrainData]);
|
|
18098
|
+
const changeBrainRisk = React5.useCallback(
|
|
18099
|
+
(delta) => {
|
|
18100
|
+
dispatch({ type: "brainRiskChange", delta });
|
|
18101
|
+
},
|
|
18102
|
+
[]
|
|
18103
|
+
);
|
|
18104
|
+
const prevRiskRef = React5.useRef(state.brainPanel.riskLevel);
|
|
18105
|
+
React5.useEffect(() => {
|
|
18106
|
+
if (!state.brainPanel.open) return;
|
|
18107
|
+
const current = state.brainPanel.riskLevel;
|
|
18108
|
+
if (current !== prevRiskRef.current && onBrainRiskLevel) {
|
|
18109
|
+
prevRiskRef.current = current;
|
|
18110
|
+
const err = onBrainRiskLevel(current);
|
|
18111
|
+
if (err) dispatch({ type: "brainHint", text: err });
|
|
18112
|
+
else dispatch({ type: "brainHint", text: `Risk ceiling \u2192 ${current.toUpperCase()}` });
|
|
18113
|
+
}
|
|
18114
|
+
}, [state.brainPanel.riskLevel, state.brainPanel.open, onBrainRiskLevel]);
|
|
18115
|
+
const openShadowPanel = React5.useCallback(() => {
|
|
18116
|
+
if (!getShadowData) return;
|
|
18117
|
+
const data = getShadowData();
|
|
18118
|
+
dispatch({ type: "shadowOpen", shadow: data });
|
|
18119
|
+
}, [getShadowData]);
|
|
18120
|
+
const handleShadowStart = React5.useCallback(async () => {
|
|
18121
|
+
if (!onShadowStart) return;
|
|
18122
|
+
dispatch({ type: "shadowHint", text: "Starting Shadow Agent\u2026" });
|
|
18123
|
+
try {
|
|
18124
|
+
const err = await onShadowStart();
|
|
18125
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18126
|
+
else {
|
|
18127
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18128
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent started." });
|
|
18129
|
+
}
|
|
18130
|
+
} catch (e) {
|
|
18131
|
+
dispatch({ type: "shadowHint", text: `Failed to start: ${toErrorMessage(e)}` });
|
|
18132
|
+
}
|
|
18133
|
+
}, [onShadowStart, getShadowData]);
|
|
18134
|
+
const handleShadowStop = React5.useCallback(async () => {
|
|
18135
|
+
if (!onShadowStop) return;
|
|
18136
|
+
dispatch({ type: "shadowHint", text: "Stopping Shadow Agent\u2026" });
|
|
18137
|
+
try {
|
|
18138
|
+
const err = await onShadowStop();
|
|
18139
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18140
|
+
else {
|
|
18141
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18142
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent stopped." });
|
|
18143
|
+
}
|
|
18144
|
+
} catch (e) {
|
|
18145
|
+
dispatch({ type: "shadowHint", text: `Failed to stop: ${toErrorMessage(e)}` });
|
|
18146
|
+
}
|
|
18147
|
+
}, [onShadowStop, getShadowData]);
|
|
18148
|
+
const openHelpPanel = React5.useCallback(() => {
|
|
18149
|
+
const entries = Array.from(slashRegistry.listWithOwner()).map(({ cmd, owner }) => ({
|
|
18150
|
+
name: owner === "core" ? cmd.name : `${owner}:${cmd.name}`,
|
|
18151
|
+
description: cmd.description,
|
|
18152
|
+
category: cmd.category ?? "App",
|
|
18153
|
+
aliases: cmd.aliases,
|
|
18154
|
+
argsHint: cmd.argsHint
|
|
18155
|
+
}));
|
|
18156
|
+
dispatch({ type: "helpOpen", entries });
|
|
18157
|
+
}, []);
|
|
17265
18158
|
useStatuslineHiddenSync({
|
|
17266
18159
|
pickerOpen: state.statuslinePicker.open,
|
|
17267
18160
|
pickerHidden: state.statuslinePicker.hiddenItems,
|
|
@@ -17318,6 +18211,7 @@ function App({
|
|
|
17318
18211
|
const streamSegmentsRef = useRef([]);
|
|
17319
18212
|
const pendingDeltaRef = useRef("");
|
|
17320
18213
|
const flushTimerRef = useRef(null);
|
|
18214
|
+
const assistantCommittedThisRunRef = useRef(false);
|
|
17321
18215
|
const stateRef = useRef(state);
|
|
17322
18216
|
stateRef.current = state;
|
|
17323
18217
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
@@ -17346,7 +18240,7 @@ function App({
|
|
|
17346
18240
|
[statuslineHiddenForPicker]
|
|
17347
18241
|
);
|
|
17348
18242
|
const [mouseMode, setMouseMode] = useState(mouse);
|
|
17349
|
-
const pickerOverlayOpen = state.modelPicker.open || state.autonomyPicker.open || state.modePicker.open || state.designPicker.open || state.settingsPicker.open || state.projectPicker.open || state.slashPicker.open || state.statuslinePicker.open || state.fKeyPicker.open || state.authPanel.open || state.picker.open;
|
|
18243
|
+
const pickerOverlayOpen = state.modelPicker.open || state.autonomyPicker.open || state.modePicker.open || state.designPicker.open || state.settingsPicker.open || state.projectPicker.open || state.slashPicker.open || state.statuslinePicker.open || state.pluginPicker.open || state.mcpPicker.open || state.toolsPicker.open || state.brainPanel.open || state.helpPanel.open || state.shadowPanel.open || state.fKeyPicker.open || state.authPanel.open || state.picker.open;
|
|
17350
18244
|
const mouseTrackingOn = mouseMode || pickerOverlayOpen;
|
|
17351
18245
|
const mouseWrittenRef = useRef(false);
|
|
17352
18246
|
useEffect(() => {
|
|
@@ -18161,7 +19055,10 @@ function App({
|
|
|
18161
19055
|
openProjectPicker,
|
|
18162
19056
|
openStatuslinePicker,
|
|
18163
19057
|
openAuthPanel: authPanelController.openAuthPanel,
|
|
18164
|
-
openModePicker
|
|
19058
|
+
openModePicker,
|
|
19059
|
+
openBrainPanel,
|
|
19060
|
+
openShadowPanel,
|
|
19061
|
+
openHelpPanel
|
|
18165
19062
|
});
|
|
18166
19063
|
onPanelOpen.current = dispatcher;
|
|
18167
19064
|
return () => {
|
|
@@ -18173,7 +19070,10 @@ function App({
|
|
|
18173
19070
|
openProjectPicker,
|
|
18174
19071
|
openStatuslinePicker,
|
|
18175
19072
|
authPanelController.openAuthPanel,
|
|
18176
|
-
openModePicker
|
|
19073
|
+
openModePicker,
|
|
19074
|
+
openBrainPanel,
|
|
19075
|
+
openShadowPanel,
|
|
19076
|
+
openHelpPanel
|
|
18177
19077
|
]);
|
|
18178
19078
|
useEffect(() => {
|
|
18179
19079
|
if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
|
|
@@ -18259,6 +19159,73 @@ function App({
|
|
|
18259
19159
|
});
|
|
18260
19160
|
}
|
|
18261
19161
|
}, [onPluginToggle]);
|
|
19162
|
+
const refreshMcpPicker = React5.useCallback(() => {
|
|
19163
|
+
if (!getMcpServers) return;
|
|
19164
|
+
dispatch({ type: "mcpPickerSetItems", items: getMcpServers() });
|
|
19165
|
+
}, [getMcpServers]);
|
|
19166
|
+
useEffect(() => {
|
|
19167
|
+
if (!state.mcpPicker.open) return;
|
|
19168
|
+
refreshMcpPicker();
|
|
19169
|
+
}, [state.mcpPicker.open, refreshMcpPicker]);
|
|
19170
|
+
const toggleSelectedMcpServer = React5.useCallback(async () => {
|
|
19171
|
+
if (!onMcpToggle) return;
|
|
19172
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19173
|
+
if (!selected) return;
|
|
19174
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19175
|
+
try {
|
|
19176
|
+
const result = await onMcpToggle(selected.name);
|
|
19177
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19178
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19179
|
+
} catch (err) {
|
|
19180
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19181
|
+
dispatch({
|
|
19182
|
+
type: "mcpPickerHint",
|
|
19183
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19184
|
+
});
|
|
19185
|
+
}
|
|
19186
|
+
}, [onMcpToggle]);
|
|
19187
|
+
const restartSelectedMcpServer = React5.useCallback(async () => {
|
|
19188
|
+
if (!onMcpRestart) return;
|
|
19189
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19190
|
+
if (!selected) return;
|
|
19191
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19192
|
+
try {
|
|
19193
|
+
const result = await onMcpRestart(selected.name);
|
|
19194
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19195
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19196
|
+
} catch (err) {
|
|
19197
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19198
|
+
dispatch({
|
|
19199
|
+
type: "mcpPickerHint",
|
|
19200
|
+
text: `Failed to restart ${selected.name}: ${toErrorMessage(err)}`
|
|
19201
|
+
});
|
|
19202
|
+
}
|
|
19203
|
+
}, [onMcpRestart]);
|
|
19204
|
+
const refreshToolsPicker = React5.useCallback(() => {
|
|
19205
|
+
if (!getToolsItems) return;
|
|
19206
|
+
dispatch({ type: "toolsPickerSetItems", items: getToolsItems() });
|
|
19207
|
+
}, [getToolsItems]);
|
|
19208
|
+
useEffect(() => {
|
|
19209
|
+
if (!state.toolsPicker.open) return;
|
|
19210
|
+
refreshToolsPicker();
|
|
19211
|
+
}, [state.toolsPicker.open, refreshToolsPicker]);
|
|
19212
|
+
const toggleSelectedTool = React5.useCallback(async () => {
|
|
19213
|
+
if (!onToolToggle) return;
|
|
19214
|
+
const selected = stateRef.current.toolsPicker.items[stateRef.current.toolsPicker.selected];
|
|
19215
|
+
if (!selected) return;
|
|
19216
|
+
dispatch({ type: "toolsPickerBusy", busy: true });
|
|
19217
|
+
try {
|
|
19218
|
+
const result = await onToolToggle(selected.name);
|
|
19219
|
+
dispatch({ type: "toolsPickerSetItems", items: result.items });
|
|
19220
|
+
dispatch({ type: "toolsPickerHint", text: result.error ?? result.message });
|
|
19221
|
+
} catch (err) {
|
|
19222
|
+
dispatch({ type: "toolsPickerBusy", busy: false });
|
|
19223
|
+
dispatch({
|
|
19224
|
+
type: "toolsPickerHint",
|
|
19225
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19226
|
+
});
|
|
19227
|
+
}
|
|
19228
|
+
}, [onToolToggle]);
|
|
18262
19229
|
const autoSubmitStreakRef = useRef(0);
|
|
18263
19230
|
const autoSubmitCapWarnedRef = useRef(false);
|
|
18264
19231
|
const [nextStepsRecheck, setNextStepsRecheck] = useState(0);
|
|
@@ -18935,12 +19902,15 @@ Available chords:
|
|
|
18935
19902
|
for (const seg of segments) {
|
|
18936
19903
|
if (seg.text.trim()) {
|
|
18937
19904
|
dispatch({ type: "addEntry", entry: { kind: seg.kind, text: seg.text } });
|
|
19905
|
+
if (seg.kind === "assistant") assistantCommittedThisRunRef.current = true;
|
|
18938
19906
|
}
|
|
18939
19907
|
}
|
|
18940
19908
|
if (segments.length === 0 && text.trim()) {
|
|
18941
19909
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text } });
|
|
19910
|
+
assistantCommittedThisRunRef.current = true;
|
|
18942
19911
|
} else if (segments.length === 0 && fallbackText.trim()) {
|
|
18943
19912
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: fallbackText } });
|
|
19913
|
+
assistantCommittedThisRunRef.current = true;
|
|
18944
19914
|
}
|
|
18945
19915
|
});
|
|
18946
19916
|
const offConfirmNeeded = events.on("tool.confirm_needed", (e) => {
|
|
@@ -19350,6 +20320,18 @@ Available chords:
|
|
|
19350
20320
|
}
|
|
19351
20321
|
},
|
|
19352
20322
|
onPluginPickerToggle: toggleSelectedPlugin,
|
|
20323
|
+
onMcpPickerToggle: toggleSelectedMcpServer,
|
|
20324
|
+
onMcpPickerRestart: restartSelectedMcpServer,
|
|
20325
|
+
onToolsPickerToggle: toggleSelectedTool,
|
|
20326
|
+
onHelpPanelEnter: () => {
|
|
20327
|
+
const entry = state.helpPanel.entries[state.helpPanel.selected];
|
|
20328
|
+
if (!entry) return;
|
|
20329
|
+
dispatch({ type: "helpClose" });
|
|
20330
|
+
submitRef.current(`/${entry.name}`);
|
|
20331
|
+
},
|
|
20332
|
+
onBrainRiskChange: changeBrainRisk,
|
|
20333
|
+
onShadowStart: handleShadowStart,
|
|
20334
|
+
onShadowStop: handleShadowStop,
|
|
19353
20335
|
onAuthEnter: authPanelController.onAuthEnter,
|
|
19354
20336
|
onAuthBack: authPanelController.onAuthBack,
|
|
19355
20337
|
onAuthShortcut: authPanelController.onAuthShortcut,
|
|
@@ -20320,9 +21302,7 @@ Available chords:
|
|
|
20320
21302
|
}
|
|
20321
21303
|
});
|
|
20322
21304
|
}
|
|
20323
|
-
|
|
20324
|
-
(entry) => entry.kind === "assistant"
|
|
20325
|
-
).length;
|
|
21305
|
+
assistantCommittedThisRunRef.current = false;
|
|
20326
21306
|
const result = await agent.run(routed.blocks, { signal: ctrl.signal });
|
|
20327
21307
|
const lingering = streamingTextRef.current;
|
|
20328
21308
|
const lingeringSegments = streamSegmentsRef.current;
|
|
@@ -20342,7 +21322,13 @@ Available chords:
|
|
|
20342
21322
|
}
|
|
20343
21323
|
} else if (lingering.trim()) {
|
|
20344
21324
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
|
|
20345
|
-
} else if (result.status === "done" && result.finalText?.trim() &&
|
|
21325
|
+
} else if (result.status === "done" && result.finalText?.trim() && // Only recover finalText when no assistant entry was committed by the
|
|
21326
|
+
// per-iteration `provider.response` flush during this run. Checked via
|
|
21327
|
+
// a synchronous ref, NOT `stateRef` — the flush's `addEntry` dispatch
|
|
21328
|
+
// isn't reflected in `stateRef` yet when we resume here, so a
|
|
21329
|
+
// state-based count would read stale and re-commit the final reply,
|
|
21330
|
+
// rendering it twice.
|
|
21331
|
+
!assistantCommittedThisRunRef.current) {
|
|
20346
21332
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
|
|
20347
21333
|
}
|
|
20348
21334
|
if (result.status === "aborted") {
|
|
@@ -21074,6 +22060,50 @@ ${content}
|
|
|
21074
22060
|
hint: state.pluginPicker.hint
|
|
21075
22061
|
}
|
|
21076
22062
|
) : null,
|
|
22063
|
+
state.mcpPicker.open ? /* @__PURE__ */ jsx(
|
|
22064
|
+
McpPicker,
|
|
22065
|
+
{
|
|
22066
|
+
items: state.mcpPicker.items,
|
|
22067
|
+
selected: state.mcpPicker.selected,
|
|
22068
|
+
busy: state.mcpPicker.busy,
|
|
22069
|
+
hint: state.mcpPicker.hint
|
|
22070
|
+
}
|
|
22071
|
+
) : null,
|
|
22072
|
+
state.toolsPicker.open ? /* @__PURE__ */ jsx(
|
|
22073
|
+
ToolsPicker,
|
|
22074
|
+
{
|
|
22075
|
+
items: state.toolsPicker.items,
|
|
22076
|
+
selected: state.toolsPicker.selected,
|
|
22077
|
+
busy: state.toolsPicker.busy,
|
|
22078
|
+
hint: state.toolsPicker.hint,
|
|
22079
|
+
filter: state.toolsPicker.filter
|
|
22080
|
+
}
|
|
22081
|
+
) : null,
|
|
22082
|
+
state.brainPanel.open ? /* @__PURE__ */ jsx(
|
|
22083
|
+
BrainPanel,
|
|
22084
|
+
{
|
|
22085
|
+
riskLevel: state.brainPanel.riskLevel,
|
|
22086
|
+
log: state.brainPanel.log,
|
|
22087
|
+
selected: state.brainPanel.selected,
|
|
22088
|
+
hint: state.brainPanel.hint
|
|
22089
|
+
}
|
|
22090
|
+
) : null,
|
|
22091
|
+
state.helpPanel.open ? /* @__PURE__ */ jsx(
|
|
22092
|
+
HelpPanel,
|
|
22093
|
+
{
|
|
22094
|
+
entries: state.helpPanel.entries,
|
|
22095
|
+
filter: state.helpPanel.filter,
|
|
22096
|
+
selected: state.helpPanel.selected,
|
|
22097
|
+
hint: state.helpPanel.hint
|
|
22098
|
+
}
|
|
22099
|
+
) : null,
|
|
22100
|
+
state.shadowPanel.open ? /* @__PURE__ */ jsx(
|
|
22101
|
+
ShadowPanel,
|
|
22102
|
+
{
|
|
22103
|
+
shadow: state.shadowPanel.shadow,
|
|
22104
|
+
hint: state.shadowPanel.hint
|
|
22105
|
+
}
|
|
22106
|
+
) : null,
|
|
21077
22107
|
state.authPanel.open ? /* @__PURE__ */ jsx(AuthPanel, { panel: state.authPanel }) : null,
|
|
21078
22108
|
state.projectPicker.open ? /* @__PURE__ */ jsx(
|
|
21079
22109
|
ProjectPicker,
|
|
@@ -21848,6 +22878,16 @@ async function runTui(opts) {
|
|
|
21848
22878
|
saveSettings: opts.saveSettings,
|
|
21849
22879
|
getPluginItems: opts.getPluginItems,
|
|
21850
22880
|
onPluginToggle: opts.onPluginToggle,
|
|
22881
|
+
getMcpServers: opts.getMcpServers,
|
|
22882
|
+
onMcpToggle: opts.onMcpToggle,
|
|
22883
|
+
onMcpRestart: opts.onMcpRestart,
|
|
22884
|
+
getToolsItems: opts.getToolsItems,
|
|
22885
|
+
onToolToggle: opts.onToolToggle,
|
|
22886
|
+
getBrainData: opts.getBrainData,
|
|
22887
|
+
onBrainRiskLevel: opts.onBrainRiskLevel,
|
|
22888
|
+
getShadowData: opts.getShadowData,
|
|
22889
|
+
onShadowStart: opts.onShadowStart,
|
|
22890
|
+
onShadowStop: opts.onShadowStop,
|
|
21851
22891
|
authHost: opts.authHost,
|
|
21852
22892
|
predictNext: opts.predictNext,
|
|
21853
22893
|
onSuggestionsParsed: opts.onSuggestionsParsed,
|