@wrongstack/tui 0.282.0 → 0.282.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +80 -18
- package/dist/index.js +1898 -728
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal,
|
|
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';
|
|
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
|
-
import * as
|
|
5
|
+
import * as path9 from 'path';
|
|
6
6
|
import React5, { 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
|
-
import { createRequire } from 'module';
|
|
9
8
|
import { expectDefined, toErrorMessage, resolveWstackPaths as resolveWstackPaths$1, sessionScopedPath } from '@wrongstack/core/utils';
|
|
10
9
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
11
10
|
import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
|
|
@@ -14,6 +13,7 @@ import { getToolIcon, TOOL_ICON_CONFIG } from '@wrongstack/tools/tool-icons';
|
|
|
14
13
|
import { spawn } from 'child_process';
|
|
15
14
|
import * as v8 from 'v8';
|
|
16
15
|
import { readClipboardText, readClipboardImage } from '@wrongstack/runtime/clipboard';
|
|
16
|
+
import { createRequire } from 'module';
|
|
17
17
|
|
|
18
18
|
// src/run-tui.ts
|
|
19
19
|
|
|
@@ -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,
|
|
@@ -4156,6 +4336,36 @@ function StatusBar({
|
|
|
4156
4336
|
return () => clearInterval(t);
|
|
4157
4337
|
}, [state]);
|
|
4158
4338
|
const spinner = expectDefined$1(SPINNER_FRAMES[spinnerIdx]);
|
|
4339
|
+
const TODOS_CLEAR_DELAY_MS = 3e3;
|
|
4340
|
+
const [todosCleared, setTodosCleared] = useState(false);
|
|
4341
|
+
const todosClearTimerRef = useRef(null);
|
|
4342
|
+
useEffect(() => {
|
|
4343
|
+
const hasActive = todos && (todos.pending > 0 || todos.inProgress > 0);
|
|
4344
|
+
if (hasActive) {
|
|
4345
|
+
if (todosClearTimerRef.current) {
|
|
4346
|
+
clearTimeout(todosClearTimerRef.current);
|
|
4347
|
+
todosClearTimerRef.current = null;
|
|
4348
|
+
}
|
|
4349
|
+
setTodosCleared(false);
|
|
4350
|
+
return;
|
|
4351
|
+
}
|
|
4352
|
+
if (todos && todos.completed > 0) {
|
|
4353
|
+
if (!todosClearTimerRef.current) {
|
|
4354
|
+
todosClearTimerRef.current = setTimeout(() => {
|
|
4355
|
+
setTodosCleared(true);
|
|
4356
|
+
todosClearTimerRef.current = null;
|
|
4357
|
+
}, TODOS_CLEAR_DELAY_MS);
|
|
4358
|
+
}
|
|
4359
|
+
return () => {
|
|
4360
|
+
if (todosClearTimerRef.current) {
|
|
4361
|
+
clearTimeout(todosClearTimerRef.current);
|
|
4362
|
+
todosClearTimerRef.current = null;
|
|
4363
|
+
}
|
|
4364
|
+
};
|
|
4365
|
+
}
|
|
4366
|
+
setTodosCleared(true);
|
|
4367
|
+
return;
|
|
4368
|
+
}, [todos]);
|
|
4159
4369
|
const animationStyle = thinkingAnimationStyle ?? "rainbow";
|
|
4160
4370
|
const [cycleTick, setCycleTick] = useState(0);
|
|
4161
4371
|
useEffect(() => {
|
|
@@ -4186,7 +4396,7 @@ function StatusBar({
|
|
|
4186
4396
|
const hasNextStepsAutoSubmit = nextStepsAutoSubmitCountdown != null && nextStepsAutoSubmitCountdown > 0;
|
|
4187
4397
|
const nextStepsColor = nextStepsAutoSubmitCountdown != null ? countdownColor(nextStepsAutoSubmitCountdown, 20, 10) : "green";
|
|
4188
4398
|
const hasTaskActivity = tasks && (tasks.pending > 0 || tasks.inProgress > 0 || tasks.completed > 0 || tasks.blocked > 0 || tasks.failed > 0);
|
|
4189
|
-
const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && showChip("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && showChip("plan") || hasTaskActivity && showChip("tasks") || fleetHasActivity && showChip("fleet") || showBrain || showDebugStream || showEnhance || hasNextStepsAutoSubmit && showChip("next_steps");
|
|
4399
|
+
const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0 && !todosCleared) && showChip("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && showChip("plan") || hasTaskActivity && showChip("tasks") || fleetHasActivity && showChip("fleet") || showBrain || showDebugStream || showEnhance || hasNextStepsAutoSubmit && showChip("next_steps");
|
|
4190
4400
|
const minimalWorkParts = [
|
|
4191
4401
|
queueCount > 0 && showChip("queue") ? `q${queueCount}` : "",
|
|
4192
4402
|
todos && showChip("todos") && todos.inProgress + todos.pending > 0 ? `todo ${todos.inProgress}/${todos.pending}` : "",
|
|
@@ -4529,7 +4739,7 @@ function StatusBar({
|
|
|
4529
4739
|
) }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
|
|
4530
4740
|
hasThirdLine ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: renderChipLine(
|
|
4531
4741
|
[
|
|
4532
|
-
todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && showChip("todos") ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
4742
|
+
todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0 && !todosCleared) && showChip("todos") ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
4533
4743
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
|
|
4534
4744
|
todos.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
4535
4745
|
"\u231B",
|
|
@@ -5008,7 +5218,7 @@ function FleetMonitor({
|
|
|
5008
5218
|
nowTick,
|
|
5009
5219
|
collabSession
|
|
5010
5220
|
}) {
|
|
5011
|
-
const
|
|
5221
|
+
const TERMINAL_TTL_MS = 5 * 6e4;
|
|
5012
5222
|
const all = Object.values(entries);
|
|
5013
5223
|
const running = all.filter((e) => e.status === "running");
|
|
5014
5224
|
const idle = all.filter((e) => e.status === "idle").length;
|
|
@@ -5016,7 +5226,7 @@ function FleetMonitor({
|
|
|
5016
5226
|
const failed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
|
|
5017
5227
|
const recent = all.filter((e) => {
|
|
5018
5228
|
if (e.status === "running" || e.status === "idle") return true;
|
|
5019
|
-
return nowTick - e.lastEventAt <
|
|
5229
|
+
return nowTick - e.lastEventAt < TERMINAL_TTL_MS;
|
|
5020
5230
|
});
|
|
5021
5231
|
const concurrencyRatio = maxConcurrent > 0 ? running.length / maxConcurrent : 0;
|
|
5022
5232
|
const ordered = [...recent].sort((a, b) => {
|
|
@@ -5214,15 +5424,12 @@ var STATUS2 = {
|
|
|
5214
5424
|
};
|
|
5215
5425
|
var IDLE_HIDE_MS = 6e4;
|
|
5216
5426
|
var EMPTY_AGENTS_CLOSE_DELAY_MS = 7500;
|
|
5217
|
-
function isTerminalAgentStatus(status) {
|
|
5218
|
-
return status === "success" || status === "failed" || status === "timeout" || status === "stopped";
|
|
5219
|
-
}
|
|
5220
5427
|
function isLeaderEntry(entry) {
|
|
5221
5428
|
return entry.id === "leader" || entry.name === "LEADER";
|
|
5222
5429
|
}
|
|
5223
5430
|
function selectLiveAgents(all, _now, _idleHideMs = IDLE_HIDE_MS) {
|
|
5224
5431
|
const leader = all.find(isLeaderEntry);
|
|
5225
|
-
const activeSubagents = all.filter((entry) => !isLeaderEntry(entry) &&
|
|
5432
|
+
const activeSubagents = all.filter((entry) => !isLeaderEntry(entry) && entry.status === "running");
|
|
5226
5433
|
const showLeader = leader !== void 0 && (leader.status !== "idle" || activeSubagents.length > 0);
|
|
5227
5434
|
return all.filter((entry) => isLeaderEntry(entry) ? showLeader : activeSubagents.some((active) => active.id === entry.id));
|
|
5228
5435
|
}
|
|
@@ -5551,9 +5758,6 @@ function AgentsMonitor({
|
|
|
5551
5758
|
const running = live.filter((e) => e.status === "running").length;
|
|
5552
5759
|
const totalDone = all.filter((e) => e.status === "success").length;
|
|
5553
5760
|
const totalFailed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
|
|
5554
|
-
const staleIdle = all.filter(
|
|
5555
|
-
(e) => e.status === "idle" && nowTick - e.lastEventAt >= IDLE_HIDE_MS
|
|
5556
|
-
).length;
|
|
5557
5761
|
const hotAgent = selectHotAgent(live);
|
|
5558
5762
|
const pressure = live.length > 0 ? live.reduce((max, e) => Math.max(max, e.ctxPct ?? 0), 0) : 0;
|
|
5559
5763
|
const toolCalls = live.reduce((sum, e) => sum + e.toolCalls, 0);
|
|
@@ -5645,12 +5849,7 @@ function AgentsMonitor({
|
|
|
5645
5849
|
" \xB7 fleet $",
|
|
5646
5850
|
totalCost.toFixed(4),
|
|
5647
5851
|
")"
|
|
5648
|
-
] })
|
|
5649
|
-
staleIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
5650
|
-
"\xB7 ",
|
|
5651
|
-
staleIdle,
|
|
5652
|
-
" idle stale"
|
|
5653
|
-
] }) : null
|
|
5852
|
+
] })
|
|
5654
5853
|
] }),
|
|
5655
5854
|
live.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
|
|
5656
5855
|
live.map((e) => e.id === selected?.id ? /* @__PURE__ */ jsx(AgentDetail, { entry: e, now: nowTick }, e.id) : /* @__PURE__ */ jsx(AgentRow, { entry: e, now: nowTick, selected: false }, e.id))
|
|
@@ -6664,8 +6863,8 @@ function detectLang(fenceInfo) {
|
|
|
6664
6863
|
const tag = fenceInfo.trim().toLowerCase().split(/\s+/)[0] ?? "";
|
|
6665
6864
|
return LANG_ALIASES[tag] ?? "plain";
|
|
6666
6865
|
}
|
|
6667
|
-
function langFromPath(
|
|
6668
|
-
const m = /\.([A-Za-z0-9]+)$/.exec(
|
|
6866
|
+
function langFromPath(path10) {
|
|
6867
|
+
const m = /\.([A-Za-z0-9]+)$/.exec(path10.trim());
|
|
6669
6868
|
const ext = m?.[1]?.toLowerCase() ?? "";
|
|
6670
6869
|
return LANG_ALIASES[ext] ?? "plain";
|
|
6671
6870
|
}
|
|
@@ -7459,19 +7658,19 @@ function visualEdit(toolName, text, ok) {
|
|
|
7459
7658
|
const parsed = tryParseJson(text);
|
|
7460
7659
|
if (parsed && typeof parsed === "object") {
|
|
7461
7660
|
const obj = parsed;
|
|
7462
|
-
const
|
|
7661
|
+
const path10 = typeof obj["path"] === "string" ? obj["path"] : void 0;
|
|
7463
7662
|
const replacements = typeof obj["replacements"] === "number" ? obj["replacements"] : void 0;
|
|
7464
7663
|
const bytes = typeof obj["bytes"] === "number" ? obj["bytes"] : void 0;
|
|
7465
7664
|
const created = obj["created"] === true;
|
|
7466
7665
|
const files = Array.isArray(obj["files"]) ? obj["files"] : void 0;
|
|
7467
7666
|
const results = Array.isArray(obj["results"]) ? obj["results"] : void 0;
|
|
7468
|
-
if (toolName === "edit" &&
|
|
7667
|
+
if (toolName === "edit" && path10 !== void 0) {
|
|
7469
7668
|
const repText = replacements !== void 0 ? `${replacements} replacement${replacements === 1 ? "" : "s"}` : void 0;
|
|
7470
|
-
rows.push({ kind: "ok", text: "", marker: "edit ", path:
|
|
7669
|
+
rows.push({ kind: "ok", text: "", marker: "edit ", path: path10 });
|
|
7471
7670
|
if (repText) rows.push({ kind: "meta", text: repText });
|
|
7472
|
-
} else if (toolName === "write" &&
|
|
7671
|
+
} else if (toolName === "write" && path10 !== void 0) {
|
|
7473
7672
|
const sizeText = bytes !== void 0 ? `${bytes} bytes` : created ? "new file" : "updated";
|
|
7474
|
-
rows.push({ kind: "ok", text: "", marker: "write ", path:
|
|
7673
|
+
rows.push({ kind: "ok", text: "", marker: "write ", path: path10 });
|
|
7475
7674
|
rows.push({ kind: "meta", text: sizeText });
|
|
7476
7675
|
} else if ((toolName === "diff" || toolName === "patch") && files && files.length > 0) {
|
|
7477
7676
|
rows.push({
|
|
@@ -7494,8 +7693,8 @@ function visualEdit(toolName, text, ok) {
|
|
|
7494
7693
|
marker: "replace ",
|
|
7495
7694
|
text: `${results.length} replacement${results.length === 1 ? "" : "s"} across ${fileCount} file${fileCount === 1 ? "" : "s"}`
|
|
7496
7695
|
});
|
|
7497
|
-
} else if (
|
|
7498
|
-
rows.push({ kind: "ok", text: "", marker: `${toolName} `, path:
|
|
7696
|
+
} else if (path10 !== void 0) {
|
|
7697
|
+
rows.push({ kind: "ok", text: "", marker: `${toolName} `, path: path10 });
|
|
7499
7698
|
} else {
|
|
7500
7699
|
return void 0;
|
|
7501
7700
|
}
|
|
@@ -7589,12 +7788,12 @@ function parseMatchHit(hit) {
|
|
|
7589
7788
|
}
|
|
7590
7789
|
if (hit && typeof hit === "object") {
|
|
7591
7790
|
const o = hit;
|
|
7592
|
-
const
|
|
7791
|
+
const path10 = stringOf(o["file"]) ?? stringOf(o["path"]) ?? stringOf(o["url"]);
|
|
7593
7792
|
const line = numOf(o["line"]) ?? numOf(o["lineNumber"]);
|
|
7594
7793
|
const title = stringOf(o["title"]);
|
|
7595
7794
|
const snippet2 = stringOf(o["snippet"]);
|
|
7596
7795
|
const text = stringOf(o["text"]) ?? stringOf(o["match"]) ?? stringOf(o["preview"]) ?? [title, snippet2].filter(Boolean).join(" \u2014 ");
|
|
7597
|
-
return { path:
|
|
7796
|
+
return { path: path10, line: line === void 0 ? void 0 : String(line), text };
|
|
7598
7797
|
}
|
|
7599
7798
|
return void 0;
|
|
7600
7799
|
}
|
|
@@ -8402,13 +8601,13 @@ function formatMultiDiffSummary(summary, threshold = MULTI_DIFF_SUMMARY_THRESHOL
|
|
|
8402
8601
|
return parts.join(" \xB7 ");
|
|
8403
8602
|
}
|
|
8404
8603
|
function DiffFileBlock({
|
|
8405
|
-
path:
|
|
8604
|
+
path: path10,
|
|
8406
8605
|
preview,
|
|
8407
8606
|
useColor = true,
|
|
8408
8607
|
contentWidth
|
|
8409
8608
|
}) {
|
|
8410
8609
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
8411
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children:
|
|
8610
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: path10 }),
|
|
8412
8611
|
/* @__PURE__ */ jsx(
|
|
8413
8612
|
DiffBlock,
|
|
8414
8613
|
{
|
|
@@ -8419,7 +8618,7 @@ function DiffFileBlock({
|
|
|
8419
8618
|
hiddenAdded: preview.hiddenAdded,
|
|
8420
8619
|
hiddenRemoved: preview.hiddenRemoved,
|
|
8421
8620
|
useColor,
|
|
8422
|
-
lang: langFromPath(
|
|
8621
|
+
lang: langFromPath(path10),
|
|
8423
8622
|
contentWidth
|
|
8424
8623
|
}
|
|
8425
8624
|
)
|
|
@@ -8509,7 +8708,8 @@ function DiffBlock({
|
|
|
8509
8708
|
return row.text || " ";
|
|
8510
8709
|
};
|
|
8511
8710
|
const stats = showStats ? formatDiffStats(added, removed) : null;
|
|
8512
|
-
const
|
|
8711
|
+
const terminalWrapGuard = typeof contentWidth === "number" ? 1 : 0;
|
|
8712
|
+
const bodyBudget = typeof contentWidth === "number" ? Math.max(16, contentWidth - (2 + 3 + gutterWidth + 3 + terminalWrapGuard)) : DIFF_FALLBACK_WRAP_WIDTH;
|
|
8513
8713
|
const hasWidth = typeof contentWidth === "number";
|
|
8514
8714
|
const padBody = (seg) => {
|
|
8515
8715
|
if (!hasWidth) return 0;
|
|
@@ -8677,8 +8877,8 @@ function splitReplaceDiffs(obj) {
|
|
|
8677
8877
|
const record = result;
|
|
8678
8878
|
const diff = stringOf(record["diff"]);
|
|
8679
8879
|
if (!diff?.trim()) continue;
|
|
8680
|
-
const
|
|
8681
|
-
items.push(
|
|
8880
|
+
const path10 = stringOf(record["path"]);
|
|
8881
|
+
items.push(path10 ? { path: path10, diff } : { diff });
|
|
8682
8882
|
}
|
|
8683
8883
|
return items;
|
|
8684
8884
|
}
|
|
@@ -8742,8 +8942,8 @@ function collectMultiFileDiffItems(toolName, output, _input) {
|
|
|
8742
8942
|
if (!diffText?.trim()) return void 0;
|
|
8743
8943
|
const blocks = splitGitStyleDiff(diffText);
|
|
8744
8944
|
if (blocks.length === 0) {
|
|
8745
|
-
const
|
|
8746
|
-
return [{ path:
|
|
8945
|
+
const path10 = explicitFiles[0] ?? extractPatchHeaderPath(diffText);
|
|
8946
|
+
return [{ path: path10, diff: diffText }];
|
|
8747
8947
|
}
|
|
8748
8948
|
return blocks.map((block, idx) => ({
|
|
8749
8949
|
path: explicitFiles[idx] ?? block.path,
|
|
@@ -8789,17 +8989,17 @@ function splitGitStyleDiff(diff) {
|
|
|
8789
8989
|
}
|
|
8790
8990
|
flush();
|
|
8791
8991
|
if (blocks.length === 1 && !blocks[0].path) {
|
|
8792
|
-
const
|
|
8793
|
-
if (
|
|
8992
|
+
const path10 = extractPatchHeaderPath(blocks[0].diff);
|
|
8993
|
+
if (path10) blocks[0] = { path: path10, diff: blocks[0].diff };
|
|
8794
8994
|
}
|
|
8795
8995
|
return blocks;
|
|
8796
8996
|
}
|
|
8797
8997
|
function parseDiffGitPath(line) {
|
|
8798
8998
|
const rest = line.slice("diff --git ".length).trim();
|
|
8799
8999
|
if (!rest) return void 0;
|
|
8800
|
-
const
|
|
8801
|
-
if (
|
|
8802
|
-
return rest.slice(
|
|
9000
|
+
const sep3 = rest.lastIndexOf(" b/");
|
|
9001
|
+
if (sep3 > 0 && sep3 > rest.length - sep3 - 3) {
|
|
9002
|
+
return rest.slice(sep3 + 3);
|
|
8803
9003
|
}
|
|
8804
9004
|
const spaceIdx = rest.lastIndexOf(" ");
|
|
8805
9005
|
if (spaceIdx > 0) {
|
|
@@ -8811,8 +9011,8 @@ function parseDiffGitPath(line) {
|
|
|
8811
9011
|
function extractPatchHeaderPath(diffText) {
|
|
8812
9012
|
for (const line of diffText.split("\n")) {
|
|
8813
9013
|
if (line.startsWith("+++ ")) {
|
|
8814
|
-
const
|
|
8815
|
-
const cleaned =
|
|
9014
|
+
const path10 = line.slice(4).trim();
|
|
9015
|
+
const cleaned = path10.replace(/^b\//, "").split(" ")[0].trim();
|
|
8816
9016
|
return cleaned || void 0;
|
|
8817
9017
|
}
|
|
8818
9018
|
}
|
|
@@ -8838,9 +9038,9 @@ function newFileDiffFromWriteInput(output, input) {
|
|
|
8838
9038
|
const obj = input;
|
|
8839
9039
|
const content = stringOf(obj["content"]);
|
|
8840
9040
|
if (content === void 0) return void 0;
|
|
8841
|
-
const
|
|
9041
|
+
const path10 = stringOf(output["path"]) ?? stringOf(obj["path"]) ?? "new file";
|
|
8842
9042
|
const lines = content === "" ? [] : content.replace(/\n$/, "").split("\n");
|
|
8843
|
-
const header = [`+++ ${
|
|
9043
|
+
const header = [`+++ ${path10}`, `@@ -0,0 +1,${lines.length} @@`];
|
|
8844
9044
|
return [...header, ...lines.map((line) => `+${line}`)].join("\n");
|
|
8845
9045
|
}
|
|
8846
9046
|
var BUTTON_COLOR = {
|
|
@@ -8878,7 +9078,7 @@ function renderDiffLine(line) {
|
|
|
8878
9078
|
"\n"
|
|
8879
9079
|
] }, line);
|
|
8880
9080
|
}
|
|
8881
|
-
function renderDiff(diff,
|
|
9081
|
+
function renderDiff(diff, path10) {
|
|
8882
9082
|
const preview = parseUnifiedDiff(diff, CONFIRM_DIFF_MAX_LINES);
|
|
8883
9083
|
if (preview.rows.length > 0) {
|
|
8884
9084
|
return /* @__PURE__ */ jsx(
|
|
@@ -8891,7 +9091,7 @@ function renderDiff(diff, path8) {
|
|
|
8891
9091
|
hiddenAdded: preview.hiddenAdded,
|
|
8892
9092
|
hiddenRemoved: preview.hiddenRemoved,
|
|
8893
9093
|
useColor: theme.supportsBackground,
|
|
8894
|
-
lang: langFromPath(
|
|
9094
|
+
lang: langFromPath(path10 ?? "")
|
|
8895
9095
|
}
|
|
8896
9096
|
);
|
|
8897
9097
|
}
|
|
@@ -9336,10 +9536,9 @@ function FilePicker({ query, matches, selected }) {
|
|
|
9336
9536
|
] }, m))
|
|
9337
9537
|
] });
|
|
9338
9538
|
}
|
|
9339
|
-
function highlight(
|
|
9340
|
-
return
|
|
9539
|
+
function highlight(path10, _query) {
|
|
9540
|
+
return path10;
|
|
9341
9541
|
}
|
|
9342
|
-
var TERMINAL_TTL_MS = 9e4;
|
|
9343
9542
|
var METER_WIDTH = 10;
|
|
9344
9543
|
function isLeaderEntry2(entry) {
|
|
9345
9544
|
return entry.id === "leader" || entry.name === "LEADER";
|
|
@@ -9413,22 +9612,19 @@ function swarmColumnCount(width) {
|
|
|
9413
9612
|
if (width < 54) return 1;
|
|
9414
9613
|
return Math.max(1, Math.min(5, Math.floor(width / 38)));
|
|
9415
9614
|
}
|
|
9416
|
-
function selectSwarmEntries(entries,
|
|
9417
|
-
const terminalTtlMs = opts.terminalTtlMs ?? TERMINAL_TTL_MS;
|
|
9615
|
+
function selectSwarmEntries(entries, _now, opts = {}) {
|
|
9418
9616
|
return Object.values(entries).filter((entry) => {
|
|
9419
9617
|
if (isLeaderEntry2(entry) && !opts.includeLeader) return false;
|
|
9420
|
-
if (entry
|
|
9421
|
-
return
|
|
9618
|
+
if (isLeaderEntry2(entry)) return true;
|
|
9619
|
+
return entry.status === "running";
|
|
9422
9620
|
}).sort((a, b) => {
|
|
9423
9621
|
const rank = (entry) => {
|
|
9424
9622
|
if (entry.status === "running") return 0;
|
|
9425
|
-
|
|
9426
|
-
return 2;
|
|
9623
|
+
return 1;
|
|
9427
9624
|
};
|
|
9428
9625
|
const ar = rank(a);
|
|
9429
9626
|
const br = rank(b);
|
|
9430
9627
|
if (ar !== br) return ar - br;
|
|
9431
|
-
if (ar === 2) return b.lastEventAt - a.lastEventAt;
|
|
9432
9628
|
return a.startedAt - b.startedAt;
|
|
9433
9629
|
});
|
|
9434
9630
|
}
|
|
@@ -9549,16 +9745,8 @@ function FleetPanel({
|
|
|
9549
9745
|
const hasSwarm = grid.rows.length > 0;
|
|
9550
9746
|
if (!hasSwarm && todoRows.length === 0 && !hasCollab) return null;
|
|
9551
9747
|
const runningCount = subagents.filter((e) => e.status === "running").length;
|
|
9552
|
-
const idleCount = subagents.filter((e) => e.status === "idle").length;
|
|
9553
|
-
const doneCount = subagents.filter((e) => e.status === "success").length;
|
|
9554
|
-
const failedCount = subagents.filter(
|
|
9555
|
-
(e) => e.status === "failed" || e.status === "timeout"
|
|
9556
|
-
).length;
|
|
9557
9748
|
const summaryBits = [
|
|
9558
|
-
runningCount > 0 ? `${runningCount} running` : "
|
|
9559
|
-
idleCount > 0 ? `${idleCount} idle` : "",
|
|
9560
|
-
doneCount > 0 ? `${doneCount} done` : "",
|
|
9561
|
-
failedCount > 0 ? `${failedCount} failed` : "",
|
|
9749
|
+
runningCount > 0 ? `${runningCount} running` : "",
|
|
9562
9750
|
fmtCost2(totalCost)
|
|
9563
9751
|
].filter(Boolean);
|
|
9564
9752
|
const collabLabel = hasCollab && collabSession.sessionId ? `collab ${collabSession.bugCount}b/${collabSession.planCount}p/${collabSession.evalCount}e` : "";
|
|
@@ -9962,8 +10150,8 @@ var SEP_RE = /^\s*\|[\s\-:|]+\|\s*$/;
|
|
|
9962
10150
|
function detectTable(lines, start) {
|
|
9963
10151
|
if (start + 1 >= lines.length) return start;
|
|
9964
10152
|
if (!ROW_RE.test(lines[start] ?? "")) return start;
|
|
9965
|
-
const
|
|
9966
|
-
if (!SEP_RE.test(
|
|
10153
|
+
const sep3 = lines[start + 1] ?? "";
|
|
10154
|
+
if (!SEP_RE.test(sep3) || !/-/.test(sep3)) return start;
|
|
9967
10155
|
let end = start + 2;
|
|
9968
10156
|
while (end < lines.length && ROW_RE.test(lines[end] ?? "")) end++;
|
|
9969
10157
|
return end;
|
|
@@ -9989,8 +10177,8 @@ function parseCells(line) {
|
|
|
9989
10177
|
parts.push(buf);
|
|
9990
10178
|
return parts.map((c) => c.trim());
|
|
9991
10179
|
}
|
|
9992
|
-
function parseAlign(
|
|
9993
|
-
const t =
|
|
10180
|
+
function parseAlign(sep3) {
|
|
10181
|
+
const t = sep3.trim();
|
|
9994
10182
|
const left = t.startsWith(":");
|
|
9995
10183
|
const right = t.endsWith(":");
|
|
9996
10184
|
if (left && right) return "center";
|
|
@@ -10556,7 +10744,7 @@ function Banner({
|
|
|
10556
10744
|
entry
|
|
10557
10745
|
}) {
|
|
10558
10746
|
const cwdShort = shortenPath(entry.cwd, 48);
|
|
10559
|
-
const projectLabel =
|
|
10747
|
+
const projectLabel = path9.basename(entry.cwd);
|
|
10560
10748
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
|
|
10561
10749
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
10562
10750
|
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
|
|
@@ -10594,18 +10782,12 @@ function Banner({
|
|
|
10594
10782
|
}
|
|
10595
10783
|
|
|
10596
10784
|
// src/components/suggestions.ts
|
|
10597
|
-
var
|
|
10598
|
-
var PERMISSIVE_HEADING_PATTERNS = [
|
|
10599
|
-
{ re: /💡\s*Next steps?\s*\n+/i, label: "emoji" },
|
|
10600
|
-
{ re: /##?\s*Next steps?\s*\n+/i, label: "markdown" },
|
|
10601
|
-
{ re: /\n{1,2}Next steps?\s*\n+/i, label: "plain" },
|
|
10602
|
-
{ re: /<next_steps>\s*\n+/i, label: "xml-tag" }
|
|
10603
|
-
];
|
|
10785
|
+
var NEXT_STEPS_TAG_RE = /<nextsteps>\s*\n+/i;
|
|
10604
10786
|
var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+?)(\s+auto="true")?$/;
|
|
10605
10787
|
var MAX_STEPS = 6;
|
|
10606
10788
|
function parseNextSteps(content, strict = false, requireHeading = true) {
|
|
10607
10789
|
if (requireHeading) {
|
|
10608
|
-
return parseWithHeading(content
|
|
10790
|
+
return parseWithHeading(content);
|
|
10609
10791
|
}
|
|
10610
10792
|
return parseRawNumbered(content);
|
|
10611
10793
|
}
|
|
@@ -10640,9 +10822,8 @@ function parseRawNumbered(content) {
|
|
|
10640
10822
|
autoTexts: steps.filter((s2) => s2.auto).map((s2) => s2.text)
|
|
10641
10823
|
};
|
|
10642
10824
|
}
|
|
10643
|
-
function parseWithHeading(content,
|
|
10644
|
-
const
|
|
10645
|
-
const headingMatch = headingRe.exec(content);
|
|
10825
|
+
function parseWithHeading(content, _strict) {
|
|
10826
|
+
const headingMatch = NEXT_STEPS_TAG_RE.exec(content);
|
|
10646
10827
|
if (!headingMatch) {
|
|
10647
10828
|
return { steps: [], texts: [], stripped: content, autoTexts: [] };
|
|
10648
10829
|
}
|
|
@@ -10674,8 +10855,7 @@ function parseWithHeading(content, strict) {
|
|
|
10674
10855
|
if (steps.length === 0) {
|
|
10675
10856
|
return { steps: [], texts: [], stripped: content, autoTexts: [] };
|
|
10676
10857
|
}
|
|
10677
|
-
|
|
10678
|
-
if (strict && headingWasXmlTag && !afterHeading.includes("</next_steps>")) {
|
|
10858
|
+
if (!afterHeading.includes("</nextsteps>")) {
|
|
10679
10859
|
return { steps: [], texts: [], stripped: content, autoTexts: [] };
|
|
10680
10860
|
}
|
|
10681
10861
|
const texts = steps.map((s2) => s2.text);
|
|
@@ -10685,14 +10865,10 @@ function parseWithHeading(content, strict) {
|
|
|
10685
10865
|
const stripped = (content.slice(0, blockStart) + content.slice(blockStart + blockEnd)).replace(/\n{3,}/g, "\n\n").trim();
|
|
10686
10866
|
return { steps, texts, stripped, autoTexts };
|
|
10687
10867
|
}
|
|
10688
|
-
function buildPermissiveHeadingRe() {
|
|
10689
|
-
const variants = PERMISSIVE_HEADING_PATTERNS.map(({ re }) => `(?:${re.source})`).join("|");
|
|
10690
|
-
return new RegExp(variants, "i");
|
|
10691
|
-
}
|
|
10692
10868
|
function findBlockEnd(afterHeading, stepCount) {
|
|
10693
|
-
const closeIdx = afterHeading.indexOf("</
|
|
10869
|
+
const closeIdx = afterHeading.indexOf("</nextsteps>");
|
|
10694
10870
|
if (closeIdx !== -1) {
|
|
10695
|
-
let end = closeIdx + "</
|
|
10871
|
+
let end = closeIdx + "</nextsteps>".length;
|
|
10696
10872
|
if (afterHeading[end] === "\n") end += 1;
|
|
10697
10873
|
return end;
|
|
10698
10874
|
}
|
|
@@ -10714,7 +10890,7 @@ function findBlockEnd(afterHeading, stepCount) {
|
|
|
10714
10890
|
return consumed;
|
|
10715
10891
|
}
|
|
10716
10892
|
function stripNextStepsBlock(text) {
|
|
10717
|
-
return text.replace(/<
|
|
10893
|
+
return text.replace(/<nextsteps\b[^>]*>[\s\S]*?<\/nextsteps>/gi, "").replace(/<nextsteps\b[^>]*\/?>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
10718
10894
|
}
|
|
10719
10895
|
function brainStatusStyle(status) {
|
|
10720
10896
|
switch (status) {
|
|
@@ -10908,15 +11084,15 @@ var Entry = React5.memo(function Entry2({
|
|
|
10908
11084
|
const outObj = outJson && typeof outJson === "object" ? outJson : void 0;
|
|
10909
11085
|
const created = name === "write" && (outObj?.["created"] === true || /^[^\n]*\bcreated=true\b/.test(entry.output ?? ""));
|
|
10910
11086
|
const verb = created ? "Write" : "Update";
|
|
10911
|
-
const
|
|
10912
|
-
const target = multiDiffs2 ? multiDiffs2.length === 1 ? multiDiffs2[0].path : `${multiDiffs2.length} files` :
|
|
11087
|
+
const path10 = stringOf(inputObj?.["path"]) ?? stringOf(outObj?.["path"]);
|
|
11088
|
+
const target = multiDiffs2 ? multiDiffs2.length === 1 ? multiDiffs2[0].path : `${multiDiffs2.length} files` : path10 ?? "file";
|
|
10913
11089
|
const agg = multiDiffs2 ? summarizeMultiFileDiffs(multiDiffs2) : void 0;
|
|
10914
11090
|
return {
|
|
10915
11091
|
verb,
|
|
10916
11092
|
target,
|
|
10917
11093
|
added: agg ? agg.added : diff2?.added ?? 0,
|
|
10918
11094
|
removed: agg ? agg.removed : diff2?.removed ?? 0,
|
|
10919
|
-
lang: langFromPath(multiDiffs2 ? "" :
|
|
11095
|
+
lang: langFromPath(multiDiffs2 ? "" : path10 ?? "")
|
|
10920
11096
|
};
|
|
10921
11097
|
})();
|
|
10922
11098
|
return { argSummary: argSummary2, outLines: outLines2, visualLines: visualLines2, diff: diff2, multiDiffs: multiDiffs2, sizeChip: sizeChip2, mutation: mutation2 };
|
|
@@ -12470,12 +12646,12 @@ var STATUS_ICON = {
|
|
|
12470
12646
|
function planFilePath(projectRoot, sessionId, scope) {
|
|
12471
12647
|
const base = resolveWstackPaths$1({ projectRoot }).projectSessions;
|
|
12472
12648
|
if (scope === "project") {
|
|
12473
|
-
return
|
|
12649
|
+
return path9.join(base, "backlog.plan.json");
|
|
12474
12650
|
}
|
|
12475
12651
|
if (sessionId) {
|
|
12476
12652
|
return sessionScopedPath(base, sessionId, ".plan.json");
|
|
12477
12653
|
}
|
|
12478
|
-
return
|
|
12654
|
+
return path9.join(base, "backlog.plan.json");
|
|
12479
12655
|
}
|
|
12480
12656
|
function PlanPanel({ projectRoot, sessionId, onClose: _onClose }) {
|
|
12481
12657
|
const [items, setItems] = useState([]);
|
|
@@ -12603,7 +12779,135 @@ function PlanRow({ item }) {
|
|
|
12603
12779
|
] }) : null
|
|
12604
12780
|
] });
|
|
12605
12781
|
}
|
|
12606
|
-
var CHROME_ROWS2 =
|
|
12782
|
+
var CHROME_ROWS2 = 14;
|
|
12783
|
+
var RISK_DESCS = {
|
|
12784
|
+
off: "Human decides everything",
|
|
12785
|
+
low: "Auto-decide low risk only",
|
|
12786
|
+
medium: "Auto-decide up to medium risk",
|
|
12787
|
+
high: "Auto-decide up to high risk",
|
|
12788
|
+
all: "Auto-decide everything"
|
|
12789
|
+
};
|
|
12790
|
+
var RISK_COLORS2 = {
|
|
12791
|
+
off: "gray",
|
|
12792
|
+
low: "green",
|
|
12793
|
+
medium: "yellow",
|
|
12794
|
+
high: "red",
|
|
12795
|
+
all: "magenta"
|
|
12796
|
+
};
|
|
12797
|
+
function BrainPanel({
|
|
12798
|
+
riskLevel,
|
|
12799
|
+
log,
|
|
12800
|
+
selected,
|
|
12801
|
+
hint
|
|
12802
|
+
}) {
|
|
12803
|
+
const { stdout } = useStdout();
|
|
12804
|
+
const termRows = stdout?.rows ?? 24;
|
|
12805
|
+
const maxVisible = Math.max(4, termRows - CHROME_ROWS2);
|
|
12806
|
+
const total = log.length;
|
|
12807
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12808
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12809
|
+
const above = windowStart;
|
|
12810
|
+
const below = total - windowEnd;
|
|
12811
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
12812
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "\u2501\u2501 Brain \u2501\u2501" }),
|
|
12813
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate log \xB7 \u2190/\u2192 change risk \xB7 Esc close" }),
|
|
12814
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12815
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
12816
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Risk ceiling: " }),
|
|
12817
|
+
/* @__PURE__ */ jsx(Text, { color: RISK_COLORS2[riskLevel], bold: true, children: riskLevel.toUpperCase() }),
|
|
12818
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${RISK_DESCS[riskLevel]}` })
|
|
12819
|
+
] }),
|
|
12820
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
12821
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "Recent decisions" }),
|
|
12822
|
+
total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No decisions recorded yet this session." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12823
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12824
|
+
log.slice(windowStart, windowEnd).map((entry, i) => {
|
|
12825
|
+
const index = windowStart + i;
|
|
12826
|
+
const focused = index === selected;
|
|
12827
|
+
return /* @__PURE__ */ jsxs(
|
|
12828
|
+
Text,
|
|
12829
|
+
{
|
|
12830
|
+
inverse: focused,
|
|
12831
|
+
...focused ? { color: "magenta" } : {},
|
|
12832
|
+
wrap: "truncate-end",
|
|
12833
|
+
children: [
|
|
12834
|
+
focused ? "\u203A " : " ",
|
|
12835
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.age.padEnd(8) }),
|
|
12836
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: entry.kind.padEnd(12) }),
|
|
12837
|
+
/* @__PURE__ */ jsx(Text, { children: entry.question.length > 60 ? `${entry.question.slice(0, 57)}\u2026` : entry.question }),
|
|
12838
|
+
entry.outcome ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2192 ${entry.outcome.length > 20 ? `${entry.outcome.slice(0, 17)}\u2026` : entry.outcome}` }) : null
|
|
12839
|
+
]
|
|
12840
|
+
},
|
|
12841
|
+
`${entry.kind}-${i}`
|
|
12842
|
+
);
|
|
12843
|
+
}),
|
|
12844
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
12845
|
+
] })
|
|
12846
|
+
] })
|
|
12847
|
+
] }),
|
|
12848
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12849
|
+
] });
|
|
12850
|
+
}
|
|
12851
|
+
var CHROME_ROWS3 = 17;
|
|
12852
|
+
function statusBadge(status, enabled) {
|
|
12853
|
+
if (!enabled) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disabled" });
|
|
12854
|
+
switch (status) {
|
|
12855
|
+
case "connected":
|
|
12856
|
+
return /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF connected" });
|
|
12857
|
+
case "connecting":
|
|
12858
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D0 connecting" });
|
|
12859
|
+
case "reconnecting":
|
|
12860
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25D1 reconnecting" });
|
|
12861
|
+
case "disconnected":
|
|
12862
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB disconnected" });
|
|
12863
|
+
case "failed":
|
|
12864
|
+
return /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 failed" });
|
|
12865
|
+
default:
|
|
12866
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: status });
|
|
12867
|
+
}
|
|
12868
|
+
}
|
|
12869
|
+
function McpPicker({
|
|
12870
|
+
items,
|
|
12871
|
+
selected,
|
|
12872
|
+
busy = false,
|
|
12873
|
+
hint
|
|
12874
|
+
}) {
|
|
12875
|
+
const { stdout } = useStdout();
|
|
12876
|
+
const rows = stdout?.rows ?? 24;
|
|
12877
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS3);
|
|
12878
|
+
const total = items.length;
|
|
12879
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12880
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12881
|
+
const above = windowStart;
|
|
12882
|
+
const below = total - windowEnd;
|
|
12883
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
12884
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MCP Servers" }),
|
|
12885
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle enable \xB7 r restart \xB7 Esc close" }),
|
|
12886
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: busy ? "Loading servers\u2026" : "No MCP servers configured." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12887
|
+
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12888
|
+
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
12889
|
+
const index = windowStart + i;
|
|
12890
|
+
const focused = index === selected;
|
|
12891
|
+
const marker = focused ? "\u203A" : " ";
|
|
12892
|
+
return /* @__PURE__ */ jsxs(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
12893
|
+
marker,
|
|
12894
|
+
" ",
|
|
12895
|
+
statusBadge(item.status, item.enabled),
|
|
12896
|
+
" ",
|
|
12897
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.name.padEnd(18) }),
|
|
12898
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12899
|
+
item.transport.padEnd(14),
|
|
12900
|
+
item.toolCount > 0 ? `${item.toolCount} tools` : "",
|
|
12901
|
+
item.lazy ? " lazy" : ""
|
|
12902
|
+
] })
|
|
12903
|
+
] }, item.name);
|
|
12904
|
+
}),
|
|
12905
|
+
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
12906
|
+
] }) }),
|
|
12907
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12908
|
+
] });
|
|
12909
|
+
}
|
|
12910
|
+
var CHROME_ROWS4 = 17;
|
|
12607
12911
|
function PluginPicker({
|
|
12608
12912
|
items,
|
|
12609
12913
|
selected,
|
|
@@ -12612,15 +12916,20 @@ function PluginPicker({
|
|
|
12612
12916
|
}) {
|
|
12613
12917
|
const { stdout } = useStdout();
|
|
12614
12918
|
const rows = stdout?.rows ?? 24;
|
|
12615
|
-
const maxVisible = Math.max(4, rows -
|
|
12919
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS4);
|
|
12616
12920
|
const total = items.length;
|
|
12617
12921
|
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12618
12922
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12619
12923
|
const above = windowStart;
|
|
12620
12924
|
const below = total - windowEnd;
|
|
12925
|
+
const hasLockedRows = items.some((item) => item.lockable === false);
|
|
12621
12926
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
12622
12927
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Plugin menu" }),
|
|
12623
|
-
/* @__PURE__ */
|
|
12928
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12929
|
+
"\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle",
|
|
12930
|
+
hasLockedRows ? " \xB7 \u{1F512} = locked" : "",
|
|
12931
|
+
" \xB7 Esc close"
|
|
12932
|
+
] }),
|
|
12624
12933
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: busy ? "Loading plugins\u2026" : "No plugins available." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12625
12934
|
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12626
12935
|
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
@@ -12653,60 +12962,388 @@ function PluginPicker({
|
|
|
12653
12962
|
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
12654
12963
|
] });
|
|
12655
12964
|
}
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12965
|
+
var CHROME_ROWS5 = 15;
|
|
12966
|
+
function formatCount(noun, count) {
|
|
12967
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
12968
|
+
}
|
|
12969
|
+
function toolActionLabel(enabled) {
|
|
12970
|
+
return enabled ? "Enter disables this tool" : "Enter re-enables this tool";
|
|
12971
|
+
}
|
|
12972
|
+
function statusBadge2(enabled) {
|
|
12973
|
+
return enabled ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF active" }) : /* @__PURE__ */ jsx(Text, { color: "red", children: "\u25CB disabled" });
|
|
12974
|
+
}
|
|
12975
|
+
function rwBadge(mutating) {
|
|
12976
|
+
return mutating ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "mut" }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: "ro" });
|
|
12977
|
+
}
|
|
12978
|
+
function displayCategory(cat) {
|
|
12979
|
+
if (!cat || cat.trim() === "") return "Other";
|
|
12980
|
+
return cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
12981
|
+
}
|
|
12982
|
+
function buildRows(items) {
|
|
12983
|
+
const rows = [];
|
|
12984
|
+
let lastCat = "";
|
|
12985
|
+
for (let i = 0; i < items.length; i++) {
|
|
12986
|
+
const item = items[i];
|
|
12987
|
+
const cat = displayCategory(item.category);
|
|
12988
|
+
if (cat !== lastCat) {
|
|
12989
|
+
lastCat = cat;
|
|
12990
|
+
rows.push({ type: "header", category: cat });
|
|
12991
|
+
}
|
|
12992
|
+
rows.push({ type: "item", item, index: i });
|
|
12669
12993
|
}
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
getProcessRegistry().killAll();
|
|
12695
|
-
} else if (input === "A") {
|
|
12696
|
-
getProcessRegistry().killAll({ force: true });
|
|
12697
|
-
} else if (input === "r") {
|
|
12698
|
-
getProcessRegistry().forceBreakerReset();
|
|
12994
|
+
return rows;
|
|
12995
|
+
}
|
|
12996
|
+
function windowRows(rows, focus, max) {
|
|
12997
|
+
if (rows.length <= max) {
|
|
12998
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
12999
|
+
}
|
|
13000
|
+
let start = focus - Math.floor(max / 2);
|
|
13001
|
+
if (start < 0) start = 0;
|
|
13002
|
+
let end = start + max;
|
|
13003
|
+
if (end > rows.length) {
|
|
13004
|
+
end = rows.length;
|
|
13005
|
+
start = end - max;
|
|
13006
|
+
}
|
|
13007
|
+
let contextHeader = null;
|
|
13008
|
+
if (start > 0) {
|
|
13009
|
+
const first = rows[start];
|
|
13010
|
+
if (first && first.type === "item") {
|
|
13011
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
13012
|
+
const r = rows[i];
|
|
13013
|
+
if (r && r.type === "header") {
|
|
13014
|
+
contextHeader = r.category;
|
|
13015
|
+
break;
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
12699
13018
|
}
|
|
12700
|
-
}
|
|
12701
|
-
return
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
13019
|
+
}
|
|
13020
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
13021
|
+
}
|
|
13022
|
+
function ToolsPicker({
|
|
13023
|
+
items,
|
|
13024
|
+
selected,
|
|
13025
|
+
busy = false,
|
|
13026
|
+
hint,
|
|
13027
|
+
filter
|
|
13028
|
+
}) {
|
|
13029
|
+
const { stdout } = useStdout();
|
|
13030
|
+
const termRows = stdout?.rows ?? 24;
|
|
13031
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS5);
|
|
13032
|
+
const total = items.length;
|
|
13033
|
+
let visibleItems;
|
|
13034
|
+
let visibleSelected;
|
|
13035
|
+
const filterActive = Boolean(filter && filter.length > 0);
|
|
13036
|
+
if (filterActive) {
|
|
13037
|
+
const q = filter.toLowerCase();
|
|
13038
|
+
visibleItems = items.filter(
|
|
13039
|
+
(it) => it.name.toLowerCase().includes(q) || it.owner.toLowerCase().includes(q) || it.description.toLowerCase().includes(q)
|
|
13040
|
+
);
|
|
13041
|
+
const rawSelected = items[selected];
|
|
13042
|
+
visibleSelected = rawSelected ? visibleItems.indexOf(rawSelected) : 0;
|
|
13043
|
+
if (visibleSelected < 0) visibleSelected = 0;
|
|
13044
|
+
} else {
|
|
13045
|
+
visibleItems = items;
|
|
13046
|
+
visibleSelected = selected;
|
|
13047
|
+
}
|
|
13048
|
+
const rows = buildRows(visibleItems);
|
|
13049
|
+
const enabledCount = items.filter((item) => item.enabled).length;
|
|
13050
|
+
const disabledCount = total - enabledCount;
|
|
13051
|
+
const selectedItem = visibleItems[visibleSelected];
|
|
13052
|
+
let displayRows;
|
|
13053
|
+
let hiddenAbove = 0;
|
|
13054
|
+
let hiddenBelow = 0;
|
|
13055
|
+
let contextHeader = null;
|
|
13056
|
+
if (filterActive) {
|
|
13057
|
+
displayRows = rows;
|
|
13058
|
+
} else {
|
|
13059
|
+
const selectedRowIdx = rows.findIndex(
|
|
13060
|
+
(r) => r.type === "item" && r.index === visibleSelected
|
|
13061
|
+
);
|
|
13062
|
+
const win = windowRows(
|
|
13063
|
+
rows,
|
|
13064
|
+
selectedRowIdx < 0 ? 0 : selectedRowIdx,
|
|
13065
|
+
maxVisible
|
|
13066
|
+
);
|
|
13067
|
+
displayRows = win.rows;
|
|
13068
|
+
hiddenAbove = win.start;
|
|
13069
|
+
hiddenBelow = rows.length - win.end;
|
|
13070
|
+
contextHeader = win.contextHeader;
|
|
13071
|
+
}
|
|
13072
|
+
const hasFilter = filterActive;
|
|
13073
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
|
|
13074
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "\u2501\u2501 Tools \u2501\u2501" }),
|
|
13075
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${visibleItems.length} match${visibleItems.length === 1 ? "" : "es"}) \xB7 Backspace edit \xB7 Esc clear` : `\u2191/\u2193 select \xB7 type to filter \xB7 Enter toggles \xB7 Esc close \xB7 ${formatCount("active", enabledCount)} / ${formatCount("disabled", disabledCount)}` }),
|
|
13076
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Disabled tools stay listed here so you can select them and re-enable them later." }),
|
|
13077
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: busy ? "Loading tools\u2026" : "No tools registered." }) : visibleItems.length === 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13078
|
+
'No tools match "',
|
|
13079
|
+
filter,
|
|
13080
|
+
'".'
|
|
13081
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13082
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13083
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13084
|
+
" ",
|
|
13085
|
+
contextHeader
|
|
13086
|
+
] }) : null,
|
|
13087
|
+
displayRows.map((row) => {
|
|
13088
|
+
if (row.type === "header") {
|
|
13089
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13090
|
+
" ",
|
|
13091
|
+
row.category
|
|
13092
|
+
] }, `cat-${row.category}`);
|
|
13093
|
+
}
|
|
13094
|
+
const { item, index } = row;
|
|
13095
|
+
const focused = index === visibleSelected;
|
|
13096
|
+
return /* @__PURE__ */ jsxs(
|
|
13097
|
+
Text,
|
|
13098
|
+
{
|
|
13099
|
+
inverse: focused,
|
|
13100
|
+
...focused ? { color: "green" } : {},
|
|
13101
|
+
wrap: "truncate-end",
|
|
13102
|
+
children: [
|
|
13103
|
+
focused ? "\u203A " : " ",
|
|
13104
|
+
statusBadge2(item.enabled),
|
|
13105
|
+
" ",
|
|
13106
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.name.padEnd(20) }),
|
|
13107
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13108
|
+
`[${item.owner}]`.padEnd(22),
|
|
13109
|
+
rwBadge(item.mutating),
|
|
13110
|
+
" ",
|
|
13111
|
+
" ",
|
|
13112
|
+
item.permission.padEnd(6),
|
|
13113
|
+
" ",
|
|
13114
|
+
" ",
|
|
13115
|
+
/* @__PURE__ */ jsxs(Text, { color: item.descMode === "simple" ? "yellow" : void 0, children: [
|
|
13116
|
+
"desc:",
|
|
13117
|
+
item.descMode
|
|
13118
|
+
] })
|
|
13119
|
+
] })
|
|
13120
|
+
]
|
|
13121
|
+
},
|
|
13122
|
+
item.name
|
|
13123
|
+
);
|
|
13124
|
+
}),
|
|
13125
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13126
|
+
] }) }),
|
|
13127
|
+
selectedItem ? /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13128
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
13129
|
+
/* @__PURE__ */ jsx(Text, { color: selectedItem.enabled ? "green" : "red", children: toolActionLabel(selectedItem.enabled) }),
|
|
13130
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${selectedItem.mutating ? "Mutating" : "Read-only"} \xB7 permission: ${selectedItem.permission} \xB7 descriptions: ${selectedItem.descMode}` })
|
|
13131
|
+
] }),
|
|
13132
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: selectedItem.description || "No description provided." })
|
|
13133
|
+
] }) : null,
|
|
13134
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13135
|
+
] });
|
|
13136
|
+
}
|
|
13137
|
+
var CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
13138
|
+
var CHROME_ROWS6 = 7;
|
|
13139
|
+
function normalizeQuery(raw) {
|
|
13140
|
+
return raw.trim().toLowerCase();
|
|
13141
|
+
}
|
|
13142
|
+
function buildRows2(entries) {
|
|
13143
|
+
const rows = [];
|
|
13144
|
+
let lastCat = "";
|
|
13145
|
+
for (let i = 0; i < entries.length; i++) {
|
|
13146
|
+
const e = entries[i];
|
|
13147
|
+
const cat = e.category || "App";
|
|
13148
|
+
if (cat !== lastCat) {
|
|
13149
|
+
lastCat = cat;
|
|
13150
|
+
rows.push({ type: "header", category: cat });
|
|
13151
|
+
}
|
|
13152
|
+
rows.push({ type: "item", entry: e, index: i });
|
|
13153
|
+
}
|
|
13154
|
+
return rows;
|
|
13155
|
+
}
|
|
13156
|
+
function windowRows2(rows, focus, max) {
|
|
13157
|
+
if (rows.length <= max) {
|
|
13158
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13159
|
+
}
|
|
13160
|
+
let start = focus - Math.floor(max / 2);
|
|
13161
|
+
if (start < 0) start = 0;
|
|
13162
|
+
let end = start + max;
|
|
13163
|
+
if (end > rows.length) {
|
|
13164
|
+
end = rows.length;
|
|
13165
|
+
start = end - max;
|
|
13166
|
+
}
|
|
13167
|
+
let contextHeader = null;
|
|
13168
|
+
if (start > 0) {
|
|
13169
|
+
const first = rows[start];
|
|
13170
|
+
if (first && first.type === "item") {
|
|
13171
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
13172
|
+
const r = rows[i];
|
|
13173
|
+
if (r && r.type === "header") {
|
|
13174
|
+
contextHeader = r.category;
|
|
13175
|
+
break;
|
|
13176
|
+
}
|
|
13177
|
+
}
|
|
13178
|
+
}
|
|
13179
|
+
}
|
|
13180
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
13181
|
+
}
|
|
13182
|
+
function HelpPanel({
|
|
13183
|
+
entries,
|
|
13184
|
+
filter,
|
|
13185
|
+
selected,
|
|
13186
|
+
hint
|
|
13187
|
+
}) {
|
|
13188
|
+
const { stdout } = useStdout();
|
|
13189
|
+
const termRows = stdout?.rows ?? 24;
|
|
13190
|
+
const maxVisible = Math.max(6, termRows - CHROME_ROWS6);
|
|
13191
|
+
const query = normalizeQuery(filter);
|
|
13192
|
+
const filtered = query ? entries.filter(
|
|
13193
|
+
(e) => e.name.toLowerCase().includes(query) || e.description.toLowerCase().includes(query) || e.category.toLowerCase().includes(query) || (e.aliases ?? []).some((a) => a.toLowerCase().includes(query))
|
|
13194
|
+
) : entries;
|
|
13195
|
+
filtered.sort((a, b) => {
|
|
13196
|
+
const ai = CATEGORY_ORDER.indexOf(a.category);
|
|
13197
|
+
const bi = CATEGORY_ORDER.indexOf(b.category);
|
|
13198
|
+
if (ai !== bi) return ai - bi;
|
|
13199
|
+
return a.name.localeCompare(b.name);
|
|
13200
|
+
});
|
|
13201
|
+
const rows = buildRows2(filtered);
|
|
13202
|
+
const focus = Math.min(selected, Math.max(0, filtered.length - 1));
|
|
13203
|
+
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === focus);
|
|
13204
|
+
const win = windowRows2(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, maxVisible);
|
|
13205
|
+
const { rows: visible, start, end, contextHeader } = win;
|
|
13206
|
+
const hiddenAbove = start;
|
|
13207
|
+
const hiddenBelow = rows.length - end;
|
|
13208
|
+
const hasFilter = query.length > 0;
|
|
13209
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
13210
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2501\u2501 Help / Command Palette \u2501\u2501" }),
|
|
13211
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${filtered.length} match${filtered.length === 1 ? "" : "es"})` : "\u2191/\u2193 navigate \xB7 Enter run \xB7 Tab fill \xB7 type to filter \xB7 Esc close" }),
|
|
13212
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13213
|
+
'No commands match "',
|
|
13214
|
+
filter,
|
|
13215
|
+
'".'
|
|
13216
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13217
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
13218
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13219
|
+
" ",
|
|
13220
|
+
contextHeader
|
|
13221
|
+
] }) : null,
|
|
13222
|
+
visible.map((row) => {
|
|
13223
|
+
if (row.type === "header") {
|
|
13224
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
13225
|
+
" ",
|
|
13226
|
+
row.category
|
|
13227
|
+
] }, `cat-${row.category}`);
|
|
13228
|
+
}
|
|
13229
|
+
const { entry, index } = row;
|
|
13230
|
+
const isSelected = index === focus;
|
|
13231
|
+
return /* @__PURE__ */ jsxs(
|
|
13232
|
+
Text,
|
|
13233
|
+
{
|
|
13234
|
+
inverse: isSelected,
|
|
13235
|
+
...isSelected ? { color: "cyan" } : {},
|
|
13236
|
+
wrap: "truncate-end",
|
|
13237
|
+
children: [
|
|
13238
|
+
isSelected ? "\u203A " : " ",
|
|
13239
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
13240
|
+
"/",
|
|
13241
|
+
entry.name
|
|
13242
|
+
] }),
|
|
13243
|
+
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13244
|
+
" (",
|
|
13245
|
+
entry.aliases.map((a) => `/${a}`).join(", "),
|
|
13246
|
+
")"
|
|
13247
|
+
] }) : null,
|
|
13248
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13249
|
+
" \u2014 ",
|
|
13250
|
+
entry.description
|
|
13251
|
+
] }),
|
|
13252
|
+
entry.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13253
|
+
" ",
|
|
13254
|
+
entry.argsHint
|
|
13255
|
+
] }) : null
|
|
13256
|
+
]
|
|
13257
|
+
},
|
|
13258
|
+
entry.name
|
|
13259
|
+
);
|
|
13260
|
+
}),
|
|
13261
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
13262
|
+
] }) }),
|
|
13263
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13264
|
+
] });
|
|
13265
|
+
}
|
|
13266
|
+
function ShadowPanel({
|
|
13267
|
+
shadow,
|
|
13268
|
+
hint
|
|
13269
|
+
}) {
|
|
13270
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
13271
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "blue", children: "\u2501\u2501 Shadow Agent \u2501\u2501" }),
|
|
13272
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "s start \xB7 t stop \xB7 i cycle interval \xB7 m cycle model \xB7 Esc close" }),
|
|
13273
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
13274
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
13275
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Status: " }),
|
|
13276
|
+
shadow.running ? /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF running" }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u25CB stopped" }),
|
|
13277
|
+
shadow.activeId ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${shadow.activeId.slice(0, 12)}\u2026` }) : null
|
|
13278
|
+
] }),
|
|
13279
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13280
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Model: " }),
|
|
13281
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: shadow.model })
|
|
13282
|
+
] }),
|
|
13283
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13284
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Interval: " }),
|
|
13285
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: shadow.intervalMs >= 1e3 ? `${shadow.intervalMs / 1e3}s` : `${shadow.intervalMs}ms` }),
|
|
13286
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (min 5s)" })
|
|
13287
|
+
] }),
|
|
13288
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: shadow.running ? "Press t to stop the Shadow Agent" : "Press s to start the Shadow Agent" }) })
|
|
13289
|
+
] }),
|
|
13290
|
+
hint ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) }) : null
|
|
13291
|
+
] });
|
|
13292
|
+
}
|
|
13293
|
+
function ProcessListMonitor() {
|
|
13294
|
+
const [, setTick] = useState(0);
|
|
13295
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
13296
|
+
useEffect(() => {
|
|
13297
|
+
const id = setInterval(() => setTick((t) => t + 1), 1e3);
|
|
13298
|
+
return () => clearInterval(id);
|
|
13299
|
+
}, []);
|
|
13300
|
+
const registry = getProcessRegistry();
|
|
13301
|
+
const all = registry.list();
|
|
13302
|
+
const stats = registry.stats();
|
|
13303
|
+
const safeIndex = Math.min(selectedIndex, Math.max(0, all.length - 1));
|
|
13304
|
+
if (safeIndex !== selectedIndex) {
|
|
13305
|
+
setSelectedIndex(safeIndex);
|
|
13306
|
+
}
|
|
13307
|
+
const selected = all[safeIndex];
|
|
13308
|
+
const now = Date.now();
|
|
13309
|
+
const running = all.filter((p) => !p.killed).length;
|
|
13310
|
+
const b = stats.breaker;
|
|
13311
|
+
const breakerState = b.state === "closed" ? "\u{1F7E2} closed" : b.state === "half-open" ? "\u{1F7E1} half-open" : "\u{1F534} open";
|
|
13312
|
+
const pageSize = Math.max(1, Math.floor(all.length / 2));
|
|
13313
|
+
useInput((input, key) => {
|
|
13314
|
+
if (key.upArrow) {
|
|
13315
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
13316
|
+
} else if (key.downArrow) {
|
|
13317
|
+
setSelectedIndex((prev) => Math.min(all.length - 1, prev + 1));
|
|
13318
|
+
} else if (key.pageUp) {
|
|
13319
|
+
setSelectedIndex((prev) => Math.max(0, prev - pageSize));
|
|
13320
|
+
} else if (key.pageDown) {
|
|
13321
|
+
setSelectedIndex((prev) => Math.min(all.length - 1, prev + pageSize));
|
|
13322
|
+
} else if (key.home || key.ctrl && input === "a" || input === "g") {
|
|
13323
|
+
setSelectedIndex(0);
|
|
13324
|
+
} else if (key.end || key.ctrl && input === "e" || input === "G") {
|
|
13325
|
+
setSelectedIndex(Math.max(0, all.length - 1));
|
|
13326
|
+
} else if (key.return && selected) {
|
|
13327
|
+
getProcessRegistry().kill(selected.pid);
|
|
13328
|
+
} else if (key.delete && selected) {
|
|
13329
|
+
getProcessRegistry().kill(selected.pid, { force: true });
|
|
13330
|
+
} else if (input === "a" && !key.ctrl) {
|
|
13331
|
+
getProcessRegistry().killAll();
|
|
13332
|
+
} else if (input === "A") {
|
|
13333
|
+
getProcessRegistry().killAll({ force: true });
|
|
13334
|
+
} else if (input === "r") {
|
|
13335
|
+
getProcessRegistry().forceBreakerReset();
|
|
13336
|
+
}
|
|
13337
|
+
});
|
|
13338
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, children: [
|
|
13339
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
13340
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "red", children: "PROCESS LIST" }),
|
|
13341
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
13342
|
+
/* @__PURE__ */ jsxs(Text, { color: running > 0 ? "yellow" : "green", children: [
|
|
13343
|
+
"\u25CF",
|
|
13344
|
+
running
|
|
13345
|
+
] }),
|
|
13346
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/" }),
|
|
12710
13347
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12711
13348
|
all.length,
|
|
12712
13349
|
" tracked"
|
|
@@ -13335,7 +13972,7 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13335
13972
|
rows.push({ type: "item", match: m, index: i });
|
|
13336
13973
|
}
|
|
13337
13974
|
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === selected);
|
|
13338
|
-
const visible =
|
|
13975
|
+
const visible = windowRows3(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, MAX_VISIBLE_ITEMS);
|
|
13339
13976
|
const hiddenAbove = visible.start;
|
|
13340
13977
|
const hiddenBelow = rows.length - visible.end;
|
|
13341
13978
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
@@ -13387,7 +14024,7 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
13387
14024
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500 \u2191\u2193 nav \xB7 Enter run \xB7 Tab fill \xB7 Esc close" })
|
|
13388
14025
|
] });
|
|
13389
14026
|
}
|
|
13390
|
-
function
|
|
14027
|
+
function windowRows3(rows, focus, max) {
|
|
13391
14028
|
if (rows.length <= max) {
|
|
13392
14029
|
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
13393
14030
|
}
|
|
@@ -13546,11 +14183,11 @@ function WorktreeMonitor({
|
|
|
13546
14183
|
useInput((input, key) => {
|
|
13547
14184
|
if (isWorktreeMonitorCloseKey(input, key)) onClose();
|
|
13548
14185
|
});
|
|
13549
|
-
const
|
|
14186
|
+
const TERMINAL_TTL_MS = 5 * 6e4;
|
|
13550
14187
|
const list = Object.values(worktrees);
|
|
13551
14188
|
const recent = list.filter((w) => {
|
|
13552
14189
|
if (["active", "committing", "merging", "needs-review"].includes(w.status)) return true;
|
|
13553
|
-
return nowTick - (w.allocatedAt ?? nowTick) <
|
|
14190
|
+
return nowTick - (w.allocatedAt ?? nowTick) < TERMINAL_TTL_MS;
|
|
13554
14191
|
});
|
|
13555
14192
|
const active = list.filter((w) => ["active", "committing", "merging"].includes(w.status)).length;
|
|
13556
14193
|
const merged = list.filter((w) => w.status === "merged").length;
|
|
@@ -13780,80 +14417,293 @@ function runGit(cwd, args) {
|
|
|
13780
14417
|
}
|
|
13781
14418
|
});
|
|
13782
14419
|
}
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
14420
|
+
|
|
14421
|
+
// src/app-initial-state.ts
|
|
14422
|
+
function buildRestoredEntries(messages, restoredToolCalls) {
|
|
14423
|
+
if (!messages || messages.length === 0) return [];
|
|
14424
|
+
const visible = messages.filter((m) => m.role !== "system");
|
|
14425
|
+
if (visible.length === 0) return [];
|
|
14426
|
+
return rehydrateHistory(visible, 1, restoredToolCalls);
|
|
14427
|
+
}
|
|
14428
|
+
function createInitialState(options) {
|
|
14429
|
+
const {
|
|
14430
|
+
banner,
|
|
14431
|
+
appVersion,
|
|
14432
|
+
provider,
|
|
14433
|
+
model,
|
|
14434
|
+
cwd,
|
|
14435
|
+
family,
|
|
14436
|
+
keyTail,
|
|
14437
|
+
restoredEntries,
|
|
14438
|
+
enhanceEnabled,
|
|
14439
|
+
initialAgentsMonitorOpen
|
|
14440
|
+
} = options;
|
|
14441
|
+
const initialNextId = 1 + restoredEntries.length;
|
|
13790
14442
|
return {
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
14443
|
+
entries: [
|
|
14444
|
+
...banner ? [
|
|
14445
|
+
{
|
|
14446
|
+
id: 0,
|
|
14447
|
+
kind: "banner",
|
|
14448
|
+
version: appVersion ?? "dev",
|
|
14449
|
+
provider: provider ?? "agent",
|
|
14450
|
+
model,
|
|
14451
|
+
cwd,
|
|
14452
|
+
family,
|
|
14453
|
+
keyTail
|
|
14454
|
+
}
|
|
14455
|
+
] : [],
|
|
14456
|
+
...restoredEntries
|
|
14457
|
+
],
|
|
14458
|
+
historyGen: 0,
|
|
14459
|
+
buffer: "",
|
|
14460
|
+
cursor: 0,
|
|
14461
|
+
streamingText: "",
|
|
14462
|
+
toolStream: null,
|
|
14463
|
+
status: "idle",
|
|
14464
|
+
interrupts: 0,
|
|
14465
|
+
steeringPending: false,
|
|
14466
|
+
steerSnapshot: null,
|
|
14467
|
+
hint: "",
|
|
14468
|
+
brain: { state: "idle" },
|
|
14469
|
+
brainPrompt: null,
|
|
14470
|
+
nextId: initialNextId,
|
|
14471
|
+
picker: { open: false, query: "", matches: [], selected: 0 },
|
|
14472
|
+
slashPicker: { open: false, query: "", matches: [], selected: 0 },
|
|
14473
|
+
runningTools: /* @__PURE__ */ new Map(),
|
|
14474
|
+
queue: [],
|
|
14475
|
+
nextQueueId: 1,
|
|
14476
|
+
inputHistory: [],
|
|
14477
|
+
historyIndex: 0,
|
|
14478
|
+
historyDraft: "",
|
|
14479
|
+
modelPicker: {
|
|
14480
|
+
open: false,
|
|
14481
|
+
step: "provider",
|
|
14482
|
+
providerOptions: [],
|
|
14483
|
+
modelOptions: [],
|
|
14484
|
+
filteredOptions: [],
|
|
14485
|
+
selected: 0,
|
|
14486
|
+
searchQuery: ""
|
|
14487
|
+
},
|
|
14488
|
+
autonomyPicker: { open: false, options: [], selected: 0 },
|
|
14489
|
+
modePicker: { open: false, modes: [], selected: 0 },
|
|
14490
|
+
designPicker: { open: false, kits: [], selected: 0, stack: "web" },
|
|
14491
|
+
promptPicker: {
|
|
14492
|
+
open: false,
|
|
14493
|
+
all: [],
|
|
14494
|
+
categories: [],
|
|
14495
|
+
recentSlugs: [],
|
|
14496
|
+
catIndex: 0,
|
|
14497
|
+
selected: 0
|
|
14498
|
+
},
|
|
14499
|
+
resumePicker: {
|
|
14500
|
+
open: false,
|
|
14501
|
+
sessions: [],
|
|
14502
|
+
selected: 0,
|
|
14503
|
+
busy: false,
|
|
14504
|
+
hint: void 0,
|
|
14505
|
+
error: void 0
|
|
14506
|
+
},
|
|
14507
|
+
settingsPicker: {
|
|
14508
|
+
open: false,
|
|
14509
|
+
field: 0,
|
|
14510
|
+
lastSettingsField: 0,
|
|
14511
|
+
filter: "",
|
|
14512
|
+
mode: "off",
|
|
14513
|
+
delayMs: 0,
|
|
14514
|
+
titleAnimation: true,
|
|
14515
|
+
yolo: false,
|
|
14516
|
+
streamFleet: true,
|
|
14517
|
+
chime: false,
|
|
14518
|
+
confirmExit: true,
|
|
14519
|
+
nextPrediction: false,
|
|
14520
|
+
featureMcp: true,
|
|
14521
|
+
featurePlugins: true,
|
|
14522
|
+
featureMemory: true,
|
|
14523
|
+
featureSkills: true,
|
|
14524
|
+
featureModelsRegistry: true,
|
|
14525
|
+
tokenSavingTier: "off",
|
|
14526
|
+
allowOutsideProjectRoot: true,
|
|
14527
|
+
contextAutoCompact: true,
|
|
14528
|
+
contextStrategy: "hybrid",
|
|
14529
|
+
contextMode: "balanced",
|
|
14530
|
+
maxConcurrent: 10,
|
|
14531
|
+
logLevel: "info",
|
|
14532
|
+
auditLevel: "standard",
|
|
14533
|
+
indexOnStart: true,
|
|
14534
|
+
multiDiffSummaryThreshold: 5,
|
|
14535
|
+
maxIterations: 500,
|
|
14536
|
+
autoProceedMaxIterations: 50,
|
|
14537
|
+
enhanceDelayMs: 6e4,
|
|
14538
|
+
enhanceEnabled: true,
|
|
14539
|
+
enhanceLanguage: "original",
|
|
14540
|
+
debugStream: false,
|
|
14541
|
+
statuslineMode: "detailed",
|
|
14542
|
+
reasoningMode: "auto",
|
|
14543
|
+
reasoningEffort: "high",
|
|
14544
|
+
reasoningPreserve: false,
|
|
14545
|
+
thinkingWord: "thinking",
|
|
14546
|
+
thinkingWordEditing: false,
|
|
14547
|
+
thinkingWordDraft: "",
|
|
14548
|
+
cacheTtl: "default",
|
|
14549
|
+
configScope: "global",
|
|
14550
|
+
animationStyle: "rainbow"
|
|
14551
|
+
},
|
|
14552
|
+
statuslinePicker: {
|
|
14553
|
+
open: false,
|
|
14554
|
+
field: 0,
|
|
14555
|
+
hiddenItems: [],
|
|
14556
|
+
visibleChips: [],
|
|
14557
|
+
hint: void 0
|
|
14558
|
+
},
|
|
14559
|
+
pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14560
|
+
mcpPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
14561
|
+
toolsPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0, filter: void 0 },
|
|
14562
|
+
brainPanel: { open: false, riskLevel: "medium", log: [], selected: 0, hint: void 0 },
|
|
14563
|
+
helpPanel: { open: false, entries: [], selected: 0, filter: "", hint: void 0 },
|
|
14564
|
+
shadowPanel: { open: false, shadow: { activeId: null, running: false, model: "", intervalMs: 3e4 }, hint: void 0 },
|
|
14565
|
+
authPanel: AUTH_PANEL_INITIAL,
|
|
14566
|
+
projectPicker: {
|
|
14567
|
+
open: false,
|
|
14568
|
+
allItems: [],
|
|
14569
|
+
items: [],
|
|
14570
|
+
selected: 0,
|
|
14571
|
+
filter: "",
|
|
14572
|
+
hint: void 0
|
|
14573
|
+
},
|
|
14574
|
+
fKeyPicker: { open: false, selected: 0 },
|
|
14575
|
+
confirmQueue: [],
|
|
14576
|
+
enhance: null,
|
|
14577
|
+
enhanceEnabled,
|
|
14578
|
+
enhanceBusy: false,
|
|
14579
|
+
escConfirm: null,
|
|
14580
|
+
sendModePicker: null,
|
|
14581
|
+
contextChipVersion: 0,
|
|
14582
|
+
fleet: {},
|
|
14583
|
+
leader: {
|
|
14584
|
+
iterations: 0,
|
|
14585
|
+
toolCalls: 0,
|
|
14586
|
+
recentTools: [],
|
|
14587
|
+
currentTool: void 0,
|
|
14588
|
+
startedAt: Date.now(),
|
|
14589
|
+
lastEventAt: Date.now(),
|
|
14590
|
+
iterating: false
|
|
14591
|
+
},
|
|
14592
|
+
fleetCost: 0,
|
|
14593
|
+
fleetTokens: { input: 0, output: 0 },
|
|
14594
|
+
fleetConcurrency: 4,
|
|
14595
|
+
streamFleet: true,
|
|
14596
|
+
monitorOpen: false,
|
|
14597
|
+
agentsMonitorOpen: initialAgentsMonitorOpen ?? false,
|
|
14598
|
+
helpOpen: false,
|
|
14599
|
+
todosMonitorOpen: false,
|
|
14600
|
+
queuePanelOpen: false,
|
|
14601
|
+
processListOpen: false,
|
|
14602
|
+
auditPanelOpen: false,
|
|
14603
|
+
planPanelOpen: false,
|
|
14604
|
+
kanbanPanelOpen: false,
|
|
14605
|
+
goalPanelOpen: false,
|
|
14606
|
+
sessionsPanelOpen: false,
|
|
14607
|
+
sessionsPanel: { sessions: [], busy: false, selected: -1 },
|
|
14608
|
+
sessionResumeConfirm: null,
|
|
14609
|
+
collabSession: null,
|
|
14610
|
+
checkpoints: [],
|
|
14611
|
+
rewindOverlay: null,
|
|
14612
|
+
eternalStage: null,
|
|
14613
|
+
goalSummary: null,
|
|
14614
|
+
autoPhase: null,
|
|
14615
|
+
sddBoard: null,
|
|
14616
|
+
worktrees: {},
|
|
14617
|
+
worktreeMonitorOpen: false,
|
|
14618
|
+
coordinator: {
|
|
14619
|
+
goals: [],
|
|
14620
|
+
timeline: [],
|
|
14621
|
+
knowledgeCount: 0,
|
|
14622
|
+
monitorOpen: false,
|
|
14623
|
+
healthy: false
|
|
14624
|
+
},
|
|
14625
|
+
scrollOffset: 0,
|
|
14626
|
+
totalLines: 0,
|
|
14627
|
+
viewportRows: 0,
|
|
14628
|
+
pendingNewLines: 0,
|
|
14629
|
+
debugStreamStats: null,
|
|
14630
|
+
countdown: null
|
|
14631
|
+
};
|
|
14632
|
+
}
|
|
14633
|
+
var MB = 1024 * 1024;
|
|
14634
|
+
function defaultHeapLogPath() {
|
|
14635
|
+
return path9.join(wstackGlobalRoot(), "logs", "heap.jsonl");
|
|
14636
|
+
}
|
|
14637
|
+
function takeHeapSample() {
|
|
14638
|
+
const m = process.memoryUsage();
|
|
14639
|
+
const limit = v8.getHeapStatistics().heap_size_limit || 0;
|
|
14640
|
+
return {
|
|
14641
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14642
|
+
rss: m.rss,
|
|
14643
|
+
heapUsed: m.heapUsed,
|
|
14644
|
+
heapTotal: m.heapTotal,
|
|
14645
|
+
external: m.external,
|
|
14646
|
+
heapLimit: limit,
|
|
14647
|
+
load: limit > 0 ? m.heapUsed / limit : 0
|
|
14648
|
+
};
|
|
14649
|
+
}
|
|
14650
|
+
function startHeapWatchdog(opts = {}) {
|
|
14651
|
+
const sampleEveryMs = opts.sampleEveryMs ?? 6e4;
|
|
14652
|
+
const logEveryMs = opts.logEveryMs ?? 3e5;
|
|
14653
|
+
const logPath = opts.logPath ?? defaultHeapLogPath();
|
|
14654
|
+
const warnAt = opts.warnAt ?? 0.6;
|
|
14655
|
+
const criticalAt = opts.criticalAt ?? 0.85;
|
|
14656
|
+
const REARM_MARGIN = 0.05;
|
|
14657
|
+
let warnArmed = true;
|
|
14658
|
+
let criticalArmed = true;
|
|
14659
|
+
let lastLogAt = 0;
|
|
14660
|
+
let writeChain = Promise.resolve();
|
|
14661
|
+
let dirReady = false;
|
|
14662
|
+
const append = (line) => {
|
|
14663
|
+
writeChain = writeChain.then(async () => {
|
|
14664
|
+
if (!dirReady) {
|
|
14665
|
+
await fsp.mkdir(path9.dirname(logPath), { recursive: true });
|
|
14666
|
+
dirReady = true;
|
|
14667
|
+
}
|
|
14668
|
+
await fsp.appendFile(logPath, `${line}
|
|
14669
|
+
`, "utf8");
|
|
14670
|
+
}).catch(() => void 0);
|
|
14671
|
+
};
|
|
14672
|
+
const tick = () => {
|
|
14673
|
+
let userTimings = 0;
|
|
14674
|
+
try {
|
|
14675
|
+
userTimings = performance.getEntriesByType("mark").length + performance.getEntriesByType("measure").length;
|
|
14676
|
+
if (userTimings > 0) {
|
|
14677
|
+
performance.clearMarks();
|
|
14678
|
+
performance.clearMeasures();
|
|
14679
|
+
}
|
|
14680
|
+
} catch {
|
|
14681
|
+
}
|
|
14682
|
+
const s2 = takeHeapSample();
|
|
14683
|
+
if (s2.load >= criticalAt && criticalArmed) {
|
|
14684
|
+
criticalArmed = false;
|
|
14685
|
+
warnArmed = false;
|
|
14686
|
+
opts.onWarn?.(
|
|
14687
|
+
"critical",
|
|
14688
|
+
`Heap critical: ${Math.round(s2.heapUsed / MB)} MB of ~${Math.round(s2.heapLimit / MB)} MB V8 limit (${Math.round(s2.load * 100)}%). An out-of-memory crash is likely soon \u2014 finish/checkpoint work and restart the session. Diagnostics: ${logPath}`,
|
|
14689
|
+
s2
|
|
14690
|
+
);
|
|
14691
|
+
} else if (s2.load >= warnAt && warnArmed) {
|
|
14692
|
+
warnArmed = false;
|
|
14693
|
+
opts.onWarn?.(
|
|
14694
|
+
"warn",
|
|
14695
|
+
`Heap high: ${Math.round(s2.heapUsed / MB)} MB of ~${Math.round(s2.heapLimit / MB)} MB V8 limit (${Math.round(s2.load * 100)}%). Memory diagnostics are being recorded to ${logPath}`,
|
|
14696
|
+
s2
|
|
14697
|
+
);
|
|
14698
|
+
}
|
|
14699
|
+
if (!warnArmed && s2.load < warnAt - REARM_MARGIN) warnArmed = true;
|
|
14700
|
+
if (!criticalArmed && s2.load < criticalAt - REARM_MARGIN) criticalArmed = true;
|
|
14701
|
+
const due = Date.now() - lastLogAt >= logEveryMs;
|
|
14702
|
+
const crossed = s2.load >= warnAt;
|
|
14703
|
+
if (due || crossed) {
|
|
14704
|
+
lastLogAt = Date.now();
|
|
14705
|
+
let extras = {};
|
|
14706
|
+
try {
|
|
13857
14707
|
extras = opts.collectStats?.() ?? {};
|
|
13858
14708
|
} catch {
|
|
13859
14709
|
}
|
|
@@ -14603,7 +15453,7 @@ async function loadIndex(root) {
|
|
|
14603
15453
|
async function walk(root, rel, depth, out) {
|
|
14604
15454
|
if (out.length >= MAX_FILES_INDEXED) return;
|
|
14605
15455
|
if (depth > MAX_DEPTH) return;
|
|
14606
|
-
const dir = rel ?
|
|
15456
|
+
const dir = rel ? path9.join(root, rel) : root;
|
|
14607
15457
|
let entries;
|
|
14608
15458
|
try {
|
|
14609
15459
|
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
@@ -14702,7 +15552,7 @@ function useFileSearch(options) {
|
|
|
14702
15552
|
dispatch({ type: "pickerClose" });
|
|
14703
15553
|
return;
|
|
14704
15554
|
}
|
|
14705
|
-
const absPath =
|
|
15555
|
+
const absPath = path9.isAbsolute(picked) ? picked : path9.join(projectRoot, picked);
|
|
14706
15556
|
try {
|
|
14707
15557
|
const data = await fsp.readFile(absPath, "utf8");
|
|
14708
15558
|
const token = await builder.registerFile({
|
|
@@ -15265,13 +16115,152 @@ function usePickerKeys(host) {
|
|
|
15265
16115
|
}
|
|
15266
16116
|
return true;
|
|
15267
16117
|
}
|
|
15268
|
-
if (state.
|
|
16118
|
+
if (state.mcpPicker.open) {
|
|
15269
16119
|
if (key.escape) {
|
|
15270
|
-
dispatch({ type: "
|
|
16120
|
+
dispatch({ type: "mcpPickerClose" });
|
|
15271
16121
|
return true;
|
|
15272
16122
|
}
|
|
15273
16123
|
if (key.mouse?.kind === "wheel") {
|
|
15274
|
-
dispatch({ type: "
|
|
16124
|
+
dispatch({ type: "mcpPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16125
|
+
return true;
|
|
16126
|
+
}
|
|
16127
|
+
if (key.upArrow) {
|
|
16128
|
+
dispatch({ type: "mcpPickerMove", delta: -1 });
|
|
16129
|
+
return true;
|
|
16130
|
+
}
|
|
16131
|
+
if (key.downArrow) {
|
|
16132
|
+
dispatch({ type: "mcpPickerMove", delta: 1 });
|
|
16133
|
+
return true;
|
|
16134
|
+
}
|
|
16135
|
+
if (input === "r" || input === "R") {
|
|
16136
|
+
void host.onMcpPickerRestart?.();
|
|
16137
|
+
return true;
|
|
16138
|
+
}
|
|
16139
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16140
|
+
if (debouncedEnter(host)) return true;
|
|
16141
|
+
void host.onMcpPickerToggle?.();
|
|
16142
|
+
return true;
|
|
16143
|
+
}
|
|
16144
|
+
return true;
|
|
16145
|
+
}
|
|
16146
|
+
if (state.toolsPicker.open) {
|
|
16147
|
+
if (key.escape) {
|
|
16148
|
+
if (state.toolsPicker.filter) {
|
|
16149
|
+
dispatch({ type: "toolsPickerFilter", filter: "" });
|
|
16150
|
+
} else {
|
|
16151
|
+
dispatch({ type: "toolsPickerClose" });
|
|
16152
|
+
}
|
|
16153
|
+
return true;
|
|
16154
|
+
}
|
|
16155
|
+
if (key.mouse?.kind === "wheel") {
|
|
16156
|
+
dispatch({ type: "toolsPickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16157
|
+
return true;
|
|
16158
|
+
}
|
|
16159
|
+
if (key.upArrow) {
|
|
16160
|
+
dispatch({ type: "toolsPickerMove", delta: -1 });
|
|
16161
|
+
return true;
|
|
16162
|
+
}
|
|
16163
|
+
if (key.downArrow) {
|
|
16164
|
+
dispatch({ type: "toolsPickerMove", delta: 1 });
|
|
16165
|
+
return true;
|
|
16166
|
+
}
|
|
16167
|
+
if (key.leftArrow || key.rightArrow || isEnter) {
|
|
16168
|
+
if (debouncedEnter(host)) return true;
|
|
16169
|
+
void host.onToolsPickerToggle?.();
|
|
16170
|
+
return true;
|
|
16171
|
+
}
|
|
16172
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16173
|
+
dispatch({ type: "toolsPickerFilter", filter: (state.toolsPicker.filter ?? "") + input });
|
|
16174
|
+
return true;
|
|
16175
|
+
}
|
|
16176
|
+
if (key.backspace) {
|
|
16177
|
+
const cur = state.toolsPicker.filter ?? "";
|
|
16178
|
+
dispatch({ type: "toolsPickerFilter", filter: cur.length > 0 ? cur.slice(0, -1) : "" });
|
|
16179
|
+
return true;
|
|
16180
|
+
}
|
|
16181
|
+
return true;
|
|
16182
|
+
}
|
|
16183
|
+
if (state.helpPanel.open) {
|
|
16184
|
+
if (key.escape) {
|
|
16185
|
+
dispatch({ type: "helpClose" });
|
|
16186
|
+
return true;
|
|
16187
|
+
}
|
|
16188
|
+
if (key.mouse?.kind === "wheel") {
|
|
16189
|
+
dispatch({ type: "helpMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16190
|
+
return true;
|
|
16191
|
+
}
|
|
16192
|
+
if (key.upArrow) {
|
|
16193
|
+
dispatch({ type: "helpMove", delta: -1 });
|
|
16194
|
+
return true;
|
|
16195
|
+
}
|
|
16196
|
+
if (key.downArrow) {
|
|
16197
|
+
dispatch({ type: "helpMove", delta: 1 });
|
|
16198
|
+
return true;
|
|
16199
|
+
}
|
|
16200
|
+
if (key.backspace && state.helpPanel.filter) {
|
|
16201
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter.slice(0, -1) });
|
|
16202
|
+
return true;
|
|
16203
|
+
}
|
|
16204
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
16205
|
+
dispatch({ type: "helpFilter", filter: state.helpPanel.filter + input });
|
|
16206
|
+
return true;
|
|
16207
|
+
}
|
|
16208
|
+
if (isEnter) {
|
|
16209
|
+
if (debouncedEnter(host)) return true;
|
|
16210
|
+
host.onHelpPanelEnter?.();
|
|
16211
|
+
return true;
|
|
16212
|
+
}
|
|
16213
|
+
return true;
|
|
16214
|
+
}
|
|
16215
|
+
if (state.brainPanel.open) {
|
|
16216
|
+
if (key.escape) {
|
|
16217
|
+
dispatch({ type: "brainClose" });
|
|
16218
|
+
return true;
|
|
16219
|
+
}
|
|
16220
|
+
if (key.mouse?.kind === "wheel") {
|
|
16221
|
+
dispatch({ type: "brainMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
16222
|
+
return true;
|
|
16223
|
+
}
|
|
16224
|
+
if (key.upArrow) {
|
|
16225
|
+
dispatch({ type: "brainMove", delta: -1 });
|
|
16226
|
+
return true;
|
|
16227
|
+
}
|
|
16228
|
+
if (key.downArrow) {
|
|
16229
|
+
dispatch({ type: "brainMove", delta: 1 });
|
|
16230
|
+
return true;
|
|
16231
|
+
}
|
|
16232
|
+
if (key.leftArrow) {
|
|
16233
|
+
host.onBrainRiskChange?.(-1);
|
|
16234
|
+
return true;
|
|
16235
|
+
}
|
|
16236
|
+
if (key.rightArrow) {
|
|
16237
|
+
host.onBrainRiskChange?.(1);
|
|
16238
|
+
return true;
|
|
16239
|
+
}
|
|
16240
|
+
return true;
|
|
16241
|
+
}
|
|
16242
|
+
if (state.shadowPanel.open) {
|
|
16243
|
+
if (key.escape) {
|
|
16244
|
+
dispatch({ type: "shadowClose" });
|
|
16245
|
+
return true;
|
|
16246
|
+
}
|
|
16247
|
+
if (input === "s" || input === "S") {
|
|
16248
|
+
void host.onShadowStart?.();
|
|
16249
|
+
return true;
|
|
16250
|
+
}
|
|
16251
|
+
if (input === "t" || input === "T") {
|
|
16252
|
+
void host.onShadowStop?.();
|
|
16253
|
+
return true;
|
|
16254
|
+
}
|
|
16255
|
+
return true;
|
|
16256
|
+
}
|
|
16257
|
+
if (state.statuslinePicker.open) {
|
|
16258
|
+
if (key.escape) {
|
|
16259
|
+
dispatch({ type: "statuslineClose" });
|
|
16260
|
+
return true;
|
|
16261
|
+
}
|
|
16262
|
+
if (key.mouse?.kind === "wheel") {
|
|
16263
|
+
dispatch({ type: "statuslineFieldMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
15275
16264
|
return true;
|
|
15276
16265
|
}
|
|
15277
16266
|
if (key.upArrow) {
|
|
@@ -15452,6 +16441,120 @@ function usePickerKeys(host) {
|
|
|
15452
16441
|
[host]
|
|
15453
16442
|
);
|
|
15454
16443
|
}
|
|
16444
|
+
function useInputHistoryPersistence({
|
|
16445
|
+
projectRoot,
|
|
16446
|
+
inputHistory,
|
|
16447
|
+
dispatch
|
|
16448
|
+
}) {
|
|
16449
|
+
const inputHistoryStore = useMemo(() => {
|
|
16450
|
+
if (!projectRoot) return null;
|
|
16451
|
+
const file = resolveWstackPaths({ projectRoot }).projectInputHistory;
|
|
16452
|
+
return new InputHistoryStore(file, new DefaultSecretScrubber(), INPUT_HISTORY_DEFAULT_MAX);
|
|
16453
|
+
}, [projectRoot]);
|
|
16454
|
+
const inputHistoryLoadedRef = useRef(false);
|
|
16455
|
+
const inputHistorySaveTimerRef = useRef(void 0);
|
|
16456
|
+
const inputHistoryLastSavedRef = useRef("");
|
|
16457
|
+
useEffect(() => {
|
|
16458
|
+
if (!inputHistoryStore) return;
|
|
16459
|
+
let cancelled = false;
|
|
16460
|
+
inputHistoryStore.load().then((entries) => {
|
|
16461
|
+
if (cancelled) return;
|
|
16462
|
+
inputHistoryLoadedRef.current = true;
|
|
16463
|
+
inputHistoryLastSavedRef.current = JSON.stringify(entries);
|
|
16464
|
+
if (entries.length === 0) return;
|
|
16465
|
+
dispatch({ type: "setInputHistory", entries });
|
|
16466
|
+
}).catch(() => {
|
|
16467
|
+
if (!cancelled) inputHistoryLoadedRef.current = true;
|
|
16468
|
+
});
|
|
16469
|
+
return () => {
|
|
16470
|
+
cancelled = true;
|
|
16471
|
+
};
|
|
16472
|
+
}, [inputHistoryStore, dispatch]);
|
|
16473
|
+
useEffect(() => {
|
|
16474
|
+
if (!inputHistoryStore || !inputHistoryLoadedRef.current) return;
|
|
16475
|
+
const snapshot = JSON.stringify(inputHistory);
|
|
16476
|
+
if (snapshot === inputHistoryLastSavedRef.current) return;
|
|
16477
|
+
if (inputHistorySaveTimerRef.current) clearTimeout(inputHistorySaveTimerRef.current);
|
|
16478
|
+
inputHistorySaveTimerRef.current = setTimeout(() => {
|
|
16479
|
+
inputHistoryLastSavedRef.current = snapshot;
|
|
16480
|
+
inputHistoryStore.save(inputHistory).catch(() => {
|
|
16481
|
+
});
|
|
16482
|
+
}, 200);
|
|
16483
|
+
return () => {
|
|
16484
|
+
if (inputHistorySaveTimerRef.current) clearTimeout(inputHistorySaveTimerRef.current);
|
|
16485
|
+
};
|
|
16486
|
+
}, [inputHistory, inputHistoryStore]);
|
|
16487
|
+
}
|
|
16488
|
+
function buildModePickerOptions(result) {
|
|
16489
|
+
return toModeOptions(result.modes, result.activeId);
|
|
16490
|
+
}
|
|
16491
|
+
function useModePicker({
|
|
16492
|
+
dispatch,
|
|
16493
|
+
getModes
|
|
16494
|
+
}) {
|
|
16495
|
+
const openModePicker = useCallback(async () => {
|
|
16496
|
+
if (!getModes) return;
|
|
16497
|
+
const result = await getModes();
|
|
16498
|
+
const options = buildModePickerOptions(result);
|
|
16499
|
+
dispatch({ type: "modePickerOpen", modes: options });
|
|
16500
|
+
}, [dispatch, getModes]);
|
|
16501
|
+
return { openModePicker };
|
|
16502
|
+
}
|
|
16503
|
+
function buildPromptPickerPayload(all, recentSlugs) {
|
|
16504
|
+
const entries = all.map((e) => ({
|
|
16505
|
+
slug: e.slug,
|
|
16506
|
+
title: e.title,
|
|
16507
|
+
description: e.description,
|
|
16508
|
+
category: e.category,
|
|
16509
|
+
source: e.source,
|
|
16510
|
+
content: e.content,
|
|
16511
|
+
favorite: e.favorite
|
|
16512
|
+
}));
|
|
16513
|
+
const hasFavorites = entries.some((e) => e.favorite);
|
|
16514
|
+
const categories = [
|
|
16515
|
+
"all",
|
|
16516
|
+
...recentSlugs.length > 0 ? ["\u{1F558} recent"] : [],
|
|
16517
|
+
...hasFavorites ? ["\u2605 favorites"] : [],
|
|
16518
|
+
...Array.from(new Set(entries.map((e) => e.category))).sort()
|
|
16519
|
+
];
|
|
16520
|
+
return { all: entries, categories, recentSlugs };
|
|
16521
|
+
}
|
|
16522
|
+
function usePromptPicker({
|
|
16523
|
+
projectRoot,
|
|
16524
|
+
dispatch
|
|
16525
|
+
}) {
|
|
16526
|
+
const promptLoaderRef = useRef(null);
|
|
16527
|
+
const promptUsageRef = useRef(null);
|
|
16528
|
+
const getPromptLoader = useCallback(() => {
|
|
16529
|
+
if (!promptLoaderRef.current && projectRoot) {
|
|
16530
|
+
let bundledDir;
|
|
16531
|
+
try {
|
|
16532
|
+
const req = createRequire(import.meta.url);
|
|
16533
|
+
bundledDir = path9.join(
|
|
16534
|
+
path9.dirname(req.resolve("@wrongstack/core/package.json")),
|
|
16535
|
+
"data",
|
|
16536
|
+
"prompts"
|
|
16537
|
+
);
|
|
16538
|
+
} catch {
|
|
16539
|
+
bundledDir = void 0;
|
|
16540
|
+
}
|
|
16541
|
+
const paths = resolveWstackPaths({ projectRoot });
|
|
16542
|
+
promptLoaderRef.current = new DefaultPromptLoader({ paths, bundledDir });
|
|
16543
|
+
promptUsageRef.current = new PromptUsageStore(paths.promptUsage);
|
|
16544
|
+
}
|
|
16545
|
+
return promptLoaderRef.current;
|
|
16546
|
+
}, [projectRoot]);
|
|
16547
|
+
const openPromptPicker = useCallback(async () => {
|
|
16548
|
+
const loader = getPromptLoader();
|
|
16549
|
+
if (!loader) return;
|
|
16550
|
+
loader.invalidateCache();
|
|
16551
|
+
const all = await loader.list();
|
|
16552
|
+
const recentSlugs = (await promptUsageRef.current?.recent(50).catch(() => []))?.map((r) => r.slug) ?? [];
|
|
16553
|
+
const payload = buildPromptPickerPayload(all, recentSlugs);
|
|
16554
|
+
dispatch({ type: "promptPickerOpen", ...payload });
|
|
16555
|
+
}, [dispatch, getPromptLoader]);
|
|
16556
|
+
return { openPromptPicker };
|
|
16557
|
+
}
|
|
15455
16558
|
|
|
15456
16559
|
// src/queue-slash.ts
|
|
15457
16560
|
var USAGE = "Usage:\n /queue \u2014 list pending messages\n /queue list \u2014 same as /queue\n /queue clear \u2014 drop all pending messages\n /queue delete N M\u2026 \u2014 drop messages at 1-based positions\n /queue picker on|off \u2014 toggle the mid-run send-mode picker (queue/btw/steer)\n /queue picker \u2014 show whether the picker is on";
|
|
@@ -15615,6 +16718,90 @@ function useQueueManager({
|
|
|
15615
16718
|
};
|
|
15616
16719
|
}, [slashRegistry, stateRef, dispatch, getSettings, saveSettings, midRunSendPickerRef]);
|
|
15617
16720
|
}
|
|
16721
|
+
function statuslineHiddenDiffers(hookHidden, pickerHidden) {
|
|
16722
|
+
const currentHidden = new Set(hookHidden);
|
|
16723
|
+
const pickerHiddenSet = new Set(pickerHidden);
|
|
16724
|
+
return currentHidden.size !== pickerHiddenSet.size || pickerHidden.some((item) => !currentHidden.has(item)) || hookHidden.some((item) => !pickerHiddenSet.has(item));
|
|
16725
|
+
}
|
|
16726
|
+
function useStatuslineHiddenSync({
|
|
16727
|
+
pickerOpen,
|
|
16728
|
+
pickerHidden,
|
|
16729
|
+
hiddenItems,
|
|
16730
|
+
setHiddenItems
|
|
16731
|
+
}) {
|
|
16732
|
+
useEffect(() => {
|
|
16733
|
+
if (!pickerOpen) return;
|
|
16734
|
+
if (statuslineHiddenDiffers(hiddenItems, pickerHidden)) {
|
|
16735
|
+
setHiddenItems([...pickerHidden]);
|
|
16736
|
+
}
|
|
16737
|
+
}, [pickerHidden, pickerOpen, setHiddenItems, hiddenItems]);
|
|
16738
|
+
}
|
|
16739
|
+
function computeStreamChipActions(input) {
|
|
16740
|
+
const actions = [];
|
|
16741
|
+
const visible = new Set(input.visibleChipKeys);
|
|
16742
|
+
if (input.brainPromptNow && !input.brainPromptPrev) {
|
|
16743
|
+
actions.push({ type: "statuslineChipShow", key: "brain", expiresIn: 5 });
|
|
16744
|
+
} else if (!input.brainPromptNow && input.brainPromptPrev && visible.has("brain")) {
|
|
16745
|
+
actions.push({ type: "statuslineChipExpire", key: "brain" });
|
|
16746
|
+
}
|
|
16747
|
+
if (input.enhanceNow && !input.enhancePrev) {
|
|
16748
|
+
actions.push({ type: "statuslineChipShow", key: "enhance", expiresIn: 5 });
|
|
16749
|
+
} else if (!input.enhanceNow && input.enhancePrev && visible.has("enhance")) {
|
|
16750
|
+
actions.push({ type: "statuslineChipExpire", key: "enhance" });
|
|
16751
|
+
}
|
|
16752
|
+
return actions;
|
|
16753
|
+
}
|
|
16754
|
+
function computeExpiredChipKeys(chips, now = Date.now()) {
|
|
16755
|
+
return chips.filter((chip) => isChipExpired(chip, now)).map((chip) => chip.key);
|
|
16756
|
+
}
|
|
16757
|
+
function useStreamChipExpiration({
|
|
16758
|
+
brainPrompt,
|
|
16759
|
+
enhance,
|
|
16760
|
+
visibleChips,
|
|
16761
|
+
dispatch
|
|
16762
|
+
}) {
|
|
16763
|
+
const prevBrainPromptRef = useRef(brainPrompt);
|
|
16764
|
+
const prevEnhanceRef = useRef(enhance);
|
|
16765
|
+
useEffect(() => {
|
|
16766
|
+
const actions = computeStreamChipActions({
|
|
16767
|
+
brainPromptNow: !!brainPrompt,
|
|
16768
|
+
brainPromptPrev: !!prevBrainPromptRef.current,
|
|
16769
|
+
enhanceNow: !!enhance,
|
|
16770
|
+
enhancePrev: !!prevEnhanceRef.current,
|
|
16771
|
+
visibleChipKeys: visibleChips.map((chip) => chip.key)
|
|
16772
|
+
});
|
|
16773
|
+
for (const action of actions) dispatch(action);
|
|
16774
|
+
prevBrainPromptRef.current = brainPrompt;
|
|
16775
|
+
prevEnhanceRef.current = enhance;
|
|
16776
|
+
}, [brainPrompt, enhance, visibleChips, dispatch]);
|
|
16777
|
+
useEffect(() => {
|
|
16778
|
+
const interval = setInterval(() => {
|
|
16779
|
+
const expired = computeExpiredChipKeys(visibleChips, Date.now());
|
|
16780
|
+
for (const key of expired) {
|
|
16781
|
+
dispatch({ type: "statuslineChipExpire", key });
|
|
16782
|
+
}
|
|
16783
|
+
}, 3e4);
|
|
16784
|
+
return () => clearInterval(interval);
|
|
16785
|
+
}, [visibleChips, dispatch]);
|
|
16786
|
+
}
|
|
16787
|
+
function formatWorkingDirChip(workingDir, projectRoot) {
|
|
16788
|
+
if (!workingDir || workingDir === projectRoot) return void 0;
|
|
16789
|
+
const rel = path9.relative(projectRoot, workingDir) || ".";
|
|
16790
|
+
if (rel === ".") return void 0;
|
|
16791
|
+
return rel.replaceAll(path9.sep, "/");
|
|
16792
|
+
}
|
|
16793
|
+
function useWorkingDirChip(ctx, projectRoot) {
|
|
16794
|
+
const [workingDirChip, setWorkingDirChip] = useState(
|
|
16795
|
+
() => formatWorkingDirChip(ctx.workingDir, projectRoot)
|
|
16796
|
+
);
|
|
16797
|
+
useEffect(() => {
|
|
16798
|
+
setWorkingDirChip(formatWorkingDirChip(ctx.workingDir, projectRoot));
|
|
16799
|
+
return ctx.onWorkingDirChanged((newDir) => {
|
|
16800
|
+
setWorkingDirChip(formatWorkingDirChip(newDir, projectRoot));
|
|
16801
|
+
});
|
|
16802
|
+
}, [ctx, projectRoot]);
|
|
16803
|
+
return workingDirChip;
|
|
16804
|
+
}
|
|
15618
16805
|
function useStatuslineState(opts) {
|
|
15619
16806
|
const [liveModel, setLiveModel] = useState(opts.model);
|
|
15620
16807
|
const [liveProvider, setLiveProvider] = useState(opts.provider ?? "agent");
|
|
@@ -16227,6 +17414,12 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16227
17414
|
case "pluginPickerOpen":
|
|
16228
17415
|
dispatch({ type: "pluginPickerOpen" });
|
|
16229
17416
|
return true;
|
|
17417
|
+
case "mcpPickerOpen":
|
|
17418
|
+
dispatch({ type: "mcpPickerOpen" });
|
|
17419
|
+
return true;
|
|
17420
|
+
case "toolsPickerOpen":
|
|
17421
|
+
dispatch({ type: "toolsPickerOpen" });
|
|
17422
|
+
return true;
|
|
16230
17423
|
case "projectPickerOpen":
|
|
16231
17424
|
void openProjectPicker();
|
|
16232
17425
|
return true;
|
|
@@ -16239,6 +17432,24 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16239
17432
|
return true;
|
|
16240
17433
|
}
|
|
16241
17434
|
return false;
|
|
17435
|
+
case "brainOpen":
|
|
17436
|
+
if (deps.openBrainPanel) {
|
|
17437
|
+
void deps.openBrainPanel();
|
|
17438
|
+
return true;
|
|
17439
|
+
}
|
|
17440
|
+
return false;
|
|
17441
|
+
case "shadowOpen":
|
|
17442
|
+
if (deps.openShadowPanel) {
|
|
17443
|
+
void deps.openShadowPanel();
|
|
17444
|
+
return true;
|
|
17445
|
+
}
|
|
17446
|
+
return false;
|
|
17447
|
+
case "helpOpen":
|
|
17448
|
+
if (deps.openHelpPanel) {
|
|
17449
|
+
void deps.openHelpPanel();
|
|
17450
|
+
return true;
|
|
17451
|
+
}
|
|
17452
|
+
return false;
|
|
16242
17453
|
case "toggleMonitor":
|
|
16243
17454
|
dispatch({ type: "toggleMonitor" });
|
|
16244
17455
|
return true;
|
|
@@ -16267,6 +17478,22 @@ function createPanelOpenDispatcher(deps) {
|
|
|
16267
17478
|
};
|
|
16268
17479
|
}
|
|
16269
17480
|
|
|
17481
|
+
// src/submit-history.ts
|
|
17482
|
+
function shouldPushSubmittedHistory(raw) {
|
|
17483
|
+
const trimmed = raw.trim();
|
|
17484
|
+
if (!trimmed) return { push: false, route: "empty", trimmed };
|
|
17485
|
+
if (trimmed === "/image" || trimmed === "/paste-image") {
|
|
17486
|
+
return { push: true, route: "paste-image", trimmed };
|
|
17487
|
+
}
|
|
17488
|
+
if (trimmed === "/prompt" || trimmed === "/prompts-browse") {
|
|
17489
|
+
return { push: true, route: "prompt-picker", trimmed };
|
|
17490
|
+
}
|
|
17491
|
+
if (trimmed.startsWith("/")) {
|
|
17492
|
+
return { push: true, route: "slash", trimmed };
|
|
17493
|
+
}
|
|
17494
|
+
return { push: true, route: "normal", trimmed };
|
|
17495
|
+
}
|
|
17496
|
+
|
|
16270
17497
|
// src/paste-accumulator.ts
|
|
16271
17498
|
var BEGIN = "[200~";
|
|
16272
17499
|
var END = "[201~";
|
|
@@ -16295,7 +17522,7 @@ function feedPaste(accum, input) {
|
|
|
16295
17522
|
if (accum === null && !input.includes(BEGIN)) {
|
|
16296
17523
|
if (input.startsWith("[") && !input.startsWith(BEGIN) && !input.startsWith(END)) {
|
|
16297
17524
|
if (PARTIAL_ANSI_RE.test(input)) {
|
|
16298
|
-
return { accum:
|
|
17525
|
+
return { accum: null, complete: null };
|
|
16299
17526
|
}
|
|
16300
17527
|
return null;
|
|
16301
17528
|
}
|
|
@@ -16338,7 +17565,7 @@ function renderList3() {
|
|
|
16338
17565
|
}
|
|
16339
17566
|
|
|
16340
17567
|
// src/slash-command-search.ts
|
|
16341
|
-
var
|
|
17568
|
+
var CATEGORY_ORDER2 = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
16342
17569
|
function buildSlashCommandMatches(entries, rawQuery) {
|
|
16343
17570
|
const query = normalizeSlashQuery(rawQuery);
|
|
16344
17571
|
const matches = [];
|
|
@@ -16349,7 +17576,7 @@ function buildSlashCommandMatches(entries, rawQuery) {
|
|
|
16349
17576
|
}
|
|
16350
17577
|
return matches.sort((a, b) => {
|
|
16351
17578
|
if (a.rank !== b.rank) return a.rank - b.rank;
|
|
16352
|
-
const catDiff =
|
|
17579
|
+
const catDiff = CATEGORY_ORDER2.indexOf(a.category) - CATEGORY_ORDER2.indexOf(b.category);
|
|
16353
17580
|
if (catDiff !== 0) return catDiff;
|
|
16354
17581
|
return a.name.localeCompare(b.name);
|
|
16355
17582
|
}).map(({ rank: _rank, ...match }) => match);
|
|
@@ -16546,24 +17773,38 @@ function rehydrateHistory(messages, startId, toolCalls) {
|
|
|
16546
17773
|
outputTokens: tc.outputTokens,
|
|
16547
17774
|
outputLines: tc.outputLines
|
|
16548
17775
|
});
|
|
17776
|
+
const pushAssistantText = (parts) => {
|
|
17777
|
+
const text = parts.join("").trim();
|
|
17778
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
17779
|
+
parts.length = 0;
|
|
17780
|
+
};
|
|
16549
17781
|
for (const msg of messages) {
|
|
16550
17782
|
if (msg.role === "system") continue;
|
|
16551
|
-
const text = textOf(msg).trim();
|
|
16552
17783
|
if (msg.role === "user") {
|
|
17784
|
+
const text = textOf(msg).trim();
|
|
16553
17785
|
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
16554
17786
|
continue;
|
|
16555
17787
|
}
|
|
16556
17788
|
if (msg.role === "assistant") {
|
|
16557
|
-
if (
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
17789
|
+
if (!Array.isArray(msg.content)) {
|
|
17790
|
+
const text = textOf(msg).trim();
|
|
17791
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
17792
|
+
continue;
|
|
17793
|
+
}
|
|
17794
|
+
const textParts = [];
|
|
17795
|
+
for (const block of msg.content) {
|
|
17796
|
+
if (block.type === "text") {
|
|
17797
|
+
textParts.push(block.text);
|
|
17798
|
+
continue;
|
|
16565
17799
|
}
|
|
17800
|
+
if (block.type !== "tool_use") continue;
|
|
17801
|
+
pushAssistantText(textParts);
|
|
17802
|
+
const tc = toolCallsById.get(block.id);
|
|
17803
|
+
if (!tc) continue;
|
|
17804
|
+
entries.push(toolEntryFor(tc));
|
|
17805
|
+
consumed.add(block.id);
|
|
16566
17806
|
}
|
|
17807
|
+
pushAssistantText(textParts);
|
|
16567
17808
|
}
|
|
16568
17809
|
}
|
|
16569
17810
|
if (toolCalls) {
|
|
@@ -16663,6 +17904,16 @@ function App({
|
|
|
16663
17904
|
saveSettings,
|
|
16664
17905
|
getPluginItems,
|
|
16665
17906
|
onPluginToggle,
|
|
17907
|
+
getMcpServers,
|
|
17908
|
+
onMcpToggle,
|
|
17909
|
+
onMcpRestart,
|
|
17910
|
+
getToolsItems,
|
|
17911
|
+
onToolToggle,
|
|
17912
|
+
getBrainData,
|
|
17913
|
+
onBrainRiskLevel,
|
|
17914
|
+
getShadowData,
|
|
17915
|
+
onShadowStart,
|
|
17916
|
+
onShadowStop,
|
|
16666
17917
|
authHost,
|
|
16667
17918
|
predictNext,
|
|
16668
17919
|
onSuggestionsParsed,
|
|
@@ -16683,458 +17934,239 @@ function App({
|
|
|
16683
17934
|
interruptController,
|
|
16684
17935
|
statuslineHiddenItems,
|
|
16685
17936
|
setStatuslineHiddenItems,
|
|
16686
|
-
saveStatuslineHiddenItems,
|
|
16687
|
-
agentsMonitorController,
|
|
16688
|
-
initialGoal,
|
|
16689
|
-
initialAsk,
|
|
16690
|
-
sessionsDir,
|
|
16691
|
-
modeLabel,
|
|
16692
|
-
getModeLabel,
|
|
16693
|
-
getModes,
|
|
16694
|
-
registerDebugStreamCallback,
|
|
16695
|
-
restoreDebugStreamCallback,
|
|
16696
|
-
restoredToolCalls,
|
|
16697
|
-
getProjectPickerItems,
|
|
16698
|
-
onProjectSelect,
|
|
16699
|
-
requestExit,
|
|
16700
|
-
getLiveSessions,
|
|
16701
|
-
onSwitchToSession,
|
|
16702
|
-
initialAgentsMonitorOpen,
|
|
16703
|
-
onPanelOpen,
|
|
16704
|
-
subscribeCoordinatorEvents,
|
|
16705
|
-
onCoordinatorStart,
|
|
16706
|
-
onCoordinatorStop,
|
|
16707
|
-
// Reserved for the coordinator monitor panel: terminal-driven task discovery/claim.
|
|
16708
|
-
onCoordinatorTasks: _onCoordinatorTasks,
|
|
16709
|
-
onCoordinatorClaim: _onCoordinatorClaim,
|
|
16710
|
-
coordinatorRunning = false,
|
|
16711
|
-
clientId
|
|
16712
|
-
}) {
|
|
16713
|
-
const { exit } = useApp();
|
|
16714
|
-
const { stdout } = useStdout();
|
|
16715
|
-
const {
|
|
16716
|
-
liveModel,
|
|
16717
|
-
setLiveModel,
|
|
16718
|
-
liveProvider,
|
|
16719
|
-
setLiveProvider,
|
|
16720
|
-
activeMaxContext,
|
|
16721
|
-
setActiveMaxContext,
|
|
16722
|
-
yoloLive,
|
|
16723
|
-
setYoloLive,
|
|
16724
|
-
autonomyLive,
|
|
16725
|
-
setAutonomyLive,
|
|
16726
|
-
liveModeLabel,
|
|
16727
|
-
setLiveModeLabel,
|
|
16728
|
-
hiddenItems,
|
|
16729
|
-
setHiddenItems,
|
|
16730
|
-
sessionCount,
|
|
16731
|
-
setSessionCount
|
|
16732
|
-
} = useStatuslineState({
|
|
16733
|
-
model,
|
|
16734
|
-
provider,
|
|
16735
|
-
effectiveMaxContext,
|
|
16736
|
-
yolo,
|
|
16737
|
-
getAutonomy,
|
|
16738
|
-
modeLabel,
|
|
16739
|
-
statuslineHiddenItems
|
|
16740
|
-
});
|
|
16741
|
-
const hiddenItemsRef = useRef(hiddenItems);
|
|
16742
|
-
hiddenItemsRef.current = hiddenItems;
|
|
16743
|
-
const prevBranchRef = useRef(null);
|
|
16744
|
-
const [indexState, setIndexState] = useState(() => getIndexState());
|
|
16745
|
-
useEffect(() => {
|
|
16746
|
-
setIndexState(getIndexState());
|
|
16747
|
-
return onIndexStateChange((next) => setIndexState(next));
|
|
16748
|
-
}, []);
|
|
16749
|
-
const [breakerCountdown, setBreakerCountdown] = useState(
|
|
16750
|
-
() => getProcessRegistry().getBreakerCountdown()
|
|
16751
|
-
);
|
|
16752
|
-
useEffect(() => {
|
|
16753
|
-
const s2 = getSettings?.();
|
|
16754
|
-
if (s2) {
|
|
16755
|
-
getProcessRegistry().setBreakerConfig({
|
|
16756
|
-
enabled: s2.breakerEnabled ?? false,
|
|
16757
|
-
autoKillResetMs: s2.breakerAutoKillResetMs ?? 6e4
|
|
16758
|
-
});
|
|
16759
|
-
}
|
|
16760
|
-
return getProcessRegistry().onBreakerCountdownChange((snap) => setBreakerCountdown(snap));
|
|
16761
|
-
}, [getSettings]);
|
|
16762
|
-
const breakerArmed = breakerCountdown !== null;
|
|
16763
|
-
useEffect(() => {
|
|
16764
|
-
if (!breakerArmed) return;
|
|
16765
|
-
const t = setInterval(
|
|
16766
|
-
() => setBreakerCountdown(getProcessRegistry().getBreakerCountdown()),
|
|
16767
|
-
1e3
|
|
16768
|
-
);
|
|
16769
|
-
return () => clearInterval(t);
|
|
16770
|
-
}, [breakerArmed]);
|
|
16771
|
-
useEffect(() => {
|
|
16772
|
-
setHiddenItems([...statuslineHiddenItems]);
|
|
16773
|
-
}, [statuslineHiddenItems]);
|
|
16774
|
-
useEffect(() => {
|
|
16775
|
-
setStatuslineHiddenItems(hiddenItems);
|
|
16776
|
-
saveStatuslineHiddenItems(hiddenItems).catch?.((err) => {
|
|
16777
|
-
console.error("[statusline] failed to persist hidden items:", err);
|
|
16778
|
-
});
|
|
16779
|
-
}, [setStatuslineHiddenItems, saveStatuslineHiddenItems, hiddenItems]);
|
|
16780
|
-
const projectRoot = agent.ctx.projectRoot;
|
|
16781
|
-
const promptLoaderRef = useRef(null);
|
|
16782
|
-
const promptUsageRef = useRef(null);
|
|
16783
|
-
const refreshGoalSummary = useCallback(() => {
|
|
16784
|
-
if (!projectRoot) return;
|
|
16785
|
-
const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;
|
|
16786
|
-
loadGoal(goalPath).then((goal) => {
|
|
16787
|
-
if (!goal) {
|
|
16788
|
-
dispatch({ type: "goalSummary", summary: null });
|
|
16789
|
-
return;
|
|
16790
|
-
}
|
|
16791
|
-
const lastEntry = goal.journal?.[goal.journal.length - 1];
|
|
16792
|
-
dispatch({
|
|
16793
|
-
type: "goalSummary",
|
|
16794
|
-
summary: {
|
|
16795
|
-
goal: goal.goal,
|
|
16796
|
-
refinedGoal: goal.refinedGoal,
|
|
16797
|
-
goalState: goal.goalState ?? "active",
|
|
16798
|
-
iterations: goal.iterations,
|
|
16799
|
-
progress: goal.progress,
|
|
16800
|
-
progressNote: goal.progressNote,
|
|
16801
|
-
progressTrend: goal.progressTrend,
|
|
16802
|
-
deliverables: goal.deliverables,
|
|
16803
|
-
lastTask: lastEntry?.task,
|
|
16804
|
-
lastStatus: lastEntry?.status
|
|
16805
|
-
}
|
|
16806
|
-
});
|
|
16807
|
-
}).catch(() => {
|
|
16808
|
-
});
|
|
16809
|
-
}, [projectRoot]);
|
|
16810
|
-
useEffect(() => {
|
|
16811
|
-
refreshGoalSummary();
|
|
16812
|
-
}, [refreshGoalSummary]);
|
|
16813
|
-
const restoredEntries = (() => {
|
|
16814
|
-
const msgs = agent.ctx.messages;
|
|
16815
|
-
if (!msgs || msgs.length === 0) return [];
|
|
16816
|
-
const visible = msgs.filter((m) => m.role !== "system");
|
|
16817
|
-
if (visible.length === 0) return [];
|
|
16818
|
-
return rehydrateHistory(
|
|
16819
|
-
visible,
|
|
16820
|
-
/* startId */
|
|
16821
|
-
1,
|
|
16822
|
-
restoredToolCalls
|
|
16823
|
-
);
|
|
16824
|
-
})();
|
|
16825
|
-
const initialNextId = 1 + restoredEntries.length;
|
|
16826
|
-
const [state, dispatch] = useReducer(reducer, {
|
|
16827
|
-
entries: [
|
|
16828
|
-
...banner ? [
|
|
16829
|
-
{
|
|
16830
|
-
id: 0,
|
|
16831
|
-
kind: "banner",
|
|
16832
|
-
version: appVersion ?? "dev",
|
|
16833
|
-
provider: provider ?? "agent",
|
|
16834
|
-
model,
|
|
16835
|
-
cwd: agent.ctx.cwd,
|
|
16836
|
-
family,
|
|
16837
|
-
keyTail
|
|
16838
|
-
}
|
|
16839
|
-
] : [],
|
|
16840
|
-
...restoredEntries
|
|
16841
|
-
],
|
|
16842
|
-
historyGen: 0,
|
|
16843
|
-
buffer: "",
|
|
16844
|
-
cursor: 0,
|
|
16845
|
-
streamingText: "",
|
|
16846
|
-
toolStream: null,
|
|
16847
|
-
status: "idle",
|
|
16848
|
-
interrupts: 0,
|
|
16849
|
-
steeringPending: false,
|
|
16850
|
-
steerSnapshot: null,
|
|
16851
|
-
hint: "",
|
|
16852
|
-
brain: { state: "idle" },
|
|
16853
|
-
brainPrompt: null,
|
|
16854
|
-
nextId: initialNextId,
|
|
16855
|
-
picker: { open: false, query: "", matches: [], selected: 0 },
|
|
16856
|
-
slashPicker: { open: false, query: "", matches: [], selected: 0 },
|
|
16857
|
-
runningTools: /* @__PURE__ */ new Map(),
|
|
16858
|
-
queue: [],
|
|
16859
|
-
nextQueueId: 1,
|
|
16860
|
-
inputHistory: [],
|
|
16861
|
-
historyIndex: 0,
|
|
16862
|
-
historyDraft: "",
|
|
16863
|
-
modelPicker: {
|
|
16864
|
-
open: false,
|
|
16865
|
-
step: "provider",
|
|
16866
|
-
providerOptions: [],
|
|
16867
|
-
modelOptions: [],
|
|
16868
|
-
filteredOptions: [],
|
|
16869
|
-
selected: 0,
|
|
16870
|
-
searchQuery: ""
|
|
16871
|
-
},
|
|
16872
|
-
autonomyPicker: { open: false, options: [], selected: 0 },
|
|
16873
|
-
modePicker: { open: false, modes: [], selected: 0 },
|
|
16874
|
-
designPicker: { open: false, kits: [], selected: 0, stack: "web" },
|
|
16875
|
-
promptPicker: {
|
|
16876
|
-
open: false,
|
|
16877
|
-
all: [],
|
|
16878
|
-
categories: [],
|
|
16879
|
-
recentSlugs: [],
|
|
16880
|
-
catIndex: 0,
|
|
16881
|
-
selected: 0
|
|
16882
|
-
},
|
|
16883
|
-
resumePicker: {
|
|
16884
|
-
open: false,
|
|
16885
|
-
sessions: [],
|
|
16886
|
-
selected: 0,
|
|
16887
|
-
busy: false,
|
|
16888
|
-
hint: void 0,
|
|
16889
|
-
error: void 0
|
|
16890
|
-
},
|
|
16891
|
-
settingsPicker: {
|
|
16892
|
-
open: false,
|
|
16893
|
-
field: 0,
|
|
16894
|
-
lastSettingsField: 0,
|
|
16895
|
-
filter: "",
|
|
16896
|
-
mode: "off",
|
|
16897
|
-
delayMs: 0,
|
|
16898
|
-
titleAnimation: true,
|
|
16899
|
-
yolo: false,
|
|
16900
|
-
streamFleet: true,
|
|
16901
|
-
chime: false,
|
|
16902
|
-
confirmExit: true,
|
|
16903
|
-
nextPrediction: false,
|
|
16904
|
-
featureMcp: true,
|
|
16905
|
-
featurePlugins: true,
|
|
16906
|
-
featureMemory: true,
|
|
16907
|
-
featureSkills: true,
|
|
16908
|
-
featureModelsRegistry: true,
|
|
16909
|
-
tokenSavingTier: "off",
|
|
16910
|
-
allowOutsideProjectRoot: true,
|
|
16911
|
-
contextAutoCompact: true,
|
|
16912
|
-
contextStrategy: "hybrid",
|
|
16913
|
-
contextMode: "balanced",
|
|
16914
|
-
maxConcurrent: 10,
|
|
16915
|
-
logLevel: "info",
|
|
16916
|
-
auditLevel: "standard",
|
|
16917
|
-
indexOnStart: true,
|
|
16918
|
-
multiDiffSummaryThreshold: 5,
|
|
16919
|
-
maxIterations: 500,
|
|
16920
|
-
autoProceedMaxIterations: 50,
|
|
16921
|
-
enhanceDelayMs: 6e4,
|
|
16922
|
-
enhanceEnabled: true,
|
|
16923
|
-
enhanceLanguage: "original",
|
|
16924
|
-
debugStream: false,
|
|
16925
|
-
statuslineMode: "detailed",
|
|
16926
|
-
reasoningMode: "auto",
|
|
16927
|
-
reasoningEffort: "high",
|
|
16928
|
-
reasoningPreserve: false,
|
|
16929
|
-
thinkingWord: "thinking",
|
|
16930
|
-
thinkingWordEditing: false,
|
|
16931
|
-
thinkingWordDraft: "",
|
|
16932
|
-
cacheTtl: "default",
|
|
16933
|
-
configScope: "global",
|
|
16934
|
-
animationStyle: "rainbow"
|
|
16935
|
-
},
|
|
16936
|
-
statuslinePicker: { open: false, field: 0, hiddenItems: [], visibleChips: [], hint: void 0 },
|
|
16937
|
-
pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
16938
|
-
authPanel: AUTH_PANEL_INITIAL,
|
|
16939
|
-
projectPicker: {
|
|
16940
|
-
open: false,
|
|
16941
|
-
allItems: [],
|
|
16942
|
-
items: [],
|
|
16943
|
-
selected: 0,
|
|
16944
|
-
filter: "",
|
|
16945
|
-
hint: void 0
|
|
16946
|
-
},
|
|
16947
|
-
fKeyPicker: { open: false, selected: 0 },
|
|
16948
|
-
confirmQueue: [],
|
|
16949
|
-
enhance: null,
|
|
16950
|
-
enhanceEnabled,
|
|
16951
|
-
enhanceBusy: false,
|
|
16952
|
-
escConfirm: null,
|
|
16953
|
-
sendModePicker: null,
|
|
16954
|
-
contextChipVersion: 0,
|
|
16955
|
-
fleet: {},
|
|
16956
|
-
leader: {
|
|
16957
|
-
iterations: 0,
|
|
16958
|
-
toolCalls: 0,
|
|
16959
|
-
recentTools: [],
|
|
16960
|
-
currentTool: void 0,
|
|
16961
|
-
startedAt: Date.now(),
|
|
16962
|
-
lastEventAt: Date.now(),
|
|
16963
|
-
iterating: false
|
|
16964
|
-
},
|
|
16965
|
-
fleetCost: 0,
|
|
16966
|
-
fleetTokens: { input: 0, output: 0 },
|
|
16967
|
-
fleetConcurrency: 4,
|
|
16968
|
-
streamFleet: true,
|
|
16969
|
-
monitorOpen: false,
|
|
16970
|
-
agentsMonitorOpen: initialAgentsMonitorOpen ?? false,
|
|
16971
|
-
helpOpen: false,
|
|
16972
|
-
todosMonitorOpen: false,
|
|
16973
|
-
queuePanelOpen: false,
|
|
16974
|
-
processListOpen: false,
|
|
16975
|
-
auditPanelOpen: false,
|
|
16976
|
-
planPanelOpen: false,
|
|
16977
|
-
kanbanPanelOpen: false,
|
|
16978
|
-
goalPanelOpen: false,
|
|
16979
|
-
sessionsPanelOpen: false,
|
|
16980
|
-
sessionsPanel: { sessions: [], busy: false, selected: -1 },
|
|
16981
|
-
sessionResumeConfirm: null,
|
|
16982
|
-
collabSession: null,
|
|
16983
|
-
checkpoints: [],
|
|
16984
|
-
rewindOverlay: null,
|
|
16985
|
-
eternalStage: null,
|
|
16986
|
-
goalSummary: null,
|
|
16987
|
-
autoPhase: null,
|
|
16988
|
-
sddBoard: null,
|
|
16989
|
-
worktrees: {},
|
|
16990
|
-
worktreeMonitorOpen: false,
|
|
16991
|
-
coordinator: {
|
|
16992
|
-
goals: [],
|
|
16993
|
-
timeline: [],
|
|
16994
|
-
knowledgeCount: 0,
|
|
16995
|
-
monitorOpen: false,
|
|
16996
|
-
healthy: false
|
|
16997
|
-
},
|
|
16998
|
-
scrollOffset: 0,
|
|
16999
|
-
totalLines: 0,
|
|
17000
|
-
viewportRows: 0,
|
|
17001
|
-
pendingNewLines: 0,
|
|
17002
|
-
debugStreamStats: null,
|
|
17003
|
-
countdown: null
|
|
17937
|
+
saveStatuslineHiddenItems,
|
|
17938
|
+
agentsMonitorController,
|
|
17939
|
+
initialGoal,
|
|
17940
|
+
initialAsk,
|
|
17941
|
+
sessionsDir,
|
|
17942
|
+
modeLabel,
|
|
17943
|
+
getModeLabel,
|
|
17944
|
+
getModes,
|
|
17945
|
+
registerDebugStreamCallback,
|
|
17946
|
+
restoreDebugStreamCallback,
|
|
17947
|
+
restoredToolCalls,
|
|
17948
|
+
getProjectPickerItems,
|
|
17949
|
+
onProjectSelect,
|
|
17950
|
+
requestExit,
|
|
17951
|
+
getLiveSessions,
|
|
17952
|
+
onSwitchToSession,
|
|
17953
|
+
initialAgentsMonitorOpen,
|
|
17954
|
+
onPanelOpen,
|
|
17955
|
+
subscribeCoordinatorEvents,
|
|
17956
|
+
onCoordinatorStart,
|
|
17957
|
+
onCoordinatorStop,
|
|
17958
|
+
// Reserved for the coordinator monitor panel: terminal-driven task discovery/claim.
|
|
17959
|
+
onCoordinatorTasks: _onCoordinatorTasks,
|
|
17960
|
+
onCoordinatorClaim: _onCoordinatorClaim,
|
|
17961
|
+
coordinatorRunning = false,
|
|
17962
|
+
clientId
|
|
17963
|
+
}) {
|
|
17964
|
+
const { exit } = useApp();
|
|
17965
|
+
const { stdout } = useStdout();
|
|
17966
|
+
const {
|
|
17967
|
+
liveModel,
|
|
17968
|
+
setLiveModel,
|
|
17969
|
+
liveProvider,
|
|
17970
|
+
setLiveProvider,
|
|
17971
|
+
activeMaxContext,
|
|
17972
|
+
setActiveMaxContext,
|
|
17973
|
+
yoloLive,
|
|
17974
|
+
setYoloLive,
|
|
17975
|
+
autonomyLive,
|
|
17976
|
+
setAutonomyLive,
|
|
17977
|
+
liveModeLabel,
|
|
17978
|
+
setLiveModeLabel,
|
|
17979
|
+
hiddenItems,
|
|
17980
|
+
setHiddenItems,
|
|
17981
|
+
sessionCount,
|
|
17982
|
+
setSessionCount
|
|
17983
|
+
} = useStatuslineState({
|
|
17984
|
+
model,
|
|
17985
|
+
provider,
|
|
17986
|
+
effectiveMaxContext,
|
|
17987
|
+
yolo,
|
|
17988
|
+
getAutonomy,
|
|
17989
|
+
modeLabel,
|
|
17990
|
+
statuslineHiddenItems
|
|
17004
17991
|
});
|
|
17005
|
-
const
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
}, [projectRoot]);
|
|
17010
|
-
const inputHistoryLoadedRef = useRef(false);
|
|
17011
|
-
const inputHistorySaveTimerRef = useRef(void 0);
|
|
17012
|
-
const inputHistoryLastSavedRef = useRef("");
|
|
17992
|
+
const hiddenItemsRef = useRef(hiddenItems);
|
|
17993
|
+
hiddenItemsRef.current = hiddenItems;
|
|
17994
|
+
const prevBranchRef = useRef(null);
|
|
17995
|
+
const [indexState, setIndexState] = useState(() => getIndexState());
|
|
17013
17996
|
useEffect(() => {
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
if (entries.length === 0) return;
|
|
17021
|
-
dispatch({ type: "setInputHistory", entries });
|
|
17022
|
-
}).catch(() => {
|
|
17023
|
-
if (!cancelled) inputHistoryLoadedRef.current = true;
|
|
17024
|
-
});
|
|
17025
|
-
return () => {
|
|
17026
|
-
cancelled = true;
|
|
17027
|
-
};
|
|
17028
|
-
}, [inputHistoryStore]);
|
|
17997
|
+
setIndexState(getIndexState());
|
|
17998
|
+
return onIndexStateChange((next) => setIndexState(next));
|
|
17999
|
+
}, []);
|
|
18000
|
+
const [breakerCountdown, setBreakerCountdown] = useState(
|
|
18001
|
+
() => getProcessRegistry().getBreakerCountdown()
|
|
18002
|
+
);
|
|
17029
18003
|
useEffect(() => {
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
inputHistoryLastSavedRef.current = snapshot;
|
|
17036
|
-
inputHistoryStore.save(state.inputHistory).catch(() => {
|
|
18004
|
+
const s2 = getSettings?.();
|
|
18005
|
+
if (s2) {
|
|
18006
|
+
getProcessRegistry().setBreakerConfig({
|
|
18007
|
+
enabled: s2.breakerEnabled ?? false,
|
|
18008
|
+
autoKillResetMs: s2.breakerAutoKillResetMs ?? 6e4
|
|
17037
18009
|
});
|
|
17038
|
-
}, 200);
|
|
17039
|
-
return () => {
|
|
17040
|
-
if (inputHistorySaveTimerRef.current) clearTimeout(inputHistorySaveTimerRef.current);
|
|
17041
|
-
};
|
|
17042
|
-
}, [state.inputHistory, inputHistoryStore]);
|
|
17043
|
-
const getPromptLoader = () => {
|
|
17044
|
-
if (!promptLoaderRef.current && projectRoot) {
|
|
17045
|
-
let bundledDir;
|
|
17046
|
-
try {
|
|
17047
|
-
const req = createRequire(import.meta.url);
|
|
17048
|
-
bundledDir = path6.join(
|
|
17049
|
-
path6.dirname(req.resolve("@wrongstack/core/package.json")),
|
|
17050
|
-
"data",
|
|
17051
|
-
"prompts"
|
|
17052
|
-
);
|
|
17053
|
-
} catch {
|
|
17054
|
-
bundledDir = void 0;
|
|
17055
|
-
}
|
|
17056
|
-
const paths = resolveWstackPaths({ projectRoot });
|
|
17057
|
-
promptLoaderRef.current = new DefaultPromptLoader({ paths, bundledDir });
|
|
17058
|
-
promptUsageRef.current = new PromptUsageStore(paths.promptUsage);
|
|
17059
18010
|
}
|
|
17060
|
-
return
|
|
17061
|
-
};
|
|
17062
|
-
const
|
|
17063
|
-
const loader = getPromptLoader();
|
|
17064
|
-
if (!loader) return;
|
|
17065
|
-
loader.invalidateCache();
|
|
17066
|
-
const all = await loader.list();
|
|
17067
|
-
const entries = all.map((e) => ({
|
|
17068
|
-
slug: e.slug,
|
|
17069
|
-
title: e.title,
|
|
17070
|
-
description: e.description,
|
|
17071
|
-
category: e.category,
|
|
17072
|
-
source: e.source,
|
|
17073
|
-
content: e.content,
|
|
17074
|
-
favorite: e.favorite
|
|
17075
|
-
}));
|
|
17076
|
-
const recentSlugs = (await promptUsageRef.current?.recent(50).catch(() => []))?.map((r) => r.slug) ?? [];
|
|
17077
|
-
const hasFavorites = entries.some((e) => e.favorite);
|
|
17078
|
-
const cats = [
|
|
17079
|
-
"all",
|
|
17080
|
-
...recentSlugs.length > 0 ? ["\u{1F558} recent"] : [],
|
|
17081
|
-
...hasFavorites ? ["\u2605 favorites"] : [],
|
|
17082
|
-
...Array.from(new Set(entries.map((e) => e.category))).sort()
|
|
17083
|
-
];
|
|
17084
|
-
dispatch({ type: "promptPickerOpen", all: entries, categories: cats, recentSlugs });
|
|
17085
|
-
};
|
|
17086
|
-
const openModePicker = useCallback(async () => {
|
|
17087
|
-
if (!getModes) return;
|
|
17088
|
-
const result = await getModes();
|
|
17089
|
-
const options = toModeOptions(result.modes, result.activeId);
|
|
17090
|
-
dispatch({ type: "modePickerOpen", modes: options });
|
|
17091
|
-
}, [getModes]);
|
|
18011
|
+
return getProcessRegistry().onBreakerCountdownChange((snap) => setBreakerCountdown(snap));
|
|
18012
|
+
}, [getSettings]);
|
|
18013
|
+
const breakerArmed = breakerCountdown !== null;
|
|
17092
18014
|
useEffect(() => {
|
|
17093
|
-
if (
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
}
|
|
17101
|
-
}
|
|
17102
|
-
}, [
|
|
17103
|
-
state.statuslinePicker.hiddenItems,
|
|
17104
|
-
state.statuslinePicker.open,
|
|
17105
|
-
setHiddenItems,
|
|
17106
|
-
hiddenItems
|
|
17107
|
-
]);
|
|
17108
|
-
const prevBrainPromptRef = useRef(state.brainPrompt);
|
|
17109
|
-
const prevEnhanceRef = useRef(state.enhance);
|
|
18015
|
+
if (!breakerArmed) return;
|
|
18016
|
+
const t = setInterval(
|
|
18017
|
+
() => setBreakerCountdown(getProcessRegistry().getBreakerCountdown()),
|
|
18018
|
+
1e3
|
|
18019
|
+
);
|
|
18020
|
+
return () => clearInterval(t);
|
|
18021
|
+
}, [breakerArmed]);
|
|
17110
18022
|
useEffect(() => {
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
18023
|
+
setHiddenItems([...statuslineHiddenItems]);
|
|
18024
|
+
}, [statuslineHiddenItems]);
|
|
18025
|
+
useEffect(() => {
|
|
18026
|
+
setStatuslineHiddenItems(hiddenItems);
|
|
18027
|
+
saveStatuslineHiddenItems(hiddenItems).catch?.((err) => {
|
|
18028
|
+
console.error(
|
|
18029
|
+
JSON.stringify({
|
|
18030
|
+
level: "error",
|
|
18031
|
+
event: "statusline.persist_hidden_failed",
|
|
18032
|
+
message: err instanceof Error ? err.message : String(err),
|
|
18033
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
18034
|
+
})
|
|
18035
|
+
);
|
|
18036
|
+
});
|
|
18037
|
+
}, [setStatuslineHiddenItems, saveStatuslineHiddenItems, hiddenItems]);
|
|
18038
|
+
const projectRoot = agent.ctx.projectRoot;
|
|
18039
|
+
const promptUsageRef = useRef(null);
|
|
18040
|
+
const refreshGoalSummary = useCallback(() => {
|
|
18041
|
+
if (!projectRoot) return;
|
|
18042
|
+
const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;
|
|
18043
|
+
loadGoal(goalPath).then((goal) => {
|
|
18044
|
+
if (!goal) {
|
|
18045
|
+
dispatch({ type: "goalSummary", summary: null });
|
|
18046
|
+
return;
|
|
17124
18047
|
}
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
18048
|
+
const lastEntry = goal.journal?.[goal.journal.length - 1];
|
|
18049
|
+
dispatch({
|
|
18050
|
+
type: "goalSummary",
|
|
18051
|
+
summary: {
|
|
18052
|
+
goal: goal.goal,
|
|
18053
|
+
refinedGoal: goal.refinedGoal,
|
|
18054
|
+
goalState: goal.goalState ?? "active",
|
|
18055
|
+
iterations: goal.iterations,
|
|
18056
|
+
progress: goal.progress,
|
|
18057
|
+
progressNote: goal.progressNote,
|
|
18058
|
+
progressTrend: goal.progressTrend,
|
|
18059
|
+
deliverables: goal.deliverables,
|
|
18060
|
+
lastTask: lastEntry?.task,
|
|
18061
|
+
lastStatus: lastEntry?.status
|
|
18062
|
+
}
|
|
18063
|
+
});
|
|
18064
|
+
}).catch(() => {
|
|
18065
|
+
});
|
|
18066
|
+
}, [projectRoot]);
|
|
17128
18067
|
useEffect(() => {
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
18068
|
+
refreshGoalSummary();
|
|
18069
|
+
}, [refreshGoalSummary]);
|
|
18070
|
+
const restoredEntries = buildRestoredEntries(agent.ctx.messages, restoredToolCalls);
|
|
18071
|
+
const [state, dispatch] = useReducer(
|
|
18072
|
+
reducer,
|
|
18073
|
+
createInitialState({
|
|
18074
|
+
banner,
|
|
18075
|
+
appVersion,
|
|
18076
|
+
provider,
|
|
18077
|
+
model,
|
|
18078
|
+
cwd: agent.ctx.cwd,
|
|
18079
|
+
family,
|
|
18080
|
+
keyTail,
|
|
18081
|
+
restoredEntries,
|
|
18082
|
+
enhanceEnabled,
|
|
18083
|
+
initialAgentsMonitorOpen
|
|
18084
|
+
})
|
|
18085
|
+
);
|
|
18086
|
+
useInputHistoryPersistence({
|
|
18087
|
+
projectRoot,
|
|
18088
|
+
inputHistory: state.inputHistory,
|
|
18089
|
+
dispatch
|
|
18090
|
+
});
|
|
18091
|
+
const { openPromptPicker } = usePromptPicker({ projectRoot, dispatch });
|
|
18092
|
+
const { openModePicker } = useModePicker({ dispatch, getModes });
|
|
18093
|
+
const openBrainPanel = React5.useCallback(() => {
|
|
18094
|
+
if (!getBrainData) return;
|
|
18095
|
+
const data = getBrainData();
|
|
18096
|
+
dispatch({ type: "brainOpen", riskLevel: data.riskLevel, log: data.log });
|
|
18097
|
+
}, [getBrainData]);
|
|
18098
|
+
const changeBrainRisk = React5.useCallback(
|
|
18099
|
+
(delta) => {
|
|
18100
|
+
dispatch({ type: "brainRiskChange", delta });
|
|
18101
|
+
},
|
|
18102
|
+
[]
|
|
18103
|
+
);
|
|
18104
|
+
const prevRiskRef = React5.useRef(state.brainPanel.riskLevel);
|
|
18105
|
+
React5.useEffect(() => {
|
|
18106
|
+
if (!state.brainPanel.open) return;
|
|
18107
|
+
const current = state.brainPanel.riskLevel;
|
|
18108
|
+
if (current !== prevRiskRef.current && onBrainRiskLevel) {
|
|
18109
|
+
prevRiskRef.current = current;
|
|
18110
|
+
const err = onBrainRiskLevel(current);
|
|
18111
|
+
if (err) dispatch({ type: "brainHint", text: err });
|
|
18112
|
+
else dispatch({ type: "brainHint", text: `Risk ceiling \u2192 ${current.toUpperCase()}` });
|
|
18113
|
+
}
|
|
18114
|
+
}, [state.brainPanel.riskLevel, state.brainPanel.open, onBrainRiskLevel]);
|
|
18115
|
+
const openShadowPanel = React5.useCallback(() => {
|
|
18116
|
+
if (!getShadowData) return;
|
|
18117
|
+
const data = getShadowData();
|
|
18118
|
+
dispatch({ type: "shadowOpen", shadow: data });
|
|
18119
|
+
}, [getShadowData]);
|
|
18120
|
+
const handleShadowStart = React5.useCallback(async () => {
|
|
18121
|
+
if (!onShadowStart) return;
|
|
18122
|
+
dispatch({ type: "shadowHint", text: "Starting Shadow Agent\u2026" });
|
|
18123
|
+
try {
|
|
18124
|
+
const err = await onShadowStart();
|
|
18125
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18126
|
+
else {
|
|
18127
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18128
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent started." });
|
|
17134
18129
|
}
|
|
17135
|
-
}
|
|
17136
|
-
|
|
17137
|
-
|
|
18130
|
+
} catch (e) {
|
|
18131
|
+
dispatch({ type: "shadowHint", text: `Failed to start: ${toErrorMessage(e)}` });
|
|
18132
|
+
}
|
|
18133
|
+
}, [onShadowStart, getShadowData]);
|
|
18134
|
+
const handleShadowStop = React5.useCallback(async () => {
|
|
18135
|
+
if (!onShadowStop) return;
|
|
18136
|
+
dispatch({ type: "shadowHint", text: "Stopping Shadow Agent\u2026" });
|
|
18137
|
+
try {
|
|
18138
|
+
const err = await onShadowStop();
|
|
18139
|
+
if (err) dispatch({ type: "shadowHint", text: err });
|
|
18140
|
+
else {
|
|
18141
|
+
if (getShadowData) dispatch({ type: "shadowUpdate", shadow: getShadowData() });
|
|
18142
|
+
dispatch({ type: "shadowHint", text: "Shadow Agent stopped." });
|
|
18143
|
+
}
|
|
18144
|
+
} catch (e) {
|
|
18145
|
+
dispatch({ type: "shadowHint", text: `Failed to stop: ${toErrorMessage(e)}` });
|
|
18146
|
+
}
|
|
18147
|
+
}, [onShadowStop, getShadowData]);
|
|
18148
|
+
const openHelpPanel = React5.useCallback(() => {
|
|
18149
|
+
const entries = Array.from(slashRegistry.listWithOwner()).map(({ cmd, owner }) => ({
|
|
18150
|
+
name: owner === "core" ? cmd.name : `${owner}:${cmd.name}`,
|
|
18151
|
+
description: cmd.description,
|
|
18152
|
+
category: cmd.category ?? "App",
|
|
18153
|
+
aliases: cmd.aliases,
|
|
18154
|
+
argsHint: cmd.argsHint
|
|
18155
|
+
}));
|
|
18156
|
+
dispatch({ type: "helpOpen", entries });
|
|
18157
|
+
}, []);
|
|
18158
|
+
useStatuslineHiddenSync({
|
|
18159
|
+
pickerOpen: state.statuslinePicker.open,
|
|
18160
|
+
pickerHidden: state.statuslinePicker.hiddenItems,
|
|
18161
|
+
hiddenItems,
|
|
18162
|
+
setHiddenItems: (items) => setHiddenItems(items)
|
|
18163
|
+
});
|
|
18164
|
+
useStreamChipExpiration({
|
|
18165
|
+
brainPrompt: state.brainPrompt,
|
|
18166
|
+
enhance: state.enhance,
|
|
18167
|
+
visibleChips: state.statuslinePicker.visibleChips,
|
|
18168
|
+
dispatch
|
|
18169
|
+
});
|
|
17138
18170
|
useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch);
|
|
17139
18171
|
const builderRef = useRef(null);
|
|
17140
18172
|
if (builderRef.current === null) {
|
|
@@ -17146,23 +18178,10 @@ function App({
|
|
|
17146
18178
|
const lastEnterAtRef = useRef(0);
|
|
17147
18179
|
const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
|
|
17148
18180
|
const projectName = React5.useMemo(() => {
|
|
17149
|
-
const base =
|
|
17150
|
-
return base && base !==
|
|
18181
|
+
const base = path9.basename(projectRoot);
|
|
18182
|
+
return base && base !== path9.sep ? base : void 0;
|
|
17151
18183
|
}, [projectRoot]);
|
|
17152
|
-
const
|
|
17153
|
-
const ctx = agent.ctx;
|
|
17154
|
-
if (ctx.workingDir && ctx.workingDir !== projectRoot) {
|
|
17155
|
-
return path6.relative(projectRoot, ctx.workingDir) || ".";
|
|
17156
|
-
}
|
|
17157
|
-
return void 0;
|
|
17158
|
-
});
|
|
17159
|
-
React5.useEffect(() => {
|
|
17160
|
-
const ctx = agent.ctx;
|
|
17161
|
-
return ctx.onWorkingDirChanged((newDir) => {
|
|
17162
|
-
const rel = path6.relative(projectRoot, newDir) || ".";
|
|
17163
|
-
setWorkingDirChip(rel === "." ? void 0 : rel);
|
|
17164
|
-
});
|
|
17165
|
-
}, [agent.ctx, projectRoot]);
|
|
18184
|
+
const workingDirChip = useWorkingDirChip(agent.ctx, projectRoot);
|
|
17166
18185
|
const liveSettings = getSettings?.();
|
|
17167
18186
|
const liveStatuslineMode = liveSettings?.statuslineMode ?? "detailed";
|
|
17168
18187
|
const liveAnimationStyle = liveSettings?.animationStyle ?? "rainbow";
|
|
@@ -17192,6 +18211,7 @@ function App({
|
|
|
17192
18211
|
const streamSegmentsRef = useRef([]);
|
|
17193
18212
|
const pendingDeltaRef = useRef("");
|
|
17194
18213
|
const flushTimerRef = useRef(null);
|
|
18214
|
+
const assistantCommittedThisRunRef = useRef(false);
|
|
17195
18215
|
const stateRef = useRef(state);
|
|
17196
18216
|
stateRef.current = state;
|
|
17197
18217
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
@@ -17220,7 +18240,7 @@ function App({
|
|
|
17220
18240
|
[statuslineHiddenForPicker]
|
|
17221
18241
|
);
|
|
17222
18242
|
const [mouseMode, setMouseMode] = useState(mouse);
|
|
17223
|
-
const pickerOverlayOpen = state.modelPicker.open || state.autonomyPicker.open || state.modePicker.open || state.designPicker.open || state.settingsPicker.open || state.projectPicker.open || state.slashPicker.open || state.statuslinePicker.open || state.fKeyPicker.open || state.authPanel.open || state.picker.open;
|
|
18243
|
+
const pickerOverlayOpen = state.modelPicker.open || state.autonomyPicker.open || state.modePicker.open || state.designPicker.open || state.settingsPicker.open || state.projectPicker.open || state.slashPicker.open || state.statuslinePicker.open || state.pluginPicker.open || state.mcpPicker.open || state.toolsPicker.open || state.brainPanel.open || state.helpPanel.open || state.shadowPanel.open || state.fKeyPicker.open || state.authPanel.open || state.picker.open;
|
|
17224
18244
|
const mouseTrackingOn = mouseMode || pickerOverlayOpen;
|
|
17225
18245
|
const mouseWrittenRef = useRef(false);
|
|
17226
18246
|
useEffect(() => {
|
|
@@ -17564,15 +18584,16 @@ function App({
|
|
|
17564
18584
|
const fleetCounts = useMemo(() => {
|
|
17565
18585
|
const entries = Object.values(state.fleet);
|
|
17566
18586
|
if (entries.length === 0) return void 0;
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17570
|
-
|
|
17571
|
-
|
|
17572
|
-
|
|
17573
|
-
|
|
17574
|
-
|
|
17575
|
-
|
|
18587
|
+
const running = entries.filter((e) => e.status === "running").length;
|
|
18588
|
+
if (running === 0) return void 0;
|
|
18589
|
+
return { running, idle: 0, pending: 0, completed: 0 };
|
|
18590
|
+
}, [state.fleet]);
|
|
18591
|
+
const visibleSubagentCount = fleetCounts?.running ?? 0;
|
|
18592
|
+
const hasVisibleFleetPanel = useMemo(() => {
|
|
18593
|
+
for (const e of Object.values(state.fleet)) {
|
|
18594
|
+
if (e.status === "running") return true;
|
|
18595
|
+
}
|
|
18596
|
+
return false;
|
|
17576
18597
|
}, [state.fleet]);
|
|
17577
18598
|
const entriesWithLeader = useMemo(() => {
|
|
17578
18599
|
const leaderEntry = {
|
|
@@ -18034,7 +19055,10 @@ function App({
|
|
|
18034
19055
|
openProjectPicker,
|
|
18035
19056
|
openStatuslinePicker,
|
|
18036
19057
|
openAuthPanel: authPanelController.openAuthPanel,
|
|
18037
|
-
openModePicker
|
|
19058
|
+
openModePicker,
|
|
19059
|
+
openBrainPanel,
|
|
19060
|
+
openShadowPanel,
|
|
19061
|
+
openHelpPanel
|
|
18038
19062
|
});
|
|
18039
19063
|
onPanelOpen.current = dispatcher;
|
|
18040
19064
|
return () => {
|
|
@@ -18046,7 +19070,10 @@ function App({
|
|
|
18046
19070
|
openProjectPicker,
|
|
18047
19071
|
openStatuslinePicker,
|
|
18048
19072
|
authPanelController.openAuthPanel,
|
|
18049
|
-
openModePicker
|
|
19073
|
+
openModePicker,
|
|
19074
|
+
openBrainPanel,
|
|
19075
|
+
openShadowPanel,
|
|
19076
|
+
openHelpPanel
|
|
18050
19077
|
]);
|
|
18051
19078
|
useEffect(() => {
|
|
18052
19079
|
if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
|
|
@@ -18132,6 +19159,73 @@ function App({
|
|
|
18132
19159
|
});
|
|
18133
19160
|
}
|
|
18134
19161
|
}, [onPluginToggle]);
|
|
19162
|
+
const refreshMcpPicker = React5.useCallback(() => {
|
|
19163
|
+
if (!getMcpServers) return;
|
|
19164
|
+
dispatch({ type: "mcpPickerSetItems", items: getMcpServers() });
|
|
19165
|
+
}, [getMcpServers]);
|
|
19166
|
+
useEffect(() => {
|
|
19167
|
+
if (!state.mcpPicker.open) return;
|
|
19168
|
+
refreshMcpPicker();
|
|
19169
|
+
}, [state.mcpPicker.open, refreshMcpPicker]);
|
|
19170
|
+
const toggleSelectedMcpServer = React5.useCallback(async () => {
|
|
19171
|
+
if (!onMcpToggle) return;
|
|
19172
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19173
|
+
if (!selected) return;
|
|
19174
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19175
|
+
try {
|
|
19176
|
+
const result = await onMcpToggle(selected.name);
|
|
19177
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19178
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19179
|
+
} catch (err) {
|
|
19180
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19181
|
+
dispatch({
|
|
19182
|
+
type: "mcpPickerHint",
|
|
19183
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19184
|
+
});
|
|
19185
|
+
}
|
|
19186
|
+
}, [onMcpToggle]);
|
|
19187
|
+
const restartSelectedMcpServer = React5.useCallback(async () => {
|
|
19188
|
+
if (!onMcpRestart) return;
|
|
19189
|
+
const selected = stateRef.current.mcpPicker.items[stateRef.current.mcpPicker.selected];
|
|
19190
|
+
if (!selected) return;
|
|
19191
|
+
dispatch({ type: "mcpPickerBusy", busy: true });
|
|
19192
|
+
try {
|
|
19193
|
+
const result = await onMcpRestart(selected.name);
|
|
19194
|
+
dispatch({ type: "mcpPickerSetItems", items: result.items });
|
|
19195
|
+
dispatch({ type: "mcpPickerHint", text: result.error ?? result.message });
|
|
19196
|
+
} catch (err) {
|
|
19197
|
+
dispatch({ type: "mcpPickerBusy", busy: false });
|
|
19198
|
+
dispatch({
|
|
19199
|
+
type: "mcpPickerHint",
|
|
19200
|
+
text: `Failed to restart ${selected.name}: ${toErrorMessage(err)}`
|
|
19201
|
+
});
|
|
19202
|
+
}
|
|
19203
|
+
}, [onMcpRestart]);
|
|
19204
|
+
const refreshToolsPicker = React5.useCallback(() => {
|
|
19205
|
+
if (!getToolsItems) return;
|
|
19206
|
+
dispatch({ type: "toolsPickerSetItems", items: getToolsItems() });
|
|
19207
|
+
}, [getToolsItems]);
|
|
19208
|
+
useEffect(() => {
|
|
19209
|
+
if (!state.toolsPicker.open) return;
|
|
19210
|
+
refreshToolsPicker();
|
|
19211
|
+
}, [state.toolsPicker.open, refreshToolsPicker]);
|
|
19212
|
+
const toggleSelectedTool = React5.useCallback(async () => {
|
|
19213
|
+
if (!onToolToggle) return;
|
|
19214
|
+
const selected = stateRef.current.toolsPicker.items[stateRef.current.toolsPicker.selected];
|
|
19215
|
+
if (!selected) return;
|
|
19216
|
+
dispatch({ type: "toolsPickerBusy", busy: true });
|
|
19217
|
+
try {
|
|
19218
|
+
const result = await onToolToggle(selected.name);
|
|
19219
|
+
dispatch({ type: "toolsPickerSetItems", items: result.items });
|
|
19220
|
+
dispatch({ type: "toolsPickerHint", text: result.error ?? result.message });
|
|
19221
|
+
} catch (err) {
|
|
19222
|
+
dispatch({ type: "toolsPickerBusy", busy: false });
|
|
19223
|
+
dispatch({
|
|
19224
|
+
type: "toolsPickerHint",
|
|
19225
|
+
text: `Failed to toggle ${selected.name}: ${toErrorMessage(err)}`
|
|
19226
|
+
});
|
|
19227
|
+
}
|
|
19228
|
+
}, [onToolToggle]);
|
|
18135
19229
|
const autoSubmitStreakRef = useRef(0);
|
|
18136
19230
|
const autoSubmitCapWarnedRef = useRef(false);
|
|
18137
19231
|
const [nextStepsRecheck, setNextStepsRecheck] = useState(0);
|
|
@@ -18808,12 +19902,15 @@ Available chords:
|
|
|
18808
19902
|
for (const seg of segments) {
|
|
18809
19903
|
if (seg.text.trim()) {
|
|
18810
19904
|
dispatch({ type: "addEntry", entry: { kind: seg.kind, text: seg.text } });
|
|
19905
|
+
if (seg.kind === "assistant") assistantCommittedThisRunRef.current = true;
|
|
18811
19906
|
}
|
|
18812
19907
|
}
|
|
18813
19908
|
if (segments.length === 0 && text.trim()) {
|
|
18814
19909
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text } });
|
|
19910
|
+
assistantCommittedThisRunRef.current = true;
|
|
18815
19911
|
} else if (segments.length === 0 && fallbackText.trim()) {
|
|
18816
19912
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: fallbackText } });
|
|
19913
|
+
assistantCommittedThisRunRef.current = true;
|
|
18817
19914
|
}
|
|
18818
19915
|
});
|
|
18819
19916
|
const offConfirmNeeded = events.on("tool.confirm_needed", (e) => {
|
|
@@ -19223,6 +20320,18 @@ Available chords:
|
|
|
19223
20320
|
}
|
|
19224
20321
|
},
|
|
19225
20322
|
onPluginPickerToggle: toggleSelectedPlugin,
|
|
20323
|
+
onMcpPickerToggle: toggleSelectedMcpServer,
|
|
20324
|
+
onMcpPickerRestart: restartSelectedMcpServer,
|
|
20325
|
+
onToolsPickerToggle: toggleSelectedTool,
|
|
20326
|
+
onHelpPanelEnter: () => {
|
|
20327
|
+
const entry = state.helpPanel.entries[state.helpPanel.selected];
|
|
20328
|
+
if (!entry) return;
|
|
20329
|
+
dispatch({ type: "helpClose" });
|
|
20330
|
+
submitRef.current(`/${entry.name}`);
|
|
20331
|
+
},
|
|
20332
|
+
onBrainRiskChange: changeBrainRisk,
|
|
20333
|
+
onShadowStart: handleShadowStart,
|
|
20334
|
+
onShadowStop: handleShadowStop,
|
|
19226
20335
|
onAuthEnter: authPanelController.onAuthEnter,
|
|
19227
20336
|
onAuthBack: authPanelController.onAuthBack,
|
|
19228
20337
|
onAuthShortcut: authPanelController.onAuthShortcut,
|
|
@@ -20193,9 +21302,7 @@ Available chords:
|
|
|
20193
21302
|
}
|
|
20194
21303
|
});
|
|
20195
21304
|
}
|
|
20196
|
-
|
|
20197
|
-
(entry) => entry.kind === "assistant"
|
|
20198
|
-
).length;
|
|
21305
|
+
assistantCommittedThisRunRef.current = false;
|
|
20199
21306
|
const result = await agent.run(routed.blocks, { signal: ctrl.signal });
|
|
20200
21307
|
const lingering = streamingTextRef.current;
|
|
20201
21308
|
const lingeringSegments = streamSegmentsRef.current;
|
|
@@ -20215,7 +21322,13 @@ Available chords:
|
|
|
20215
21322
|
}
|
|
20216
21323
|
} else if (lingering.trim()) {
|
|
20217
21324
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
|
|
20218
|
-
} else if (result.status === "done" && result.finalText?.trim() &&
|
|
21325
|
+
} else if (result.status === "done" && result.finalText?.trim() && // Only recover finalText when no assistant entry was committed by the
|
|
21326
|
+
// per-iteration `provider.response` flush during this run. Checked via
|
|
21327
|
+
// a synchronous ref, NOT `stateRef` — the flush's `addEntry` dispatch
|
|
21328
|
+
// isn't reflected in `stateRef` yet when we resume here, so a
|
|
21329
|
+
// state-based count would read stale and re-commit the final reply,
|
|
21330
|
+
// rendering it twice.
|
|
21331
|
+
!assistantCommittedThisRunRef.current) {
|
|
20219
21332
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
|
|
20220
21333
|
}
|
|
20221
21334
|
if (result.status === "aborted") {
|
|
@@ -20407,7 +21520,10 @@ Available chords:
|
|
|
20407
21520
|
autoSubmitCapWarnedRef.current = false;
|
|
20408
21521
|
dispatch({ type: "scrollToBottom" });
|
|
20409
21522
|
const pushSubmittedHistory = () => {
|
|
20410
|
-
|
|
21523
|
+
const decision = shouldPushSubmittedHistory(trimmed);
|
|
21524
|
+
if (decision.push) {
|
|
21525
|
+
dispatch({ type: "historyPush", text: decision.trimmed });
|
|
21526
|
+
}
|
|
20411
21527
|
};
|
|
20412
21528
|
if (trimmed === "/image" || trimmed === "/paste-image") {
|
|
20413
21529
|
pushSubmittedHistory();
|
|
@@ -20944,6 +22060,50 @@ ${content}
|
|
|
20944
22060
|
hint: state.pluginPicker.hint
|
|
20945
22061
|
}
|
|
20946
22062
|
) : null,
|
|
22063
|
+
state.mcpPicker.open ? /* @__PURE__ */ jsx(
|
|
22064
|
+
McpPicker,
|
|
22065
|
+
{
|
|
22066
|
+
items: state.mcpPicker.items,
|
|
22067
|
+
selected: state.mcpPicker.selected,
|
|
22068
|
+
busy: state.mcpPicker.busy,
|
|
22069
|
+
hint: state.mcpPicker.hint
|
|
22070
|
+
}
|
|
22071
|
+
) : null,
|
|
22072
|
+
state.toolsPicker.open ? /* @__PURE__ */ jsx(
|
|
22073
|
+
ToolsPicker,
|
|
22074
|
+
{
|
|
22075
|
+
items: state.toolsPicker.items,
|
|
22076
|
+
selected: state.toolsPicker.selected,
|
|
22077
|
+
busy: state.toolsPicker.busy,
|
|
22078
|
+
hint: state.toolsPicker.hint,
|
|
22079
|
+
filter: state.toolsPicker.filter
|
|
22080
|
+
}
|
|
22081
|
+
) : null,
|
|
22082
|
+
state.brainPanel.open ? /* @__PURE__ */ jsx(
|
|
22083
|
+
BrainPanel,
|
|
22084
|
+
{
|
|
22085
|
+
riskLevel: state.brainPanel.riskLevel,
|
|
22086
|
+
log: state.brainPanel.log,
|
|
22087
|
+
selected: state.brainPanel.selected,
|
|
22088
|
+
hint: state.brainPanel.hint
|
|
22089
|
+
}
|
|
22090
|
+
) : null,
|
|
22091
|
+
state.helpPanel.open ? /* @__PURE__ */ jsx(
|
|
22092
|
+
HelpPanel,
|
|
22093
|
+
{
|
|
22094
|
+
entries: state.helpPanel.entries,
|
|
22095
|
+
filter: state.helpPanel.filter,
|
|
22096
|
+
selected: state.helpPanel.selected,
|
|
22097
|
+
hint: state.helpPanel.hint
|
|
22098
|
+
}
|
|
22099
|
+
) : null,
|
|
22100
|
+
state.shadowPanel.open ? /* @__PURE__ */ jsx(
|
|
22101
|
+
ShadowPanel,
|
|
22102
|
+
{
|
|
22103
|
+
shadow: state.shadowPanel.shadow,
|
|
22104
|
+
hint: state.shadowPanel.hint
|
|
22105
|
+
}
|
|
22106
|
+
) : null,
|
|
20947
22107
|
state.authPanel.open ? /* @__PURE__ */ jsx(AuthPanel, { panel: state.authPanel }) : null,
|
|
20948
22108
|
state.projectPicker.open ? /* @__PURE__ */ jsx(
|
|
20949
22109
|
ProjectPicker,
|
|
@@ -21157,7 +22317,7 @@ ${content}
|
|
|
21157
22317
|
brain: state.brain,
|
|
21158
22318
|
projectName,
|
|
21159
22319
|
workingDir: workingDirChip,
|
|
21160
|
-
subagentCount:
|
|
22320
|
+
subagentCount: visibleSubagentCount,
|
|
21161
22321
|
processCount: getProcessRegistry().activeCount,
|
|
21162
22322
|
hiddenItems,
|
|
21163
22323
|
mode: liveStatuslineMode,
|
|
@@ -21255,7 +22415,7 @@ ${content}
|
|
|
21255
22415
|
onCoordinatorStop: onCoordinatorStop ?? void 0,
|
|
21256
22416
|
coordinatorRunning
|
|
21257
22417
|
}
|
|
21258
|
-
) : director ||
|
|
22418
|
+
) : director || hasVisibleFleetPanel || state.collabSession ? /* @__PURE__ */ jsx(
|
|
21259
22419
|
FleetPanel,
|
|
21260
22420
|
{
|
|
21261
22421
|
entries: entriesWithLeader,
|
|
@@ -21442,7 +22602,7 @@ async function runTui(opts) {
|
|
|
21442
22602
|
stdout,
|
|
21443
22603
|
events: opts.events,
|
|
21444
22604
|
model: opts.model,
|
|
21445
|
-
appName: opts.projectRoot ?
|
|
22605
|
+
appName: opts.projectRoot ? path9.basename(opts.projectRoot) : void 0
|
|
21446
22606
|
});
|
|
21447
22607
|
};
|
|
21448
22608
|
const stopTitle = () => {
|
|
@@ -21539,7 +22699,7 @@ async function runTui(opts) {
|
|
|
21539
22699
|
const hqPublisher = createHqPublisherFromEnv({
|
|
21540
22700
|
clientKind: "tui",
|
|
21541
22701
|
projectRoot: opts.projectRoot,
|
|
21542
|
-
projectName:
|
|
22702
|
+
projectName: path9.basename(opts.projectRoot),
|
|
21543
22703
|
appConfig: opts.appConfig
|
|
21544
22704
|
});
|
|
21545
22705
|
hqPublisher?.connect();
|
|
@@ -21579,7 +22739,7 @@ async function runTui(opts) {
|
|
|
21579
22739
|
await mailbox.registerClient({
|
|
21580
22740
|
clientId,
|
|
21581
22741
|
sessionId: opts.getSessionId?.() ?? opts.projectRoot,
|
|
21582
|
-
name: `TUI [${
|
|
22742
|
+
name: `TUI [${path9.basename(opts.projectRoot)}]`,
|
|
21583
22743
|
source: "tui",
|
|
21584
22744
|
pid: process.pid
|
|
21585
22745
|
});
|
|
@@ -21718,6 +22878,16 @@ async function runTui(opts) {
|
|
|
21718
22878
|
saveSettings: opts.saveSettings,
|
|
21719
22879
|
getPluginItems: opts.getPluginItems,
|
|
21720
22880
|
onPluginToggle: opts.onPluginToggle,
|
|
22881
|
+
getMcpServers: opts.getMcpServers,
|
|
22882
|
+
onMcpToggle: opts.onMcpToggle,
|
|
22883
|
+
onMcpRestart: opts.onMcpRestart,
|
|
22884
|
+
getToolsItems: opts.getToolsItems,
|
|
22885
|
+
onToolToggle: opts.onToolToggle,
|
|
22886
|
+
getBrainData: opts.getBrainData,
|
|
22887
|
+
onBrainRiskLevel: opts.onBrainRiskLevel,
|
|
22888
|
+
getShadowData: opts.getShadowData,
|
|
22889
|
+
onShadowStart: opts.onShadowStart,
|
|
22890
|
+
onShadowStop: opts.onShadowStop,
|
|
21721
22891
|
authHost: opts.authHost,
|
|
21722
22892
|
predictNext: opts.predictNext,
|
|
21723
22893
|
onSuggestionsParsed: opts.onSuggestionsParsed,
|