@wrongstack/tui 0.281.1 → 0.282.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +27 -13
- package/dist/index.js +1839 -923
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputHistoryStore, DefaultSecretScrubber, INPUT_HISTORY_DEFAULT_MAX, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, buildChildEnv, DefaultPromptLoader, PromptUsageStore } from '@wrongstack/core';
|
|
1
|
+
import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputHistoryStore, DefaultSecretScrubber, INPUT_HISTORY_DEFAULT_MAX, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, listBoards, getBoard, createBoard, addTask, buildChildEnv, DefaultPromptLoader, PromptUsageStore, 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';
|
|
@@ -17,6 +17,83 @@ import { readClipboardText, readClipboardImage } from '@wrongstack/runtime/clipb
|
|
|
17
17
|
|
|
18
18
|
// src/run-tui.ts
|
|
19
19
|
|
|
20
|
+
// src/components/auth-panel-model.ts
|
|
21
|
+
var AUTH_PANEL_INITIAL = {
|
|
22
|
+
open: false,
|
|
23
|
+
view: "list",
|
|
24
|
+
busy: false,
|
|
25
|
+
providers: [],
|
|
26
|
+
presets: [],
|
|
27
|
+
catalog: [],
|
|
28
|
+
selected: 0,
|
|
29
|
+
filter: "",
|
|
30
|
+
flowTitle: "",
|
|
31
|
+
log: [],
|
|
32
|
+
flowDone: false
|
|
33
|
+
};
|
|
34
|
+
function filterAuthCatalog(catalog, filter) {
|
|
35
|
+
const q = filter.trim().toLowerCase();
|
|
36
|
+
if (!q) return catalog;
|
|
37
|
+
return catalog.filter(
|
|
38
|
+
(c) => c.id.toLowerCase().includes(q) || c.name.toLowerCase().includes(q) || c.family.toLowerCase().includes(q)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function authSelectedProvider(state) {
|
|
42
|
+
return state.providers.find((p) => p.id === state.providerId);
|
|
43
|
+
}
|
|
44
|
+
function authPanelRows(state) {
|
|
45
|
+
switch (state.view) {
|
|
46
|
+
case "list": {
|
|
47
|
+
const rows = state.providers.map((provider) => ({
|
|
48
|
+
kind: "provider",
|
|
49
|
+
provider
|
|
50
|
+
}));
|
|
51
|
+
rows.push(
|
|
52
|
+
{ kind: "list-action", action: "catalog" },
|
|
53
|
+
{ kind: "list-action", action: "local" },
|
|
54
|
+
{ kind: "list-action", action: "custom" },
|
|
55
|
+
{ kind: "list-action", action: "oauth" }
|
|
56
|
+
);
|
|
57
|
+
return rows;
|
|
58
|
+
}
|
|
59
|
+
case "provider": {
|
|
60
|
+
const provider = authSelectedProvider(state);
|
|
61
|
+
if (!provider) return [];
|
|
62
|
+
const rows = provider.keys.map((keyRow) => ({
|
|
63
|
+
kind: "key",
|
|
64
|
+
keyRow
|
|
65
|
+
}));
|
|
66
|
+
rows.push(
|
|
67
|
+
{ kind: "provider-action", action: "add-key" },
|
|
68
|
+
{ kind: "provider-action", action: "edit-family" },
|
|
69
|
+
{ kind: "provider-action", action: "edit-base-url" },
|
|
70
|
+
{ kind: "provider-action", action: "edit-models" },
|
|
71
|
+
{ kind: "provider-action", action: "remove" }
|
|
72
|
+
);
|
|
73
|
+
return rows;
|
|
74
|
+
}
|
|
75
|
+
case "catalog":
|
|
76
|
+
return filterAuthCatalog(state.catalog, state.filter).map((entry) => ({
|
|
77
|
+
kind: "catalog-entry",
|
|
78
|
+
entry
|
|
79
|
+
}));
|
|
80
|
+
case "local":
|
|
81
|
+
return state.presets.map((preset) => ({ kind: "local-preset", preset }));
|
|
82
|
+
case "oauth":
|
|
83
|
+
return ["chatgpt", "claude", "copilot"].map((oauth) => ({
|
|
84
|
+
kind: "oauth-option",
|
|
85
|
+
oauth
|
|
86
|
+
}));
|
|
87
|
+
case "flow":
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function authMoveSelected(state, delta) {
|
|
92
|
+
const count = authPanelRows(state).length;
|
|
93
|
+
if (count === 0) return 0;
|
|
94
|
+
return ((state.selected + delta) % count + count) % count;
|
|
95
|
+
}
|
|
96
|
+
|
|
20
97
|
// src/theme.ts
|
|
21
98
|
var pastel = Object.freeze({
|
|
22
99
|
// Base 8
|
|
@@ -163,213 +240,82 @@ function PromptPicker({ entries, selected, category, total }) {
|
|
|
163
240
|
})
|
|
164
241
|
] });
|
|
165
242
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
git: "Git branch name",
|
|
188
|
-
elapsed: "Session elapsed time",
|
|
189
|
-
context: "Context window usage %",
|
|
190
|
-
cost: "Token cost estimate",
|
|
191
|
-
working_dir: "Current working directory",
|
|
192
|
-
project: "Project name",
|
|
193
|
-
yolo: "YOLO permission mode",
|
|
194
|
-
autonomy: "Autonomy mode",
|
|
195
|
-
eternal_stage: "Autonomy stage",
|
|
196
|
-
goal: "Active goal summary",
|
|
197
|
-
mode: "Active agent mode label",
|
|
198
|
-
auto_proceed: "Auto-proceed countdown",
|
|
199
|
-
sessions: "Live session count",
|
|
200
|
-
tools: "Registered tool count",
|
|
201
|
-
token_saving: "Token-saving mode indicator",
|
|
202
|
-
brain: "Brain arbiter decisions",
|
|
203
|
-
mailbox: "Mailbox unread messages",
|
|
204
|
-
enhance: "Prompt-enhance countdown",
|
|
205
|
-
debug_stream: "Stream debug telemetry",
|
|
206
|
-
next_steps: "Next-step auto-submit countdown"
|
|
207
|
-
};
|
|
208
|
-
var ITEM_LINE = {
|
|
209
|
-
breaker: 1,
|
|
210
|
-
cache: 1,
|
|
211
|
-
context: 1,
|
|
212
|
-
cost: 1,
|
|
213
|
-
hint: 1,
|
|
214
|
-
index: 1,
|
|
215
|
-
model: 1,
|
|
216
|
-
processes: 1,
|
|
217
|
-
queue: 1,
|
|
218
|
-
state: 1,
|
|
219
|
-
tokens: 1,
|
|
220
|
-
version: 1,
|
|
221
|
-
auto_proceed: 2,
|
|
222
|
-
autonomy: 2,
|
|
223
|
-
elapsed: 2,
|
|
224
|
-
eternal_stage: 2,
|
|
225
|
-
git: 2,
|
|
226
|
-
goal: 2,
|
|
227
|
-
mode: 2,
|
|
228
|
-
project: 2,
|
|
229
|
-
sessions: 2,
|
|
230
|
-
token_saving: 2,
|
|
231
|
-
tools: 2,
|
|
232
|
-
working_dir: 2,
|
|
233
|
-
yolo: 2,
|
|
234
|
-
brain: 3,
|
|
235
|
-
debug_stream: 3,
|
|
236
|
-
enhance: 3,
|
|
237
|
-
fleet: 3,
|
|
238
|
-
next_steps: 3,
|
|
239
|
-
todos: 3,
|
|
240
|
-
plan: 3,
|
|
241
|
-
tasks: 3,
|
|
242
|
-
fleet_agents: 4,
|
|
243
|
-
mailbox: 4
|
|
244
|
-
};
|
|
245
|
-
var STATUSLINE_FIELD_COUNT = Object.keys(ITEM_LINE).length;
|
|
246
|
-
var STATUSLINE_ITEMS = [
|
|
247
|
-
// Line 1
|
|
248
|
-
"breaker",
|
|
249
|
-
"cache",
|
|
250
|
-
"context",
|
|
251
|
-
"cost",
|
|
252
|
-
"hint",
|
|
253
|
-
"index",
|
|
254
|
-
"model",
|
|
255
|
-
"processes",
|
|
256
|
-
"queue",
|
|
257
|
-
"state",
|
|
258
|
-
"tokens",
|
|
259
|
-
"version",
|
|
260
|
-
// Line 2
|
|
261
|
-
"auto_proceed",
|
|
262
|
-
"autonomy",
|
|
263
|
-
"elapsed",
|
|
264
|
-
"eternal_stage",
|
|
265
|
-
"git",
|
|
266
|
-
"goal",
|
|
267
|
-
"mode",
|
|
268
|
-
"project",
|
|
269
|
-
"sessions",
|
|
270
|
-
"token_saving",
|
|
271
|
-
"tools",
|
|
272
|
-
"working_dir",
|
|
273
|
-
"yolo",
|
|
274
|
-
// Line 3
|
|
275
|
-
"brain",
|
|
276
|
-
"debug_stream",
|
|
277
|
-
"enhance",
|
|
278
|
-
"fleet",
|
|
279
|
-
"next_steps",
|
|
280
|
-
"plan",
|
|
281
|
-
"tasks",
|
|
282
|
-
"todos",
|
|
283
|
-
// Line 4
|
|
284
|
-
"fleet_agents",
|
|
285
|
-
"mailbox"
|
|
286
|
-
];
|
|
287
|
-
var STREAM_CHIP_KEYS = ["brain", "mailbox", "enhance", "debug_stream"];
|
|
288
|
-
function groupByLine(items) {
|
|
289
|
-
const map = /* @__PURE__ */ new Map();
|
|
290
|
-
for (const item of items) {
|
|
291
|
-
const line = ITEM_LINE[item];
|
|
292
|
-
if (!map.has(line)) map.set(line, []);
|
|
293
|
-
map.get(line).push(item);
|
|
243
|
+
var SEND_MODE_OPTIONS = [
|
|
244
|
+
{
|
|
245
|
+
mode: "queue",
|
|
246
|
+
key: "q",
|
|
247
|
+
label: "Queue",
|
|
248
|
+
description: "Run after the current turn finishes (default)",
|
|
249
|
+
color: "green"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
mode: "btw",
|
|
253
|
+
key: "b",
|
|
254
|
+
label: "By the way",
|
|
255
|
+
description: "Fold in at the next step \u2014 no restart, no interrupt",
|
|
256
|
+
color: "cyan"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
mode: "steer",
|
|
260
|
+
key: "s",
|
|
261
|
+
label: "Steer",
|
|
262
|
+
description: "Abort now, drop the queue, redirect to this",
|
|
263
|
+
color: "red"
|
|
294
264
|
}
|
|
295
|
-
|
|
265
|
+
];
|
|
266
|
+
function nextSendModeIndex(selected, delta, len) {
|
|
267
|
+
if (len <= 0) return 0;
|
|
268
|
+
return ((selected + delta) % len + len) % len;
|
|
296
269
|
}
|
|
297
|
-
function
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
270
|
+
function sendModeFromKey(input, key, selected) {
|
|
271
|
+
if (key.escape) return "cancel";
|
|
272
|
+
if (key.return) return SEND_MODE_OPTIONS[selected]?.mode ?? "queue";
|
|
273
|
+
const ch = input.trim().toLowerCase();
|
|
274
|
+
const match = SEND_MODE_OPTIONS.find((o) => o.key === ch);
|
|
275
|
+
if (match) return match.mode;
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
function formatSendModeMessagePreview(text, maxChars = 120) {
|
|
279
|
+
const singleLine = text.replace(/\s+/g, " ").trim();
|
|
280
|
+
if (singleLine.length <= maxChars) return singleLine;
|
|
281
|
+
return `${singleLine.slice(0, Math.max(0, maxChars - 1))}\u2026`;
|
|
282
|
+
}
|
|
283
|
+
function SendModePicker({
|
|
284
|
+
selected,
|
|
285
|
+
messagePreview,
|
|
286
|
+
onMove,
|
|
287
|
+
onSelect
|
|
302
288
|
}) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const VISIBLE_FIELDS = 8;
|
|
308
|
-
const windowStart = Math.max(0, Math.min(field - Math.floor(VISIBLE_FIELDS / 2), totalFields - VISIBLE_FIELDS));
|
|
309
|
-
const windowEnd = Math.min(windowStart + VISIBLE_FIELDS, totalFields);
|
|
310
|
-
const hasAbove = windowStart > 0;
|
|
311
|
-
const hasBelow = windowEnd < totalFields;
|
|
312
|
-
const rows = [];
|
|
313
|
-
for (const [line, items] of [...byLine.entries()].sort((a, b) => a[0] - b[0])) {
|
|
314
|
-
const windowedItems = items.filter((item) => {
|
|
315
|
-
const idx = STATUSLINE_ITEMS.indexOf(item);
|
|
316
|
-
return idx >= windowStart && idx < windowEnd;
|
|
317
|
-
});
|
|
318
|
-
if (windowedItems.length === 0) continue;
|
|
319
|
-
rows.push({ section: `Line ${line}` });
|
|
320
|
-
for (const item of windowedItems) {
|
|
321
|
-
rows.push({ item, fieldIdx: STATUSLINE_ITEMS.indexOf(item) });
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
const boolVal = (item) => {
|
|
325
|
-
if (hiddenSet.has(item)) return "off";
|
|
326
|
-
if (STREAM_CHIP_KEYS.includes(item)) {
|
|
327
|
-
const meta = visibleChipsMap.get(item);
|
|
328
|
-
if (!meta) return "auto";
|
|
329
|
-
if (meta.expiresIn == null) return "on ";
|
|
330
|
-
const remainingMs = meta.shownAt + meta.expiresIn * 6e4 - Date.now();
|
|
331
|
-
if (remainingMs <= 0) return "auto";
|
|
332
|
-
const remainingMin = Math.max(1, Math.ceil(remainingMs / 6e4));
|
|
333
|
-
return `~${remainingMin}m`;
|
|
289
|
+
useInput((input, key) => {
|
|
290
|
+
if (key.upArrow) {
|
|
291
|
+
onMove(-1);
|
|
292
|
+
return;
|
|
334
293
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (hiddenSet.has(item)) return "red";
|
|
339
|
-
if (STREAM_CHIP_KEYS.includes(item)) {
|
|
340
|
-
const meta = visibleChipsMap.get(item);
|
|
341
|
-
if (!meta) return "cyan";
|
|
342
|
-
if (isChipExpired(meta)) return "cyan";
|
|
343
|
-
return "yellow";
|
|
294
|
+
if (key.downArrow) {
|
|
295
|
+
onMove(1);
|
|
296
|
+
return;
|
|
344
297
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
/* @__PURE__ */ jsx(Text, {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ITEM_DESCRIPTIONS[item] }),
|
|
367
|
-
selected ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2190/\u2192 toggle" }) : null
|
|
368
|
-
] }, `row-${item}`);
|
|
369
|
-
}),
|
|
370
|
-
hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} item${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
|
|
371
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Changes apply instantly \xB7 persisted to ~/.wrongstack/statusline.json \xB7 auto chips show when data exists" }),
|
|
372
|
-
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
298
|
+
const decision = sendModeFromKey(input, key, selected);
|
|
299
|
+
if (decision) onSelect(decision);
|
|
300
|
+
});
|
|
301
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, marginY: 1, children: [
|
|
302
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Deliver this message how? \u2501\u2501" }),
|
|
303
|
+
messagePreview ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
304
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Message: " }),
|
|
305
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: formatSendModeMessagePreview(messagePreview) })
|
|
306
|
+
] }) : null,
|
|
307
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "q/b/s pick \xB7 \u2191/\u2193 move \xB7 Enter select \xB7 Esc \u2192 queue" }),
|
|
308
|
+
SEND_MODE_OPTIONS.map((opt, i) => /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: opt.color } : {}, children: [
|
|
309
|
+
i === selected ? "\u203A " : " ",
|
|
310
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: opt.color, children: [
|
|
311
|
+
"[",
|
|
312
|
+
opt.key,
|
|
313
|
+
"]"
|
|
314
|
+
] }),
|
|
315
|
+
" ",
|
|
316
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
|
|
317
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
|
|
318
|
+
] }, opt.mode))
|
|
373
319
|
] });
|
|
374
320
|
}
|
|
375
321
|
|
|
@@ -1494,159 +1440,213 @@ function SettingsPicker({
|
|
|
1494
1440
|
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
1495
1441
|
] });
|
|
1496
1442
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
view: "list",
|
|
1502
|
-
busy: false,
|
|
1503
|
-
providers: [],
|
|
1504
|
-
presets: [],
|
|
1505
|
-
catalog: [],
|
|
1506
|
-
selected: 0,
|
|
1507
|
-
filter: "",
|
|
1508
|
-
flowTitle: "",
|
|
1509
|
-
log: [],
|
|
1510
|
-
flowDone: false
|
|
1511
|
-
};
|
|
1512
|
-
function filterAuthCatalog(catalog, filter) {
|
|
1513
|
-
const q = filter.trim().toLowerCase();
|
|
1514
|
-
if (!q) return catalog;
|
|
1515
|
-
return catalog.filter(
|
|
1516
|
-
(c) => c.id.toLowerCase().includes(q) || c.name.toLowerCase().includes(q) || c.family.toLowerCase().includes(q)
|
|
1517
|
-
);
|
|
1443
|
+
function isChipExpired(meta, now = Date.now()) {
|
|
1444
|
+
if (meta.expiresIn == null || meta.expiresIn === 0) return false;
|
|
1445
|
+
if (meta.shownAt == null || meta.shownAt === 0) return false;
|
|
1446
|
+
return now >= meta.shownAt + meta.expiresIn * 60 * 1e3;
|
|
1518
1447
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1448
|
+
var ITEM_DESCRIPTIONS = {
|
|
1449
|
+
version: "WrongStack version chip",
|
|
1450
|
+
state: "Agent run state / thinking spinner",
|
|
1451
|
+
model: "Current provider/model id",
|
|
1452
|
+
tokens: "Input/output token counters",
|
|
1453
|
+
cache: "Prompt cache hit ratio",
|
|
1454
|
+
queue: "Queued prompt count",
|
|
1455
|
+
processes: "Tracked shell/process count",
|
|
1456
|
+
hint: "Transient status hint text",
|
|
1457
|
+
index: "Codebase indexing status",
|
|
1458
|
+
breaker: "Process breaker countdown",
|
|
1459
|
+
todos: "Todo items (pending/in-progress/done)",
|
|
1460
|
+
plan: "Plan board items",
|
|
1461
|
+
tasks: "Task board items",
|
|
1462
|
+
fleet: "Fleet agent status",
|
|
1463
|
+
fleet_agents: "Per-agent live detail row",
|
|
1464
|
+
git: "Git branch name",
|
|
1465
|
+
elapsed: "Session elapsed time",
|
|
1466
|
+
context: "Context window usage %",
|
|
1467
|
+
cost: "Token cost estimate",
|
|
1468
|
+
working_dir: "Current working directory",
|
|
1469
|
+
project: "Project name",
|
|
1470
|
+
yolo: "YOLO permission mode",
|
|
1471
|
+
autonomy: "Autonomy mode",
|
|
1472
|
+
eternal_stage: "Autonomy stage",
|
|
1473
|
+
goal: "Active goal summary",
|
|
1474
|
+
mode: "Active agent mode label",
|
|
1475
|
+
auto_proceed: "Auto-proceed countdown",
|
|
1476
|
+
sessions: "Live session count",
|
|
1477
|
+
tools: "Registered tool count",
|
|
1478
|
+
token_saving: "Token-saving mode indicator",
|
|
1479
|
+
brain: "Brain arbiter decisions",
|
|
1480
|
+
mailbox: "Mailbox unread messages",
|
|
1481
|
+
enhance: "Prompt-enhance countdown",
|
|
1482
|
+
debug_stream: "Stream debug telemetry",
|
|
1483
|
+
next_steps: "Next-step auto-submit countdown"
|
|
1484
|
+
};
|
|
1485
|
+
var ITEM_LINE = {
|
|
1486
|
+
breaker: 1,
|
|
1487
|
+
cache: 1,
|
|
1488
|
+
context: 1,
|
|
1489
|
+
cost: 1,
|
|
1490
|
+
hint: 1,
|
|
1491
|
+
index: 1,
|
|
1492
|
+
model: 1,
|
|
1493
|
+
processes: 1,
|
|
1494
|
+
queue: 1,
|
|
1495
|
+
state: 1,
|
|
1496
|
+
tokens: 1,
|
|
1497
|
+
version: 1,
|
|
1498
|
+
auto_proceed: 2,
|
|
1499
|
+
autonomy: 2,
|
|
1500
|
+
elapsed: 2,
|
|
1501
|
+
eternal_stage: 2,
|
|
1502
|
+
git: 2,
|
|
1503
|
+
goal: 2,
|
|
1504
|
+
mode: 2,
|
|
1505
|
+
project: 2,
|
|
1506
|
+
sessions: 2,
|
|
1507
|
+
token_saving: 2,
|
|
1508
|
+
tools: 2,
|
|
1509
|
+
working_dir: 2,
|
|
1510
|
+
yolo: 2,
|
|
1511
|
+
brain: 3,
|
|
1512
|
+
debug_stream: 3,
|
|
1513
|
+
enhance: 3,
|
|
1514
|
+
fleet: 3,
|
|
1515
|
+
next_steps: 3,
|
|
1516
|
+
todos: 3,
|
|
1517
|
+
plan: 3,
|
|
1518
|
+
tasks: 3,
|
|
1519
|
+
fleet_agents: 4,
|
|
1520
|
+
mailbox: 4
|
|
1521
|
+
};
|
|
1522
|
+
var STATUSLINE_FIELD_COUNT = Object.keys(ITEM_LINE).length;
|
|
1523
|
+
var STATUSLINE_ITEMS = [
|
|
1524
|
+
// Line 1
|
|
1525
|
+
"breaker",
|
|
1526
|
+
"cache",
|
|
1527
|
+
"context",
|
|
1528
|
+
"cost",
|
|
1529
|
+
"hint",
|
|
1530
|
+
"index",
|
|
1531
|
+
"model",
|
|
1532
|
+
"processes",
|
|
1533
|
+
"queue",
|
|
1534
|
+
"state",
|
|
1535
|
+
"tokens",
|
|
1536
|
+
"version",
|
|
1537
|
+
// Line 2
|
|
1538
|
+
"auto_proceed",
|
|
1539
|
+
"autonomy",
|
|
1540
|
+
"elapsed",
|
|
1541
|
+
"eternal_stage",
|
|
1542
|
+
"git",
|
|
1543
|
+
"goal",
|
|
1544
|
+
"mode",
|
|
1545
|
+
"project",
|
|
1546
|
+
"sessions",
|
|
1547
|
+
"token_saving",
|
|
1548
|
+
"tools",
|
|
1549
|
+
"working_dir",
|
|
1550
|
+
"yolo",
|
|
1551
|
+
// Line 3
|
|
1552
|
+
"brain",
|
|
1553
|
+
"debug_stream",
|
|
1554
|
+
"enhance",
|
|
1555
|
+
"fleet",
|
|
1556
|
+
"next_steps",
|
|
1557
|
+
"plan",
|
|
1558
|
+
"tasks",
|
|
1559
|
+
"todos",
|
|
1560
|
+
// Line 4
|
|
1561
|
+
"fleet_agents",
|
|
1562
|
+
"mailbox"
|
|
1563
|
+
];
|
|
1564
|
+
var STREAM_CHIP_KEYS = ["brain", "mailbox", "enhance", "debug_stream"];
|
|
1565
|
+
function groupByLine(items) {
|
|
1566
|
+
const map = /* @__PURE__ */ new Map();
|
|
1567
|
+
for (const item of items) {
|
|
1568
|
+
const line = ITEM_LINE[item];
|
|
1569
|
+
if (!map.has(line)) map.set(line, []);
|
|
1570
|
+
map.get(line).push(item);
|
|
1571
|
+
}
|
|
1572
|
+
return map;
|
|
1521
1573
|
}
|
|
1522
|
-
function
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
const
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
{ kind: "provider-action", action: "edit-base-url" },
|
|
1548
|
-
{ kind: "provider-action", action: "edit-models" },
|
|
1549
|
-
{ kind: "provider-action", action: "remove" }
|
|
1550
|
-
);
|
|
1551
|
-
return rows;
|
|
1574
|
+
function StatuslinePicker({
|
|
1575
|
+
field,
|
|
1576
|
+
hiddenItems,
|
|
1577
|
+
visibleChips = [],
|
|
1578
|
+
hint
|
|
1579
|
+
}) {
|
|
1580
|
+
const hiddenSet = new Set(hiddenItems);
|
|
1581
|
+
const visibleChipsMap = new Map(visibleChips.map((c) => [c.key, c]));
|
|
1582
|
+
const totalFields = STATUSLINE_ITEMS.length;
|
|
1583
|
+
const byLine = groupByLine(STATUSLINE_ITEMS);
|
|
1584
|
+
const VISIBLE_FIELDS = 8;
|
|
1585
|
+
const windowStart = Math.max(0, Math.min(field - Math.floor(VISIBLE_FIELDS / 2), totalFields - VISIBLE_FIELDS));
|
|
1586
|
+
const windowEnd = Math.min(windowStart + VISIBLE_FIELDS, totalFields);
|
|
1587
|
+
const hasAbove = windowStart > 0;
|
|
1588
|
+
const hasBelow = windowEnd < totalFields;
|
|
1589
|
+
const rows = [];
|
|
1590
|
+
for (const [line, items] of [...byLine.entries()].sort((a, b) => a[0] - b[0])) {
|
|
1591
|
+
const windowedItems = items.filter((item) => {
|
|
1592
|
+
const idx = STATUSLINE_ITEMS.indexOf(item);
|
|
1593
|
+
return idx >= windowStart && idx < windowEnd;
|
|
1594
|
+
});
|
|
1595
|
+
if (windowedItems.length === 0) continue;
|
|
1596
|
+
rows.push({ section: `Line ${line}` });
|
|
1597
|
+
for (const item of windowedItems) {
|
|
1598
|
+
rows.push({ item, fieldIdx: STATUSLINE_ITEMS.indexOf(item) });
|
|
1552
1599
|
}
|
|
1553
|
-
case "catalog":
|
|
1554
|
-
return filterAuthCatalog(state.catalog, state.filter).map((entry) => ({
|
|
1555
|
-
kind: "catalog-entry",
|
|
1556
|
-
entry
|
|
1557
|
-
}));
|
|
1558
|
-
case "local":
|
|
1559
|
-
return state.presets.map((preset) => ({ kind: "local-preset", preset }));
|
|
1560
|
-
case "oauth":
|
|
1561
|
-
return ["chatgpt", "claude", "copilot"].map((oauth) => ({
|
|
1562
|
-
kind: "oauth-option",
|
|
1563
|
-
oauth
|
|
1564
|
-
}));
|
|
1565
|
-
case "flow":
|
|
1566
|
-
return [];
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
function authMoveSelected(state, delta) {
|
|
1570
|
-
const count = authPanelRows(state).length;
|
|
1571
|
-
if (count === 0) return 0;
|
|
1572
|
-
return ((state.selected + delta) % count + count) % count;
|
|
1573
|
-
}
|
|
1574
|
-
var SEND_MODE_OPTIONS = [
|
|
1575
|
-
{
|
|
1576
|
-
mode: "queue",
|
|
1577
|
-
key: "q",
|
|
1578
|
-
label: "Queue",
|
|
1579
|
-
description: "Run after the current turn finishes (default)",
|
|
1580
|
-
color: "green"
|
|
1581
|
-
},
|
|
1582
|
-
{
|
|
1583
|
-
mode: "btw",
|
|
1584
|
-
key: "b",
|
|
1585
|
-
label: "By the way",
|
|
1586
|
-
description: "Fold in at the next step \u2014 no restart, no interrupt",
|
|
1587
|
-
color: "cyan"
|
|
1588
|
-
},
|
|
1589
|
-
{
|
|
1590
|
-
mode: "steer",
|
|
1591
|
-
key: "s",
|
|
1592
|
-
label: "Steer",
|
|
1593
|
-
description: "Abort now, drop the queue, redirect to this",
|
|
1594
|
-
color: "red"
|
|
1595
1600
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
if (match) return match.mode;
|
|
1607
|
-
return null;
|
|
1608
|
-
}
|
|
1609
|
-
function formatSendModeMessagePreview(text, maxChars = 120) {
|
|
1610
|
-
const singleLine = text.replace(/\s+/g, " ").trim();
|
|
1611
|
-
if (singleLine.length <= maxChars) return singleLine;
|
|
1612
|
-
return `${singleLine.slice(0, Math.max(0, maxChars - 1))}\u2026`;
|
|
1613
|
-
}
|
|
1614
|
-
function SendModePicker({
|
|
1615
|
-
selected,
|
|
1616
|
-
messagePreview,
|
|
1617
|
-
onMove,
|
|
1618
|
-
onSelect
|
|
1619
|
-
}) {
|
|
1620
|
-
useInput((input, key) => {
|
|
1621
|
-
if (key.upArrow) {
|
|
1622
|
-
onMove(-1);
|
|
1623
|
-
return;
|
|
1601
|
+
const boolVal = (item) => {
|
|
1602
|
+
if (hiddenSet.has(item)) return "off";
|
|
1603
|
+
if (STREAM_CHIP_KEYS.includes(item)) {
|
|
1604
|
+
const meta = visibleChipsMap.get(item);
|
|
1605
|
+
if (!meta) return "auto";
|
|
1606
|
+
if (meta.expiresIn == null) return "on ";
|
|
1607
|
+
const remainingMs = meta.shownAt + meta.expiresIn * 6e4 - Date.now();
|
|
1608
|
+
if (remainingMs <= 0) return "auto";
|
|
1609
|
+
const remainingMin = Math.max(1, Math.ceil(remainingMs / 6e4));
|
|
1610
|
+
return `~${remainingMin}m`;
|
|
1624
1611
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1612
|
+
return "on ";
|
|
1613
|
+
};
|
|
1614
|
+
const valColor = (item) => {
|
|
1615
|
+
if (hiddenSet.has(item)) return "red";
|
|
1616
|
+
if (STREAM_CHIP_KEYS.includes(item)) {
|
|
1617
|
+
const meta = visibleChipsMap.get(item);
|
|
1618
|
+
if (!meta) return "cyan";
|
|
1619
|
+
if (isChipExpired(meta)) return "cyan";
|
|
1620
|
+
return "yellow";
|
|
1628
1621
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
"
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1622
|
+
return "green";
|
|
1623
|
+
};
|
|
1624
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
1625
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Statusline \u2501\u2501" }),
|
|
1626
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 move \xB7 \u2190/\u2192 toggle \xB7 Esc to close" }),
|
|
1627
|
+
hasAbove ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${windowStart} item${windowStart === 1 ? "" : "s"} above` }) : null,
|
|
1628
|
+
rows.map((row) => {
|
|
1629
|
+
if (row.section) {
|
|
1630
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "green", children: [
|
|
1631
|
+
"\u2500\u2500 ",
|
|
1632
|
+
row.section,
|
|
1633
|
+
" \u2500\u2500"
|
|
1634
|
+
] }, `section-${row.section}`);
|
|
1635
|
+
}
|
|
1636
|
+
const item = row.item;
|
|
1637
|
+
const fieldIdx = row.fieldIdx;
|
|
1638
|
+
const selected = fieldIdx === field;
|
|
1639
|
+
return /* @__PURE__ */ jsxs(Text, { inverse: selected, ...selected ? { color: "yellow" } : {}, children: [
|
|
1640
|
+
selected ? "\u203A " : " ",
|
|
1641
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: item.padEnd(12) }),
|
|
1642
|
+
/* @__PURE__ */ jsx(Text, { color: valColor(item), children: boolVal(item).padEnd(4) }),
|
|
1643
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ITEM_DESCRIPTIONS[item] }),
|
|
1644
|
+
selected ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2190/\u2192 toggle" }) : null
|
|
1645
|
+
] }, `row-${item}`);
|
|
1646
|
+
}),
|
|
1647
|
+
hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} item${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
|
|
1648
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Changes apply instantly \xB7 persisted to ~/.wrongstack/statusline.json \xB7 auto chips show when data exists" }),
|
|
1649
|
+
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
1650
1650
|
] });
|
|
1651
1651
|
}
|
|
1652
1652
|
|
|
@@ -1661,6 +1661,7 @@ function closePanels(state) {
|
|
|
1661
1661
|
processListOpen: false,
|
|
1662
1662
|
auditPanelOpen: false,
|
|
1663
1663
|
planPanelOpen: false,
|
|
1664
|
+
kanbanPanelOpen: false,
|
|
1664
1665
|
goalPanelOpen: false,
|
|
1665
1666
|
sessionsPanelOpen: false,
|
|
1666
1667
|
settingsPicker: { ...state.settingsPicker, open: false },
|
|
@@ -2063,7 +2064,7 @@ function reducer(state, action) {
|
|
|
2063
2064
|
switch (action.type) {
|
|
2064
2065
|
case "addEntry": {
|
|
2065
2066
|
const e = action.entry;
|
|
2066
|
-
if ((e.kind === "user" || e.kind === "assistant" || e.kind === "info" || e.kind === "warn" || e.kind === "error" || e.kind === "turn-summary") && !e.text?.trim()) {
|
|
2067
|
+
if ((e.kind === "user" || e.kind === "assistant" || e.kind === "thinking" || e.kind === "info" || e.kind === "warn" || e.kind === "error" || e.kind === "turn-summary") && !e.text?.trim()) {
|
|
2067
2068
|
return state;
|
|
2068
2069
|
}
|
|
2069
2070
|
const stored = e.kind === "tool" && e.input !== void 0 ? { ...e, input: pruneToolInput(e.input) } : e;
|
|
@@ -2412,6 +2413,31 @@ function reducer(state, action) {
|
|
|
2412
2413
|
...state,
|
|
2413
2414
|
autonomyPicker: { ...state.autonomyPicker, hint: action.text }
|
|
2414
2415
|
};
|
|
2416
|
+
case "modePickerOpen":
|
|
2417
|
+
return {
|
|
2418
|
+
...state,
|
|
2419
|
+
...closePanels(state),
|
|
2420
|
+
modePicker: { open: true, modes: action.modes, selected: 0, hint: void 0 }
|
|
2421
|
+
};
|
|
2422
|
+
case "modePickerClose":
|
|
2423
|
+
return {
|
|
2424
|
+
...state,
|
|
2425
|
+
modePicker: { open: false, modes: [], selected: 0 }
|
|
2426
|
+
};
|
|
2427
|
+
case "modePickerMove": {
|
|
2428
|
+
const n = state.modePicker.modes.length;
|
|
2429
|
+
if (n === 0) return state;
|
|
2430
|
+
const next = (state.modePicker.selected + action.delta + n) % n;
|
|
2431
|
+
return {
|
|
2432
|
+
...state,
|
|
2433
|
+
modePicker: { ...state.modePicker, selected: next }
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
case "modePickerHint":
|
|
2437
|
+
return {
|
|
2438
|
+
...state,
|
|
2439
|
+
modePicker: { ...state.modePicker, hint: action.text }
|
|
2440
|
+
};
|
|
2415
2441
|
case "designPickerOpen":
|
|
2416
2442
|
return {
|
|
2417
2443
|
...state,
|
|
@@ -3400,6 +3426,10 @@ function reducer(state, action) {
|
|
|
3400
3426
|
const opening = !state.planPanelOpen;
|
|
3401
3427
|
return opening ? { ...state, ...closePanels(state), planPanelOpen: true } : { ...state, planPanelOpen: false };
|
|
3402
3428
|
}
|
|
3429
|
+
case "toggleKanbanPanel": {
|
|
3430
|
+
const opening = !state.kanbanPanelOpen;
|
|
3431
|
+
return opening ? { ...state, ...closePanels(state), kanbanPanelOpen: true } : { ...state, kanbanPanelOpen: false };
|
|
3432
|
+
}
|
|
3403
3433
|
case "toggleGoalPanel": {
|
|
3404
3434
|
const opening = !state.goalPanelOpen;
|
|
3405
3435
|
return opening ? { ...state, ...closePanels(state), goalPanelOpen: true } : { ...state, goalPanelOpen: false };
|
|
@@ -4978,7 +5008,7 @@ function FleetMonitor({
|
|
|
4978
5008
|
nowTick,
|
|
4979
5009
|
collabSession
|
|
4980
5010
|
}) {
|
|
4981
|
-
const
|
|
5011
|
+
const TERMINAL_TTL_MS2 = 5 * 6e4;
|
|
4982
5012
|
const all = Object.values(entries);
|
|
4983
5013
|
const running = all.filter((e) => e.status === "running");
|
|
4984
5014
|
const idle = all.filter((e) => e.status === "idle").length;
|
|
@@ -4986,7 +5016,7 @@ function FleetMonitor({
|
|
|
4986
5016
|
const failed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
|
|
4987
5017
|
const recent = all.filter((e) => {
|
|
4988
5018
|
if (e.status === "running" || e.status === "idle") return true;
|
|
4989
|
-
return nowTick - e.lastEventAt <
|
|
5019
|
+
return nowTick - e.lastEventAt < TERMINAL_TTL_MS2;
|
|
4990
5020
|
});
|
|
4991
5021
|
const concurrencyRatio = maxConcurrent > 0 ? running.length / maxConcurrent : 0;
|
|
4992
5022
|
const ordered = [...recent].sort((a, b) => {
|
|
@@ -5683,54 +5713,349 @@ function AuditPanel({ sideEffects, onClose: _onClose }) {
|
|
|
5683
5713
|
}) })
|
|
5684
5714
|
] });
|
|
5685
5715
|
}
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
+
|
|
5717
|
+
// src/components/provider-colors.ts
|
|
5718
|
+
function colorForFamily(family) {
|
|
5719
|
+
return FAMILY_COLORS[family?.toLowerCase() ?? ""] ?? "#89dceb";
|
|
5720
|
+
}
|
|
5721
|
+
function dimColorForFamily(family) {
|
|
5722
|
+
return DIMMED_FAMILY_COLORS[family?.toLowerCase() ?? ""] ?? "#585b70";
|
|
5723
|
+
}
|
|
5724
|
+
var FAMILY_COLORS = {
|
|
5725
|
+
anthropic: "#f38ba8",
|
|
5726
|
+
"anthropic-oauth": "#f38ba8",
|
|
5727
|
+
"anthropic-claude": "#f38ba8",
|
|
5728
|
+
openai: "#a6e3a1",
|
|
5729
|
+
"openai-codex": "#a6e3a1",
|
|
5730
|
+
"openai-compatible": "#94e2d5",
|
|
5731
|
+
google: "#89b4fa",
|
|
5732
|
+
gemini: "#89b4fa",
|
|
5733
|
+
"google-gemini": "#89b4fa",
|
|
5734
|
+
"github-copilot": "#cba6f7",
|
|
5735
|
+
copilot: "#cba6f7",
|
|
5736
|
+
local: "#f9e2af",
|
|
5737
|
+
ollama: "#fab387",
|
|
5738
|
+
vllm: "#fab387",
|
|
5739
|
+
lmstudio: "#f9e2af",
|
|
5740
|
+
omniroute: "#eba0ac",
|
|
5741
|
+
mistral: "#b4befe",
|
|
5742
|
+
groq: "#89dceb",
|
|
5743
|
+
together: "#89dceb",
|
|
5744
|
+
fireworks: "#89dceb",
|
|
5745
|
+
perplexity: "#89dceb",
|
|
5746
|
+
deepseek: "#f5c2e7"
|
|
5747
|
+
};
|
|
5748
|
+
var DIMMED_FAMILY_COLORS = {
|
|
5749
|
+
anthropic: "#6c3f4a",
|
|
5750
|
+
"anthropic-oauth": "#6c3f4a",
|
|
5751
|
+
openai: "#3d5c3d",
|
|
5752
|
+
"openai-codex": "#3d5c3d",
|
|
5753
|
+
"openai-compatible": "#3a524e",
|
|
5754
|
+
google: "#3a4570",
|
|
5755
|
+
gemini: "#3a4570",
|
|
5756
|
+
"github-copilot": "#4a3f5c",
|
|
5757
|
+
copilot: "#4a3f5c",
|
|
5758
|
+
local: "#5c5430",
|
|
5759
|
+
ollama: "#5c4730",
|
|
5760
|
+
vllm: "#5c4730",
|
|
5761
|
+
mistral: "#3e3f5c",
|
|
5762
|
+
deepseek: "#5c3f50"
|
|
5763
|
+
};
|
|
5764
|
+
function badgeForKind(kind) {
|
|
5765
|
+
switch (kind) {
|
|
5766
|
+
case "oauth":
|
|
5767
|
+
return { label: "oauth", color: "#cba6f7" };
|
|
5768
|
+
case "session_token":
|
|
5769
|
+
return { label: "session", color: "#89dceb" };
|
|
5770
|
+
default:
|
|
5771
|
+
return void 0;
|
|
5716
5772
|
}
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
}
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5773
|
+
}
|
|
5774
|
+
var OAUTH_KIND_COLORS = {
|
|
5775
|
+
chatgpt: "#a6e3a1",
|
|
5776
|
+
claude: "#f38ba8",
|
|
5777
|
+
copilot: "#cba6f7"
|
|
5778
|
+
};
|
|
5779
|
+
var UI_COLORS = {
|
|
5780
|
+
focused: "#89b4fa",
|
|
5781
|
+
active: "#a6e3a1",
|
|
5782
|
+
inactive: "#585b70",
|
|
5783
|
+
warning: "#f9e2af",
|
|
5784
|
+
error: "#f38ba8",
|
|
5785
|
+
hint: "#f9e2af",
|
|
5786
|
+
border: "#89b4fa",
|
|
5787
|
+
title: "#89b4fa",
|
|
5788
|
+
selectedModel: "#89b4fa"};
|
|
5789
|
+
var CHROME_ROWS = 18;
|
|
5790
|
+
var LIST_ACTION_LABEL = {
|
|
5791
|
+
catalog: "\uFF0B Add provider (models.dev catalog)",
|
|
5792
|
+
local: "\uFF0B Add local server (OmniRoute / Ollama / vLLM / LM Studio)",
|
|
5793
|
+
custom: "\uFF0B Add custom provider",
|
|
5794
|
+
oauth: "\u26A1 Sign in with OAuth (ChatGPT / Claude / Copilot)"
|
|
5795
|
+
};
|
|
5796
|
+
var PROVIDER_ACTION_LABEL = {
|
|
5797
|
+
"add-key": "\uFF0B Add another key",
|
|
5798
|
+
"edit-family": "\u270E Edit family",
|
|
5799
|
+
"edit-base-url": "\u270E Edit base URL",
|
|
5800
|
+
"edit-models": "\u270E Edit visible model list",
|
|
5801
|
+
remove: "\u2715 Remove this provider"
|
|
5802
|
+
};
|
|
5803
|
+
var OAUTH_LABEL = {
|
|
5804
|
+
chatgpt: { title: "ChatGPT Plus/Pro", detail: "\u2192 openai-codex" },
|
|
5805
|
+
claude: { title: "Claude Pro/Max", detail: "\u2192 anthropic-oauth" },
|
|
5806
|
+
copilot: { title: "GitHub Copilot", detail: "\u2192 github-copilot" }
|
|
5807
|
+
};
|
|
5808
|
+
function keySummary(keyRow) {
|
|
5809
|
+
const method = keyRow.authMethod === "oauth" ? " oauth" : "";
|
|
5810
|
+
const created = keyRow.createdAt ? ` ${keyRow.createdAt.slice(0, 10)}` : "";
|
|
5811
|
+
return `${keyRow.masked}${method}${created}`;
|
|
5812
|
+
}
|
|
5813
|
+
function renderRow(row, focused, i) {
|
|
5814
|
+
const marker = focused ? "\u203A" : " ";
|
|
5815
|
+
const rowColor = focused ? UI_COLORS.focused : void 0;
|
|
5816
|
+
switch (row.kind) {
|
|
5817
|
+
case "provider": {
|
|
5818
|
+
const p = row.provider;
|
|
5819
|
+
const keys = p.keys.length === 0 ? "no keys" : p.keys.length === 1 ? `1 key ${p.keys[0]?.masked ?? ""}` : `${p.keys.length} keys`;
|
|
5820
|
+
const famColor = colorForFamily(p.family);
|
|
5821
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5822
|
+
marker,
|
|
5823
|
+
" ",
|
|
5824
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: focused ? void 0 : famColor, children: p.id.padEnd(22) }),
|
|
5825
|
+
" ",
|
|
5826
|
+
/* @__PURE__ */ jsx(Text, { color: focused ? void 0 : dimColorForFamily(p.family), children: (p.family ?? "\u2014").padEnd(18) }),
|
|
5827
|
+
" ",
|
|
5828
|
+
/* @__PURE__ */ jsx(Text, { color: p.keys.length > 0 ? UI_COLORS.active : UI_COLORS.warning, children: keys })
|
|
5829
|
+
] }, `p-${p.id}`);
|
|
5830
|
+
}
|
|
5831
|
+
case "list-action":
|
|
5832
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5833
|
+
marker,
|
|
5834
|
+
" ",
|
|
5835
|
+
LIST_ACTION_LABEL[row.action]
|
|
5836
|
+
] }, `a-${row.action}`);
|
|
5837
|
+
case "key": {
|
|
5838
|
+
const k = row.keyRow;
|
|
5839
|
+
const badge = badgeForKind(k.authMethod);
|
|
5840
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5841
|
+
marker,
|
|
5842
|
+
" ",
|
|
5843
|
+
/* @__PURE__ */ jsx(Text, { color: k.active ? UI_COLORS.active : UI_COLORS.inactive, children: k.active ? "\u25CF" : "\u25CB" }),
|
|
5844
|
+
" ",
|
|
5845
|
+
k.label.padEnd(20),
|
|
5846
|
+
" ",
|
|
5847
|
+
badge ? /* @__PURE__ */ jsx(Text, { color: badge.color, children: badge.label.padEnd(8) }) : null,
|
|
5848
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: keySummary(k) })
|
|
5849
|
+
] }, `k-${k.label}`);
|
|
5850
|
+
}
|
|
5851
|
+
case "provider-action":
|
|
5852
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5853
|
+
marker,
|
|
5854
|
+
" ",
|
|
5855
|
+
PROVIDER_ACTION_LABEL[row.action]
|
|
5856
|
+
] }, `pa-${row.action}`);
|
|
5857
|
+
case "catalog-entry": {
|
|
5858
|
+
const c = row.entry;
|
|
5859
|
+
const famColor = colorForFamily(c.family);
|
|
5860
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5861
|
+
marker,
|
|
5862
|
+
" ",
|
|
5863
|
+
/* @__PURE__ */ jsx(Text, { color: c.saved ? UI_COLORS.active : UI_COLORS.inactive, children: c.saved ? "\u25C9" : "\u25CB" }),
|
|
5864
|
+
" ",
|
|
5865
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: focused ? void 0 : famColor, children: c.id.padEnd(24) }),
|
|
5866
|
+
" ",
|
|
5867
|
+
/* @__PURE__ */ jsx(Text, { color: focused ? void 0 : dimColorForFamily(c.family), children: c.family.padEnd(20) }),
|
|
5868
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: c.envVars.length > 0 ? c.envVars.join(", ") : "" })
|
|
5869
|
+
] }, `c-${c.id}`);
|
|
5870
|
+
}
|
|
5871
|
+
case "local-preset": {
|
|
5872
|
+
const p = row.preset;
|
|
5873
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5874
|
+
marker,
|
|
5875
|
+
" ",
|
|
5876
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: focused ? void 0 : "#fab387", children: p.label.padEnd(12) }),
|
|
5877
|
+
" ",
|
|
5878
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: p.defaultBaseUrl.padEnd(28) }),
|
|
5879
|
+
" ",
|
|
5880
|
+
/* @__PURE__ */ jsx(Text, { color: p.noAuth ? UI_COLORS.inactive : UI_COLORS.active, children: p.noAuth ? "no auth" : "optional key" })
|
|
5881
|
+
] }, `l-${p.id}`);
|
|
5882
|
+
}
|
|
5883
|
+
case "oauth-option": {
|
|
5884
|
+
const o = OAUTH_LABEL[row.oauth] ?? { title: row.oauth, detail: "" };
|
|
5885
|
+
const kindColor = OAUTH_KIND_COLORS[row.oauth] ?? UI_COLORS.focused;
|
|
5886
|
+
return /* @__PURE__ */ jsxs(Text, { color: rowColor, wrap: "truncate-end", children: [
|
|
5887
|
+
marker,
|
|
5888
|
+
" ",
|
|
5889
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: focused ? void 0 : kindColor, children: o.title.padEnd(20) }),
|
|
5890
|
+
" ",
|
|
5891
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: o.detail })
|
|
5892
|
+
] }, `o-${row.oauth}`);
|
|
5893
|
+
}
|
|
5894
|
+
default:
|
|
5895
|
+
return /* @__PURE__ */ jsx(Text, { children: " " }, `r-${i}`);
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
function viewTitle(panel) {
|
|
5899
|
+
switch (panel.view) {
|
|
5900
|
+
case "list":
|
|
5901
|
+
return "API keys & sign-in";
|
|
5902
|
+
case "provider":
|
|
5903
|
+
return `Provider \u2014 ${panel.providerId ?? ""}`;
|
|
5904
|
+
case "catalog":
|
|
5905
|
+
return "Add provider \u2014 models.dev catalog";
|
|
5906
|
+
case "local":
|
|
5907
|
+
return "Add local server";
|
|
5908
|
+
case "oauth":
|
|
5909
|
+
return "Sign in with OAuth";
|
|
5910
|
+
case "flow":
|
|
5911
|
+
return panel.flowTitle || "Working\u2026";
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
function viewLegend(panel) {
|
|
5915
|
+
if (panel.input) return "Enter submit \xB7 Esc cancel";
|
|
5916
|
+
if (panel.confirm) return "y/Enter confirm \xB7 n/Esc cancel";
|
|
5917
|
+
switch (panel.view) {
|
|
5918
|
+
case "list":
|
|
5919
|
+
return "\u2191/\u2193 select \xB7 Enter open \xB7 Esc close";
|
|
5920
|
+
case "provider":
|
|
5921
|
+
return "\u2191/\u2193 select \xB7 Enter activate/run \xB7 u update key \xB7 d delete key \xB7 Esc back";
|
|
5922
|
+
case "catalog":
|
|
5923
|
+
return "type to filter \xB7 \u2191/\u2193 select \xB7 Enter add key \xB7 Esc back";
|
|
5924
|
+
case "local":
|
|
5925
|
+
return "\u2191/\u2193 select \xB7 Enter configure & probe \xB7 Esc back";
|
|
5926
|
+
case "oauth":
|
|
5927
|
+
return "\u2191/\u2193 select \xB7 Enter sign in \xB7 Esc back";
|
|
5928
|
+
case "flow":
|
|
5929
|
+
return panel.flowDone ? "Enter/Esc back" : "Esc cancel";
|
|
5930
|
+
}
|
|
5931
|
+
}
|
|
5932
|
+
function AuthPanel({ panel }) {
|
|
5933
|
+
const { stdout } = useStdout();
|
|
5934
|
+
const rows = stdout?.rows ?? 24;
|
|
5935
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS);
|
|
5936
|
+
const allRows = authPanelRows(panel);
|
|
5937
|
+
const total = allRows.length;
|
|
5938
|
+
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(panel.selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
5939
|
+
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
5940
|
+
const above = windowStart;
|
|
5941
|
+
const below = total - windowEnd;
|
|
5942
|
+
const provider = panel.view === "provider" ? authSelectedProvider(panel) : void 0;
|
|
5943
|
+
const logWindow = panel.log.slice(-Math.max(6, maxVisible));
|
|
5944
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
5945
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: UI_COLORS.title, children: viewTitle(panel) }),
|
|
5946
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: viewLegend(panel) }),
|
|
5947
|
+
panel.view === "provider" && provider ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
5948
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
5949
|
+
"type: ",
|
|
5950
|
+
provider.type ?? provider.id,
|
|
5951
|
+
" \xB7 family: ",
|
|
5952
|
+
provider.family ?? "unset",
|
|
5953
|
+
" \xB7 baseUrl:",
|
|
5954
|
+
" ",
|
|
5955
|
+
provider.baseUrl ?? "unset"
|
|
5956
|
+
] }),
|
|
5957
|
+
provider.models.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
5958
|
+
"models: ",
|
|
5959
|
+
provider.models.join(", ")
|
|
5960
|
+
] }) : null
|
|
5961
|
+
] }) : null,
|
|
5962
|
+
panel.view === "oauth" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
5963
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.warning, wrap: "truncate-end", children: "\u26A0 Subscription tokens used outside official clients may violate provider Terms \u2014" }),
|
|
5964
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.warning, wrap: "truncate-end", children: "your account could be rate-limited or banned. An API key is the sanctioned path." })
|
|
5965
|
+
] }) : null,
|
|
5966
|
+
panel.view === "catalog" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5967
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "filter: " }),
|
|
5968
|
+
panel.filter.length > 0 ? panel.filter : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(type to search)" }),
|
|
5969
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.focused, children: "\u258F" })
|
|
5970
|
+
] }) }) : null,
|
|
5971
|
+
panel.view === "flow" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
5972
|
+
logWindow.length === 0 && !panel.flowDone ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Starting\u2026" }) : null,
|
|
5973
|
+
logWindow.map((line) => /* @__PURE__ */ jsx(
|
|
5974
|
+
Text,
|
|
5975
|
+
{
|
|
5976
|
+
wrap: "truncate-end",
|
|
5977
|
+
color: line.startsWith("\u2717") ? UI_COLORS.error : line.startsWith("\u2713") ? UI_COLORS.active : void 0,
|
|
5978
|
+
dimColor: !line.startsWith("\u2717") && !line.startsWith("\u2713"),
|
|
5979
|
+
children: line
|
|
5980
|
+
},
|
|
5981
|
+
line
|
|
5982
|
+
)),
|
|
5983
|
+
panel.flowDone ? /* @__PURE__ */ jsxs(Text, { color: panel.flowOk ? UI_COLORS.active : UI_COLORS.error, children: [
|
|
5984
|
+
panel.flowOk ? "\u2713 Done." : "\u2717 Not completed.",
|
|
5985
|
+
" ",
|
|
5986
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Enter or Esc to go back." })
|
|
5987
|
+
] }) : panel.input ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
5988
|
+
/* @__PURE__ */ jsx(Text, { children: panel.input.label }),
|
|
5989
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.hint, children: panel.input.masked ? "\u2022".repeat(panel.input.draft.length) : panel.input.draft }),
|
|
5990
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.focused, children: "\u258F" })
|
|
5991
|
+
] }) : null
|
|
5992
|
+
] }) : null,
|
|
5993
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", minHeight: maxVisible, children: [
|
|
5994
|
+
above > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
5995
|
+
"\u25B2",
|
|
5996
|
+
" ",
|
|
5997
|
+
above,
|
|
5998
|
+
" above"
|
|
5999
|
+
] }) : null,
|
|
6000
|
+
allRows.slice(windowStart, windowEnd).map((row, ri) => /* @__PURE__ */ jsx(Box, { marginLeft: 0, children: renderRow(row, windowStart + ri === panel.selected, windowStart + ri) }, `row-${windowStart + ri}`)),
|
|
6001
|
+
Array.from({ length: maxVisible - (windowEnd - windowStart) }).map((_, i) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `pad-${i}`)),
|
|
6002
|
+
below > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
6003
|
+
"\u25BC",
|
|
6004
|
+
" ",
|
|
6005
|
+
below,
|
|
6006
|
+
" below"
|
|
6007
|
+
] }) : null
|
|
6008
|
+
] })
|
|
6009
|
+
] });
|
|
6010
|
+
}
|
|
6011
|
+
var AUTONOMY_OPTIONS = [
|
|
6012
|
+
{
|
|
6013
|
+
mode: "off",
|
|
6014
|
+
label: "OFF",
|
|
6015
|
+
description: "Agent stops after each turn (normal interactive mode)",
|
|
6016
|
+
color: "green"
|
|
6017
|
+
},
|
|
6018
|
+
{
|
|
6019
|
+
mode: "suggest",
|
|
6020
|
+
label: "SUGGEST",
|
|
6021
|
+
description: "Shows next-step suggestions after each turn",
|
|
6022
|
+
color: "cyan"
|
|
6023
|
+
},
|
|
6024
|
+
{
|
|
6025
|
+
mode: "auto",
|
|
6026
|
+
label: "AUTO",
|
|
6027
|
+
description: "Self-driving \u2014 agent picks next step and continues",
|
|
6028
|
+
color: "yellow"
|
|
6029
|
+
},
|
|
6030
|
+
{
|
|
6031
|
+
mode: "eternal",
|
|
6032
|
+
label: "ETERNAL",
|
|
6033
|
+
description: "Goal-driven loop \u2014 requires /goal set first",
|
|
6034
|
+
color: "red"
|
|
6035
|
+
},
|
|
6036
|
+
{
|
|
6037
|
+
mode: "eternal-parallel",
|
|
6038
|
+
label: "PARALLEL",
|
|
6039
|
+
description: "Fan-out 4\u20138 subagents per tick \u2014 requires /goal",
|
|
6040
|
+
color: "magenta"
|
|
6041
|
+
}
|
|
6042
|
+
];
|
|
6043
|
+
function AutonomyPicker({
|
|
6044
|
+
options,
|
|
6045
|
+
selected,
|
|
6046
|
+
hint
|
|
6047
|
+
}) {
|
|
6048
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
6049
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
|
|
6050
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
6051
|
+
options.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
6052
|
+
Text,
|
|
6053
|
+
{
|
|
6054
|
+
inverse: i === selected,
|
|
6055
|
+
...i === selected ? { color: opt.color } : {},
|
|
6056
|
+
children: [
|
|
6057
|
+
i === selected ? "\u203A " : " ",
|
|
6058
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
|
|
5734
6059
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
|
|
5735
6060
|
]
|
|
5736
6061
|
},
|
|
@@ -5822,6 +6147,39 @@ function BrainDecisionPrompt({
|
|
|
5822
6147
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press A/B/C or 1/2/3 to answer; Esc or D denies with the safe default." })
|
|
5823
6148
|
] });
|
|
5824
6149
|
}
|
|
6150
|
+
function toModeOptions(modes, activeId) {
|
|
6151
|
+
return modes.map((m) => ({
|
|
6152
|
+
id: m.id,
|
|
6153
|
+
name: m.name,
|
|
6154
|
+
description: m.description,
|
|
6155
|
+
isActive: m.id === activeId
|
|
6156
|
+
}));
|
|
6157
|
+
}
|
|
6158
|
+
function ModePicker({
|
|
6159
|
+
modes,
|
|
6160
|
+
selected,
|
|
6161
|
+
hint
|
|
6162
|
+
}) {
|
|
6163
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
6164
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Mode Selection \u2501\u2501" }),
|
|
6165
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel" }),
|
|
6166
|
+
modes.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No modes available." }) : modes.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
6167
|
+
Text,
|
|
6168
|
+
{
|
|
6169
|
+
inverse: i === selected,
|
|
6170
|
+
...i === selected ? { color: "cyan" } : {},
|
|
6171
|
+
children: [
|
|
6172
|
+
i === selected ? "\u203A " : " ",
|
|
6173
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.name.padEnd(20) }),
|
|
6174
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description }),
|
|
6175
|
+
opt.isActive ? /* @__PURE__ */ jsx(Text, { color: "green", children: " [active]" }) : null
|
|
6176
|
+
]
|
|
6177
|
+
},
|
|
6178
|
+
opt.id
|
|
6179
|
+
)),
|
|
6180
|
+
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
6181
|
+
] });
|
|
6182
|
+
}
|
|
5825
6183
|
function CheckpointTimeline({
|
|
5826
6184
|
checkpoints,
|
|
5827
6185
|
selected,
|
|
@@ -7150,29 +7508,28 @@ function visualEdit(toolName, text, ok) {
|
|
|
7150
7508
|
return rows;
|
|
7151
7509
|
}
|
|
7152
7510
|
function visualRead(text) {
|
|
7511
|
+
const header = parseHeaderLine(text);
|
|
7153
7512
|
const lines = bodyLines(text);
|
|
7154
7513
|
const numbered = lines.map((line) => line.match(/^\s*(\d+)→(.*)$/)).filter((match) => Boolean(match?.[1]));
|
|
7155
7514
|
if (numbered.length === 0) {
|
|
7156
|
-
const
|
|
7157
|
-
return
|
|
7515
|
+
const first2 = firstNonEmpty(lines.join("\n"));
|
|
7516
|
+
return first2 ? [{ kind: "meta", text: first2 }] : void 0;
|
|
7158
7517
|
}
|
|
7159
|
-
const
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
const extra = numbered.slice(10, 15).map((match) => ({
|
|
7166
|
-
kind: "code",
|
|
7167
|
-
lineNo: match[1],
|
|
7168
|
-
text: match[2] ?? ""
|
|
7169
|
-
}));
|
|
7170
|
-
rows.push(...extra);
|
|
7171
|
-
if (numbered.length > 15) {
|
|
7172
|
-
rows.push({ kind: "meta", text: `more ${numbered.length - 15} line(s)` });
|
|
7173
|
-
}
|
|
7518
|
+
const first = Number.parseInt(numbered[0]?.[1] ?? "", 10);
|
|
7519
|
+
const last = Number.parseInt(numbered[numbered.length - 1]?.[1] ?? "", 10);
|
|
7520
|
+
const total = numberFromParsedField(header.fields, "total_lines");
|
|
7521
|
+
const parts = [];
|
|
7522
|
+
if (Number.isFinite(first) && Number.isFinite(last)) {
|
|
7523
|
+
parts.push(first === last ? `L${first}` : `L${first}\u2013${last}`);
|
|
7174
7524
|
}
|
|
7175
|
-
|
|
7525
|
+
const contiguous = Number.isFinite(first) && Number.isFinite(last) ? numbered.length === last - first + 1 : true;
|
|
7526
|
+
parts.push(
|
|
7527
|
+
`${numbered.length} line${numbered.length === 1 ? "" : "s"}${contiguous ? "" : " (gaps)"}`
|
|
7528
|
+
);
|
|
7529
|
+
if (total !== void 0 && total !== numbered.length) parts.push(`${total} total`);
|
|
7530
|
+
if (header.fields["truncated"] === "true") parts.push("truncated");
|
|
7531
|
+
if (header.fields["cached"] === "true") parts.push("cached");
|
|
7532
|
+
return [{ kind: "meta", text: parts.join(" \xB7 ") }];
|
|
7176
7533
|
}
|
|
7177
7534
|
function visualSearch(toolName, text) {
|
|
7178
7535
|
const json = tryParseJson(text);
|
|
@@ -7894,6 +8251,7 @@ function numberFromParsedField(fields, key) {
|
|
|
7894
8251
|
}
|
|
7895
8252
|
var MAX_STREAM_DISPLAY_CHARS = 480;
|
|
7896
8253
|
var MAX_STREAM_LINES = 8;
|
|
8254
|
+
var WRITE_CREATE_STREAM_LINES = 3;
|
|
7897
8255
|
function streamBoxRows(text, maxLines, contentWidth) {
|
|
7898
8256
|
const trunc = (line) => line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
|
|
7899
8257
|
const lines = text.split("\n");
|
|
@@ -7922,21 +8280,23 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
|
|
|
7922
8280
|
return () => clearInterval(t);
|
|
7923
8281
|
}, []);
|
|
7924
8282
|
const elapsedMs = Date.now() - startedAt;
|
|
8283
|
+
const streamLines = name === "write" ? WRITE_CREATE_STREAM_LINES : MAX_STREAM_LINES;
|
|
7925
8284
|
const totalLines = text.split("\n").length;
|
|
7926
|
-
const hidden = Math.max(0, totalLines -
|
|
8285
|
+
const hidden = Math.max(0, totalLines - streamLines);
|
|
7927
8286
|
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
7928
|
-
const rows = streamBoxRows(text,
|
|
8287
|
+
const rows = streamBoxRows(text, streamLines, contentWidth);
|
|
8288
|
+
const isWritePreview = name === "write";
|
|
7929
8289
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
7930
8290
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
7931
8291
|
/* @__PURE__ */ jsxs(Text, { color, children: [
|
|
7932
8292
|
glyph2,
|
|
7933
8293
|
" "
|
|
7934
8294
|
] }),
|
|
7935
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color, children: name }),
|
|
8295
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color, children: isWritePreview ? "write \xB7 creating file" : name }),
|
|
7936
8296
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
|
|
7937
|
-
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${
|
|
8297
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${streamLines})` }) : null
|
|
7938
8298
|
] }),
|
|
7939
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => /* @__PURE__ */ jsx(Text, { dimColor:
|
|
8299
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => /* @__PURE__ */ jsx(Text, { color: isWritePreview ? "gray" : void 0, dimColor: !isWritePreview, italic: Boolean(r.italic), children: r.text || " " }, i)) })
|
|
7940
8300
|
] });
|
|
7941
8301
|
});
|
|
7942
8302
|
function tailForDisplay(text, maxChars) {
|
|
@@ -7949,7 +8309,7 @@ function tailForDisplay(text, maxChars) {
|
|
|
7949
8309
|
return `\u2026 ${text.slice(cut)}`;
|
|
7950
8310
|
}
|
|
7951
8311
|
var MAX_CODE_LINES = 80;
|
|
7952
|
-
var DIFF_MAX_LINES =
|
|
8312
|
+
var DIFF_MAX_LINES = Number.POSITIVE_INFINITY;
|
|
7953
8313
|
var DIFF_LINE_SAFETY_CAP = 4e3;
|
|
7954
8314
|
var DIFF_FALLBACK_WRAP_WIDTH = 100;
|
|
7955
8315
|
function CodeBlock({
|
|
@@ -8073,9 +8433,17 @@ function formatDiffStats(added, removed) {
|
|
|
8073
8433
|
const joined = parts.join(", ");
|
|
8074
8434
|
return joined.charAt(0).toUpperCase() + joined.slice(1);
|
|
8075
8435
|
}
|
|
8076
|
-
function
|
|
8077
|
-
if (
|
|
8078
|
-
return tokens.map((t
|
|
8436
|
+
function applyWashTokens(tokens, onWash) {
|
|
8437
|
+
if (!onWash) return tokens;
|
|
8438
|
+
return tokens.map((t) => {
|
|
8439
|
+
if (t.color !== "gray") return t;
|
|
8440
|
+
return { ...t, color: "grayBright", dim: false };
|
|
8441
|
+
});
|
|
8442
|
+
}
|
|
8443
|
+
function renderTokens(tokens, onWash = false) {
|
|
8444
|
+
const effective = applyWashTokens(tokens, onWash);
|
|
8445
|
+
if (effective.length === 0) return " ";
|
|
8446
|
+
return effective.map((t, j) => /* @__PURE__ */ jsx(
|
|
8079
8447
|
Text,
|
|
8080
8448
|
{
|
|
8081
8449
|
dimColor: Boolean(t.dim),
|
|
@@ -8189,7 +8557,7 @@ function DiffBlock({
|
|
|
8189
8557
|
/* @__PURE__ */ jsx(Text, { color: markerColor, bold: true, children: marker }),
|
|
8190
8558
|
/* @__PURE__ */ jsx(Text, { children: " " })
|
|
8191
8559
|
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: contPrefix }),
|
|
8192
|
-
renderTokens(seg),
|
|
8560
|
+
renderTokens(seg, true),
|
|
8193
8561
|
pad > 0 ? /* @__PURE__ */ jsx(Text, { children: " ".repeat(pad) }) : null
|
|
8194
8562
|
] }, si);
|
|
8195
8563
|
}) }, key);
|
|
@@ -8456,7 +8824,14 @@ function extractUnifiedDiffText(text) {
|
|
|
8456
8824
|
(line) => line.startsWith("--- ") || line.startsWith("diff --git") || line.startsWith("@@")
|
|
8457
8825
|
);
|
|
8458
8826
|
if (start === -1) return void 0;
|
|
8459
|
-
|
|
8827
|
+
let end = lines.length;
|
|
8828
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
8829
|
+
if (lines[i]?.length === 0) {
|
|
8830
|
+
end = i;
|
|
8831
|
+
break;
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
return lines.slice(start, end).join("\n");
|
|
8460
8835
|
}
|
|
8461
8836
|
function newFileDiffFromWriteInput(output, input) {
|
|
8462
8837
|
if (!input || typeof input !== "object") return void 0;
|
|
@@ -8596,13 +8971,13 @@ function fmtElapsed2(at, nowTick) {
|
|
|
8596
8971
|
function GoalRow({
|
|
8597
8972
|
goal
|
|
8598
8973
|
}) {
|
|
8599
|
-
const
|
|
8974
|
+
const statusColor2 = {
|
|
8600
8975
|
active: "green",
|
|
8601
8976
|
paused: "yellow",
|
|
8602
8977
|
completed: "gray",
|
|
8603
8978
|
failed: "red"
|
|
8604
8979
|
};
|
|
8605
|
-
const color =
|
|
8980
|
+
const color = statusColor2[goal.status] ?? "gray";
|
|
8606
8981
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
8607
8982
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color, bold: true, children: [
|
|
8608
8983
|
goal.status === "active" ? "\u25B6" : goal.status === "paused" ? "\u23F8" : goal.status === "completed" ? "\u2713" : "\u2717",
|
|
@@ -8964,9 +9339,188 @@ function FilePicker({ query, matches, selected }) {
|
|
|
8964
9339
|
function highlight(path8, _query) {
|
|
8965
9340
|
return path8;
|
|
8966
9341
|
}
|
|
8967
|
-
|
|
8968
|
-
|
|
9342
|
+
var TERMINAL_TTL_MS = 9e4;
|
|
9343
|
+
var METER_WIDTH = 10;
|
|
9344
|
+
function isLeaderEntry2(entry) {
|
|
9345
|
+
return entry.id === "leader" || entry.name === "LEADER";
|
|
9346
|
+
}
|
|
9347
|
+
function statusColor(status) {
|
|
9348
|
+
if (status === "running") return "green";
|
|
9349
|
+
if (status === "success") return "green";
|
|
9350
|
+
if (status === "failed") return "red";
|
|
9351
|
+
if (status === "timeout") return "yellow";
|
|
9352
|
+
if (status === "stopped") return "gray";
|
|
9353
|
+
return "gray";
|
|
9354
|
+
}
|
|
9355
|
+
function fmtShortDuration2(ms) {
|
|
9356
|
+
if (ms < 1e3) return `${Math.max(0, Math.round(ms))}ms`;
|
|
9357
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(ms < 1e4 ? 1 : 0)}s`;
|
|
9358
|
+
const m = Math.floor(ms / 6e4);
|
|
9359
|
+
const s2 = Math.floor(ms % 6e4 / 1e3);
|
|
9360
|
+
return `${m}m${s2.toString().padStart(2, "0")}s`;
|
|
9361
|
+
}
|
|
9362
|
+
function fmtCost2(n) {
|
|
9363
|
+
if (n <= 0) return "";
|
|
9364
|
+
return `$${n.toFixed(4)}`;
|
|
9365
|
+
}
|
|
9366
|
+
function normalizeInlineText(text) {
|
|
9367
|
+
return text.replace(/\s+/g, " ").trim();
|
|
9368
|
+
}
|
|
9369
|
+
function truncToWidth(text, width) {
|
|
9370
|
+
if (width <= 0) return "";
|
|
9371
|
+
if (text.length <= width) return text;
|
|
9372
|
+
if (width === 1) return "\u2026";
|
|
9373
|
+
return `${text.slice(0, width - 1)}\u2026`;
|
|
9374
|
+
}
|
|
9375
|
+
function displayName(entry, roster) {
|
|
9376
|
+
const rosterName = roster?.[entry.id]?.name;
|
|
9377
|
+
const name = rosterName || entry.name || entry.id;
|
|
9378
|
+
return normalizeInlineText(name) || entry.id.slice(0, 8);
|
|
9379
|
+
}
|
|
9380
|
+
function activityText(entry, now) {
|
|
9381
|
+
if (entry.currentTool) {
|
|
9382
|
+
return `${entry.currentTool.name} ${fmtShortDuration2(now - entry.currentTool.startedAt)}`;
|
|
9383
|
+
}
|
|
9384
|
+
const streaming = normalizeInlineText(entry.streamingText);
|
|
9385
|
+
if (entry.status === "running" && streaming) return streaming;
|
|
9386
|
+
const lastMessage = entry.recentMessages.at(-1);
|
|
9387
|
+
if (lastMessage) return normalizeInlineText(lastMessage.text);
|
|
9388
|
+
const lastTool = entry.recentTools.at(-1);
|
|
9389
|
+
if (lastTool) {
|
|
9390
|
+
const ok = lastTool.ok === false ? "failed" : "done";
|
|
9391
|
+
return `${ok} ${lastTool.name}`;
|
|
9392
|
+
}
|
|
9393
|
+
if (entry.status === "running") return "thinking";
|
|
9394
|
+
if (entry.status === "idle") return "standing by";
|
|
9395
|
+
if (entry.status === "success") return "complete";
|
|
9396
|
+
if (entry.status === "timeout") return "timeout";
|
|
9397
|
+
if (entry.status === "stopped") return "stopped";
|
|
9398
|
+
return entry.failureReason ? `failed ${entry.failureReason}` : "failed";
|
|
9399
|
+
}
|
|
9400
|
+
function swarmMeter(entry, now, width = METER_WIDTH) {
|
|
9401
|
+
if (width <= 0) return "";
|
|
9402
|
+
if (entry.status === "success") return "\u2588".repeat(width);
|
|
9403
|
+
if (entry.status === "failed" || entry.status === "timeout" || entry.status === "stopped") {
|
|
9404
|
+
return "\u25A0".repeat(width);
|
|
9405
|
+
}
|
|
9406
|
+
if (entry.status === "idle") return "\u2591".repeat(width);
|
|
9407
|
+
const elapsedBucket = Math.floor(Math.max(0, now - entry.startedAt) / 1e3);
|
|
9408
|
+
const phase = (elapsedBucket + entry.iterations + entry.toolCalls) % width;
|
|
9409
|
+
const filled = Math.max(Math.min(width, 2), Math.min(width, phase + 1));
|
|
9410
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
9411
|
+
}
|
|
9412
|
+
function swarmColumnCount(width) {
|
|
9413
|
+
if (width < 54) return 1;
|
|
9414
|
+
return Math.max(1, Math.min(5, Math.floor(width / 38)));
|
|
9415
|
+
}
|
|
9416
|
+
function selectSwarmEntries(entries, now, opts = {}) {
|
|
9417
|
+
const terminalTtlMs = opts.terminalTtlMs ?? TERMINAL_TTL_MS;
|
|
9418
|
+
return Object.values(entries).filter((entry) => {
|
|
9419
|
+
if (isLeaderEntry2(entry) && !opts.includeLeader) return false;
|
|
9420
|
+
if (entry.status === "running" || entry.status === "idle") return true;
|
|
9421
|
+
return now - entry.lastEventAt <= terminalTtlMs;
|
|
9422
|
+
}).sort((a, b) => {
|
|
9423
|
+
const rank = (entry) => {
|
|
9424
|
+
if (entry.status === "running") return 0;
|
|
9425
|
+
if (entry.status === "idle") return 1;
|
|
9426
|
+
return 2;
|
|
9427
|
+
};
|
|
9428
|
+
const ar = rank(a);
|
|
9429
|
+
const br = rank(b);
|
|
9430
|
+
if (ar !== br) return ar - br;
|
|
9431
|
+
if (ar === 2) return b.lastEventAt - a.lastEventAt;
|
|
9432
|
+
return a.startedAt - b.startedAt;
|
|
9433
|
+
});
|
|
9434
|
+
}
|
|
9435
|
+
function buildSwarmGrid(entries, now, width, opts = {}) {
|
|
9436
|
+
const columns = swarmColumnCount(width);
|
|
9437
|
+
const gapWidth = Math.max(0, columns - 1) * 2;
|
|
9438
|
+
const tileWidth = Math.max(24, Math.floor((Math.max(24, width) - gapWidth) / columns));
|
|
9439
|
+
const maxRows = opts.maxRows ?? 3;
|
|
9440
|
+
const maxCells = Math.max(1, columns * maxRows);
|
|
9441
|
+
const selected = selectSwarmEntries(entries, now, { includeLeader: opts.includeLeader });
|
|
9442
|
+
const hasOverflow = selected.length > maxCells;
|
|
9443
|
+
const shown = hasOverflow ? selected.slice(0, maxCells - 1) : selected.slice(0, maxCells);
|
|
9444
|
+
const bodyWidth = Math.max(6, tileWidth - 3 - 1 - (METER_WIDTH + 2) - 1);
|
|
9445
|
+
const cells = shown.map((entry, i) => {
|
|
9446
|
+
const name = displayName(entry, opts.roster);
|
|
9447
|
+
const label = `${name} \xB7 ${activityText(entry, now)}`;
|
|
9448
|
+
return {
|
|
9449
|
+
id: entry.id,
|
|
9450
|
+
index: String(i + 1).padStart(3, "0"),
|
|
9451
|
+
meter: swarmMeter(entry, now),
|
|
9452
|
+
text: truncToWidth(label, bodyWidth),
|
|
9453
|
+
color: statusColor(entry.status),
|
|
9454
|
+
dim: entry.status === "idle"
|
|
9455
|
+
};
|
|
9456
|
+
});
|
|
9457
|
+
const overflow = selected.length - shown.length;
|
|
9458
|
+
if (overflow > 0) {
|
|
9459
|
+
cells.push({
|
|
9460
|
+
id: "__overflow",
|
|
9461
|
+
index: "+++",
|
|
9462
|
+
meter: "\u2591".repeat(METER_WIDTH),
|
|
9463
|
+
text: truncToWidth(`${overflow} more agents`, bodyWidth),
|
|
9464
|
+
color: "gray",
|
|
9465
|
+
dim: true
|
|
9466
|
+
});
|
|
9467
|
+
}
|
|
9468
|
+
const rows = [];
|
|
9469
|
+
for (let i = 0; i < cells.length; i += columns) rows.push(cells.slice(i, i + columns));
|
|
9470
|
+
return { columns, tileWidth, overflow, rows };
|
|
9471
|
+
}
|
|
9472
|
+
function buildTodoPreviewRows(todos, width, maxRows = 5) {
|
|
9473
|
+
if (!todos || todos.length === 0 || maxRows <= 0) return [];
|
|
9474
|
+
const ordered = [...todos].sort((a, b) => {
|
|
9475
|
+
const rank = (t) => t.status === "in_progress" ? 0 : t.status === "pending" ? 1 : 2;
|
|
9476
|
+
return rank(a) - rank(b);
|
|
9477
|
+
});
|
|
9478
|
+
const shown = ordered.slice(0, maxRows);
|
|
9479
|
+
const textWidth = Math.max(4, width - 5);
|
|
9480
|
+
const rows = shown.map((todo) => {
|
|
9481
|
+
const label = todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content;
|
|
9482
|
+
if (todo.status === "completed") {
|
|
9483
|
+
return {
|
|
9484
|
+
id: todo.id,
|
|
9485
|
+
marker: "\u2713",
|
|
9486
|
+
text: truncToWidth(label, textWidth),
|
|
9487
|
+
color: "green",
|
|
9488
|
+
dim: true
|
|
9489
|
+
};
|
|
9490
|
+
}
|
|
9491
|
+
if (todo.status === "in_progress") {
|
|
9492
|
+
return {
|
|
9493
|
+
id: todo.id,
|
|
9494
|
+
marker: "\u25CF",
|
|
9495
|
+
text: truncToWidth(label, textWidth),
|
|
9496
|
+
color: "blue"
|
|
9497
|
+
};
|
|
9498
|
+
}
|
|
9499
|
+
return {
|
|
9500
|
+
id: todo.id,
|
|
9501
|
+
marker: "\u25CB",
|
|
9502
|
+
text: truncToWidth(label, textWidth),
|
|
9503
|
+
color: "gray"
|
|
9504
|
+
};
|
|
9505
|
+
});
|
|
9506
|
+
const overflow = ordered.length - shown.length;
|
|
9507
|
+
if (overflow > 0) {
|
|
9508
|
+
rows.push({
|
|
9509
|
+
id: "__todo_overflow",
|
|
9510
|
+
marker: "+",
|
|
9511
|
+
text: truncToWidth(`${overflow} more`, textWidth),
|
|
9512
|
+
color: "gray",
|
|
9513
|
+
dim: true
|
|
9514
|
+
});
|
|
9515
|
+
}
|
|
9516
|
+
return rows;
|
|
9517
|
+
}
|
|
9518
|
+
function FleetPanel({
|
|
9519
|
+
entries,
|
|
8969
9520
|
totalCost,
|
|
9521
|
+
roster,
|
|
9522
|
+
todos,
|
|
9523
|
+
nowTick,
|
|
8970
9524
|
collabSession
|
|
8971
9525
|
}) {
|
|
8972
9526
|
const { stdout } = useStdout();
|
|
@@ -8980,52 +9534,54 @@ function FleetPanel({
|
|
|
8980
9534
|
};
|
|
8981
9535
|
}, [stdout]);
|
|
8982
9536
|
const list = Object.values(entries);
|
|
8983
|
-
if (list.length === 0 && !collabSession) return null;
|
|
8984
|
-
const nameMaxLen = Math.max(6, Math.min(14, termWidth - 30));
|
|
8985
9537
|
const leader = list.find((e) => e.id === "leader");
|
|
8986
|
-
const subagents = list.filter((e) => e
|
|
8987
|
-
const running = subagents.filter((e) => e.status === "running");
|
|
8988
|
-
const runningCount = running.length;
|
|
9538
|
+
const subagents = list.filter((e) => !isLeaderEntry2(e));
|
|
8989
9539
|
const hasCollab = !!collabSession;
|
|
8990
|
-
const
|
|
8991
|
-
const
|
|
8992
|
-
const
|
|
8993
|
-
const
|
|
8994
|
-
|
|
8995
|
-
|
|
9540
|
+
const now = nowTick ?? Date.now();
|
|
9541
|
+
const contentWidth = Math.max(40, termWidth - 2);
|
|
9542
|
+
const includeLeader = hasCollab || leader?.status === "running";
|
|
9543
|
+
const grid = buildSwarmGrid(entries, now, contentWidth, {
|
|
9544
|
+
includeLeader,
|
|
9545
|
+
maxRows: termWidth >= 120 ? 3 : 4,
|
|
9546
|
+
roster
|
|
9547
|
+
});
|
|
9548
|
+
const todoRows = buildTodoPreviewRows(todos, contentWidth, 5);
|
|
9549
|
+
const hasSwarm = grid.rows.length > 0;
|
|
9550
|
+
if (!hasSwarm && todoRows.length === 0 && !hasCollab) return null;
|
|
9551
|
+
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
|
+
const summaryBits = [
|
|
9558
|
+
runningCount > 0 ? `${runningCount} running` : "idle",
|
|
9559
|
+
idleCount > 0 ? `${idleCount} idle` : "",
|
|
9560
|
+
doneCount > 0 ? `${doneCount} done` : "",
|
|
9561
|
+
failedCount > 0 ? `${failedCount} failed` : "",
|
|
9562
|
+
fmtCost2(totalCost)
|
|
9563
|
+
].filter(Boolean);
|
|
9564
|
+
const collabLabel = hasCollab && collabSession.sessionId ? `collab ${collabSession.bugCount}b/${collabSession.planCount}p/${collabSession.evalCount}e` : "";
|
|
9565
|
+
if (collabLabel) summaryBits.push(collabLabel);
|
|
9566
|
+
const summary = summaryBits.join(" \xB7 ");
|
|
9567
|
+
const title = ` Agent Swarm${summary ? ` - ${summary}` : ""} `;
|
|
9568
|
+
const header = `\u2500${truncToWidth(title, Math.max(10, contentWidth - 1)).padEnd(contentWidth - 1, "\u2500")}`;
|
|
8996
9569
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
8997
|
-
/* @__PURE__ */
|
|
8998
|
-
|
|
8999
|
-
/* @__PURE__ */ jsx(Text, {
|
|
9000
|
-
/* @__PURE__ */ jsx(Text, { children:
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
/* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF" }),
|
|
9013
|
-
/* @__PURE__ */ jsx(Text, { children: name.slice(0, nameMaxLen) }),
|
|
9014
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2192" }),
|
|
9015
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: tool })
|
|
9016
|
-
] }, entry.id);
|
|
9017
|
-
}),
|
|
9018
|
-
overflow > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
9019
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
9020
|
-
"+",
|
|
9021
|
-
overflow,
|
|
9022
|
-
":"
|
|
9023
|
-
] }),
|
|
9024
|
-
running.slice(5, 7).map((e) => /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
9025
|
-
e.name?.split(" ")[0]?.slice(0, nameMaxLen - 2) ?? "agent",
|
|
9026
|
-
","
|
|
9027
|
-
] }, e.id)),
|
|
9028
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2026" })
|
|
9570
|
+
/* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { color: "blue", children: header }) }),
|
|
9571
|
+
grid.rows.map((row, rowIndex) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, height: 1, children: row.map((cell) => /* @__PURE__ */ jsxs(Box, { width: grid.tileWidth, flexShrink: 0, children: [
|
|
9572
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", children: cell.index }),
|
|
9573
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " [" }),
|
|
9574
|
+
/* @__PURE__ */ jsx(Text, { color: cell.color, children: cell.meter }),
|
|
9575
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "] " }),
|
|
9576
|
+
/* @__PURE__ */ jsx(Text, { color: cell.color, ...cell.dim ? { dimColor: true } : {}, wrap: "truncate", children: cell.text })
|
|
9577
|
+
] }, cell.id)) }, `swarm-row-${rowIndex}`)),
|
|
9578
|
+
todoRows.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
9579
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", children: "Todo" }),
|
|
9580
|
+
todoRows.map((row) => /* @__PURE__ */ jsxs(Box, { height: 1, children: [
|
|
9581
|
+
/* @__PURE__ */ jsx(Text, { color: row.color, children: row.marker }),
|
|
9582
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
9583
|
+
/* @__PURE__ */ jsx(Text, { color: row.color, ...row.dim ? { dimColor: true } : {}, wrap: "truncate", children: row.text })
|
|
9584
|
+
] }, row.id))
|
|
9029
9585
|
] }) : null
|
|
9030
9586
|
] });
|
|
9031
9587
|
}
|
|
@@ -9466,10 +10022,10 @@ function renderTable(tableLines, maxWidth) {
|
|
|
9466
10022
|
const widths = computeWidths([header, ...dataRows], cols, maxWidth, sepWidths);
|
|
9467
10023
|
const lines = [];
|
|
9468
10024
|
lines.push(border("\u250C", "\u252C", "\u2510", widths));
|
|
9469
|
-
lines.push(...
|
|
10025
|
+
lines.push(...renderRow2(header, widths, aligns));
|
|
9470
10026
|
lines.push(border("\u251C", "\u253C", "\u2524", widths));
|
|
9471
10027
|
for (const row of dataRows) {
|
|
9472
|
-
lines.push(...
|
|
10028
|
+
lines.push(...renderRow2(row, widths, aligns));
|
|
9473
10029
|
}
|
|
9474
10030
|
lines.push(border("\u2514", "\u2534", "\u2518", widths));
|
|
9475
10031
|
return lines.join("\n");
|
|
@@ -9640,7 +10196,7 @@ var ANSI_RESET_ALL = "\x1B[0m";
|
|
|
9640
10196
|
function applyInlineAnsi(text) {
|
|
9641
10197
|
return text.replace(/\*\*(.+?)\*\*/g, `${ANSI_BOLD}$1${ANSI_RESET_ALL}`).replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, `${ANSI_DIM}$1${ANSI_RESET_ALL}`).replace(/`(.+?)`/g, `${ANSI_CYAN}$1${ANSI_RESET_ALL}`).replace(/~~(.+?)~~/g, `${ANSI_STRIKE}$1${ANSI_RESET_ALL}`);
|
|
9642
10198
|
}
|
|
9643
|
-
function
|
|
10199
|
+
function renderRow2(cells, widths, aligns) {
|
|
9644
10200
|
const styled = cells.map((c) => applyInlineAnsi(c));
|
|
9645
10201
|
const safe = styled.map((c) => breakLigatures(c));
|
|
9646
10202
|
const wrapped = safe.map((c, i) => wrapCell(c, widths[i] ?? MIN_COL_WIDTH));
|
|
@@ -10233,6 +10789,27 @@ var Entry = React5.memo(function Entry2({
|
|
|
10233
10789
|
] })
|
|
10234
10790
|
}
|
|
10235
10791
|
);
|
|
10792
|
+
case "thinking": {
|
|
10793
|
+
const contentWidth = assistantContentWidth(termWidth);
|
|
10794
|
+
return /* @__PURE__ */ jsxs(
|
|
10795
|
+
Box,
|
|
10796
|
+
{
|
|
10797
|
+
flexDirection: "column",
|
|
10798
|
+
marginX: 0,
|
|
10799
|
+
marginY: 1,
|
|
10800
|
+
borderStyle: "single",
|
|
10801
|
+
borderTop: false,
|
|
10802
|
+
borderRight: false,
|
|
10803
|
+
borderBottom: false,
|
|
10804
|
+
borderColor: "magenta",
|
|
10805
|
+
paddingLeft: 1,
|
|
10806
|
+
children: [
|
|
10807
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "THINKING" }) }),
|
|
10808
|
+
/* @__PURE__ */ jsx(AssistantBody, { text: entry.text, termWidth, contentWidth })
|
|
10809
|
+
]
|
|
10810
|
+
}
|
|
10811
|
+
);
|
|
10812
|
+
}
|
|
10236
10813
|
case "assistant": {
|
|
10237
10814
|
const contentWidth = assistantContentWidth(termWidth);
|
|
10238
10815
|
const { steps, stripped } = nextSteps;
|
|
@@ -10732,21 +11309,21 @@ function inputIndexAtRowCol(prompt, value, width, row, col) {
|
|
|
10732
11309
|
rows.push(cur);
|
|
10733
11310
|
starts.push(curStart);
|
|
10734
11311
|
}
|
|
10735
|
-
const
|
|
11312
|
+
const clamp2 = (n) => Math.max(0, Math.min(value.length, n));
|
|
10736
11313
|
if (row < 0) return 0;
|
|
10737
11314
|
if (row >= rows.length) return value.length;
|
|
10738
11315
|
const r = rows[row];
|
|
10739
11316
|
const c = Math.max(0, col);
|
|
10740
11317
|
if (c < r.length) {
|
|
10741
11318
|
const b = r[c].buf;
|
|
10742
|
-
return b < 0 ? 0 :
|
|
11319
|
+
return b < 0 ? 0 : clamp2(b);
|
|
10743
11320
|
}
|
|
10744
11321
|
for (let k = r.length - 1; k >= 0; k--) {
|
|
10745
11322
|
const b = r[k].buf;
|
|
10746
|
-
if (b >= 0) return
|
|
11323
|
+
if (b >= 0) return clamp2(b + 1);
|
|
10747
11324
|
}
|
|
10748
11325
|
const start = starts[row];
|
|
10749
|
-
return
|
|
11326
|
+
return clamp2(start !== void 0 && start >= 0 ? start : value.length);
|
|
10750
11327
|
}
|
|
10751
11328
|
|
|
10752
11329
|
// src/mouse.ts
|
|
@@ -10787,7 +11364,7 @@ function parseMouseEvents(data) {
|
|
|
10787
11364
|
function isLeakedMouseInput(input) {
|
|
10788
11365
|
return LEAKED_MOUSE_RE.test(input);
|
|
10789
11366
|
}
|
|
10790
|
-
function
|
|
11367
|
+
function renderRow3(cells, rowKey, promptColor) {
|
|
10791
11368
|
const out = [];
|
|
10792
11369
|
let run = "";
|
|
10793
11370
|
let runStart = 0;
|
|
@@ -11002,11 +11579,456 @@ var Input = memo(function Input2({
|
|
|
11002
11579
|
}
|
|
11003
11580
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
11004
11581
|
rows.map(
|
|
11005
|
-
(row, i) => row.length === 0 ? /* @__PURE__ */ jsx(Text, { children: " " }, i) : /* @__PURE__ */ jsx(Text, { children:
|
|
11582
|
+
(row, i) => row.length === 0 ? /* @__PURE__ */ jsx(Text, { children: " " }, i) : /* @__PURE__ */ jsx(Text, { children: renderRow3(row, `r${i}`, promptColor) }, i)
|
|
11006
11583
|
),
|
|
11007
11584
|
hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
|
|
11008
11585
|
] });
|
|
11009
11586
|
});
|
|
11587
|
+
function KanbanPanel({ projectRoot, onClose }) {
|
|
11588
|
+
const [boards, setBoards] = useState([]);
|
|
11589
|
+
const [selectedBoard, setSelectedBoard] = useState(0);
|
|
11590
|
+
const [selectedTask, setSelectedTask] = useState(0);
|
|
11591
|
+
const [board, setBoard] = useState(null);
|
|
11592
|
+
const [loading, setLoading] = useState(true);
|
|
11593
|
+
const [error, setError] = useState(null);
|
|
11594
|
+
const [notice, setNotice] = useState(null);
|
|
11595
|
+
const [prompt, setPrompt] = useState(null);
|
|
11596
|
+
const sortedColumns = useMemo(
|
|
11597
|
+
() => [...board?.columns ?? []].sort((a, b) => a.order - b.order),
|
|
11598
|
+
[board]
|
|
11599
|
+
);
|
|
11600
|
+
const visibleTasks = useMemo(() => {
|
|
11601
|
+
if (!board) return [];
|
|
11602
|
+
return sortedColumns.flatMap(
|
|
11603
|
+
(column) => board.tasks.filter((task) => task.columnId === column.id).sort((a, b) => a.order - b.order)
|
|
11604
|
+
);
|
|
11605
|
+
}, [board, sortedColumns]);
|
|
11606
|
+
const activeTask = visibleTasks[selectedTask] ?? null;
|
|
11607
|
+
const transferTarget = nextBoard(boards, board?.id);
|
|
11608
|
+
async function load(nextBoardIndex = selectedBoard, nextTaskIndex = selectedTask) {
|
|
11609
|
+
setLoading(true);
|
|
11610
|
+
setError(null);
|
|
11611
|
+
try {
|
|
11612
|
+
const summaries = await listBoards(projectRoot);
|
|
11613
|
+
setBoards(summaries);
|
|
11614
|
+
const clampedBoard = clamp(nextBoardIndex, 0, Math.max(0, summaries.length - 1));
|
|
11615
|
+
setSelectedBoard(clampedBoard);
|
|
11616
|
+
const active = summaries[clampedBoard];
|
|
11617
|
+
const loaded = active ? await getBoard(projectRoot, active.id) : null;
|
|
11618
|
+
setBoard(loaded);
|
|
11619
|
+
const taskCount = loaded?.tasks.length ?? 0;
|
|
11620
|
+
setSelectedTask(clamp(nextTaskIndex, 0, Math.max(0, taskCount - 1)));
|
|
11621
|
+
} catch (err) {
|
|
11622
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
11623
|
+
} finally {
|
|
11624
|
+
setLoading(false);
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
async function runMutation(fn, selection = {}) {
|
|
11628
|
+
setLoading(true);
|
|
11629
|
+
setError(null);
|
|
11630
|
+
try {
|
|
11631
|
+
const message = await fn();
|
|
11632
|
+
setNotice(message ?? null);
|
|
11633
|
+
await load(selection.boardIndex ?? selectedBoard, selection.taskIndex ?? selectedTask);
|
|
11634
|
+
} catch (err) {
|
|
11635
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
11636
|
+
} finally {
|
|
11637
|
+
setLoading(false);
|
|
11638
|
+
}
|
|
11639
|
+
}
|
|
11640
|
+
async function commitPrompt() {
|
|
11641
|
+
if (!prompt) return;
|
|
11642
|
+
if (prompt.kind === "confirmDeleteTask") {
|
|
11643
|
+
setPrompt(null);
|
|
11644
|
+
await runMutation(async () => {
|
|
11645
|
+
if (!board) return null;
|
|
11646
|
+
await removeTask(projectRoot, board.id, prompt.task.id);
|
|
11647
|
+
return `Deleted task: ${prompt.task.title}`;
|
|
11648
|
+
});
|
|
11649
|
+
return;
|
|
11650
|
+
}
|
|
11651
|
+
const value = prompt.buffer.trim();
|
|
11652
|
+
if (!value) return;
|
|
11653
|
+
const kind = prompt.kind;
|
|
11654
|
+
setPrompt(null);
|
|
11655
|
+
await runMutation(
|
|
11656
|
+
async () => {
|
|
11657
|
+
if (kind === "createBoard") {
|
|
11658
|
+
const created = await createBoard(projectRoot, { title: value });
|
|
11659
|
+
return `Created board: ${created.title}`;
|
|
11660
|
+
}
|
|
11661
|
+
if (!board) return null;
|
|
11662
|
+
const added = await addTask(projectRoot, board.id, {
|
|
11663
|
+
title: value,
|
|
11664
|
+
columnId: sortedColumns[0]?.id ?? "backlog"
|
|
11665
|
+
});
|
|
11666
|
+
return added ? `Added task: ${added.task.title}` : "Task add failed";
|
|
11667
|
+
},
|
|
11668
|
+
kind === "createBoard" ? { boardIndex: 0, taskIndex: 0 } : { taskIndex: board?.tasks.length }
|
|
11669
|
+
);
|
|
11670
|
+
}
|
|
11671
|
+
useEffect(() => {
|
|
11672
|
+
void load(0, 0);
|
|
11673
|
+
}, [projectRoot]);
|
|
11674
|
+
useInput((input, key) => {
|
|
11675
|
+
if (prompt) {
|
|
11676
|
+
if (key.escape) {
|
|
11677
|
+
setPrompt(null);
|
|
11678
|
+
return;
|
|
11679
|
+
}
|
|
11680
|
+
if (prompt.kind === "confirmDeleteTask") {
|
|
11681
|
+
if (input.toLowerCase() === "y") void commitPrompt();
|
|
11682
|
+
else if (input.toLowerCase() === "n") setPrompt(null);
|
|
11683
|
+
return;
|
|
11684
|
+
}
|
|
11685
|
+
if (key.return || input === "\r" || input === "\n") {
|
|
11686
|
+
void commitPrompt();
|
|
11687
|
+
return;
|
|
11688
|
+
}
|
|
11689
|
+
if (key.backspace || key.delete) {
|
|
11690
|
+
setPrompt({ ...prompt, buffer: prompt.buffer.slice(0, -1) });
|
|
11691
|
+
return;
|
|
11692
|
+
}
|
|
11693
|
+
if (input && !key.ctrl && !key.meta && input >= " ") {
|
|
11694
|
+
setPrompt({ ...prompt, buffer: `${prompt.buffer}${input}` });
|
|
11695
|
+
}
|
|
11696
|
+
return;
|
|
11697
|
+
}
|
|
11698
|
+
if (key.escape || input === "q") {
|
|
11699
|
+
onClose();
|
|
11700
|
+
return;
|
|
11701
|
+
}
|
|
11702
|
+
if (input === "r" || input === "R") {
|
|
11703
|
+
void load(selectedBoard, selectedTask);
|
|
11704
|
+
return;
|
|
11705
|
+
}
|
|
11706
|
+
if (input === "c") {
|
|
11707
|
+
setPrompt({ kind: "createBoard", buffer: "" });
|
|
11708
|
+
return;
|
|
11709
|
+
}
|
|
11710
|
+
if (input === "a" && board) {
|
|
11711
|
+
setPrompt({ kind: "addTask", buffer: "" });
|
|
11712
|
+
return;
|
|
11713
|
+
}
|
|
11714
|
+
if ((input === "n" || key.downArrow) && boards.length > 0) {
|
|
11715
|
+
void load(clamp(selectedBoard + 1, 0, boards.length - 1), 0);
|
|
11716
|
+
return;
|
|
11717
|
+
}
|
|
11718
|
+
if ((input === "p" || key.upArrow) && boards.length > 0) {
|
|
11719
|
+
void load(clamp(selectedBoard - 1, 0, boards.length - 1), 0);
|
|
11720
|
+
return;
|
|
11721
|
+
}
|
|
11722
|
+
if (key.shift && key.tab && visibleTasks.length > 0) {
|
|
11723
|
+
setSelectedTask((idx) => (idx - 1 + visibleTasks.length) % visibleTasks.length);
|
|
11724
|
+
return;
|
|
11725
|
+
}
|
|
11726
|
+
if (key.tab && visibleTasks.length > 0) {
|
|
11727
|
+
setSelectedTask((idx) => (idx + 1) % visibleTasks.length);
|
|
11728
|
+
return;
|
|
11729
|
+
}
|
|
11730
|
+
if (key.rightArrow && board && activeTask) {
|
|
11731
|
+
const nextColumn = adjacentColumn(sortedColumns, activeTask.columnId, 1);
|
|
11732
|
+
if (nextColumn) {
|
|
11733
|
+
void runMutation(async () => {
|
|
11734
|
+
await moveTask(projectRoot, board.id, activeTask.id, nextColumn.id);
|
|
11735
|
+
return `Moved to ${nextColumn.title}`;
|
|
11736
|
+
});
|
|
11737
|
+
}
|
|
11738
|
+
return;
|
|
11739
|
+
}
|
|
11740
|
+
if (key.leftArrow && board && activeTask) {
|
|
11741
|
+
const prevColumn = adjacentColumn(sortedColumns, activeTask.columnId, -1);
|
|
11742
|
+
if (prevColumn) {
|
|
11743
|
+
void runMutation(async () => {
|
|
11744
|
+
await moveTask(projectRoot, board.id, activeTask.id, prevColumn.id);
|
|
11745
|
+
return `Moved to ${prevColumn.title}`;
|
|
11746
|
+
});
|
|
11747
|
+
}
|
|
11748
|
+
return;
|
|
11749
|
+
}
|
|
11750
|
+
if ((input === " " || input === "D") && board && activeTask) {
|
|
11751
|
+
void runMutation(async () => {
|
|
11752
|
+
await updateTask(projectRoot, board.id, activeTask.id, {
|
|
11753
|
+
status: "completed",
|
|
11754
|
+
columnId: doneColumnId(board) ?? activeTask.columnId
|
|
11755
|
+
});
|
|
11756
|
+
return `Completed task: ${activeTask.title}`;
|
|
11757
|
+
});
|
|
11758
|
+
return;
|
|
11759
|
+
}
|
|
11760
|
+
if (input === "b" && board && activeTask) {
|
|
11761
|
+
void runMutation(async () => {
|
|
11762
|
+
await updateTask(projectRoot, board.id, activeTask.id, { status: "blocked" });
|
|
11763
|
+
return `Blocked task: ${activeTask.title}`;
|
|
11764
|
+
});
|
|
11765
|
+
return;
|
|
11766
|
+
}
|
|
11767
|
+
if (input === "x" && activeTask) {
|
|
11768
|
+
setPrompt({ kind: "confirmDeleteTask", task: activeTask });
|
|
11769
|
+
return;
|
|
11770
|
+
}
|
|
11771
|
+
if (input === "d" && board) {
|
|
11772
|
+
void runMutation(
|
|
11773
|
+
async () => {
|
|
11774
|
+
const duplicated = await duplicateBoard(projectRoot, board.id, {
|
|
11775
|
+
title: `${board.title} Copy`,
|
|
11776
|
+
preserveAssignment: true
|
|
11777
|
+
});
|
|
11778
|
+
return duplicated ? `Duplicated board: ${duplicated.title}` : "Board duplicate failed";
|
|
11779
|
+
},
|
|
11780
|
+
{ boardIndex: 0, taskIndex: selectedTask }
|
|
11781
|
+
);
|
|
11782
|
+
return;
|
|
11783
|
+
}
|
|
11784
|
+
if (input === "C" && board && activeTask && transferTarget) {
|
|
11785
|
+
void runMutation(async () => {
|
|
11786
|
+
await copyTaskToBoard(projectRoot, board.id, activeTask.id, transferTarget.id);
|
|
11787
|
+
return `Copied task to ${transferTarget.title}`;
|
|
11788
|
+
});
|
|
11789
|
+
return;
|
|
11790
|
+
}
|
|
11791
|
+
if (input === "T" && board && activeTask && transferTarget) {
|
|
11792
|
+
void runMutation(async () => {
|
|
11793
|
+
await transferTaskToBoard(projectRoot, board.id, activeTask.id, transferTarget.id, {
|
|
11794
|
+
preserveAssignment: true
|
|
11795
|
+
});
|
|
11796
|
+
return `Transferred task to ${transferTarget.title}`;
|
|
11797
|
+
});
|
|
11798
|
+
}
|
|
11799
|
+
});
|
|
11800
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
11801
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
|
|
11802
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "KANBAN" }),
|
|
11803
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11804
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11805
|
+
boards.length,
|
|
11806
|
+
" board",
|
|
11807
|
+
boards.length === 1 ? "" : "s"
|
|
11808
|
+
] }),
|
|
11809
|
+
board ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11810
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11811
|
+
/* @__PURE__ */ jsx(Text, { children: board.title })
|
|
11812
|
+
] }) : null,
|
|
11813
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "| n/p board | Tab task | left/right move | c/a/d create/add/dup | C/T copy/transfer | Esc close" })
|
|
11814
|
+
] }),
|
|
11815
|
+
prompt ? /* @__PURE__ */ jsx(PromptLine, { prompt }) : null,
|
|
11816
|
+
notice && !prompt ? /* @__PURE__ */ jsx(Text, { color: "green", wrap: "truncate", children: notice }) : null,
|
|
11817
|
+
loading ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading kanban..." }) : error ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
11818
|
+
"Error: ",
|
|
11819
|
+
error
|
|
11820
|
+
] }) : !board ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
11821
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "No kanban boards yet." }),
|
|
11822
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11823
|
+
"Press ",
|
|
11824
|
+
/* @__PURE__ */ jsx(Text, { color: theme.accent, children: "c" }),
|
|
11825
|
+
" to create one, or use",
|
|
11826
|
+
" ",
|
|
11827
|
+
/* @__PURE__ */ jsx(Text, { color: theme.accent, children: "/kanban create <title>" }),
|
|
11828
|
+
"."
|
|
11829
|
+
] })
|
|
11830
|
+
] }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
11831
|
+
/* @__PURE__ */ jsx(BoardSummary, { board, target: transferTarget }),
|
|
11832
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
11833
|
+
/* @__PURE__ */ jsx(BoardList, { boards, selected: selectedBoard }),
|
|
11834
|
+
/* @__PURE__ */ jsx(BoardColumns, { board, activeTaskId: activeTask?.id }),
|
|
11835
|
+
/* @__PURE__ */ jsx(TaskDetail, { board, task: activeTask, target: transferTarget })
|
|
11836
|
+
] })
|
|
11837
|
+
] })
|
|
11838
|
+
] });
|
|
11839
|
+
}
|
|
11840
|
+
function PromptLine({ prompt }) {
|
|
11841
|
+
if (prompt.kind === "confirmDeleteTask") {
|
|
11842
|
+
return /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
11843
|
+
'Delete "',
|
|
11844
|
+
prompt.task.title,
|
|
11845
|
+
'"? y/n'
|
|
11846
|
+
] });
|
|
11847
|
+
}
|
|
11848
|
+
const label = prompt.kind === "createBoard" ? "New board title" : "New task title";
|
|
11849
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
11850
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
11851
|
+
label,
|
|
11852
|
+
": "
|
|
11853
|
+
] }),
|
|
11854
|
+
prompt.buffer,
|
|
11855
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "_" })
|
|
11856
|
+
] });
|
|
11857
|
+
}
|
|
11858
|
+
function BoardList({
|
|
11859
|
+
boards,
|
|
11860
|
+
selected
|
|
11861
|
+
}) {
|
|
11862
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 24, borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
|
|
11863
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Boards" }),
|
|
11864
|
+
boards.slice(0, 12).map((item, index) => /* @__PURE__ */ jsxs(Text, { color: index === selected ? "cyan" : void 0, wrap: "truncate", children: [
|
|
11865
|
+
index === selected ? ">" : " ",
|
|
11866
|
+
" ",
|
|
11867
|
+
item.title,
|
|
11868
|
+
" (",
|
|
11869
|
+
item.taskCount,
|
|
11870
|
+
")"
|
|
11871
|
+
] }, item.id)),
|
|
11872
|
+
boards.length > 12 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11873
|
+
"... ",
|
|
11874
|
+
boards.length - 12,
|
|
11875
|
+
" more"
|
|
11876
|
+
] }) : null
|
|
11877
|
+
] });
|
|
11878
|
+
}
|
|
11879
|
+
function BoardColumns({
|
|
11880
|
+
board,
|
|
11881
|
+
activeTaskId
|
|
11882
|
+
}) {
|
|
11883
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 1, children: [...board.columns].sort((a, b) => a.order - b.order).slice(0, 5).map((column) => {
|
|
11884
|
+
const allTasks = board.tasks.filter((task) => task.columnId === column.id).sort((a, b) => a.order - b.order);
|
|
11885
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 26, children: [
|
|
11886
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", wrap: "truncate", children: [
|
|
11887
|
+
column.title,
|
|
11888
|
+
" (",
|
|
11889
|
+
allTasks.length,
|
|
11890
|
+
")"
|
|
11891
|
+
] }),
|
|
11892
|
+
allTasks.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " empty" }) : allTasks.slice(0, 8).map((task) => /* @__PURE__ */ jsxs(
|
|
11893
|
+
Text,
|
|
11894
|
+
{
|
|
11895
|
+
color: task.id === activeTaskId ? "cyan" : void 0,
|
|
11896
|
+
wrap: "truncate",
|
|
11897
|
+
children: [
|
|
11898
|
+
task.id === activeTaskId ? ">" : " ",
|
|
11899
|
+
" ",
|
|
11900
|
+
statusIcon(task.status),
|
|
11901
|
+
" ",
|
|
11902
|
+
task.title,
|
|
11903
|
+
task.assignedAgent ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11904
|
+
" @",
|
|
11905
|
+
task.assignedAgent
|
|
11906
|
+
] }) : null
|
|
11907
|
+
]
|
|
11908
|
+
},
|
|
11909
|
+
task.id
|
|
11910
|
+
)),
|
|
11911
|
+
allTasks.length > 8 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11912
|
+
" ... ",
|
|
11913
|
+
allTasks.length - 8,
|
|
11914
|
+
" more"
|
|
11915
|
+
] }) : null
|
|
11916
|
+
] }, column.id);
|
|
11917
|
+
}) });
|
|
11918
|
+
}
|
|
11919
|
+
function TaskDetail({
|
|
11920
|
+
board,
|
|
11921
|
+
task,
|
|
11922
|
+
target
|
|
11923
|
+
}) {
|
|
11924
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 34, borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
|
|
11925
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Task" }),
|
|
11926
|
+
!task ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No task selected." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11927
|
+
/* @__PURE__ */ jsx(Text, { wrap: "truncate", children: task.title }),
|
|
11928
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11929
|
+
"ID ",
|
|
11930
|
+
task.id.slice(0, 8)
|
|
11931
|
+
] }),
|
|
11932
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
11933
|
+
task.priority.toUpperCase(),
|
|
11934
|
+
" / ",
|
|
11935
|
+
task.status
|
|
11936
|
+
] }),
|
|
11937
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11938
|
+
"Column ",
|
|
11939
|
+
columnTitle(board, task.columnId)
|
|
11940
|
+
] }),
|
|
11941
|
+
task.description ? /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: task.description }) : null,
|
|
11942
|
+
task.assignment ? /* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
11943
|
+
"Agent ",
|
|
11944
|
+
task.assignment.agentId ?? task.assignedAgent ?? task.assignment.role ?? "-",
|
|
11945
|
+
" /",
|
|
11946
|
+
" ",
|
|
11947
|
+
task.assignment.status
|
|
11948
|
+
] }) : task.assignedAgent ? /* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
11949
|
+
"Agent ",
|
|
11950
|
+
task.assignedAgent
|
|
11951
|
+
] }) : null,
|
|
11952
|
+
task.dependsOn?.length ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11953
|
+
"Depends on ",
|
|
11954
|
+
task.dependsOn.length
|
|
11955
|
+
] }) : null,
|
|
11956
|
+
target ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11957
|
+
"C/T target: ",
|
|
11958
|
+
target.title
|
|
11959
|
+
] }) : null,
|
|
11960
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "space done | b block | x delete" })
|
|
11961
|
+
] })
|
|
11962
|
+
] });
|
|
11963
|
+
}
|
|
11964
|
+
function BoardSummary({
|
|
11965
|
+
board,
|
|
11966
|
+
target
|
|
11967
|
+
}) {
|
|
11968
|
+
const done = board.tasks.filter((task) => task.status === "completed").length;
|
|
11969
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
|
|
11970
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11971
|
+
"ID ",
|
|
11972
|
+
board.id.slice(0, 8)
|
|
11973
|
+
] }),
|
|
11974
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11975
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11976
|
+
board.columns.length,
|
|
11977
|
+
" columns"
|
|
11978
|
+
] }),
|
|
11979
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11980
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11981
|
+
board.tasks.length,
|
|
11982
|
+
" tasks"
|
|
11983
|
+
] }),
|
|
11984
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11985
|
+
/* @__PURE__ */ jsxs(Text, { color: done === board.tasks.length && done > 0 ? "green" : "yellow", children: [
|
|
11986
|
+
done,
|
|
11987
|
+
" done"
|
|
11988
|
+
] }),
|
|
11989
|
+
target ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11990
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
11991
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11992
|
+
"next board: ",
|
|
11993
|
+
target.title
|
|
11994
|
+
] })
|
|
11995
|
+
] }) : null
|
|
11996
|
+
] });
|
|
11997
|
+
}
|
|
11998
|
+
function nextBoard(boards, boardId) {
|
|
11999
|
+
if (!boardId || boards.length < 2) return void 0;
|
|
12000
|
+
const index = boards.findIndex((item) => item.id === boardId);
|
|
12001
|
+
if (index === -1) return boards.find((item) => item.id !== boardId);
|
|
12002
|
+
for (let offset = 1; offset < boards.length; offset++) {
|
|
12003
|
+
const candidate = boards[(index + offset) % boards.length];
|
|
12004
|
+
if (candidate && candidate.id !== boardId) return candidate;
|
|
12005
|
+
}
|
|
12006
|
+
return void 0;
|
|
12007
|
+
}
|
|
12008
|
+
function adjacentColumn(columns, columnId, delta) {
|
|
12009
|
+
const index = columns.findIndex((column) => column.id === columnId);
|
|
12010
|
+
if (index === -1) return void 0;
|
|
12011
|
+
return columns[index + delta];
|
|
12012
|
+
}
|
|
12013
|
+
function doneColumnId(board) {
|
|
12014
|
+
return board.columns.find(
|
|
12015
|
+
(column) => ["done", "completed", "finished"].includes(column.id.toLowerCase())
|
|
12016
|
+
)?.id;
|
|
12017
|
+
}
|
|
12018
|
+
function columnTitle(board, columnId) {
|
|
12019
|
+
return board.columns.find((column) => column.id === columnId)?.title ?? columnId;
|
|
12020
|
+
}
|
|
12021
|
+
function statusIcon(status) {
|
|
12022
|
+
if (status === "completed") return "x";
|
|
12023
|
+
if (status === "blocked") return "!";
|
|
12024
|
+
if (status === "in_progress") return ">";
|
|
12025
|
+
if (status === "failed") return "!";
|
|
12026
|
+
if (status === "review") return "?";
|
|
12027
|
+
return "-";
|
|
12028
|
+
}
|
|
12029
|
+
function clamp(value, min, max) {
|
|
12030
|
+
return Math.max(min, Math.min(max, value));
|
|
12031
|
+
}
|
|
11010
12032
|
function hintsFor(ctx) {
|
|
11011
12033
|
if (ctx.confirm) {
|
|
11012
12034
|
return [
|
|
@@ -11174,33 +12196,46 @@ function ModelPicker({
|
|
|
11174
12196
|
hint
|
|
11175
12197
|
}) {
|
|
11176
12198
|
if (step === "provider") {
|
|
11177
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor:
|
|
11178
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
12199
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
12200
|
+
/* @__PURE__ */ jsx(Text, { color: UI_COLORS.title, bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
|
|
11179
12201
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
11180
|
-
providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) :
|
|
11181
|
-
i === selected
|
|
11182
|
-
|
|
11183
|
-
/* @__PURE__ */ jsxs(
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
12202
|
+
providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : /* @__PURE__ */ jsx(Box, { flexDirection: "column", minHeight: providerOptions.length, children: providerOptions.map((p, i) => {
|
|
12203
|
+
const isSelected = i === selected;
|
|
12204
|
+
const famColor = colorForFamily(p.family);
|
|
12205
|
+
return /* @__PURE__ */ jsxs(
|
|
12206
|
+
Text,
|
|
12207
|
+
{
|
|
12208
|
+
inverse: isSelected,
|
|
12209
|
+
...isSelected ? { color: UI_COLORS.focused } : {},
|
|
12210
|
+
children: [
|
|
12211
|
+
isSelected ? "\u203A " : " ",
|
|
12212
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: isSelected ? void 0 : famColor, children: p.id.padEnd(28) }),
|
|
12213
|
+
/* @__PURE__ */ jsxs(Text, { color: isSelected ? void 0 : famColor, dimColor: !isSelected, children: [
|
|
12214
|
+
" ",
|
|
12215
|
+
"[",
|
|
12216
|
+
p.family,
|
|
12217
|
+
"]"
|
|
12218
|
+
] }),
|
|
12219
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12220
|
+
" ",
|
|
12221
|
+
p.models.length,
|
|
12222
|
+
" model",
|
|
12223
|
+
p.models.length === 1 ? "" : "s"
|
|
12224
|
+
] })
|
|
12225
|
+
]
|
|
12226
|
+
},
|
|
12227
|
+
p.id
|
|
12228
|
+
);
|
|
12229
|
+
}) }),
|
|
12230
|
+
hint ? /* @__PURE__ */ jsx(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
12231
|
+
] });
|
|
11197
12232
|
}
|
|
11198
12233
|
const total = filteredOptions.length;
|
|
11199
12234
|
const { start, end } = getVisibleWindow2(selected, total);
|
|
11200
12235
|
const visibleItems = filteredOptions.slice(start, end);
|
|
11201
12236
|
const searchHint = searchQuery ? ` | filter:"${searchQuery}" \u2192 ${total} match${total === 1 ? "" : "es"}` : total > MAX_VISIBLE2 ? ` (${total} models \u2014 type to filter)` : "";
|
|
11202
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor:
|
|
11203
|
-
/* @__PURE__ */ jsxs(Text, { color:
|
|
12237
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
12238
|
+
/* @__PURE__ */ jsxs(Text, { color: UI_COLORS.title, bold: true, children: [
|
|
11204
12239
|
"\u2501\u2501 Switch model \u2014 Step 2/2: Pick model ",
|
|
11205
12240
|
"(",
|
|
11206
12241
|
pickedProviderId,
|
|
@@ -11209,7 +12244,7 @@ function ModelPicker({
|
|
|
11209
12244
|
" \u2501\u2501"
|
|
11210
12245
|
] }),
|
|
11211
12246
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit \xB7 type to filter" }),
|
|
11212
|
-
total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: searchQuery ? `(no models match "${searchQuery}")` : "(no models known for this provider)" }) : /* @__PURE__ */ jsxs(
|
|
12247
|
+
total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: searchQuery ? `(no models match "${searchQuery}")` : "(no models known for this provider)" }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", minHeight: MAX_VISIBLE2 + 2, children: [
|
|
11213
12248
|
start > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11214
12249
|
"\u25B2 ",
|
|
11215
12250
|
start,
|
|
@@ -11217,26 +12252,30 @@ function ModelPicker({
|
|
|
11217
12252
|
] }),
|
|
11218
12253
|
visibleItems.map((id, vi) => {
|
|
11219
12254
|
const absoluteIndex = start + vi;
|
|
12255
|
+
const isSelected = absoluteIndex === selected;
|
|
11220
12256
|
return /* @__PURE__ */ jsxs(
|
|
11221
12257
|
Text,
|
|
11222
12258
|
{
|
|
11223
|
-
inverse:
|
|
11224
|
-
...
|
|
12259
|
+
inverse: isSelected,
|
|
12260
|
+
...isSelected ? { color: UI_COLORS.selectedModel } : {},
|
|
11225
12261
|
children: [
|
|
11226
|
-
|
|
12262
|
+
isSelected ? "\u203A " : " ",
|
|
11227
12263
|
id
|
|
11228
12264
|
]
|
|
11229
12265
|
},
|
|
11230
12266
|
id
|
|
11231
12267
|
);
|
|
11232
12268
|
}),
|
|
12269
|
+
Array.from({ length: MAX_VISIBLE2 - visibleItems.length }).map(
|
|
12270
|
+
(_, i) => /* @__PURE__ */ jsx(Text, { children: " " }, `pad-${i}`)
|
|
12271
|
+
),
|
|
11233
12272
|
end < total && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
11234
12273
|
"\u25BC ",
|
|
11235
12274
|
total - end,
|
|
11236
12275
|
" below"
|
|
11237
12276
|
] })
|
|
11238
12277
|
] }),
|
|
11239
|
-
hint ? /* @__PURE__ */ jsx(Text, { color:
|
|
12278
|
+
hint ? /* @__PURE__ */ jsx(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
11240
12279
|
] });
|
|
11241
12280
|
}
|
|
11242
12281
|
var fmtElapsed3 = (ms) => {
|
|
@@ -11564,7 +12603,7 @@ function PlanRow({ item }) {
|
|
|
11564
12603
|
] }) : null
|
|
11565
12604
|
] });
|
|
11566
12605
|
}
|
|
11567
|
-
var
|
|
12606
|
+
var CHROME_ROWS2 = 17;
|
|
11568
12607
|
function PluginPicker({
|
|
11569
12608
|
items,
|
|
11570
12609
|
selected,
|
|
@@ -11573,7 +12612,7 @@ function PluginPicker({
|
|
|
11573
12612
|
}) {
|
|
11574
12613
|
const { stdout } = useStdout();
|
|
11575
12614
|
const rows = stdout?.rows ?? 24;
|
|
11576
|
-
const maxVisible = Math.max(4, rows -
|
|
12615
|
+
const maxVisible = Math.max(4, rows - CHROME_ROWS2);
|
|
11577
12616
|
const total = items.length;
|
|
11578
12617
|
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
11579
12618
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
@@ -12142,7 +13181,7 @@ function SddBoardOverlay({
|
|
|
12142
13181
|
] }) : null
|
|
12143
13182
|
] });
|
|
12144
13183
|
}
|
|
12145
|
-
function
|
|
13184
|
+
function statusIcon2(status) {
|
|
12146
13185
|
switch (status) {
|
|
12147
13186
|
case "active":
|
|
12148
13187
|
return "\u25CF";
|
|
@@ -12210,7 +13249,7 @@ function SessionsPanel({
|
|
|
12210
13249
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
12211
13250
|
/* @__PURE__ */ jsxs(Text, { inverse: idx === selected, color: s2.status === "active" ? "green" : s2.status === "idle" ? "cyan" : "yellow", children: [
|
|
12212
13251
|
s2.sessionId === currentSessionId ? "\u25CF " : "",
|
|
12213
|
-
|
|
13252
|
+
statusIcon2(s2.status),
|
|
12214
13253
|
" "
|
|
12215
13254
|
] }),
|
|
12216
13255
|
/* @__PURE__ */ jsx(Text, { bold: true, children: s2.projectName }),
|
|
@@ -12507,11 +13546,11 @@ function WorktreeMonitor({
|
|
|
12507
13546
|
useInput((input, key) => {
|
|
12508
13547
|
if (isWorktreeMonitorCloseKey(input, key)) onClose();
|
|
12509
13548
|
});
|
|
12510
|
-
const
|
|
13549
|
+
const TERMINAL_TTL_MS2 = 5 * 6e4;
|
|
12511
13550
|
const list = Object.values(worktrees);
|
|
12512
13551
|
const recent = list.filter((w) => {
|
|
12513
13552
|
if (["active", "committing", "merging", "needs-review"].includes(w.status)) return true;
|
|
12514
|
-
return nowTick - (w.allocatedAt ?? nowTick) <
|
|
13553
|
+
return nowTick - (w.allocatedAt ?? nowTick) < TERMINAL_TTL_MS2;
|
|
12515
13554
|
});
|
|
12516
13555
|
const active = list.filter((w) => ["active", "committing", "merging"].includes(w.status)).length;
|
|
12517
13556
|
const merged = list.filter((w) => w.status === "merged").length;
|
|
@@ -12573,350 +13612,121 @@ function WorktreeMonitor({
|
|
|
12573
13612
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginLeft: 2, children: [
|
|
12574
13613
|
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
12575
13614
|
"+",
|
|
12576
|
-
w.insertions
|
|
12577
|
-
] }),
|
|
12578
|
-
/* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
12579
|
-
"-",
|
|
12580
|
-
w.deletions
|
|
12581
|
-
] }),
|
|
12582
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12583
|
-
"\xB7 ",
|
|
12584
|
-
w.files,
|
|
12585
|
-
" files"
|
|
12586
|
-
] })
|
|
12587
|
-
] }),
|
|
12588
|
-
w.conflictFiles && w.conflictFiles.length > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
|
|
12589
|
-
"conflicts: ",
|
|
12590
|
-
w.conflictFiles.join(", ")
|
|
12591
|
-
] }) }) : null
|
|
12592
|
-
] }, w.branch);
|
|
12593
|
-
}),
|
|
12594
|
-
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
12595
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Esc / F4 to close \xB7 merge conflicts with /worktree merge <branch>" }),
|
|
12596
|
-
staleTerminal > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${staleTerminal} terminal pruned` }) : null
|
|
12597
|
-
] })
|
|
12598
|
-
] });
|
|
12599
|
-
}
|
|
12600
|
-
var fmtElapsed6 = (ms) => {
|
|
12601
|
-
const s2 = Math.floor(ms / 1e3);
|
|
12602
|
-
const m = Math.floor(s2 / 60);
|
|
12603
|
-
const h = Math.floor(m / 60);
|
|
12604
|
-
if (h > 0) return `${h}:${String(m % 60).padStart(2, "0")}:${String(s2 % 60).padStart(2, "0")}`;
|
|
12605
|
-
if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
|
|
12606
|
-
return `${s2}s`;
|
|
12607
|
-
};
|
|
12608
|
-
var STATUS5 = {
|
|
12609
|
-
allocating: { icon: "\u25CB", color: "gray" },
|
|
12610
|
-
active: { icon: "\u25CF", color: "yellow" },
|
|
12611
|
-
committing: { icon: "\u25D0", color: "cyan" },
|
|
12612
|
-
merging: { icon: "\u21E1", color: "blue" },
|
|
12613
|
-
merged: { icon: "\u2713", color: "green" },
|
|
12614
|
-
"needs-review": { icon: "\u26A0", color: "magenta" },
|
|
12615
|
-
failed: { icon: "\u2717", color: "red" }
|
|
12616
|
-
};
|
|
12617
|
-
function st(status) {
|
|
12618
|
-
return STATUS5[status] ?? { icon: "?", color: "white" };
|
|
12619
|
-
}
|
|
12620
|
-
function WorktreePanel({
|
|
12621
|
-
worktrees,
|
|
12622
|
-
nowTick
|
|
12623
|
-
}) {
|
|
12624
|
-
const list = Object.values(worktrees);
|
|
12625
|
-
if (list.length === 0) return null;
|
|
12626
|
-
const active = list.filter(
|
|
12627
|
-
(w) => w.status === "active" || w.status === "committing" || w.status === "merging"
|
|
12628
|
-
).length;
|
|
12629
|
-
const merged = list.filter((w) => w.status === "merged").length;
|
|
12630
|
-
const failed = list.filter((w) => w.status === "failed" || w.status === "needs-review").length;
|
|
12631
|
-
return /* @__PURE__ */ jsxs(
|
|
12632
|
-
Box,
|
|
12633
|
-
{
|
|
12634
|
-
flexDirection: "column",
|
|
12635
|
-
paddingX: 1,
|
|
12636
|
-
borderStyle: "single",
|
|
12637
|
-
borderTop: false,
|
|
12638
|
-
borderBottom: false,
|
|
12639
|
-
borderLeft: false,
|
|
12640
|
-
borderRight: false,
|
|
12641
|
-
children: [
|
|
12642
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
12643
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Worktrees" }),
|
|
12644
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
12645
|
-
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
12646
|
-
"\u25B6",
|
|
12647
|
-
active
|
|
12648
|
-
] }),
|
|
12649
|
-
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
12650
|
-
"\u2713",
|
|
12651
|
-
merged
|
|
12652
|
-
] }),
|
|
12653
|
-
failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
12654
|
-
"\u2717",
|
|
12655
|
-
failed
|
|
12656
|
-
] }) : null,
|
|
12657
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12658
|
-
"\xB7 ",
|
|
12659
|
-
list.length,
|
|
12660
|
-
" total \xB7 Ctrl+T for details"
|
|
12661
|
-
] })
|
|
12662
|
-
] }),
|
|
12663
|
-
list.map((w) => {
|
|
12664
|
-
const s2 = st(w.status);
|
|
12665
|
-
const conflict = w.status === "needs-review";
|
|
12666
|
-
const elapsed = w.allocatedAt ? fmtElapsed6(nowTick - w.allocatedAt) : "";
|
|
12667
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
12668
|
-
/* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.icon }),
|
|
12669
|
-
/* @__PURE__ */ jsx(Text, { children: w.branch.replace(/^wstack\/ap\//, "").slice(0, 18).padEnd(18) }),
|
|
12670
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: w.ownerLabel.slice(0, 12) }),
|
|
12671
|
-
conflict ? /* @__PURE__ */ jsx(Text, { color: "magenta", children: " CONFLICT" }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12672
|
-
" ",
|
|
12673
|
-
"+",
|
|
12674
|
-
w.insertions,
|
|
12675
|
-
"/-",
|
|
12676
|
-
w.deletions,
|
|
12677
|
-
" ",
|
|
12678
|
-
w.files,
|
|
12679
|
-
"f"
|
|
12680
|
-
] }),
|
|
12681
|
-
elapsed && (w.status === "active" || w.status === "committing") ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12682
|
-
" ",
|
|
12683
|
-
elapsed
|
|
12684
|
-
] }) : null
|
|
12685
|
-
] }, w.branch);
|
|
12686
|
-
})
|
|
12687
|
-
]
|
|
12688
|
-
}
|
|
12689
|
-
);
|
|
12690
|
-
}
|
|
12691
|
-
var CHROME_ROWS2 = 18;
|
|
12692
|
-
var LIST_ACTION_LABEL = {
|
|
12693
|
-
catalog: "\uFF0B Add provider (models.dev catalog)",
|
|
12694
|
-
local: "\uFF0B Add local server (OmniRoute / Ollama / vLLM / LM Studio)",
|
|
12695
|
-
custom: "\uFF0B Add custom provider",
|
|
12696
|
-
oauth: "\u26A1 Sign in with OAuth (ChatGPT / Claude / Copilot)"
|
|
12697
|
-
};
|
|
12698
|
-
var PROVIDER_ACTION_LABEL = {
|
|
12699
|
-
"add-key": "\uFF0B Add another key",
|
|
12700
|
-
"edit-family": "\u270E Edit family",
|
|
12701
|
-
"edit-base-url": "\u270E Edit base URL",
|
|
12702
|
-
"edit-models": "\u270E Edit visible model list",
|
|
12703
|
-
remove: "\u2715 Remove this provider"
|
|
12704
|
-
};
|
|
12705
|
-
var OAUTH_LABEL = {
|
|
12706
|
-
chatgpt: { title: "ChatGPT Plus/Pro", detail: "\u2192 openai-codex" },
|
|
12707
|
-
claude: { title: "Claude Pro/Max", detail: "\u2192 anthropic-oauth" },
|
|
12708
|
-
copilot: { title: "GitHub Copilot", detail: "\u2192 github-copilot" }
|
|
12709
|
-
};
|
|
12710
|
-
function keySummary(keyRow) {
|
|
12711
|
-
const method = keyRow.authMethod === "oauth" ? " oauth" : "";
|
|
12712
|
-
const created = keyRow.createdAt ? ` ${keyRow.createdAt.slice(0, 10)}` : "";
|
|
12713
|
-
return `${keyRow.masked}${method}${created}`;
|
|
12714
|
-
}
|
|
12715
|
-
function renderRow3(row, focused, i) {
|
|
12716
|
-
const marker = focused ? "\u203A" : " ";
|
|
12717
|
-
const color = focused ? "cyan" : void 0;
|
|
12718
|
-
switch (row.kind) {
|
|
12719
|
-
case "provider": {
|
|
12720
|
-
const p = row.provider;
|
|
12721
|
-
const keys = p.keys.length === 0 ? "no keys" : p.keys.length === 1 ? `1 key ${p.keys[0]?.masked ?? ""}` : `${p.keys.length} keys`;
|
|
12722
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12723
|
-
marker,
|
|
12724
|
-
" ",
|
|
12725
|
-
p.id.padEnd(22),
|
|
12726
|
-
" ",
|
|
12727
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: (p.family ?? "\u2014").padEnd(18) }),
|
|
12728
|
-
" ",
|
|
12729
|
-
/* @__PURE__ */ jsx(Text, { color: p.keys.length > 0 ? "green" : "yellow", children: keys })
|
|
12730
|
-
] }, `p-${p.id}`);
|
|
12731
|
-
}
|
|
12732
|
-
case "list-action":
|
|
12733
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12734
|
-
marker,
|
|
12735
|
-
" ",
|
|
12736
|
-
LIST_ACTION_LABEL[row.action]
|
|
12737
|
-
] }, `a-${row.action}`);
|
|
12738
|
-
case "key": {
|
|
12739
|
-
const k = row.keyRow;
|
|
12740
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12741
|
-
marker,
|
|
12742
|
-
" ",
|
|
12743
|
-
/* @__PURE__ */ jsx(Text, { color: k.active ? "green" : "gray", children: k.active ? "\u25CF" : "\u25CB" }),
|
|
12744
|
-
" ",
|
|
12745
|
-
k.label.padEnd(20),
|
|
12746
|
-
" ",
|
|
12747
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: keySummary(k) })
|
|
12748
|
-
] }, `k-${k.label}`);
|
|
12749
|
-
}
|
|
12750
|
-
case "provider-action":
|
|
12751
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12752
|
-
marker,
|
|
12753
|
-
" ",
|
|
12754
|
-
PROVIDER_ACTION_LABEL[row.action]
|
|
12755
|
-
] }, `pa-${row.action}`);
|
|
12756
|
-
case "catalog-entry": {
|
|
12757
|
-
const c = row.entry;
|
|
12758
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12759
|
-
marker,
|
|
12760
|
-
" ",
|
|
12761
|
-
/* @__PURE__ */ jsx(Text, { color: c.saved ? "green" : "gray", children: c.saved ? "\u25C9" : "\u25CB" }),
|
|
12762
|
-
" ",
|
|
12763
|
-
c.id.padEnd(24),
|
|
12764
|
-
" ",
|
|
12765
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: c.family.padEnd(20) }),
|
|
12766
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: c.name !== c.id ? c.name : "" })
|
|
12767
|
-
] }, `c-${c.id}`);
|
|
12768
|
-
}
|
|
12769
|
-
case "local-preset": {
|
|
12770
|
-
const p = row.preset;
|
|
12771
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12772
|
-
marker,
|
|
12773
|
-
" ",
|
|
12774
|
-
p.label.padEnd(12),
|
|
12775
|
-
" ",
|
|
12776
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: p.defaultBaseUrl.padEnd(28) }),
|
|
12777
|
-
" ",
|
|
12778
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: p.noAuth ? "no auth" : "optional key" })
|
|
12779
|
-
] }, `l-${p.id}`);
|
|
12780
|
-
}
|
|
12781
|
-
case "oauth-option": {
|
|
12782
|
-
const o = OAUTH_LABEL[row.oauth] ?? { title: row.oauth, detail: "" };
|
|
12783
|
-
return /* @__PURE__ */ jsxs(Text, { color, wrap: "truncate-end", children: [
|
|
12784
|
-
marker,
|
|
12785
|
-
" ",
|
|
12786
|
-
o.title.padEnd(20),
|
|
12787
|
-
" ",
|
|
12788
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: o.detail })
|
|
12789
|
-
] }, `o-${row.oauth}`);
|
|
12790
|
-
}
|
|
12791
|
-
default:
|
|
12792
|
-
return /* @__PURE__ */ jsx(Text, { children: " " }, `r-${i}`);
|
|
12793
|
-
}
|
|
12794
|
-
}
|
|
12795
|
-
function viewTitle(panel) {
|
|
12796
|
-
switch (panel.view) {
|
|
12797
|
-
case "list":
|
|
12798
|
-
return "API keys & sign-in";
|
|
12799
|
-
case "provider":
|
|
12800
|
-
return `Provider \u2014 ${panel.providerId ?? ""}`;
|
|
12801
|
-
case "catalog":
|
|
12802
|
-
return "Add provider \u2014 models.dev catalog";
|
|
12803
|
-
case "local":
|
|
12804
|
-
return "Add local server";
|
|
12805
|
-
case "oauth":
|
|
12806
|
-
return "Sign in with OAuth";
|
|
12807
|
-
case "flow":
|
|
12808
|
-
return panel.flowTitle || "Working\u2026";
|
|
12809
|
-
}
|
|
12810
|
-
}
|
|
12811
|
-
function viewLegend(panel) {
|
|
12812
|
-
if (panel.input) return "Enter submit \xB7 Esc cancel";
|
|
12813
|
-
if (panel.confirm) return "y/Enter confirm \xB7 n/Esc cancel";
|
|
12814
|
-
switch (panel.view) {
|
|
12815
|
-
case "list":
|
|
12816
|
-
return "\u2191/\u2193 select \xB7 Enter open \xB7 Esc close";
|
|
12817
|
-
case "provider":
|
|
12818
|
-
return "\u2191/\u2193 select \xB7 Enter activate/run \xB7 u update key \xB7 d delete key \xB7 Esc back";
|
|
12819
|
-
case "catalog":
|
|
12820
|
-
return "type to filter \xB7 \u2191/\u2193 select \xB7 Enter add key \xB7 Esc back";
|
|
12821
|
-
case "local":
|
|
12822
|
-
return "\u2191/\u2193 select \xB7 Enter configure & probe \xB7 Esc back";
|
|
12823
|
-
case "oauth":
|
|
12824
|
-
return "\u2191/\u2193 select \xB7 Enter sign in \xB7 Esc back";
|
|
12825
|
-
case "flow":
|
|
12826
|
-
return panel.flowDone ? "Enter/Esc back" : "Esc cancel";
|
|
12827
|
-
}
|
|
12828
|
-
}
|
|
12829
|
-
function AuthPanel({ panel }) {
|
|
12830
|
-
const { stdout } = useStdout();
|
|
12831
|
-
const rows = stdout?.rows ?? 24;
|
|
12832
|
-
const maxVisible = Math.max(4, rows - CHROME_ROWS2);
|
|
12833
|
-
const allRows = authPanelRows(panel);
|
|
12834
|
-
const total = allRows.length;
|
|
12835
|
-
const windowStart = total <= maxVisible ? 0 : Math.max(0, Math.min(panel.selected - Math.floor(maxVisible / 2), total - maxVisible));
|
|
12836
|
-
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
12837
|
-
const above = windowStart;
|
|
12838
|
-
const below = total - windowEnd;
|
|
12839
|
-
const provider = panel.view === "provider" ? authSelectedProvider(panel) : void 0;
|
|
12840
|
-
const logWindow = panel.log.slice(-Math.max(6, maxVisible));
|
|
12841
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
12842
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: viewTitle(panel) }),
|
|
12843
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: viewLegend(panel) }),
|
|
12844
|
-
panel.view === "provider" && provider ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
12845
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
12846
|
-
"type: ",
|
|
12847
|
-
provider.type ?? provider.id,
|
|
12848
|
-
" \xB7 family: ",
|
|
12849
|
-
provider.family ?? "unset",
|
|
12850
|
-
" \xB7 baseUrl:",
|
|
12851
|
-
" ",
|
|
12852
|
-
provider.baseUrl ?? "unset"
|
|
12853
|
-
] }),
|
|
12854
|
-
provider.models.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
12855
|
-
"models: ",
|
|
12856
|
-
provider.models.join(", ")
|
|
12857
|
-
] }) : null
|
|
12858
|
-
] }) : null,
|
|
12859
|
-
panel.view === "oauth" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
12860
|
-
/* @__PURE__ */ jsx(Text, { color: "yellow", wrap: "truncate-end", children: "\u26A0 Subscription tokens used outside official clients may violate provider Terms \u2014" }),
|
|
12861
|
-
/* @__PURE__ */ jsx(Text, { color: "yellow", wrap: "truncate-end", children: "your account could be rate-limited or banned. An API key is the sanctioned path." })
|
|
12862
|
-
] }) : null,
|
|
12863
|
-
panel.view === "catalog" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
12864
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "filter: " }),
|
|
12865
|
-
panel.filter.length > 0 ? panel.filter : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(type to search)" }),
|
|
12866
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u258F" })
|
|
12867
|
-
] }) }) : null,
|
|
12868
|
-
panel.view === "flow" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
12869
|
-
logWindow.length === 0 && !panel.flowDone ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Starting\u2026" }) : null,
|
|
12870
|
-
logWindow.map((line) => /* @__PURE__ */ jsx(
|
|
12871
|
-
Text,
|
|
12872
|
-
{
|
|
12873
|
-
wrap: "truncate-end",
|
|
12874
|
-
color: line.startsWith("\u2717") ? "red" : line.startsWith("\u2713") ? "green" : void 0,
|
|
12875
|
-
dimColor: !line.startsWith("\u2717") && !line.startsWith("\u2713"),
|
|
12876
|
-
children: line
|
|
12877
|
-
},
|
|
12878
|
-
line
|
|
12879
|
-
)),
|
|
12880
|
-
panel.flowDone ? /* @__PURE__ */ jsxs(Text, { color: panel.flowOk ? "green" : "red", children: [
|
|
12881
|
-
panel.flowOk ? "\u2713 Done." : "\u2717 Not completed.",
|
|
12882
|
-
" ",
|
|
12883
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Enter or Esc to go back." })
|
|
12884
|
-
] }) : panel.input ? null : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2026 working (Esc to cancel)" })
|
|
12885
|
-
] }) : /* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: panel.busy ? "Loading\u2026" : panel.view === "catalog" ? "No catalog entries match." : "Nothing here yet." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12886
|
-
above > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
12887
|
-
allRows.slice(windowStart, windowEnd).map((row, i) => renderRow3(row, windowStart + i === panel.selected, i)),
|
|
12888
|
-
below > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
12889
|
-
] }) }),
|
|
12890
|
-
panel.input ? /* @__PURE__ */ jsxs(
|
|
12891
|
-
Box,
|
|
12892
|
-
{
|
|
12893
|
-
flexDirection: "column",
|
|
12894
|
-
marginTop: 1,
|
|
12895
|
-
borderStyle: "round",
|
|
12896
|
-
borderColor: "yellow",
|
|
12897
|
-
paddingX: 1,
|
|
12898
|
-
children: [
|
|
12899
|
-
/* @__PURE__ */ jsxs(Text, { color: "yellow", wrap: "truncate-end", children: [
|
|
12900
|
-
"? ",
|
|
12901
|
-
panel.input.label
|
|
13615
|
+
w.insertions
|
|
12902
13616
|
] }),
|
|
12903
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
13617
|
+
/* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
13618
|
+
"-",
|
|
13619
|
+
w.deletions
|
|
13620
|
+
] }),
|
|
13621
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13622
|
+
"\xB7 ",
|
|
13623
|
+
w.files,
|
|
13624
|
+
" files"
|
|
12907
13625
|
] })
|
|
12908
|
-
]
|
|
12909
|
-
|
|
12910
|
-
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
|
|
13626
|
+
] }),
|
|
13627
|
+
w.conflictFiles && w.conflictFiles.length > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
|
|
13628
|
+
"conflicts: ",
|
|
13629
|
+
w.conflictFiles.join(", ")
|
|
13630
|
+
] }) }) : null
|
|
13631
|
+
] }, w.branch);
|
|
13632
|
+
}),
|
|
13633
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
13634
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Esc / F4 to close \xB7 merge conflicts with /worktree merge <branch>" }),
|
|
13635
|
+
staleTerminal > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${staleTerminal} terminal pruned` }) : null
|
|
13636
|
+
] })
|
|
12918
13637
|
] });
|
|
12919
13638
|
}
|
|
13639
|
+
var fmtElapsed6 = (ms) => {
|
|
13640
|
+
const s2 = Math.floor(ms / 1e3);
|
|
13641
|
+
const m = Math.floor(s2 / 60);
|
|
13642
|
+
const h = Math.floor(m / 60);
|
|
13643
|
+
if (h > 0) return `${h}:${String(m % 60).padStart(2, "0")}:${String(s2 % 60).padStart(2, "0")}`;
|
|
13644
|
+
if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
|
|
13645
|
+
return `${s2}s`;
|
|
13646
|
+
};
|
|
13647
|
+
var STATUS5 = {
|
|
13648
|
+
allocating: { icon: "\u25CB", color: "gray" },
|
|
13649
|
+
active: { icon: "\u25CF", color: "yellow" },
|
|
13650
|
+
committing: { icon: "\u25D0", color: "cyan" },
|
|
13651
|
+
merging: { icon: "\u21E1", color: "blue" },
|
|
13652
|
+
merged: { icon: "\u2713", color: "green" },
|
|
13653
|
+
"needs-review": { icon: "\u26A0", color: "magenta" },
|
|
13654
|
+
failed: { icon: "\u2717", color: "red" }
|
|
13655
|
+
};
|
|
13656
|
+
function st(status) {
|
|
13657
|
+
return STATUS5[status] ?? { icon: "?", color: "white" };
|
|
13658
|
+
}
|
|
13659
|
+
function WorktreePanel({
|
|
13660
|
+
worktrees,
|
|
13661
|
+
nowTick
|
|
13662
|
+
}) {
|
|
13663
|
+
const list = Object.values(worktrees);
|
|
13664
|
+
if (list.length === 0) return null;
|
|
13665
|
+
const active = list.filter(
|
|
13666
|
+
(w) => w.status === "active" || w.status === "committing" || w.status === "merging"
|
|
13667
|
+
).length;
|
|
13668
|
+
const merged = list.filter((w) => w.status === "merged").length;
|
|
13669
|
+
const failed = list.filter((w) => w.status === "failed" || w.status === "needs-review").length;
|
|
13670
|
+
return /* @__PURE__ */ jsxs(
|
|
13671
|
+
Box,
|
|
13672
|
+
{
|
|
13673
|
+
flexDirection: "column",
|
|
13674
|
+
paddingX: 1,
|
|
13675
|
+
borderStyle: "single",
|
|
13676
|
+
borderTop: false,
|
|
13677
|
+
borderBottom: false,
|
|
13678
|
+
borderLeft: false,
|
|
13679
|
+
borderRight: false,
|
|
13680
|
+
children: [
|
|
13681
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
13682
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Worktrees" }),
|
|
13683
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
13684
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
13685
|
+
"\u25B6",
|
|
13686
|
+
active
|
|
13687
|
+
] }),
|
|
13688
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
13689
|
+
"\u2713",
|
|
13690
|
+
merged
|
|
13691
|
+
] }),
|
|
13692
|
+
failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
13693
|
+
"\u2717",
|
|
13694
|
+
failed
|
|
13695
|
+
] }) : null,
|
|
13696
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13697
|
+
"\xB7 ",
|
|
13698
|
+
list.length,
|
|
13699
|
+
" total \xB7 Ctrl+T for details"
|
|
13700
|
+
] })
|
|
13701
|
+
] }),
|
|
13702
|
+
list.map((w) => {
|
|
13703
|
+
const s2 = st(w.status);
|
|
13704
|
+
const conflict = w.status === "needs-review";
|
|
13705
|
+
const elapsed = w.allocatedAt ? fmtElapsed6(nowTick - w.allocatedAt) : "";
|
|
13706
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
13707
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.icon }),
|
|
13708
|
+
/* @__PURE__ */ jsx(Text, { children: w.branch.replace(/^wstack\/ap\//, "").slice(0, 18).padEnd(18) }),
|
|
13709
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: w.ownerLabel.slice(0, 12) }),
|
|
13710
|
+
conflict ? /* @__PURE__ */ jsx(Text, { color: "magenta", children: " CONFLICT" }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13711
|
+
" ",
|
|
13712
|
+
"+",
|
|
13713
|
+
w.insertions,
|
|
13714
|
+
"/-",
|
|
13715
|
+
w.deletions,
|
|
13716
|
+
" ",
|
|
13717
|
+
w.files,
|
|
13718
|
+
"f"
|
|
13719
|
+
] }),
|
|
13720
|
+
elapsed && (w.status === "active" || w.status === "committing") ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
13721
|
+
" ",
|
|
13722
|
+
elapsed
|
|
13723
|
+
] }) : null
|
|
13724
|
+
] }, w.branch);
|
|
13725
|
+
})
|
|
13726
|
+
]
|
|
13727
|
+
}
|
|
13728
|
+
);
|
|
13729
|
+
}
|
|
12920
13730
|
async function readGitInfo(cwd) {
|
|
12921
13731
|
const [branchRes, numstatRes, statusRes] = await Promise.all([
|
|
12922
13732
|
runGit(cwd, ["branch", "--show-current"]),
|
|
@@ -14192,6 +15002,33 @@ function usePickerKeys(host) {
|
|
|
14192
15002
|
}
|
|
14193
15003
|
return true;
|
|
14194
15004
|
}
|
|
15005
|
+
if (state.modePicker.open) {
|
|
15006
|
+
if (key.escape) {
|
|
15007
|
+
dispatch({ type: "modePickerClose" });
|
|
15008
|
+
return true;
|
|
15009
|
+
}
|
|
15010
|
+
if (key.mouse?.kind === "wheel") {
|
|
15011
|
+
dispatch({ type: "modePickerMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
|
|
15012
|
+
return true;
|
|
15013
|
+
}
|
|
15014
|
+
if (key.upArrow) {
|
|
15015
|
+
dispatch({ type: "modePickerMove", delta: -1 });
|
|
15016
|
+
return true;
|
|
15017
|
+
}
|
|
15018
|
+
if (key.downArrow) {
|
|
15019
|
+
dispatch({ type: "modePickerMove", delta: 1 });
|
|
15020
|
+
return true;
|
|
15021
|
+
}
|
|
15022
|
+
if (isEnter) {
|
|
15023
|
+
if (debouncedEnter(host)) return true;
|
|
15024
|
+
const opt = state.modePicker.modes[state.modePicker.selected];
|
|
15025
|
+
if (!opt) return true;
|
|
15026
|
+
dispatch({ type: "modePickerClose" });
|
|
15027
|
+
host.submit?.(`/mode ${opt.id}`);
|
|
15028
|
+
return true;
|
|
15029
|
+
}
|
|
15030
|
+
return true;
|
|
15031
|
+
}
|
|
14195
15032
|
if (state.autonomyPicker.open) {
|
|
14196
15033
|
if (key.escape) {
|
|
14197
15034
|
dispatch({ type: "autonomyPickerClose" });
|
|
@@ -15378,6 +16215,58 @@ ${breakerLine}`;
|
|
|
15378
16215
|
return [...lines, "", breakerLine].join("\n");
|
|
15379
16216
|
}
|
|
15380
16217
|
|
|
16218
|
+
// src/on-panel-open.ts
|
|
16219
|
+
function createPanelOpenDispatcher(deps) {
|
|
16220
|
+
const { dispatch, openProjectPicker, openStatuslinePicker, openAuthPanel } = deps;
|
|
16221
|
+
return (action) => {
|
|
16222
|
+
switch (action) {
|
|
16223
|
+
case "authOpen":
|
|
16224
|
+
return openAuthPanel ? openAuthPanel("list") : false;
|
|
16225
|
+
case "authOauthOpen":
|
|
16226
|
+
return openAuthPanel ? openAuthPanel("oauth") : false;
|
|
16227
|
+
case "pluginPickerOpen":
|
|
16228
|
+
dispatch({ type: "pluginPickerOpen" });
|
|
16229
|
+
return true;
|
|
16230
|
+
case "projectPickerOpen":
|
|
16231
|
+
void openProjectPicker();
|
|
16232
|
+
return true;
|
|
16233
|
+
case "statuslineOpen":
|
|
16234
|
+
openStatuslinePicker();
|
|
16235
|
+
return true;
|
|
16236
|
+
case "modePickerOpen":
|
|
16237
|
+
if (deps.openModePicker) {
|
|
16238
|
+
void deps.openModePicker();
|
|
16239
|
+
return true;
|
|
16240
|
+
}
|
|
16241
|
+
return false;
|
|
16242
|
+
case "toggleMonitor":
|
|
16243
|
+
dispatch({ type: "toggleMonitor" });
|
|
16244
|
+
return true;
|
|
16245
|
+
case "toggleAuditPanel":
|
|
16246
|
+
dispatch({ type: "toggleAuditPanel" });
|
|
16247
|
+
return true;
|
|
16248
|
+
// All other toggle* panels share the same handler in the reducer —
|
|
16249
|
+
// the action type string IS the dispatch type. Dispatching them
|
|
16250
|
+
// verbatim works because the reducer's switch covers every F-key
|
|
16251
|
+
// panel action.
|
|
16252
|
+
case "toggleAgentsMonitor":
|
|
16253
|
+
case "toggleWorktreeMonitor":
|
|
16254
|
+
case "togglePlanPanel":
|
|
16255
|
+
case "toggleKanbanPanel":
|
|
16256
|
+
case "toggleTodosMonitor":
|
|
16257
|
+
case "toggleQueuePanel":
|
|
16258
|
+
case "toggleProcessList":
|
|
16259
|
+
case "toggleGoalPanel":
|
|
16260
|
+
case "toggleSessionsPanel":
|
|
16261
|
+
case "toggleCoordinatorMonitor":
|
|
16262
|
+
dispatch({ type: action });
|
|
16263
|
+
return true;
|
|
16264
|
+
default:
|
|
16265
|
+
return false;
|
|
16266
|
+
}
|
|
16267
|
+
};
|
|
16268
|
+
}
|
|
16269
|
+
|
|
15381
16270
|
// src/paste-accumulator.ts
|
|
15382
16271
|
var BEGIN = "[200~";
|
|
15383
16272
|
var END = "[201~";
|
|
@@ -15471,7 +16360,7 @@ function normalizeSlashQuery(raw) {
|
|
|
15471
16360
|
function rankSlashCommand(entry, query) {
|
|
15472
16361
|
const { cmd, owner } = entry;
|
|
15473
16362
|
if (query === "" && cmd.hidden) return null;
|
|
15474
|
-
const name =
|
|
16363
|
+
const name = displayName2(entry);
|
|
15475
16364
|
const lowerName = name.toLowerCase();
|
|
15476
16365
|
const aliases = aliasCandidates(entry);
|
|
15477
16366
|
const category = cmd.category ?? "App";
|
|
@@ -15504,7 +16393,7 @@ function rankSlashCommand(entry, query) {
|
|
|
15504
16393
|
rank
|
|
15505
16394
|
};
|
|
15506
16395
|
}
|
|
15507
|
-
function
|
|
16396
|
+
function displayName2({ cmd, owner, fullName }) {
|
|
15508
16397
|
if (owner === "core") return cmd.name;
|
|
15509
16398
|
return fullName.includes(":") ? fullName : cmd.name;
|
|
15510
16399
|
}
|
|
@@ -15557,51 +16446,6 @@ function buildSteeringPreamble(snapshot, newDirection) {
|
|
|
15557
16446
|
return lines.join("\n");
|
|
15558
16447
|
}
|
|
15559
16448
|
|
|
15560
|
-
// src/on-panel-open.ts
|
|
15561
|
-
function createPanelOpenDispatcher(deps) {
|
|
15562
|
-
const { dispatch, openProjectPicker, openStatuslinePicker, openAuthPanel } = deps;
|
|
15563
|
-
return (action) => {
|
|
15564
|
-
switch (action) {
|
|
15565
|
-
case "authOpen":
|
|
15566
|
-
return openAuthPanel ? openAuthPanel("list") : false;
|
|
15567
|
-
case "authOauthOpen":
|
|
15568
|
-
return openAuthPanel ? openAuthPanel("oauth") : false;
|
|
15569
|
-
case "pluginPickerOpen":
|
|
15570
|
-
dispatch({ type: "pluginPickerOpen" });
|
|
15571
|
-
return true;
|
|
15572
|
-
case "projectPickerOpen":
|
|
15573
|
-
void openProjectPicker();
|
|
15574
|
-
return true;
|
|
15575
|
-
case "statuslineOpen":
|
|
15576
|
-
openStatuslinePicker();
|
|
15577
|
-
return true;
|
|
15578
|
-
case "toggleMonitor":
|
|
15579
|
-
dispatch({ type: "toggleMonitor" });
|
|
15580
|
-
return true;
|
|
15581
|
-
case "toggleAuditPanel":
|
|
15582
|
-
dispatch({ type: "toggleAuditPanel" });
|
|
15583
|
-
return true;
|
|
15584
|
-
// All other toggle* panels share the same handler in the reducer —
|
|
15585
|
-
// the action type string IS the dispatch type. Dispatching them
|
|
15586
|
-
// verbatim works because the reducer's switch covers every F-key
|
|
15587
|
-
// panel action.
|
|
15588
|
-
case "toggleAgentsMonitor":
|
|
15589
|
-
case "toggleWorktreeMonitor":
|
|
15590
|
-
case "togglePlanPanel":
|
|
15591
|
-
case "toggleTodosMonitor":
|
|
15592
|
-
case "toggleQueuePanel":
|
|
15593
|
-
case "toggleProcessList":
|
|
15594
|
-
case "toggleGoalPanel":
|
|
15595
|
-
case "toggleSessionsPanel":
|
|
15596
|
-
case "toggleCoordinatorMonitor":
|
|
15597
|
-
dispatch({ type: action });
|
|
15598
|
-
return true;
|
|
15599
|
-
default:
|
|
15600
|
-
return false;
|
|
15601
|
-
}
|
|
15602
|
-
};
|
|
15603
|
-
}
|
|
15604
|
-
|
|
15605
16449
|
// src/input-editing.ts
|
|
15606
16450
|
var WORD_SEPARATORS = new Set(
|
|
15607
16451
|
// dashes
|
|
@@ -15673,6 +16517,13 @@ function selectedSlashCommandLine(picker) {
|
|
|
15673
16517
|
const picked = picker.matches[picker.selected];
|
|
15674
16518
|
return picked ? `/${picked.name}` : null;
|
|
15675
16519
|
}
|
|
16520
|
+
function contentBlocksText(content) {
|
|
16521
|
+
if (typeof content === "string") return content;
|
|
16522
|
+
if (!Array.isArray(content)) return "";
|
|
16523
|
+
return content.filter(
|
|
16524
|
+
(block) => !!block && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
16525
|
+
).map((block) => block.text).join("");
|
|
16526
|
+
}
|
|
15676
16527
|
function rehydrateHistory(messages, startId, toolCalls) {
|
|
15677
16528
|
const entries = [];
|
|
15678
16529
|
const toolCallsById = /* @__PURE__ */ new Map();
|
|
@@ -15684,10 +16535,7 @@ function rehydrateHistory(messages, startId, toolCalls) {
|
|
|
15684
16535
|
const consumed = /* @__PURE__ */ new Set();
|
|
15685
16536
|
const fallback = [];
|
|
15686
16537
|
let nextId = startId;
|
|
15687
|
-
const textOf = (msg) =>
|
|
15688
|
-
if (typeof msg.content === "string") return msg.content;
|
|
15689
|
-
return msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
15690
|
-
};
|
|
16538
|
+
const textOf = (msg) => contentBlocksText(msg.content);
|
|
15691
16539
|
const toolEntryFor = (tc) => ({
|
|
15692
16540
|
id: nextId++,
|
|
15693
16541
|
kind: "tool",
|
|
@@ -15701,13 +16549,12 @@ function rehydrateHistory(messages, startId, toolCalls) {
|
|
|
15701
16549
|
for (const msg of messages) {
|
|
15702
16550
|
if (msg.role === "system") continue;
|
|
15703
16551
|
const text = textOf(msg).trim();
|
|
15704
|
-
if (!text) continue;
|
|
15705
16552
|
if (msg.role === "user") {
|
|
15706
|
-
entries.push({ id: nextId++, kind: "user", text });
|
|
16553
|
+
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
15707
16554
|
continue;
|
|
15708
16555
|
}
|
|
15709
16556
|
if (msg.role === "assistant") {
|
|
15710
|
-
entries.push({ id: nextId++, kind: "assistant", text });
|
|
16557
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
15711
16558
|
if (Array.isArray(msg.content)) {
|
|
15712
16559
|
for (const block of msg.content) {
|
|
15713
16560
|
if (block.type !== "tool_use") continue;
|
|
@@ -15843,6 +16690,7 @@ function App({
|
|
|
15843
16690
|
sessionsDir,
|
|
15844
16691
|
modeLabel,
|
|
15845
16692
|
getModeLabel,
|
|
16693
|
+
getModes,
|
|
15846
16694
|
registerDebugStreamCallback,
|
|
15847
16695
|
restoreDebugStreamCallback,
|
|
15848
16696
|
restoredToolCalls,
|
|
@@ -16022,6 +16870,7 @@ function App({
|
|
|
16022
16870
|
searchQuery: ""
|
|
16023
16871
|
},
|
|
16024
16872
|
autonomyPicker: { open: false, options: [], selected: 0 },
|
|
16873
|
+
modePicker: { open: false, modes: [], selected: 0 },
|
|
16025
16874
|
designPicker: { open: false, kits: [], selected: 0, stack: "web" },
|
|
16026
16875
|
promptPicker: {
|
|
16027
16876
|
open: false,
|
|
@@ -16125,6 +16974,7 @@ function App({
|
|
|
16125
16974
|
processListOpen: false,
|
|
16126
16975
|
auditPanelOpen: false,
|
|
16127
16976
|
planPanelOpen: false,
|
|
16977
|
+
kanbanPanelOpen: false,
|
|
16128
16978
|
goalPanelOpen: false,
|
|
16129
16979
|
sessionsPanelOpen: false,
|
|
16130
16980
|
sessionsPanel: { sessions: [], busy: false, selected: -1 },
|
|
@@ -16233,6 +17083,12 @@ function App({
|
|
|
16233
17083
|
];
|
|
16234
17084
|
dispatch({ type: "promptPickerOpen", all: entries, categories: cats, recentSlugs });
|
|
16235
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]);
|
|
16236
17092
|
useEffect(() => {
|
|
16237
17093
|
if (state.statuslinePicker.open) {
|
|
16238
17094
|
const pickerHidden = state.statuslinePicker.hiddenItems;
|
|
@@ -16333,6 +17189,7 @@ function App({
|
|
|
16333
17189
|
titleController.setEnabled(liveTitleAnimation !== false);
|
|
16334
17190
|
}, [titleController, liveTitleAnimation]);
|
|
16335
17191
|
const streamingTextRef = useRef("");
|
|
17192
|
+
const streamSegmentsRef = useRef([]);
|
|
16336
17193
|
const pendingDeltaRef = useRef("");
|
|
16337
17194
|
const flushTimerRef = useRef(null);
|
|
16338
17195
|
const stateRef = useRef(state);
|
|
@@ -16363,7 +17220,7 @@ function App({
|
|
|
16363
17220
|
[statuslineHiddenForPicker]
|
|
16364
17221
|
);
|
|
16365
17222
|
const [mouseMode, setMouseMode] = useState(mouse);
|
|
16366
|
-
const pickerOverlayOpen = state.modelPicker.open || state.autonomyPicker.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;
|
|
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;
|
|
16367
17224
|
const mouseTrackingOn = mouseMode || pickerOverlayOpen;
|
|
16368
17225
|
const mouseWrittenRef = useRef(false);
|
|
16369
17226
|
useEffect(() => {
|
|
@@ -16886,6 +17743,8 @@ function App({
|
|
|
16886
17743
|
todos: stateRef.current.todosMonitorOpen,
|
|
16887
17744
|
queue: stateRef.current.queuePanelOpen,
|
|
16888
17745
|
processList: stateRef.current.processListOpen,
|
|
17746
|
+
planPanel: stateRef.current.planPanelOpen,
|
|
17747
|
+
kanbanPanel: stateRef.current.kanbanPanelOpen,
|
|
16889
17748
|
goalPanel: stateRef.current.goalPanelOpen,
|
|
16890
17749
|
sessionsPanel: stateRef.current.sessionsPanelOpen,
|
|
16891
17750
|
coordinator: stateRef.current.coordinator.monitorOpen
|
|
@@ -16908,6 +17767,7 @@ function App({
|
|
|
16908
17767
|
if (stateRef.current.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
16909
17768
|
if (stateRef.current.processListOpen) dispatch({ type: "toggleProcessList" });
|
|
16910
17769
|
if (stateRef.current.planPanelOpen) dispatch({ type: "togglePlanPanel" });
|
|
17770
|
+
if (stateRef.current.kanbanPanelOpen) dispatch({ type: "toggleKanbanPanel" });
|
|
16911
17771
|
if (stateRef.current.goalPanelOpen) dispatch({ type: "toggleGoalPanel" });
|
|
16912
17772
|
if (stateRef.current.sessionsPanelOpen) dispatch({ type: "toggleSessionsPanel" });
|
|
16913
17773
|
eraseLiveRegion();
|
|
@@ -16971,6 +17831,8 @@ function App({
|
|
|
16971
17831
|
if (prev.todos) dispatch({ type: "toggleTodosMonitor" });
|
|
16972
17832
|
if (prev.queue) dispatch({ type: "toggleQueuePanel" });
|
|
16973
17833
|
if (prev.processList) dispatch({ type: "toggleProcessList" });
|
|
17834
|
+
if (prev.planPanel) dispatch({ type: "togglePlanPanel" });
|
|
17835
|
+
if (prev.kanbanPanel) dispatch({ type: "toggleKanbanPanel" });
|
|
16974
17836
|
if (prev.goalPanel) dispatch({ type: "toggleGoalPanel" });
|
|
16975
17837
|
if (prev.sessionsPanel) dispatch({ type: "toggleSessionsPanel" });
|
|
16976
17838
|
if (prev.coordinator) dispatch({ type: "toggleCoordinatorMonitor" });
|
|
@@ -17171,7 +18033,8 @@ function App({
|
|
|
17171
18033
|
dispatch,
|
|
17172
18034
|
openProjectPicker,
|
|
17173
18035
|
openStatuslinePicker,
|
|
17174
|
-
openAuthPanel: authPanelController.openAuthPanel
|
|
18036
|
+
openAuthPanel: authPanelController.openAuthPanel,
|
|
18037
|
+
openModePicker
|
|
17175
18038
|
});
|
|
17176
18039
|
onPanelOpen.current = dispatcher;
|
|
17177
18040
|
return () => {
|
|
@@ -17182,7 +18045,8 @@ function App({
|
|
|
17182
18045
|
dispatch,
|
|
17183
18046
|
openProjectPicker,
|
|
17184
18047
|
openStatuslinePicker,
|
|
17185
|
-
authPanelController.openAuthPanel
|
|
18048
|
+
authPanelController.openAuthPanel,
|
|
18049
|
+
openModePicker
|
|
17186
18050
|
]);
|
|
17187
18051
|
useEffect(() => {
|
|
17188
18052
|
if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
|
|
@@ -17829,6 +18693,14 @@ Available chords:
|
|
|
17829
18693
|
}, [slashRegistry, listSessions]);
|
|
17830
18694
|
useEffect(() => {
|
|
17831
18695
|
const FLUSH_MS2 = 100;
|
|
18696
|
+
const appendStreamSegment = (kind, text) => {
|
|
18697
|
+
const last = streamSegmentsRef.current.at(-1);
|
|
18698
|
+
if (last?.kind === kind) {
|
|
18699
|
+
last.text += text;
|
|
18700
|
+
} else {
|
|
18701
|
+
streamSegmentsRef.current.push({ kind, text });
|
|
18702
|
+
}
|
|
18703
|
+
};
|
|
17832
18704
|
const flush = () => {
|
|
17833
18705
|
if (pendingDeltaRef.current) {
|
|
17834
18706
|
dispatch({ type: "streamDelta", delta: pendingDeltaRef.current });
|
|
@@ -17840,6 +18712,13 @@ Available chords:
|
|
|
17840
18712
|
const text = e.text.replace(/\x1b?\[200~|\x1b?\[201~/g, "");
|
|
17841
18713
|
streamingTextRef.current += text;
|
|
17842
18714
|
pendingDeltaRef.current += text;
|
|
18715
|
+
appendStreamSegment("assistant", text);
|
|
18716
|
+
if (!flushTimerRef.current) flushTimerRef.current = setTimeout(flush, FLUSH_MS2);
|
|
18717
|
+
});
|
|
18718
|
+
const offThinking = events.on("provider.thinking_delta", (e) => {
|
|
18719
|
+
const text = e.text.replace(/\x1b?\[200~|\x1b?\[201~/g, "");
|
|
18720
|
+
appendStreamSegment("thinking", text);
|
|
18721
|
+
pendingDeltaRef.current += text;
|
|
17843
18722
|
if (!flushTimerRef.current) flushTimerRef.current = setTimeout(flush, FLUSH_MS2);
|
|
17844
18723
|
});
|
|
17845
18724
|
const offToolStart = events.on("tool.started", (e) => {
|
|
@@ -17914,17 +18793,27 @@ Available chords:
|
|
|
17914
18793
|
}
|
|
17915
18794
|
});
|
|
17916
18795
|
});
|
|
17917
|
-
const offProvResp = events.on("provider.response", () => {
|
|
18796
|
+
const offProvResp = events.on("provider.response", (e) => {
|
|
17918
18797
|
const text = streamingTextRef.current;
|
|
18798
|
+
const segments = streamSegmentsRef.current;
|
|
18799
|
+
const fallbackText = contentBlocksText(e.content);
|
|
17919
18800
|
streamingTextRef.current = "";
|
|
18801
|
+
streamSegmentsRef.current = [];
|
|
17920
18802
|
pendingDeltaRef.current = "";
|
|
17921
18803
|
if (flushTimerRef.current) {
|
|
17922
18804
|
clearTimeout(flushTimerRef.current);
|
|
17923
18805
|
flushTimerRef.current = null;
|
|
17924
18806
|
}
|
|
17925
18807
|
dispatch({ type: "streamReset" });
|
|
17926
|
-
|
|
18808
|
+
for (const seg of segments) {
|
|
18809
|
+
if (seg.text.trim()) {
|
|
18810
|
+
dispatch({ type: "addEntry", entry: { kind: seg.kind, text: seg.text } });
|
|
18811
|
+
}
|
|
18812
|
+
}
|
|
18813
|
+
if (segments.length === 0 && text.trim()) {
|
|
17927
18814
|
dispatch({ type: "addEntry", entry: { kind: "assistant", text } });
|
|
18815
|
+
} else if (segments.length === 0 && fallbackText.trim()) {
|
|
18816
|
+
dispatch({ type: "addEntry", entry: { kind: "assistant", text: fallbackText } });
|
|
17928
18817
|
}
|
|
17929
18818
|
});
|
|
17930
18819
|
const offConfirmNeeded = events.on("tool.confirm_needed", (e) => {
|
|
@@ -17981,6 +18870,7 @@ Available chords:
|
|
|
17981
18870
|
});
|
|
17982
18871
|
return () => {
|
|
17983
18872
|
offDelta();
|
|
18873
|
+
offThinking();
|
|
17984
18874
|
offToolStart();
|
|
17985
18875
|
offIterStart();
|
|
17986
18876
|
offIterEnd();
|
|
@@ -19308,18 +20198,26 @@ Available chords:
|
|
|
19308
20198
|
).length;
|
|
19309
20199
|
const result = await agent.run(routed.blocks, { signal: ctrl.signal });
|
|
19310
20200
|
const lingering = streamingTextRef.current;
|
|
19311
|
-
|
|
19312
|
-
dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
|
|
19313
|
-
} else if (result.status === "done" && result.finalText?.trim() && stateRef.current.entries.filter((entry) => entry.kind === "assistant").length === assistantEntriesBeforeRun) {
|
|
19314
|
-
dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
|
|
19315
|
-
}
|
|
20201
|
+
const lingeringSegments = streamSegmentsRef.current;
|
|
19316
20202
|
streamingTextRef.current = "";
|
|
20203
|
+
streamSegmentsRef.current = [];
|
|
19317
20204
|
pendingDeltaRef.current = "";
|
|
19318
20205
|
if (flushTimerRef.current) {
|
|
19319
20206
|
clearTimeout(flushTimerRef.current);
|
|
19320
20207
|
flushTimerRef.current = null;
|
|
19321
20208
|
}
|
|
19322
20209
|
dispatch({ type: "streamReset" });
|
|
20210
|
+
if (lingeringSegments.length > 0) {
|
|
20211
|
+
for (const seg of lingeringSegments) {
|
|
20212
|
+
if (seg.text.trim()) {
|
|
20213
|
+
dispatch({ type: "addEntry", entry: { kind: seg.kind, text: seg.text } });
|
|
20214
|
+
}
|
|
20215
|
+
}
|
|
20216
|
+
} else if (lingering.trim()) {
|
|
20217
|
+
dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
|
|
20218
|
+
} else if (result.status === "done" && result.finalText?.trim() && stateRef.current.entries.filter((entry) => entry.kind === "assistant").length === assistantEntriesBeforeRun) {
|
|
20219
|
+
dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
|
|
20220
|
+
}
|
|
19323
20221
|
if (result.status === "aborted") {
|
|
19324
20222
|
const reason = result.abortReason ? `Aborted (${result.abortReason}).` : "Aborted.";
|
|
19325
20223
|
dispatch({ type: "addEntry", entry: { kind: "warn", text: reason } });
|
|
@@ -19860,7 +20758,7 @@ ${content}
|
|
|
19860
20758
|
);
|
|
19861
20759
|
const inputHeight = Math.max(1, inputCellRows.length);
|
|
19862
20760
|
const hideInput = enhanceActive || state.helpOpen || state.processListOpen || state.authPanel.open;
|
|
19863
|
-
const lowerFunctionPanelOpen = state.monitorOpen || state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.planPanelOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen;
|
|
20761
|
+
const lowerFunctionPanelOpen = state.monitorOpen || state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.planPanelOpen || state.kanbanPanelOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen;
|
|
19864
20762
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
|
|
19865
20763
|
mouseMode ? /* @__PURE__ */ jsx(
|
|
19866
20764
|
ScrollableHistory,
|
|
@@ -19941,6 +20839,14 @@ ${content}
|
|
|
19941
20839
|
hint: state.autonomyPicker.hint
|
|
19942
20840
|
}
|
|
19943
20841
|
) : null,
|
|
20842
|
+
state.modePicker.open ? /* @__PURE__ */ jsx(
|
|
20843
|
+
ModePicker,
|
|
20844
|
+
{
|
|
20845
|
+
modes: state.modePicker.modes,
|
|
20846
|
+
selected: state.modePicker.selected,
|
|
20847
|
+
hint: state.modePicker.hint
|
|
20848
|
+
}
|
|
20849
|
+
) : null,
|
|
19944
20850
|
state.designPicker.open ? /* @__PURE__ */ jsx(
|
|
19945
20851
|
DesignPicker,
|
|
19946
20852
|
{
|
|
@@ -20335,6 +21241,12 @@ ${content}
|
|
|
20335
21241
|
sessionId: agent.ctx.session?.id ?? null,
|
|
20336
21242
|
onClose: () => dispatch({ type: "togglePlanPanel" })
|
|
20337
21243
|
}
|
|
21244
|
+
) : state.kanbanPanelOpen ? /* @__PURE__ */ jsx(
|
|
21245
|
+
KanbanPanel,
|
|
21246
|
+
{
|
|
21247
|
+
projectRoot: agent.ctx.projectRoot,
|
|
21248
|
+
onClose: () => dispatch({ type: "toggleKanbanPanel" })
|
|
21249
|
+
}
|
|
20338
21250
|
) : state.queuePanelOpen ? /* @__PURE__ */ jsx(QueuePanel, { items: state.queue }) : state.processListOpen ? /* @__PURE__ */ jsx(ProcessListMonitor, {}) : state.goalPanelOpen ? /* @__PURE__ */ jsx(
|
|
20339
21251
|
GoalPanel,
|
|
20340
21252
|
{
|
|
@@ -20343,12 +21255,14 @@ ${content}
|
|
|
20343
21255
|
onCoordinatorStop: onCoordinatorStop ?? void 0,
|
|
20344
21256
|
coordinatorRunning
|
|
20345
21257
|
}
|
|
20346
|
-
) : director ? /* @__PURE__ */ jsx(
|
|
21258
|
+
) : director || Object.keys(state.fleet).length > 0 || state.collabSession ? /* @__PURE__ */ jsx(
|
|
20347
21259
|
FleetPanel,
|
|
20348
21260
|
{
|
|
20349
21261
|
entries: entriesWithLeader,
|
|
20350
21262
|
totalCost: state.fleetCost,
|
|
20351
21263
|
roster: fleetRoster,
|
|
21264
|
+
todos: agent.ctx.todos,
|
|
21265
|
+
nowTick,
|
|
20352
21266
|
collabSession: state.collabSession
|
|
20353
21267
|
}
|
|
20354
21268
|
) : null,
|
|
@@ -20819,6 +21733,8 @@ async function runTui(opts) {
|
|
|
20819
21733
|
tokenSavingMode: opts.tokenSavingMode,
|
|
20820
21734
|
toolCount: opts.toolCount,
|
|
20821
21735
|
getModeLabel: opts.getModeLabel,
|
|
21736
|
+
getModes: opts.getModes,
|
|
21737
|
+
switchMode: opts.switchMode,
|
|
20822
21738
|
registerDebugStreamCallback: opts.registerDebugStreamCallback,
|
|
20823
21739
|
restoreDebugStreamCallback: opts.restoreDebugStreamCallback,
|
|
20824
21740
|
restoredMessages: opts.restoredMessages,
|