@wrongstack/tui 0.282.1 → 0.283.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/index.d.ts +68 -0
- package/dist/index.js +1472 -150
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, InputHistoryStore, DefaultSecretScrubber, INPUT_HISTORY_DEFAULT_MAX, DefaultPromptLoader, PromptUsageStore, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, listBoards, getBoard, createBoard, addTask, buildChildEnv, removeTask, moveTask, updateTask, duplicateBoard, copyTaskToBoard, transferTaskToBoard } from '@wrongstack/core';
|
|
1
|
+
import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, InputHistoryStore, DefaultSecretScrubber, INPUT_HISTORY_DEFAULT_MAX, DefaultPromptLoader, PromptUsageStore, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, detectContinueIntent, resolveContinuation, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, listBoards, getBoard, createBoard, addTask, buildChildEnv, removeTask, moveTask, updateTask, duplicateBoard, copyTaskToBoard, transferTaskToBoard } from '@wrongstack/core';
|
|
2
2
|
export { buildGoalPreamble } from '@wrongstack/core';
|
|
3
3
|
import { Box as Box$1, useStdout, Static, useInput, useStdin, measureElement, Text as Text$1, render, useApp } from 'ink';
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
5
|
import * as path9 from 'path';
|
|
6
|
-
import
|
|
6
|
+
import React7, { forwardRef, useState, useEffect, useMemo, memo, useRef, useLayoutEffect, useCallback, useReducer, isValidElement, Fragment as Fragment$1 } from 'react';
|
|
7
7
|
import * as fsp from 'fs/promises';
|
|
8
8
|
import { expectDefined, toErrorMessage, resolveWstackPaths as resolveWstackPaths$1, sessionScopedPath } from '@wrongstack/core/utils';
|
|
9
9
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
@@ -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,
|
|
@@ -3344,6 +3524,10 @@ function reducer(state, action) {
|
|
|
3344
3524
|
return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
|
|
3345
3525
|
case "confirmClose":
|
|
3346
3526
|
return { ...state, confirmQueue: state.confirmQueue.slice(1) };
|
|
3527
|
+
case "shellCommandWarningOpen":
|
|
3528
|
+
return { ...state, shellCommandWarning: action.info };
|
|
3529
|
+
case "shellCommandWarningClose":
|
|
3530
|
+
return { ...state, shellCommandWarning: null };
|
|
3347
3531
|
case "enhanceOpen":
|
|
3348
3532
|
return { ...state, enhance: action.info };
|
|
3349
3533
|
case "enhanceClose":
|
|
@@ -3352,6 +3536,10 @@ function reducer(state, action) {
|
|
|
3352
3536
|
return { ...state, enhanceEnabled: action.enabled };
|
|
3353
3537
|
case "enhanceBusy":
|
|
3354
3538
|
return { ...state, enhanceBusy: action.on };
|
|
3539
|
+
case "continueConfirmOpen":
|
|
3540
|
+
return { ...state, continueConfirm: action.info };
|
|
3541
|
+
case "continueConfirmClose":
|
|
3542
|
+
return { ...state, continueConfirm: null };
|
|
3355
3543
|
case "escConfirmOpen":
|
|
3356
3544
|
return { ...state, escConfirm: { snapshot: action.snapshot } };
|
|
3357
3545
|
case "escConfirmClose":
|
|
@@ -6166,22 +6354,62 @@ function BrainDecisionPrompt({
|
|
|
6166
6354
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press A/B/C or 1/2/3 to answer; Esc or D denies with the safe default." })
|
|
6167
6355
|
] });
|
|
6168
6356
|
}
|
|
6357
|
+
function modeFamily(mode) {
|
|
6358
|
+
if (mode.tags?.includes("lite")) return "lite";
|
|
6359
|
+
if (mode.tags?.includes("deep")) return "deep";
|
|
6360
|
+
if (mode.tags?.includes("balanced") || mode.id === "default") return "balanced";
|
|
6361
|
+
return "custom";
|
|
6362
|
+
}
|
|
6169
6363
|
function toModeOptions(modes, activeId) {
|
|
6170
6364
|
return modes.map((m) => ({
|
|
6171
6365
|
id: m.id,
|
|
6172
6366
|
name: m.name,
|
|
6173
6367
|
description: m.description,
|
|
6368
|
+
family: modeFamily(m),
|
|
6174
6369
|
isActive: m.id === activeId
|
|
6175
6370
|
}));
|
|
6176
6371
|
}
|
|
6372
|
+
function familyLabel(family) {
|
|
6373
|
+
switch (family) {
|
|
6374
|
+
case "lite":
|
|
6375
|
+
return "lite";
|
|
6376
|
+
case "deep":
|
|
6377
|
+
return "deep";
|
|
6378
|
+
case "balanced":
|
|
6379
|
+
return "base";
|
|
6380
|
+
case "custom":
|
|
6381
|
+
return "custom";
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
function familyColor(family) {
|
|
6385
|
+
switch (family) {
|
|
6386
|
+
case "lite":
|
|
6387
|
+
return "green";
|
|
6388
|
+
case "deep":
|
|
6389
|
+
return "magenta";
|
|
6390
|
+
case "balanced":
|
|
6391
|
+
return "blue";
|
|
6392
|
+
case "custom":
|
|
6393
|
+
return "yellow";
|
|
6394
|
+
}
|
|
6395
|
+
}
|
|
6177
6396
|
function ModePicker({
|
|
6178
6397
|
modes,
|
|
6179
6398
|
selected,
|
|
6180
6399
|
hint
|
|
6181
6400
|
}) {
|
|
6401
|
+
const activeMode = modes.find((mode) => mode.isActive);
|
|
6402
|
+
const modeMeta = `${modes.length} mode${modes.length === 1 ? "" : "s"}`;
|
|
6182
6403
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
6183
|
-
/* @__PURE__ */
|
|
6184
|
-
|
|
6404
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
6405
|
+
"\u2501\u2501 Mode Selection \u2501\u2501 ",
|
|
6406
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: modeMeta })
|
|
6407
|
+
] }),
|
|
6408
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
6409
|
+
"Current: ",
|
|
6410
|
+
activeMode ? activeMode.name : "none",
|
|
6411
|
+
" \xB7 \u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel"
|
|
6412
|
+
] }),
|
|
6185
6413
|
modes.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No modes available." }) : modes.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
6186
6414
|
Text,
|
|
6187
6415
|
{
|
|
@@ -6189,9 +6417,17 @@ function ModePicker({
|
|
|
6189
6417
|
...i === selected ? { color: "cyan" } : {},
|
|
6190
6418
|
children: [
|
|
6191
6419
|
i === selected ? "\u203A " : " ",
|
|
6192
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.name.padEnd(
|
|
6193
|
-
/* @__PURE__ */
|
|
6194
|
-
|
|
6420
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.name.padEnd(18) }),
|
|
6421
|
+
/* @__PURE__ */ jsxs(Text, { color: familyColor(opt.family), children: [
|
|
6422
|
+
"[",
|
|
6423
|
+
familyLabel(opt.family),
|
|
6424
|
+
"]"
|
|
6425
|
+
] }),
|
|
6426
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
6427
|
+
" ",
|
|
6428
|
+
opt.description
|
|
6429
|
+
] }),
|
|
6430
|
+
opt.isActive ? /* @__PURE__ */ jsx(Text, { color: "green", children: " \u25CF active" }) : null
|
|
6195
6431
|
]
|
|
6196
6432
|
},
|
|
6197
6433
|
opt.id
|
|
@@ -8286,7 +8522,7 @@ function streamBoxRows(text, maxLines, contentWidth) {
|
|
|
8286
8522
|
}
|
|
8287
8523
|
return rows;
|
|
8288
8524
|
}
|
|
8289
|
-
var ToolStreamBox =
|
|
8525
|
+
var ToolStreamBox = React7.memo(function ToolStreamBox2({
|
|
8290
8526
|
name,
|
|
8291
8527
|
text,
|
|
8292
8528
|
startedAt,
|
|
@@ -8926,7 +9162,7 @@ function ConfirmPrompt({
|
|
|
8926
9162
|
onEnableYolo,
|
|
8927
9163
|
destructive
|
|
8928
9164
|
}) {
|
|
8929
|
-
|
|
9165
|
+
React7.useEffect(() => {
|
|
8930
9166
|
writeOut("\x07");
|
|
8931
9167
|
}, []);
|
|
8932
9168
|
useInput((input2, _key) => {
|
|
@@ -8960,7 +9196,7 @@ function ConfirmPrompt({
|
|
|
8960
9196
|
inputSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: inputSummary }) : null,
|
|
8961
9197
|
showDiff && diff ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
|
|
8962
9198
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
8963
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(
|
|
9199
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React7.Fragment, { children: [
|
|
8964
9200
|
/* @__PURE__ */ jsx(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
|
|
8965
9201
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: l.rest })
|
|
8966
9202
|
] }, l.decision)) }) }),
|
|
@@ -9098,6 +9334,72 @@ function DesignPicker({ kits, selected, stack }) {
|
|
|
9098
9334
|
] }) }, kit.id))
|
|
9099
9335
|
] });
|
|
9100
9336
|
}
|
|
9337
|
+
function continueAutoProceedSeconds(grounded, delayMs) {
|
|
9338
|
+
return grounded ? Math.max(1, Math.ceil(delayMs / 1e3)) : null;
|
|
9339
|
+
}
|
|
9340
|
+
function ContinueConfirmPanel({
|
|
9341
|
+
label,
|
|
9342
|
+
instruction,
|
|
9343
|
+
source,
|
|
9344
|
+
grounded,
|
|
9345
|
+
delayMs,
|
|
9346
|
+
onDecision
|
|
9347
|
+
}) {
|
|
9348
|
+
const autoProceedSecs = continueAutoProceedSeconds(grounded, delayMs);
|
|
9349
|
+
const remainingRef = React7.useRef(autoProceedSecs ?? 0);
|
|
9350
|
+
const decideRef = React7.useRef(onDecision);
|
|
9351
|
+
decideRef.current = onDecision;
|
|
9352
|
+
React7.useEffect(() => {
|
|
9353
|
+
if (!grounded) return;
|
|
9354
|
+
const id = setInterval(() => {
|
|
9355
|
+
const r = remainingRef.current - 1;
|
|
9356
|
+
remainingRef.current = r;
|
|
9357
|
+
if (r <= 0) {
|
|
9358
|
+
clearInterval(id);
|
|
9359
|
+
decideRef.current("proceed");
|
|
9360
|
+
}
|
|
9361
|
+
}, 1e3);
|
|
9362
|
+
return () => clearInterval(id);
|
|
9363
|
+
}, [grounded]);
|
|
9364
|
+
useInput((input, key) => {
|
|
9365
|
+
if (key.return) {
|
|
9366
|
+
onDecision("proceed");
|
|
9367
|
+
} else if (key.escape) {
|
|
9368
|
+
onDecision("cancel");
|
|
9369
|
+
} else if (input?.toLowerCase() === "e") {
|
|
9370
|
+
onDecision("edit");
|
|
9371
|
+
}
|
|
9372
|
+
});
|
|
9373
|
+
const accent = grounded ? "cyan" : "yellow";
|
|
9374
|
+
const preview = instruction.length > 320 ? `${instruction.slice(0, 317)}\u2026` : instruction;
|
|
9375
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: accent, paddingX: 1, children: [
|
|
9376
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
9377
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: accent, children: grounded ? "\u25B6 Continue" : "\u26A0 Continue (ambiguous)" }),
|
|
9378
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ' \u2014 you typed a bare "continue"' })
|
|
9379
|
+
] }),
|
|
9380
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
9381
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "resolves to: " }),
|
|
9382
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: label.replace(/^▶\s*Continue\s*→\s*/, "") })
|
|
9383
|
+
] }),
|
|
9384
|
+
source === "open" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
9385
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: 'No pending todo or suggestion \u2014 "continue" has no anchor here.' }),
|
|
9386
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "If you proceed, I'll choose the next step myself from the conversation and project state. That's a guess \u2014 it can drift from what you meant." })
|
|
9387
|
+
] }) : /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: preview }) }),
|
|
9388
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
9389
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
9390
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "[Enter]" }),
|
|
9391
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: autoProceedSecs != null ? ` proceed (auto ${autoProceedSecs}s) \xB7 ` : " proceed anyway \xB7 " }),
|
|
9392
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "[e]" }),
|
|
9393
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
9394
|
+
" ",
|
|
9395
|
+
source === "open" ? "type what to continue" : "edit",
|
|
9396
|
+
" \xB7 "
|
|
9397
|
+
] }),
|
|
9398
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "red", children: "[Esc]" }),
|
|
9399
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " cancel" })
|
|
9400
|
+
] }) })
|
|
9401
|
+
] });
|
|
9402
|
+
}
|
|
9101
9403
|
function EnhancePanel({
|
|
9102
9404
|
original,
|
|
9103
9405
|
refined,
|
|
@@ -9107,12 +9409,12 @@ function EnhancePanel({
|
|
|
9107
9409
|
onTick
|
|
9108
9410
|
}) {
|
|
9109
9411
|
const totalSecs = Math.max(1, Math.ceil(delayMs / 1e3));
|
|
9110
|
-
const remainingRef =
|
|
9111
|
-
const decideRef =
|
|
9412
|
+
const remainingRef = React7.useRef(totalSecs);
|
|
9413
|
+
const decideRef = React7.useRef(onDecision);
|
|
9112
9414
|
decideRef.current = onDecision;
|
|
9113
|
-
const tickRef =
|
|
9415
|
+
const tickRef = React7.useRef(onTick);
|
|
9114
9416
|
tickRef.current = onTick;
|
|
9115
|
-
|
|
9417
|
+
React7.useEffect(() => {
|
|
9116
9418
|
const id = setInterval(() => {
|
|
9117
9419
|
const r = remainingRef.current - 1;
|
|
9118
9420
|
remainingRef.current = r;
|
|
@@ -9359,6 +9661,44 @@ function FilePicker({ query, matches, selected }) {
|
|
|
9359
9661
|
function highlight(path10, _query) {
|
|
9360
9662
|
return path10;
|
|
9361
9663
|
}
|
|
9664
|
+
function truncateShellCommandWarningCommand(text, max = 80) {
|
|
9665
|
+
return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;
|
|
9666
|
+
}
|
|
9667
|
+
function ShellCommandWarning({
|
|
9668
|
+
command,
|
|
9669
|
+
onDecision
|
|
9670
|
+
}) {
|
|
9671
|
+
React7.useEffect(() => {
|
|
9672
|
+
writeOut("\x07");
|
|
9673
|
+
}, []);
|
|
9674
|
+
useInput((input, _key) => {
|
|
9675
|
+
if (!input || input === "\r" || input === "\n") return;
|
|
9676
|
+
const ch = input.toLowerCase();
|
|
9677
|
+
if (ch === "y") onDecision("yes");
|
|
9678
|
+
if (ch === "n") onDecision("no");
|
|
9679
|
+
if (ch === "d") onDecision("dont-show-again");
|
|
9680
|
+
});
|
|
9681
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
9682
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
9683
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "\u26A0 SHELL COMMAND" }),
|
|
9684
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
9685
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "white", children: [
|
|
9686
|
+
"!",
|
|
9687
|
+
truncateShellCommandWarningCommand(command)
|
|
9688
|
+
] })
|
|
9689
|
+
] }),
|
|
9690
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "This will execute in your shell via /dev. Only run commands you trust." }),
|
|
9691
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
9692
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
9693
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "[y]" }),
|
|
9694
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "es " }),
|
|
9695
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "red", children: "[n]" }),
|
|
9696
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "o " }),
|
|
9697
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "[d]" }),
|
|
9698
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "ont show again" })
|
|
9699
|
+
] }) })
|
|
9700
|
+
] });
|
|
9701
|
+
}
|
|
9362
9702
|
var METER_WIDTH = 10;
|
|
9363
9703
|
function isLeaderEntry2(entry) {
|
|
9364
9704
|
return entry.id === "leader" || entry.name === "LEADER";
|
|
@@ -10738,7 +11078,7 @@ function brainRiskColor(risk) {
|
|
|
10738
11078
|
return "red";
|
|
10739
11079
|
}
|
|
10740
11080
|
}
|
|
10741
|
-
var Entry =
|
|
11081
|
+
var Entry = React7.memo(function Entry2({
|
|
10742
11082
|
entry,
|
|
10743
11083
|
termWidth,
|
|
10744
11084
|
setSuggestions,
|
|
@@ -12599,7 +12939,135 @@ function PlanRow({ item }) {
|
|
|
12599
12939
|
] }) : null
|
|
12600
12940
|
] });
|
|
12601
12941
|
}
|
|
12602
|
-
var CHROME_ROWS2 =
|
|
12942
|
+
var CHROME_ROWS2 = 14;
|
|
12943
|
+
var RISK_DESCS = {
|
|
12944
|
+
off: "Human decides everything",
|
|
12945
|
+
low: "Auto-decide low risk only",
|
|
12946
|
+
medium: "Auto-decide up to medium risk",
|
|
12947
|
+
high: "Auto-decide up to high risk",
|
|
12948
|
+
all: "Auto-decide everything"
|
|
12949
|
+
};
|
|
12950
|
+
var RISK_COLORS2 = {
|
|
12951
|
+
off: "gray",
|
|
12952
|
+
low: "green",
|
|
12953
|
+
medium: "yellow",
|
|
12954
|
+
high: "red",
|
|
12955
|
+
all: "magenta"
|
|
12956
|
+
};
|
|
12957
|
+
function BrainPanel({
|
|
12958
|
+
riskLevel,
|
|
12959
|
+
log,
|
|
12960
|
+
selected,
|
|
12961
|
+
hint
|
|
12962
|
+
}) {
|
|
12963
|
+
const { stdout } = useStdout();
|
|
12964
|
+
const termRows = stdout?.rows ?? 24;
|
|
12965
|
+
const maxVisible = Math.max(4, termRows - CHROME_ROWS2);
|
|
12966
|
+
const total = log.length;
|
|
12967
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12968
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12969
|
+
const above = windowStart;
|
|
12970
|
+
const below = total - windowEnd;
|
|
12971
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
12972
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "\u2501\u2501 Brain \u2501\u2501" }),
|
|
12973
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate log \xB7 \u2190/\u2192 change risk \xB7 Esc close" }),
|
|
12974
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12975
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
12976
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Risk ceiling: " }),
|
|
12977
|
+
/* @__PURE__ */ jsx(Text, { color: RISK_COLORS2[riskLevel], bold: true, children: riskLevel.toUpperCase() }),
|
|
12978
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${RISK_DESCS[riskLevel]}` })
|
|
12979
|
+
] }),
|
|
12980
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12981
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "Recent decisions" }),
|
|
12982
|
+
total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No decisions recorded yet this session." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12983
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12984
|
+
log.slice(windowStart, windowEnd).map((entry, i) => {
|
|
12985
|
+
const index = windowStart + i;
|
|
12986
|
+
const focused = index === selected;
|
|
12987
|
+
return /* @__PURE__ */ jsxs(
|
|
12988
|
+
Text,
|
|
12989
|
+
{
|
|
12990
|
+
inverse: focused,
|
|
12991
|
+
...focused ? { color: "magenta" } : {},
|
|
12992
|
+
wrap: "truncate-end",
|
|
12993
|
+
children: [
|
|
12994
|
+
focused ? "\u203A " : " ",
|
|
12995
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.age.padEnd(8) }),
|
|
12996
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: entry.kind.padEnd(12) }),
|
|
12997
|
+
/* @__PURE__ */ jsx(Text, { children: entry.question.length > 60 ? `${entry.question.slice(0, 57)}\u2026` : entry.question }),
|
|
12998
|
+
entry.outcome ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2192 ${entry.outcome.length > 20 ? `${entry.outcome.slice(0, 17)}\u2026` : entry.outcome}` }) : null
|
|
12999
|
+
]
|
|
13000
|
+
},
|
|
13001
|
+
`${entry.kind}-${i}`
|
|
13002
|
+
);
|
|
13003
|
+
}),
|
|
13004
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
13005
|
+
] })
|
|
13006
|
+
] })
|
|
13007
|
+
] }),
|
|
13008
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13009
|
+
] });
|
|
13010
|
+
}
|
|
13011
|
+
var CHROME_ROWS3 = 17;
|
|
13012
|
+
function statusBadge(status, enabled) {
|
|
13013
|
+
if (!enabled) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disabled" });
|
|
13014
|
+
switch (status) {
|
|
13015
|
+
case "connected":
|
|
13016
|
+
return /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF connected" });
|
|
13017
|
+
case "connecting":
|
|
13018
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D0 connecting" });
|
|
13019
|
+
case "reconnecting":
|
|
13020
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D1 reconnecting" });
|
|
13021
|
+
case "disconnected":
|
|
13022
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disconnected" });
|
|
13023
|
+
case "failed":
|
|
13024
|
+
return /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 failed" });
|
|
13025
|
+
default:
|
|
13026
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: status });
|
|
13027
|
+
}
|
|
13028
|
+
}
|
|
13029
|
+
function McpPicker({
|
|
13030
|
+
items,
|
|
13031
|
+
selected,
|
|
13032
|
+
busy = false,
|
|
13033
|
+
hint
|
|
13034
|
+
}) {
|
|
13035
|
+
const { stdout } = useStdout();
|
|
13036
|
+
const rows = stdout?.rows ?? 24;
|
|
13037
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS3);
|
|
13038
|
+
const total = items.length;
|
|
13039
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
13040
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
13041
|
+
const above = windowStart;
|
|
13042
|
+
const below = total - windowEnd;
|
|
13043
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
13044
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MCP Servers" }),
|
|
13045
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle enable \xB7 r restart \xB7 Esc close" }),
|
|
13046
|
+
/* @__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: [
|
|
13047
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
13048
|
+
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
13049
|
+
const index = windowStart + i;
|
|
13050
|
+
const focused = index === selected;
|
|
13051
|
+
const marker = focused ? "\u203A" : " ";
|
|
13052
|
+
return /* @__PURE__ */ jsxs(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
13053
|
+
marker,
|
|
13054
|
+
" ",
|
|
13055
|
+
statusBadge(item.status, item.enabled),
|
|
13056
|
+
" ",
|
|
13057
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.name.padEnd(18) }),
|
|
13058
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13059
|
+
item.transport.padEnd(14),
|
|
13060
|
+
item.toolCount > 0 ? `${item.toolCount} tools` : "",
|
|
13061
|
+
item.lazy ? " lazy" : ""
|
|
13062
|
+
] })
|
|
13063
|
+
] }, item.name);
|
|
13064
|
+
}),
|
|
13065
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
13066
|
+
] }) }),
|
|
13067
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13068
|
+
] });
|
|
13069
|
+
}
|
|
13070
|
+
var CHROME_ROWS4 = 17;
|
|
12603
13071
|
function PluginPicker({
|
|
12604
13072
|
items,
|
|
12605
13073
|
selected,
|
|
@@ -12608,7 +13076,7 @@ function PluginPicker({
|
|
|
12608
13076
|
}) {
|
|
12609
13077
|
const { stdout } = useStdout();
|
|
12610
13078
|
const rows = stdout?.rows ?? 24;
|
|
12611
|
-
const maxVisible = Math.max(4, rows -
|
|
13079
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS4);
|
|
12612
13080
|
const total = items.length;
|
|
12613
13081
|
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12614
13082
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
@@ -12654,43 +13122,369 @@ function PluginPicker({
|
|
|
12654
13122
|
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12655
13123
|
] });
|
|
12656
13124
|
}
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
if (
|
|
12669
|
-
|
|
13125
|
+
var CHROME_ROWS5 = 15;
|
|
13126
|
+
function toolActionLabel(enabled) {
|
|
13127
|
+
return enabled ? "Enter makes this tool passive" : "Enter re-enables this tool";
|
|
13128
|
+
}
|
|
13129
|
+
function statusBadge2(enabled) {
|
|
13130
|
+
return enabled ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF active" }) : /* @__PURE__ */ jsx(Text, { color: "red", children: "\u25CB passive" });
|
|
13131
|
+
}
|
|
13132
|
+
function rwBadge(mutating) {
|
|
13133
|
+
return mutating ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "mut" }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: "ro" });
|
|
13134
|
+
}
|
|
13135
|
+
function displayCategory(cat) {
|
|
13136
|
+
if (!cat || cat.trim() === "") return "Other";
|
|
13137
|
+
return cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
13138
|
+
}
|
|
13139
|
+
var DEFAULT_COLUMN_WIDTHS = {
|
|
13140
|
+
name: 28,
|
|
13141
|
+
category: 16,
|
|
13142
|
+
owner: 31,
|
|
13143
|
+
permission: 8
|
|
13144
|
+
};
|
|
13145
|
+
var MIN_COLUMN_WIDTHS = {
|
|
13146
|
+
name: 22,
|
|
13147
|
+
category: 13,
|
|
13148
|
+
owner: 20,
|
|
13149
|
+
permission: 7
|
|
13150
|
+
};
|
|
13151
|
+
function shrinkColumn(widths, column, overflow) {
|
|
13152
|
+
const room = widths[column] - MIN_COLUMN_WIDTHS[column];
|
|
13153
|
+
const shrinkBy = Math.min(room, overflow);
|
|
13154
|
+
widths[column] -= shrinkBy;
|
|
13155
|
+
return overflow - shrinkBy;
|
|
13156
|
+
}
|
|
13157
|
+
function columnWidthsFor(columns) {
|
|
13158
|
+
const widths = { ...DEFAULT_COLUMN_WIDTHS };
|
|
13159
|
+
const rowChromeWidth = 30;
|
|
13160
|
+
const availableVariableWidth = Math.max(
|
|
13161
|
+
Object.values(MIN_COLUMN_WIDTHS).reduce((sum, width) => sum + width, 0),
|
|
13162
|
+
columns - rowChromeWidth
|
|
13163
|
+
);
|
|
13164
|
+
const desiredVariableWidth = Object.values(widths).reduce((sum, width) => sum + width, 0);
|
|
13165
|
+
let overflow = desiredVariableWidth - availableVariableWidth;
|
|
13166
|
+
for (const column of ["owner", "category", "name", "permission"]) {
|
|
13167
|
+
if (overflow <= 0) break;
|
|
13168
|
+
overflow = shrinkColumn(widths, column, overflow);
|
|
12670
13169
|
}
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
13170
|
+
return widths;
|
|
13171
|
+
}
|
|
13172
|
+
function fitCell(value, width) {
|
|
13173
|
+
if (width <= 0) return "";
|
|
13174
|
+
if (value.length > width) {
|
|
13175
|
+
return `${value.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
13176
|
+
}
|
|
13177
|
+
return value.padEnd(width);
|
|
13178
|
+
}
|
|
13179
|
+
function buildRows(items) {
|
|
13180
|
+
return items.map((item, index) => ({ item, index }));
|
|
13181
|
+
}
|
|
13182
|
+
function windowRows(rows, focus, max) {
|
|
13183
|
+
if (rows.length <= max) {
|
|
13184
|
+
return { rows, start: 0, end: rows.length };
|
|
13185
|
+
}
|
|
13186
|
+
let start = focus - Math.floor(max / 2);
|
|
13187
|
+
if (start < 0) start = 0;
|
|
13188
|
+
let end = start + max;
|
|
13189
|
+
if (end > rows.length) {
|
|
13190
|
+
end = rows.length;
|
|
13191
|
+
start = end - max;
|
|
13192
|
+
}
|
|
13193
|
+
return { rows: rows.slice(start, end), start, end };
|
|
13194
|
+
}
|
|
13195
|
+
function ToolsPicker({
|
|
13196
|
+
items,
|
|
13197
|
+
selected,
|
|
13198
|
+
busy = false,
|
|
13199
|
+
hint,
|
|
13200
|
+
filter
|
|
13201
|
+
}) {
|
|
13202
|
+
const { stdout } = useStdout();
|
|
13203
|
+
const termRows = stdout?.rows ?? 24;
|
|
13204
|
+
const termColumns = stdout?.columns ?? 100;
|
|
13205
|
+
const columnWidths = columnWidthsFor(termColumns);
|
|
13206
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS5);
|
|
13207
|
+
const total = items.length;
|
|
13208
|
+
let visibleItems;
|
|
13209
|
+
let visibleSelected;
|
|
13210
|
+
const filterActive = Boolean(filter && filter.length > 0);
|
|
13211
|
+
if (filterActive) {
|
|
13212
|
+
const q = filter.toLowerCase();
|
|
13213
|
+
visibleItems = items.filter(
|
|
13214
|
+
(it) => it.name.toLowerCase().includes(q) || it.owner.toLowerCase().includes(q) || it.description.toLowerCase().includes(q)
|
|
13215
|
+
);
|
|
13216
|
+
const rawSelected = items[selected];
|
|
13217
|
+
visibleSelected = rawSelected ? visibleItems.indexOf(rawSelected) : 0;
|
|
13218
|
+
if (visibleSelected < 0) visibleSelected = 0;
|
|
13219
|
+
} else {
|
|
13220
|
+
visibleItems = items;
|
|
13221
|
+
visibleSelected = selected;
|
|
13222
|
+
}
|
|
13223
|
+
const rows = buildRows(visibleItems);
|
|
13224
|
+
const enabledCount = items.filter((item) => item.enabled).length;
|
|
13225
|
+
const passiveCount = total - enabledCount;
|
|
13226
|
+
const selectedItem = visibleItems[visibleSelected];
|
|
13227
|
+
let displayRows;
|
|
13228
|
+
let hiddenAbove = 0;
|
|
13229
|
+
let hiddenBelow = 0;
|
|
13230
|
+
if (filterActive) {
|
|
13231
|
+
displayRows = rows;
|
|
13232
|
+
} else {
|
|
13233
|
+
const win = windowRows(rows, visibleSelected, maxVisible);
|
|
13234
|
+
displayRows = win.rows;
|
|
13235
|
+
hiddenAbove = win.start;
|
|
13236
|
+
hiddenBelow = rows.length - win.end;
|
|
13237
|
+
}
|
|
13238
|
+
const hasFilter = filterActive;
|
|
13239
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
|
|
13240
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "\u2501\u2501 Tools \u2501\u2501" }),
|
|
13241
|
+
/* @__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 ${enabledCount} active / ${passiveCount} passive` }),
|
|
13242
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Passive tools stay listed for this session so you can select them and re-enable them later." }),
|
|
13243
|
+
/* @__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: [
|
|
13244
|
+
'No tools match "',
|
|
13245
|
+
filter,
|
|
13246
|
+
'".'
|
|
13247
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13248
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13249
|
+
displayRows.map(({ item, index }) => {
|
|
13250
|
+
const focused = index === visibleSelected;
|
|
13251
|
+
return /* @__PURE__ */ jsxs(
|
|
13252
|
+
Text,
|
|
13253
|
+
{
|
|
13254
|
+
inverse: focused,
|
|
13255
|
+
...focused ? { color: "green" } : {},
|
|
13256
|
+
wrap: "truncate-end",
|
|
13257
|
+
children: [
|
|
13258
|
+
focused ? "\u203A " : " ",
|
|
13259
|
+
statusBadge2(item.enabled),
|
|
13260
|
+
" ",
|
|
13261
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: fitCell(item.name, columnWidths.name) }),
|
|
13262
|
+
" ",
|
|
13263
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13264
|
+
fitCell(displayCategory(item.category), columnWidths.category),
|
|
13265
|
+
" ",
|
|
13266
|
+
fitCell(`[${item.owner}]`, columnWidths.owner),
|
|
13267
|
+
" ",
|
|
13268
|
+
rwBadge(item.mutating),
|
|
13269
|
+
" ",
|
|
13270
|
+
" ",
|
|
13271
|
+
fitCell(item.permission, columnWidths.permission),
|
|
13272
|
+
" ",
|
|
13273
|
+
/* @__PURE__ */ jsxs(Text, { color: item.descMode === "simple" ? "yellow" : void 0, children: [
|
|
13274
|
+
"desc:",
|
|
13275
|
+
item.descMode
|
|
13276
|
+
] })
|
|
13277
|
+
] })
|
|
13278
|
+
]
|
|
13279
|
+
},
|
|
13280
|
+
item.name
|
|
13281
|
+
);
|
|
13282
|
+
}),
|
|
13283
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13284
|
+
] }) }),
|
|
13285
|
+
selectedItem ? /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13286
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
13287
|
+
/* @__PURE__ */ jsx(Text, { color: selectedItem.enabled ? "green" : "red", children: toolActionLabel(selectedItem.enabled) }),
|
|
13288
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${selectedItem.mutating ? "Mutating" : "Read-only"} \xB7 permission: ${selectedItem.permission} \xB7 descriptions: ${selectedItem.descMode}` })
|
|
13289
|
+
] }),
|
|
13290
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: selectedItem.description || "No description provided." })
|
|
13291
|
+
] }) : null,
|
|
13292
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13293
|
+
] });
|
|
13294
|
+
}
|
|
13295
|
+
var CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
13296
|
+
var CHROME_ROWS6 = 7;
|
|
13297
|
+
function normalizeQuery(raw) {
|
|
13298
|
+
return raw.trim().toLowerCase();
|
|
13299
|
+
}
|
|
13300
|
+
function buildRows2(entries) {
|
|
13301
|
+
const rows = [];
|
|
13302
|
+
let lastCat = "";
|
|
13303
|
+
for (let i = 0; i < entries.length; i++) {
|
|
13304
|
+
const e = entries[i];
|
|
13305
|
+
const cat = e.category || "App";
|
|
13306
|
+
if (cat !== lastCat) {
|
|
13307
|
+
lastCat = cat;
|
|
13308
|
+
rows.push({ type: "header", category: cat });
|
|
13309
|
+
}
|
|
13310
|
+
rows.push({ type: "item", entry: e, index: i });
|
|
13311
|
+
}
|
|
13312
|
+
return rows;
|
|
13313
|
+
}
|
|
13314
|
+
function windowRows2(rows, focus, max) {
|
|
13315
|
+
if (rows.length <= max) {
|
|
13316
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13317
|
+
}
|
|
13318
|
+
let start = focus - Math.floor(max / 2);
|
|
13319
|
+
if (start < 0) start = 0;
|
|
13320
|
+
let end = start + max;
|
|
13321
|
+
if (end > rows.length) {
|
|
13322
|
+
end = rows.length;
|
|
13323
|
+
start = end - max;
|
|
13324
|
+
}
|
|
13325
|
+
let contextHeader = null;
|
|
13326
|
+
if (start > 0) {
|
|
13327
|
+
const first = rows[start];
|
|
13328
|
+
if (first && first.type === "item") {
|
|
13329
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
13330
|
+
const r = rows[i];
|
|
13331
|
+
if (r && r.type === "header") {
|
|
13332
|
+
contextHeader = r.category;
|
|
13333
|
+
break;
|
|
13334
|
+
}
|
|
13335
|
+
}
|
|
13336
|
+
}
|
|
13337
|
+
}
|
|
13338
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
13339
|
+
}
|
|
13340
|
+
function HelpPanel({
|
|
13341
|
+
entries,
|
|
13342
|
+
filter,
|
|
13343
|
+
selected,
|
|
13344
|
+
hint
|
|
13345
|
+
}) {
|
|
13346
|
+
const { stdout } = useStdout();
|
|
13347
|
+
const termRows = stdout?.rows ?? 24;
|
|
13348
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS6);
|
|
13349
|
+
const query = normalizeQuery(filter);
|
|
13350
|
+
const filtered = query ? entries.filter(
|
|
13351
|
+
(e) => e.name.toLowerCase().includes(query) || e.description.toLowerCase().includes(query) || e.category.toLowerCase().includes(query) || (e.aliases ?? []).some((a) => a.toLowerCase().includes(query))
|
|
13352
|
+
) : entries;
|
|
13353
|
+
filtered.sort((a, b) => {
|
|
13354
|
+
const ai = CATEGORY_ORDER.indexOf(a.category);
|
|
13355
|
+
const bi = CATEGORY_ORDER.indexOf(b.category);
|
|
13356
|
+
if (ai !== bi) return ai - bi;
|
|
13357
|
+
return a.name.localeCompare(b.name);
|
|
13358
|
+
});
|
|
13359
|
+
const rows = buildRows2(filtered);
|
|
13360
|
+
const focus = Math.min(selected, Math.max(0, filtered.length - 1));
|
|
13361
|
+
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === focus);
|
|
13362
|
+
const win = windowRows2(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, maxVisible);
|
|
13363
|
+
const { rows: visible, start, end, contextHeader } = win;
|
|
13364
|
+
const hiddenAbove = start;
|
|
13365
|
+
const hiddenBelow = rows.length - end;
|
|
13366
|
+
const hasFilter = query.length > 0;
|
|
13367
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
13368
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2501\u2501 Help / Command Palette \u2501\u2501" }),
|
|
13369
|
+
/* @__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" }),
|
|
13370
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13371
|
+
'No commands match "',
|
|
13372
|
+
filter,
|
|
13373
|
+
'".'
|
|
13374
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13375
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13376
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13377
|
+
" ",
|
|
13378
|
+
contextHeader
|
|
13379
|
+
] }) : null,
|
|
13380
|
+
visible.map((row) => {
|
|
13381
|
+
if (row.type === "header") {
|
|
13382
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13383
|
+
" ",
|
|
13384
|
+
row.category
|
|
13385
|
+
] }, `cat-${row.category}`);
|
|
13386
|
+
}
|
|
13387
|
+
const { entry, index } = row;
|
|
13388
|
+
const isSelected = index === focus;
|
|
13389
|
+
return /* @__PURE__ */ jsxs(
|
|
13390
|
+
Text,
|
|
13391
|
+
{
|
|
13392
|
+
inverse: isSelected,
|
|
13393
|
+
...isSelected ? { color: "cyan" } : {},
|
|
13394
|
+
wrap: "truncate-end",
|
|
13395
|
+
children: [
|
|
13396
|
+
isSelected ? "\u203A " : " ",
|
|
13397
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
13398
|
+
"/",
|
|
13399
|
+
entry.name
|
|
13400
|
+
] }),
|
|
13401
|
+
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13402
|
+
" (",
|
|
13403
|
+
entry.aliases.map((a) => `/${a}`).join(", "),
|
|
13404
|
+
")"
|
|
13405
|
+
] }) : null,
|
|
13406
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13407
|
+
" \u2014 ",
|
|
13408
|
+
entry.description
|
|
13409
|
+
] }),
|
|
13410
|
+
entry.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13411
|
+
" ",
|
|
13412
|
+
entry.argsHint
|
|
13413
|
+
] }) : null
|
|
13414
|
+
]
|
|
13415
|
+
},
|
|
13416
|
+
entry.name
|
|
13417
|
+
);
|
|
13418
|
+
}),
|
|
13419
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13420
|
+
] }) }),
|
|
13421
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13422
|
+
] });
|
|
13423
|
+
}
|
|
13424
|
+
function ShadowPanel({
|
|
13425
|
+
shadow,
|
|
13426
|
+
hint
|
|
13427
|
+
}) {
|
|
13428
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
13429
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "\u2501\u2501 Shadow Agent \u2501\u2501" }),
|
|
13430
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "s start \xB7 t stop \xB7 i cycle interval \xB7 m cycle model \xB7 Esc close" }),
|
|
13431
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13432
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
13433
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Status: " }),
|
|
13434
|
+
shadow.running ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF running" }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u25CB stopped" }),
|
|
13435
|
+
shadow.activeId ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${shadow.activeId.slice(0, 12)}\u2026` }) : null
|
|
13436
|
+
] }),
|
|
13437
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13438
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Model: " }),
|
|
13439
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: shadow.model })
|
|
13440
|
+
] }),
|
|
13441
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13442
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Interval: " }),
|
|
13443
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: shadow.intervalMs >= 1e3 ? `${shadow.intervalMs / 1e3}s` : `${shadow.intervalMs}ms` }),
|
|
13444
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (min 5s)" })
|
|
13445
|
+
] }),
|
|
13446
|
+
/* @__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" }) })
|
|
13447
|
+
] }),
|
|
13448
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13449
|
+
] });
|
|
13450
|
+
}
|
|
13451
|
+
function ProcessListMonitor() {
|
|
13452
|
+
const [, setTick] = useState(0);
|
|
13453
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
13454
|
+
useEffect(() => {
|
|
13455
|
+
const id = setInterval(() => setTick((t) => t + 1), 1e3);
|
|
13456
|
+
return () => clearInterval(id);
|
|
13457
|
+
}, []);
|
|
13458
|
+
const registry = getProcessRegistry();
|
|
13459
|
+
const all = registry.list();
|
|
13460
|
+
const stats = registry.stats();
|
|
13461
|
+
const safeIndex = Math.min(selectedIndex, Math.max(0, all.length - 1));
|
|
13462
|
+
if (safeIndex !== selectedIndex) {
|
|
13463
|
+
setSelectedIndex(safeIndex);
|
|
13464
|
+
}
|
|
13465
|
+
const selected = all[safeIndex];
|
|
13466
|
+
const now = Date.now();
|
|
13467
|
+
const running = all.filter((p) => !p.killed).length;
|
|
13468
|
+
const b = stats.breaker;
|
|
13469
|
+
const breakerState = b.state === "closed" ? "\u{1F7E2} closed" : b.state === "half-open" ? "\u{1F7E1} half-open" : "\u{1F534} open";
|
|
13470
|
+
const pageSize = Math.max(1, Math.floor(all.length / 2));
|
|
13471
|
+
useInput((input, key) => {
|
|
13472
|
+
if (key.upArrow) {
|
|
13473
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
13474
|
+
} else if (key.downArrow) {
|
|
13475
|
+
setSelectedIndex((prev) => Math.min(all.length - 1, prev + 1));
|
|
13476
|
+
} else if (key.pageUp) {
|
|
13477
|
+
setSelectedIndex((prev) => Math.max(0, prev - pageSize));
|
|
13478
|
+
} else if (key.pageDown) {
|
|
13479
|
+
setSelectedIndex((prev) => Math.min(all.length - 1, prev + pageSize));
|
|
13480
|
+
} else if (key.home || key.ctrl && input === "a" || input === "g") {
|
|
13481
|
+
setSelectedIndex(0);
|
|
13482
|
+
} else if (key.end || key.ctrl && input === "e" || input === "G") {
|
|
13483
|
+
setSelectedIndex(Math.max(0, all.length - 1));
|
|
13484
|
+
} else if (key.return && selected) {
|
|
13485
|
+
getProcessRegistry().kill(selected.pid);
|
|
13486
|
+
} else if (key.delete && selected) {
|
|
13487
|
+
getProcessRegistry().kill(selected.pid, { force: true });
|
|
12694
13488
|
} else if (input === "a" && !key.ctrl) {
|
|
12695
13489
|
getProcessRegistry().killAll();
|
|
12696
13490
|
} else if (input === "A") {
|
|
@@ -13325,6 +14119,7 @@ function SessionsPanel({
|
|
|
13325
14119
|
var MAX_VISIBLE_ITEMS = 8;
|
|
13326
14120
|
function SlashMenu({ query, matches, selected }) {
|
|
13327
14121
|
const placeholder = query ? `/${query}` : "/";
|
|
14122
|
+
const resultMeta = matches.length > 0 ? `${selected + 1}/${matches.length}` : "no matches";
|
|
13328
14123
|
const rows = [];
|
|
13329
14124
|
let lastCategory = "";
|
|
13330
14125
|
for (let i = 0; i < matches.length; i++) {
|
|
@@ -13336,15 +14131,21 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13336
14131
|
rows.push({ type: "item", match: m, index: i });
|
|
13337
14132
|
}
|
|
13338
14133
|
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === selected);
|
|
13339
|
-
const visible =
|
|
14134
|
+
const visible = windowRows3(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, MAX_VISIBLE_ITEMS);
|
|
13340
14135
|
const hiddenAbove = visible.start;
|
|
13341
14136
|
const hiddenBelow = rows.length - visible.end;
|
|
13342
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
13343
|
-
/* @__PURE__ */ jsxs(Text, {
|
|
13344
|
-
|
|
14137
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
14138
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
14139
|
+
"\u2501\u2501 Command palette \u2501\u2501 ",
|
|
14140
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: placeholder }),
|
|
13345
14141
|
" ",
|
|
13346
|
-
|
|
14142
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
14143
|
+
"(",
|
|
14144
|
+
resultMeta,
|
|
14145
|
+
")"
|
|
14146
|
+
] })
|
|
13347
14147
|
] }),
|
|
14148
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type to filter commands by name, alias, or description." }),
|
|
13348
14149
|
hiddenAbove > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13349
14150
|
" \u2191 ",
|
|
13350
14151
|
hiddenAbove,
|
|
@@ -13388,7 +14189,7 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13388
14189
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500 \u2191\u2193 nav \xB7 Enter run \xB7 Tab fill \xB7 Esc close" })
|
|
13389
14190
|
] });
|
|
13390
14191
|
}
|
|
13391
|
-
function
|
|
14192
|
+
function windowRows3(rows, focus, max) {
|
|
13392
14193
|
if (rows.length <= max) {
|
|
13393
14194
|
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13394
14195
|
}
|
|
@@ -13782,6 +14583,79 @@ function runGit(cwd, args) {
|
|
|
13782
14583
|
});
|
|
13783
14584
|
}
|
|
13784
14585
|
|
|
14586
|
+
// src/rehydrate-history.ts
|
|
14587
|
+
function contentBlocksText(content) {
|
|
14588
|
+
if (typeof content === "string") return content;
|
|
14589
|
+
if (!Array.isArray(content)) return "";
|
|
14590
|
+
return content.filter(
|
|
14591
|
+
(block) => !!block && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
14592
|
+
).map((block) => block.text).join("");
|
|
14593
|
+
}
|
|
14594
|
+
function rehydrateHistory(messages, startId, toolCalls) {
|
|
14595
|
+
const entries = [];
|
|
14596
|
+
const toolCallsById = /* @__PURE__ */ new Map();
|
|
14597
|
+
if (toolCalls) {
|
|
14598
|
+
for (const tc of toolCalls) {
|
|
14599
|
+
if (!toolCallsById.has(tc.id)) toolCallsById.set(tc.id, tc);
|
|
14600
|
+
}
|
|
14601
|
+
}
|
|
14602
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
14603
|
+
const fallback = [];
|
|
14604
|
+
let nextId = startId;
|
|
14605
|
+
const textOf = (msg) => contentBlocksText(msg.content);
|
|
14606
|
+
const toolEntryFor = (tc) => ({
|
|
14607
|
+
id: nextId++,
|
|
14608
|
+
kind: "tool",
|
|
14609
|
+
name: tc.name,
|
|
14610
|
+
durationMs: tc.durationMs,
|
|
14611
|
+
ok: tc.ok,
|
|
14612
|
+
outputBytes: tc.outputBytes,
|
|
14613
|
+
outputTokens: tc.outputTokens,
|
|
14614
|
+
outputLines: tc.outputLines
|
|
14615
|
+
});
|
|
14616
|
+
const pushAssistantText = (parts) => {
|
|
14617
|
+
const text = parts.join("").trim();
|
|
14618
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
14619
|
+
parts.length = 0;
|
|
14620
|
+
};
|
|
14621
|
+
for (const msg of messages) {
|
|
14622
|
+
if (msg.role === "system") continue;
|
|
14623
|
+
if (msg.role === "user") {
|
|
14624
|
+
const text = textOf(msg).trim();
|
|
14625
|
+
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
14626
|
+
continue;
|
|
14627
|
+
}
|
|
14628
|
+
if (msg.role === "assistant") {
|
|
14629
|
+
if (!Array.isArray(msg.content)) {
|
|
14630
|
+
const text = textOf(msg).trim();
|
|
14631
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
14632
|
+
continue;
|
|
14633
|
+
}
|
|
14634
|
+
const textParts = [];
|
|
14635
|
+
for (const block of msg.content) {
|
|
14636
|
+
if (block.type === "text") {
|
|
14637
|
+
textParts.push(block.text);
|
|
14638
|
+
continue;
|
|
14639
|
+
}
|
|
14640
|
+
if (block.type !== "tool_use") continue;
|
|
14641
|
+
pushAssistantText(textParts);
|
|
14642
|
+
const tc = toolCallsById.get(block.id);
|
|
14643
|
+
if (!tc) continue;
|
|
14644
|
+
entries.push(toolEntryFor(tc));
|
|
14645
|
+
consumed.add(block.id);
|
|
14646
|
+
}
|
|
14647
|
+
pushAssistantText(textParts);
|
|
14648
|
+
}
|
|
14649
|
+
}
|
|
14650
|
+
if (toolCalls) {
|
|
14651
|
+
for (const tc of toolCalls) {
|
|
14652
|
+
if (!consumed.has(tc.id)) fallback.push(toolEntryFor(tc));
|
|
14653
|
+
}
|
|
14654
|
+
}
|
|
14655
|
+
entries.push(...fallback);
|
|
14656
|
+
return entries;
|
|
14657
|
+
}
|
|
14658
|
+
|
|
13785
14659
|
// src/app-initial-state.ts
|
|
13786
14660
|
function buildRestoredEntries(messages, restoredToolCalls) {
|
|
13787
14661
|
if (!messages || messages.length === 0) return [];
|
|
@@ -13921,6 +14795,11 @@ function createInitialState(options) {
|
|
|
13921
14795
|
hint: void 0
|
|
13922
14796
|
},
|
|
13923
14797
|
pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14798
|
+
mcpPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14799
|
+
toolsPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0, filter: void 0 },
|
|
14800
|
+
brainPanel: { open: false, riskLevel: "medium", log: [], selected: 0, hint: void 0 },
|
|
14801
|
+
helpPanel: { open: false, entries: [], selected: 0, filter: "", hint: void 0 },
|
|
14802
|
+
shadowPanel: { open: false, shadow: { activeId: null, running: false, model: "", intervalMs: 3e4 }, hint: void 0 },
|
|
13924
14803
|
authPanel: AUTH_PANEL_INITIAL,
|
|
13925
14804
|
projectPicker: {
|
|
13926
14805
|
open: false,
|
|
@@ -13932,9 +14811,11 @@ function createInitialState(options) {
|
|
|
13932
14811
|
},
|
|
13933
14812
|
fKeyPicker: { open: false, selected: 0 },
|
|
13934
14813
|
confirmQueue: [],
|
|
14814
|
+
shellCommandWarning: null,
|
|
13935
14815
|
enhance: null,
|
|
13936
14816
|
enhanceEnabled,
|
|
13937
14817
|
enhanceBusy: false,
|
|
14818
|
+
continueConfirm: null,
|
|
13938
14819
|
escConfirm: null,
|
|
13939
14820
|
sendModePicker: null,
|
|
13940
14821
|
contextChipVersion: 0,
|
|
@@ -15029,6 +15910,7 @@ function usePasteHandling({
|
|
|
15029
15910
|
};
|
|
15030
15911
|
}
|
|
15031
15912
|
var ENTER_DOUBLE_TAP_MS = 50;
|
|
15913
|
+
var formatTokens = (tokens) => tokens.toLocaleString("en-US");
|
|
15032
15914
|
function debouncedEnter(host) {
|
|
15033
15915
|
const now = Date.now();
|
|
15034
15916
|
if (now - host.lastEnterAtRef.current < ENTER_DOUBLE_TAP_MS) return true;
|
|
@@ -15187,12 +16069,16 @@ function usePickerKeys(host) {
|
|
|
15187
16069
|
dispatch({ type: "modelPickerHint", text: err });
|
|
15188
16070
|
return;
|
|
15189
16071
|
}
|
|
16072
|
+
const previousMaxContext = host.activeMaxContext;
|
|
16073
|
+
const nextMaxContext = host.getAgentCtxMaxContext();
|
|
15190
16074
|
host.setLiveProvider?.(providerId);
|
|
15191
16075
|
host.setLiveModel?.(modelId);
|
|
15192
|
-
host.setActiveMaxContext?.(
|
|
16076
|
+
host.setActiveMaxContext?.(nextMaxContext);
|
|
16077
|
+
const contextWarning = previousMaxContext && nextMaxContext > 0 && nextMaxContext < previousMaxContext ? `
|
|
16078
|
+
\u26A0 smaller context window: ${formatTokens(previousMaxContext)} \u2192 ${formatTokens(nextMaxContext)} tokens${host.currentContextTokens > 0 ? `; current request \u2248 ${formatTokens(host.currentContextTokens)} tokens (${Math.round(host.currentContextTokens / nextMaxContext * 100)}% of new window)` : ""}` : "";
|
|
15193
16079
|
dispatch({
|
|
15194
16080
|
type: "addEntry",
|
|
15195
|
-
entry: { kind: "info", text: `Switched to ${providerId} / ${modelId}
|
|
16081
|
+
entry: { kind: "info", text: `Switched to ${providerId} / ${modelId}.${contextWarning}` }
|
|
15196
16082
|
});
|
|
15197
16083
|
dispatch({ type: "modelPickerClose" });
|
|
15198
16084
|
};
|
|
@@ -15474,6 +16360,145 @@ function usePickerKeys(host) {
|
|
|
15474
16360
|
}
|
|
15475
16361
|
return true;
|
|
15476
16362
|
}
|
|
16363
|
+
if (state.mcpPicker.open) {
|
|
16364
|
+
if (key.escape) {
|
|
16365
|
+
dispatch({ type: "mcpPickerClose" });
|
|
16366
|
+
return true;
|
|
16367
|
+
}
|
|
16368
|
+
if (key.mouse?.kind === "wheel") {
|
|
16369
|
+
dispatch({ type: "mcpPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16370
|
+
return true;
|
|
16371
|
+
}
|
|
16372
|
+
if (key.upArrow) {
|
|
16373
|
+
dispatch({ type: "mcpPickerMove", delta: -1 });
|
|
16374
|
+
return true;
|
|
16375
|
+
}
|
|
16376
|
+
if (key.downArrow) {
|
|
16377
|
+
dispatch({ type: "mcpPickerMove", delta: 1 });
|
|
16378
|
+
return true;
|
|
16379
|
+
}
|
|
16380
|
+
if (input === "r" || input === "R") {
|
|
16381
|
+
void host.onMcpPickerRestart?.();
|
|
16382
|
+
return true;
|
|
16383
|
+
}
|
|
16384
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16385
|
+
if (debouncedEnter(host)) return true;
|
|
16386
|
+
void host.onMcpPickerToggle?.();
|
|
16387
|
+
return true;
|
|
16388
|
+
}
|
|
16389
|
+
return true;
|
|
16390
|
+
}
|
|
16391
|
+
if (state.toolsPicker.open) {
|
|
16392
|
+
if (key.escape) {
|
|
16393
|
+
if (state.toolsPicker.filter) {
|
|
16394
|
+
dispatch({ type: "toolsPickerFilter", filter: "" });
|
|
16395
|
+
} else {
|
|
16396
|
+
dispatch({ type: "toolsPickerClose" });
|
|
16397
|
+
}
|
|
16398
|
+
return true;
|
|
16399
|
+
}
|
|
16400
|
+
if (key.mouse?.kind === "wheel") {
|
|
16401
|
+
dispatch({ type: "toolsPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16402
|
+
return true;
|
|
16403
|
+
}
|
|
16404
|
+
if (key.upArrow) {
|
|
16405
|
+
dispatch({ type: "toolsPickerMove", delta: -1 });
|
|
16406
|
+
return true;
|
|
16407
|
+
}
|
|
16408
|
+
if (key.downArrow) {
|
|
16409
|
+
dispatch({ type: "toolsPickerMove", delta: 1 });
|
|
16410
|
+
return true;
|
|
16411
|
+
}
|
|
16412
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16413
|
+
if (debouncedEnter(host)) return true;
|
|
16414
|
+
void host.onToolsPickerToggle?.();
|
|
16415
|
+
return true;
|
|
16416
|
+
}
|
|
16417
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16418
|
+
dispatch({ type: "toolsPickerFilter", filter: (state.toolsPicker.filter ?? "") + input });
|
|
16419
|
+
return true;
|
|
16420
|
+
}
|
|
16421
|
+
if (key.backspace) {
|
|
16422
|
+
const cur = state.toolsPicker.filter ?? "";
|
|
16423
|
+
dispatch({ type: "toolsPickerFilter", filter: cur.length > 0 ? cur.slice(0, -1) : "" });
|
|
16424
|
+
return true;
|
|
16425
|
+
}
|
|
16426
|
+
return true;
|
|
16427
|
+
}
|
|
16428
|
+
if (state.helpPanel.open) {
|
|
16429
|
+
if (key.escape) {
|
|
16430
|
+
dispatch({ type: "helpClose" });
|
|
16431
|
+
return true;
|
|
16432
|
+
}
|
|
16433
|
+
if (key.mouse?.kind === "wheel") {
|
|
16434
|
+
dispatch({ type: "helpMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16435
|
+
return true;
|
|
16436
|
+
}
|
|
16437
|
+
if (key.upArrow) {
|
|
16438
|
+
dispatch({ type: "helpMove", delta: -1 });
|
|
16439
|
+
return true;
|
|
16440
|
+
}
|
|
16441
|
+
if (key.downArrow) {
|
|
16442
|
+
dispatch({ type: "helpMove", delta: 1 });
|
|
16443
|
+
return true;
|
|
16444
|
+
}
|
|
16445
|
+
if (key.backspace && state.helpPanel.filter) {
|
|
16446
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter.slice(0, -1) });
|
|
16447
|
+
return true;
|
|
16448
|
+
}
|
|
16449
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16450
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter + input });
|
|
16451
|
+
return true;
|
|
16452
|
+
}
|
|
16453
|
+
if (isEnter) {
|
|
16454
|
+
if (debouncedEnter(host)) return true;
|
|
16455
|
+
host.onHelpPanelEnter?.();
|
|
16456
|
+
return true;
|
|
16457
|
+
}
|
|
16458
|
+
return true;
|
|
16459
|
+
}
|
|
16460
|
+
if (state.brainPanel.open) {
|
|
16461
|
+
if (key.escape) {
|
|
16462
|
+
dispatch({ type: "brainClose" });
|
|
16463
|
+
return true;
|
|
16464
|
+
}
|
|
16465
|
+
if (key.mouse?.kind === "wheel") {
|
|
16466
|
+
dispatch({ type: "brainMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16467
|
+
return true;
|
|
16468
|
+
}
|
|
16469
|
+
if (key.upArrow) {
|
|
16470
|
+
dispatch({ type: "brainMove", delta: -1 });
|
|
16471
|
+
return true;
|
|
16472
|
+
}
|
|
16473
|
+
if (key.downArrow) {
|
|
16474
|
+
dispatch({ type: "brainMove", delta: 1 });
|
|
16475
|
+
return true;
|
|
16476
|
+
}
|
|
16477
|
+
if (key.leftArrow) {
|
|
16478
|
+
host.onBrainRiskChange?.(-1);
|
|
16479
|
+
return true;
|
|
16480
|
+
}
|
|
16481
|
+
if (key.rightArrow) {
|
|
16482
|
+
host.onBrainRiskChange?.(1);
|
|
16483
|
+
return true;
|
|
16484
|
+
}
|
|
16485
|
+
return true;
|
|
16486
|
+
}
|
|
16487
|
+
if (state.shadowPanel.open) {
|
|
16488
|
+
if (key.escape) {
|
|
16489
|
+
dispatch({ type: "shadowClose" });
|
|
16490
|
+
return true;
|
|
16491
|
+
}
|
|
16492
|
+
if (input === "s" || input === "S") {
|
|
16493
|
+
void host.onShadowStart?.();
|
|
16494
|
+
return true;
|
|
16495
|
+
}
|
|
16496
|
+
if (input === "t" || input === "T") {
|
|
16497
|
+
void host.onShadowStop?.();
|
|
16498
|
+
return true;
|
|
16499
|
+
}
|
|
16500
|
+
return true;
|
|
16501
|
+
}
|
|
15477
16502
|
if (state.statuslinePicker.open) {
|
|
15478
16503
|
if (key.escape) {
|
|
15479
16504
|
dispatch({ type: "statuslineClose" });
|
|
@@ -16634,6 +17659,12 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16634
17659
|
case "pluginPickerOpen":
|
|
16635
17660
|
dispatch({ type: "pluginPickerOpen" });
|
|
16636
17661
|
return true;
|
|
17662
|
+
case "mcpPickerOpen":
|
|
17663
|
+
dispatch({ type: "mcpPickerOpen" });
|
|
17664
|
+
return true;
|
|
17665
|
+
case "toolsPickerOpen":
|
|
17666
|
+
dispatch({ type: "toolsPickerOpen" });
|
|
17667
|
+
return true;
|
|
16637
17668
|
case "projectPickerOpen":
|
|
16638
17669
|
void openProjectPicker();
|
|
16639
17670
|
return true;
|
|
@@ -16646,6 +17677,24 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16646
17677
|
return true;
|
|
16647
17678
|
}
|
|
16648
17679
|
return false;
|
|
17680
|
+
case "brainOpen":
|
|
17681
|
+
if (deps.openBrainPanel) {
|
|
17682
|
+
void deps.openBrainPanel();
|
|
17683
|
+
return true;
|
|
17684
|
+
}
|
|
17685
|
+
return false;
|
|
17686
|
+
case "shadowOpen":
|
|
17687
|
+
if (deps.openShadowPanel) {
|
|
17688
|
+
void deps.openShadowPanel();
|
|
17689
|
+
return true;
|
|
17690
|
+
}
|
|
17691
|
+
return false;
|
|
17692
|
+
case "helpOpen":
|
|
17693
|
+
if (deps.openHelpPanel) {
|
|
17694
|
+
void deps.openHelpPanel();
|
|
17695
|
+
return true;
|
|
17696
|
+
}
|
|
17697
|
+
return false;
|
|
16649
17698
|
case "toggleMonitor":
|
|
16650
17699
|
dispatch({ type: "toggleMonitor" });
|
|
16651
17700
|
return true;
|
|
@@ -16761,7 +17810,7 @@ function renderList3() {
|
|
|
16761
17810
|
}
|
|
16762
17811
|
|
|
16763
17812
|
// src/slash-command-search.ts
|
|
16764
|
-
var
|
|
17813
|
+
var CATEGORY_ORDER2 = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
16765
17814
|
function buildSlashCommandMatches(entries, rawQuery) {
|
|
16766
17815
|
const query = normalizeSlashQuery(rawQuery);
|
|
16767
17816
|
const matches = [];
|
|
@@ -16772,7 +17821,7 @@ function buildSlashCommandMatches(entries, rawQuery) {
|
|
|
16772
17821
|
}
|
|
16773
17822
|
return matches.sort((a, b) => {
|
|
16774
17823
|
if (a.rank !== b.rank) return a.rank - b.rank;
|
|
16775
|
-
const catDiff =
|
|
17824
|
+
const catDiff = CATEGORY_ORDER2.indexOf(a.category) - CATEGORY_ORDER2.indexOf(b.category);
|
|
16776
17825
|
if (catDiff !== 0) return catDiff;
|
|
16777
17826
|
return a.name.localeCompare(b.name);
|
|
16778
17827
|
}).map(({ rank: _rank, ...match }) => match);
|
|
@@ -16940,64 +17989,8 @@ function selectedSlashCommandLine(picker) {
|
|
|
16940
17989
|
const picked = picker.matches[picker.selected];
|
|
16941
17990
|
return picked ? `/${picked.name}` : null;
|
|
16942
17991
|
}
|
|
16943
|
-
function contentBlocksText(content) {
|
|
16944
|
-
if (typeof content === "string") return content;
|
|
16945
|
-
if (!Array.isArray(content)) return "";
|
|
16946
|
-
return content.filter(
|
|
16947
|
-
(block) => !!block && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
16948
|
-
).map((block) => block.text).join("");
|
|
16949
|
-
}
|
|
16950
|
-
function rehydrateHistory(messages, startId, toolCalls) {
|
|
16951
|
-
const entries = [];
|
|
16952
|
-
const toolCallsById = /* @__PURE__ */ new Map();
|
|
16953
|
-
if (toolCalls) {
|
|
16954
|
-
for (const tc of toolCalls) {
|
|
16955
|
-
if (!toolCallsById.has(tc.id)) toolCallsById.set(tc.id, tc);
|
|
16956
|
-
}
|
|
16957
|
-
}
|
|
16958
|
-
const consumed = /* @__PURE__ */ new Set();
|
|
16959
|
-
const fallback = [];
|
|
16960
|
-
let nextId = startId;
|
|
16961
|
-
const textOf = (msg) => contentBlocksText(msg.content);
|
|
16962
|
-
const toolEntryFor = (tc) => ({
|
|
16963
|
-
id: nextId++,
|
|
16964
|
-
kind: "tool",
|
|
16965
|
-
name: tc.name,
|
|
16966
|
-
durationMs: tc.durationMs,
|
|
16967
|
-
ok: tc.ok,
|
|
16968
|
-
outputBytes: tc.outputBytes,
|
|
16969
|
-
outputTokens: tc.outputTokens,
|
|
16970
|
-
outputLines: tc.outputLines
|
|
16971
|
-
});
|
|
16972
|
-
for (const msg of messages) {
|
|
16973
|
-
if (msg.role === "system") continue;
|
|
16974
|
-
const text = textOf(msg).trim();
|
|
16975
|
-
if (msg.role === "user") {
|
|
16976
|
-
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
16977
|
-
continue;
|
|
16978
|
-
}
|
|
16979
|
-
if (msg.role === "assistant") {
|
|
16980
|
-
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
16981
|
-
if (Array.isArray(msg.content)) {
|
|
16982
|
-
for (const block of msg.content) {
|
|
16983
|
-
if (block.type !== "tool_use") continue;
|
|
16984
|
-
const tc = toolCallsById.get(block.id);
|
|
16985
|
-
if (!tc) continue;
|
|
16986
|
-
entries.push(toolEntryFor(tc));
|
|
16987
|
-
consumed.add(block.id);
|
|
16988
|
-
}
|
|
16989
|
-
}
|
|
16990
|
-
}
|
|
16991
|
-
}
|
|
16992
|
-
if (toolCalls) {
|
|
16993
|
-
for (const tc of toolCalls) {
|
|
16994
|
-
if (!consumed.has(tc.id)) fallback.push(toolEntryFor(tc));
|
|
16995
|
-
}
|
|
16996
|
-
}
|
|
16997
|
-
entries.push(...fallback);
|
|
16998
|
-
return entries;
|
|
16999
|
-
}
|
|
17000
17992
|
var PASTE_THRESHOLD_CHARS = 200;
|
|
17993
|
+
var CONTINUE_CONFIRM_DELAY_MS = 4e3;
|
|
17001
17994
|
var SB_PADX2 = 2;
|
|
17002
17995
|
function sddLifecycleEntry(op, r) {
|
|
17003
17996
|
if (typeof r === "number") {
|
|
@@ -17086,6 +18079,16 @@ function App({
|
|
|
17086
18079
|
saveSettings,
|
|
17087
18080
|
getPluginItems,
|
|
17088
18081
|
onPluginToggle,
|
|
18082
|
+
getMcpServers,
|
|
18083
|
+
onMcpToggle,
|
|
18084
|
+
onMcpRestart,
|
|
18085
|
+
getToolsItems,
|
|
18086
|
+
onToolToggle,
|
|
18087
|
+
getBrainData,
|
|
18088
|
+
onBrainRiskLevel,
|
|
18089
|
+
getShadowData,
|
|
18090
|
+
onShadowStart,
|
|
18091
|
+
onShadowStop,
|
|
17089
18092
|
authHost,
|
|
17090
18093
|
predictNext,
|
|
17091
18094
|
onSuggestionsParsed,
|
|
@@ -17163,6 +18166,10 @@ function App({
|
|
|
17163
18166
|
});
|
|
17164
18167
|
const hiddenItemsRef = useRef(hiddenItems);
|
|
17165
18168
|
hiddenItemsRef.current = hiddenItems;
|
|
18169
|
+
const [liveToolCount, setLiveToolCount] = useState(toolCount);
|
|
18170
|
+
useEffect(() => {
|
|
18171
|
+
setLiveToolCount(toolCount);
|
|
18172
|
+
}, [toolCount]);
|
|
17166
18173
|
const prevBranchRef = useRef(null);
|
|
17167
18174
|
const [indexState, setIndexState] = useState(() => getIndexState());
|
|
17168
18175
|
useEffect(() => {
|
|
@@ -17262,6 +18269,71 @@ function App({
|
|
|
17262
18269
|
});
|
|
17263
18270
|
const { openPromptPicker } = usePromptPicker({ projectRoot, dispatch });
|
|
17264
18271
|
const { openModePicker } = useModePicker({ dispatch, getModes });
|
|
18272
|
+
const openBrainPanel = React7.useCallback(() => {
|
|
18273
|
+
if (!getBrainData) return;
|
|
18274
|
+
const data = getBrainData();
|
|
18275
|
+
dispatch({ type: "brainOpen", riskLevel: data.riskLevel, log: data.log });
|
|
18276
|
+
}, [getBrainData]);
|
|
18277
|
+
const changeBrainRisk = React7.useCallback(
|
|
18278
|
+
(delta) => {
|
|
18279
|
+
dispatch({ type: "brainRiskChange", delta });
|
|
18280
|
+
},
|
|
18281
|
+
[]
|
|
18282
|
+
);
|
|
18283
|
+
const prevRiskRef = React7.useRef(state.brainPanel.riskLevel);
|
|
18284
|
+
React7.useEffect(() => {
|
|
18285
|
+
if (!state.brainPanel.open) return;
|
|
18286
|
+
const current = state.brainPanel.riskLevel;
|
|
18287
|
+
if (current !== prevRiskRef.current && onBrainRiskLevel) {
|
|
18288
|
+
prevRiskRef.current = current;
|
|
18289
|
+
const err = onBrainRiskLevel(current);
|
|
18290
|
+
if (err) dispatch({ type: "brainHint", text: err });
|
|
18291
|
+
else dispatch({ type: "brainHint", text: `Risk ceiling \u2192 ${current.toUpperCase()}` });
|
|
18292
|
+
}
|
|
18293
|
+
}, [state.brainPanel.riskLevel, state.brainPanel.open, onBrainRiskLevel]);
|
|
18294
|
+
const openShadowPanel = React7.useCallback(() => {
|
|
18295
|
+
if (!getShadowData) return;
|
|
18296
|
+
const data = getShadowData();
|
|
18297
|
+
dispatch({ type: "shadowOpen", shadow: data });
|
|
18298
|
+
}, [getShadowData]);
|
|
18299
|
+
const handleShadowStart = React7.useCallback(async () => {
|
|
18300
|
+
if (!onShadowStart) return;
|
|
18301
|
+
dispatch({ type: "shadowHint", text: "Starting Shadow Agent\u2026" });
|
|
18302
|
+
try {
|
|
18303
|
+
const err = await onShadowStart();
|
|
18304
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18305
|
+
else {
|
|
18306
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18307
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent started." });
|
|
18308
|
+
}
|
|
18309
|
+
} catch (e) {
|
|
18310
|
+
dispatch({ type: "shadowHint", text: `Failed to start: ${toErrorMessage(e)}` });
|
|
18311
|
+
}
|
|
18312
|
+
}, [onShadowStart, getShadowData]);
|
|
18313
|
+
const handleShadowStop = React7.useCallback(async () => {
|
|
18314
|
+
if (!onShadowStop) return;
|
|
18315
|
+
dispatch({ type: "shadowHint", text: "Stopping Shadow Agent\u2026" });
|
|
18316
|
+
try {
|
|
18317
|
+
const err = await onShadowStop();
|
|
18318
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18319
|
+
else {
|
|
18320
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18321
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent stopped." });
|
|
18322
|
+
}
|
|
18323
|
+
} catch (e) {
|
|
18324
|
+
dispatch({ type: "shadowHint", text: `Failed to stop: ${toErrorMessage(e)}` });
|
|
18325
|
+
}
|
|
18326
|
+
}, [onShadowStop, getShadowData]);
|
|
18327
|
+
const openHelpPanel = React7.useCallback(() => {
|
|
18328
|
+
const entries = Array.from(slashRegistry.listWithOwner()).map(({ cmd, owner }) => ({
|
|
18329
|
+
name: owner === "core" ? cmd.name : `${owner}:${cmd.name}`,
|
|
18330
|
+
description: cmd.description,
|
|
18331
|
+
category: cmd.category ?? "App",
|
|
18332
|
+
aliases: cmd.aliases,
|
|
18333
|
+
argsHint: cmd.argsHint
|
|
18334
|
+
}));
|
|
18335
|
+
dispatch({ type: "helpOpen", entries });
|
|
18336
|
+
}, []);
|
|
17265
18337
|
useStatuslineHiddenSync({
|
|
17266
18338
|
pickerOpen: state.statuslinePicker.open,
|
|
17267
18339
|
pickerHidden: state.statuslinePicker.hiddenItems,
|
|
@@ -17284,7 +18356,7 @@ function App({
|
|
|
17284
18356
|
const inputGateRef = useRef(false);
|
|
17285
18357
|
const lastEnterAtRef = useRef(0);
|
|
17286
18358
|
const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
|
|
17287
|
-
const projectName =
|
|
18359
|
+
const projectName = React7.useMemo(() => {
|
|
17288
18360
|
const base = path9.basename(projectRoot);
|
|
17289
18361
|
return base && base !== path9.sep ? base : void 0;
|
|
17290
18362
|
}, [projectRoot]);
|
|
@@ -17318,6 +18390,7 @@ function App({
|
|
|
17318
18390
|
const streamSegmentsRef = useRef([]);
|
|
17319
18391
|
const pendingDeltaRef = useRef("");
|
|
17320
18392
|
const flushTimerRef = useRef(null);
|
|
18393
|
+
const assistantCommittedThisRunRef = useRef(false);
|
|
17321
18394
|
const stateRef = useRef(state);
|
|
17322
18395
|
stateRef.current = state;
|
|
17323
18396
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
@@ -17346,7 +18419,7 @@ function App({
|
|
|
17346
18419
|
[statuslineHiddenForPicker]
|
|
17347
18420
|
);
|
|
17348
18421
|
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;
|
|
18422
|
+
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
18423
|
const mouseTrackingOn = mouseMode || pickerOverlayOpen;
|
|
17351
18424
|
const mouseWrittenRef = useRef(false);
|
|
17352
18425
|
useEffect(() => {
|
|
@@ -17388,7 +18461,7 @@ function App({
|
|
|
17388
18461
|
}
|
|
17389
18462
|
});
|
|
17390
18463
|
const handleKeyRef = useRef(null);
|
|
17391
|
-
const handleRewindTo =
|
|
18464
|
+
const handleRewindTo = React7.useCallback(
|
|
17392
18465
|
async (checkpointIndex) => {
|
|
17393
18466
|
const sessionId = agent.ctx.session.id;
|
|
17394
18467
|
if (!sessionId) return;
|
|
@@ -17410,7 +18483,7 @@ function App({
|
|
|
17410
18483
|
dispatch({ type: "clearInput" });
|
|
17411
18484
|
};
|
|
17412
18485
|
const startedAtRef = useRef(Date.now());
|
|
17413
|
-
const [nowTick, setNowTick] =
|
|
18486
|
+
const [nowTick, setNowTick] = React7.useState(Date.now());
|
|
17414
18487
|
useEffect(() => {
|
|
17415
18488
|
const t = setInterval(() => setNowTick(Date.now()), 1e4);
|
|
17416
18489
|
return () => clearInterval(t);
|
|
@@ -17496,7 +18569,7 @@ function App({
|
|
|
17496
18569
|
agent.ctx.provider,
|
|
17497
18570
|
agent.ctx.todos
|
|
17498
18571
|
]);
|
|
17499
|
-
const [gitInfo, setGitInfo] =
|
|
18572
|
+
const [gitInfo, setGitInfo] = React7.useState(null);
|
|
17500
18573
|
useEffect(() => {
|
|
17501
18574
|
let cancelled = false;
|
|
17502
18575
|
const refresh = () => {
|
|
@@ -17824,8 +18897,8 @@ function App({
|
|
|
17824
18897
|
} catch {
|
|
17825
18898
|
}
|
|
17826
18899
|
}, []);
|
|
17827
|
-
|
|
17828
|
-
const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.designPicker.open || state.resumePicker.open || state.settingsPicker.open || state.enhanceBusy || state.enhance != null || state.coordinator.monitorOpen || state.escConfirm != null || state.sendModePicker != null || state.confirmQueue.length > 0;
|
|
18900
|
+
React7.useLayoutEffect(() => {
|
|
18901
|
+
const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.designPicker.open || state.resumePicker.open || state.settingsPicker.open || state.enhanceBusy || state.enhance != null || state.continueConfirm != null || state.coordinator.monitorOpen || state.escConfirm != null || state.sendModePicker != null || state.confirmQueue.length > 0;
|
|
17829
18902
|
const overlayClosed = prevAnyOverlayOpen.current && !anyOpenNow;
|
|
17830
18903
|
const newEntryCommitted = state.entries.length > prevEntriesCount.current;
|
|
17831
18904
|
const curToolStreamLen = state.toolStream?.text.length ?? 0;
|
|
@@ -17845,6 +18918,7 @@ function App({
|
|
|
17845
18918
|
state.settingsPicker.open,
|
|
17846
18919
|
state.enhanceBusy,
|
|
17847
18920
|
state.enhance,
|
|
18921
|
+
state.continueConfirm,
|
|
17848
18922
|
state.coordinator.monitorOpen,
|
|
17849
18923
|
state.escConfirm,
|
|
17850
18924
|
state.sendModePicker,
|
|
@@ -17977,8 +19051,9 @@ function App({
|
|
|
17977
19051
|
process.stdout.off("resize", handleResize);
|
|
17978
19052
|
};
|
|
17979
19053
|
}, [eraseLiveRegion]);
|
|
17980
|
-
|
|
17981
|
-
if (state.enhanceBusy || state.enhance != null
|
|
19054
|
+
React7.useLayoutEffect(() => {
|
|
19055
|
+
if (state.enhanceBusy || state.enhance != null || state.continueConfirm != null)
|
|
19056
|
+
eraseLiveRegion();
|
|
17982
19057
|
});
|
|
17983
19058
|
useEffect(() => {
|
|
17984
19059
|
const trimmed = state.buffer.trimStart();
|
|
@@ -18128,20 +19203,20 @@ function App({
|
|
|
18128
19203
|
slashRegistry.unregister("agents");
|
|
18129
19204
|
};
|
|
18130
19205
|
}, [slashRegistry]);
|
|
18131
|
-
const openModelPicker =
|
|
19206
|
+
const openModelPicker = React7.useCallback(async () => {
|
|
18132
19207
|
if (!getPickableProviders) return;
|
|
18133
19208
|
const providers = await getPickableProviders();
|
|
18134
19209
|
dispatch({ type: "modelPickerOpen", providers });
|
|
18135
19210
|
}, [getPickableProviders]);
|
|
18136
|
-
const openProjectPicker =
|
|
19211
|
+
const openProjectPicker = React7.useCallback(async () => {
|
|
18137
19212
|
if (!getProjectPickerItems) return;
|
|
18138
19213
|
const items = await getProjectPickerItems();
|
|
18139
19214
|
dispatch({ type: "projectPickerOpen", items });
|
|
18140
19215
|
}, [getProjectPickerItems]);
|
|
18141
|
-
const openFKeyPicker =
|
|
19216
|
+
const openFKeyPicker = React7.useCallback(() => {
|
|
18142
19217
|
dispatch({ type: "fKeyPickerOpen" });
|
|
18143
19218
|
}, [dispatch]);
|
|
18144
|
-
const loadLiveSessions =
|
|
19219
|
+
const loadLiveSessions = React7.useCallback(async () => {
|
|
18145
19220
|
if (!getLiveSessions) {
|
|
18146
19221
|
dispatch({ type: "sessionsPanelSet", sessions: [] });
|
|
18147
19222
|
return;
|
|
@@ -18161,7 +19236,10 @@ function App({
|
|
|
18161
19236
|
openProjectPicker,
|
|
18162
19237
|
openStatuslinePicker,
|
|
18163
19238
|
openAuthPanel: authPanelController.openAuthPanel,
|
|
18164
|
-
openModePicker
|
|
19239
|
+
openModePicker,
|
|
19240
|
+
openBrainPanel,
|
|
19241
|
+
openShadowPanel,
|
|
19242
|
+
openHelpPanel
|
|
18165
19243
|
});
|
|
18166
19244
|
onPanelOpen.current = dispatcher;
|
|
18167
19245
|
return () => {
|
|
@@ -18173,7 +19251,10 @@ function App({
|
|
|
18173
19251
|
openProjectPicker,
|
|
18174
19252
|
openStatuslinePicker,
|
|
18175
19253
|
authPanelController.openAuthPanel,
|
|
18176
|
-
openModePicker
|
|
19254
|
+
openModePicker,
|
|
19255
|
+
openBrainPanel,
|
|
19256
|
+
openShadowPanel,
|
|
19257
|
+
openHelpPanel
|
|
18177
19258
|
]);
|
|
18178
19259
|
useEffect(() => {
|
|
18179
19260
|
if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
|
|
@@ -18182,7 +19263,7 @@ function App({
|
|
|
18182
19263
|
}, 5e3);
|
|
18183
19264
|
return () => clearInterval(t);
|
|
18184
19265
|
}, [state.sessionsPanelOpen, getLiveSessions, loadLiveSessions]);
|
|
18185
|
-
const openSettings =
|
|
19266
|
+
const openSettings = React7.useCallback(() => {
|
|
18186
19267
|
if (!getSettings) return;
|
|
18187
19268
|
const s2 = getSettings();
|
|
18188
19269
|
dispatch({
|
|
@@ -18227,7 +19308,7 @@ function App({
|
|
|
18227
19308
|
animationStyle: s2.animationStyle ?? "rainbow"
|
|
18228
19309
|
});
|
|
18229
19310
|
}, [getSettings]);
|
|
18230
|
-
const refreshPluginPicker =
|
|
19311
|
+
const refreshPluginPicker = React7.useCallback(() => {
|
|
18231
19312
|
if (!getPluginItems) return;
|
|
18232
19313
|
dispatch({ type: "pluginPickerSetItems", items: getPluginItems() });
|
|
18233
19314
|
}, [getPluginItems]);
|
|
@@ -18235,7 +19316,7 @@ function App({
|
|
|
18235
19316
|
if (!state.pluginPicker.open) return;
|
|
18236
19317
|
refreshPluginPicker();
|
|
18237
19318
|
}, [state.pluginPicker.open, refreshPluginPicker]);
|
|
18238
|
-
const toggleSelectedPlugin =
|
|
19319
|
+
const toggleSelectedPlugin = React7.useCallback(async () => {
|
|
18239
19320
|
if (!onPluginToggle) return;
|
|
18240
19321
|
const selected = stateRef.current.pluginPicker.items[stateRef.current.pluginPicker.selected];
|
|
18241
19322
|
if (!selected) return;
|
|
@@ -18259,6 +19340,76 @@ function App({
|
|
|
18259
19340
|
});
|
|
18260
19341
|
}
|
|
18261
19342
|
}, [onPluginToggle]);
|
|
19343
|
+
const refreshMcpPicker = React7.useCallback(() => {
|
|
19344
|
+
if (!getMcpServers) return;
|
|
19345
|
+
dispatch({ type: "mcpPickerSetItems", items: getMcpServers() });
|
|
19346
|
+
}, [getMcpServers]);
|
|
19347
|
+
useEffect(() => {
|
|
19348
|
+
if (!state.mcpPicker.open) return;
|
|
19349
|
+
refreshMcpPicker();
|
|
19350
|
+
}, [state.mcpPicker.open, refreshMcpPicker]);
|
|
19351
|
+
const toggleSelectedMcpServer = React7.useCallback(async () => {
|
|
19352
|
+
if (!onMcpToggle) return;
|
|
19353
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19354
|
+
if (!selected) return;
|
|
19355
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19356
|
+
try {
|
|
19357
|
+
const result = await onMcpToggle(selected.name);
|
|
19358
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19359
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19360
|
+
} catch (err) {
|
|
19361
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19362
|
+
dispatch({
|
|
19363
|
+
type: "mcpPickerHint",
|
|
19364
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19365
|
+
});
|
|
19366
|
+
}
|
|
19367
|
+
}, [onMcpToggle]);
|
|
19368
|
+
const restartSelectedMcpServer = React7.useCallback(async () => {
|
|
19369
|
+
if (!onMcpRestart) return;
|
|
19370
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19371
|
+
if (!selected) return;
|
|
19372
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19373
|
+
try {
|
|
19374
|
+
const result = await onMcpRestart(selected.name);
|
|
19375
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19376
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19377
|
+
} catch (err) {
|
|
19378
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19379
|
+
dispatch({
|
|
19380
|
+
type: "mcpPickerHint",
|
|
19381
|
+
text: `Failed to restart ${selected.name}: ${toErrorMessage(err)}`
|
|
19382
|
+
});
|
|
19383
|
+
}
|
|
19384
|
+
}, [onMcpRestart]);
|
|
19385
|
+
const refreshToolsPicker = React7.useCallback(() => {
|
|
19386
|
+
if (!getToolsItems) return;
|
|
19387
|
+
const items = getToolsItems();
|
|
19388
|
+
dispatch({ type: "toolsPickerSetItems", items });
|
|
19389
|
+
setLiveToolCount(items.filter((item) => item.enabled).length);
|
|
19390
|
+
}, [getToolsItems]);
|
|
19391
|
+
useEffect(() => {
|
|
19392
|
+
if (!state.toolsPicker.open) return;
|
|
19393
|
+
refreshToolsPicker();
|
|
19394
|
+
}, [state.toolsPicker.open, refreshToolsPicker]);
|
|
19395
|
+
const toggleSelectedTool = React7.useCallback(async () => {
|
|
19396
|
+
if (!onToolToggle) return;
|
|
19397
|
+
const selected = stateRef.current.toolsPicker.items[stateRef.current.toolsPicker.selected];
|
|
19398
|
+
if (!selected) return;
|
|
19399
|
+
dispatch({ type: "toolsPickerBusy", busy: true });
|
|
19400
|
+
try {
|
|
19401
|
+
const result = await onToolToggle(selected.name);
|
|
19402
|
+
dispatch({ type: "toolsPickerSetItems", items: result.items });
|
|
19403
|
+
setLiveToolCount(result.items.filter((item) => item.enabled).length);
|
|
19404
|
+
dispatch({ type: "toolsPickerHint", text: result.error ?? result.message });
|
|
19405
|
+
} catch (err) {
|
|
19406
|
+
dispatch({ type: "toolsPickerBusy", busy: false });
|
|
19407
|
+
dispatch({
|
|
19408
|
+
type: "toolsPickerHint",
|
|
19409
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19410
|
+
});
|
|
19411
|
+
}
|
|
19412
|
+
}, [onToolToggle]);
|
|
18262
19413
|
const autoSubmitStreakRef = useRef(0);
|
|
18263
19414
|
const autoSubmitCapWarnedRef = useRef(false);
|
|
18264
19415
|
const [nextStepsRecheck, setNextStepsRecheck] = useState(0);
|
|
@@ -18274,7 +19425,7 @@ function App({
|
|
|
18274
19425
|
nextStepsAutoSubmitSuggestionRef.current = null;
|
|
18275
19426
|
return;
|
|
18276
19427
|
}
|
|
18277
|
-
if (state.enhance != null || state.enhanceBusy) {
|
|
19428
|
+
if (state.enhance != null || state.enhanceBusy || state.continueConfirm != null) {
|
|
18278
19429
|
return;
|
|
18279
19430
|
}
|
|
18280
19431
|
if (nextStepsAutoSubmitTimerRef.current != null) {
|
|
@@ -18355,6 +19506,7 @@ function App({
|
|
|
18355
19506
|
autonomyLive,
|
|
18356
19507
|
state.enhance,
|
|
18357
19508
|
state.enhanceBusy,
|
|
19509
|
+
state.continueConfirm,
|
|
18358
19510
|
nextStepsRecheck,
|
|
18359
19511
|
getSettings,
|
|
18360
19512
|
getSuggestions,
|
|
@@ -18912,11 +20064,14 @@ Available chords:
|
|
|
18912
20064
|
});
|
|
18913
20065
|
});
|
|
18914
20066
|
const offFallback = events.on("provider.fallback", (e) => {
|
|
20067
|
+
const fallbackEvent = e;
|
|
20068
|
+
const contextWarning = fallbackEvent.contextWindowWarning ? `
|
|
20069
|
+
\u26A0 smaller context window: ${fallbackEvent.contextWindowWarning.fromMaxContext.toLocaleString("en-US")} \u2192 ${fallbackEvent.contextWindowWarning.toMaxContext.toLocaleString("en-US")} tokens${fallbackEvent.contextWindowWarning.currentTokens ? `; current request \u2248 ${fallbackEvent.contextWindowWarning.currentTokens.toLocaleString("en-US")} tokens (${Math.round(fallbackEvent.contextWindowWarning.currentTokens / fallbackEvent.contextWindowWarning.toMaxContext * 100)}% of new window)` : ""}` : "";
|
|
18915
20070
|
dispatch({
|
|
18916
20071
|
type: "addEntry",
|
|
18917
20072
|
entry: {
|
|
18918
20073
|
kind: "warn",
|
|
18919
|
-
text: `\u21BB rate-limited (${e.status}) \u2014 switched to ${e.to.providerId}/${e.to.model}`
|
|
20074
|
+
text: `\u21BB rate-limited (${e.status}) \u2014 switched to ${e.to.providerId}/${e.to.model}${contextWarning}`
|
|
18920
20075
|
}
|
|
18921
20076
|
});
|
|
18922
20077
|
});
|
|
@@ -18935,12 +20090,15 @@ Available chords:
|
|
|
18935
20090
|
for (const seg of segments) {
|
|
18936
20091
|
if (seg.text.trim()) {
|
|
18937
20092
|
dispatch({ type: "addEntry", entry: { kind: seg.kind, text: seg.text } });
|
|
20093
|
+
if (seg.kind === "assistant") assistantCommittedThisRunRef.current = true;
|
|
18938
20094
|
}
|
|
18939
20095
|
}
|
|
18940
20096
|
if (segments.length === 0 && text.trim()) {
|
|
18941
20097
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text } });
|
|
20098
|
+
assistantCommittedThisRunRef.current = true;
|
|
18942
20099
|
} else if (segments.length === 0 && fallbackText.trim()) {
|
|
18943
20100
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: fallbackText } });
|
|
20101
|
+
assistantCommittedThisRunRef.current = true;
|
|
18944
20102
|
}
|
|
18945
20103
|
});
|
|
18946
20104
|
const offConfirmNeeded = events.on("tool.confirm_needed", (e) => {
|
|
@@ -19183,7 +20341,9 @@ Available chords:
|
|
|
19183
20341
|
setLiveProvider,
|
|
19184
20342
|
setLiveModel,
|
|
19185
20343
|
setActiveMaxContext,
|
|
19186
|
-
|
|
20344
|
+
getAgentCtxMaxContext: () => agent.ctx.provider.capabilities.maxContext,
|
|
20345
|
+
activeMaxContext,
|
|
20346
|
+
currentContextTokens,
|
|
19187
20347
|
switchAutonomy,
|
|
19188
20348
|
submit: (text) => submitRef.current(text),
|
|
19189
20349
|
onPromptPickerEnter: () => {
|
|
@@ -19350,6 +20510,18 @@ Available chords:
|
|
|
19350
20510
|
}
|
|
19351
20511
|
},
|
|
19352
20512
|
onPluginPickerToggle: toggleSelectedPlugin,
|
|
20513
|
+
onMcpPickerToggle: toggleSelectedMcpServer,
|
|
20514
|
+
onMcpPickerRestart: restartSelectedMcpServer,
|
|
20515
|
+
onToolsPickerToggle: toggleSelectedTool,
|
|
20516
|
+
onHelpPanelEnter: () => {
|
|
20517
|
+
const entry = state.helpPanel.entries[state.helpPanel.selected];
|
|
20518
|
+
if (!entry) return;
|
|
20519
|
+
dispatch({ type: "helpClose" });
|
|
20520
|
+
submitRef.current(`/${entry.name}`);
|
|
20521
|
+
},
|
|
20522
|
+
onBrainRiskChange: changeBrainRisk,
|
|
20523
|
+
onShadowStart: handleShadowStart,
|
|
20524
|
+
onShadowStop: handleShadowStop,
|
|
19353
20525
|
onAuthEnter: authPanelController.onAuthEnter,
|
|
19354
20526
|
onAuthBack: authPanelController.onAuthBack,
|
|
19355
20527
|
onAuthShortcut: authPanelController.onAuthShortcut,
|
|
@@ -19505,11 +20677,13 @@ Available chords:
|
|
|
19505
20677
|
const handleKey = async (input, key) => {
|
|
19506
20678
|
if (state.status === "aborting" && !state.steeringPending && state.interrupts === 0) return;
|
|
19507
20679
|
if (state.confirmQueue.length > 0) return;
|
|
20680
|
+
if (state.shellCommandWarning) return;
|
|
19508
20681
|
if (state.enhanceBusy) {
|
|
19509
20682
|
if (key.escape) enhanceAbortRef.current?.abort();
|
|
19510
20683
|
return;
|
|
19511
20684
|
}
|
|
19512
20685
|
if (state.enhance) return;
|
|
20686
|
+
if (state.continueConfirm) return;
|
|
19513
20687
|
if (state.escConfirm) return;
|
|
19514
20688
|
if (state.sendModePicker) return;
|
|
19515
20689
|
if (state.helpOpen) {
|
|
@@ -20320,9 +21494,7 @@ Available chords:
|
|
|
20320
21494
|
}
|
|
20321
21495
|
});
|
|
20322
21496
|
}
|
|
20323
|
-
|
|
20324
|
-
(entry) => entry.kind === "assistant"
|
|
20325
|
-
).length;
|
|
21497
|
+
assistantCommittedThisRunRef.current = false;
|
|
20326
21498
|
const result = await agent.run(routed.blocks, { signal: ctrl.signal });
|
|
20327
21499
|
const lingering = streamingTextRef.current;
|
|
20328
21500
|
const lingeringSegments = streamSegmentsRef.current;
|
|
@@ -20342,7 +21514,13 @@ Available chords:
|
|
|
20342
21514
|
}
|
|
20343
21515
|
} else if (lingering.trim()) {
|
|
20344
21516
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
|
|
20345
|
-
} else if (result.status === "done" && result.finalText?.trim() &&
|
|
21517
|
+
} else if (result.status === "done" && result.finalText?.trim() && // Only recover finalText when no assistant entry was committed by the
|
|
21518
|
+
// per-iteration `provider.response` flush during this run. Checked via
|
|
21519
|
+
// a synchronous ref, NOT `stateRef` — the flush's `addEntry` dispatch
|
|
21520
|
+
// isn't reflected in `stateRef` yet when we resume here, so a
|
|
21521
|
+
// state-based count would read stale and re-commit the final reply,
|
|
21522
|
+
// rendering it twice.
|
|
21523
|
+
!assistantCommittedThisRunRef.current) {
|
|
20346
21524
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
|
|
20347
21525
|
}
|
|
20348
21526
|
if (result.status === "aborted") {
|
|
@@ -20545,6 +21723,33 @@ Available chords:
|
|
|
20545
21723
|
await pasteClipboardImage();
|
|
20546
21724
|
return;
|
|
20547
21725
|
}
|
|
21726
|
+
if (trimmed.startsWith("!")) {
|
|
21727
|
+
const command = trimmed.slice(1).trim();
|
|
21728
|
+
if (!command) {
|
|
21729
|
+
dispatch({
|
|
21730
|
+
type: "addEntry",
|
|
21731
|
+
entry: { kind: "info", text: "Usage: !<shell command>" }
|
|
21732
|
+
});
|
|
21733
|
+
return;
|
|
21734
|
+
}
|
|
21735
|
+
const settings = getSettings?.();
|
|
21736
|
+
if (settings?.shellBangWarningDontShowAgain !== true) {
|
|
21737
|
+
const decision = await new Promise((resolve) => {
|
|
21738
|
+
dispatch({ type: "shellCommandWarningOpen", info: { command, resolve } });
|
|
21739
|
+
});
|
|
21740
|
+
dispatch({ type: "shellCommandWarningClose" });
|
|
21741
|
+
if (decision === "no") return;
|
|
21742
|
+
if (decision === "dont-show-again") {
|
|
21743
|
+
if (settings && saveSettings) {
|
|
21744
|
+
const err = await saveSettings({ ...settings, shellBangWarningDontShowAgain: true });
|
|
21745
|
+
if (err) {
|
|
21746
|
+
dispatch({ type: "addEntry", entry: { kind: "warn", text: err } });
|
|
21747
|
+
}
|
|
21748
|
+
}
|
|
21749
|
+
}
|
|
21750
|
+
}
|
|
21751
|
+
return submit(`/dev ${command}`);
|
|
21752
|
+
}
|
|
20548
21753
|
if (trimmed === "/prompt" || trimmed === "/prompts-browse") {
|
|
20549
21754
|
pushSubmittedHistory();
|
|
20550
21755
|
clearDraft();
|
|
@@ -20627,6 +21832,9 @@ ${content}
|
|
|
20627
21832
|
const currentMode = getModeLabel();
|
|
20628
21833
|
if (currentMode !== liveModeLabel) setLiveModeLabel(currentMode);
|
|
20629
21834
|
}
|
|
21835
|
+
if (getToolsItems) {
|
|
21836
|
+
setLiveToolCount(getToolsItems().filter((item) => item.enabled).length);
|
|
21837
|
+
}
|
|
20630
21838
|
if (res?.exit) {
|
|
20631
21839
|
exit();
|
|
20632
21840
|
onExit(0);
|
|
@@ -20664,6 +21872,10 @@ ${content}
|
|
|
20664
21872
|
const builder = builderRef.current;
|
|
20665
21873
|
if (!builder) return;
|
|
20666
21874
|
const steering = state.steeringPending;
|
|
21875
|
+
const continueResolved = !steering && state.status === "idle" && detectContinueIntent(trimmed) ? resolveContinuation({
|
|
21876
|
+
todos: agent.ctx.todos,
|
|
21877
|
+
suggestions: getSuggestions?.() ?? []
|
|
21878
|
+
}) : null;
|
|
20667
21879
|
let effectiveText = trimmed;
|
|
20668
21880
|
const chips = [];
|
|
20669
21881
|
let cleanText = trimmed;
|
|
@@ -20679,7 +21891,7 @@ ${content}
|
|
|
20679
21891
|
chips.length = 0;
|
|
20680
21892
|
}
|
|
20681
21893
|
}
|
|
20682
|
-
if (enhanceEnabledRef.current && state.status === "idle" && !steering && shouldEnhance(cleanText)) {
|
|
21894
|
+
if (enhanceEnabledRef.current && state.status === "idle" && !steering && !continueResolved && shouldEnhance(cleanText)) {
|
|
20683
21895
|
dispatch({ type: "enhanceBusy", on: true });
|
|
20684
21896
|
const ac = new AbortController();
|
|
20685
21897
|
enhanceAbortRef.current = ac;
|
|
@@ -20742,6 +21954,31 @@ ${content}
|
|
|
20742
21954
|
}
|
|
20743
21955
|
}
|
|
20744
21956
|
}
|
|
21957
|
+
if (continueResolved) {
|
|
21958
|
+
const decision = await new Promise((resolve) => {
|
|
21959
|
+
dispatch({
|
|
21960
|
+
type: "continueConfirmOpen",
|
|
21961
|
+
info: {
|
|
21962
|
+
label: continueResolved.label,
|
|
21963
|
+
instruction: continueResolved.text,
|
|
21964
|
+
source: continueResolved.source,
|
|
21965
|
+
grounded: continueResolved.source !== "open",
|
|
21966
|
+
resolve
|
|
21967
|
+
}
|
|
21968
|
+
});
|
|
21969
|
+
});
|
|
21970
|
+
dispatch({ type: "continueConfirmClose" });
|
|
21971
|
+
if (decision === "cancel") {
|
|
21972
|
+
clearDraft();
|
|
21973
|
+
return;
|
|
21974
|
+
}
|
|
21975
|
+
if (decision === "edit") {
|
|
21976
|
+
const seed = continueResolved.source === "open" ? "" : continueResolved.text;
|
|
21977
|
+
setDraft(seed, seed.length);
|
|
21978
|
+
return;
|
|
21979
|
+
}
|
|
21980
|
+
effectiveText = continueResolved.text;
|
|
21981
|
+
}
|
|
20745
21982
|
const sddContext = await getSDDContext?.();
|
|
20746
21983
|
if (sddContext && trimmed) {
|
|
20747
21984
|
builder.appendText(`[SDD SESSION ACTIVE]
|
|
@@ -20756,7 +21993,7 @@ User message:
|
|
|
20756
21993
|
builder.appendText(toAppend);
|
|
20757
21994
|
}
|
|
20758
21995
|
if (steering) dispatch({ type: "steerConsume" });
|
|
20759
|
-
const displayText = steering ? `\u21AF ${effectiveText}` : effectiveText;
|
|
21996
|
+
const displayText = continueResolved ? continueResolved.label : steering ? `\u21AF ${effectiveText}` : effectiveText;
|
|
20760
21997
|
const pasteParts = [];
|
|
20761
21998
|
for (const m of trimmed.matchAll(new RegExp(INLINE_TOKEN_SRC, "g"))) {
|
|
20762
21999
|
const token = m[0];
|
|
@@ -20887,7 +22124,7 @@ ${content}
|
|
|
20887
22124
|
stdout?.columns ?? 80
|
|
20888
22125
|
);
|
|
20889
22126
|
const inputHeight = Math.max(1, inputCellRows.length);
|
|
20890
|
-
const hideInput = enhanceActive || state.helpOpen || state.processListOpen || state.authPanel.open;
|
|
22127
|
+
const hideInput = enhanceActive || state.continueConfirm != null || state.helpOpen || state.processListOpen || state.authPanel.open;
|
|
20891
22128
|
const lowerFunctionPanelOpen = state.monitorOpen || state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.planPanelOpen || state.kanbanPanelOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen;
|
|
20892
22129
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
|
|
20893
22130
|
mouseMode ? /* @__PURE__ */ jsx(
|
|
@@ -21074,6 +22311,50 @@ ${content}
|
|
|
21074
22311
|
hint: state.pluginPicker.hint
|
|
21075
22312
|
}
|
|
21076
22313
|
) : null,
|
|
22314
|
+
state.mcpPicker.open ? /* @__PURE__ */ jsx(
|
|
22315
|
+
McpPicker,
|
|
22316
|
+
{
|
|
22317
|
+
items: state.mcpPicker.items,
|
|
22318
|
+
selected: state.mcpPicker.selected,
|
|
22319
|
+
busy: state.mcpPicker.busy,
|
|
22320
|
+
hint: state.mcpPicker.hint
|
|
22321
|
+
}
|
|
22322
|
+
) : null,
|
|
22323
|
+
state.toolsPicker.open ? /* @__PURE__ */ jsx(
|
|
22324
|
+
ToolsPicker,
|
|
22325
|
+
{
|
|
22326
|
+
items: state.toolsPicker.items,
|
|
22327
|
+
selected: state.toolsPicker.selected,
|
|
22328
|
+
busy: state.toolsPicker.busy,
|
|
22329
|
+
hint: state.toolsPicker.hint,
|
|
22330
|
+
filter: state.toolsPicker.filter
|
|
22331
|
+
}
|
|
22332
|
+
) : null,
|
|
22333
|
+
state.brainPanel.open ? /* @__PURE__ */ jsx(
|
|
22334
|
+
BrainPanel,
|
|
22335
|
+
{
|
|
22336
|
+
riskLevel: state.brainPanel.riskLevel,
|
|
22337
|
+
log: state.brainPanel.log,
|
|
22338
|
+
selected: state.brainPanel.selected,
|
|
22339
|
+
hint: state.brainPanel.hint
|
|
22340
|
+
}
|
|
22341
|
+
) : null,
|
|
22342
|
+
state.helpPanel.open ? /* @__PURE__ */ jsx(
|
|
22343
|
+
HelpPanel,
|
|
22344
|
+
{
|
|
22345
|
+
entries: state.helpPanel.entries,
|
|
22346
|
+
filter: state.helpPanel.filter,
|
|
22347
|
+
selected: state.helpPanel.selected,
|
|
22348
|
+
hint: state.helpPanel.hint
|
|
22349
|
+
}
|
|
22350
|
+
) : null,
|
|
22351
|
+
state.shadowPanel.open ? /* @__PURE__ */ jsx(
|
|
22352
|
+
ShadowPanel,
|
|
22353
|
+
{
|
|
22354
|
+
shadow: state.shadowPanel.shadow,
|
|
22355
|
+
hint: state.shadowPanel.hint
|
|
22356
|
+
}
|
|
22357
|
+
) : null,
|
|
21077
22358
|
state.authPanel.open ? /* @__PURE__ */ jsx(AuthPanel, { panel: state.authPanel }) : null,
|
|
21078
22359
|
state.projectPicker.open ? /* @__PURE__ */ jsx(
|
|
21079
22360
|
ProjectPicker,
|
|
@@ -21136,6 +22417,17 @@ ${content}
|
|
|
21136
22417
|
}
|
|
21137
22418
|
}
|
|
21138
22419
|
) }) : null,
|
|
22420
|
+
state.shellCommandWarning ? (() => {
|
|
22421
|
+
const info = state.shellCommandWarning;
|
|
22422
|
+
let resolved = false;
|
|
22423
|
+
const onDecision = (decision) => {
|
|
22424
|
+
if (resolved) return;
|
|
22425
|
+
resolved = true;
|
|
22426
|
+
info.resolve(decision);
|
|
22427
|
+
dispatch({ type: "shellCommandWarningClose" });
|
|
22428
|
+
};
|
|
22429
|
+
return /* @__PURE__ */ jsx(ShellCommandWarning, { command: info.command, onDecision });
|
|
22430
|
+
})() : null,
|
|
21139
22431
|
state.confirmQueue.length > 0 && (() => {
|
|
21140
22432
|
const head = expectDefined$1(state.confirmQueue[0]);
|
|
21141
22433
|
let resolved = false;
|
|
@@ -21257,6 +22549,26 @@ ${content}
|
|
|
21257
22549
|
}
|
|
21258
22550
|
);
|
|
21259
22551
|
})() : null,
|
|
22552
|
+
state.continueConfirm ? (() => {
|
|
22553
|
+
const info = state.continueConfirm;
|
|
22554
|
+
let resolved = false;
|
|
22555
|
+
const onDecision = (decision) => {
|
|
22556
|
+
if (resolved) return;
|
|
22557
|
+
resolved = true;
|
|
22558
|
+
info.resolve(decision);
|
|
22559
|
+
};
|
|
22560
|
+
return /* @__PURE__ */ jsx(
|
|
22561
|
+
ContinueConfirmPanel,
|
|
22562
|
+
{
|
|
22563
|
+
label: info.label,
|
|
22564
|
+
instruction: info.instruction,
|
|
22565
|
+
source: info.source,
|
|
22566
|
+
grounded: info.grounded,
|
|
22567
|
+
delayMs: CONTINUE_CONFIRM_DELAY_MS,
|
|
22568
|
+
onDecision
|
|
22569
|
+
}
|
|
22570
|
+
);
|
|
22571
|
+
})() : null,
|
|
21260
22572
|
/* @__PURE__ */ jsx(Box, { ref: statusBarWrapRef, flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsx(
|
|
21261
22573
|
StatusBar,
|
|
21262
22574
|
{
|
|
@@ -21307,7 +22619,7 @@ ${content}
|
|
|
21307
22619
|
sessionCount,
|
|
21308
22620
|
mailbox: mailboxStatus,
|
|
21309
22621
|
tokenSavingMode: liveSettings?.featureTokenSaving ?? tokenSavingMode,
|
|
21310
|
-
toolCount,
|
|
22622
|
+
toolCount: liveToolCount,
|
|
21311
22623
|
sideEffectCount: agent.ctx.sideEffects?.length ?? 0
|
|
21312
22624
|
}
|
|
21313
22625
|
) }),
|
|
@@ -21793,7 +23105,7 @@ async function runTui(opts) {
|
|
|
21793
23105
|
};
|
|
21794
23106
|
try {
|
|
21795
23107
|
instance = render(
|
|
21796
|
-
|
|
23108
|
+
React7.createElement(App, {
|
|
21797
23109
|
agent: opts.agent,
|
|
21798
23110
|
slashRegistry: opts.slashRegistry,
|
|
21799
23111
|
attachments: opts.attachments,
|
|
@@ -21848,6 +23160,16 @@ async function runTui(opts) {
|
|
|
21848
23160
|
saveSettings: opts.saveSettings,
|
|
21849
23161
|
getPluginItems: opts.getPluginItems,
|
|
21850
23162
|
onPluginToggle: opts.onPluginToggle,
|
|
23163
|
+
getMcpServers: opts.getMcpServers,
|
|
23164
|
+
onMcpToggle: opts.onMcpToggle,
|
|
23165
|
+
onMcpRestart: opts.onMcpRestart,
|
|
23166
|
+
getToolsItems: opts.getToolsItems,
|
|
23167
|
+
onToolToggle: opts.onToolToggle,
|
|
23168
|
+
getBrainData: opts.getBrainData,
|
|
23169
|
+
onBrainRiskLevel: opts.onBrainRiskLevel,
|
|
23170
|
+
getShadowData: opts.getShadowData,
|
|
23171
|
+
onShadowStart: opts.onShadowStart,
|
|
23172
|
+
onShadowStop: opts.onShadowStop,
|
|
21851
23173
|
authHost: opts.authHost,
|
|
21852
23174
|
predictNext: opts.predictNext,
|
|
21853
23175
|
onSuggestionsParsed: opts.onSuggestionsParsed,
|