@wrongstack/webui 0.260.0 → 0.264.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/assets/index-BBPaC1tO.js +170 -0
- package/dist/assets/index-DJmqJ5Wo.css +2 -0
- package/dist/assets/{vendor-BRkhRU94.js → vendor-pWpGJmMc.js} +182 -182
- package/dist/index.html +3 -3
- package/dist/index.js +887 -390
- package/dist/index.js.map +1 -1
- package/dist/server/entry.js +376 -115
- package/dist/server/entry.js.map +1 -1
- package/dist/server/index.js +377 -116
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +1208 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +5 -5
- package/dist/assets/index-6rPVh7TJ.css +0 -2
- package/dist/assets/index-CfIQObXO.js +0 -165
package/dist/index.js
CHANGED
|
@@ -62,6 +62,20 @@ function installFaviconVisibilityReset() {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// src/lib/ws-client-helpers.ts
|
|
66
|
+
function buildClearModelsMessage(providerId) {
|
|
67
|
+
return { type: "provider.clear_models", payload: { providerId } };
|
|
68
|
+
}
|
|
69
|
+
function buildUndoClearMessage(providerId, previousModels) {
|
|
70
|
+
return {
|
|
71
|
+
type: "provider.undo_clear",
|
|
72
|
+
payload: { providerId, previousModels: [...previousModels] }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function buildProviderUpdateMessage(payload) {
|
|
76
|
+
return { type: "provider.update", payload };
|
|
77
|
+
}
|
|
78
|
+
|
|
65
79
|
// src/lib/ws-client.ts
|
|
66
80
|
function getTokenFromWsUrl(wsUrl) {
|
|
67
81
|
try {
|
|
@@ -338,14 +352,15 @@ var WrongStackWebSocketClient = class {
|
|
|
338
352
|
off(eventType, handler) {
|
|
339
353
|
this.handlers.get(eventType)?.delete(handler);
|
|
340
354
|
}
|
|
341
|
-
sendMessage(content) {
|
|
355
|
+
sendMessage(content, imageBase64) {
|
|
342
356
|
const id = `msg_${Date.now()}_${crypto.randomUUID().slice(0, 8)}`;
|
|
343
357
|
this.send({
|
|
344
358
|
type: "user_message",
|
|
345
359
|
payload: {
|
|
346
360
|
id,
|
|
347
361
|
content,
|
|
348
|
-
timestamp: Date.now()
|
|
362
|
+
timestamp: Date.now(),
|
|
363
|
+
...imageBase64 ? { imageBase64 } : {}
|
|
349
364
|
}
|
|
350
365
|
});
|
|
351
366
|
return id;
|
|
@@ -356,6 +371,9 @@ var WrongStackWebSocketClient = class {
|
|
|
356
371
|
payload: {}
|
|
357
372
|
});
|
|
358
373
|
}
|
|
374
|
+
getGitInfo() {
|
|
375
|
+
this.send({ type: "git.info" });
|
|
376
|
+
}
|
|
359
377
|
sendConfirm(id, decision) {
|
|
360
378
|
const pending = this.pendingConfirms.get(id);
|
|
361
379
|
if (pending) {
|
|
@@ -404,6 +422,25 @@ var WrongStackWebSocketClient = class {
|
|
|
404
422
|
removeProvider(providerId) {
|
|
405
423
|
this.send({ type: "provider.remove", payload: { providerId } });
|
|
406
424
|
}
|
|
425
|
+
/** Run a health probe against a saved provider's `/v1/models`. */
|
|
426
|
+
probeProvider(providerId, timeoutMs) {
|
|
427
|
+
this.send({
|
|
428
|
+
type: "provider.probe",
|
|
429
|
+
payload: timeoutMs !== void 0 ? { providerId, timeoutMs } : { providerId }
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/** Remove the saved model allowlist for a provider. */
|
|
433
|
+
clearProviderModels(providerId) {
|
|
434
|
+
this.send(buildClearModelsMessage(providerId));
|
|
435
|
+
}
|
|
436
|
+
/** Restore a previously-cleared model allowlist (pairs with clear). */
|
|
437
|
+
undoProviderClear(providerId, previousModels) {
|
|
438
|
+
this.send(buildUndoClearMessage(providerId, previousModels));
|
|
439
|
+
}
|
|
440
|
+
/** Update a saved provider's wire config (family / baseUrl / envVars / models). */
|
|
441
|
+
updateProvider(payload) {
|
|
442
|
+
this.send(buildProviderUpdateMessage(payload));
|
|
443
|
+
}
|
|
407
444
|
clearContext() {
|
|
408
445
|
this.send({ type: "context.clear" });
|
|
409
446
|
}
|
|
@@ -890,6 +927,8 @@ var useUIStore = create4()(
|
|
|
890
927
|
agentsMonitorOpen: false,
|
|
891
928
|
inspectorOpen: false,
|
|
892
929
|
inspectorTab: "fleet",
|
|
930
|
+
processMonitorOpen: false,
|
|
931
|
+
queuePanelOpen: false,
|
|
893
932
|
selectActivity: (activity) => set({ activeActivity: activity }),
|
|
894
933
|
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
|
|
895
934
|
setSidebarOpen: (open) => set({ sidebarOpen: open }),
|
|
@@ -940,7 +979,9 @@ var useUIStore = create4()(
|
|
|
940
979
|
setAgentsMonitorOpen: (open) => set({ agentsMonitorOpen: open }),
|
|
941
980
|
setInspectorOpen: (open) => set({ inspectorOpen: open }),
|
|
942
981
|
setInspectorTab: (tab) => set({ inspectorTab: tab }),
|
|
943
|
-
toggleInspector: () => set((s) => ({ inspectorOpen: !s.inspectorOpen }))
|
|
982
|
+
toggleInspector: () => set((s) => ({ inspectorOpen: !s.inspectorOpen })),
|
|
983
|
+
setProcessMonitorOpen: (open) => set({ processMonitorOpen: open }),
|
|
984
|
+
setQueuePanelOpen: (open) => set({ queuePanelOpen: open })
|
|
944
985
|
}),
|
|
945
986
|
{
|
|
946
987
|
name: "wrongstack-ui",
|
|
@@ -990,12 +1031,20 @@ var useMailboxStore = create5()((set) => ({
|
|
|
990
1031
|
setAgents: (agents) => set({ agents })
|
|
991
1032
|
}));
|
|
992
1033
|
function selectUnreadCount(s) {
|
|
993
|
-
return s.messages.filter((m) => m.readByCount
|
|
1034
|
+
return s.messages.filter((m) => !m.completed && (m.readByCount ?? 0) === 0).length;
|
|
994
1035
|
}
|
|
995
1036
|
|
|
996
|
-
// src/stores/
|
|
1037
|
+
// src/stores/git-info-store.ts
|
|
997
1038
|
import { create as create6 } from "zustand";
|
|
998
|
-
var
|
|
1039
|
+
var useGitInfoStore = create6()((set) => ({
|
|
1040
|
+
info: null,
|
|
1041
|
+
setInfo: (info) => set({ info }),
|
|
1042
|
+
clear: () => set({ info: null })
|
|
1043
|
+
}));
|
|
1044
|
+
|
|
1045
|
+
// src/stores/history-store.ts
|
|
1046
|
+
import { create as create7 } from "zustand";
|
|
1047
|
+
var useHistoryStore = create7()((set) => ({
|
|
999
1048
|
entries: [],
|
|
1000
1049
|
loading: false,
|
|
1001
1050
|
error: null,
|
|
@@ -1008,8 +1057,8 @@ var useHistoryStore = create6()((set) => ({
|
|
|
1008
1057
|
}));
|
|
1009
1058
|
|
|
1010
1059
|
// src/stores/worktree-store.ts
|
|
1011
|
-
import { create as
|
|
1012
|
-
var useWorktreeStore =
|
|
1060
|
+
import { create as create8 } from "zustand";
|
|
1061
|
+
var useWorktreeStore = create8()((set) => ({
|
|
1013
1062
|
worktrees: [],
|
|
1014
1063
|
baseBranch: "",
|
|
1015
1064
|
activity: [],
|
|
@@ -1018,34 +1067,75 @@ var useWorktreeStore = create7()((set) => ({
|
|
|
1018
1067
|
}));
|
|
1019
1068
|
|
|
1020
1069
|
// src/stores/fleet-store.ts
|
|
1021
|
-
import { create as
|
|
1070
|
+
import { create as create9 } from "zustand";
|
|
1022
1071
|
|
|
1023
1072
|
// src/components/NextStepsBar.tsx
|
|
1024
1073
|
import { ArrowRight, Lightbulb, MousePointerClick, Timer } from "lucide-react";
|
|
1025
1074
|
import { useEffect, useState } from "react";
|
|
1026
1075
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1027
|
-
var
|
|
1028
|
-
var ITEM_RE = /^(\d+)
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
return
|
|
1076
|
+
var STRICT_HEADING_RE = /(?:💡\s*Next steps?|<next_steps>)\s*\n+/i;
|
|
1077
|
+
var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+?)(\s+auto="true")?$/;
|
|
1078
|
+
var MAX_STEPS = 6;
|
|
1079
|
+
function parseNextSteps(content, strict = true) {
|
|
1080
|
+
const headingMatch = strict ? STRICT_HEADING_RE.exec(content) : buildPermissiveHeadingRe().exec(content);
|
|
1081
|
+
if (!headingMatch) {
|
|
1082
|
+
return { steps: [], stripped: content };
|
|
1034
1083
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
const lines = block.split("\n").filter(Boolean);
|
|
1084
|
+
const headingEnd = headingMatch.index + headingMatch[0].length;
|
|
1085
|
+
const afterHeading = content.slice(headingEnd);
|
|
1086
|
+
const lines = afterHeading.split("\n");
|
|
1039
1087
|
const steps = [];
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1088
|
+
const seenNumbers = /* @__PURE__ */ new Set();
|
|
1089
|
+
let consumed = 0;
|
|
1090
|
+
let found = 0;
|
|
1091
|
+
for (const rawLine of lines) {
|
|
1092
|
+
const line = rawLine.trim();
|
|
1093
|
+
if (line === "</next_steps>") {
|
|
1094
|
+
consumed += rawLine.length + 1;
|
|
1095
|
+
break;
|
|
1046
1096
|
}
|
|
1097
|
+
if (!line) {
|
|
1098
|
+
consumed += rawLine.length + 1;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
const m = ITEM_RE.exec(line);
|
|
1102
|
+
if (!m) break;
|
|
1103
|
+
const numPart = m[1];
|
|
1104
|
+
const text = m[2].trim();
|
|
1105
|
+
const hasAuto = !!m[3];
|
|
1106
|
+
const index = numPart !== void 0 ? Number.parseInt(numPart, 10) : steps.length + 1;
|
|
1107
|
+
if (seenNumbers.has(index)) {
|
|
1108
|
+
consumed += rawLine.length + 1;
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
seenNumbers.add(index);
|
|
1112
|
+
steps.push(hasAuto ? { index, text, auto: true } : { index, text });
|
|
1113
|
+
consumed += rawLine.length + 1;
|
|
1114
|
+
found++;
|
|
1115
|
+
if (found >= MAX_STEPS) break;
|
|
1116
|
+
}
|
|
1117
|
+
if (steps.length === 0) {
|
|
1118
|
+
return { steps: [], stripped: content };
|
|
1119
|
+
}
|
|
1120
|
+
if (strict && /<next_steps>/i.test(headingMatch[0]) && !afterHeading.includes("</next_steps>")) {
|
|
1121
|
+
return { steps: [], stripped: content };
|
|
1047
1122
|
}
|
|
1048
|
-
|
|
1123
|
+
const blockStart = headingMatch.index;
|
|
1124
|
+
const blockEnd = headingEnd + consumed;
|
|
1125
|
+
const stripped = (content.slice(0, blockStart) + content.slice(blockEnd)).replace(/\n{3,}/g, "\n\n").trim();
|
|
1126
|
+
return { steps, stripped };
|
|
1127
|
+
}
|
|
1128
|
+
var PERMISSIVE_HEADING_PATTERNS = [
|
|
1129
|
+
{ re: /💡\s*Next steps?\s*\n+/i, label: "emoji" },
|
|
1130
|
+
{ re: /##?\s*Next steps?\s*\n+/i, label: "markdown" },
|
|
1131
|
+
{ re: /\n{1,2}Next steps?\s*\n+/i, label: "plain" },
|
|
1132
|
+
{ re: /<next_steps>\s*\n+/i, label: "xml-tag" }
|
|
1133
|
+
];
|
|
1134
|
+
function buildPermissiveHeadingRe() {
|
|
1135
|
+
const variants = PERMISSIVE_HEADING_PATTERNS.map(
|
|
1136
|
+
({ re }) => `(?:${re.source})`
|
|
1137
|
+
).join("|");
|
|
1138
|
+
return new RegExp(variants, "i");
|
|
1049
1139
|
}
|
|
1050
1140
|
function stripNextStepsBlock(text) {
|
|
1051
1141
|
return text.replace(/<next_steps\b[^>]*>[\s\S]*?<\/next_steps>/gi, "").replace(/<next_steps\b[^>]*\/?>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
@@ -1085,10 +1175,11 @@ function NextStepsBar({
|
|
|
1085
1175
|
yoloMode = false,
|
|
1086
1176
|
autoMode = false,
|
|
1087
1177
|
autoDelayMs = 3e4,
|
|
1088
|
-
onAutoSubmit
|
|
1178
|
+
onAutoSubmit,
|
|
1179
|
+
canAutoSubmit: canAutoSubmitProp = true
|
|
1089
1180
|
}) {
|
|
1090
1181
|
if (steps.length === 0) return null;
|
|
1091
|
-
const showAutoCountdown = yoloMode && autoMode;
|
|
1182
|
+
const showAutoCountdown = yoloMode && autoMode && canAutoSubmitProp;
|
|
1092
1183
|
const autoStep = showAutoCountdown ? steps.find((s) => s.auto) : void 0;
|
|
1093
1184
|
return /* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-xl border border-primary/20 bg-primary/[0.03] overflow-hidden animate-message", children: [
|
|
1094
1185
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3.5 py-2 border-b border-primary/10 bg-primary/[0.04]", children: [
|
|
@@ -1131,7 +1222,7 @@ function NextStepsBar({
|
|
|
1131
1222
|
}
|
|
1132
1223
|
),
|
|
1133
1224
|
s.auto && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-primary/70", children: [
|
|
1134
|
-
/* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }),
|
|
1225
|
+
autoMode && s.index === 1 && !showAutoCountdown ? /* @__PURE__ */ jsx("span", { title: "Will auto-submit after countdown", children: "\u23E9" }) : /* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }),
|
|
1135
1226
|
"auto"
|
|
1136
1227
|
] }),
|
|
1137
1228
|
/* @__PURE__ */ jsx(
|
|
@@ -1179,7 +1270,7 @@ function pushTimeline(timeline, event) {
|
|
|
1179
1270
|
function bumpSparkline(bins) {
|
|
1180
1271
|
return [bins[0] + 1, ...bins.slice(0, SPARKLINE_BINS - 1)];
|
|
1181
1272
|
}
|
|
1182
|
-
var useFleetStore =
|
|
1273
|
+
var useFleetStore = create9()((set, get) => ({
|
|
1183
1274
|
agents: /* @__PURE__ */ new Map(),
|
|
1184
1275
|
leaderId: void 0,
|
|
1185
1276
|
fleetTokensIn: 0,
|
|
@@ -1378,7 +1469,7 @@ var useFleetStore = create8()((set, get) => ({
|
|
|
1378
1469
|
}));
|
|
1379
1470
|
|
|
1380
1471
|
// src/stores/goal-store.ts
|
|
1381
|
-
import { create as
|
|
1472
|
+
import { create as create10 } from "zustand";
|
|
1382
1473
|
|
|
1383
1474
|
// src/lib/goal.ts
|
|
1384
1475
|
function parseGoalState(raw) {
|
|
@@ -1405,7 +1496,7 @@ function parseGoalState(raw) {
|
|
|
1405
1496
|
}
|
|
1406
1497
|
|
|
1407
1498
|
// src/stores/goal-store.ts
|
|
1408
|
-
var useGoalStore =
|
|
1499
|
+
var useGoalStore = create10()((set) => ({
|
|
1409
1500
|
goal: null,
|
|
1410
1501
|
setGoal: (raw) => set({ goal: parseGoalState(raw) }),
|
|
1411
1502
|
clear: () => set({ goal: null }),
|
|
@@ -1418,8 +1509,8 @@ var useGoalStore = create9()((set) => ({
|
|
|
1418
1509
|
}));
|
|
1419
1510
|
|
|
1420
1511
|
// src/stores/autophase-store.ts
|
|
1421
|
-
import { create as
|
|
1422
|
-
var useAutoPhaseStore =
|
|
1512
|
+
import { create as create11 } from "zustand";
|
|
1513
|
+
var useAutoPhaseStore = create11()((set) => ({
|
|
1423
1514
|
phases: [],
|
|
1424
1515
|
activePhaseId: null,
|
|
1425
1516
|
overallPercent: 0,
|
|
@@ -1442,7 +1533,7 @@ var useAutoPhaseStore = create10()((set) => ({
|
|
|
1442
1533
|
}));
|
|
1443
1534
|
|
|
1444
1535
|
// src/stores/local-prefs.ts
|
|
1445
|
-
import { create as
|
|
1536
|
+
import { create as create12 } from "zustand";
|
|
1446
1537
|
import { persist as persist5 } from "zustand/middleware";
|
|
1447
1538
|
var DEFAULTS = {
|
|
1448
1539
|
autonomy: "off",
|
|
@@ -1466,9 +1557,13 @@ var DEFAULTS = {
|
|
|
1466
1557
|
auditLevel: "standard",
|
|
1467
1558
|
enhanceEnabled: true,
|
|
1468
1559
|
enhanceDelayMs: 6e4,
|
|
1469
|
-
enhanceLanguage: "original"
|
|
1560
|
+
enhanceLanguage: "original",
|
|
1561
|
+
tgConfigured: false,
|
|
1562
|
+
tgSessionEnd: false,
|
|
1563
|
+
tgDelegate: true,
|
|
1564
|
+
tgLongToolMs: 3e4
|
|
1470
1565
|
};
|
|
1471
|
-
var useLocalPrefs =
|
|
1566
|
+
var useLocalPrefs = create12()(
|
|
1472
1567
|
persist5(
|
|
1473
1568
|
(set) => ({
|
|
1474
1569
|
...DEFAULTS,
|
|
@@ -1477,11 +1572,17 @@ var useLocalPrefs = create11()(
|
|
|
1477
1572
|
}),
|
|
1478
1573
|
{
|
|
1479
1574
|
name: "wrongstack-local-prefs",
|
|
1480
|
-
version:
|
|
1575
|
+
version: 3,
|
|
1481
1576
|
// v1 stored option values that don't exist in core's config schema —
|
|
1482
1577
|
// contextStrategy frugal/balanced/deep/archival (context-window modes,
|
|
1483
1578
|
// a different setting) and auditLevel 'verbose'. Map them onto the
|
|
1484
1579
|
// canonical values so persisted stores don't resurrect invalid prefs.
|
|
1580
|
+
//
|
|
1581
|
+
// v2 added autoProceedMaxIterations.
|
|
1582
|
+
//
|
|
1583
|
+
// v3 added Telegram notification prefs (tgConfigured, tgSessionEnd,
|
|
1584
|
+
// tgDelegate, tgLongToolMs). Older stores simply get the defaults via
|
|
1585
|
+
// the spread of DEFAULTS; no explicit remap is needed.
|
|
1485
1586
|
migrate: (persisted) => {
|
|
1486
1587
|
const p = persisted ?? {};
|
|
1487
1588
|
const validStrategies = ["hybrid", "intelligent", "selective"];
|
|
@@ -1502,8 +1603,8 @@ var useLocalPrefs = create11()(
|
|
|
1502
1603
|
);
|
|
1503
1604
|
|
|
1504
1605
|
// src/stores/file-store.ts
|
|
1505
|
-
import { create as
|
|
1506
|
-
var useFileStore =
|
|
1606
|
+
import { create as create13 } from "zustand";
|
|
1607
|
+
var useFileStore = create13()((set, get) => ({
|
|
1507
1608
|
projectRoot: "",
|
|
1508
1609
|
tree: [],
|
|
1509
1610
|
openFiles: [],
|
|
@@ -1566,7 +1667,7 @@ var useFileStore = create12()((set, get) => ({
|
|
|
1566
1667
|
}));
|
|
1567
1668
|
|
|
1568
1669
|
// src/stores/viz-store.ts
|
|
1569
|
-
import { create as
|
|
1670
|
+
import { create as create14 } from "zustand";
|
|
1570
1671
|
var _eventSeq = 0;
|
|
1571
1672
|
function nextId() {
|
|
1572
1673
|
return `viz_${Date.now()}_${++_eventSeq}`;
|
|
@@ -1594,7 +1695,7 @@ var EDGE_COLORS = {
|
|
|
1594
1695
|
"mailbox:send": "hsl(140, 70%, 55%)",
|
|
1595
1696
|
"default": "hsl(0, 0%, 40%)"
|
|
1596
1697
|
};
|
|
1597
|
-
var useVizStore =
|
|
1698
|
+
var useVizStore = create14()((set, get) => ({
|
|
1598
1699
|
events: [],
|
|
1599
1700
|
nodes: /* @__PURE__ */ new Map(),
|
|
1600
1701
|
edges: /* @__PURE__ */ new Map(),
|
|
@@ -1971,12 +2072,14 @@ function cn(...inputs) {
|
|
|
1971
2072
|
// src/components/Toaster.tsx
|
|
1972
2073
|
import { AlertTriangle, CheckCircle2, Info, X, XCircle } from "lucide-react";
|
|
1973
2074
|
import { useEffect as useEffect2 } from "react";
|
|
1974
|
-
import {
|
|
2075
|
+
import { randomUUID } from "crypto";
|
|
2076
|
+
import { create as create15 } from "zustand";
|
|
1975
2077
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1976
|
-
var
|
|
2078
|
+
var ACTION_TTL_MS = 8e3;
|
|
2079
|
+
var useToastStore = create15((set) => ({
|
|
1977
2080
|
toasts: [],
|
|
1978
2081
|
push: (t) => {
|
|
1979
|
-
const id = `toast_${
|
|
2082
|
+
const id = `toast_${randomUUID()}`;
|
|
1980
2083
|
set((state) => ({ toasts: [...state.toasts, { ...t, id }] }));
|
|
1981
2084
|
return id;
|
|
1982
2085
|
},
|
|
@@ -1987,6 +2090,12 @@ var toast = {
|
|
|
1987
2090
|
error: (msg, ttl = 6e3) => useToastStore.getState().push({ message: msg, variant: "error", ttl }),
|
|
1988
2091
|
warn: (msg, ttl = 4500) => useToastStore.getState().push({ message: msg, variant: "warn", ttl }),
|
|
1989
2092
|
info: (msg, ttl = 3500) => useToastStore.getState().push({ message: msg, variant: "info", ttl }),
|
|
2093
|
+
/**
|
|
2094
|
+
* Fire a toast carrying an "Undo" action button. The toast lingers
|
|
2095
|
+
* for {@link ACTION_TTL_MS} so the user has time to react; letting it
|
|
2096
|
+
* expire is the same as not undoing.
|
|
2097
|
+
*/
|
|
2098
|
+
undoable: (msg, onUndo, label = "Undo", ttl = ACTION_TTL_MS) => useToastStore.getState().push({ message: msg, variant: "info", ttl, action: { label, onClick: onUndo } }),
|
|
1990
2099
|
dismiss: (id) => useToastStore.getState().dismiss(id)
|
|
1991
2100
|
};
|
|
1992
2101
|
function Icon({ variant }) {
|
|
@@ -2014,6 +2123,18 @@ function ToastItem({ entry }) {
|
|
|
2014
2123
|
children: [
|
|
2015
2124
|
/* @__PURE__ */ jsx2(Icon, { variant: entry.variant }),
|
|
2016
2125
|
/* @__PURE__ */ jsx2("div", { className: "flex-1 min-w-0 whitespace-pre-wrap break-words leading-snug", children: entry.message }),
|
|
2126
|
+
entry.action && /* @__PURE__ */ jsx2(
|
|
2127
|
+
"button",
|
|
2128
|
+
{
|
|
2129
|
+
type: "button",
|
|
2130
|
+
onClick: () => {
|
|
2131
|
+
entry.action?.onClick();
|
|
2132
|
+
dismiss(entry.id);
|
|
2133
|
+
},
|
|
2134
|
+
className: "shrink-0 font-medium text-primary hover:underline",
|
|
2135
|
+
children: entry.action.label
|
|
2136
|
+
}
|
|
2137
|
+
),
|
|
2017
2138
|
/* @__PURE__ */ jsx2(
|
|
2018
2139
|
"button",
|
|
2019
2140
|
{
|
|
@@ -2670,8 +2791,8 @@ function handleFilesWritten(msg) {
|
|
|
2670
2791
|
}
|
|
2671
2792
|
}
|
|
2672
2793
|
function queryMailbox() {
|
|
2673
|
-
const ws = getWSClient(
|
|
2674
|
-
ws?.send?.({ type: "mailbox.messages", payload: { limit: 30 } });
|
|
2794
|
+
const ws = getWSClient();
|
|
2795
|
+
ws?.send?.({ type: "mailbox.messages", payload: { limit: 30, incompleteOnly: true } });
|
|
2675
2796
|
ws?.send?.({ type: "mailbox.agents", payload: {} });
|
|
2676
2797
|
}
|
|
2677
2798
|
var WS_HANDLERS = {
|
|
@@ -2755,6 +2876,9 @@ var WS_HANDLERS = {
|
|
|
2755
2876
|
useMailboxStore.getState().setMessages([]);
|
|
2756
2877
|
queryMailbox();
|
|
2757
2878
|
},
|
|
2879
|
+
"mailbox.purged": (msg) => {
|
|
2880
|
+
queryMailbox();
|
|
2881
|
+
},
|
|
2758
2882
|
"brain.status": (msg) => {
|
|
2759
2883
|
const p = msg.payload;
|
|
2760
2884
|
const lines = [
|
|
@@ -2840,6 +2964,10 @@ _${p.decision.rationale}_` : "";
|
|
|
2840
2964
|
refined: p.refined,
|
|
2841
2965
|
english: p.english
|
|
2842
2966
|
});
|
|
2967
|
+
},
|
|
2968
|
+
"git.info": (msg) => {
|
|
2969
|
+
const p = msg.payload;
|
|
2970
|
+
useGitInfoStore.getState().setInfo({ ...p, fetchedAt: Date.now() });
|
|
2843
2971
|
}
|
|
2844
2972
|
};
|
|
2845
2973
|
|
|
@@ -2896,8 +3024,8 @@ function useWebSocket() {
|
|
|
2896
3024
|
const { wsUrl } = useConfigStore();
|
|
2897
3025
|
const client2 = getWSClient(wsUrl);
|
|
2898
3026
|
const sendMessage = useCallback(
|
|
2899
|
-
(content) => {
|
|
2900
|
-
if (client2.isConnected) return client2.sendMessage(content);
|
|
3027
|
+
(content, imageBase64) => {
|
|
3028
|
+
if (client2.isConnected) return client2.sendMessage(content, imageBase64);
|
|
2901
3029
|
return null;
|
|
2902
3030
|
},
|
|
2903
3031
|
[client2]
|
|
@@ -3060,7 +3188,7 @@ function useWebSocket() {
|
|
|
3060
3188
|
}
|
|
3061
3189
|
|
|
3062
3190
|
// src/App.tsx
|
|
3063
|
-
import { useEffect as
|
|
3191
|
+
import { useEffect as useEffect46 } from "react";
|
|
3064
3192
|
|
|
3065
3193
|
// src/components/ActivityBar.tsx
|
|
3066
3194
|
import {
|
|
@@ -4036,7 +4164,7 @@ import {
|
|
|
4036
4164
|
Terminal as Terminal4,
|
|
4037
4165
|
Zap as Zap4
|
|
4038
4166
|
} from "lucide-react";
|
|
4039
|
-
import { memo as memo5, useCallback as
|
|
4167
|
+
import { memo as memo5, useCallback as useCallback10, useEffect as useEffect19, useMemo as useMemo7, useRef as useRef14, useState as useState24 } from "react";
|
|
4040
4168
|
import { VList } from "virtua";
|
|
4041
4169
|
|
|
4042
4170
|
// src/components/AutonomyPicker.tsx
|
|
@@ -4156,9 +4284,68 @@ function AutonomyPicker({
|
|
|
4156
4284
|
}
|
|
4157
4285
|
|
|
4158
4286
|
// src/components/ChatInput.tsx
|
|
4159
|
-
import { expectDefined as expectDefined6 } from "@wrongstack/core";
|
|
4287
|
+
import { expectDefined as expectDefined6, toErrorMessage } from "@wrongstack/core";
|
|
4288
|
+
|
|
4289
|
+
// src/stores/auto-submit-streak.ts
|
|
4290
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
4291
|
+
var _streak = 0;
|
|
4292
|
+
var _capWarned = false;
|
|
4293
|
+
function useAutoSubmitStreak() {
|
|
4294
|
+
const autoProceedMaxIterations = useLocalPrefs((s) => s.autoProceedMaxIterations);
|
|
4295
|
+
const autonomy = useLocalPrefs((s) => s.autonomy);
|
|
4296
|
+
const streakRef = useRef3(_streak);
|
|
4297
|
+
const capWarnedRef = useRef3(_capWarned);
|
|
4298
|
+
const prevAutonomyRef = useRef3(autonomy);
|
|
4299
|
+
useEffect6(() => {
|
|
4300
|
+
streakRef.current = _streak;
|
|
4301
|
+
capWarnedRef.current = _capWarned;
|
|
4302
|
+
});
|
|
4303
|
+
useEffect6(() => {
|
|
4304
|
+
if (prevAutonomyRef.current !== "auto" && autonomy === "auto") {
|
|
4305
|
+
_capWarned = false;
|
|
4306
|
+
capWarnedRef.current = false;
|
|
4307
|
+
}
|
|
4308
|
+
prevAutonomyRef.current = autonomy;
|
|
4309
|
+
}, [autonomy]);
|
|
4310
|
+
const canAutoSubmit = useCallback4(() => {
|
|
4311
|
+
if (autoProceedMaxIterations <= 0) return true;
|
|
4312
|
+
return streakRef.current < autoProceedMaxIterations;
|
|
4313
|
+
}, [autoProceedMaxIterations]);
|
|
4314
|
+
const recordAutoSubmit = useCallback4(() => {
|
|
4315
|
+
const max = autoProceedMaxIterations;
|
|
4316
|
+
if (max > 0 && streakRef.current >= max) {
|
|
4317
|
+
return false;
|
|
4318
|
+
}
|
|
4319
|
+
_streak = ++streakRef.current;
|
|
4320
|
+
if (max > 0 && _streak >= max) {
|
|
4321
|
+
_capWarned = true;
|
|
4322
|
+
capWarnedRef.current = true;
|
|
4323
|
+
}
|
|
4324
|
+
return true;
|
|
4325
|
+
}, [autoProceedMaxIterations]);
|
|
4326
|
+
const reset = useCallback4(() => {
|
|
4327
|
+
_streak = 0;
|
|
4328
|
+
streakRef.current = 0;
|
|
4329
|
+
_capWarned = false;
|
|
4330
|
+
capWarnedRef.current = false;
|
|
4331
|
+
}, []);
|
|
4332
|
+
const resetCapWarned = useCallback4(() => {
|
|
4333
|
+
_capWarned = false;
|
|
4334
|
+
capWarnedRef.current = false;
|
|
4335
|
+
}, []);
|
|
4336
|
+
return {
|
|
4337
|
+
streak: streakRef.current,
|
|
4338
|
+
capWarned: capWarnedRef.current,
|
|
4339
|
+
canAutoSubmit,
|
|
4340
|
+
recordAutoSubmit,
|
|
4341
|
+
reset,
|
|
4342
|
+
resetCapWarned
|
|
4343
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
// src/components/ChatInput.tsx
|
|
4160
4347
|
import { Pencil, Send, Square as Square2, Sparkles as Sparkles2 } from "lucide-react";
|
|
4161
|
-
import { useCallback as
|
|
4348
|
+
import { useCallback as useCallback5, useEffect as useEffect10, useRef as useRef7, useState as useState8 } from "react";
|
|
4162
4349
|
|
|
4163
4350
|
// src/components/CommandPalette/index.tsx
|
|
4164
4351
|
import {
|
|
@@ -4188,7 +4375,7 @@ import {
|
|
|
4188
4375
|
VolumeX,
|
|
4189
4376
|
Wrench
|
|
4190
4377
|
} from "lucide-react";
|
|
4191
|
-
import { useEffect as
|
|
4378
|
+
import { useEffect as useEffect7, useMemo, useRef as useRef4, useState as useState5 } from "react";
|
|
4192
4379
|
|
|
4193
4380
|
// src/components/CommandPalette/export-utils.ts
|
|
4194
4381
|
function downloadChatAsMarkdown() {
|
|
@@ -4327,15 +4514,15 @@ function CommandPalette() {
|
|
|
4327
4514
|
const ws = useWebSocket();
|
|
4328
4515
|
const [query, setQuery] = useState5("");
|
|
4329
4516
|
const [index, setIndex] = useState5(0);
|
|
4330
|
-
const inputRef =
|
|
4331
|
-
|
|
4517
|
+
const inputRef = useRef4(null);
|
|
4518
|
+
useEffect7(() => {
|
|
4332
4519
|
if (open) {
|
|
4333
4520
|
setQuery("");
|
|
4334
4521
|
setIndex(0);
|
|
4335
4522
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
4336
4523
|
}
|
|
4337
4524
|
}, [open]);
|
|
4338
|
-
|
|
4525
|
+
useEffect7(() => {
|
|
4339
4526
|
const onKey = (e) => {
|
|
4340
4527
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
|
|
4341
4528
|
e.preventDefault();
|
|
@@ -4564,7 +4751,7 @@ function CommandPalette() {
|
|
|
4564
4751
|
return hay.includes(q);
|
|
4565
4752
|
});
|
|
4566
4753
|
}, [items, query]);
|
|
4567
|
-
|
|
4754
|
+
useEffect7(() => {
|
|
4568
4755
|
if (index >= filtered.length) setIndex(0);
|
|
4569
4756
|
}, [filtered.length, index]);
|
|
4570
4757
|
if (!open) return null;
|
|
@@ -4669,16 +4856,16 @@ function renderGroupedList(filtered, index, dispatch, setIndex) {
|
|
|
4669
4856
|
// src/components/FilePicker.tsx
|
|
4670
4857
|
import { expectDefined as expectDefined4 } from "@wrongstack/core";
|
|
4671
4858
|
import { FileText, Folder } from "lucide-react";
|
|
4672
|
-
import { useEffect as
|
|
4859
|
+
import { useEffect as useEffect8, useRef as useRef5, useState as useState6 } from "react";
|
|
4673
4860
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4674
4861
|
function FilePicker({ query, onPick, onClose }) {
|
|
4675
4862
|
const ws = useWebSocket();
|
|
4676
4863
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
4677
4864
|
const [files, setFiles] = useState6([]);
|
|
4678
4865
|
const [index, setIndex] = useState6(0);
|
|
4679
|
-
const debounceRef =
|
|
4680
|
-
const wantHandle =
|
|
4681
|
-
|
|
4866
|
+
const debounceRef = useRef5(null);
|
|
4867
|
+
const wantHandle = useRef5(null);
|
|
4868
|
+
useEffect8(() => {
|
|
4682
4869
|
const client2 = getWSClient(wsUrl);
|
|
4683
4870
|
const off = client2.on("files.list", (msg) => {
|
|
4684
4871
|
const p = msg.payload;
|
|
@@ -4689,7 +4876,7 @@ function FilePicker({ query, onPick, onClose }) {
|
|
|
4689
4876
|
});
|
|
4690
4877
|
return () => off();
|
|
4691
4878
|
}, [wsUrl]);
|
|
4692
|
-
|
|
4879
|
+
useEffect8(() => {
|
|
4693
4880
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
4694
4881
|
debounceRef.current = setTimeout(() => {
|
|
4695
4882
|
ws.client.listFiles(query, 50);
|
|
@@ -4698,7 +4885,7 @@ function FilePicker({ query, onPick, onClose }) {
|
|
|
4698
4885
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
4699
4886
|
};
|
|
4700
4887
|
}, [query, ws.client]);
|
|
4701
|
-
|
|
4888
|
+
useEffect8(() => {
|
|
4702
4889
|
const onKey = (e) => {
|
|
4703
4890
|
if (e.key === "ArrowDown") {
|
|
4704
4891
|
e.preventDefault();
|
|
@@ -4987,7 +5174,7 @@ ${text}
|
|
|
4987
5174
|
}
|
|
4988
5175
|
|
|
4989
5176
|
// src/components/RefinePanel.tsx
|
|
4990
|
-
import { useEffect as
|
|
5177
|
+
import { useEffect as useEffect9, useRef as useRef6, useState as useState7 } from "react";
|
|
4991
5178
|
import { Check, Edit3, Globe, X as X3 } from "lucide-react";
|
|
4992
5179
|
import { Fragment, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4993
5180
|
function RefinePanel({
|
|
@@ -5001,9 +5188,9 @@ function RefinePanel({
|
|
|
5001
5188
|
const [countdown, setCountdown] = useState7(autoSendDelayMs > 0 ? Math.ceil(autoSendDelayMs / 1e3) : null);
|
|
5002
5189
|
const [editText, setEditText] = useState7(refined);
|
|
5003
5190
|
const [isEditing, setIsEditing] = useState7(false);
|
|
5004
|
-
const countdownRef =
|
|
5005
|
-
const panelRef =
|
|
5006
|
-
|
|
5191
|
+
const countdownRef = useRef6(null);
|
|
5192
|
+
const panelRef = useRef6(null);
|
|
5193
|
+
useEffect9(() => {
|
|
5007
5194
|
if (autoSendDelayMs <= 0 || isEditing) return;
|
|
5008
5195
|
countdownRef.current = setInterval(() => {
|
|
5009
5196
|
setCountdown((prev) => {
|
|
@@ -5019,7 +5206,7 @@ function RefinePanel({
|
|
|
5019
5206
|
if (countdownRef.current) clearInterval(countdownRef.current);
|
|
5020
5207
|
};
|
|
5021
5208
|
}, [autoSendDelayMs, isEditing, onDecision]);
|
|
5022
|
-
|
|
5209
|
+
useEffect9(() => {
|
|
5023
5210
|
const handleKeyDown = (e) => {
|
|
5024
5211
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
5025
5212
|
switch (e.key) {
|
|
@@ -5065,7 +5252,7 @@ function RefinePanel({
|
|
|
5065
5252
|
window.addEventListener("keydown", handleKeyDown);
|
|
5066
5253
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
5067
5254
|
}, [isEditing, onDecision, refined, setRefinePanel]);
|
|
5068
|
-
|
|
5255
|
+
useEffect9(() => {
|
|
5069
5256
|
if (isEditing && panelRef.current) {
|
|
5070
5257
|
const textarea = panelRef.current.querySelector("textarea");
|
|
5071
5258
|
textarea?.focus();
|
|
@@ -5261,6 +5448,9 @@ function ChatInput({
|
|
|
5261
5448
|
const refinePanel = useUIStore((s) => s.refinePanel);
|
|
5262
5449
|
const toggleRefineEnabled = useUIStore((s) => s.toggleRefineEnabled);
|
|
5263
5450
|
const setRefinePanel = useUIStore((s) => s.setRefinePanel);
|
|
5451
|
+
const setProcessMonitorOpen = useUIStore((s) => s.setProcessMonitorOpen);
|
|
5452
|
+
const setQueuePanelOpen = useUIStore((s) => s.setQueuePanelOpen);
|
|
5453
|
+
const { reset: resetAutoSubmitStreak } = useAutoSubmitStreak();
|
|
5264
5454
|
const lastInputTokens = useSessionStore((s) => s.lastInputTokens);
|
|
5265
5455
|
const maxContext = useSessionStore((s) => s.maxContext);
|
|
5266
5456
|
const [input, setInput] = useState8("");
|
|
@@ -5269,8 +5459,8 @@ function ChatInput({
|
|
|
5269
5459
|
const [atMention, setAtMention] = useState8(null);
|
|
5270
5460
|
const [pasteHint, setPasteHint] = useState8(null);
|
|
5271
5461
|
const [draggingOver, setDraggingOver] = useState8(false);
|
|
5272
|
-
const textareaRef =
|
|
5273
|
-
const runSlashCommand =
|
|
5462
|
+
const textareaRef = useRef7(null);
|
|
5463
|
+
const runSlashCommand = useCallback5(
|
|
5274
5464
|
(raw) => {
|
|
5275
5465
|
const trimmed = raw.trim();
|
|
5276
5466
|
const sp = trimmed.indexOf(" ");
|
|
@@ -5415,6 +5605,32 @@ function ChatInput({
|
|
|
5415
5605
|
case "/next-steps":
|
|
5416
5606
|
sendMsg("What are the next steps I should take? Be specific and actionable.");
|
|
5417
5607
|
return true;
|
|
5608
|
+
case "/kill":
|
|
5609
|
+
case "/ps": {
|
|
5610
|
+
setProcessMonitorOpen(true);
|
|
5611
|
+
return true;
|
|
5612
|
+
}
|
|
5613
|
+
case "/queue": {
|
|
5614
|
+
const q = queue;
|
|
5615
|
+
if (q.length === 0) {
|
|
5616
|
+
addMessage({
|
|
5617
|
+
role: "assistant",
|
|
5618
|
+
content: "\u{1F4CB} **Message Queue** \u2014 empty.\n\nType while the agent is running to queue messages; they are sent automatically when the agent finishes."
|
|
5619
|
+
});
|
|
5620
|
+
} else {
|
|
5621
|
+
const lines = [`\u{1F4CB} **Message Queue** (${q.length} queued)`, ""];
|
|
5622
|
+
q.forEach((item, i) => {
|
|
5623
|
+
const preview = item.length > 80 ? `${item.slice(0, 77)}\u2026` : item;
|
|
5624
|
+
lines.push(`${i + 1}. ${preview}`);
|
|
5625
|
+
});
|
|
5626
|
+
lines.push("", "_Use `/queue open` to manage, or `/queue clear` to wipe._");
|
|
5627
|
+
addMessage({ role: "assistant", content: lines.join("\n") });
|
|
5628
|
+
}
|
|
5629
|
+
if (args.toLowerCase() === "open") {
|
|
5630
|
+
setQueuePanelOpen(true);
|
|
5631
|
+
}
|
|
5632
|
+
return true;
|
|
5633
|
+
}
|
|
5418
5634
|
case "/next": {
|
|
5419
5635
|
const narg = args.trim().toLowerCase();
|
|
5420
5636
|
if (!narg || narg === "list" || narg === "ls" || narg === "show") return handleNextList();
|
|
@@ -5432,17 +5648,20 @@ function ChatInput({
|
|
|
5432
5648
|
addMessage,
|
|
5433
5649
|
clearMessages,
|
|
5434
5650
|
client2,
|
|
5651
|
+
queue,
|
|
5435
5652
|
sendAbort,
|
|
5436
5653
|
setLoading,
|
|
5437
5654
|
setCurrentView,
|
|
5438
5655
|
toggleRefineEnabled,
|
|
5656
|
+
setProcessMonitorOpen,
|
|
5657
|
+
setQueuePanelOpen,
|
|
5439
5658
|
ws,
|
|
5440
5659
|
onOpenBreakdown
|
|
5441
5660
|
]
|
|
5442
5661
|
);
|
|
5443
|
-
const
|
|
5662
|
+
const NEXT_STEPS_RE = /💡\s*Next steps?\s*\n+((?:\d+\.\s+.+\n?)+)/i;
|
|
5444
5663
|
function parseNextStepsFromContent(content) {
|
|
5445
|
-
const match =
|
|
5664
|
+
const match = NEXT_STEPS_RE.exec(content);
|
|
5446
5665
|
if (!match?.[1]) return [];
|
|
5447
5666
|
const steps = [];
|
|
5448
5667
|
for (const line of match[1].split("\n").filter(Boolean)) {
|
|
@@ -5515,10 +5734,10 @@ function ChatInput({
|
|
|
5515
5734
|
return true;
|
|
5516
5735
|
}
|
|
5517
5736
|
const slashSuggestions = input.startsWith("/") && !input.includes(" ") ? matchSlash(input) : [];
|
|
5518
|
-
|
|
5737
|
+
useEffect10(() => {
|
|
5519
5738
|
if (slashIndex >= slashSuggestions.length) setSlashIndex(0);
|
|
5520
5739
|
}, [slashSuggestions.length, slashIndex]);
|
|
5521
|
-
const _clearTextarea =
|
|
5740
|
+
const _clearTextarea = useCallback5(() => {
|
|
5522
5741
|
const ta = textareaRef.current;
|
|
5523
5742
|
if (ta) {
|
|
5524
5743
|
ta.value = "";
|
|
@@ -5529,10 +5748,13 @@ function ChatInput({
|
|
|
5529
5748
|
}
|
|
5530
5749
|
}
|
|
5531
5750
|
}, [isLoading]);
|
|
5532
|
-
const handleSubmit =
|
|
5751
|
+
const handleSubmit = useCallback5(
|
|
5533
5752
|
async (e) => {
|
|
5534
5753
|
e.preventDefault();
|
|
5535
|
-
|
|
5754
|
+
resetAutoSubmitStreak();
|
|
5755
|
+
if (!input.trim() && !pendingImageRef.current) return;
|
|
5756
|
+
const pendingImage = pendingImageRef.current;
|
|
5757
|
+
pendingImageRef.current = null;
|
|
5536
5758
|
const content = input.trim();
|
|
5537
5759
|
if (content.startsWith("/") && runSlashCommand(content)) {
|
|
5538
5760
|
pushPrompt(content);
|
|
@@ -5547,7 +5769,10 @@ function ChatInput({
|
|
|
5547
5769
|
pushPrompt(content);
|
|
5548
5770
|
_clearTextarea();
|
|
5549
5771
|
if (isLoading) {
|
|
5550
|
-
|
|
5772
|
+
const queued = pendingImage ? `
|
|
5773
|
+
|
|
5774
|
+
${content}` : content;
|
|
5775
|
+
enqueue(queued);
|
|
5551
5776
|
return;
|
|
5552
5777
|
}
|
|
5553
5778
|
try {
|
|
@@ -5563,15 +5788,18 @@ function ChatInput({
|
|
|
5563
5788
|
});
|
|
5564
5789
|
refineModel(content);
|
|
5565
5790
|
} else {
|
|
5566
|
-
|
|
5791
|
+
const fullContent = pendingImage ? `
|
|
5792
|
+
|
|
5793
|
+
${content}` : content;
|
|
5794
|
+
addMessage({ role: "user", content: fullContent });
|
|
5567
5795
|
setLoading(true);
|
|
5568
|
-
sendMessage(content);
|
|
5796
|
+
sendMessage(content, pendingImage ?? void 0);
|
|
5569
5797
|
}
|
|
5570
5798
|
} else {
|
|
5571
5799
|
console.warn(JSON.stringify({ level: "warn", event: "ws_send_failed", reason: "not_connected", timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
5572
5800
|
}
|
|
5573
5801
|
} catch (err) {
|
|
5574
|
-
console.warn(JSON.stringify({ level: "warn", event: "ws_send_error", error:
|
|
5802
|
+
console.warn(JSON.stringify({ level: "warn", event: "ws_send_error", error: toErrorMessage(err), timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
5575
5803
|
setLoading(false);
|
|
5576
5804
|
}
|
|
5577
5805
|
},
|
|
@@ -5588,14 +5816,15 @@ function ChatInput({
|
|
|
5588
5816
|
setLoading,
|
|
5589
5817
|
runSlashCommand,
|
|
5590
5818
|
pushPrompt,
|
|
5591
|
-
_clearTextarea
|
|
5819
|
+
_clearTextarea,
|
|
5820
|
+
resetAutoSubmitStreak
|
|
5592
5821
|
]
|
|
5593
5822
|
);
|
|
5594
|
-
const handleAbort =
|
|
5823
|
+
const handleAbort = useCallback5(() => {
|
|
5595
5824
|
sendAbort();
|
|
5596
5825
|
setLoading(false);
|
|
5597
5826
|
}, [sendAbort, setLoading]);
|
|
5598
|
-
const handleStopAndEdit =
|
|
5827
|
+
const handleStopAndEdit = useCallback5(() => {
|
|
5599
5828
|
sendAbort();
|
|
5600
5829
|
setLoading(false);
|
|
5601
5830
|
const all = useChatStore.getState().messages;
|
|
@@ -5616,7 +5845,7 @@ function ChatInput({
|
|
|
5616
5845
|
}
|
|
5617
5846
|
}
|
|
5618
5847
|
}, [sendAbort, setLoading]);
|
|
5619
|
-
const handleKeyDown =
|
|
5848
|
+
const handleKeyDown = useCallback5(
|
|
5620
5849
|
(e) => {
|
|
5621
5850
|
if (slashSuggestions.length === 0 && !atMention && promptHistory.length > 0) {
|
|
5622
5851
|
if (e.key === "ArrowUp") {
|
|
@@ -5703,6 +5932,33 @@ function ChatInput({
|
|
|
5703
5932
|
},
|
|
5704
5933
|
[slashSuggestions, slashIndex, atMention, promptHistory, historyIdx, input, runSlashCommand, handleSubmit]
|
|
5705
5934
|
);
|
|
5935
|
+
const pendingImageRef = useRef7(null);
|
|
5936
|
+
useEffect10(() => {
|
|
5937
|
+
const ta = textareaRef.current;
|
|
5938
|
+
if (!ta) return;
|
|
5939
|
+
const onPaste = async (e) => {
|
|
5940
|
+
const items = e.clipboardData?.items;
|
|
5941
|
+
if (!items) return;
|
|
5942
|
+
for (const item of items) {
|
|
5943
|
+
if (item.type.startsWith("image/")) {
|
|
5944
|
+
e.preventDefault();
|
|
5945
|
+
try {
|
|
5946
|
+
const blob = item.getAsFile();
|
|
5947
|
+
if (!blob) continue;
|
|
5948
|
+
const reader = new FileReader();
|
|
5949
|
+
reader.onload = () => {
|
|
5950
|
+
pendingImageRef.current = reader.result;
|
|
5951
|
+
};
|
|
5952
|
+
reader.readAsDataURL(blob);
|
|
5953
|
+
} catch {
|
|
5954
|
+
}
|
|
5955
|
+
return;
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
};
|
|
5959
|
+
ta.addEventListener("paste", onPaste);
|
|
5960
|
+
return () => ta.removeEventListener("paste", onPaste);
|
|
5961
|
+
}, []);
|
|
5706
5962
|
const adjustTextareaHeight = () => {
|
|
5707
5963
|
const textarea = textareaRef.current;
|
|
5708
5964
|
if (textarea) {
|
|
@@ -6130,7 +6386,7 @@ function ChatInput({
|
|
|
6130
6386
|
|
|
6131
6387
|
// src/components/CheckpointTimeline.tsx
|
|
6132
6388
|
import { Clock as Clock4, History, Rewind, X as X4 } from "lucide-react";
|
|
6133
|
-
import { useCallback as
|
|
6389
|
+
import { useCallback as useCallback6, useEffect as useEffect11, useRef as useRef8, useState as useState9 } from "react";
|
|
6134
6390
|
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6135
6391
|
function CheckpointTimeline({
|
|
6136
6392
|
open,
|
|
@@ -6140,8 +6396,8 @@ function CheckpointTimeline({
|
|
|
6140
6396
|
const [checkpoints, setCheckpoints] = useState9([]);
|
|
6141
6397
|
const [rewinding, setRewinding] = useState9(false);
|
|
6142
6398
|
const ws = useWebSocket();
|
|
6143
|
-
const offRef =
|
|
6144
|
-
|
|
6399
|
+
const offRef = useRef8(null);
|
|
6400
|
+
useEffect11(() => {
|
|
6145
6401
|
if (!open || !ws.client?.isConnected) return;
|
|
6146
6402
|
ws.client.send?.({ type: "session.checkpoints" });
|
|
6147
6403
|
offRef.current = ws.client.on?.("session.checkpoints", (msg) => {
|
|
@@ -6152,7 +6408,7 @@ function CheckpointTimeline({
|
|
|
6152
6408
|
offRef.current?.();
|
|
6153
6409
|
};
|
|
6154
6410
|
}, [open, ws.client]);
|
|
6155
|
-
const handleRewind =
|
|
6411
|
+
const handleRewind = useCallback6(
|
|
6156
6412
|
async (index) => {
|
|
6157
6413
|
setRewinding(true);
|
|
6158
6414
|
ws.client.send?.({ type: "session.rewind", payload: { checkpointIndex: index } });
|
|
@@ -6276,7 +6532,7 @@ function CheckpointTimeline({
|
|
|
6276
6532
|
// src/components/ContextModePicker.tsx
|
|
6277
6533
|
import { expectDefined as expectDefined7 } from "@wrongstack/core";
|
|
6278
6534
|
import { Check as Check2, ChevronDown as ChevronDown2, Gauge, Wrench as Wrench2, Zap as Zap2, FileSearch } from "lucide-react";
|
|
6279
|
-
import { useCallback as
|
|
6535
|
+
import { useCallback as useCallback7, useEffect as useEffect12, useRef as useRef9, useState as useState10 } from "react";
|
|
6280
6536
|
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6281
6537
|
var FALLBACK_MODES = [
|
|
6282
6538
|
{
|
|
@@ -6294,12 +6550,12 @@ function ContextModePicker() {
|
|
|
6294
6550
|
const { listContextModes, switchContextMode, client: client2 } = useWebSocket();
|
|
6295
6551
|
const [open, setOpen] = useState10(false);
|
|
6296
6552
|
const [opsOpen, setOpsOpen] = useState10(false);
|
|
6297
|
-
const rootRef =
|
|
6298
|
-
const opsRef =
|
|
6299
|
-
|
|
6553
|
+
const rootRef = useRef9(null);
|
|
6554
|
+
const opsRef = useRef9(null);
|
|
6555
|
+
useEffect12(() => {
|
|
6300
6556
|
if (open) listContextModes();
|
|
6301
6557
|
}, [open, listContextModes]);
|
|
6302
|
-
|
|
6558
|
+
useEffect12(() => {
|
|
6303
6559
|
if (!open) return;
|
|
6304
6560
|
const onClick = (e) => {
|
|
6305
6561
|
if (!rootRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -6314,7 +6570,7 @@ function ContextModePicker() {
|
|
|
6314
6570
|
document.removeEventListener("keydown", onKey);
|
|
6315
6571
|
};
|
|
6316
6572
|
}, [open]);
|
|
6317
|
-
|
|
6573
|
+
useEffect12(() => {
|
|
6318
6574
|
if (!opsOpen) return;
|
|
6319
6575
|
const onClick = (e) => {
|
|
6320
6576
|
if (!opsRef.current?.contains(e.target)) setOpsOpen(false);
|
|
@@ -6322,12 +6578,12 @@ function ContextModePicker() {
|
|
|
6322
6578
|
document.addEventListener("mousedown", onClick);
|
|
6323
6579
|
return () => document.removeEventListener("mousedown", onClick);
|
|
6324
6580
|
}, [opsOpen]);
|
|
6325
|
-
const compact =
|
|
6581
|
+
const compact = useCallback7((aggressive) => {
|
|
6326
6582
|
client2?.compactContext?.(aggressive);
|
|
6327
6583
|
setOpsOpen(false);
|
|
6328
6584
|
setOpen(false);
|
|
6329
6585
|
}, [client2]);
|
|
6330
|
-
const repair =
|
|
6586
|
+
const repair = useCallback7(() => {
|
|
6331
6587
|
client2?.repairContext?.();
|
|
6332
6588
|
setOpsOpen(false);
|
|
6333
6589
|
setOpen(false);
|
|
@@ -6731,7 +6987,7 @@ function ContextFillBar({
|
|
|
6731
6987
|
|
|
6732
6988
|
// src/components/ContextBreakdownModal.tsx
|
|
6733
6989
|
import { AlertTriangle as AlertTriangle2, FileText as FileText2, MessageSquare as MessageSquare2, RefreshCw, Wrench as Wrench3, X as X5 } from "lucide-react";
|
|
6734
|
-
import { useEffect as
|
|
6990
|
+
import { useEffect as useEffect13, useState as useState11 } from "react";
|
|
6735
6991
|
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
6736
6992
|
function ContextBreakdownModal({ open, onClose }) {
|
|
6737
6993
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
@@ -6739,7 +6995,7 @@ function ContextBreakdownModal({ open, onClose }) {
|
|
|
6739
6995
|
const [data, setData] = useState11(null);
|
|
6740
6996
|
const [loading, setLoading] = useState11(false);
|
|
6741
6997
|
const [error, setError] = useState11(null);
|
|
6742
|
-
|
|
6998
|
+
useEffect13(() => {
|
|
6743
6999
|
if (!open) {
|
|
6744
7000
|
setData(null);
|
|
6745
7001
|
setError(null);
|
|
@@ -6773,7 +7029,7 @@ function ContextBreakdownModal({ open, onClose }) {
|
|
|
6773
7029
|
unsubscribe();
|
|
6774
7030
|
};
|
|
6775
7031
|
}, [open, wsUrl]);
|
|
6776
|
-
|
|
7032
|
+
useEffect13(() => {
|
|
6777
7033
|
if (!open) return;
|
|
6778
7034
|
const onKey = (e) => {
|
|
6779
7035
|
if (e.key === "Escape") onClose();
|
|
@@ -6931,7 +7187,7 @@ function ContextBreakdownModal({ open, onClose }) {
|
|
|
6931
7187
|
}
|
|
6932
7188
|
|
|
6933
7189
|
// src/components/CostChip.tsx
|
|
6934
|
-
import { useEffect as
|
|
7190
|
+
import { useEffect as useEffect14, useRef as useRef10, useState as useState12 } from "react";
|
|
6935
7191
|
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
6936
7192
|
function CostChip() {
|
|
6937
7193
|
const cost = useSessionStore((s) => s.cost);
|
|
@@ -6940,8 +7196,8 @@ function CostChip() {
|
|
|
6940
7196
|
const cacheReadCost = useSessionStore((s) => s.cacheReadCost);
|
|
6941
7197
|
const messages = useChatStore((s) => s.messages);
|
|
6942
7198
|
const [open, setOpen] = useState12(false);
|
|
6943
|
-
const rootRef =
|
|
6944
|
-
|
|
7199
|
+
const rootRef = useRef10(null);
|
|
7200
|
+
useEffect14(() => {
|
|
6945
7201
|
if (!open) return;
|
|
6946
7202
|
const onClick = (e) => {
|
|
6947
7203
|
if (!rootRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -7190,7 +7446,7 @@ import {
|
|
|
7190
7446
|
User,
|
|
7191
7447
|
XCircle as XCircle4
|
|
7192
7448
|
} from "lucide-react";
|
|
7193
|
-
import { memo as memo3, useState as useState18 } from "react";
|
|
7449
|
+
import { memo as memo3, useMemo as useMemo5, useState as useState18 } from "react";
|
|
7194
7450
|
import ReactMarkdown from "react-markdown";
|
|
7195
7451
|
import remarkGfm from "remark-gfm";
|
|
7196
7452
|
|
|
@@ -7547,7 +7803,7 @@ import { useState as useState15 } from "react";
|
|
|
7547
7803
|
|
|
7548
7804
|
// src/components/MessageBubble/utils.tsx
|
|
7549
7805
|
import { Check as Check3, Copy, FileCode2 } from "lucide-react";
|
|
7550
|
-
import { useCallback as
|
|
7806
|
+
import { useCallback as useCallback8, useMemo as useMemo4, useState as useState14 } from "react";
|
|
7551
7807
|
import rehypeHighlight from "rehype-highlight";
|
|
7552
7808
|
import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
7553
7809
|
async function copyToClipboard(text) {
|
|
@@ -7600,7 +7856,7 @@ function formatToolDuration(ms) {
|
|
|
7600
7856
|
var rehypePlugins = [rehypeHighlight];
|
|
7601
7857
|
function CodeCopyButton({ text }) {
|
|
7602
7858
|
const [copied, setCopied] = useState14(false);
|
|
7603
|
-
const handleCopy =
|
|
7859
|
+
const handleCopy = useCallback8(async () => {
|
|
7604
7860
|
const ok = await copyToClipboard(text);
|
|
7605
7861
|
if (ok) {
|
|
7606
7862
|
setCopied(true);
|
|
@@ -7626,25 +7882,17 @@ function CodeCopyButton({ text }) {
|
|
|
7626
7882
|
);
|
|
7627
7883
|
}
|
|
7628
7884
|
var markdownComponents = {
|
|
7629
|
-
next_steps
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
const form = document.querySelector('form[class*="flex items-end gap-2"]');
|
|
7641
|
-
if (form) {
|
|
7642
|
-
form.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
|
|
7643
|
-
}
|
|
7644
|
-
}
|
|
7645
|
-
}
|
|
7646
|
-
);
|
|
7647
|
-
},
|
|
7885
|
+
// NOTE: <next_steps> is parsed and rendered in MessageBubble/index.tsx
|
|
7886
|
+
// (post-render, via parseNextSteps + NextStepsBar). We do NOT register a
|
|
7887
|
+
// custom component here for two reasons:
|
|
7888
|
+
// 1. react-markdown v10's micromark parser doesn't actually dispatch
|
|
7889
|
+
// <next_steps> (or any underscored tag) to the components map — they
|
|
7890
|
+
// fall through as raw HTML, which is exactly what the previous code
|
|
7891
|
+
// was trying (and failing) to catch.
|
|
7892
|
+
// 2. The MessageBubble path strips the block before passing content to
|
|
7893
|
+
// react-markdown, so this handler is unreachable in practice.
|
|
7894
|
+
// Leaving the comment here so future contributors know this was a
|
|
7895
|
+
// deliberate decision, not an oversight.
|
|
7648
7896
|
code({
|
|
7649
7897
|
inline,
|
|
7650
7898
|
className,
|
|
@@ -7859,7 +8107,20 @@ var MessageBubble = memo3(function MessageBubble2({
|
|
|
7859
8107
|
const cacheReadCost = useSessionStore((s) => s.cacheReadCost);
|
|
7860
8108
|
const localPrefs = useLocalPrefs();
|
|
7861
8109
|
const { autonomy, yolo } = localPrefs;
|
|
8110
|
+
const { canAutoSubmit, recordAutoSubmit, capWarned } = useAutoSubmitStreak();
|
|
8111
|
+
const autoProceedMaxIterations = localPrefs.autoProceedMaxIterations;
|
|
8112
|
+
const canAutoSubmitNow = autoProceedMaxIterations <= 0 || canAutoSubmit();
|
|
7862
8113
|
const handleAutoSubmit = (text) => {
|
|
8114
|
+
if (!canAutoSubmit()) {
|
|
8115
|
+
if (!capWarned) {
|
|
8116
|
+
addMessage({
|
|
8117
|
+
role: "assistant",
|
|
8118
|
+
content: "\u26A0\uFE0F _Auto-proceed paused \u2014 maximum consecutive automatic turns reached. Type anything to continue (autonomy stays on)._"
|
|
8119
|
+
});
|
|
8120
|
+
}
|
|
8121
|
+
return;
|
|
8122
|
+
}
|
|
8123
|
+
recordAutoSubmit();
|
|
7863
8124
|
addMessage({ role: "user", content: text });
|
|
7864
8125
|
setLoading(true);
|
|
7865
8126
|
const client2 = getWSClient(wsUrl);
|
|
@@ -7875,6 +8136,10 @@ var MessageBubble = memo3(function MessageBubble2({
|
|
|
7875
8136
|
}
|
|
7876
8137
|
return false;
|
|
7877
8138
|
})();
|
|
8139
|
+
const nextStepsResult = useMemo5(
|
|
8140
|
+
() => isLatestAssistant && message.content ? parseNextSteps(message.content) : null,
|
|
8141
|
+
[isLatestAssistant, message.content]
|
|
8142
|
+
);
|
|
7878
8143
|
const regenerate = () => {
|
|
7879
8144
|
const all = useChatStore.getState().messages;
|
|
7880
8145
|
const idx = all.findIndex((m) => m.id === message.id);
|
|
@@ -8034,21 +8299,21 @@ var MessageBubble = memo3(function MessageBubble2({
|
|
|
8034
8299
|
/* @__PURE__ */ jsx27("button", { type: "button", onClick: saveEdit, disabled: !editValue.trim(), className: "text-xs px-2 py-0.5 rounded bg-primary-foreground text-primary disabled:opacity-50", children: "Save & resend" })
|
|
8035
8300
|
] })
|
|
8036
8301
|
] })
|
|
8037
|
-
] }) :
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8302
|
+
] }) : (() => {
|
|
8303
|
+
const renderedContent = nextStepsResult ? nextStepsResult.stripped : message.content;
|
|
8304
|
+
return /* @__PURE__ */ jsx27("div", { className: cn("text-sm leading-relaxed markdown-content", message.streaming && "streaming-cursor"), children: renderedContent ? showRaw && message.role === "assistant" ? /* @__PURE__ */ jsx27("pre", { className: "whitespace-pre-wrap break-words font-mono text-xs leading-relaxed text-foreground/90 max-h-[40rem] overflow-auto", children: message.content }) : message.role === "assistant" && message.isError ? /* @__PURE__ */ jsx27(ErrorBodyWithStack, { text: message.content }) : /* @__PURE__ */ jsx27(ReactMarkdown, { remarkPlugins: [remarkGfm], rehypePlugins, components: markdownComponents, children: renderedContent }) : message.streaming ? /* @__PURE__ */ jsx27("span", { className: "inline-block animate-pulse text-muted-foreground", children: "Typing..." }) : /* @__PURE__ */ jsx27("span", { className: "text-muted-foreground italic", children: "No content" }) });
|
|
8305
|
+
})() }),
|
|
8306
|
+
nextStepsResult && nextStepsResult.steps.length > 0 && /* @__PURE__ */ jsx27(
|
|
8307
|
+
NextStepsBar,
|
|
8308
|
+
{
|
|
8309
|
+
steps: nextStepsResult.steps,
|
|
8310
|
+
yoloMode: yolo,
|
|
8311
|
+
autoMode: autonomy === "auto",
|
|
8312
|
+
autoDelayMs: localPrefs.autonomyDelayMs,
|
|
8313
|
+
onAutoSubmit: handleAutoSubmit,
|
|
8314
|
+
canAutoSubmit: canAutoSubmitNow
|
|
8315
|
+
}
|
|
8316
|
+
),
|
|
8052
8317
|
/* @__PURE__ */ jsxs25("div", { className: cn("flex items-center gap-2 px-1", isUser ? "flex-row-reverse" : "flex-row"), children: [
|
|
8053
8318
|
/* @__PURE__ */ jsx27("span", { className: "text-xs text-muted-foreground/50", children: new Date(message.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) }),
|
|
8054
8319
|
/* @__PURE__ */ jsx27("span", { className: "w-px h-3 bg-border/60 shrink-0", "aria-hidden": true }),
|
|
@@ -8124,18 +8389,18 @@ var MessageBubble = memo3(function MessageBubble2({
|
|
|
8124
8389
|
|
|
8125
8390
|
// src/components/ModePicker.tsx
|
|
8126
8391
|
import { Check as Check5, ChevronDown as ChevronDown5 } from "lucide-react";
|
|
8127
|
-
import { useEffect as
|
|
8392
|
+
import { useEffect as useEffect15, useRef as useRef11, useState as useState19 } from "react";
|
|
8128
8393
|
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
8129
8394
|
function ModePicker() {
|
|
8130
8395
|
const mode = useSessionStore((s) => s.mode);
|
|
8131
8396
|
const modes = useSessionStore((s) => s.modes);
|
|
8132
8397
|
const { listModes, switchMode } = useWebSocket();
|
|
8133
8398
|
const [open, setOpen] = useState19(false);
|
|
8134
|
-
const rootRef =
|
|
8135
|
-
|
|
8399
|
+
const rootRef = useRef11(null);
|
|
8400
|
+
useEffect15(() => {
|
|
8136
8401
|
if (open) listModes();
|
|
8137
8402
|
}, [open, listModes]);
|
|
8138
|
-
|
|
8403
|
+
useEffect15(() => {
|
|
8139
8404
|
if (!open) return;
|
|
8140
8405
|
const onClick = (e) => {
|
|
8141
8406
|
if (!rootRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -8207,7 +8472,7 @@ function ModePicker() {
|
|
|
8207
8472
|
|
|
8208
8473
|
// src/components/ProcessMonitor.tsx
|
|
8209
8474
|
import { Shield, Square as Square3, Terminal as Terminal2, X as X6 } from "lucide-react";
|
|
8210
|
-
import { useCallback as
|
|
8475
|
+
import { useCallback as useCallback9, useEffect as useEffect16, useRef as useRef12, useState as useState20 } from "react";
|
|
8211
8476
|
import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
8212
8477
|
function ProcessMonitor({
|
|
8213
8478
|
open,
|
|
@@ -8216,9 +8481,9 @@ function ProcessMonitor({
|
|
|
8216
8481
|
}) {
|
|
8217
8482
|
const [processes, setProcesses] = useState20([]);
|
|
8218
8483
|
const ws = useWebSocket();
|
|
8219
|
-
const offRef =
|
|
8220
|
-
const pollRef =
|
|
8221
|
-
|
|
8484
|
+
const offRef = useRef12(null);
|
|
8485
|
+
const pollRef = useRef12(null);
|
|
8486
|
+
useEffect16(() => {
|
|
8222
8487
|
if (!open || !ws.client?.isConnected) return;
|
|
8223
8488
|
ws.client.send?.({ type: "process.list" });
|
|
8224
8489
|
offRef.current = ws.client.on?.("process.list", (msg) => {
|
|
@@ -8233,13 +8498,13 @@ function ProcessMonitor({
|
|
|
8233
8498
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
8234
8499
|
};
|
|
8235
8500
|
}, [open, ws.client]);
|
|
8236
|
-
const handleKill =
|
|
8501
|
+
const handleKill = useCallback9(
|
|
8237
8502
|
(pid) => {
|
|
8238
8503
|
ws.client.send?.({ type: "process.kill", payload: { pid } });
|
|
8239
8504
|
},
|
|
8240
8505
|
[ws.client]
|
|
8241
8506
|
);
|
|
8242
|
-
const handleKillAll =
|
|
8507
|
+
const handleKillAll = useCallback9(() => {
|
|
8243
8508
|
ws.client.send?.({ type: "process.killAll" });
|
|
8244
8509
|
}, [ws.client]);
|
|
8245
8510
|
const running = processes.filter((p) => p.status === "running");
|
|
@@ -8365,7 +8630,7 @@ function ProcessMonitor({
|
|
|
8365
8630
|
|
|
8366
8631
|
// src/components/SearchOverlay.tsx
|
|
8367
8632
|
import { ArrowDown, ArrowUp, Search as Search2, X as X7 } from "lucide-react";
|
|
8368
|
-
import { useEffect as
|
|
8633
|
+
import { useEffect as useEffect17, useMemo as useMemo6, useRef as useRef13, useState as useState21 } from "react";
|
|
8369
8634
|
import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
8370
8635
|
var HIGHLIGHT_STYLES = `
|
|
8371
8636
|
::highlight(chat-search) { background-color: hsl(var(--primary) / 0.3); color: inherit; }
|
|
@@ -8378,13 +8643,13 @@ function SearchOverlay() {
|
|
|
8378
8643
|
const setQuery = useUIStore((s) => s.setSearchQuery);
|
|
8379
8644
|
const messages = useChatStore((s) => s.messages);
|
|
8380
8645
|
const requestScrollToMessage = useUIStore((s) => s.requestScrollToMessage);
|
|
8381
|
-
const inputRef =
|
|
8646
|
+
const inputRef = useRef13(null);
|
|
8382
8647
|
const [activeHit, setActiveHit] = useState21(0);
|
|
8383
8648
|
const [repaintNonce, setRepaintNonce] = useState21(0);
|
|
8384
|
-
|
|
8649
|
+
useEffect17(() => {
|
|
8385
8650
|
if (open) requestAnimationFrame(() => inputRef.current?.focus());
|
|
8386
8651
|
}, [open]);
|
|
8387
|
-
|
|
8652
|
+
useEffect17(() => {
|
|
8388
8653
|
const style = document.createElement("style");
|
|
8389
8654
|
style.textContent = HIGHLIGHT_STYLES;
|
|
8390
8655
|
document.head.appendChild(style);
|
|
@@ -8392,7 +8657,7 @@ function SearchOverlay() {
|
|
|
8392
8657
|
document.head.removeChild(style);
|
|
8393
8658
|
};
|
|
8394
8659
|
}, []);
|
|
8395
|
-
const hits =
|
|
8660
|
+
const hits = useMemo6(() => {
|
|
8396
8661
|
const q = query.trim().toLowerCase();
|
|
8397
8662
|
if (!q) return [];
|
|
8398
8663
|
return messages.filter((m) => {
|
|
@@ -8402,10 +8667,10 @@ function SearchOverlay() {
|
|
|
8402
8667
|
return m.content.toLowerCase().includes(q);
|
|
8403
8668
|
}).map((m) => m.id);
|
|
8404
8669
|
}, [messages, query]);
|
|
8405
|
-
|
|
8670
|
+
useEffect17(() => {
|
|
8406
8671
|
if (activeHit >= hits.length) setActiveHit(0);
|
|
8407
8672
|
}, [hits, activeHit]);
|
|
8408
|
-
|
|
8673
|
+
useEffect17(() => {
|
|
8409
8674
|
const win = window;
|
|
8410
8675
|
const highlights = win.CSS?.highlights;
|
|
8411
8676
|
const HighlightCtor = win.Highlight;
|
|
@@ -8459,7 +8724,7 @@ function SearchOverlay() {
|
|
|
8459
8724
|
}
|
|
8460
8725
|
return clear;
|
|
8461
8726
|
}, [query, hits, activeHit, open, repaintNonce]);
|
|
8462
|
-
|
|
8727
|
+
useEffect17(() => {
|
|
8463
8728
|
const id = hits[activeHit];
|
|
8464
8729
|
if (!id) return;
|
|
8465
8730
|
requestScrollToMessage(id);
|
|
@@ -8618,7 +8883,7 @@ import {
|
|
|
8618
8883
|
Sparkles as Sparkles3,
|
|
8619
8884
|
Zap as Zap3
|
|
8620
8885
|
} from "lucide-react";
|
|
8621
|
-
import { useEffect as
|
|
8886
|
+
import { useEffect as useEffect18, useState as useState23 } from "react";
|
|
8622
8887
|
import { Fragment as Fragment7, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
8623
8888
|
var CARDS = [
|
|
8624
8889
|
{
|
|
@@ -8694,7 +8959,7 @@ function WelcomeScreen() {
|
|
|
8694
8959
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
8695
8960
|
const setCurrentView = useUIStore((s) => s.setCurrentView);
|
|
8696
8961
|
const [savedCount, setSavedCount] = useState23(void 0);
|
|
8697
|
-
|
|
8962
|
+
useEffect18(() => {
|
|
8698
8963
|
if (!wsConnected) return;
|
|
8699
8964
|
const client2 = getWSClient(wsUrl);
|
|
8700
8965
|
const off = client2.on("providers.saved", (msg) => {
|
|
@@ -8710,7 +8975,7 @@ function WelcomeScreen() {
|
|
|
8710
8975
|
const recentPrompts = promptHistory.slice(0, 6);
|
|
8711
8976
|
const { listSessions, resumeSession } = useWebSocket();
|
|
8712
8977
|
const historyEntries = useHistoryStore((s) => s.entries);
|
|
8713
|
-
|
|
8978
|
+
useEffect18(() => {
|
|
8714
8979
|
if (wsConnected && historyEntries.length === 0) listSessions(10);
|
|
8715
8980
|
}, [wsConnected]);
|
|
8716
8981
|
const sessionNicknames = useUIStore((s) => s.sessionNicknames);
|
|
@@ -8958,8 +9223,8 @@ function ChatView() {
|
|
|
8958
9223
|
const [titleDraft, setTitleDraft] = useState24("");
|
|
8959
9224
|
const historyEntries = useHistoryStore((s) => s.entries);
|
|
8960
9225
|
const [switcherOpen, setSwitcherOpen] = useState24(false);
|
|
8961
|
-
const switcherRef =
|
|
8962
|
-
|
|
9226
|
+
const switcherRef = useRef14(null);
|
|
9227
|
+
useEffect19(() => {
|
|
8963
9228
|
if (!switcherOpen) return;
|
|
8964
9229
|
const onClick = (e) => {
|
|
8965
9230
|
if (!switcherRef.current?.contains(e.target)) setSwitcherOpen(false);
|
|
@@ -8975,11 +9240,11 @@ function ChatView() {
|
|
|
8975
9240
|
};
|
|
8976
9241
|
}, [switcherOpen]);
|
|
8977
9242
|
const { provider, model } = useConfigStore();
|
|
8978
|
-
const vlistRef =
|
|
8979
|
-
const rows =
|
|
8980
|
-
const childCountRef =
|
|
9243
|
+
const vlistRef = useRef14(null);
|
|
9244
|
+
const rows = useMemo7(() => buildChatRows(messages), [messages]);
|
|
9245
|
+
const childCountRef = useRef14(0);
|
|
8981
9246
|
childCountRef.current = rows.length + 1;
|
|
8982
|
-
const rowIndexById =
|
|
9247
|
+
const rowIndexById = useMemo7(() => {
|
|
8983
9248
|
const map = /* @__PURE__ */ new Map();
|
|
8984
9249
|
rows.forEach((row, i) => {
|
|
8985
9250
|
if (row.kind === "user") map.set(row.message.id, i);
|
|
@@ -8994,7 +9259,7 @@ function ChatView() {
|
|
|
8994
9259
|
}, [rows]);
|
|
8995
9260
|
const scrollTarget = useUIStore((s) => s.scrollTarget);
|
|
8996
9261
|
const autonomy = useLocalPrefs((s) => s.autonomy);
|
|
8997
|
-
const handleAutonomyChange =
|
|
9262
|
+
const handleAutonomyChange = useCallback10((mode) => {
|
|
8998
9263
|
useLocalPrefs.getState().set({ autonomy: mode });
|
|
8999
9264
|
const ws = getWSClient();
|
|
9000
9265
|
ws?.send?.({ type: "autonomy.switch", payload: { mode } });
|
|
@@ -9002,7 +9267,7 @@ function ChatView() {
|
|
|
9002
9267
|
const [processOpen, setProcessOpen] = useState24(false);
|
|
9003
9268
|
const [checkpointOpen, setCheckpointOpen] = useState24(false);
|
|
9004
9269
|
const [breakdownOpen, setBreakdownOpen] = useState24(false);
|
|
9005
|
-
|
|
9270
|
+
useEffect19(() => {
|
|
9006
9271
|
const handler = () => setBreakdownOpen(true);
|
|
9007
9272
|
document.addEventListener("open:context-breakdown", handler);
|
|
9008
9273
|
return () => document.removeEventListener("open:context-breakdown", handler);
|
|
@@ -9012,8 +9277,8 @@ function ChatView() {
|
|
|
9012
9277
|
const [pinnedToBottom, setPinnedToBottom] = useState24(true);
|
|
9013
9278
|
const [unreadCount, setUnreadCount] = useState24(0);
|
|
9014
9279
|
const [scrolledDeep, setScrolledDeep] = useState24(false);
|
|
9015
|
-
const lastSeenCount =
|
|
9016
|
-
const handleScroll =
|
|
9280
|
+
const lastSeenCount = useRef14(messages.length);
|
|
9281
|
+
const handleScroll = useCallback10(() => {
|
|
9017
9282
|
const h = vlistRef.current;
|
|
9018
9283
|
if (!h) return;
|
|
9019
9284
|
const dist = h.scrollSize - h.scrollOffset - h.viewportSize;
|
|
@@ -9025,7 +9290,7 @@ function ChatView() {
|
|
|
9025
9290
|
}
|
|
9026
9291
|
setScrolledDeep(h.scrollOffset > h.viewportSize && h.scrollSize > h.viewportSize * 2.5);
|
|
9027
9292
|
}, []);
|
|
9028
|
-
const handleHistorySelect =
|
|
9293
|
+
const handleHistorySelect = useCallback10(
|
|
9029
9294
|
(sessionId2) => {
|
|
9030
9295
|
const ws = getWSClient();
|
|
9031
9296
|
ws?.resumeSession?.(sessionId2);
|
|
@@ -9033,7 +9298,7 @@ function ChatView() {
|
|
|
9033
9298
|
},
|
|
9034
9299
|
[]
|
|
9035
9300
|
);
|
|
9036
|
-
|
|
9301
|
+
useEffect19(() => {
|
|
9037
9302
|
const h = vlistRef.current;
|
|
9038
9303
|
if (!h) return;
|
|
9039
9304
|
if (pinnedToBottom) {
|
|
@@ -9044,7 +9309,7 @@ function ChatView() {
|
|
|
9044
9309
|
if (delta > 0) setUnreadCount(delta);
|
|
9045
9310
|
}
|
|
9046
9311
|
}, [messages, pinnedToBottom]);
|
|
9047
|
-
|
|
9312
|
+
useEffect19(() => {
|
|
9048
9313
|
setPinnedToBottom(true);
|
|
9049
9314
|
setUnreadCount(0);
|
|
9050
9315
|
lastSeenCount.current = useChatStore.getState().messages.length;
|
|
@@ -9052,25 +9317,25 @@ function ChatView() {
|
|
|
9052
9317
|
vlistRef.current?.scrollToIndex(childCountRef.current - 1, { align: "end" });
|
|
9053
9318
|
});
|
|
9054
9319
|
}, [sessionId]);
|
|
9055
|
-
|
|
9320
|
+
useEffect19(() => {
|
|
9056
9321
|
if (!scrollTarget) return;
|
|
9057
9322
|
const idx = rowIndexById.get(scrollTarget.id);
|
|
9058
9323
|
if (idx === void 0) return;
|
|
9059
9324
|
vlistRef.current?.scrollToIndex(idx, { align: "center", smooth: true });
|
|
9060
9325
|
}, [scrollTarget, rowIndexById]);
|
|
9061
|
-
const scrollToBottom =
|
|
9326
|
+
const scrollToBottom = useCallback10(() => {
|
|
9062
9327
|
vlistRef.current?.scrollToIndex(childCountRef.current - 1, { align: "end", smooth: true });
|
|
9063
9328
|
setPinnedToBottom(true);
|
|
9064
9329
|
setUnreadCount(0);
|
|
9065
9330
|
lastSeenCount.current = useChatStore.getState().messages.length;
|
|
9066
9331
|
}, []);
|
|
9067
|
-
const scrollToTop =
|
|
9332
|
+
const scrollToTop = useCallback10(() => {
|
|
9068
9333
|
vlistRef.current?.scrollToIndex(0, { align: "start", smooth: true });
|
|
9069
9334
|
}, []);
|
|
9070
9335
|
const [runStartedAt, setRunStartedAt] = useState24(null);
|
|
9071
9336
|
const [nowTick, setNowTick] = useState24(() => Date.now());
|
|
9072
|
-
const streamAnchor =
|
|
9073
|
-
const runningStatus =
|
|
9337
|
+
const streamAnchor = useRef14(null);
|
|
9338
|
+
const runningStatus = useMemo7(() => {
|
|
9074
9339
|
const last = messages[messages.length - 1];
|
|
9075
9340
|
const runningTools = messages.filter((m) => m.role === "tool" && m.toolResult === void 0);
|
|
9076
9341
|
let label = "Thinking\u2026";
|
|
@@ -9105,11 +9370,11 @@ function ChatView() {
|
|
|
9105
9370
|
}
|
|
9106
9371
|
return { label, elapsed, speedLabel };
|
|
9107
9372
|
}, [messages, nowTick, runStartedAt]);
|
|
9108
|
-
|
|
9373
|
+
useEffect19(() => {
|
|
9109
9374
|
if (isLoading && runStartedAt === null) setRunStartedAt(Date.now());
|
|
9110
9375
|
if (!isLoading && runStartedAt !== null) setRunStartedAt(null);
|
|
9111
9376
|
}, [isLoading, runStartedAt]);
|
|
9112
|
-
|
|
9377
|
+
useEffect19(() => {
|
|
9113
9378
|
if (!isLoading) return;
|
|
9114
9379
|
const t = setInterval(() => setNowTick(Date.now()), 500);
|
|
9115
9380
|
return () => clearInterval(t);
|
|
@@ -9495,7 +9760,7 @@ function ChatView() {
|
|
|
9495
9760
|
|
|
9496
9761
|
// src/components/CodeEditor.tsx
|
|
9497
9762
|
import { X as X8, Circle as Circle3 } from "lucide-react";
|
|
9498
|
-
import { useCallback as
|
|
9763
|
+
import { useCallback as useCallback11, useEffect as useEffect20, useMemo as useMemo8, useRef as useRef15 } from "react";
|
|
9499
9764
|
import Editor, { loader } from "@monaco-editor/react";
|
|
9500
9765
|
import * as monaco2 from "monaco-editor";
|
|
9501
9766
|
|
|
@@ -9941,22 +10206,22 @@ function CodeEditor() {
|
|
|
9941
10206
|
const activeFilePath = useFileStore((s) => s.activeFilePath);
|
|
9942
10207
|
const updateContent = useFileStore((s) => s.updateContent);
|
|
9943
10208
|
const { theme: appTheme } = useTheme();
|
|
9944
|
-
const editorRef =
|
|
9945
|
-
const activeFile =
|
|
10209
|
+
const editorRef = useRef15(null);
|
|
10210
|
+
const activeFile = useMemo8(
|
|
9946
10211
|
() => openFiles.find((f) => f.path === activeFilePath) ?? null,
|
|
9947
10212
|
[openFiles, activeFilePath]
|
|
9948
10213
|
);
|
|
9949
10214
|
const language = activeFilePath ? getLanguage(activeFilePath) : "plaintext";
|
|
9950
10215
|
const monacoTheme = getMonacoTheme();
|
|
9951
|
-
|
|
10216
|
+
useEffect20(() => {
|
|
9952
10217
|
const resolved = getMonacoTheme();
|
|
9953
10218
|
monaco2.editor.setTheme(resolved);
|
|
9954
10219
|
}, [appTheme]);
|
|
9955
|
-
const handleMount =
|
|
10220
|
+
const handleMount = useCallback11((editor3) => {
|
|
9956
10221
|
editorRef.current = editor3;
|
|
9957
10222
|
monaco2.editor.setTheme(getMonacoTheme());
|
|
9958
10223
|
}, []);
|
|
9959
|
-
const handleChange =
|
|
10224
|
+
const handleChange = useCallback11(
|
|
9960
10225
|
(value) => {
|
|
9961
10226
|
if (activeFilePath && value !== void 0) {
|
|
9962
10227
|
updateContent(activeFilePath, value);
|
|
@@ -9964,7 +10229,7 @@ function CodeEditor() {
|
|
|
9964
10229
|
},
|
|
9965
10230
|
[activeFilePath, updateContent]
|
|
9966
10231
|
);
|
|
9967
|
-
|
|
10232
|
+
useEffect20(() => {
|
|
9968
10233
|
const onKeyDown = (e) => {
|
|
9969
10234
|
const mod = e.ctrlKey || e.metaKey;
|
|
9970
10235
|
const tag = e.target?.tagName?.toLowerCase();
|
|
@@ -10030,7 +10295,7 @@ function CodeEditor() {
|
|
|
10030
10295
|
|
|
10031
10296
|
// src/components/ConfirmDialog.tsx
|
|
10032
10297
|
import { AlertTriangle as AlertTriangle3, FileEdit, Globe as Globe2, ShieldAlert, Terminal as Terminal5, Wrench as Wrench4 } from "lucide-react";
|
|
10033
|
-
import { useEffect as
|
|
10298
|
+
import { useEffect as useEffect21, useRef as useRef16 } from "react";
|
|
10034
10299
|
|
|
10035
10300
|
// src/components/ui/dialog.tsx
|
|
10036
10301
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
@@ -10159,14 +10424,14 @@ function SmartInputPreview({
|
|
|
10159
10424
|
function ConfirmDialog() {
|
|
10160
10425
|
const { showConfirmDialog, confirmInfo, hideConfirm } = useUIStore();
|
|
10161
10426
|
const { sendConfirm } = useWebSocket();
|
|
10162
|
-
const dialogRef =
|
|
10427
|
+
const dialogRef = useRef16(null);
|
|
10163
10428
|
const handleConfirm = (decision) => {
|
|
10164
10429
|
if (confirmInfo) {
|
|
10165
10430
|
sendConfirm(confirmInfo.id, decision);
|
|
10166
10431
|
}
|
|
10167
10432
|
hideConfirm();
|
|
10168
10433
|
};
|
|
10169
|
-
|
|
10434
|
+
useEffect21(() => {
|
|
10170
10435
|
if (!showConfirmDialog) return;
|
|
10171
10436
|
const onKey = (e) => {
|
|
10172
10437
|
const target = e.target;
|
|
@@ -10290,10 +10555,10 @@ function ConfirmDialog() {
|
|
|
10290
10555
|
}
|
|
10291
10556
|
|
|
10292
10557
|
// src/components/ConfirmModal.tsx
|
|
10293
|
-
import { useEffect as
|
|
10294
|
-
import { create as
|
|
10558
|
+
import { useEffect as useEffect22 } from "react";
|
|
10559
|
+
import { create as create16 } from "zustand";
|
|
10295
10560
|
import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
10296
|
-
var useConfirmModalStore =
|
|
10561
|
+
var useConfirmModalStore = create16()((set, get) => ({
|
|
10297
10562
|
request: null,
|
|
10298
10563
|
open: (request) => {
|
|
10299
10564
|
get().request?.resolve(false);
|
|
@@ -10312,7 +10577,7 @@ function confirmModal(options) {
|
|
|
10312
10577
|
function ConfirmModalHost() {
|
|
10313
10578
|
const request = useConfirmModalStore((s) => s.request);
|
|
10314
10579
|
const settle = useConfirmModalStore((s) => s.settle);
|
|
10315
|
-
|
|
10580
|
+
useEffect22(() => {
|
|
10316
10581
|
if (!request) return;
|
|
10317
10582
|
const onKey = (e) => {
|
|
10318
10583
|
if (e.key === "Enter") {
|
|
@@ -10355,19 +10620,19 @@ function ConfirmModalHost() {
|
|
|
10355
10620
|
|
|
10356
10621
|
// src/components/ConnectionBanner.tsx
|
|
10357
10622
|
import { Loader2 as Loader22, RotateCcw as RotateCcw4, WifiOff, X as X10 } from "lucide-react";
|
|
10358
|
-
import { useEffect as
|
|
10623
|
+
import { useEffect as useEffect23, useState as useState25 } from "react";
|
|
10359
10624
|
import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
10360
10625
|
function ConnectionBanner() {
|
|
10361
10626
|
const wsStatus = useConfigStore((s) => s.wsStatus);
|
|
10362
10627
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
10363
10628
|
const [dismissed, setDismissed] = useState25(false);
|
|
10364
10629
|
const [now, setNow] = useState25(Date.now());
|
|
10365
|
-
|
|
10630
|
+
useEffect23(() => {
|
|
10366
10631
|
if (wsStatus.state !== "reconnecting") return;
|
|
10367
10632
|
const id = setInterval(() => setNow(Date.now()), 500);
|
|
10368
10633
|
return () => clearInterval(id);
|
|
10369
10634
|
}, [wsStatus.state]);
|
|
10370
|
-
|
|
10635
|
+
useEffect23(() => {
|
|
10371
10636
|
if (wsStatus.state === "open") setDismissed(false);
|
|
10372
10637
|
}, [wsStatus.state]);
|
|
10373
10638
|
if (wsStatus.state === "open" || wsStatus.state === "connecting") return null;
|
|
@@ -10459,7 +10724,7 @@ var ErrorBoundary = class extends Component {
|
|
|
10459
10724
|
|
|
10460
10725
|
// src/components/QuickModelSwitcher.tsx
|
|
10461
10726
|
import { ArrowRight as ArrowRight3, Cpu as Cpu5, Search as Search4 } from "lucide-react";
|
|
10462
|
-
import { useEffect as
|
|
10727
|
+
import { useEffect as useEffect24, useMemo as useMemo9, useRef as useRef17, useState as useState26 } from "react";
|
|
10463
10728
|
|
|
10464
10729
|
// src/components/QuickModelSwitcher.filter.ts
|
|
10465
10730
|
function buildModelCandidates(saved, modelsByProvider, query, currentProvider, currentModel) {
|
|
@@ -10495,13 +10760,13 @@ function QuickModelSwitcher() {
|
|
|
10495
10760
|
const [selected, setSelected] = useState26(0);
|
|
10496
10761
|
const [saved, setSaved] = useState26([]);
|
|
10497
10762
|
const [modelsByProvider, setModelsByProvider] = useState26({});
|
|
10498
|
-
const inputRef =
|
|
10763
|
+
const inputRef = useRef17(null);
|
|
10499
10764
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
10500
10765
|
const currentProvider = useConfigStore((s) => s.provider);
|
|
10501
10766
|
const currentModel = useConfigStore((s) => s.model);
|
|
10502
10767
|
const paletteOpen = useUIStore((s) => s.paletteOpen);
|
|
10503
10768
|
const { listSavedProviders, listProviderModels, switchModel } = useWebSocket();
|
|
10504
|
-
|
|
10769
|
+
useEffect24(() => {
|
|
10505
10770
|
const onKey = (e) => {
|
|
10506
10771
|
const mod = e.ctrlKey || e.metaKey;
|
|
10507
10772
|
if (mod && e.key.toLowerCase() === "m" && !e.shiftKey && !e.altKey) {
|
|
@@ -10518,7 +10783,7 @@ function QuickModelSwitcher() {
|
|
|
10518
10783
|
window.addEventListener("keydown", onKey);
|
|
10519
10784
|
return () => window.removeEventListener("keydown", onKey);
|
|
10520
10785
|
}, [open, paletteOpen]);
|
|
10521
|
-
|
|
10786
|
+
useEffect24(() => {
|
|
10522
10787
|
const client2 = getWSClient(wsUrl);
|
|
10523
10788
|
const offSaved = client2.on("providers.saved", (msg) => {
|
|
10524
10789
|
const p = msg.payload;
|
|
@@ -10533,14 +10798,14 @@ function QuickModelSwitcher() {
|
|
|
10533
10798
|
offModels();
|
|
10534
10799
|
};
|
|
10535
10800
|
}, [wsUrl]);
|
|
10536
|
-
|
|
10801
|
+
useEffect24(() => {
|
|
10537
10802
|
if (!open) return;
|
|
10538
10803
|
setQuery("");
|
|
10539
10804
|
setSelected(0);
|
|
10540
10805
|
listSavedProviders();
|
|
10541
10806
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
10542
10807
|
}, [open, listSavedProviders]);
|
|
10543
|
-
|
|
10808
|
+
useEffect24(() => {
|
|
10544
10809
|
if (!open) return;
|
|
10545
10810
|
for (const sp of saved) {
|
|
10546
10811
|
if (!modelsByProvider[sp.id]) {
|
|
@@ -10548,7 +10813,7 @@ function QuickModelSwitcher() {
|
|
|
10548
10813
|
}
|
|
10549
10814
|
}
|
|
10550
10815
|
}, [open, saved, modelsByProvider, listProviderModels]);
|
|
10551
|
-
const candidates =
|
|
10816
|
+
const candidates = useMemo9(
|
|
10552
10817
|
() => buildModelCandidates(
|
|
10553
10818
|
saved,
|
|
10554
10819
|
modelsByProvider,
|
|
@@ -10558,7 +10823,7 @@ function QuickModelSwitcher() {
|
|
|
10558
10823
|
),
|
|
10559
10824
|
[saved, modelsByProvider, query, currentProvider, currentModel]
|
|
10560
10825
|
);
|
|
10561
|
-
|
|
10826
|
+
useEffect24(() => {
|
|
10562
10827
|
if (selected >= candidates.length) setSelected(0);
|
|
10563
10828
|
}, [candidates.length, selected]);
|
|
10564
10829
|
const commit = (idx) => {
|
|
@@ -10666,12 +10931,13 @@ import {
|
|
|
10666
10931
|
Network,
|
|
10667
10932
|
Palette,
|
|
10668
10933
|
Puzzle,
|
|
10934
|
+
Send as Send2,
|
|
10669
10935
|
Shield as Shield2,
|
|
10670
10936
|
Sun as Sun3,
|
|
10671
10937
|
X as X11,
|
|
10672
10938
|
Zap as Zap5
|
|
10673
10939
|
} from "lucide-react";
|
|
10674
|
-
import { useState as useState28, useEffect as
|
|
10940
|
+
import { useState as useState28, useEffect as useEffect25, useCallback as useCallback13 } from "react";
|
|
10675
10941
|
|
|
10676
10942
|
// src/components/ui/input.tsx
|
|
10677
10943
|
import * as React3 from "react";
|
|
@@ -10900,7 +11166,7 @@ import {
|
|
|
10900
11166
|
Plus,
|
|
10901
11167
|
Trash2 as Trash22
|
|
10902
11168
|
} from "lucide-react";
|
|
10903
|
-
import { useState as useState27, useCallback as
|
|
11169
|
+
import { useState as useState27, useCallback as useCallback12 } from "react";
|
|
10904
11170
|
import { Fragment as Fragment9, jsx as jsx47, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
10905
11171
|
var PROVIDER_FAMILIES = ["anthropic", "openai", "google", "openai-compatible"];
|
|
10906
11172
|
function ProviderSection({
|
|
@@ -10929,7 +11195,7 @@ function ProviderSection({
|
|
|
10929
11195
|
const [newProviderFamily, setNewProviderFamily] = useState27("openai-compatible");
|
|
10930
11196
|
const [newProviderBaseUrl, setNewProviderBaseUrl] = useState27("");
|
|
10931
11197
|
const [newProviderApiKey, setNewProviderApiKey] = useState27("");
|
|
10932
|
-
const handleAddKey =
|
|
11198
|
+
const handleAddKey = useCallback12(
|
|
10933
11199
|
(providerId) => {
|
|
10934
11200
|
if (!newKeyLabel.trim() || !newKeyValue.trim()) return;
|
|
10935
11201
|
onAddKey(providerId, newKeyLabel.trim(), newKeyValue.trim());
|
|
@@ -10939,7 +11205,7 @@ function ProviderSection({
|
|
|
10939
11205
|
},
|
|
10940
11206
|
[onAddKey, newKeyLabel, newKeyValue]
|
|
10941
11207
|
);
|
|
10942
|
-
const handleAddProvider =
|
|
11208
|
+
const handleAddProvider = useCallback12(() => {
|
|
10943
11209
|
if (!newProviderId.trim()) return;
|
|
10944
11210
|
onAddProvider(newProviderId.trim(), newProviderFamily, newProviderBaseUrl || void 0, newProviderApiKey || void 0);
|
|
10945
11211
|
setNewProviderId("");
|
|
@@ -11296,7 +11562,7 @@ function ModelSection({
|
|
|
11296
11562
|
}
|
|
11297
11563
|
|
|
11298
11564
|
// src/components/SettingsPanel/index.tsx
|
|
11299
|
-
import { jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
11565
|
+
import { Fragment as Fragment11, jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
11300
11566
|
function SettingsPanel() {
|
|
11301
11567
|
const { setCurrentView } = useUIStore();
|
|
11302
11568
|
const { provider, model, setProvider, setModel, wsConnected } = useConfigStore();
|
|
@@ -11305,7 +11571,7 @@ function SettingsPanel() {
|
|
|
11305
11571
|
const wsClient = ws.client;
|
|
11306
11572
|
const { updatePrefs, switchAutonomy } = ws;
|
|
11307
11573
|
const localPrefs = useLocalPrefs();
|
|
11308
|
-
const syncPref =
|
|
11574
|
+
const syncPref = useCallback13(
|
|
11309
11575
|
(key, value) => {
|
|
11310
11576
|
localPrefs.set({ [key]: value });
|
|
11311
11577
|
updatePrefs({ [key]: value });
|
|
@@ -11321,7 +11587,7 @@ function SettingsPanel() {
|
|
|
11321
11587
|
const [providerTab, setProviderTab] = useState28("catalog");
|
|
11322
11588
|
const [catalogQuery, setCatalogQuery] = useState28("");
|
|
11323
11589
|
const currentCatalogProvider = catalogProviders.find((p) => p.id === provider);
|
|
11324
|
-
|
|
11590
|
+
useEffect25(() => {
|
|
11325
11591
|
const handleProviderCatalog = (msg) => {
|
|
11326
11592
|
if (msg.type === "provider.catalog") {
|
|
11327
11593
|
const payload = msg.payload;
|
|
@@ -11359,7 +11625,7 @@ function SettingsPanel() {
|
|
|
11359
11625
|
off3?.();
|
|
11360
11626
|
};
|
|
11361
11627
|
}, [wsConnected, wsClient]);
|
|
11362
|
-
const handleProviderSelect =
|
|
11628
|
+
const handleProviderSelect = useCallback13(
|
|
11363
11629
|
(providerId) => {
|
|
11364
11630
|
setProvider(providerId);
|
|
11365
11631
|
if (!catalogModels[providerId]) {
|
|
@@ -11369,7 +11635,7 @@ function SettingsPanel() {
|
|
|
11369
11635
|
},
|
|
11370
11636
|
[catalogModels, setProvider, ws]
|
|
11371
11637
|
);
|
|
11372
|
-
const handleModelSelect =
|
|
11638
|
+
const handleModelSelect = useCallback13(
|
|
11373
11639
|
(modelId) => {
|
|
11374
11640
|
setModel(modelId);
|
|
11375
11641
|
const currentProvider = useConfigStore.getState().provider;
|
|
@@ -11378,31 +11644,31 @@ function SettingsPanel() {
|
|
|
11378
11644
|
},
|
|
11379
11645
|
[setModel, ws]
|
|
11380
11646
|
);
|
|
11381
|
-
const handleAddKey =
|
|
11647
|
+
const handleAddKey = useCallback13(
|
|
11382
11648
|
(providerId, label, value) => {
|
|
11383
11649
|
ws.addKey?.(providerId, label, value);
|
|
11384
11650
|
},
|
|
11385
11651
|
[ws]
|
|
11386
11652
|
);
|
|
11387
|
-
const handleDeleteKey =
|
|
11653
|
+
const handleDeleteKey = useCallback13(
|
|
11388
11654
|
(providerId, label) => {
|
|
11389
11655
|
ws.deleteKey?.(providerId, label);
|
|
11390
11656
|
},
|
|
11391
11657
|
[ws]
|
|
11392
11658
|
);
|
|
11393
|
-
const handleSetActiveKey =
|
|
11659
|
+
const handleSetActiveKey = useCallback13(
|
|
11394
11660
|
(providerId, label) => {
|
|
11395
11661
|
ws.setActiveKey?.(providerId, label);
|
|
11396
11662
|
},
|
|
11397
11663
|
[ws]
|
|
11398
11664
|
);
|
|
11399
|
-
const handleAddProvider =
|
|
11665
|
+
const handleAddProvider = useCallback13(
|
|
11400
11666
|
(id, family, baseUrl, apiKey) => {
|
|
11401
11667
|
ws.addProvider?.(id, family, baseUrl, apiKey);
|
|
11402
11668
|
},
|
|
11403
11669
|
[ws]
|
|
11404
11670
|
);
|
|
11405
|
-
const handleRemoveProvider =
|
|
11671
|
+
const handleRemoveProvider = useCallback13(
|
|
11406
11672
|
(providerId) => {
|
|
11407
11673
|
ws.removeProvider?.(providerId);
|
|
11408
11674
|
},
|
|
@@ -11742,6 +12008,47 @@ function SettingsPanel() {
|
|
|
11742
12008
|
onChange: () => syncPref("nextPrediction", !localPrefs.nextPrediction)
|
|
11743
12009
|
}
|
|
11744
12010
|
)
|
|
12011
|
+
] }),
|
|
12012
|
+
/* @__PURE__ */ jsxs45("div", { className: "pt-2 border-t", children: [
|
|
12013
|
+
/* @__PURE__ */ jsxs45("h3", { className: "text-sm font-semibold mb-3 mt-3 flex items-center gap-2", children: [
|
|
12014
|
+
/* @__PURE__ */ jsx49(Send2, { className: "h-4 w-4 text-muted-foreground" }),
|
|
12015
|
+
"Telegram Notifications"
|
|
12016
|
+
] }),
|
|
12017
|
+
localPrefs.tgConfigured ? /* @__PURE__ */ jsxs45(Fragment11, { children: [
|
|
12018
|
+
/* @__PURE__ */ jsx49(
|
|
12019
|
+
PreferenceToggle,
|
|
12020
|
+
{
|
|
12021
|
+
label: "Session end",
|
|
12022
|
+
hint: "Send a summary when a session ends.",
|
|
12023
|
+
value: localPrefs.tgSessionEnd,
|
|
12024
|
+
onChange: () => syncPref("tgSessionEnd", !localPrefs.tgSessionEnd)
|
|
12025
|
+
}
|
|
12026
|
+
),
|
|
12027
|
+
/* @__PURE__ */ jsx49(
|
|
12028
|
+
PreferenceToggle,
|
|
12029
|
+
{
|
|
12030
|
+
label: "Delegate finished",
|
|
12031
|
+
hint: "Send a humanized note when a subagent completes.",
|
|
12032
|
+
value: localPrefs.tgDelegate,
|
|
12033
|
+
onChange: () => syncPref("tgDelegate", !localPrefs.tgDelegate)
|
|
12034
|
+
}
|
|
12035
|
+
),
|
|
12036
|
+
/* @__PURE__ */ jsx49(
|
|
12037
|
+
PreferenceToggle,
|
|
12038
|
+
{
|
|
12039
|
+
label: "Long-running tools",
|
|
12040
|
+
hint: `Notify when a tool exceeds ${localPrefs.tgLongToolMs}ms. Set 0 to disable.`,
|
|
12041
|
+
value: localPrefs.tgLongToolMs > 0,
|
|
12042
|
+
onChange: () => syncPref("tgLongToolMs", localPrefs.tgLongToolMs > 0 ? 0 : 3e4)
|
|
12043
|
+
}
|
|
12044
|
+
),
|
|
12045
|
+
/* @__PURE__ */ jsx49("p", { className: "text-xs text-muted-foreground mt-2", children: "Changes apply immediately." })
|
|
12046
|
+
] }) : /* @__PURE__ */ jsxs45("p", { className: "text-xs text-muted-foreground", children: [
|
|
12047
|
+
"Telegram is not configured. Run",
|
|
12048
|
+
" ",
|
|
12049
|
+
/* @__PURE__ */ jsx49("code", { className: "bg-muted px-1 py-0.5 rounded", children: "/telegram-setup" }),
|
|
12050
|
+
" in the CLI to connect a bot first."
|
|
12051
|
+
] })
|
|
11745
12052
|
] })
|
|
11746
12053
|
] }),
|
|
11747
12054
|
/* @__PURE__ */ jsxs45(TabsContent, { value: "features", className: "space-y-4", children: [
|
|
@@ -11880,7 +12187,7 @@ import {
|
|
|
11880
12187
|
Network as Network2,
|
|
11881
12188
|
Zap as Zap6
|
|
11882
12189
|
} from "lucide-react";
|
|
11883
|
-
import { useCallback as
|
|
12190
|
+
import { useCallback as useCallback14, useEffect as useEffect26, useState as useState29 } from "react";
|
|
11884
12191
|
import { jsx as jsx50, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
11885
12192
|
function ProviderCard({
|
|
11886
12193
|
provider,
|
|
@@ -12029,7 +12336,7 @@ function SetupScreen() {
|
|
|
12029
12336
|
const [isLoadingModels, setIsLoadingModels] = useState29(false);
|
|
12030
12337
|
const [selectedProvider, setSelectedProvider] = useState29(null);
|
|
12031
12338
|
const [selectedModel, setSelectedModel] = useState29(null);
|
|
12032
|
-
|
|
12339
|
+
useEffect26(() => {
|
|
12033
12340
|
if (!wsConnected) return;
|
|
12034
12341
|
const wsClient = getWSClient(wsUrl);
|
|
12035
12342
|
const off1 = wsClient.on("provider.catalog", (msg) => {
|
|
@@ -12071,7 +12378,7 @@ function SetupScreen() {
|
|
|
12071
12378
|
off3?.();
|
|
12072
12379
|
};
|
|
12073
12380
|
}, [wsConnected, wsUrl, provider, model]);
|
|
12074
|
-
|
|
12381
|
+
useEffect26(() => {
|
|
12075
12382
|
if (!selectedProvider || !wsConnected) return;
|
|
12076
12383
|
const wsClient = getWSClient(wsUrl);
|
|
12077
12384
|
if (!catalogModels[selectedProvider]) {
|
|
@@ -12082,12 +12389,12 @@ function SetupScreen() {
|
|
|
12082
12389
|
const selectedProviderData = catalogProviders.find((p) => p.id === selectedProvider);
|
|
12083
12390
|
const savedProviderData = savedProviders.find((p) => p.id === selectedProvider);
|
|
12084
12391
|
const hasActiveKey = savedProviderData?.apiKeys.some((k) => k.isActive) || selectedProviderData?.hasApiKey;
|
|
12085
|
-
const handleProviderSelect =
|
|
12392
|
+
const handleProviderSelect = useCallback14((providerId) => {
|
|
12086
12393
|
setSelectedProvider(providerId);
|
|
12087
12394
|
setSelectedModel(null);
|
|
12088
12395
|
setStep("model");
|
|
12089
12396
|
}, []);
|
|
12090
|
-
const handleModelSelect =
|
|
12397
|
+
const handleModelSelect = useCallback14(
|
|
12091
12398
|
(modelId) => {
|
|
12092
12399
|
setSelectedModel(modelId);
|
|
12093
12400
|
if (!hasActiveKey) {
|
|
@@ -12098,10 +12405,10 @@ function SetupScreen() {
|
|
|
12098
12405
|
},
|
|
12099
12406
|
[hasActiveKey]
|
|
12100
12407
|
);
|
|
12101
|
-
const handleApiKeySaved =
|
|
12408
|
+
const handleApiKeySaved = useCallback14(() => {
|
|
12102
12409
|
setStep("done");
|
|
12103
12410
|
}, []);
|
|
12104
|
-
const handleStartSession =
|
|
12411
|
+
const handleStartSession = useCallback14(() => {
|
|
12105
12412
|
if (!selectedProvider || !selectedModel) return;
|
|
12106
12413
|
setProvider(selectedProvider);
|
|
12107
12414
|
setModel(selectedModel);
|
|
@@ -12277,7 +12584,7 @@ function SetupScreen() {
|
|
|
12277
12584
|
|
|
12278
12585
|
// src/components/SessionsDashboard.tsx
|
|
12279
12586
|
import { Clock as Clock8, Cpu as Cpu9, FolderGit2, Wifi, WifiOff as WifiOff2, Loader2 as Loader26 } from "lucide-react";
|
|
12280
|
-
import { useCallback as
|
|
12587
|
+
import { useCallback as useCallback15, useEffect as useEffect27, useState as useState30 } from "react";
|
|
12281
12588
|
import { jsx as jsx51, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
12282
12589
|
function agentIcon(status) {
|
|
12283
12590
|
switch (status) {
|
|
@@ -12343,7 +12650,7 @@ function SessionsDashboard() {
|
|
|
12343
12650
|
const [sessions, setSessions] = useState30([]);
|
|
12344
12651
|
const [loading, setLoading] = useState30(true);
|
|
12345
12652
|
const [error, setError] = useState30(null);
|
|
12346
|
-
const fetchSessions =
|
|
12653
|
+
const fetchSessions = useCallback15(async () => {
|
|
12347
12654
|
try {
|
|
12348
12655
|
const res = await fetch("/api/sessions");
|
|
12349
12656
|
if (!res.ok) {
|
|
@@ -12363,7 +12670,7 @@ function SessionsDashboard() {
|
|
|
12363
12670
|
setLoading(false);
|
|
12364
12671
|
}
|
|
12365
12672
|
}, []);
|
|
12366
|
-
|
|
12673
|
+
useEffect27(() => {
|
|
12367
12674
|
void fetchSessions();
|
|
12368
12675
|
const t = setInterval(fetchSessions, 5e3);
|
|
12369
12676
|
return () => clearInterval(t);
|
|
@@ -12456,7 +12763,7 @@ function SessionsDashboard() {
|
|
|
12456
12763
|
|
|
12457
12764
|
// src/components/ShortcutsOverlay.tsx
|
|
12458
12765
|
import { Keyboard as Keyboard3, X as X12 } from "lucide-react";
|
|
12459
|
-
import { useEffect as
|
|
12766
|
+
import { useEffect as useEffect28 } from "react";
|
|
12460
12767
|
import { jsx as jsx52, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
12461
12768
|
var SHORTCUTS = [
|
|
12462
12769
|
{
|
|
@@ -12518,7 +12825,7 @@ var SHORTCUTS = [
|
|
|
12518
12825
|
function ShortcutsOverlay() {
|
|
12519
12826
|
const open = useUIStore((s) => s.shortcutsOpen);
|
|
12520
12827
|
const setOpen = useUIStore((s) => s.setShortcutsOpen);
|
|
12521
|
-
|
|
12828
|
+
useEffect28(() => {
|
|
12522
12829
|
const onKey = (e) => {
|
|
12523
12830
|
const target = e.target;
|
|
12524
12831
|
const tag = target?.tagName?.toLowerCase();
|
|
@@ -12612,7 +12919,7 @@ import {
|
|
|
12612
12919
|
ReactFlowProvider
|
|
12613
12920
|
} from "@xyflow/react";
|
|
12614
12921
|
import "@xyflow/react/dist/style.css";
|
|
12615
|
-
import { useCallback as
|
|
12922
|
+
import { useCallback as useCallback16, useEffect as useEffect29, useState as useState31 } from "react";
|
|
12616
12923
|
import {
|
|
12617
12924
|
Bot as Bot7,
|
|
12618
12925
|
Cpu as Cpu10,
|
|
@@ -12693,7 +13000,7 @@ function AgentFlowGraphCSS() {
|
|
|
12693
13000
|
}
|
|
12694
13001
|
|
|
12695
13002
|
// src/components/AgentFlowGraph/AgentFlowCanvas.tsx
|
|
12696
|
-
import { Fragment as
|
|
13003
|
+
import { Fragment as Fragment12, jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
12697
13004
|
var TOOL_ICONS = {
|
|
12698
13005
|
read: /* @__PURE__ */ jsx54(FileText3, { className: "h-3 w-3" }),
|
|
12699
13006
|
write: /* @__PURE__ */ jsx54(FileText3, { className: "h-3 w-3" }),
|
|
@@ -12820,7 +13127,7 @@ function ContextNode({ data }) {
|
|
|
12820
13127
|
/* @__PURE__ */ jsx54(Database2, { className: "h-3 w-3", style: { color: colors } }),
|
|
12821
13128
|
/* @__PURE__ */ jsx54("span", { className: "text-[10px] font-medium", style: { color: colors }, children: "Context" })
|
|
12822
13129
|
] }),
|
|
12823
|
-
data.stats?.ctxPct !== void 0 && /* @__PURE__ */ jsxs49(
|
|
13130
|
+
data.stats?.ctxPct !== void 0 && /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
12824
13131
|
/* @__PURE__ */ jsxs49("div", { className: "mt-1 text-[9px] text-center text-gray-400", children: [
|
|
12825
13132
|
data.stats.ctxPct,
|
|
12826
13133
|
"%"
|
|
@@ -12859,7 +13166,7 @@ function FlowEdge({
|
|
|
12859
13166
|
status: { icon: "\u{1F4CA}", bg: "bg-pink-500/20", text: "text-pink-400" }
|
|
12860
13167
|
};
|
|
12861
13168
|
const meta2 = flowMeta[flowType] || flowMeta.response;
|
|
12862
|
-
return /* @__PURE__ */ jsxs49(
|
|
13169
|
+
return /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
12863
13170
|
/* @__PURE__ */ jsx54(
|
|
12864
13171
|
"path",
|
|
12865
13172
|
{
|
|
@@ -12959,7 +13266,7 @@ function AgentFlowCanvas({ containerRef }) {
|
|
|
12959
13266
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
12960
13267
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
12961
13268
|
const [selectedNode, setSelectedNode] = useState31(null);
|
|
12962
|
-
|
|
13269
|
+
useEffect29(() => {
|
|
12963
13270
|
const rfNodes = [];
|
|
12964
13271
|
const rfEdges = [];
|
|
12965
13272
|
rfNodes.push({
|
|
@@ -13133,7 +13440,7 @@ function AgentFlowCanvas({ containerRef }) {
|
|
|
13133
13440
|
setEdges(rfEdges);
|
|
13134
13441
|
setTimeout(() => fitView({ padding: 0.2, duration: 300 }), 50);
|
|
13135
13442
|
}, [session, projectName, iteration, fleetAgents, cost, lastInputTokens, maxContext, setNodes, setEdges, fitView]);
|
|
13136
|
-
|
|
13443
|
+
useEffect29(() => {
|
|
13137
13444
|
if (vizEvents.length === 0) return;
|
|
13138
13445
|
const latestEvent = vizEvents[0];
|
|
13139
13446
|
if (!latestEvent) return;
|
|
@@ -13155,14 +13462,14 @@ function AgentFlowCanvas({ containerRef }) {
|
|
|
13155
13462
|
);
|
|
13156
13463
|
}
|
|
13157
13464
|
}, [vizEvents, setNodes]);
|
|
13158
|
-
const onConnect =
|
|
13465
|
+
const onConnect = useCallback16(
|
|
13159
13466
|
(params) => setEdges((eds) => addEdge({ ...params, type: "flow" }, eds)),
|
|
13160
13467
|
[setEdges]
|
|
13161
13468
|
);
|
|
13162
|
-
const onNodeClick =
|
|
13469
|
+
const onNodeClick = useCallback16((_, node) => {
|
|
13163
13470
|
setSelectedNode(node);
|
|
13164
13471
|
}, []);
|
|
13165
|
-
const onPaneClick =
|
|
13472
|
+
const onPaneClick = useCallback16(() => {
|
|
13166
13473
|
setSelectedNode(null);
|
|
13167
13474
|
}, []);
|
|
13168
13475
|
return /* @__PURE__ */ jsxs49("div", { className: "w-full h-full bg-background relative", children: [
|
|
@@ -13238,7 +13545,7 @@ function AgentFlowCanvas({ containerRef }) {
|
|
|
13238
13545
|
/* @__PURE__ */ jsx54("span", { className: "text-muted-foreground", children: "Tool" }),
|
|
13239
13546
|
/* @__PURE__ */ jsx54("span", { className: "font-mono text-amber-400", children: String(selectedNode.data.currentTool) })
|
|
13240
13547
|
] }),
|
|
13241
|
-
selectedNode.data.stats && /* @__PURE__ */ jsxs49(
|
|
13548
|
+
selectedNode.data.stats && /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
13242
13549
|
selectedNode.data.stats.iterations !== void 0 && /* @__PURE__ */ jsxs49("div", { className: "flex justify-between", children: [
|
|
13243
13550
|
/* @__PURE__ */ jsx54("span", { className: "text-muted-foreground", children: "Iterations" }),
|
|
13244
13551
|
/* @__PURE__ */ jsx54("span", { className: "font-mono", children: selectedNode.data.stats.iterations })
|
|
@@ -13339,7 +13646,7 @@ function AgentFlowCanvasWithProvider(props) {
|
|
|
13339
13646
|
|
|
13340
13647
|
// src/components/SidePanel/index.tsx
|
|
13341
13648
|
import { PanelLeftClose } from "lucide-react";
|
|
13342
|
-
import { useEffect as
|
|
13649
|
+
import { useEffect as useEffect36 } from "react";
|
|
13343
13650
|
|
|
13344
13651
|
// src/components/FileExplorer.tsx
|
|
13345
13652
|
import {
|
|
@@ -13360,7 +13667,7 @@ import {
|
|
|
13360
13667
|
Loader2 as Loader27,
|
|
13361
13668
|
Minimize2
|
|
13362
13669
|
} from "lucide-react";
|
|
13363
|
-
import { useCallback as
|
|
13670
|
+
import { useCallback as useCallback17, useEffect as useEffect30, useMemo as useMemo11, useRef as useRef19, useState as useState32 } from "react";
|
|
13364
13671
|
import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
13365
13672
|
var EXT_ICONS = {
|
|
13366
13673
|
// ── Code ──
|
|
@@ -13484,7 +13791,7 @@ function TreeNodeItem({
|
|
|
13484
13791
|
const [expanded, setExpanded] = useState32(depth < 1);
|
|
13485
13792
|
const activeFilePath = useFileStore((s) => s.activeFilePath);
|
|
13486
13793
|
const isActive = node.type === "file" && node.path === activeFilePath;
|
|
13487
|
-
|
|
13794
|
+
useEffect30(() => {
|
|
13488
13795
|
if (forceExpand !== null) setExpanded(forceExpand);
|
|
13489
13796
|
}, [forceExpand]);
|
|
13490
13797
|
if (node.type === "directory") {
|
|
@@ -13586,7 +13893,7 @@ function FileExplorer() {
|
|
|
13586
13893
|
const segments = cwd.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
13587
13894
|
return (segments[segments.length - 1] ?? "") === projectName;
|
|
13588
13895
|
})();
|
|
13589
|
-
const breadcrumbs =
|
|
13896
|
+
const breadcrumbs = useMemo11(() => {
|
|
13590
13897
|
if (!cwd || !projectName) return [];
|
|
13591
13898
|
const norm = cwd.replace(/\\/g, "/");
|
|
13592
13899
|
const segments = norm.split("/").filter(Boolean);
|
|
@@ -13612,18 +13919,18 @@ function FileExplorer() {
|
|
|
13612
13919
|
isLast: i === rel.length - 1
|
|
13613
13920
|
}));
|
|
13614
13921
|
}, [cwd, projectName]);
|
|
13615
|
-
const bcRef =
|
|
13616
|
-
|
|
13922
|
+
const bcRef = useRef19(null);
|
|
13923
|
+
useEffect30(() => {
|
|
13617
13924
|
const el = bcRef.current;
|
|
13618
13925
|
if (el && breadcrumbs.length > 1) {
|
|
13619
13926
|
el.scrollLeft = el.scrollWidth;
|
|
13620
13927
|
}
|
|
13621
13928
|
}, [breadcrumbs]);
|
|
13622
|
-
const handleBreadcrumbClick =
|
|
13929
|
+
const handleBreadcrumbClick = useCallback17((crumbPath) => {
|
|
13623
13930
|
getWSClient().send({ type: "working_dir.set", payload: { path: crumbPath } });
|
|
13624
13931
|
}, []);
|
|
13625
13932
|
const [contextMenu, setContextMenu] = useState32(null);
|
|
13626
|
-
|
|
13933
|
+
useEffect30(() => {
|
|
13627
13934
|
if (!contextMenu) return;
|
|
13628
13935
|
const close = () => setContextMenu(null);
|
|
13629
13936
|
const onKey = (e) => {
|
|
@@ -13636,7 +13943,7 @@ function FileExplorer() {
|
|
|
13636
13943
|
window.removeEventListener("keydown", onKey);
|
|
13637
13944
|
};
|
|
13638
13945
|
}, [contextMenu]);
|
|
13639
|
-
const handleBreadcrumbContext =
|
|
13946
|
+
const handleBreadcrumbContext = useCallback17(
|
|
13640
13947
|
(e, crumb) => {
|
|
13641
13948
|
e.preventDefault();
|
|
13642
13949
|
e.stopPropagation();
|
|
@@ -13644,29 +13951,29 @@ function FileExplorer() {
|
|
|
13644
13951
|
},
|
|
13645
13952
|
[]
|
|
13646
13953
|
);
|
|
13647
|
-
const copyToClipboard2 =
|
|
13954
|
+
const copyToClipboard2 = useCallback17((text) => {
|
|
13648
13955
|
void navigator.clipboard.writeText(text);
|
|
13649
13956
|
setContextMenu(null);
|
|
13650
13957
|
}, []);
|
|
13651
|
-
const handleFileIndicatorClick =
|
|
13958
|
+
const handleFileIndicatorClick = useCallback17(() => {
|
|
13652
13959
|
if (!activeFilePath) return;
|
|
13653
13960
|
const norm = activeFilePath.replace(/\\/g, "/");
|
|
13654
13961
|
const parent = norm.split("/").slice(0, -1).join("/") || ".";
|
|
13655
13962
|
getWSClient().send({ type: "working_dir.set", payload: { path: parent } });
|
|
13656
13963
|
}, [activeFilePath]);
|
|
13657
|
-
const handleShellOpen =
|
|
13964
|
+
const handleShellOpen = useCallback17((dirPath, target) => {
|
|
13658
13965
|
getWSClient().send({ type: "shell.open", payload: { path: dirPath, target } });
|
|
13659
13966
|
setContextMenu(null);
|
|
13660
13967
|
}, []);
|
|
13661
|
-
const handleGoUp =
|
|
13968
|
+
const handleGoUp = useCallback17(() => {
|
|
13662
13969
|
if (!cwd) return;
|
|
13663
13970
|
const norm = cwd.replace(/\\/g, "/");
|
|
13664
13971
|
const parent = norm.split("/").slice(0, -1).join("/") || norm;
|
|
13665
13972
|
getWSClient().send({ type: "working_dir.set", payload: { path: parent } });
|
|
13666
13973
|
}, [cwd]);
|
|
13667
13974
|
const [showSpinner, setShowSpinner] = useState32(false);
|
|
13668
|
-
const spinnerTimer =
|
|
13669
|
-
|
|
13975
|
+
const spinnerTimer = useRef19(null);
|
|
13976
|
+
useEffect30(() => {
|
|
13670
13977
|
if (treeLoading) {
|
|
13671
13978
|
spinnerTimer.current = setTimeout(() => setShowSpinner(true), 150);
|
|
13672
13979
|
} else {
|
|
@@ -13679,7 +13986,7 @@ function FileExplorer() {
|
|
|
13679
13986
|
}, [treeLoading]);
|
|
13680
13987
|
const [selectedPath, setSelectedPath] = useState32(null);
|
|
13681
13988
|
const [globalExpand, setGlobalExpand] = useState32(null);
|
|
13682
|
-
const dirCount =
|
|
13989
|
+
const dirCount = useMemo11(() => {
|
|
13683
13990
|
let count = 0;
|
|
13684
13991
|
const walk = (nodes) => {
|
|
13685
13992
|
for (const n of nodes) {
|
|
@@ -13690,7 +13997,7 @@ function FileExplorer() {
|
|
|
13690
13997
|
walk(tree);
|
|
13691
13998
|
return count;
|
|
13692
13999
|
}, [tree]);
|
|
13693
|
-
const cwdStats =
|
|
14000
|
+
const cwdStats = useMemo11(() => {
|
|
13694
14001
|
let files = 0;
|
|
13695
14002
|
let dirs = 0;
|
|
13696
14003
|
for (const n of tree) {
|
|
@@ -13700,21 +14007,21 @@ function FileExplorer() {
|
|
|
13700
14007
|
return { files, dirs };
|
|
13701
14008
|
}, [tree]);
|
|
13702
14009
|
const userInteractedRef = { value: false };
|
|
13703
|
-
const handleGlobalCollapse =
|
|
14010
|
+
const handleGlobalCollapse = useCallback17(() => {
|
|
13704
14011
|
userInteractedRef.value = true;
|
|
13705
14012
|
setGlobalExpand(false);
|
|
13706
14013
|
setTimeout(() => {
|
|
13707
14014
|
userInteractedRef.value = false;
|
|
13708
14015
|
}, 400);
|
|
13709
14016
|
}, []);
|
|
13710
|
-
const handleGlobalExpand =
|
|
14017
|
+
const handleGlobalExpand = useCallback17(() => {
|
|
13711
14018
|
userInteractedRef.value = true;
|
|
13712
14019
|
setGlobalExpand(true);
|
|
13713
14020
|
setTimeout(() => {
|
|
13714
14021
|
userInteractedRef.value = false;
|
|
13715
14022
|
}, 400);
|
|
13716
14023
|
}, []);
|
|
13717
|
-
const handleSelect =
|
|
14024
|
+
const handleSelect = useCallback17(
|
|
13718
14025
|
(filePath) => {
|
|
13719
14026
|
const existing = openFiles.find((f) => f.path === filePath);
|
|
13720
14027
|
if (existing) {
|
|
@@ -13725,13 +14032,13 @@ function FileExplorer() {
|
|
|
13725
14032
|
},
|
|
13726
14033
|
[openFiles]
|
|
13727
14034
|
);
|
|
13728
|
-
const handleOpen =
|
|
14035
|
+
const handleOpen = useCallback17((filePath) => {
|
|
13729
14036
|
window.dispatchEvent(
|
|
13730
14037
|
new CustomEvent("wrongstack:open-file", { detail: { filePath } })
|
|
13731
14038
|
);
|
|
13732
14039
|
setSelectedPath(null);
|
|
13733
14040
|
}, []);
|
|
13734
|
-
|
|
14041
|
+
useEffect30(() => {
|
|
13735
14042
|
if (activeFilePath) setSelectedPath(null);
|
|
13736
14043
|
}, [activeFilePath]);
|
|
13737
14044
|
if (showSpinner) {
|
|
@@ -13939,21 +14246,22 @@ import {
|
|
|
13939
14246
|
Circle as Circle4,
|
|
13940
14247
|
FileText as FileText5,
|
|
13941
14248
|
HelpCircle,
|
|
13942
|
-
Send as
|
|
14249
|
+
Send as Send3,
|
|
13943
14250
|
Bell,
|
|
13944
14251
|
RotateCw,
|
|
13945
14252
|
UserCheck,
|
|
13946
|
-
Trash2 as Trash23
|
|
14253
|
+
Trash2 as Trash23,
|
|
14254
|
+
Sparkles as Sparkles4
|
|
13947
14255
|
} from "lucide-react";
|
|
13948
|
-
import { useEffect as
|
|
14256
|
+
import { useEffect as useEffect31, useState as useState33 } from "react";
|
|
13949
14257
|
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
13950
14258
|
var TYPE_ICONS = {
|
|
13951
14259
|
note: FileText5,
|
|
13952
14260
|
ask: HelpCircle,
|
|
13953
|
-
assign:
|
|
14261
|
+
assign: Send3,
|
|
13954
14262
|
steer: RotateCw,
|
|
13955
14263
|
btw: Bell,
|
|
13956
|
-
broadcast:
|
|
14264
|
+
broadcast: Send3,
|
|
13957
14265
|
status: Circle4,
|
|
13958
14266
|
result: CheckCircle210
|
|
13959
14267
|
};
|
|
@@ -13971,13 +14279,14 @@ function MailboxPanel({ className }) {
|
|
|
13971
14279
|
const agents = useMailboxStore((s) => s.agents);
|
|
13972
14280
|
const [collapsed, setCollapsed] = useState33(false);
|
|
13973
14281
|
const [deleting, setDeleting] = useState33(false);
|
|
14282
|
+
const [purging, setPurging] = useState33(false);
|
|
13974
14283
|
const { client: client2 } = useWebSocket();
|
|
13975
14284
|
const [ready, setReady] = useState33(client2.status.state === "open");
|
|
13976
|
-
|
|
14285
|
+
useEffect31(() => {
|
|
13977
14286
|
const off = client2.onStatus((s) => setReady(s.state === "open"));
|
|
13978
14287
|
return () => off();
|
|
13979
14288
|
}, [client2]);
|
|
13980
|
-
|
|
14289
|
+
useEffect31(() => {
|
|
13981
14290
|
if (!ready) return;
|
|
13982
14291
|
client2.send({ type: "mailbox.messages", payload: { limit: 30 } });
|
|
13983
14292
|
client2.send({ type: "mailbox.agents", payload: {} });
|
|
@@ -13996,9 +14305,26 @@ function MailboxPanel({ className }) {
|
|
|
13996
14305
|
setDeleting(true);
|
|
13997
14306
|
client2.send({ type: "mailbox.clear" });
|
|
13998
14307
|
}
|
|
13999
|
-
|
|
14308
|
+
useEffect31(() => {
|
|
14000
14309
|
if (deleting && messages.length === 0) setDeleting(false);
|
|
14001
14310
|
}, [deleting, messages.length]);
|
|
14311
|
+
async function handlePurge() {
|
|
14312
|
+
const ok = await confirmModal({
|
|
14313
|
+
title: "Purge stale messages?",
|
|
14314
|
+
message: "Removes completed messages older than 1 day and incomplete messages older than 7 days. Active messages are preserved.",
|
|
14315
|
+
confirmLabel: "Purge",
|
|
14316
|
+
danger: false
|
|
14317
|
+
});
|
|
14318
|
+
if (!ok) return;
|
|
14319
|
+
setPurging(true);
|
|
14320
|
+
client2.send({ type: "mailbox.purge" });
|
|
14321
|
+
}
|
|
14322
|
+
useEffect31(() => {
|
|
14323
|
+
if (purging) {
|
|
14324
|
+
const t = setTimeout(() => setPurging(false), 3e3);
|
|
14325
|
+
return () => clearTimeout(t);
|
|
14326
|
+
}
|
|
14327
|
+
}, [purging]);
|
|
14002
14328
|
return /* @__PURE__ */ jsxs51("div", { className: cn("rounded-lg border border-border bg-card/60 backdrop-blur-sm", className), children: [
|
|
14003
14329
|
/* @__PURE__ */ jsxs51(
|
|
14004
14330
|
"button",
|
|
@@ -14034,6 +14360,20 @@ function MailboxPanel({ className }) {
|
|
|
14034
14360
|
deleting ? "Deleting\u2026" : "Delete all"
|
|
14035
14361
|
]
|
|
14036
14362
|
}
|
|
14363
|
+
),
|
|
14364
|
+
/* @__PURE__ */ jsxs51(
|
|
14365
|
+
"button",
|
|
14366
|
+
{
|
|
14367
|
+
type: "button",
|
|
14368
|
+
onClick: handlePurge,
|
|
14369
|
+
disabled: purging,
|
|
14370
|
+
className: "flex items-center gap-1 text-[10px] text-muted-foreground hover:text-cyan-500 disabled:opacity-40 transition-colors",
|
|
14371
|
+
title: "Purge stale/orphaned messages",
|
|
14372
|
+
children: [
|
|
14373
|
+
/* @__PURE__ */ jsx56(Sparkles4, { className: "h-3 w-3" }),
|
|
14374
|
+
purging ? "Purging\u2026" : "Purge"
|
|
14375
|
+
]
|
|
14376
|
+
}
|
|
14037
14377
|
)
|
|
14038
14378
|
] }),
|
|
14039
14379
|
messages.slice(0, 8).map((m) => {
|
|
@@ -14105,7 +14445,7 @@ function MailboxPanel({ className }) {
|
|
|
14105
14445
|
|
|
14106
14446
|
// src/components/ProjectsPanel.tsx
|
|
14107
14447
|
import { ExternalLink, Folder as Folder3, FolderPlus, History as History3, Loader2 as Loader28 } from "lucide-react";
|
|
14108
|
-
import { useCallback as
|
|
14448
|
+
import { useCallback as useCallback18, useEffect as useEffect32, useRef as useRef20, useState as useState34 } from "react";
|
|
14109
14449
|
import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
14110
14450
|
function ProjectsPanel({ fullView }) {
|
|
14111
14451
|
const [projects, setProjects] = useState34([]);
|
|
@@ -14114,13 +14454,13 @@ function ProjectsPanel({ fullView }) {
|
|
|
14114
14454
|
const [folderPath, setFolderPath] = useState34("");
|
|
14115
14455
|
const [projectName, setProjectName] = useState34("");
|
|
14116
14456
|
const [dialogOpen, setDialogOpen] = useState34(false);
|
|
14117
|
-
const projectNameRef =
|
|
14457
|
+
const projectNameRef = useRef20(null);
|
|
14118
14458
|
const [confirmSwitch, setConfirmSwitch] = useState34({ open: false, project: null, agentCount: 0 });
|
|
14119
|
-
const fetchProjects =
|
|
14459
|
+
const fetchProjects = useCallback18(() => {
|
|
14120
14460
|
const ws = getWSClient();
|
|
14121
14461
|
ws.send({ type: "projects.list" });
|
|
14122
14462
|
}, []);
|
|
14123
|
-
|
|
14463
|
+
useEffect32(() => {
|
|
14124
14464
|
setLoading(true);
|
|
14125
14465
|
const ws = getWSClient();
|
|
14126
14466
|
const offList = ws.on("projects.list", (msg) => {
|
|
@@ -14157,7 +14497,7 @@ function ProjectsPanel({ fullView }) {
|
|
|
14157
14497
|
if (days < 365) return `${Math.floor(days / 30)}mo ago`;
|
|
14158
14498
|
return `${Math.floor(days / 365)}y ago`;
|
|
14159
14499
|
};
|
|
14160
|
-
const handleSelect =
|
|
14500
|
+
const handleSelect = useCallback18((p) => {
|
|
14161
14501
|
const sessionId = useSessionStore.getState().session?.id;
|
|
14162
14502
|
if (sessionId) {
|
|
14163
14503
|
const fleet = useFleetStore.getState();
|
|
@@ -14170,7 +14510,7 @@ function ProjectsPanel({ fullView }) {
|
|
|
14170
14510
|
}
|
|
14171
14511
|
doSwitch(p);
|
|
14172
14512
|
}, []);
|
|
14173
|
-
const doSwitch =
|
|
14513
|
+
const doSwitch = useCallback18((p) => {
|
|
14174
14514
|
const ws = getWSClient();
|
|
14175
14515
|
ws.send({ type: "projects.select", payload: { root: p.root, name: p.name } });
|
|
14176
14516
|
const off = ws.on("projects.selected", (msg) => {
|
|
@@ -14185,7 +14525,7 @@ function ProjectsPanel({ fullView }) {
|
|
|
14185
14525
|
}
|
|
14186
14526
|
});
|
|
14187
14527
|
}, []);
|
|
14188
|
-
const handleAdd =
|
|
14528
|
+
const handleAdd = useCallback18(() => {
|
|
14189
14529
|
const trimmed = folderPath.trim();
|
|
14190
14530
|
if (!trimmed) {
|
|
14191
14531
|
toast.error("Please enter a folder path.");
|
|
@@ -14394,11 +14734,11 @@ function ProjectsPanel({ fullView }) {
|
|
|
14394
14734
|
|
|
14395
14735
|
// src/components/SidePanel/AgentsPanel.tsx
|
|
14396
14736
|
import { Bot as Bot9, LayoutGrid as LayoutGrid2, Wrench as Wrench7 } from "lucide-react";
|
|
14397
|
-
import { useMemo as
|
|
14737
|
+
import { useMemo as useMemo13, useState as useState36 } from "react";
|
|
14398
14738
|
|
|
14399
14739
|
// src/components/FleetPanel.tsx
|
|
14400
14740
|
import { Bot as Bot8, Check as Check7, ChevronDown as ChevronDown8, ChevronRight as ChevronRight7, Clock as Clock10, Copy as Copy3, Cpu as Cpu11, Crown, Wrench as Wrench6, X as X14, Zap as Zap8 } from "lucide-react";
|
|
14401
|
-
import { useCallback as
|
|
14741
|
+
import { useCallback as useCallback19, useMemo as useMemo12, useState as useState35 } from "react";
|
|
14402
14742
|
|
|
14403
14743
|
// src/components/ui/sparkline.tsx
|
|
14404
14744
|
import { jsx as jsx58 } from "react/jsx-runtime";
|
|
@@ -14442,7 +14782,7 @@ function SparklineChart({ bins, className, width = NUM_BINS }) {
|
|
|
14442
14782
|
}
|
|
14443
14783
|
|
|
14444
14784
|
// src/components/FleetPanel.tsx
|
|
14445
|
-
import { Fragment as
|
|
14785
|
+
import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
14446
14786
|
var STATUS_META2 = {
|
|
14447
14787
|
running: { led: "text-[hsl(var(--success))]", label: "running", pulse: true },
|
|
14448
14788
|
completed: { led: "text-[hsl(var(--success))]", label: "done", pulse: false },
|
|
@@ -14477,7 +14817,7 @@ function AgentDetail({
|
|
|
14477
14817
|
const [copied, setCopied] = useState35(false);
|
|
14478
14818
|
const leaderId = useFleetStore((s) => s.leaderId);
|
|
14479
14819
|
const isLeader = agent.id === leaderId;
|
|
14480
|
-
const handleCopy =
|
|
14820
|
+
const handleCopy = useCallback19(async (text) => {
|
|
14481
14821
|
try {
|
|
14482
14822
|
await navigator.clipboard.writeText(text);
|
|
14483
14823
|
setCopied(true);
|
|
@@ -14777,7 +15117,7 @@ function FleetPanel({
|
|
|
14777
15117
|
const agents = useFleetStore((s) => s.agents);
|
|
14778
15118
|
const [collapsed, setCollapsed] = useState35(true);
|
|
14779
15119
|
const [selectedId, setSelectedId] = useState35(null);
|
|
14780
|
-
const list =
|
|
15120
|
+
const list = useMemo12(() => {
|
|
14781
15121
|
const arr = Array.from(agents.values());
|
|
14782
15122
|
arr.sort((x, y) => {
|
|
14783
15123
|
const xa = x.status === "running" ? 0 : 1;
|
|
@@ -14794,7 +15134,7 @@ function FleetPanel({
|
|
|
14794
15134
|
const failed = list.filter((a) => a.status === "failed" || a.status === "timeout");
|
|
14795
15135
|
const totalCost = list.reduce((sum, a) => sum + (a.costUsd ?? 0), 0);
|
|
14796
15136
|
const effectiveCollapsed = collapsed && list.length >= 3;
|
|
14797
|
-
return /* @__PURE__ */ jsxs53(
|
|
15137
|
+
return /* @__PURE__ */ jsxs53(Fragment13, { children: [
|
|
14798
15138
|
/* @__PURE__ */ jsxs53(
|
|
14799
15139
|
"div",
|
|
14800
15140
|
{
|
|
@@ -14840,7 +15180,7 @@ function FleetPanel({
|
|
|
14840
15180
|
}
|
|
14841
15181
|
|
|
14842
15182
|
// src/components/SidePanel/AgentsPanel.tsx
|
|
14843
|
-
import { Fragment as
|
|
15183
|
+
import { Fragment as Fragment14, jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
14844
15184
|
var STATUS_META3 = {
|
|
14845
15185
|
running: { led: "text-[hsl(var(--success))]", label: "running", pulse: true },
|
|
14846
15186
|
completed: { led: "text-[hsl(var(--success))]", label: "done", pulse: false },
|
|
@@ -14891,7 +15231,7 @@ function AgentsPanel() {
|
|
|
14891
15231
|
const fleetAgents = useFleetStore((s) => s.agents);
|
|
14892
15232
|
const setCurrentView = useUIStore((s) => s.setCurrentView);
|
|
14893
15233
|
const [selectedAgentId, setSelectedAgentId] = useState36(null);
|
|
14894
|
-
const fleetList =
|
|
15234
|
+
const fleetList = useMemo13(() => {
|
|
14895
15235
|
const arr = Array.from(fleetAgents.values());
|
|
14896
15236
|
arr.sort((x, y) => {
|
|
14897
15237
|
const xa = x.status === "running" ? 0 : 1;
|
|
@@ -14910,7 +15250,7 @@ function AgentsPanel() {
|
|
|
14910
15250
|
/* @__PURE__ */ jsx60("p", { className: "text-xs mt-1", children: "Subagents appear here when the fleet is active." })
|
|
14911
15251
|
] }) });
|
|
14912
15252
|
}
|
|
14913
|
-
return /* @__PURE__ */ jsxs54(
|
|
15253
|
+
return /* @__PURE__ */ jsxs54(Fragment14, { children: [
|
|
14914
15254
|
/* @__PURE__ */ jsxs54("div", { className: "px-3 py-2 border-b text-[10px] text-muted-foreground flex items-center gap-2", children: [
|
|
14915
15255
|
/* @__PURE__ */ jsx60("span", { className: "font-semibold uppercase tracking-wider", children: "Fleet" }),
|
|
14916
15256
|
/* @__PURE__ */ jsxs54("span", { className: "ml-auto tabular-nums", children: [
|
|
@@ -14938,7 +15278,7 @@ function AgentsPanel() {
|
|
|
14938
15278
|
|
|
14939
15279
|
// src/components/SidePanel/HistoryPanel.tsx
|
|
14940
15280
|
import { LayoutGrid as LayoutGrid3 } from "lucide-react";
|
|
14941
|
-
import { useEffect as
|
|
15281
|
+
import { useEffect as useEffect34, useState as useState38 } from "react";
|
|
14942
15282
|
|
|
14943
15283
|
// src/components/SidePanel/SessionList.tsx
|
|
14944
15284
|
import {
|
|
@@ -14950,8 +15290,8 @@ import {
|
|
|
14950
15290
|
Trash2 as Trash24,
|
|
14951
15291
|
X as X15
|
|
14952
15292
|
} from "lucide-react";
|
|
14953
|
-
import { useCallback as
|
|
14954
|
-
import { Fragment as
|
|
15293
|
+
import { useCallback as useCallback20, useEffect as useEffect33, useMemo as useMemo14, useState as useState37 } from "react";
|
|
15294
|
+
import { Fragment as Fragment15, jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
14955
15295
|
var formatRelative = (iso) => {
|
|
14956
15296
|
const ts = Date.parse(iso);
|
|
14957
15297
|
if (Number.isNaN(ts)) return "";
|
|
@@ -14984,12 +15324,12 @@ function SessionList({
|
|
|
14984
15324
|
const [renamingId, setRenamingId] = useState37(null);
|
|
14985
15325
|
const [renameDraft, setRenameDraft] = useState37("");
|
|
14986
15326
|
const [resumingId, setResumingId] = useState37(null);
|
|
14987
|
-
|
|
15327
|
+
useEffect33(() => {
|
|
14988
15328
|
if (resumingId && historyEntries.some((e) => e.id === resumingId && e.isCurrent)) {
|
|
14989
15329
|
setResumingId(null);
|
|
14990
15330
|
}
|
|
14991
15331
|
}, [resumingId, historyEntries]);
|
|
14992
|
-
const handleResume =
|
|
15332
|
+
const handleResume = useCallback20(
|
|
14993
15333
|
(id) => {
|
|
14994
15334
|
setResumingId(id);
|
|
14995
15335
|
resumeSession(id);
|
|
@@ -14997,11 +15337,11 @@ function SessionList({
|
|
|
14997
15337
|
},
|
|
14998
15338
|
[resumeSession]
|
|
14999
15339
|
);
|
|
15000
|
-
const emptySessionIds =
|
|
15340
|
+
const emptySessionIds = useMemo14(
|
|
15001
15341
|
() => getEmptySessionIds(historyEntries),
|
|
15002
15342
|
[historyEntries]
|
|
15003
15343
|
);
|
|
15004
|
-
const handleDeleteEmpty =
|
|
15344
|
+
const handleDeleteEmpty = useCallback20(async () => {
|
|
15005
15345
|
if (emptySessionIds.length === 0) return;
|
|
15006
15346
|
const ok = await confirmModal({
|
|
15007
15347
|
title: emptySessionIds.length === 1 ? "Delete 1 empty session?" : `Delete ${emptySessionIds.length} empty sessions?`,
|
|
@@ -15050,7 +15390,7 @@ function SessionList({
|
|
|
15050
15390
|
if (older.length) out.push({ label: "Earlier", rows: older });
|
|
15051
15391
|
return out;
|
|
15052
15392
|
})();
|
|
15053
|
-
return /* @__PURE__ */ jsxs55(
|
|
15393
|
+
return /* @__PURE__ */ jsxs55(Fragment15, { children: [
|
|
15054
15394
|
/* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between px-4 py-2 border-b", children: [
|
|
15055
15395
|
/* @__PURE__ */ jsx61("span", { className: "text-xs uppercase tracking-wider text-muted-foreground", children: "Recent sessions" }),
|
|
15056
15396
|
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-1", children: [
|
|
@@ -15162,14 +15502,14 @@ Double-click to rename`, children: sessionNicknames[entry.id] || entry.title ||
|
|
|
15162
15502
|
/* @__PURE__ */ jsx61(Loader29, { className: "h-3 w-3 animate-spin" }),
|
|
15163
15503
|
"resuming\u2026"
|
|
15164
15504
|
] }) : /* @__PURE__ */ jsx61("span", { children: formatRelative(entry.startedAt) }),
|
|
15165
|
-
entry.tokenTotal > 0 && /* @__PURE__ */ jsxs55(
|
|
15505
|
+
entry.tokenTotal > 0 && /* @__PURE__ */ jsxs55(Fragment15, { children: [
|
|
15166
15506
|
/* @__PURE__ */ jsx61("span", { className: "opacity-50", children: "\xB7" }),
|
|
15167
15507
|
/* @__PURE__ */ jsxs55("span", { className: "tabular-nums", children: [
|
|
15168
15508
|
entry.tokenTotal.toLocaleString(),
|
|
15169
15509
|
" tok"
|
|
15170
15510
|
] })
|
|
15171
15511
|
] }),
|
|
15172
|
-
entry.isCurrent && /* @__PURE__ */ jsxs55(
|
|
15512
|
+
entry.isCurrent && /* @__PURE__ */ jsxs55(Fragment15, { children: [
|
|
15173
15513
|
/* @__PURE__ */ jsx61("span", { className: "opacity-50", children: "\xB7" }),
|
|
15174
15514
|
/* @__PURE__ */ jsx61("span", { className: "text-primary font-medium", children: "active" })
|
|
15175
15515
|
] })
|
|
@@ -15212,7 +15552,7 @@ function HistoryPanel() {
|
|
|
15212
15552
|
const setCurrentView = useUIStore((s) => s.setCurrentView);
|
|
15213
15553
|
const activeSessionId = useSessionStore((s) => s.session?.id);
|
|
15214
15554
|
const [query, setQuery] = useState38("");
|
|
15215
|
-
|
|
15555
|
+
useEffect34(() => {
|
|
15216
15556
|
void activeSessionId;
|
|
15217
15557
|
if (wsConnected) listSessions(50);
|
|
15218
15558
|
}, [wsConnected, activeSessionId, listSessions]);
|
|
@@ -15263,7 +15603,7 @@ import {
|
|
|
15263
15603
|
Wifi as Wifi2,
|
|
15264
15604
|
WifiOff as WifiOff3
|
|
15265
15605
|
} from "lucide-react";
|
|
15266
|
-
import { useCallback as
|
|
15606
|
+
import { useCallback as useCallback21, useEffect as useEffect35, useMemo as useMemo15, useState as useState39 } from "react";
|
|
15267
15607
|
import { jsx as jsx63, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
15268
15608
|
function fmtCost3(v) {
|
|
15269
15609
|
if (v <= 0) return "$0.000";
|
|
@@ -15383,7 +15723,7 @@ function SessionPanel() {
|
|
|
15383
15723
|
const unpinAll = useUIStore((s) => s.unpinAll);
|
|
15384
15724
|
const setModelSwitcherOpen = useUIStore((s) => s.setModelSwitcherOpen);
|
|
15385
15725
|
const localPrefs = useLocalPrefs();
|
|
15386
|
-
const syncPref =
|
|
15726
|
+
const syncPref = useCallback21(
|
|
15387
15727
|
(key, value) => {
|
|
15388
15728
|
localPrefs.set({ [key]: value });
|
|
15389
15729
|
updatePrefs({ [key]: value });
|
|
@@ -15393,12 +15733,12 @@ function SessionPanel() {
|
|
|
15393
15733
|
const [breakdownOpen, setBreakdownOpen] = useState39(false);
|
|
15394
15734
|
const startedAt = session?.startedAt ?? null;
|
|
15395
15735
|
const [now, setNow] = useState39(() => Date.now());
|
|
15396
|
-
|
|
15736
|
+
useEffect35(() => {
|
|
15397
15737
|
if (!startedAt) return;
|
|
15398
15738
|
const t = setInterval(() => setNow(Date.now()), 1e3);
|
|
15399
15739
|
return () => clearInterval(t);
|
|
15400
15740
|
}, [startedAt]);
|
|
15401
|
-
const runningAgents =
|
|
15741
|
+
const runningAgents = useMemo15(
|
|
15402
15742
|
() => Array.from(fleetAgents.values()).filter((a) => a.status === "running").length,
|
|
15403
15743
|
[fleetAgents]
|
|
15404
15744
|
);
|
|
@@ -15767,7 +16107,7 @@ function SidePanel() {
|
|
|
15767
16107
|
const setSidebarWidth = useUIStore((s) => s.setSidebarWidth);
|
|
15768
16108
|
const wsConnected = useConfigStore((s) => s.wsConnected);
|
|
15769
16109
|
const { client: client2 } = useWebSocket();
|
|
15770
|
-
|
|
16110
|
+
useEffect36(() => {
|
|
15771
16111
|
if (activeActivity !== "files" || !wsConnected) return;
|
|
15772
16112
|
useFileStore.getState().setTreeLoading(true);
|
|
15773
16113
|
const cwd = useSessionStore.getState().cwd;
|
|
@@ -15834,11 +16174,30 @@ function SidePanel() {
|
|
|
15834
16174
|
|
|
15835
16175
|
// src/components/WorkspaceDock.tsx
|
|
15836
16176
|
import { Bot as Bot10, GitBranch as GitBranch3, ListTodo as ListTodo2, Maximize2 as Maximize22, Rocket as Rocket4, Target as Target3, Users as Users3 } from "lucide-react";
|
|
15837
|
-
import { useCallback as
|
|
16177
|
+
import { useCallback as useCallback27, useEffect as useEffect43, useMemo as useMemo16, useRef as useRef25, useState as useState46 } from "react";
|
|
16178
|
+
|
|
16179
|
+
// src/hooks/useGitInfo.ts
|
|
16180
|
+
import { useCallback as useCallback22, useEffect as useEffect37, useRef as useRef21 } from "react";
|
|
16181
|
+
function useGitInfo() {
|
|
16182
|
+
const info = useGitInfoStore((s) => s.info);
|
|
16183
|
+
const { client: client2 } = useWebSocket();
|
|
16184
|
+
const intervalRef = useRef21(null);
|
|
16185
|
+
const fetch2 = useCallback22(() => {
|
|
16186
|
+
client2?.getGitInfo?.();
|
|
16187
|
+
}, [client2]);
|
|
16188
|
+
useEffect37(() => {
|
|
16189
|
+
fetch2();
|
|
16190
|
+
intervalRef.current = setInterval(fetch2, 3e4);
|
|
16191
|
+
return () => {
|
|
16192
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
16193
|
+
};
|
|
16194
|
+
}, [fetch2]);
|
|
16195
|
+
return info;
|
|
16196
|
+
}
|
|
15838
16197
|
|
|
15839
16198
|
// src/components/CollabPanel.tsx
|
|
15840
16199
|
import { Eye as Eye2, LogIn, LogOut, MessageSquareWarning, Pause as Pause5, Play as Play6, Users as Users2 } from "lucide-react";
|
|
15841
|
-
import { useEffect as
|
|
16200
|
+
import { useEffect as useEffect38, useState as useState40 } from "react";
|
|
15842
16201
|
import { jsx as jsx65, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
15843
16202
|
function CollabPanel({ sessionId, className }) {
|
|
15844
16203
|
const [participants, setParticipants] = useState40([]);
|
|
@@ -15849,7 +16208,7 @@ function CollabPanel({ sessionId, className }) {
|
|
|
15849
16208
|
const [paused, setPaused] = useState40(false);
|
|
15850
16209
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
15851
16210
|
const client2 = getWSClient(wsUrl);
|
|
15852
|
-
|
|
16211
|
+
useEffect38(() => {
|
|
15853
16212
|
const offs = [];
|
|
15854
16213
|
offs.push(
|
|
15855
16214
|
client2.on("collab.state", (msg) => {
|
|
@@ -16137,7 +16496,7 @@ import {
|
|
|
16137
16496
|
TrendingUp,
|
|
16138
16497
|
Minus
|
|
16139
16498
|
} from "lucide-react";
|
|
16140
|
-
import { useEffect as
|
|
16499
|
+
import { useEffect as useEffect39, useState as useState41 } from "react";
|
|
16141
16500
|
import { jsx as jsx66, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
16142
16501
|
var TREND_ICON = {
|
|
16143
16502
|
up: /* @__PURE__ */ jsx66(TrendingUp, { className: "h-3.5 w-3.5 text-emerald-500" }),
|
|
@@ -16173,7 +16532,7 @@ var STATE_CONFIG = {
|
|
|
16173
16532
|
};
|
|
16174
16533
|
function GoalPanel({ goal, className }) {
|
|
16175
16534
|
const [collapsed, setCollapsed] = useState41(false);
|
|
16176
|
-
|
|
16535
|
+
useEffect39(() => {
|
|
16177
16536
|
const ws = getWSClient();
|
|
16178
16537
|
ws?.send?.({ type: "goal.get" });
|
|
16179
16538
|
const timer = setInterval(() => {
|
|
@@ -16181,7 +16540,7 @@ function GoalPanel({ goal, className }) {
|
|
|
16181
16540
|
}, 1e4);
|
|
16182
16541
|
return () => clearInterval(timer);
|
|
16183
16542
|
}, []);
|
|
16184
|
-
|
|
16543
|
+
useEffect39(() => {
|
|
16185
16544
|
if (!goal || goal.goalState === "completed" || goal.goalState === "failed" || goal.goalState === "abandoned") {
|
|
16186
16545
|
setCollapsed(true);
|
|
16187
16546
|
}
|
|
@@ -16305,7 +16664,7 @@ import { useState as useState45 } from "react";
|
|
|
16305
16664
|
|
|
16306
16665
|
// src/components/TodosPanel.tsx
|
|
16307
16666
|
import { CheckCircle2 as CheckCircle213, Circle as Circle7, Clock as Clock12, Trash2 as Trash25 } from "lucide-react";
|
|
16308
|
-
import { useCallback as
|
|
16667
|
+
import { useCallback as useCallback24, useEffect as useEffect40, useRef as useRef22, useState as useState42 } from "react";
|
|
16309
16668
|
import { jsx as jsx67, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
16310
16669
|
var STATUS_ORDER = {
|
|
16311
16670
|
in_progress: 0,
|
|
@@ -16316,8 +16675,8 @@ function TodosPanel() {
|
|
|
16316
16675
|
const [todos, setTodos] = useState42([]);
|
|
16317
16676
|
const [collapsedSections, setCollapsedSections] = useState42(/* @__PURE__ */ new Set());
|
|
16318
16677
|
const ws = getWSClient();
|
|
16319
|
-
const offRef =
|
|
16320
|
-
|
|
16678
|
+
const offRef = useRef22(null);
|
|
16679
|
+
useEffect40(() => {
|
|
16321
16680
|
ws.send({ type: "todos.get" });
|
|
16322
16681
|
offRef.current = ws.on("todos.updated", (msg) => {
|
|
16323
16682
|
const payload = msg?.payload;
|
|
@@ -16327,10 +16686,10 @@ function TodosPanel() {
|
|
|
16327
16686
|
offRef.current?.();
|
|
16328
16687
|
};
|
|
16329
16688
|
}, [ws]);
|
|
16330
|
-
const handleRemove =
|
|
16689
|
+
const handleRemove = useCallback24((id) => {
|
|
16331
16690
|
ws.removeTodo(id);
|
|
16332
16691
|
}, [ws]);
|
|
16333
|
-
const handleToggle =
|
|
16692
|
+
const handleToggle = useCallback24(
|
|
16334
16693
|
(t) => {
|
|
16335
16694
|
if (t.status === "in_progress") return;
|
|
16336
16695
|
const next = t.status === "completed" ? "pending" : "completed";
|
|
@@ -16450,7 +16809,7 @@ function TodosPanel() {
|
|
|
16450
16809
|
|
|
16451
16810
|
// src/components/TasksPanel.tsx
|
|
16452
16811
|
import { CheckCircle2 as CheckCircle214, Circle as Circle8, Clock as Clock13, Pause as Pause6, XCircle as XCircle7, RotateCcw as RotateCcw5 } from "lucide-react";
|
|
16453
|
-
import { useCallback as
|
|
16812
|
+
import { useCallback as useCallback25, useEffect as useEffect41, useRef as useRef23, useState as useState43 } from "react";
|
|
16454
16813
|
import { jsx as jsx68, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
16455
16814
|
var STATUS_CONFIG2 = {
|
|
16456
16815
|
pending: { icon: /* @__PURE__ */ jsx68(Circle8, { className: "w-3.5 h-3.5" }), label: "Pending", color: "text-muted-foreground/50" },
|
|
@@ -16478,8 +16837,8 @@ function TasksPanel() {
|
|
|
16478
16837
|
const [tasks, setTasks] = useState43([]);
|
|
16479
16838
|
const [collapsed, setCollapsed] = useState43(/* @__PURE__ */ new Set());
|
|
16480
16839
|
const ws = getWSClient();
|
|
16481
|
-
const offRef =
|
|
16482
|
-
|
|
16840
|
+
const offRef = useRef23(null);
|
|
16841
|
+
useEffect41(() => {
|
|
16483
16842
|
ws.getTasks();
|
|
16484
16843
|
offRef.current = ws.on("tasks.updated", (msg) => {
|
|
16485
16844
|
const payload = msg?.payload;
|
|
@@ -16489,7 +16848,7 @@ function TasksPanel() {
|
|
|
16489
16848
|
offRef.current?.();
|
|
16490
16849
|
};
|
|
16491
16850
|
}, [ws]);
|
|
16492
|
-
const toggle =
|
|
16851
|
+
const toggle = useCallback25((key) => {
|
|
16493
16852
|
setCollapsed((prev) => {
|
|
16494
16853
|
const next = new Set(prev);
|
|
16495
16854
|
if (next.has(key)) next.delete(key);
|
|
@@ -16497,7 +16856,7 @@ function TasksPanel() {
|
|
|
16497
16856
|
return next;
|
|
16498
16857
|
});
|
|
16499
16858
|
}, []);
|
|
16500
|
-
const handleStatusChange =
|
|
16859
|
+
const handleStatusChange = useCallback25(
|
|
16501
16860
|
(taskId, status) => {
|
|
16502
16861
|
ws.updateTaskStatus(taskId, status);
|
|
16503
16862
|
},
|
|
@@ -16619,7 +16978,7 @@ function TasksPanel() {
|
|
|
16619
16978
|
|
|
16620
16979
|
// src/components/PlanPanel.tsx
|
|
16621
16980
|
import { CheckCircle2 as CheckCircle215, Circle as Circle9, Clock as Clock14 } from "lucide-react";
|
|
16622
|
-
import { useCallback as
|
|
16981
|
+
import { useCallback as useCallback26, useEffect as useEffect42, useRef as useRef24, useState as useState44 } from "react";
|
|
16623
16982
|
import { jsx as jsx69, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
16624
16983
|
var STATUS_CONFIG3 = {
|
|
16625
16984
|
open: { icon: /* @__PURE__ */ jsx69(Circle9, { className: "w-3.5 h-3.5" }), label: "Open", color: "text-muted-foreground/50" },
|
|
@@ -16630,8 +16989,8 @@ function PlanPanel() {
|
|
|
16630
16989
|
const [items, setItems] = useState44([]);
|
|
16631
16990
|
const [collapsed, setCollapsed] = useState44(/* @__PURE__ */ new Set());
|
|
16632
16991
|
const ws = getWSClient();
|
|
16633
|
-
const offRef =
|
|
16634
|
-
|
|
16992
|
+
const offRef = useRef24(null);
|
|
16993
|
+
useEffect42(() => {
|
|
16635
16994
|
ws.getPlan();
|
|
16636
16995
|
offRef.current = ws.on("plan.updated", (msg) => {
|
|
16637
16996
|
const payload = msg?.payload;
|
|
@@ -16641,7 +17000,7 @@ function PlanPanel() {
|
|
|
16641
17000
|
offRef.current?.();
|
|
16642
17001
|
};
|
|
16643
17002
|
}, [ws]);
|
|
16644
|
-
const toggle =
|
|
17003
|
+
const toggle = useCallback26((key) => {
|
|
16645
17004
|
setCollapsed((prev) => {
|
|
16646
17005
|
const next = new Set(prev);
|
|
16647
17006
|
if (next.has(key)) next.delete(key);
|
|
@@ -16649,7 +17008,7 @@ function PlanPanel() {
|
|
|
16649
17008
|
return next;
|
|
16650
17009
|
});
|
|
16651
17010
|
}, []);
|
|
16652
|
-
const handleStatusChange =
|
|
17011
|
+
const handleStatusChange = useCallback26(
|
|
16653
17012
|
(item, status) => {
|
|
16654
17013
|
ws.updatePlanItem(item.id, status);
|
|
16655
17014
|
},
|
|
@@ -16857,25 +17216,26 @@ function WorkspaceDock({ sessionId }) {
|
|
|
16857
17216
|
const baseBranch = useWorktreeStore((s) => s.baseBranch);
|
|
16858
17217
|
const todos = useSessionStore((s) => s.todos);
|
|
16859
17218
|
const fleetAgents = useFleetStore((s) => s.agents);
|
|
16860
|
-
const
|
|
17219
|
+
const gitInfo = useGitInfo();
|
|
17220
|
+
const handlePhaseClick = useCallback27(
|
|
16861
17221
|
(phaseId) => selectAutoPhase(phaseId),
|
|
16862
17222
|
[selectAutoPhase]
|
|
16863
17223
|
);
|
|
16864
|
-
const handleToggleAutonomous =
|
|
17224
|
+
const handleToggleAutonomous = useCallback27(
|
|
16865
17225
|
() => toggleAutoPhaseAutonomous(!autoPhase.autonomous),
|
|
16866
17226
|
[toggleAutoPhaseAutonomous, autoPhase.autonomous]
|
|
16867
17227
|
);
|
|
16868
17228
|
const [worktreeView, setWorktreeView] = useState46("graph");
|
|
16869
17229
|
const fleetTotal = fleetAgents.size;
|
|
16870
|
-
const fleetRunning =
|
|
17230
|
+
const fleetRunning = useMemo16(
|
|
16871
17231
|
() => Array.from(fleetAgents.values()).filter((a) => a.status === "running").length,
|
|
16872
17232
|
[fleetAgents]
|
|
16873
17233
|
);
|
|
16874
17234
|
const todosDone = todos.filter((t) => t.status === "completed").length;
|
|
16875
17235
|
const todosActive = todos.some((t) => t.status === "in_progress");
|
|
16876
17236
|
const phasesActive = autoPhase.phases.length > 0;
|
|
16877
|
-
const prevPhaseCount =
|
|
16878
|
-
|
|
17237
|
+
const prevPhaseCount = useRef25(autoPhase.phases.length);
|
|
17238
|
+
useEffect43(() => {
|
|
16879
17239
|
const ui = useUIStore.getState();
|
|
16880
17240
|
if (prevPhaseCount.current === 0 && autoPhase.phases.length > 0 && ui.dockSection === null) {
|
|
16881
17241
|
ui.setDockSection("autophase");
|
|
@@ -16955,6 +17315,39 @@ function WorkspaceDock({ sessionId }) {
|
|
|
16955
17315
|
onClick: () => toggleDockSection("worktrees")
|
|
16956
17316
|
}
|
|
16957
17317
|
),
|
|
17318
|
+
gitInfo && /* @__PURE__ */ jsxs65(
|
|
17319
|
+
"button",
|
|
17320
|
+
{
|
|
17321
|
+
type: "button",
|
|
17322
|
+
onClick: () => {
|
|
17323
|
+
},
|
|
17324
|
+
className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-[11px] font-mono border border-transparent hover:border-border transition-colors",
|
|
17325
|
+
children: [
|
|
17326
|
+
/* @__PURE__ */ jsx71(GitBranch3, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
|
|
17327
|
+
/* @__PURE__ */ jsx71("span", { className: "font-semibold text-foreground", children: gitInfo.branch }),
|
|
17328
|
+
gitInfo.ahead > 0 && /* @__PURE__ */ jsxs65("span", { className: "text-emerald-600 dark:text-emerald-400", title: `${gitInfo.ahead} ahead`, children: [
|
|
17329
|
+
"\u2191",
|
|
17330
|
+
gitInfo.ahead
|
|
17331
|
+
] }),
|
|
17332
|
+
gitInfo.behind > 0 && /* @__PURE__ */ jsxs65("span", { className: "text-amber-600 dark:text-amber-400", title: `${gitInfo.behind} behind`, children: [
|
|
17333
|
+
"\u2193",
|
|
17334
|
+
gitInfo.behind
|
|
17335
|
+
] }),
|
|
17336
|
+
gitInfo.added > 0 && /* @__PURE__ */ jsxs65("span", { className: "text-emerald-600 dark:text-emerald-400", title: `${gitInfo.added} lines added`, children: [
|
|
17337
|
+
"+",
|
|
17338
|
+
gitInfo.added
|
|
17339
|
+
] }),
|
|
17340
|
+
gitInfo.deleted > 0 && /* @__PURE__ */ jsxs65("span", { className: "text-red-600 dark:text-red-400", title: `${gitInfo.deleted} lines deleted`, children: [
|
|
17341
|
+
"-",
|
|
17342
|
+
gitInfo.deleted
|
|
17343
|
+
] }),
|
|
17344
|
+
gitInfo.untracked > 0 && /* @__PURE__ */ jsxs65("span", { className: "text-muted-foreground", title: `${gitInfo.untracked} untracked files`, children: [
|
|
17345
|
+
gitInfo.untracked,
|
|
17346
|
+
"?"
|
|
17347
|
+
] })
|
|
17348
|
+
]
|
|
17349
|
+
}
|
|
17350
|
+
),
|
|
16958
17351
|
/* @__PURE__ */ jsx71(
|
|
16959
17352
|
DockChip,
|
|
16960
17353
|
{
|
|
@@ -17018,8 +17411,8 @@ function WorkspaceDock({ sessionId }) {
|
|
|
17018
17411
|
|
|
17019
17412
|
// src/components/AgentsMonitor.tsx
|
|
17020
17413
|
import { Bot as Bot11, ChevronLeft, ChevronRight as ChevronRight9, Cpu as Cpu13, Crown as Crown2, Loader2 as Loader210, Wrench as Wrench8, X as X16, Zap as Zap9 } from "lucide-react";
|
|
17021
|
-
import { useCallback as
|
|
17022
|
-
import { Fragment as
|
|
17414
|
+
import { useCallback as useCallback28, useEffect as useEffect44, useMemo as useMemo17, useState as useState47 } from "react";
|
|
17415
|
+
import { Fragment as Fragment16, jsx as jsx72, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
17023
17416
|
function fmtCost4(v) {
|
|
17024
17417
|
if (v <= 0) return "$0";
|
|
17025
17418
|
if (v >= 0.01) return `$${v.toFixed(3)}`;
|
|
@@ -17144,7 +17537,7 @@ function AgentsMonitor({ onClose }) {
|
|
|
17144
17537
|
const fleetAgents = useFleetStore((s) => s.agents);
|
|
17145
17538
|
const leaderId = useFleetStore((s) => s.leaderId);
|
|
17146
17539
|
const [selectedIdx, setSelectedIdx] = useState47(0);
|
|
17147
|
-
const fleetList =
|
|
17540
|
+
const fleetList = useMemo17(() => {
|
|
17148
17541
|
const arr = Array.from(fleetAgents.values());
|
|
17149
17542
|
arr.sort((x, y) => {
|
|
17150
17543
|
if (x.id === leaderId) return -1;
|
|
@@ -17156,7 +17549,7 @@ function AgentsMonitor({ onClose }) {
|
|
|
17156
17549
|
});
|
|
17157
17550
|
return arr;
|
|
17158
17551
|
}, [fleetAgents, leaderId]);
|
|
17159
|
-
const handleKeyDown =
|
|
17552
|
+
const handleKeyDown = useCallback28(
|
|
17160
17553
|
(e) => {
|
|
17161
17554
|
if (e.key === "Escape") {
|
|
17162
17555
|
onClose();
|
|
@@ -17175,7 +17568,7 @@ function AgentsMonitor({ onClose }) {
|
|
|
17175
17568
|
},
|
|
17176
17569
|
[fleetList.length, onClose]
|
|
17177
17570
|
);
|
|
17178
|
-
|
|
17571
|
+
useEffect44(() => {
|
|
17179
17572
|
const handleGlobal = (e) => {
|
|
17180
17573
|
if (e.key === "Escape") onClose();
|
|
17181
17574
|
};
|
|
@@ -17183,7 +17576,7 @@ function AgentsMonitor({ onClose }) {
|
|
|
17183
17576
|
return () => window.removeEventListener("keydown", handleGlobal);
|
|
17184
17577
|
}, [onClose]);
|
|
17185
17578
|
const selectedAgent = fleetList[selectedIdx] ?? null;
|
|
17186
|
-
return /* @__PURE__ */ jsxs66(
|
|
17579
|
+
return /* @__PURE__ */ jsxs66(Fragment16, { children: [
|
|
17187
17580
|
/* @__PURE__ */ jsx72(
|
|
17188
17581
|
"div",
|
|
17189
17582
|
{
|
|
@@ -17297,7 +17690,7 @@ import {
|
|
|
17297
17690
|
XCircle as XCircle8,
|
|
17298
17691
|
Zap as Zap10
|
|
17299
17692
|
} from "lucide-react";
|
|
17300
|
-
import { useCallback as
|
|
17693
|
+
import { useCallback as useCallback29, useEffect as useEffect45, useMemo as useMemo18, useState as useState48 } from "react";
|
|
17301
17694
|
|
|
17302
17695
|
// src/components/ui/dropdown-menu.tsx
|
|
17303
17696
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
@@ -17486,7 +17879,7 @@ function EventTimeline({ events, max = 20, className }) {
|
|
|
17486
17879
|
}
|
|
17487
17880
|
|
|
17488
17881
|
// src/components/FleetMonitor.tsx
|
|
17489
|
-
import { Fragment as
|
|
17882
|
+
import { Fragment as Fragment17, jsx as jsx76, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
17490
17883
|
function fmtCost5(v) {
|
|
17491
17884
|
if (v <= 0) return "$0";
|
|
17492
17885
|
if (v >= 0.01) return `$${v.toFixed(3)}`;
|
|
@@ -17520,7 +17913,7 @@ function FleetAgentDetailPanel({
|
|
|
17520
17913
|
const [showFullToolLog, setShowFullToolLog] = useState48(false);
|
|
17521
17914
|
const meta2 = STATUS_META5[agent.status];
|
|
17522
17915
|
const active = agent.status === "running";
|
|
17523
|
-
const handleCopy =
|
|
17916
|
+
const handleCopy = useCallback29(async (text) => {
|
|
17524
17917
|
try {
|
|
17525
17918
|
await navigator.clipboard.writeText(text);
|
|
17526
17919
|
setCopied(true);
|
|
@@ -17530,9 +17923,9 @@ function FleetAgentDetailPanel({
|
|
|
17530
17923
|
}, []);
|
|
17531
17924
|
const totalToolDuration = agent.toolLog.reduce((sum, t) => sum + t.durationMs, 0);
|
|
17532
17925
|
const avgToolDuration = agent.toolLog.length > 0 ? Math.round(totalToolDuration / agent.toolLog.length) : 0;
|
|
17533
|
-
const uniqueTools =
|
|
17926
|
+
const uniqueTools = useMemo18(() => {
|
|
17534
17927
|
const tools = /* @__PURE__ */ new Set();
|
|
17535
|
-
agent.toolLog
|
|
17928
|
+
for (const t of agent.toolLog) tools.add(t.name);
|
|
17536
17929
|
return tools.size;
|
|
17537
17930
|
}, [agent.toolLog]);
|
|
17538
17931
|
const outputText = agent.partialText || agent.finalText || void 0;
|
|
@@ -17663,10 +18056,10 @@ function FleetAgentDetailPanel({
|
|
|
17663
18056
|
] }),
|
|
17664
18057
|
outputText ? /* @__PURE__ */ jsxs70("div", { className: "rounded-lg border bg-card", children: [
|
|
17665
18058
|
/* @__PURE__ */ jsxs70("div", { className: "flex items-center justify-between px-4 py-2 border-b bg-muted/30", children: [
|
|
17666
|
-
/* @__PURE__ */ jsx76("span", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: isStream ? /* @__PURE__ */ jsxs70(
|
|
18059
|
+
/* @__PURE__ */ jsx76("span", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: isStream ? /* @__PURE__ */ jsxs70(Fragment17, { children: [
|
|
17667
18060
|
/* @__PURE__ */ jsx76("span", { className: "w-2 h-2 rounded-full bg-blue-500 animate-pulse" }),
|
|
17668
18061
|
"Live Output"
|
|
17669
|
-
] }) : /* @__PURE__ */ jsxs70(
|
|
18062
|
+
] }) : /* @__PURE__ */ jsxs70(Fragment17, { children: [
|
|
17670
18063
|
/* @__PURE__ */ jsx76(FolderOpen4, { className: "h-3 w-3" }),
|
|
17671
18064
|
"Final Output"
|
|
17672
18065
|
] }) }),
|
|
@@ -17840,11 +18233,11 @@ function FleetMonitor({
|
|
|
17840
18233
|
const eventTimeline = useFleetStore((s) => s.eventTimeline);
|
|
17841
18234
|
const [selectedIdx, setSelectedIdx] = useState48(null);
|
|
17842
18235
|
const [nowTick, setNowTick] = useState48(Date.now());
|
|
17843
|
-
|
|
18236
|
+
useEffect45(() => {
|
|
17844
18237
|
const t = setInterval(() => setNowTick(Date.now()), 1e3);
|
|
17845
18238
|
return () => clearInterval(t);
|
|
17846
18239
|
}, []);
|
|
17847
|
-
const fleetList =
|
|
18240
|
+
const fleetList = useMemo18(() => {
|
|
17848
18241
|
const arr = Array.from(fleetAgents.values());
|
|
17849
18242
|
arr.sort((x, y) => {
|
|
17850
18243
|
if (x.id === leaderId) return -1;
|
|
@@ -17856,17 +18249,17 @@ function FleetMonitor({
|
|
|
17856
18249
|
});
|
|
17857
18250
|
return arr;
|
|
17858
18251
|
}, [fleetAgents, leaderId]);
|
|
17859
|
-
const totalCost =
|
|
18252
|
+
const totalCost = useMemo18(
|
|
17860
18253
|
() => Array.from(fleetAgents.values()).reduce((sum, a) => sum + a.costUsd, 0),
|
|
17861
18254
|
[fleetAgents]
|
|
17862
18255
|
);
|
|
17863
18256
|
const runningCount = fleetList.filter((a) => a.status === "running").length;
|
|
17864
18257
|
const selectedAgent = selectedIdx !== null ? fleetList[selectedIdx] : null;
|
|
17865
|
-
const handleAgentClick =
|
|
18258
|
+
const handleAgentClick = useCallback29(
|
|
17866
18259
|
(i) => setSelectedIdx((prev) => prev === i ? null : i),
|
|
17867
18260
|
[]
|
|
17868
18261
|
);
|
|
17869
|
-
const handleKeyDown =
|
|
18262
|
+
const handleKeyDown = useCallback29(
|
|
17870
18263
|
(e) => {
|
|
17871
18264
|
if (e.key === "Escape") {
|
|
17872
18265
|
if (selectedIdx !== null) {
|
|
@@ -17892,14 +18285,14 @@ function FleetMonitor({
|
|
|
17892
18285
|
},
|
|
17893
18286
|
[fleetList, selectedIdx, onClose, onSelectAgent]
|
|
17894
18287
|
);
|
|
17895
|
-
|
|
18288
|
+
useEffect45(() => {
|
|
17896
18289
|
const handleGlobal = (e) => {
|
|
17897
18290
|
if (e.key === "Escape") onClose();
|
|
17898
18291
|
};
|
|
17899
18292
|
window.addEventListener("keydown", handleGlobal);
|
|
17900
18293
|
return () => window.removeEventListener("keydown", handleGlobal);
|
|
17901
18294
|
}, [onClose]);
|
|
17902
|
-
return /* @__PURE__ */ jsxs70(
|
|
18295
|
+
return /* @__PURE__ */ jsxs70(Fragment17, { children: [
|
|
17903
18296
|
/* @__PURE__ */ jsx76(
|
|
17904
18297
|
"div",
|
|
17905
18298
|
{
|
|
@@ -18052,8 +18445,8 @@ function FleetMonitor({
|
|
|
18052
18445
|
|
|
18053
18446
|
// src/components/InspectorPanel.tsx
|
|
18054
18447
|
import { Bot as Bot13, ChevronDown as ChevronDown10, ChevronUp, Users as Users5 } from "lucide-react";
|
|
18055
|
-
import { useMemo as
|
|
18056
|
-
import { Fragment as
|
|
18448
|
+
import { useMemo as useMemo19, useState as useState49 } from "react";
|
|
18449
|
+
import { Fragment as Fragment18, jsx as jsx77, jsxs as jsxs71 } from "react/jsx-runtime";
|
|
18057
18450
|
var PANEL_HEIGHT = 320;
|
|
18058
18451
|
function fmtCost6(v) {
|
|
18059
18452
|
if (v <= 0) return "$0";
|
|
@@ -18090,7 +18483,7 @@ function InspectorPanel() {
|
|
|
18090
18483
|
const fleetConcurrency = useFleetStore((s) => s.fleetConcurrency);
|
|
18091
18484
|
const fleetConcurrencyMax = useFleetStore((s) => s.fleetConcurrencyMax);
|
|
18092
18485
|
const eventTimeline = useFleetStore((s) => s.eventTimeline);
|
|
18093
|
-
const fleetList =
|
|
18486
|
+
const fleetList = useMemo19(
|
|
18094
18487
|
() => sortFleet(fleetAgents, leaderId),
|
|
18095
18488
|
[fleetAgents, leaderId]
|
|
18096
18489
|
);
|
|
@@ -18098,7 +18491,7 @@ function InspectorPanel() {
|
|
|
18098
18491
|
const totalCost = fleetList.reduce((sum, a) => sum + a.costUsd, 0);
|
|
18099
18492
|
const fleetTotal = fleetList.length;
|
|
18100
18493
|
const [selectedAgentId, setSelectedAgentId] = useState49(null);
|
|
18101
|
-
const selectedAgent =
|
|
18494
|
+
const selectedAgent = useMemo19(() => {
|
|
18102
18495
|
if (!selectedAgentId) return fleetList[0] ?? null;
|
|
18103
18496
|
return fleetAgents.get(selectedAgentId) ?? fleetList[0] ?? null;
|
|
18104
18497
|
}, [selectedAgentId, fleetList, fleetAgents]);
|
|
@@ -18123,7 +18516,7 @@ function InspectorPanel() {
|
|
|
18123
18516
|
/* @__PURE__ */ jsxs71("span", { className: "flex items-center gap-2 min-w-0", children: [
|
|
18124
18517
|
inspectorOpen ? /* @__PURE__ */ jsx77(ChevronDown10, { className: "h-3.5 w-3.5 shrink-0" }) : /* @__PURE__ */ jsx77(ChevronUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18125
18518
|
/* @__PURE__ */ jsx77("span", { className: "font-medium uppercase tracking-wider", children: "Inspector" }),
|
|
18126
|
-
fleetTotal > 0 && /* @__PURE__ */ jsxs71(
|
|
18519
|
+
fleetTotal > 0 && /* @__PURE__ */ jsxs71(Fragment18, { children: [
|
|
18127
18520
|
/* @__PURE__ */ jsx77("span", { className: "opacity-40", children: "\xB7" }),
|
|
18128
18521
|
/* @__PURE__ */ jsxs71("span", { className: "flex items-center gap-1", children: [
|
|
18129
18522
|
/* @__PURE__ */ jsx77(
|
|
@@ -18364,8 +18757,106 @@ function AgentsTabContent({
|
|
|
18364
18757
|
] });
|
|
18365
18758
|
}
|
|
18366
18759
|
|
|
18760
|
+
// src/components/QueuePanel.tsx
|
|
18761
|
+
import { ListOrdered, Trash2 as Trash26, X as X17 } from "lucide-react";
|
|
18762
|
+
import { useCallback as useCallback30 } from "react";
|
|
18763
|
+
import { jsx as jsx78, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
18764
|
+
function QueuePanel({ open, onClose, className }) {
|
|
18765
|
+
const queue = useChatStore((s) => s.queue);
|
|
18766
|
+
const removeQueued = useChatStore((s) => s.removeQueued);
|
|
18767
|
+
const clearQueue = useChatStore((s) => s.clearQueue);
|
|
18768
|
+
const handleRemove = useCallback30(
|
|
18769
|
+
(index) => {
|
|
18770
|
+
removeQueued(index);
|
|
18771
|
+
},
|
|
18772
|
+
[removeQueued]
|
|
18773
|
+
);
|
|
18774
|
+
if (!open) return null;
|
|
18775
|
+
return /* @__PURE__ */ jsx78(
|
|
18776
|
+
"div",
|
|
18777
|
+
{
|
|
18778
|
+
className: cn(
|
|
18779
|
+
"fixed inset-0 z-50 flex items-start justify-center pt-[10vh] bg-black/40 backdrop-blur-sm",
|
|
18780
|
+
className
|
|
18781
|
+
),
|
|
18782
|
+
onClick: (e) => {
|
|
18783
|
+
if (e.target === e.currentTarget) onClose();
|
|
18784
|
+
},
|
|
18785
|
+
children: /* @__PURE__ */ jsxs72("div", { className: "w-full max-w-lg rounded-xl border bg-card shadow-2xl max-h-[70vh] flex flex-col animate-in fade-in zoom-in-95", children: [
|
|
18786
|
+
/* @__PURE__ */ jsxs72("div", { className: "flex items-center justify-between px-4 py-3 border-b shrink-0", children: [
|
|
18787
|
+
/* @__PURE__ */ jsxs72("div", { className: "flex items-center gap-2.5", children: [
|
|
18788
|
+
/* @__PURE__ */ jsx78("span", { className: "flex items-center justify-center w-8 h-8 rounded-lg bg-indigo-500/10 text-indigo-600 dark:text-indigo-400", children: /* @__PURE__ */ jsx78(ListOrdered, { className: "h-4 w-4" }) }),
|
|
18789
|
+
/* @__PURE__ */ jsxs72("div", { children: [
|
|
18790
|
+
/* @__PURE__ */ jsx78("h2", { className: "text-sm font-semibold", children: "Message Queue" }),
|
|
18791
|
+
/* @__PURE__ */ jsxs72("span", { className: "text-[10px] text-muted-foreground tabular-nums", children: [
|
|
18792
|
+
queue.length,
|
|
18793
|
+
" queued \xB7 messages sent before the agent finishes"
|
|
18794
|
+
] })
|
|
18795
|
+
] })
|
|
18796
|
+
] }),
|
|
18797
|
+
/* @__PURE__ */ jsxs72("div", { className: "flex items-center gap-1", children: [
|
|
18798
|
+
queue.length > 0 && /* @__PURE__ */ jsxs72(
|
|
18799
|
+
"button",
|
|
18800
|
+
{
|
|
18801
|
+
type: "button",
|
|
18802
|
+
onClick: () => clearQueue(),
|
|
18803
|
+
className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs text-destructive hover:bg-destructive/10 transition-colors font-medium",
|
|
18804
|
+
title: "Clear all queued messages",
|
|
18805
|
+
children: [
|
|
18806
|
+
/* @__PURE__ */ jsx78(Trash26, { className: "h-3 w-3" }),
|
|
18807
|
+
"Clear"
|
|
18808
|
+
]
|
|
18809
|
+
}
|
|
18810
|
+
),
|
|
18811
|
+
/* @__PURE__ */ jsx78(
|
|
18812
|
+
"button",
|
|
18813
|
+
{
|
|
18814
|
+
type: "button",
|
|
18815
|
+
onClick: onClose,
|
|
18816
|
+
className: "p-1.5 rounded-md hover:bg-muted transition-colors",
|
|
18817
|
+
children: /* @__PURE__ */ jsx78(X17, { className: "h-4 w-4" })
|
|
18818
|
+
}
|
|
18819
|
+
)
|
|
18820
|
+
] })
|
|
18821
|
+
] }),
|
|
18822
|
+
/* @__PURE__ */ jsx78("div", { className: "flex-1 overflow-y-auto", children: queue.length === 0 ? /* @__PURE__ */ jsxs72("div", { className: "flex flex-col items-center justify-center py-16 gap-3 text-muted-foreground", children: [
|
|
18823
|
+
/* @__PURE__ */ jsx78(ListOrdered, { className: "h-10 w-10 opacity-15" }),
|
|
18824
|
+
/* @__PURE__ */ jsx78("p", { className: "text-sm font-medium", children: "Queue is empty" }),
|
|
18825
|
+
/* @__PURE__ */ jsx78("p", { className: "text-xs text-center max-w-xs", children: "Type messages while the agent is running to queue them. Queued messages are sent automatically when the agent finishes." })
|
|
18826
|
+
] }) : /* @__PURE__ */ jsx78("div", { className: "divide-y", children: queue.map((item, idx) => /* @__PURE__ */ jsxs72(
|
|
18827
|
+
"div",
|
|
18828
|
+
{
|
|
18829
|
+
className: "flex items-start justify-between px-4 py-3 text-xs hover:bg-muted/30 transition-colors",
|
|
18830
|
+
children: [
|
|
18831
|
+
/* @__PURE__ */ jsxs72("div", { className: "flex items-start gap-3 min-w-0 flex-1", children: [
|
|
18832
|
+
/* @__PURE__ */ jsxs72("span", { className: "mt-0.5 text-[10px] font-mono text-muted-foreground shrink-0 w-5 text-right", children: [
|
|
18833
|
+
idx + 1,
|
|
18834
|
+
"."
|
|
18835
|
+
] }),
|
|
18836
|
+
/* @__PURE__ */ jsx78("p", { className: "text-sm text-foreground leading-relaxed min-w-0 break-words", children: item.length > 120 ? `${item.slice(0, 117)}\u2026` : item })
|
|
18837
|
+
] }),
|
|
18838
|
+
/* @__PURE__ */ jsx78(
|
|
18839
|
+
"button",
|
|
18840
|
+
{
|
|
18841
|
+
type: "button",
|
|
18842
|
+
onClick: () => handleRemove(idx),
|
|
18843
|
+
className: "ml-3 p-1.5 rounded-md shrink-0 hover:bg-destructive/10 hover:text-destructive transition-colors",
|
|
18844
|
+
title: "Remove from queue",
|
|
18845
|
+
children: /* @__PURE__ */ jsx78(X17, { className: "h-3.5 w-3.5" })
|
|
18846
|
+
}
|
|
18847
|
+
)
|
|
18848
|
+
]
|
|
18849
|
+
},
|
|
18850
|
+
idx
|
|
18851
|
+
)) }) }),
|
|
18852
|
+
queue.length > 0 && /* @__PURE__ */ jsx78("div", { className: "px-4 py-2.5 border-t shrink-0", children: /* @__PURE__ */ jsx78("p", { className: "text-[10px] text-muted-foreground text-center", children: "Messages are sent in order when the current agent run completes." }) })
|
|
18853
|
+
] })
|
|
18854
|
+
}
|
|
18855
|
+
);
|
|
18856
|
+
}
|
|
18857
|
+
|
|
18367
18858
|
// src/App.tsx
|
|
18368
|
-
import { Fragment as
|
|
18859
|
+
import { Fragment as Fragment19, jsx as jsx79, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
18369
18860
|
function AppInner() {
|
|
18370
18861
|
const { theme } = useTheme();
|
|
18371
18862
|
const {
|
|
@@ -18380,7 +18871,11 @@ function AppInner() {
|
|
|
18380
18871
|
fleetMonitorOpen,
|
|
18381
18872
|
agentsMonitorOpen,
|
|
18382
18873
|
setFleetMonitorOpen,
|
|
18383
|
-
setAgentsMonitorOpen
|
|
18874
|
+
setAgentsMonitorOpen,
|
|
18875
|
+
processMonitorOpen,
|
|
18876
|
+
setProcessMonitorOpen,
|
|
18877
|
+
queuePanelOpen,
|
|
18878
|
+
setQueuePanelOpen
|
|
18384
18879
|
} = useUIStore();
|
|
18385
18880
|
const isLoading = useChatStore((s) => s.isLoading);
|
|
18386
18881
|
const iteration = useSessionStore((s) => s.iteration);
|
|
@@ -18388,7 +18883,7 @@ function AppInner() {
|
|
|
18388
18883
|
const sessionTitle = useSessionStore((s) => s.session?.title);
|
|
18389
18884
|
const sessionId = useSessionStore((s) => s.session?.id);
|
|
18390
18885
|
const nickname = useUIStore((s) => sessionId ? s.sessionNicknames[sessionId] : void 0);
|
|
18391
|
-
|
|
18886
|
+
useEffect46(() => {
|
|
18392
18887
|
const onOpenFile = (e) => {
|
|
18393
18888
|
const { filePath } = e.detail;
|
|
18394
18889
|
const ws = getWSClient(useConfigStore.getState().wsUrl);
|
|
@@ -18399,7 +18894,7 @@ function AppInner() {
|
|
|
18399
18894
|
window.addEventListener("wrongstack:open-file", onOpenFile);
|
|
18400
18895
|
return () => window.removeEventListener("wrongstack:open-file", onOpenFile);
|
|
18401
18896
|
}, []);
|
|
18402
|
-
|
|
18897
|
+
useEffect46(() => {
|
|
18403
18898
|
const onSaveFile = (e) => {
|
|
18404
18899
|
const { filePath } = e.detail;
|
|
18405
18900
|
const file = useFileStore.getState().openFiles.find((f) => f.path === filePath);
|
|
@@ -18415,7 +18910,7 @@ function AppInner() {
|
|
|
18415
18910
|
window.addEventListener("wrongstack:save-file", onSaveFile);
|
|
18416
18911
|
return () => window.removeEventListener("wrongstack:save-file", onSaveFile);
|
|
18417
18912
|
}, []);
|
|
18418
|
-
|
|
18913
|
+
useEffect46(() => {
|
|
18419
18914
|
if (typeof window === "undefined") return;
|
|
18420
18915
|
const mq = window.matchMedia("(max-width: 768px)");
|
|
18421
18916
|
const apply = () => {
|
|
@@ -18428,7 +18923,7 @@ function AppInner() {
|
|
|
18428
18923
|
return () => mq.removeEventListener("change", apply);
|
|
18429
18924
|
}, [setSidebarOpen]);
|
|
18430
18925
|
useWebSocketBootstrap();
|
|
18431
|
-
|
|
18926
|
+
useEffect46(() => {
|
|
18432
18927
|
const parts = [];
|
|
18433
18928
|
if (isLoading) {
|
|
18434
18929
|
const it = iteration ? ` iter ${iteration.index}${iteration.max ? `/${iteration.max}` : ""}` : "";
|
|
@@ -18445,7 +18940,7 @@ function AppInner() {
|
|
|
18445
18940
|
document.title = projectName || "AI Agent";
|
|
18446
18941
|
};
|
|
18447
18942
|
}, [isLoading, iteration, projectName, sessionTitle, nickname]);
|
|
18448
|
-
|
|
18943
|
+
useEffect46(() => {
|
|
18449
18944
|
const onKey = (e) => {
|
|
18450
18945
|
const t = e.target;
|
|
18451
18946
|
const tag = t?.tagName?.toLowerCase();
|
|
@@ -18573,41 +19068,43 @@ function AppInner() {
|
|
|
18573
19068
|
window.addEventListener("keydown", onKey);
|
|
18574
19069
|
return () => window.removeEventListener("keydown", onKey);
|
|
18575
19070
|
}, [toggleSidebar, setSearchOpen]);
|
|
18576
|
-
return /* @__PURE__ */
|
|
18577
|
-
currentView !== "setup" && /* @__PURE__ */
|
|
18578
|
-
sidebarOpen && currentView !== "setup" && /* @__PURE__ */
|
|
18579
|
-
/* @__PURE__ */
|
|
18580
|
-
currentView !== "setup" && /* @__PURE__ */
|
|
18581
|
-
currentView === "chat" && /* @__PURE__ */
|
|
18582
|
-
sessionId && /* @__PURE__ */
|
|
18583
|
-
/* @__PURE__ */
|
|
18584
|
-
/* @__PURE__ */
|
|
19071
|
+
return /* @__PURE__ */ jsxs73("div", { className: cn("flex h-screen", theme), children: [
|
|
19072
|
+
currentView !== "setup" && /* @__PURE__ */ jsx79(ActivityBar, {}),
|
|
19073
|
+
sidebarOpen && currentView !== "setup" && /* @__PURE__ */ jsx79(SidePanel, {}),
|
|
19074
|
+
/* @__PURE__ */ jsxs73("main", { className: "flex-1 flex flex-col overflow-hidden", children: [
|
|
19075
|
+
currentView !== "setup" && /* @__PURE__ */ jsx79(ConnectionBanner, {}),
|
|
19076
|
+
currentView === "chat" && /* @__PURE__ */ jsxs73(Fragment19, { children: [
|
|
19077
|
+
sessionId && /* @__PURE__ */ jsx79("div", { className: "px-4 pt-2", children: /* @__PURE__ */ jsx79(WorkspaceDock, { sessionId }) }),
|
|
19078
|
+
/* @__PURE__ */ jsx79(ChatView, {}),
|
|
19079
|
+
/* @__PURE__ */ jsx79(InspectorPanel, {})
|
|
18585
19080
|
] }),
|
|
18586
|
-
currentView === "settings" && /* @__PURE__ */
|
|
18587
|
-
currentView === "setup" && /* @__PURE__ */
|
|
18588
|
-
currentView === "autophase" && /* @__PURE__ */
|
|
18589
|
-
currentView === "agentflow" && /* @__PURE__ */
|
|
18590
|
-
currentView === "sessions" && /* @__PURE__ */
|
|
18591
|
-
currentView === "files" && /* @__PURE__ */
|
|
19081
|
+
currentView === "settings" && /* @__PURE__ */ jsx79(SettingsPanel, {}),
|
|
19082
|
+
currentView === "setup" && /* @__PURE__ */ jsx79(SetupScreen, {}),
|
|
19083
|
+
currentView === "autophase" && /* @__PURE__ */ jsx79(AutoPhaseView, { onClose: () => setCurrentView("chat") }),
|
|
19084
|
+
currentView === "agentflow" && /* @__PURE__ */ jsx79("div", { className: "flex-1 flex flex-col overflow-hidden", children: /* @__PURE__ */ jsx79(AgentFlowCanvasWithProvider, {}) }),
|
|
19085
|
+
currentView === "sessions" && /* @__PURE__ */ jsx79("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx79(SessionsDashboard, {}) }),
|
|
19086
|
+
currentView === "files" && /* @__PURE__ */ jsx79(CodeEditor, {})
|
|
18592
19087
|
] }),
|
|
18593
|
-
fleetMonitorOpen && /* @__PURE__ */
|
|
18594
|
-
agentsMonitorOpen && /* @__PURE__ */
|
|
18595
|
-
/* @__PURE__ */
|
|
18596
|
-
/* @__PURE__ */
|
|
18597
|
-
/* @__PURE__ */
|
|
18598
|
-
/* @__PURE__ */
|
|
18599
|
-
/* @__PURE__ */
|
|
18600
|
-
/* @__PURE__ */
|
|
19088
|
+
fleetMonitorOpen && /* @__PURE__ */ jsx79(FleetMonitor, { onClose: () => setFleetMonitorOpen(false) }),
|
|
19089
|
+
agentsMonitorOpen && /* @__PURE__ */ jsx79(AgentsMonitor, { onClose: () => setAgentsMonitorOpen(false) }),
|
|
19090
|
+
processMonitorOpen && /* @__PURE__ */ jsx79(ProcessMonitor, { open: processMonitorOpen, onClose: () => setProcessMonitorOpen(false) }),
|
|
19091
|
+
queuePanelOpen && /* @__PURE__ */ jsx79(QueuePanel, { open: queuePanelOpen, onClose: () => setQueuePanelOpen(false) }),
|
|
19092
|
+
/* @__PURE__ */ jsx79(ConfirmDialog, {}),
|
|
19093
|
+
/* @__PURE__ */ jsx79(ConfirmModalHost, {}),
|
|
19094
|
+
/* @__PURE__ */ jsx79(CommandPalette, {}),
|
|
19095
|
+
/* @__PURE__ */ jsx79(ShortcutsOverlay, {}),
|
|
19096
|
+
/* @__PURE__ */ jsx79(QuickModelSwitcher, {}),
|
|
19097
|
+
/* @__PURE__ */ jsx79(Toaster, {})
|
|
18601
19098
|
] });
|
|
18602
19099
|
}
|
|
18603
19100
|
function App() {
|
|
18604
|
-
return /* @__PURE__ */
|
|
19101
|
+
return /* @__PURE__ */ jsx79(ErrorBoundary, { children: /* @__PURE__ */ jsx79(ThemeProvider, { defaultTheme: "system", children: /* @__PURE__ */ jsx79(AppInner, {}) }) });
|
|
18605
19102
|
}
|
|
18606
19103
|
|
|
18607
19104
|
// src/main.tsx
|
|
18608
19105
|
import "./index.css";
|
|
18609
|
-
import { jsx as
|
|
19106
|
+
import { jsx as jsx80 } from "react/jsx-runtime";
|
|
18610
19107
|
ReactDOM.createRoot(expectDefined14(document.getElementById("root"))).render(
|
|
18611
|
-
/* @__PURE__ */
|
|
19108
|
+
/* @__PURE__ */ jsx80(React7.StrictMode, { children: /* @__PURE__ */ jsx80(App, {}) })
|
|
18612
19109
|
);
|
|
18613
19110
|
//# sourceMappingURL=index.js.map
|