@yieldfabric/terminal 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,15 @@
1
1
  "use client";
2
- import React12, { createContext, memo, useMemo, useRef, useEffect, useCallback, useContext, useState, useReducer } from 'react';
2
+ /*!
3
+ * Copyright (c) 2026 YieldFabric Technologies Ltd, DIFC, UAE.
4
+ * All rights reserved. Proprietary and confidential.
5
+ * Source review requires written authorization; see package LICENSE.md and NOTICE.md.
6
+ * Runtime use requires a separate express license.
7
+ */
8
+ import React15, { createContext, memo, useMemo, useRef, useEffect, useCallback, useContext, useState, useReducer } from 'react';
3
9
  import { X, Check, Plus, FileText, MessageCircle, ChevronRight, Paperclip, FolderOpen, Brain, XCircle, Loader2, Minimize2, Maximize2, AlertTriangle, HelpCircle, ChevronLeft, Pencil, ChevronDown, ExternalLink, Search, Network, Boxes, Settings, Terminal, CheckCircle, ArrowRight, Users, Eye, AlertCircle, CheckCircle2, Copy, Zap, Download, Trash2, Link2 } from 'lucide-react';
4
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
11
  import ReactMarkdown from 'react-markdown';
12
+ import remarkGfm from 'remark-gfm';
6
13
  import { createAvatar } from '@dicebear/core';
7
14
  import { avataaars } from '@dicebear/collection';
8
15
  import { motion } from 'framer-motion';
@@ -68,6 +75,7 @@ var BUILT_IN_COMMANDS = [
68
75
  { id: "files", label: "/files", description: "List uploaded files for this page working group", category: "built-in" },
69
76
  { id: "ask", label: "/ask", description: "Ask the AI assistant for analysis (streaming)", category: "built-in" },
70
77
  { id: "note", label: "/note", description: "Save a free-form note in this workspace. Type @name to link an entity.", category: "built-in" },
78
+ { id: "log", label: "/log", description: "Capture what you did or decided as a work item on this workspace\u2019s board.", category: "built-in" },
71
79
  { id: "personal", label: "/personal", description: "Save a free-form note in your personal notebook (visible only to you, even from a team workspace).", category: "built-in" }
72
80
  ];
73
81
  function getBuiltInCommands() {
@@ -89,23 +97,45 @@ function processStreamLines(buffer, onJsonLine) {
89
97
  for (const line of lines) {
90
98
  const trimmed = line.trim();
91
99
  if (!trimmed) continue;
92
- if (trimmed.startsWith("data: ")) {
93
- const jsonStr = trimmed.substring(6);
100
+ if (trimmed.startsWith("data:")) {
101
+ const jsonStr = trimmed.substring(5).trimStart();
102
+ let parsed2;
94
103
  try {
95
- onJsonLine(JSON.parse(jsonStr));
104
+ parsed2 = JSON.parse(jsonStr);
96
105
  } catch {
106
+ continue;
97
107
  }
108
+ onJsonLine(parsed2);
98
109
  continue;
99
110
  }
100
111
  if (trimmed.startsWith(":")) continue;
112
+ let parsed;
101
113
  try {
102
- onJsonLine(JSON.parse(trimmed));
114
+ parsed = JSON.parse(trimmed);
103
115
  } catch {
116
+ continue;
104
117
  }
118
+ onJsonLine(parsed);
105
119
  }
106
120
  return remainder;
107
121
  }
108
122
 
123
+ // src/utils/streamStall.ts
124
+ var SSE_KEEPALIVE_MS = 15e3;
125
+ var SSE_STALL_MS = SSE_KEEPALIVE_MS * 3;
126
+ async function withStallTimeout(work, ms = SSE_STALL_MS, sleep = (d) => new Promise((wake) => setTimeout(wake, d))) {
127
+ let done = false;
128
+ const settled = work.then((value) => {
129
+ done = true;
130
+ return value;
131
+ });
132
+ const stalled = sleep(ms).then(() => {
133
+ if (!done) throw new Error("the connection went quiet");
134
+ return void 0;
135
+ });
136
+ return Promise.race([settled, stalled]);
137
+ }
138
+
109
139
  // src/utils/streamingHandler.ts
110
140
  async function handleStreamingResponse(url, requestBody, onChunk, onComplete, onError) {
111
141
  try {
@@ -147,6 +177,14 @@ async function handleStreamingResponse(url, requestBody, onChunk, onComplete, on
147
177
  var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) => {
148
178
  const signal = options?.signal;
149
179
  const method = options?.method || "POST";
180
+ const stallMs = options?.stallMs ?? SSE_STALL_MS;
181
+ const stallAbort = new AbortController();
182
+ const abortFromCaller = () => stallAbort.abort();
183
+ let reader;
184
+ if (signal) {
185
+ if (signal.aborted) stallAbort.abort();
186
+ else signal.addEventListener("abort", abortFromCaller, { once: true });
187
+ }
150
188
  try {
151
189
  const requestHeaders = {
152
190
  Accept: "text/event-stream",
@@ -159,7 +197,7 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
159
197
  headers: requestHeaders,
160
198
  body: method === "GET" || method === "HEAD" ? void 0 : JSON.stringify(body),
161
199
  cache: "no-store",
162
- signal
200
+ signal: stallAbort.signal
163
201
  });
164
202
  if (response.status === 410 && options?.onGone) {
165
203
  options.onGone(await response.text());
@@ -169,19 +207,32 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
169
207
  const errorText = await response.text();
170
208
  throw new Error(`HTTP ${response.status}: ${errorText}`);
171
209
  }
172
- const reader = response.body?.getReader();
210
+ reader = response.body?.getReader();
173
211
  if (!reader) {
174
212
  throw new Error("No response body reader available");
175
213
  }
176
214
  const decoder = new TextDecoder();
177
215
  let buffer = "";
178
216
  let receivedData = false;
217
+ let finalSeen = false;
218
+ let failed = false;
219
+ const dispatch = (chunk) => {
220
+ if (failed) return;
221
+ if (chunk.error) {
222
+ failed = true;
223
+ onError(typeof chunk.error === "string" ? chunk.error : "The assistant could not finish this answer.");
224
+ return;
225
+ }
226
+ if (chunk.is_final === true) finalSeen = true;
227
+ onChunk(chunk);
228
+ };
179
229
  while (true) {
180
230
  let readResult;
181
231
  try {
182
- readResult = await reader.read();
232
+ readResult = stallMs > 0 ? await withStallTimeout(reader.read(), stallMs) : await reader.read();
183
233
  } catch (readError) {
184
234
  if (signal?.aborted) return;
235
+ stallAbort.abort();
185
236
  console.warn(
186
237
  "SSE reader error (connection may have been interrupted):",
187
238
  readError.message
@@ -195,16 +246,31 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
195
246
  }
196
247
  const { done, value } = readResult;
197
248
  if (done) {
198
- onComplete();
249
+ buffer += decoder.decode();
250
+ if (buffer.trim()) processStreamLines(buffer + "\n", dispatch);
251
+ if (failed) return;
252
+ if ((options?.requireFinal ?? true) && !finalSeen) {
253
+ onError("Connection interrupted before the answer was complete. The assistant may still be working.");
254
+ } else onComplete();
199
255
  break;
200
256
  }
201
257
  buffer += decoder.decode(value, { stream: true });
202
258
  receivedData = true;
203
- buffer = processStreamLines(buffer, onChunk);
259
+ buffer = processStreamLines(buffer, dispatch);
260
+ if (failed) return;
204
261
  }
205
262
  } catch (error) {
206
263
  if (signal?.aborted) return;
207
264
  onError(error.message || "Streaming error");
265
+ } finally {
266
+ signal?.removeEventListener("abort", abortFromCaller);
267
+ if (reader) {
268
+ try {
269
+ await reader.cancel();
270
+ } catch {
271
+ }
272
+ reader.releaseLock();
273
+ }
208
274
  }
209
275
  };
210
276
 
@@ -850,7 +916,7 @@ function ScopedReasoningProvider({
850
916
  () => ({ hasOwnedKgId }),
851
917
  [hasOwnedKgId]
852
918
  );
853
- return React12.createElement(
919
+ return React15.createElement(
854
920
  ScopedReasoningContext.Provider,
855
921
  { value },
856
922
  children
@@ -1079,12 +1145,13 @@ function ShareButton({ content, title }) {
1079
1145
  "button",
1080
1146
  {
1081
1147
  onClick: handleShare,
1082
- className: "p-1 rounded-md transition-all duration-200 hover:scale-110",
1148
+ className: "inline-flex h-6 w-6 items-center justify-center rounded-md transition-all duration-200 hover:scale-110",
1083
1149
  style: {
1084
1150
  backgroundColor: done ? "rgba(74,222,128,0.15)" : t.bgRaisedHover,
1085
1151
  color: done ? t.success : t.textMuted
1086
1152
  },
1087
1153
  title: state === "copied" ? "Copied!" : state === "shared" ? "Shared!" : "Share",
1154
+ "aria-label": state === "copied" ? "Link copied" : state === "shared" ? "Shared" : "Share message",
1088
1155
  children: done ? /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M5 12l5 5L20 7" }) }) : /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1089
1156
  /* @__PURE__ */ jsx("path", { d: "M4 12v7a2 2 0 002 2h12a2 2 0 002-2v-7" }),
1090
1157
  /* @__PURE__ */ jsx("polyline", { points: "16 6 12 2 8 6" }),
@@ -1093,11 +1160,30 @@ function ShareButton({ content, title }) {
1093
1160
  }
1094
1161
  );
1095
1162
  }
1163
+
1164
+ // src/utils/stripInternalIds.ts
1165
+ var UUID = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
1166
+ var PREFIXED = `(?:KG|DOC|FRAME|SET|NODE|CHUNK):${UUID}`;
1167
+ var WRAP = "[*_`]*";
1168
+ var PAREN_PREFIXED = new RegExp(`\\s*\\(\\s*${WRAP}${PREFIXED}${WRAP}\\s*\\)`, "g");
1169
+ var PAREN_BARE = new RegExp(`\\s*\\(\\s*${WRAP}${UUID}${WRAP}\\s*\\)`, "g");
1170
+ var BARE_PREFIXED = new RegExp(`${WRAP}${PREFIXED}${WRAP}`, "g");
1171
+ var ID_PHRASE = new RegExp(
1172
+ `\\s*(?:\\(\\s*)?(?:for\\s+|with\\s+)?(?:suggestion|proposal|item|thread|entity|message|document)\\s+id[:\\s]+${WRAP}${UUID}${WRAP}(?:\\s*\\))?`,
1173
+ "gi"
1174
+ );
1175
+ var BARE_UUID = new RegExp(`${WRAP}${UUID}${WRAP}`, "g");
1176
+ function stripInternalIds(text) {
1177
+ if (!text || !/(?:KG|DOC|FRAME|SET|NODE|CHUNK):|-[0-9a-fA-F]{4}-/.test(text)) return text;
1178
+ return text.split(/(```[\s\S]*?```)/g).map(
1179
+ (part) => part.startsWith("```") ? part : part.replace(PAREN_PREFIXED, "").replace(PAREN_BARE, "").replace(BARE_PREFIXED, "").replace(ID_PHRASE, "").replace(BARE_UUID, "").replace(/[ \t]+([,.;:)])/g, "$1").replace(/([^\n ]) {2,}(?=\S)/g, "$1 ")
1180
+ ).join("");
1181
+ }
1096
1182
  function TimestampRenderer({ timestamp }) {
1097
1183
  const t = useTheme();
1098
1184
  const [timeString, setTimeString] = useState("");
1099
1185
  useEffect(() => {
1100
- setTimeString(timestamp.toLocaleTimeString());
1186
+ setTimeString(timestamp.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }));
1101
1187
  }, [timestamp]);
1102
1188
  return /* @__PURE__ */ jsx("div", { className: "text-xs ml-6 mt-1", style: { color: t.textMuted }, children: timeString });
1103
1189
  }
@@ -1118,20 +1204,20 @@ async function gql(url, token, query, variables) {
1118
1204
  return res.json();
1119
1205
  }
1120
1206
  function InteractiveActionCard({
1121
- action,
1207
+ action: action2,
1122
1208
  onExecute,
1123
1209
  graphqlUrl = "",
1124
1210
  authToken = ""
1125
1211
  }) {
1126
1212
  const t = useTheme();
1127
1213
  const initialValues = useMemo(() => {
1128
- const amount2 = action.metadata?.formatted_amount || (action.payload?.arguments?.amount && action.payload.arguments.amount !== "0" ? action.payload.arguments.amount : "") || "";
1129
- const assetId = action.payload?.arguments?.asset_id || "";
1130
- const entityId = action.payload?.arguments?.destination_id || "";
1131
- const walletId = action.payload?.arguments?.destination_wallet_id || "";
1214
+ const amount2 = action2.metadata?.formatted_amount || (action2.payload?.arguments?.amount && action2.payload.arguments.amount !== "0" ? action2.payload.arguments.amount : "") || "";
1215
+ const assetId = action2.payload?.arguments?.asset_id || "";
1216
+ const entityId = action2.payload?.arguments?.destination_id || "";
1217
+ const walletId = action2.payload?.arguments?.destination_wallet_id || "";
1132
1218
  return { amount: amount2, assetId, entityId, walletId };
1133
- }, [action]);
1134
- const [editedAction, setEditedAction] = useState(action);
1219
+ }, [action2]);
1220
+ const [editedAction, setEditedAction] = useState(action2);
1135
1221
  const [entities, setEntities] = useState([]);
1136
1222
  const [wallets, setWallets] = useState([]);
1137
1223
  const [assets, setAssets] = useState([]);
@@ -1245,14 +1331,14 @@ function InteractiveActionCard({
1245
1331
  [assets, entities, wallets]
1246
1332
  );
1247
1333
  useEffect(() => {
1248
- if (action.payload?.tool_name === "yieldfabric/send_instant_payment") {
1334
+ if (action2.payload?.tool_name === "yieldfabric/send_instant_payment") {
1249
1335
  fetchEntities();
1250
1336
  fetchAssets();
1251
1337
  if (initialValues.entityId) fetchWallets(initialValues.entityId);
1252
1338
  }
1253
1339
  }, []);
1254
1340
  useEffect(() => {
1255
- if (selectedEntityId && action.payload?.tool_name === "yieldfabric/send_instant_payment") {
1341
+ if (selectedEntityId && action2.payload?.tool_name === "yieldfabric/send_instant_payment") {
1256
1342
  const shouldFetch = selectedEntityId !== initialValues.entityId || wallets.length === 0;
1257
1343
  if (shouldFetch) fetchWallets(selectedEntityId);
1258
1344
  if (selectedEntityId !== initialValues.entityId) {
@@ -1262,14 +1348,14 @@ function InteractiveActionCard({
1262
1348
  }
1263
1349
  }, [selectedEntityId]);
1264
1350
  useEffect(() => {
1265
- if (action.payload?.tool_name !== "yieldfabric/send_instant_payment") return;
1351
+ if (action2.payload?.tool_name !== "yieldfabric/send_instant_payment") return;
1266
1352
  if (initialValues.assetId && assets.length > 0) {
1267
1353
  const match = assets.find((a) => a.id === initialValues.assetId) || assets.find(
1268
1354
  (a) => a.id.toUpperCase() === initialValues.assetId.toUpperCase()
1269
1355
  ) || assets.find(
1270
1356
  (a) => initialValues.assetId.toUpperCase() === "CBDC" && a.name?.toUpperCase().includes("CBDC")
1271
- ) || action.metadata?.asset_id && assets.find(
1272
- (a) => a.id === action.metadata.asset_id || a.id.toUpperCase() === action.metadata.asset_id.toUpperCase()
1357
+ ) || action2.metadata?.asset_id && assets.find(
1358
+ (a) => a.id === action2.metadata.asset_id || a.id.toUpperCase() === action2.metadata.asset_id.toUpperCase()
1273
1359
  );
1274
1360
  if (match && selectedAssetId !== match.id) {
1275
1361
  setSelectedAssetId(match.id);
@@ -1293,11 +1379,11 @@ function InteractiveActionCard({
1293
1379
  updateActionField("amount", initialValues.amount);
1294
1380
  }
1295
1381
  }, [assets, entities, wallets]);
1296
- if (action.payload?.tool_name === "yieldfabric/swap_credit_for_cash") {
1382
+ if (action2.payload?.tool_name === "yieldfabric/swap_credit_for_cash") {
1297
1383
  return /* @__PURE__ */ jsx(
1298
1384
  RedeemCreditCard,
1299
1385
  {
1300
- action,
1386
+ action: action2,
1301
1387
  onExecute,
1302
1388
  graphqlUrl,
1303
1389
  authToken,
@@ -1308,20 +1394,20 @@ function InteractiveActionCard({
1308
1394
  }
1309
1395
  );
1310
1396
  }
1311
- if (action.payload?.tool_name === "yieldfabric/complete_swap") {
1312
- return /* @__PURE__ */ jsx(CompleteSwapCard, { action, onExecute });
1397
+ if (action2.payload?.tool_name === "yieldfabric/complete_swap") {
1398
+ return /* @__PURE__ */ jsx(CompleteSwapCard, { action: action2, onExecute });
1313
1399
  }
1314
- if (action.payload?.tool_name === "yieldfabric/accept_payment") {
1315
- return /* @__PURE__ */ jsx(AcceptPaymentCard, { action, onExecute });
1400
+ if (action2.payload?.tool_name === "yieldfabric/accept_payment") {
1401
+ return /* @__PURE__ */ jsx(AcceptPaymentCard, { action: action2, onExecute });
1316
1402
  }
1317
- if (action.action_type === "file_controls") {
1318
- return /* @__PURE__ */ jsx(FileControlsCard, { action, onExecute });
1403
+ if (action2.action_type === "file_controls") {
1404
+ return /* @__PURE__ */ jsx(FileControlsCard, { action: action2, onExecute });
1319
1405
  }
1320
- if (action.action_type === "download_source") {
1321
- return /* @__PURE__ */ jsx(DownloadSourceCard, { action, onExecute });
1406
+ if (action2.action_type === "download_source") {
1407
+ return /* @__PURE__ */ jsx(DownloadSourceCard, { action: action2, onExecute });
1322
1408
  }
1323
- if (action.payload?.tool_name !== "yieldfabric/send_instant_payment") {
1324
- return /* @__PURE__ */ jsx(GenericActionCard, { action, onExecute });
1409
+ if (action2.payload?.tool_name !== "yieldfabric/send_instant_payment") {
1410
+ return /* @__PURE__ */ jsx(GenericActionCard, { action: action2, onExecute });
1325
1411
  }
1326
1412
  return /* @__PURE__ */ jsxs(
1327
1413
  "div",
@@ -1468,7 +1554,7 @@ function InteractiveActionCard({
1468
1554
  );
1469
1555
  }
1470
1556
  function RedeemCreditCard({
1471
- action,
1557
+ action: action2,
1472
1558
  onExecute,
1473
1559
  graphqlUrl,
1474
1560
  authToken,
@@ -1478,14 +1564,14 @@ function RedeemCreditCard({
1478
1564
  setLoadingObligor
1479
1565
  }) {
1480
1566
  const t = useTheme();
1481
- const metadata = action.metadata || {};
1567
+ const metadata = action2.metadata || {};
1482
1568
  const formattedAmount = metadata.formatted_amount || metadata.amount || "0.00";
1483
1569
  const currency = metadata.currency || "Unknown";
1484
1570
  const obligor = metadata.obligor || metadata.obligor_id || "Unknown";
1485
1571
  const obligorId = metadata.obligor_id || obligor;
1486
1572
  const assetDisplay = formatAssetDisplay(metadata, currency);
1487
1573
  useEffect(() => {
1488
- if (action.payload?.tool_name !== "yieldfabric/swap_credit_for_cash") return;
1574
+ if (action2.payload?.tool_name !== "yieldfabric/swap_credit_for_cash") return;
1489
1575
  if (obligorId === "Unknown" || obligor.includes("@")) return;
1490
1576
  if (metadata.obligor_name && metadata.obligor_name !== obligorId && !obligorId.includes("-"))
1491
1577
  return;
@@ -1516,7 +1602,7 @@ function RedeemCreditCard({
1516
1602
  setLoadingObligor(false);
1517
1603
  }
1518
1604
  })();
1519
- }, [obligorId, action.payload?.tool_name]);
1605
+ }, [obligorId, action2.payload?.tool_name]);
1520
1606
  const obligorDisplay = (() => {
1521
1607
  if (obligorEntity?.name) return obligorEntity.name;
1522
1608
  if (metadata.obligor_name && metadata.obligor_name !== obligorId && metadata.obligor_name !== obligor)
@@ -1568,7 +1654,7 @@ function RedeemCreditCard({
1568
1654
  onClick: (e) => {
1569
1655
  e.preventDefault();
1570
1656
  e.stopPropagation();
1571
- onExecute(action);
1657
+ onExecute(action2);
1572
1658
  },
1573
1659
  className: "w-full py-2 px-4 text-sm font-medium rounded transition-colors flex items-center justify-center gap-2",
1574
1660
  style: { backgroundColor: t.success, color: t.textInverse },
@@ -1583,12 +1669,12 @@ function RedeemCreditCard({
1583
1669
  );
1584
1670
  }
1585
1671
  function CompleteSwapCard({
1586
- action,
1672
+ action: action2,
1587
1673
  onExecute
1588
1674
  }) {
1589
1675
  const t = useTheme();
1590
- const metadata = action.metadata || {};
1591
- const swapId = metadata.swap_id || action.payload?.arguments?.swap_id || "Unknown";
1676
+ const metadata = action2.metadata || {};
1677
+ const swapId = metadata.swap_id || action2.payload?.arguments?.swap_id || "Unknown";
1592
1678
  const initiator = metadata.initiator || "Unknown";
1593
1679
  const status = metadata.status || "PENDING";
1594
1680
  const deadline = metadata.deadline ? new Date(metadata.deadline).toLocaleString() : "N/A";
@@ -1650,7 +1736,7 @@ function CompleteSwapCard({
1650
1736
  onClick: (e) => {
1651
1737
  e.preventDefault();
1652
1738
  e.stopPropagation();
1653
- onExecute(action);
1739
+ onExecute(action2);
1654
1740
  },
1655
1741
  className: "w-full py-2 px-4 text-sm font-medium rounded transition-colors flex items-center justify-center gap-2",
1656
1742
  style: { backgroundColor: t.success, color: t.textInverse },
@@ -1692,11 +1778,11 @@ function PaymentLeg({
1692
1778
  ] });
1693
1779
  }
1694
1780
  function AcceptPaymentCard({
1695
- action,
1781
+ action: action2,
1696
1782
  onExecute
1697
1783
  }) {
1698
1784
  const t = useTheme();
1699
- const metadata = action.metadata || {};
1785
+ const metadata = action2.metadata || {};
1700
1786
  const formattedAmount = metadata.formatted_amount || metadata.amount || "0.00";
1701
1787
  const currency = metadata.currency || "Unknown";
1702
1788
  const from = metadata.from || "Unknown";
@@ -1756,7 +1842,7 @@ function AcceptPaymentCard({
1756
1842
  onClick: (e) => {
1757
1843
  e.preventDefault();
1758
1844
  e.stopPropagation();
1759
- onExecute(action);
1845
+ onExecute(action2);
1760
1846
  },
1761
1847
  className: "w-full py-1.5 px-3 text-xs font-medium rounded transition-colors flex items-center justify-center gap-1.5 mt-auto",
1762
1848
  style: { backgroundColor: t.success, color: t.textInverse },
@@ -1771,12 +1857,12 @@ function AcceptPaymentCard({
1771
1857
  );
1772
1858
  }
1773
1859
  function FileControlsCard({
1774
- action,
1860
+ action: action2,
1775
1861
  onExecute
1776
1862
  }) {
1777
1863
  const t = useTheme();
1778
- const title = action.payload?.title || "Document";
1779
- const documentId = action.payload?.document_id;
1864
+ const title = action2.payload?.title || "Document";
1865
+ const documentId = action2.payload?.document_id;
1780
1866
  const doDownload = (e) => {
1781
1867
  e.preventDefault();
1782
1868
  e.stopPropagation();
@@ -1835,18 +1921,18 @@ function FileControlsCard({
1835
1921
  );
1836
1922
  }
1837
1923
  function DownloadSourceCard({
1838
- action,
1924
+ action: action2,
1839
1925
  onExecute
1840
1926
  }) {
1841
1927
  const t = useTheme();
1842
- const title = action.payload?.title || action.metadata?.display_text || action.description || "Document";
1928
+ const title = action2.payload?.title || action2.metadata?.display_text || action2.description || "Document";
1843
1929
  return /* @__PURE__ */ jsx(
1844
1930
  "button",
1845
1931
  {
1846
1932
  onClick: (e) => {
1847
1933
  e.preventDefault();
1848
1934
  e.stopPropagation();
1849
- onExecute(action);
1935
+ onExecute(action2);
1850
1936
  },
1851
1937
  className: "relative overflow-hidden w-full p-3 rounded-lg transition-all duration-200 text-left group",
1852
1938
  style: { backgroundColor: t.buttonBg, border: `1px solid ${t.border}` },
@@ -1866,7 +1952,7 @@ function DownloadSourceCard({
1866
1952
  );
1867
1953
  }
1868
1954
  function GenericActionCard({
1869
- action,
1955
+ action: action2,
1870
1956
  onExecute
1871
1957
  }) {
1872
1958
  const t = useTheme();
@@ -1876,14 +1962,14 @@ function GenericActionCard({
1876
1962
  onClick: (e) => {
1877
1963
  e.preventDefault();
1878
1964
  e.stopPropagation();
1879
- onExecute(action);
1965
+ onExecute(action2);
1880
1966
  },
1881
1967
  className: "flex items-center space-x-3 p-3 rounded-lg transition-colors text-left group",
1882
1968
  style: { backgroundColor: GREEN_ACTION.bg, border: GREEN_ACTION.borderStyle },
1883
1969
  onMouseEnter: (e) => e.currentTarget.style.backgroundColor = GREEN_ACTION.bgHover,
1884
1970
  onMouseLeave: (e) => e.currentTarget.style.backgroundColor = GREEN_ACTION.bg,
1885
1971
  children: [
1886
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "font-medium text-sm mb-1.5", style: { color: t.success }, children: action.metadata?.display_text || action.description || `Execute ${action.action_type}` }) }),
1972
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "font-medium text-sm mb-1.5", style: { color: t.success }, children: action2.metadata?.display_text || action2.description || `Execute ${action2.action_type}` }) }),
1887
1973
  /* @__PURE__ */ jsx(ArrowRight, { className: "w-5 h-5 transition-colors flex-shrink-0 ml-2", style: { color: t.success } })
1888
1974
  ]
1889
1975
  }
@@ -2131,13 +2217,29 @@ function CopyButton({ content }) {
2131
2217
  "button",
2132
2218
  {
2133
2219
  onClick: handleCopy,
2134
- className: "p-1 rounded transition-colors hover:scale-110",
2220
+ className: "inline-flex h-6 w-6 items-center justify-center rounded transition-colors hover:scale-110",
2135
2221
  style: { backgroundColor: t.bgRaisedHover, color: t.textSecondary },
2136
2222
  title: "Copy",
2223
+ "aria-label": copied ? "Copied" : "Copy message",
2137
2224
  children: copied ? /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5", style: { color: t.success } }) : /* @__PURE__ */ jsx(Copy, { className: "w-3.5 h-3.5" })
2138
2225
  }
2139
2226
  );
2140
2227
  }
2228
+ function AgentCompletionNotice({ completion }) {
2229
+ const t = useTheme();
2230
+ if (!completion || completion.stop_reason === "answered") return null;
2231
+ const message = {
2232
+ rounds_exhausted: "Partial answer \u2014 I reached the step limit. Ask a narrower follow-up to continue.",
2233
+ budget_exhausted: "Partial answer \u2014 this question needs more context than fits in one answer. Try narrowing the question.",
2234
+ awaiting_tool_results: "This answer paused before its next step. Ask again to review a fresh answer.",
2235
+ empty: "No answer was returned. Please try again.",
2236
+ failed: "The answer could not be completed. What arrived so far is kept here.",
2237
+ interrupted: "Connection interrupted. The assistant may still be working; check the conversation before sending again.",
2238
+ cancelled: "Stopped. You can change your question and ask again."
2239
+ }[completion.stop_reason];
2240
+ if (!message) return null;
2241
+ return /* @__PURE__ */ jsx("p", { role: "status", className: "mt-2 rounded-md px-3 py-2 text-xs", style: { color: t.textSecondary, backgroundColor: t.bgRaisedAlt, border: `1px solid ${t.border}` }, children: message });
2242
+ }
2141
2243
  var AGENT_PALETTE = [
2142
2244
  "a78bfa",
2143
2245
  // violet-400
@@ -2213,7 +2315,7 @@ function TimeLabel({ timestamp }) {
2213
2315
  const t = useTheme();
2214
2316
  const [timeStr, setTimeStr] = useState("");
2215
2317
  useEffect(() => {
2216
- setTimeStr(timestamp.toLocaleTimeString());
2318
+ setTimeStr(timestamp.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }));
2217
2319
  }, [timestamp]);
2218
2320
  return /* @__PURE__ */ jsx("span", { className: "text-[10px] mt-0.5", style: { color: t.textSecondary }, children: timeStr });
2219
2321
  }
@@ -2531,7 +2633,10 @@ function hashTypeColor(type) {
2531
2633
  for (let i = 0; i < type.length; i++) h = (h << 5) - h + type.charCodeAt(i) | 0;
2532
2634
  return SOURCE_TYPE_PALETTE[Math.abs(h) % SOURCE_TYPE_PALETTE.length];
2533
2635
  }
2534
- function SourceCard({ source }) {
2636
+ function SourceCard({
2637
+ source,
2638
+ onActivate
2639
+ }) {
2535
2640
  const t = useTheme();
2536
2641
  const [expanded, setExpanded] = useState(false);
2537
2642
  const showType = source.type && source.type.toLowerCase() !== "unknown";
@@ -2539,13 +2644,25 @@ function SourceCard({ source }) {
2539
2644
  const displayLabel = formatSourceLabel(source.label);
2540
2645
  return /* @__PURE__ */ jsxs("div", { className: "rounded", style: { border: `1px solid ${t.border}`, backgroundColor: t.bgRaisedAlt }, children: [
2541
2646
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-1.5", children: [
2542
- source.description ? /* @__PURE__ */ jsx("button", { onClick: () => setExpanded(!expanded), className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
2543
- ChevronRight,
2647
+ source.description ? /* @__PURE__ */ jsx(
2648
+ "button",
2544
2649
  {
2545
- className: "w-3 h-3 transition-transform",
2546
- style: { color: t.textMuted, transform: expanded ? "rotate(90deg)" : "none" }
2650
+ type: "button",
2651
+ onClick: (event) => {
2652
+ event.stopPropagation();
2653
+ setExpanded(!expanded);
2654
+ },
2655
+ className: "flex-shrink-0 rounded-sm focus:outline-none focus-visible:ring-2",
2656
+ "aria-label": expanded ? `Collapse ${displayLabel} details` : `Expand ${displayLabel} details`,
2657
+ children: /* @__PURE__ */ jsx(
2658
+ ChevronRight,
2659
+ {
2660
+ className: "w-3 h-3 transition-transform",
2661
+ style: { color: t.textMuted, transform: expanded ? "rotate(90deg)" : "none" }
2662
+ }
2663
+ )
2547
2664
  }
2548
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-3 h-3 flex-shrink-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full", style: { backgroundColor: badgeColor } }) }),
2665
+ ) : /* @__PURE__ */ jsx("div", { className: "w-3 h-3 flex-shrink-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full", style: { backgroundColor: badgeColor } }) }),
2549
2666
  showType && /* @__PURE__ */ jsx(
2550
2667
  "span",
2551
2668
  {
@@ -2554,11 +2671,28 @@ function SourceCard({ source }) {
2554
2671
  children: source.type
2555
2672
  }
2556
2673
  ),
2557
- /* @__PURE__ */ jsx("span", { className: "text-[11px] truncate flex-1", style: { color: t.text }, children: displayLabel })
2674
+ onActivate ? /* @__PURE__ */ jsx(
2675
+ "button",
2676
+ {
2677
+ type: "button",
2678
+ className: "text-[11px] truncate flex-1 cursor-pointer text-left rounded-sm hover:underline focus:outline-none focus-visible:ring-2",
2679
+ style: { color: t.text },
2680
+ onClick: (event) => {
2681
+ event.stopPropagation();
2682
+ onActivate(source);
2683
+ },
2684
+ "aria-label": `Open ${displayLabel}`,
2685
+ children: displayLabel
2686
+ }
2687
+ ) : /* @__PURE__ */ jsx("span", { className: "text-[11px] truncate flex-1", style: { color: t.text }, children: displayLabel })
2558
2688
  ] }),
2559
2689
  expanded && source.description && /* @__PURE__ */ jsx("div", { className: "px-2.5 pb-2 text-[10px] leading-relaxed", style: { color: t.textSecondary, borderTop: `1px solid ${t.border}` }, children: source.description })
2560
2690
  ] });
2561
2691
  }
2692
+ var REMARK_PLUGINS = [remarkGfm];
2693
+ function isBlockCode(className, text) {
2694
+ return /language-/.test(typeof className === "string" ? className : "") || text.includes("\n");
2695
+ }
2562
2696
  function getMarkdownComponents(t) {
2563
2697
  return {
2564
2698
  h1: ({ node, ...props }) => /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold mt-4 mb-2", style: { color: t.headingText }, ...props }),
@@ -2570,10 +2704,38 @@ function getMarkdownComponents(t) {
2570
2704
  li: ({ node, ...props }) => /* @__PURE__ */ jsx("li", { className: "ml-2", ...props }),
2571
2705
  strong: ({ node, ...props }) => /* @__PURE__ */ jsx("strong", { className: "font-bold", style: { color: t.text }, ...props }),
2572
2706
  em: ({ node, ...props }) => /* @__PURE__ */ jsx("em", { className: "italic", style: { color: t.textSecondary }, ...props }),
2573
- code: ({ node, inline, children, ...props }) => inline ? /* @__PURE__ */ jsx("code", { className: "px-1 py-0.5 rounded font-mono text-xs", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children }) : /* @__PURE__ */ jsxs("div", { className: "relative group/code", children: [
2574
- /* @__PURE__ */ jsx(CopyButton, { content: String(children || "") }),
2575
- /* @__PURE__ */ jsx("code", { className: "block p-2 rounded my-2 font-mono text-xs overflow-x-auto", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children })
2576
- ] })
2707
+ code: ({ node, inline, children, ...props }) => {
2708
+ const text = String(children ?? "");
2709
+ const isInline = inline ?? !isBlockCode(props.className, text);
2710
+ return isInline ? /* @__PURE__ */ jsx("code", { className: "px-1 py-0.5 rounded font-mono text-xs", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children }) : /* @__PURE__ */ jsxs("div", { className: "relative group/code", children: [
2711
+ /* @__PURE__ */ jsx(CopyButton, { content: text }),
2712
+ /* @__PURE__ */ jsx("code", { className: "block p-2 rounded my-2 font-mono text-xs overflow-x-auto", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children })
2713
+ ] });
2714
+ },
2715
+ // Tables are why remark-gfm is here. The wrapper is not decoration:
2716
+ // this renders inside a chat rail the user can drag down to ~360px,
2717
+ // and a table holding a term plus a few numbers will exceed that. It
2718
+ // has to scroll INSIDE its own box — without the wrapper the reply
2719
+ // column itself widens and every other line in the conversation
2720
+ // starts scrolling sideways along with it.
2721
+ table: ({ node, ...p }) => /* @__PURE__ */ jsx(
2722
+ "div",
2723
+ {
2724
+ className: "my-2 max-w-full overflow-x-auto rounded",
2725
+ style: { border: `1px solid ${t.codeBg}` },
2726
+ children: /* @__PURE__ */ jsx("table", { className: "w-full border-collapse text-xs", ...p })
2727
+ }
2728
+ ),
2729
+ thead: ({ node, ...p }) => /* @__PURE__ */ jsx("thead", { style: { backgroundColor: t.codeBg }, ...p }),
2730
+ th: ({ node, ...p }) => /* @__PURE__ */ jsx(
2731
+ "th",
2732
+ {
2733
+ className: "px-2.5 py-1.5 text-left font-semibold whitespace-nowrap",
2734
+ style: { color: t.headingText, borderBottom: `1px solid ${t.codeBg}` },
2735
+ ...p
2736
+ }
2737
+ ),
2738
+ td: ({ node, ...p }) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top", style: { borderBottom: `1px solid ${t.codeBg}` }, ...p })
2577
2739
  };
2578
2740
  }
2579
2741
  function TerminalEntryRenderer({
@@ -2588,6 +2750,7 @@ function TerminalEntryRenderer({
2588
2750
  authToken,
2589
2751
  onPageNavigation,
2590
2752
  onSourcesActivate,
2753
+ onSourceActivate,
2591
2754
  renderEntryExtra,
2592
2755
  renderEntry,
2593
2756
  widgets,
@@ -2605,7 +2768,7 @@ function TerminalEntryRenderer({
2605
2768
  const isError = entry.type === "error";
2606
2769
  const isSuccess = entry.type === "success";
2607
2770
  const isEmpty = !entry.content || entry.content.trim() === "";
2608
- const useAttribution = isCollaborative && entry.sender && !isSystem && !isEmpty;
2771
+ const useAttribution = (isCollaborative || entry.sender?.type === "agent") && entry.sender && !isSystem && !isEmpty;
2609
2772
  const isGrouped = useAttribution && !!prevEntry?.sender && !!entry.sender && prevEntry.sender.entity_id === entry.sender.entity_id && prevEntry.sender.type === entry.sender.type && !(!prevEntry.content || prevEntry.content.trim() === "") && entry.timestamp.getTime() - prevEntry.timestamp.getTime() < 5 * 60 * 1e3 && prevEntry.type !== "system";
2610
2773
  const beforeWidgets = widgets?.filter((w) => w.position === "before" && w.match(entry)) || [];
2611
2774
  const afterWidgets = widgets?.filter((w) => (!w.position || w.position === "after") && w.match(entry)) || [];
@@ -2618,12 +2781,12 @@ function TerminalEntryRenderer({
2618
2781
  timestamp: entry.timestamp,
2619
2782
  isOwnMessage: entry.sender.entity_id === currentUser?.entity_id,
2620
2783
  grouped: isGrouped,
2621
- children: entry.sender?.type === "agent" ? /* @__PURE__ */ jsxs("div", { className: "text-sm prose prose-invert prose-sm max-w-none group relative", style: { color: t.text }, children: [
2784
+ children: entry.sender?.type === "agent" ? /* @__PURE__ */ jsxs("div", { className: "text-sm prose prose-invert prose-sm max-w-[72ch] group relative", style: { color: t.text }, children: [
2622
2785
  /* @__PURE__ */ jsxs("div", { className: "absolute -top-9 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
2623
2786
  /* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
2624
2787
  /* @__PURE__ */ jsx(ShareButton, { content: entry.content })
2625
2788
  ] }),
2626
- /* @__PURE__ */ jsx(ReactMarkdown, { components: markdownComponents, children: entry.content })
2789
+ /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: REMARK_PLUGINS, components: markdownComponents, children: stripInternalIds(entry.content) })
2627
2790
  ] }) : /* @__PURE__ */ jsxs("div", { className: "text-sm whitespace-pre-wrap group relative", style: { color: isError ? t.error : t.text }, children: [
2628
2791
  /* @__PURE__ */ jsxs("div", { className: "absolute -top-9 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
2629
2792
  /* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
@@ -2634,7 +2797,6 @@ function TerminalEntryRenderer({
2634
2797
  }
2635
2798
  ) : /* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-2", children: [
2636
2799
  isSystem && !isEmpty && /* @__PURE__ */ jsx(Terminal, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.textSystem } }),
2637
- isCommand && !isEmpty && /* @__PURE__ */ jsx(Brain, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.info } }),
2638
2800
  isInfo && !isEmpty && /* @__PURE__ */ jsx(CheckCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.info } }),
2639
2801
  isSuccess && !isEmpty && /* @__PURE__ */ jsx(CheckCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.success } }),
2640
2802
  isError && !isEmpty && /* @__PURE__ */ jsx(XCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.error } }),
@@ -2647,12 +2809,30 @@ function TerminalEntryRenderer({
2647
2809
  /* @__PURE__ */ jsx(
2648
2810
  ReactMarkdown,
2649
2811
  {
2812
+ remarkPlugins: REMARK_PLUGINS,
2650
2813
  components: markdownComponents,
2651
- children: entry.content
2814
+ children: stripInternalIds(entry.content)
2652
2815
  },
2653
2816
  `${entry.id || index}-${entry.content.length}`
2654
2817
  )
2655
- ] }) : /* @__PURE__ */ jsxs("div", { className: "group relative", children: [
2818
+ ] }) : isCommand && !isSystem ? (
2819
+ // What the person typed: a quiet bubble on the right, the way the
2820
+ // console shows it — not a monospace line that reads as a log.
2821
+ /* @__PURE__ */ jsxs("div", { className: "group relative flex w-full flex-1 justify-end", children: [
2822
+ /* @__PURE__ */ jsxs("div", { className: "absolute -top-5 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
2823
+ /* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
2824
+ /* @__PURE__ */ jsx(ShareButton, { content: entry.content })
2825
+ ] }),
2826
+ /* @__PURE__ */ jsx(
2827
+ "p",
2828
+ {
2829
+ className: "max-w-[80%] whitespace-pre-wrap rounded-lg border px-4 py-2.5 text-sm leading-relaxed",
2830
+ style: { color: t.text, borderColor: t.borderStrong, backgroundColor: "rgba(255,255,255,0.05)" },
2831
+ children: entry.content
2832
+ }
2833
+ )
2834
+ ] })
2835
+ ) : /* @__PURE__ */ jsxs("div", { className: "group relative", children: [
2656
2836
  /* @__PURE__ */ jsxs("div", { className: "absolute -top-5 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
2657
2837
  /* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
2658
2838
  /* @__PURE__ */ jsx(ShareButton, { content: entry.content })
@@ -2660,9 +2840,9 @@ function TerminalEntryRenderer({
2660
2840
  /* @__PURE__ */ jsx(
2661
2841
  "pre",
2662
2842
  {
2663
- className: "font-mono text-sm whitespace-pre-wrap",
2843
+ className: "font-mono text-sm whitespace-pre-wrap max-w-[72ch]",
2664
2844
  style: {
2665
- color: isSystem ? t.textSystem : isCommand ? t.textCommand : isSuccess ? t.success : isError ? t.error : t.text
2845
+ color: isSystem ? t.textSystem : isSuccess ? t.success : isError ? t.error : t.text
2666
2846
  },
2667
2847
  children: entry.content
2668
2848
  }
@@ -2793,7 +2973,14 @@ function TerminalEntryRenderer({
2793
2973
  {
2794
2974
  summary: `${entry.sources.length} source${entry.sources.length !== 1 ? "s" : ""}`,
2795
2975
  defaultExpanded: false,
2796
- children: /* @__PURE__ */ jsx("div", { className: "space-y-1 py-1", children: entry.sources.map((src) => /* @__PURE__ */ jsx(SourceCard, { source: src }, src.id)) })
2976
+ children: /* @__PURE__ */ jsx("div", { className: "space-y-1 py-1", children: entry.sources.map((src) => /* @__PURE__ */ jsx(
2977
+ SourceCard,
2978
+ {
2979
+ source: src,
2980
+ onActivate: onSourceActivate ? () => onSourceActivate(src, entry) : void 0
2981
+ },
2982
+ src.id
2983
+ )) })
2797
2984
  }
2798
2985
  )
2799
2986
  }
@@ -2813,11 +3000,11 @@ function TerminalEntryRenderer({
2813
3000
  /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", style: { color: t.success }, children: "Actions" }),
2814
3001
  /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: t.textMuted }, children: "click to execute" })
2815
3002
  ] }),
2816
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2", children: entry.suggested_actions.map((action, idx) => /* @__PURE__ */ jsxs("div", { children: [
3003
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2", children: entry.suggested_actions.map((action2, idx) => /* @__PURE__ */ jsxs("div", { children: [
2817
3004
  /* @__PURE__ */ jsx(
2818
3005
  InteractiveActionCard,
2819
3006
  {
2820
- action,
3007
+ action: action2,
2821
3008
  graphqlUrl: config.graphqlUrl,
2822
3009
  authToken: authToken || "",
2823
3010
  onExecute: (updatedAction) => {
@@ -2826,15 +3013,15 @@ function TerminalEntryRenderer({
2826
3013
  }
2827
3014
  }
2828
3015
  ),
2829
- action.approval && /* @__PURE__ */ jsx(
3016
+ action2.approval && /* @__PURE__ */ jsx(
2830
3017
  ApprovalTracker,
2831
3018
  {
2832
- approval: action.approval,
3019
+ approval: action2.approval,
2833
3020
  currentUserId: currentUser?.entity_id,
2834
3021
  onApprove: () => {
2835
3022
  window.dispatchEvent(
2836
3023
  new CustomEvent("terminal-approval-decision", {
2837
- detail: { action, decision: "approved", entity_id: currentUser?.entity_id },
3024
+ detail: { action: action2, decision: "approved", entity_id: currentUser?.entity_id },
2838
3025
  bubbles: true
2839
3026
  })
2840
3027
  );
@@ -2842,7 +3029,7 @@ function TerminalEntryRenderer({
2842
3029
  onReject: () => {
2843
3030
  window.dispatchEvent(
2844
3031
  new CustomEvent("terminal-approval-decision", {
2845
- detail: { action, decision: "rejected", entity_id: currentUser?.entity_id },
3032
+ detail: { action: action2, decision: "rejected", entity_id: currentUser?.entity_id },
2846
3033
  bubbles: true
2847
3034
  })
2848
3035
  );
@@ -2890,9 +3077,10 @@ function TerminalEntryRenderer({
2890
3077
  ] });
2891
3078
  const isTurnStart = !!prevEntry && isCommand && prevEntry.type !== "system";
2892
3079
  const defaultRender = () => /* @__PURE__ */ jsxs("div", { className: `${isGrouped ? "" : "mb-5"} ${isTurnStart ? "mt-6" : ""}`, children: [
2893
- beforeWidgets.map((w) => /* @__PURE__ */ jsx(React12.Fragment, { children: w.render({ entry, index }) }, w.name)),
2894
- replaceWidget ? /* @__PURE__ */ jsx(React12.Fragment, { children: replaceWidget.render({ entry, index }) }, replaceWidget.name) : builtInContent,
2895
- afterWidgets.map((w) => /* @__PURE__ */ jsx(React12.Fragment, { children: w.render({ entry, index }) }, w.name)),
3080
+ beforeWidgets.map((w) => /* @__PURE__ */ jsx(React15.Fragment, { children: w.render({ entry, index }) }, w.name)),
3081
+ replaceWidget ? /* @__PURE__ */ jsx(React15.Fragment, { children: replaceWidget.render({ entry, index }) }, replaceWidget.name) : builtInContent,
3082
+ afterWidgets.map((w) => /* @__PURE__ */ jsx(React15.Fragment, { children: w.render({ entry, index }) }, w.name)),
3083
+ /* @__PURE__ */ jsx(AgentCompletionNotice, { completion: entry.metadata?.completion }),
2896
3084
  renderEntryExtra?.(entry, index)
2897
3085
  ] });
2898
3086
  if (renderEntry) {
@@ -2901,6 +3089,9 @@ function TerminalEntryRenderer({
2901
3089
  }
2902
3090
  return defaultRender();
2903
3091
  }
3092
+
3093
+ // src/types/terminal.types.ts
3094
+ var DEFAULT_AGENT_LABEL = "YieldFabric Agent";
2904
3095
  function LiveKGBridge({ progressState, onLiveKGUpdate }) {
2905
3096
  const onUpdateRef = useRef(onLiveKGUpdate);
2906
3097
  onUpdateRef.current = onLiveKGUpdate;
@@ -2929,14 +3120,17 @@ function TerminalShell({
2929
3120
  className = "",
2930
3121
  style,
2931
3122
  showHeader = true,
3123
+ agentLabel = DEFAULT_AGENT_LABEL,
2932
3124
  focusInput,
2933
3125
  setTerminalHistory,
2934
3126
  terminalBodyRef,
2935
3127
  workingGroupContext,
3128
+ showWorkingGroupBanner = true,
2936
3129
  progressState,
2937
3130
  streamTransparency,
2938
3131
  streamNowMs,
2939
3132
  isExecuting,
3133
+ showBusyIndicator,
2940
3134
  handleCancelReasoning,
2941
3135
  onViewKnowledgeGraph,
2942
3136
  onLiveKGUpdate,
@@ -2954,6 +3148,9 @@ function TerminalShell({
2954
3148
  className: `border-0 flex flex-col ${className}`,
2955
3149
  style: { minHeight: "300px", borderRadius: "12px", backgroundColor: "transparent", ...style },
2956
3150
  onClick: () => {
3151
+ if (typeof window !== "undefined" && window.matchMedia?.("(pointer: coarse)").matches) {
3152
+ return;
3153
+ }
2957
3154
  const sel = window.getSelection();
2958
3155
  if (!sel || sel.toString().length === 0) focusInput();
2959
3156
  },
@@ -2972,7 +3169,7 @@ function TerminalShell({
2972
3169
  "button",
2973
3170
  {
2974
3171
  onClick: () => setTerminalHistory([
2975
- { type: "system", content: "YieldFabric Agent", timestamp: /* @__PURE__ */ new Date() },
3172
+ { type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
2976
3173
  { type: "system", content: "Terminal cleared.", timestamp: /* @__PURE__ */ new Date() }
2977
3174
  ]),
2978
3175
  className: "hover:opacity-80",
@@ -2990,7 +3187,7 @@ function TerminalShell({
2990
3187
  className: "p-6 flex-1 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-700 scrollbar-track-transparent",
2991
3188
  style: { minHeight: "200px", display: "flex", flexDirection: "column", backgroundColor: "transparent" },
2992
3189
  children: [
2993
- workingGroupContext && /* @__PURE__ */ jsxs(
3190
+ workingGroupContext && showWorkingGroupBanner && /* @__PURE__ */ jsxs(
2994
3191
  "div",
2995
3192
  {
2996
3193
  className: "mb-3 ml-1 mr-1 px-3 py-2 rounded-md text-xs flex items-center justify-between",
@@ -3015,7 +3212,7 @@ function TerminalShell({
3015
3212
  }
3016
3213
  ),
3017
3214
  /* @__PURE__ */ jsx(LiveKGBridge, { progressState, onLiveKGUpdate }),
3018
- isExecuting && !progressState && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 px-6 py-2 flex-shrink-0 border-t", style: { color: t.text, borderColor: t.border }, children: [
3215
+ isExecuting && !progressState && showBusyIndicator !== false && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 px-6 py-2 flex-shrink-0 border-t", style: { color: t.text, borderColor: t.border }, children: [
3019
3216
  /* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
3020
3217
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full animate-pulse", style: { backgroundColor: t.info } }),
3021
3218
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full animate-pulse", style: { backgroundColor: t.info, animationDelay: "150ms" } }),
@@ -3145,11 +3342,24 @@ function splitInputByMentions(command, knownMentionNames) {
3145
3342
  segments.push({ kind: "text", value: command.slice(cursor) });
3146
3343
  return segments;
3147
3344
  }
3345
+ var INPUT_MAX_HEIGHT = 120;
3346
+ function fitToContent(input) {
3347
+ resetHeight(input);
3348
+ if (!input.value.trim()) return;
3349
+ const needed = input.scrollHeight;
3350
+ input.style.height = `${Math.min(needed, INPUT_MAX_HEIGHT)}px`;
3351
+ if (needed > INPUT_MAX_HEIGHT) input.style.overflowY = "auto";
3352
+ }
3353
+ function resetHeight(input) {
3354
+ input.style.height = "auto";
3355
+ input.style.overflowY = "";
3356
+ }
3148
3357
  function TerminalInputBar({
3149
3358
  inputRef,
3150
3359
  fileInputRef,
3151
3360
  currentCommand,
3152
3361
  isExecuting,
3362
+ disabled = false,
3153
3363
  placeholder = "Ask anything...",
3154
3364
  onInputChange,
3155
3365
  onKeyDown,
@@ -3172,20 +3382,27 @@ function TerminalInputBar({
3172
3382
  inputBarExtra,
3173
3383
  modeSelector,
3174
3384
  compactToolbar = false,
3175
- submitTitle = "Send"
3385
+ submitTitle = "Send",
3386
+ autoFocus = true
3176
3387
  }) {
3177
3388
  const t = useTheme();
3389
+ useEffect(() => {
3390
+ if (!autoFocus) return;
3391
+ inputRef.current?.focus({ preventScroll: true });
3392
+ }, []);
3393
+ const [focused, setFocused] = React15.useState(false);
3394
+ const chipsVisible = focused || currentCommand.trim().length > 0;
3178
3395
  const isLight = t.bgRaised === "#ffffff";
3179
3396
  const hasCommand = Boolean(currentCommand.trim());
3180
- const placeholderColor = isLight ? "rgba(30,30,58,0.44)" : "rgba(255,255,255,0.40)";
3181
- const panelBorder = isLight ? "rgba(30,30,58,0.12)" : "rgba(255,255,255,0.10)";
3182
- const panelBg = isLight ? "rgba(255,255,255,0.82)" : "rgba(24,24,24,0.82)";
3183
- const toolbarButtonBg = isLight ? "rgba(30,30,58,0.06)" : "rgba(255,255,255,0.05)";
3184
- const toolbarButtonHover = isLight ? "rgba(30,30,58,0.11)" : "rgba(255,255,255,0.14)";
3185
- const toolbarButtonText = isLight ? "rgba(30,30,58,0.58)" : "rgba(255,255,255,0.42)";
3397
+ const placeholderColor = isLight ? t.textMuted : "rgba(255,255,255,0.52)";
3398
+ const panelBorder = isLight ? t.border : "rgba(255,255,255,0.10)";
3399
+ const panelBg = t.bgInput;
3400
+ const toolbarButtonBg = isLight ? "rgba(255,255,255,0.72)" : "rgba(255,255,255,0.05)";
3401
+ const toolbarButtonHover = isLight ? t.bgRaised : "rgba(255,255,255,0.14)";
3402
+ const toolbarButtonText = isLight ? t.textSecondary : "rgba(255,255,255,0.52)";
3186
3403
  const toolbarButtonStyle = {
3187
3404
  backgroundColor: toolbarButtonBg,
3188
- border: `1px solid ${isLight ? "rgba(30,30,58,0.08)" : "rgba(255,255,255,0.08)"}`,
3405
+ border: `1px solid ${isLight ? t.border : "rgba(255,255,255,0.08)"}`,
3189
3406
  boxShadow: "none",
3190
3407
  color: toolbarButtonText
3191
3408
  };
@@ -3198,8 +3415,11 @@ function TerminalInputBar({
3198
3415
  }
3199
3416
  const el = toolbarRef.current;
3200
3417
  if (!el || typeof ResizeObserver === "undefined") return;
3418
+ let lastWidth = -1;
3201
3419
  const ro = new ResizeObserver((entries) => {
3202
- const w = entries[0]?.contentRect.width ?? 0;
3420
+ const w = Math.round(entries[0]?.contentRect.width ?? 0);
3421
+ if (w === lastWidth) return;
3422
+ lastWidth = w;
3203
3423
  setCompact((prev) => prev ? w < 520 : w < 480);
3204
3424
  });
3205
3425
  ro.observe(el);
@@ -3209,10 +3429,7 @@ function TerminalInputBar({
3209
3429
  useEffect(() => {
3210
3430
  const input = inputRef.current;
3211
3431
  if (!input) return;
3212
- input.style.height = "auto";
3213
- if (currentCommand.trim()) {
3214
- input.style.height = Math.min(input.scrollHeight, 120) + "px";
3215
- }
3432
+ fitToContent(input);
3216
3433
  }, [currentCommand, inputRef]);
3217
3434
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3218
3435
  /* @__PURE__ */ jsx("style", { children: `.yf-input-bar::placeholder { color: ${placeholderColor}; }` }),
@@ -3254,16 +3471,16 @@ function TerminalInputBar({
3254
3471
  /* @__PURE__ */ jsx(
3255
3472
  "div",
3256
3473
  {
3257
- className: `relative z-20 flex-shrink-0 px-3 pb-3 pt-2 transition-opacity duration-300 sm:px-4 ${isExecuting ? "opacity-40 pointer-events-none" : ""}`,
3474
+ className: `relative z-20 flex-shrink-0 px-3 pb-3 pt-2 transition-opacity duration-300 sm:px-4 ${isExecuting || disabled ? "opacity-40 pointer-events-none" : ""}`,
3258
3475
  children: /* @__PURE__ */ jsxs(
3259
3476
  "div",
3260
3477
  {
3261
- className: "rounded-xl border px-3 transition-colors focus-within:border-white/20 sm:px-4",
3478
+ className: `rounded-xl border px-3 transition-[box-shadow,border-color] sm:px-4 ${focused ? "yf-input-focused" : ""}`,
3262
3479
  style: {
3263
3480
  backgroundColor: panelBg,
3264
3481
  backdropFilter: "blur(18px)",
3265
- borderColor: panelBorder,
3266
- boxShadow: isLight ? "0 18px 70px -38px rgba(30,30,58,0.45)" : "0 18px 70px -38px rgba(0,0,0,0.95)",
3482
+ borderColor: focused ? t.primary : panelBorder,
3483
+ boxShadow: focused ? `0 0 0 3px ${t.primaryMuted || "rgba(5,78,146,0.18)"}` : isLight ? "0 18px 70px -38px rgba(30,30,58,0.45)" : "0 18px 70px -38px rgba(0,0,0,0.95)",
3267
3484
  WebkitBackdropFilter: "blur(18px)"
3268
3485
  },
3269
3486
  children: [
@@ -3333,8 +3550,7 @@ function TerminalInputBar({
3333
3550
  onInputChange(`${prefixRaw}${e.target.value}`);
3334
3551
  onCaretChange?.(prefixRaw.length + (e.target.selectionStart ?? e.target.value.length));
3335
3552
  onTyping?.();
3336
- e.target.style.height = "auto";
3337
- e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
3553
+ fitToContent(e.target);
3338
3554
  },
3339
3555
  onSelect: (e) => {
3340
3556
  const ta = e.currentTarget;
@@ -3361,17 +3577,19 @@ function TerminalInputBar({
3361
3577
  if (e.key === "Enter" && !e.shiftKey && !e.defaultPrevented) {
3362
3578
  e.preventDefault();
3363
3579
  onSubmit();
3364
- if (inputRef.current) inputRef.current.style.height = "auto";
3580
+ if (inputRef.current) resetHeight(inputRef.current);
3365
3581
  }
3366
3582
  },
3367
- disabled: isExecuting,
3583
+ disabled: isExecuting || disabled,
3584
+ "aria-label": placeholder ?? "Message",
3368
3585
  placeholder: isExecuting ? "Processing..." : placeholder,
3369
3586
  rows: 1,
3370
- className: "yf-input-bar flex-1 min-w-[100px] bg-transparent focus:outline-none text-[16px] leading-6 resize-none overflow-hidden sm:text-[13px] sm:leading-normal",
3587
+ className: "yf-input-bar flex-1 min-w-[100px] bg-transparent focus:outline-none text-[16px] leading-6 resize-none overflow-hidden sm:text-sm sm:leading-5",
3588
+ onFocus: () => setFocused(true),
3589
+ onBlur: () => setFocused(false),
3371
3590
  style: { color: t.text, caretColor: t.cursor },
3372
3591
  spellCheck: false,
3373
3592
  autoComplete: "off",
3374
- autoFocus: true,
3375
3593
  tabIndex: 0
3376
3594
  }
3377
3595
  )
@@ -3380,67 +3598,78 @@ function TerminalInputBar({
3380
3598
  "button",
3381
3599
  {
3382
3600
  type: "submit",
3383
- disabled: !hasCommand || isExecuting,
3384
- className: "h-10 w-10 rounded-xl disabled:opacity-45 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200 shrink-0 sm:h-8 sm:w-8",
3601
+ disabled: !hasCommand || isExecuting || disabled,
3602
+ className: "h-10 w-10 rounded-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200 shrink-0 sm:h-8 sm:w-8",
3385
3603
  style: {
3386
- backgroundColor: hasCommand ? "rgba(255,140,66,0.95)" : isLight ? "rgba(30,30,58,0.07)" : "rgba(255,255,255,0.08)",
3387
- color: hasCommand ? "#181818" : isLight ? "rgba(30,30,58,0.58)" : "rgba(255,255,255,0.72)"
3604
+ backgroundColor: hasCommand ? t.primary : isLight ? t.bgRaisedAlt : "rgba(255,255,255,0.08)",
3605
+ // `textInverse` is the theme's "text on a filled button".
3606
+ // `bgBase` was used here before and is `transparent` in
3607
+ // every app theme — so the chevron vanished the moment
3608
+ // there was something to send.
3609
+ color: hasCommand ? t.textInverse : isLight ? t.textMuted : "rgba(255,255,255,0.72)"
3388
3610
  },
3389
3611
  onMouseEnter: (e) => {
3390
- e.currentTarget.style.backgroundColor = hasCommand ? "#ffb37a" : toolbarButtonHover;
3612
+ if (hasCommand) {
3613
+ e.currentTarget.style.filter = "brightness(1.15)";
3614
+ } else {
3615
+ e.currentTarget.style.backgroundColor = toolbarButtonHover;
3616
+ }
3391
3617
  },
3392
3618
  onMouseLeave: (e) => {
3393
- e.currentTarget.style.backgroundColor = hasCommand ? "rgba(255,140,66,0.95)" : isLight ? "rgba(30,30,58,0.07)" : "rgba(255,255,255,0.08)";
3619
+ e.currentTarget.style.filter = "";
3620
+ e.currentTarget.style.backgroundColor = hasCommand ? t.primary : isLight ? t.bgRaisedAlt : "rgba(255,255,255,0.08)";
3394
3621
  },
3395
3622
  title: submitTitle,
3396
3623
  "aria-label": submitTitle,
3397
- children: isExecuting ? /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full animate-spin", style: { border: `1.5px solid ${hasCommand ? "rgba(24,24,24,0.7)" : t.textMuted}`, borderTopColor: "transparent" } }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 sm:h-4 sm:w-4" })
3624
+ children: isExecuting ? /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full animate-spin", style: { border: `1.5px solid ${hasCommand ? t.textInverse : t.textMuted}`, borderTopColor: "transparent" } }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 sm:h-4 sm:w-4" })
3398
3625
  }
3399
3626
  )
3400
3627
  ] });
3401
3628
  })(),
3402
3629
  /* @__PURE__ */ jsxs("div", { ref: toolbarRef, className: "flex items-center justify-between pt-2.5 gap-2", children: [
3403
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[10px] min-w-0 flex-wrap", children: [
3404
- /* @__PURE__ */ jsx(
3405
- "button",
3406
- {
3407
- type: "button",
3408
- onClick: () => {
3409
- onInputChange("@");
3410
- inputRef.current?.focus();
3411
- },
3412
- title: "Insert @ mention",
3413
- className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 rounded-lg transition-colors font-medium flex-shrink-0`,
3414
- style: toolbarButtonStyle,
3415
- onMouseEnter: (e) => {
3416
- e.currentTarget.style.backgroundColor = toolbarButtonHover;
3417
- },
3418
- onMouseLeave: (e) => {
3419
- e.currentTarget.style.backgroundColor = toolbarButtonBg;
3420
- },
3421
- children: toolbarIsCompact ? "@" : "@ mention"
3422
- }
3423
- ),
3424
- /* @__PURE__ */ jsx(
3425
- "button",
3426
- {
3427
- type: "button",
3428
- onClick: () => {
3429
- onInputChange("/");
3430
- inputRef.current?.focus();
3431
- },
3432
- title: "Insert / command",
3433
- className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 rounded-lg transition-colors font-medium flex-shrink-0`,
3434
- style: toolbarButtonStyle,
3435
- onMouseEnter: (e) => {
3436
- e.currentTarget.style.backgroundColor = toolbarButtonHover;
3437
- },
3438
- onMouseLeave: (e) => {
3439
- e.currentTarget.style.backgroundColor = toolbarButtonBg;
3440
- },
3441
- children: toolbarIsCompact ? "/" : "/ commands"
3442
- }
3443
- ),
3630
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[11px] min-w-0 flex-wrap", children: [
3631
+ chipsVisible && /* @__PURE__ */ jsxs(Fragment, { children: [
3632
+ /* @__PURE__ */ jsx(
3633
+ "button",
3634
+ {
3635
+ type: "button",
3636
+ onClick: () => {
3637
+ onInputChange("@");
3638
+ inputRef.current?.focus();
3639
+ },
3640
+ title: "Insert @ mention",
3641
+ className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 min-h-[40px] sm:min-h-0 inline-flex items-center rounded-lg transition-colors font-semibold flex-shrink-0`,
3642
+ style: toolbarButtonStyle,
3643
+ onMouseEnter: (e) => {
3644
+ e.currentTarget.style.backgroundColor = toolbarButtonHover;
3645
+ },
3646
+ onMouseLeave: (e) => {
3647
+ e.currentTarget.style.backgroundColor = toolbarButtonBg;
3648
+ },
3649
+ children: toolbarIsCompact ? "@" : "@ mention"
3650
+ }
3651
+ ),
3652
+ /* @__PURE__ */ jsx(
3653
+ "button",
3654
+ {
3655
+ type: "button",
3656
+ onClick: () => {
3657
+ onInputChange("/");
3658
+ inputRef.current?.focus();
3659
+ },
3660
+ title: "Insert / command",
3661
+ className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 min-h-[40px] sm:min-h-0 inline-flex items-center rounded-lg transition-colors font-semibold flex-shrink-0`,
3662
+ style: toolbarButtonStyle,
3663
+ onMouseEnter: (e) => {
3664
+ e.currentTarget.style.backgroundColor = toolbarButtonHover;
3665
+ },
3666
+ onMouseLeave: (e) => {
3667
+ e.currentTarget.style.backgroundColor = toolbarButtonBg;
3668
+ },
3669
+ children: toolbarIsCompact ? "/" : "/ commands"
3670
+ }
3671
+ )
3672
+ ] }),
3444
3673
  availableKGs && availableKGs.length > 0 && /* @__PURE__ */ jsx(Fragment, { children: activeKGScope ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md text-[10px] min-w-0", title: activeKGScope.label, style: { backgroundColor: "rgba(255,140,66,0.08)", border: "1px solid rgba(255,140,66,0.15)", color: "rgba(255,140,66,0.8)" }, children: [
3445
3674
  /* @__PURE__ */ jsxs("svg", { className: "w-3 h-3 opacity-60 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
3446
3675
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101" }),
@@ -3454,7 +3683,7 @@ function TerminalInputBar({
3454
3683
  ] }),
3455
3684
  /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onKGScopeChange?.(null), className: "ml-0.5 opacity-40 hover:opacity-100 transition-opacity", children: "\u2715" })
3456
3685
  ] }) : /* @__PURE__ */ jsx(KGScopeDropdown, { items: availableKGs, onSelect: (scope) => onKGScopeChange?.(scope), compact: toolbarIsCompact }) }),
3457
- modeSelector ?? (onReasoningModeChange && /* @__PURE__ */ jsx(ReasoningModeSelector, { current: reasoningMode || null, onChange: onReasoningModeChange, compact: toolbarIsCompact }))
3686
+ chipsVisible && (modeSelector ?? (onReasoningModeChange && /* @__PURE__ */ jsx(ReasoningModeSelector, { current: reasoningMode || null, onChange: onReasoningModeChange, compact: toolbarIsCompact })))
3458
3687
  ] }),
3459
3688
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [
3460
3689
  inputBarExtra,
@@ -3462,8 +3691,8 @@ function TerminalInputBar({
3462
3691
  "button",
3463
3692
  {
3464
3693
  type: "button",
3465
- disabled: isExecuting,
3466
- className: "h-8 w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
3694
+ disabled: isExecuting || disabled,
3695
+ className: "h-10 w-10 sm:h-8 sm:w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
3467
3696
  style: toolbarButtonStyle,
3468
3697
  title: "Upload files",
3469
3698
  onClick: () => fileInputRef.current?.click(),
@@ -3480,8 +3709,8 @@ function TerminalInputBar({
3480
3709
  "button",
3481
3710
  {
3482
3711
  type: "button",
3483
- disabled: isExecuting,
3484
- className: "h-8 w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
3712
+ disabled: isExecuting || disabled,
3713
+ className: "h-10 w-10 sm:h-8 sm:w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
3485
3714
  style: toolbarButtonStyle,
3486
3715
  title: "List files",
3487
3716
  onClick: () => onListFilesCommand(),
@@ -3601,16 +3830,15 @@ function useCommandHistory() {
3601
3830
  }, []);
3602
3831
  return { commandHistory, historyIndex, pushCommand, navigateUp, navigateDown, resetIndex };
3603
3832
  }
3604
- function useFocusManagement() {
3833
+ function useFocusManagement(autoFocus = true) {
3605
3834
  const inputRef = useRef(null);
3606
3835
  const focusInput = useCallback(() => {
3607
3836
  const selection = window.getSelection();
3608
3837
  if (selection && selection.toString().length > 0) return;
3609
- if (inputRef.current) {
3610
- inputRef.current.focus();
3611
- }
3838
+ inputRef.current?.focus({ preventScroll: true });
3612
3839
  }, []);
3613
3840
  useEffect(() => {
3841
+ if (!autoFocus) return;
3614
3842
  const timer = setTimeout(focusInput, 100);
3615
3843
  const handleVisibilityChange = () => {
3616
3844
  if (!document.hidden) {
@@ -3622,11 +3850,12 @@ function useFocusManagement() {
3622
3850
  clearTimeout(timer);
3623
3851
  document.removeEventListener("visibilitychange", handleVisibilityChange);
3624
3852
  };
3625
- }, [focusInput]);
3853
+ }, [focusInput, autoFocus]);
3626
3854
  return { inputRef, focusInput };
3627
3855
  }
3628
3856
  function useStreamingChat({
3629
3857
  config,
3858
+ authToken,
3630
3859
  onStreamRequest,
3631
3860
  reasoningMode,
3632
3861
  setTerminalHistory,
@@ -3635,11 +3864,14 @@ function useStreamingChat({
3635
3864
  currentUser,
3636
3865
  sourceKGNodes
3637
3866
  }) {
3867
+ const authTokenRef = useRef(authToken);
3868
+ authTokenRef.current = authToken;
3638
3869
  const sourceKGNodesRef = useRef(sourceKGNodes);
3639
3870
  sourceKGNodesRef.current = sourceKGNodes;
3640
3871
  const reasoningModeRef = useRef(reasoningMode);
3641
3872
  reasoningModeRef.current = reasoningMode;
3642
3873
  const [isExecuting, setIsExecuting] = useState(false);
3874
+ const turnSequence = useRef(0);
3643
3875
  const [isStreaming, setIsStreaming] = useState(false);
3644
3876
  const [progressState, setProgressState] = useState(null);
3645
3877
  const [activityEvents, setActivityEvents] = useState([]);
@@ -3655,6 +3887,15 @@ function useStreamingChat({
3655
3887
  const currentStreamingLineId = useRef(null);
3656
3888
  const liveRunIdRef = useRef(null);
3657
3889
  liveRunIdRef.current = liveRunId;
3890
+ const mountEpoch = useRef(0);
3891
+ useEffect(() => {
3892
+ const epoch = ++mountEpoch.current;
3893
+ return () => {
3894
+ void Promise.resolve().then(() => {
3895
+ if (mountEpoch.current === epoch) currentStreamingLineId.current = null;
3896
+ });
3897
+ };
3898
+ }, []);
3658
3899
  useEffect(() => {
3659
3900
  progressStateRef.current = progressState;
3660
3901
  }, [progressState]);
@@ -3707,45 +3948,54 @@ function useStreamingChat({
3707
3948
  currentStreamingLineId.current = null;
3708
3949
  setTimeout(() => focusInput(), 50);
3709
3950
  }, [focusInput]);
3710
- const handleHilSubmit = useCallback(
3711
- async (message) => {
3712
- const runId = liveRunIdRef.current;
3713
- if (!runId) return;
3714
- const apiUrl = config.agentsApiUrl || "http://localhost:3001";
3715
- try {
3716
- if (message && message.trim().length > 0) {
3717
- await fetch(`${apiUrl}/pipelines/${runId}/input`, {
3718
- method: "POST",
3719
- headers: { "Content-Type": "application/json" },
3720
- body: JSON.stringify({ kind: "guidance", content: message })
3721
- });
3722
- }
3723
- await fetch(`${apiUrl}/pipelines/${runId}/input`, {
3724
- method: "POST",
3725
- headers: { "Content-Type": "application/json" },
3726
- body: JSON.stringify({ kind: "proceed" })
3727
- });
3728
- } catch (e) {
3729
- console.error("Failed to send pipeline input:", e);
3730
- }
3731
- },
3732
- [config.agentsApiUrl]
3733
- );
3951
+ const postPipelineAction = useCallback(async (runId, action2, body) => {
3952
+ const headers = config.getAuthHeaders?.() ?? (authTokenRef.current ? { Authorization: `Bearer ${authTokenRef.current}` } : {});
3953
+ const response = await fetch(`${config.agentsApiUrl || "http://localhost:3001"}/pipelines/${runId}/${action2}`, {
3954
+ method: "POST",
3955
+ headers: { "Content-Type": "application/json", ...headers },
3956
+ body: body === void 0 ? void 0 : JSON.stringify(body)
3957
+ });
3958
+ if (!response.ok) throw new Error(`The request was not accepted (${response.status}). Please try again.`);
3959
+ }, [config]);
3960
+ const handleHilSubmit = useCallback(async (message) => {
3961
+ const runId = liveRunIdRef.current;
3962
+ if (!runId) return;
3963
+ try {
3964
+ if (message.trim()) await postPipelineAction(runId, "input", { kind: "guidance", content: message });
3965
+ await postPipelineAction(runId, "input", { kind: "proceed" });
3966
+ } catch (error) {
3967
+ addTerminalLine("error", `Your input was not sent. ${error.message}`);
3968
+ }
3969
+ }, [postPipelineAction, addTerminalLine]);
3734
3970
  const handleCancelReasoning = useCallback(async () => {
3735
3971
  const runId = liveRunIdRef.current;
3736
3972
  if (!runId) return;
3737
- const apiUrl = config.agentsApiUrl || "http://localhost:3001";
3738
- setProgressState(null);
3739
- resetStreamState();
3740
3973
  try {
3741
- await fetch(`${apiUrl}/pipelines/${runId}/cancel`, {
3742
- method: "POST",
3743
- headers: { "Content-Type": "application/json" }
3744
- });
3745
- } catch (e) {
3746
- console.error("Failed to cancel pipeline:", e);
3974
+ await postPipelineAction(runId, "cancel");
3975
+ setProgressState(null);
3976
+ resetStreamState();
3977
+ addTerminalLine("info", "Stopped the analysis.");
3978
+ } catch (error) {
3979
+ addTerminalLine("error", `The analysis is still running. ${error.message}`);
3747
3980
  }
3748
- }, [config.agentsApiUrl, resetStreamState]);
3981
+ }, [postPipelineAction, resetStreamState, addTerminalLine]);
3982
+ const settleAgentSteps = useCallback(
3983
+ (lineId) => {
3984
+ setTerminalHistory((prev) => {
3985
+ const idx = prev.findIndex((line) => line.id === lineId);
3986
+ if (idx === -1) return prev;
3987
+ const meta = prev[idx].metadata;
3988
+ if (!meta?.agentStepsLive) return prev;
3989
+ const updated = [...prev];
3990
+ updated[idx] = {
3991
+ ...updated[idx],
3992
+ metadata: { ...updated[idx].metadata || {}, agentStepsLive: false }
3993
+ };
3994
+ return updated;
3995
+ });
3996
+ },
3997
+ [setTerminalHistory]
3998
+ );
3749
3999
  const handleStreamingChat = useCallback(
3750
4000
  async (cmd) => {
3751
4001
  if (isProcessingRef.current || !onStreamRequest) return;
@@ -3757,8 +4007,9 @@ function useStreamingChat({
3757
4007
  const startMs = Date.now();
3758
4008
  setStreamTransparency({ startedAtMs: startMs, lastEventAtMs: startMs });
3759
4009
  setActivityEvents([]);
3760
- const userCommandId = Date.now().toString();
3761
- const streamingLineId = (Date.now() + 1).toString();
4010
+ const turnKey = `${Date.now()}-${++turnSequence.current}`;
4011
+ const userCommandId = `${turnKey}:question`;
4012
+ const streamingLineId = `${turnKey}:answer`;
3762
4013
  currentStreamingLineId.current = streamingLineId;
3763
4014
  const userCommandEntry = {
3764
4015
  id: userCommandId,
@@ -3784,14 +4035,14 @@ function useStreamingChat({
3784
4035
  setTerminalHistory((prev) => [
3785
4036
  ...prev,
3786
4037
  {
3787
- id: (Date.now() + 2).toString(),
4038
+ id: `${turnKey}:before-question`,
3788
4039
  type: "info",
3789
4040
  content: "",
3790
4041
  timestamp: /* @__PURE__ */ new Date()
3791
4042
  },
3792
4043
  userCommandEntry,
3793
4044
  {
3794
- id: (Date.now() + 3).toString(),
4045
+ id: `${turnKey}:before-answer`,
3795
4046
  type: "info",
3796
4047
  content: "",
3797
4048
  timestamp: /* @__PURE__ */ new Date()
@@ -3805,10 +4056,37 @@ function useStreamingChat({
3805
4056
  let sources;
3806
4057
  let kgId;
3807
4058
  let runId;
4059
+ const steps = /* @__PURE__ */ new Map();
4060
+ const fail = (error) => {
4061
+ if (currentStreamingLineId.current !== streamingLineId) return;
4062
+ settleAgentSteps(streamingLineId);
4063
+ updateStreamingLine(
4064
+ streamingLineId,
4065
+ fullResponse,
4066
+ pageSuggestions,
4067
+ suggestedActions,
4068
+ progressStateRef.current ? captureReasoningSnapshot(progressStateRef.current, true) : void 0,
4069
+ pipelineDraft,
4070
+ sources,
4071
+ kgId,
4072
+ runId
4073
+ );
4074
+ setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, completion: { stop_reason: /connection|interrupt/i.test(error) ? "interrupted" : "failed" } } } : entry));
4075
+ addTerminalLine("error", error);
4076
+ setProgressState(null);
4077
+ resetStreamState();
4078
+ };
3808
4079
  try {
3809
4080
  await onStreamRequest(cmd, {
3810
4081
  onChunk: (chunk) => {
4082
+ if (currentStreamingLineId.current !== streamingLineId) return;
4083
+ if (chunk.entryMetadata) {
4084
+ setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, ...chunk.entryMetadata } } : entry));
4085
+ }
3811
4086
  const eventMs = Date.now();
4087
+ if (chunk.completion) {
4088
+ setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, completion: chunk.completion } } : entry));
4089
+ }
3812
4090
  if (chunk.sender) {
3813
4091
  setStreamingLineSender(streamingLineId, chunk.sender);
3814
4092
  if (currentUser) {
@@ -3821,6 +4099,28 @@ function useStreamingChat({
3821
4099
  if (chunk.collaboration) {
3822
4100
  setCollaborationState(chunk.collaboration);
3823
4101
  }
4102
+ if (chunk.step) {
4103
+ steps.set(chunk.step.seq, chunk.step);
4104
+ const ordered = Array.from(steps.values()).sort((a, b) => a.seq - b.seq);
4105
+ setTerminalHistory((prev) => {
4106
+ const idx = prev.findIndex((line) => line.id === streamingLineId);
4107
+ if (idx === -1) return prev;
4108
+ const updated = [...prev];
4109
+ updated[idx] = {
4110
+ ...updated[idx],
4111
+ metadata: {
4112
+ ...updated[idx].metadata || {},
4113
+ agentSteps: ordered,
4114
+ // Explicit rather than inferred from the streaming cursor:
4115
+ // a tool loop runs to completion BEFORE the first answer
4116
+ // token, so during the whole loop the entry's content is
4117
+ // empty and carries no cursor to read.
4118
+ agentStepsLive: true
4119
+ }
4120
+ };
4121
+ return updated;
4122
+ });
4123
+ }
3824
4124
  const ckgId = extractKgId(chunk, chunk.progress);
3825
4125
  const cRunId = chunk.run_id || chunk.progress?.run_id;
3826
4126
  const ctId = chunk.thread_id || chunk.progress?.thread_id || chunk.reasoning_thread_id || chunk.progress?.reasoning_thread_id;
@@ -3964,49 +4264,14 @@ function useStreamingChat({
3964
4264
  kgId,
3965
4265
  runId
3966
4266
  );
4267
+ settleAgentSteps(streamingLineId);
3967
4268
  resetStreamState();
3968
4269
  }
3969
4270
  },
3970
- onError: (error) => {
3971
- if (currentStreamingLineId.current === streamingLineId) {
3972
- if (progressStateRef.current) {
3973
- const snap = captureReasoningSnapshot(
3974
- progressStateRef.current,
3975
- true
3976
- );
3977
- updateStreamingLine(
3978
- streamingLineId,
3979
- fullResponse || "",
3980
- void 0,
3981
- void 0,
3982
- snap
3983
- );
3984
- setProgressState(null);
3985
- } else {
3986
- addTerminalLine("error", `STREAMING ERROR: ${error}`);
3987
- setProgressState(null);
3988
- }
3989
- resetStreamState();
3990
- }
3991
- }
4271
+ onError: fail
3992
4272
  }, reasoningModeRef.current ? { reasoningMode: reasoningModeRef.current } : void 0);
3993
4273
  } catch (error) {
3994
- if (progressStateRef.current && currentStreamingLineId.current) {
3995
- const snap = captureReasoningSnapshot(
3996
- progressStateRef.current,
3997
- true
3998
- );
3999
- updateStreamingLine(
4000
- currentStreamingLineId.current,
4001
- fullResponse || "",
4002
- void 0,
4003
- void 0,
4004
- snap
4005
- );
4006
- }
4007
- addTerminalLine("error", `STREAMING EXCEPTION: ${error.message}`);
4008
- setProgressState(null);
4009
- resetStreamState();
4274
+ fail(error?.message || "The answer could not be completed.");
4010
4275
  }
4011
4276
  },
4012
4277
  [
@@ -4015,7 +4280,9 @@ function useStreamingChat({
4015
4280
  updateStreamingLine,
4016
4281
  setStreamingLineSender,
4017
4282
  resetStreamState,
4018
- addTerminalLine
4283
+ addTerminalLine,
4284
+ settleAgentSteps,
4285
+ currentUser
4019
4286
  ]
4020
4287
  );
4021
4288
  const clearReasoningSession = useCallback(() => {
@@ -4108,6 +4375,7 @@ function useTerminalCore({
4108
4375
  onReasoningModeChangeProp,
4109
4376
  reasoningRef,
4110
4377
  workingGroupContextProp = null,
4378
+ autoFocusInput = true,
4111
4379
  onResolveWorkingGroup,
4112
4380
  onRagFileUpload,
4113
4381
  onListRagFiles,
@@ -4125,12 +4393,13 @@ function useTerminalCore({
4125
4393
  pollIntervalMs,
4126
4394
  authToken
4127
4395
  }) {
4396
+ const agentLabel = config.agentLabel?.trim() || DEFAULT_AGENT_LABEL;
4128
4397
  const [internalReasoningMode, setInternalReasoningMode] = useState(null);
4129
4398
  const reasoningMode = reasoningModeProp !== void 0 ? reasoningModeProp : internalReasoningMode;
4130
4399
  const onReasoningModeChange = onReasoningModeChangeProp || setInternalReasoningMode;
4131
4400
  const [terminalHistory, setTerminalHistory] = useState(() => {
4132
4401
  if (initialHistory && initialHistory.length > 0) return initialHistory;
4133
- return [{ type: "system", content: "YieldFabric Agent", timestamp: /* @__PURE__ */ new Date() }];
4402
+ return [{ type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() }];
4134
4403
  });
4135
4404
  useEffect(() => {
4136
4405
  if (historyRef) {
@@ -4143,7 +4412,7 @@ function useTerminalCore({
4143
4412
  const enrichedHistory = useMemo(() => {
4144
4413
  if (!sourceKGNodes?.length) return terminalHistory;
4145
4414
  let changed = false;
4146
- const result = terminalHistory.map((entry) => {
4415
+ const result2 = terminalHistory.map((entry) => {
4147
4416
  if ((entry.type === "response" || entry.type === "success") && entry.content && entry.content.length > 20 && !entry.sources?.length) {
4148
4417
  const sources = extractKGSources(entry.content, sourceKGNodes);
4149
4418
  if (sources.length > 0) {
@@ -4153,7 +4422,7 @@ function useTerminalCore({
4153
4422
  }
4154
4423
  return entry;
4155
4424
  });
4156
- return changed ? result : terminalHistory;
4425
+ return changed ? result2 : terminalHistory;
4157
4426
  }, [terminalHistory, sourceKGNodes]);
4158
4427
  useEffect(() => {
4159
4428
  if (initialHistory && initialHistory.length > 0) {
@@ -4173,6 +4442,7 @@ function useTerminalCore({
4173
4442
  setTerminalHistory((prev) => [...prev, { id: Date.now().toString(), type: "response", content, timestamp: /* @__PURE__ */ new Date(), suggested_actions: actions }]);
4174
4443
  }, []);
4175
4444
  const [currentCommand, setCurrentCommand] = useState("");
4445
+ const [pendingSubmit, setPendingSubmit] = useState(null);
4176
4446
  const [workingGroupContext, setWorkingGroupContext] = useState(workingGroupContextProp);
4177
4447
  const [hasShownWelcome, setHasShownWelcome] = useState(false);
4178
4448
  const [isInputFocused, setIsInputFocused] = useState(true);
@@ -4185,13 +4455,16 @@ function useTerminalCore({
4185
4455
  for (const ctrl of uploadAbortsRef.current) ctrl.abort();
4186
4456
  uploadAbortsRef.current = [];
4187
4457
  }, []);
4188
- const { inputRef, focusInput } = useFocusManagement();
4458
+ const { inputRef, focusInput } = useFocusManagement(autoFocusInput);
4189
4459
  useEffect(() => {
4190
4460
  function onPrefill(e) {
4191
4461
  const detail = e.detail;
4192
4462
  if (!detail || typeof detail.value !== "string") return;
4193
4463
  const value = detail.value;
4194
4464
  setCurrentCommand(value);
4465
+ if (e.detail?.submit) {
4466
+ setPendingSubmit(value);
4467
+ }
4195
4468
  requestAnimationFrame(() => {
4196
4469
  focusInput();
4197
4470
  const el = inputRef.current;
@@ -4205,6 +4478,9 @@ function useTerminalCore({
4205
4478
  window.removeEventListener("yieldfabric:terminal:prefill", onPrefill);
4206
4479
  };
4207
4480
  }, [focusInput, inputRef]);
4481
+ const restoreInputFocus = useCallback(() => {
4482
+ if (autoFocusInput) focusInput();
4483
+ }, [autoFocusInput, focusInput]);
4208
4484
  const {
4209
4485
  isExecuting,
4210
4486
  setIsExecuting,
@@ -4224,11 +4500,12 @@ function useTerminalCore({
4224
4500
  activityEvents
4225
4501
  } = useStreamingChat({
4226
4502
  config,
4503
+ authToken,
4227
4504
  onStreamRequest,
4228
4505
  reasoningMode,
4229
4506
  setTerminalHistory,
4230
4507
  addTerminalLine,
4231
- focusInput,
4508
+ focusInput: restoreInputFocus,
4232
4509
  currentUser,
4233
4510
  sourceKGNodes
4234
4511
  });
@@ -4291,12 +4568,12 @@ function useTerminalCore({
4291
4568
  }, [onResolveWorkingGroup]);
4292
4569
  useEffect(() => {
4293
4570
  const handleActionResult = (event) => {
4294
- const result = event.detail;
4295
- if (result.success) {
4571
+ const result2 = event.detail;
4572
+ if (result2.success) {
4296
4573
  addTerminalLine("success", "Action executed successfully!");
4297
- if (result.data) addTerminalLine("response", JSON.stringify(result.data, null, 2));
4574
+ if (result2.data) addTerminalLine("response", JSON.stringify(result2.data, null, 2));
4298
4575
  } else {
4299
- addTerminalLine("error", `Action failed: ${result.error || "Unknown error"}`);
4576
+ addTerminalLine("error", `Action failed: ${result2.error || "Unknown error"}`);
4300
4577
  }
4301
4578
  };
4302
4579
  window.addEventListener("terminal-action-result", handleActionResult);
@@ -4308,7 +4585,7 @@ function useTerminalCore({
4308
4585
  const fullMessage = config.welcomeMessage;
4309
4586
  const typingLineId = Date.now().toString();
4310
4587
  setTerminalHistory([
4311
- { type: "system", content: "YieldFabric Agent", timestamp: /* @__PURE__ */ new Date() },
4588
+ { type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
4312
4589
  { id: typingLineId, type: "info", content: "", timestamp: /* @__PURE__ */ new Date() }
4313
4590
  ]);
4314
4591
  let i = 0;
@@ -4364,7 +4641,7 @@ function useTerminalCore({
4364
4641
  }, [commandPaletteItems, selectedPaletteItem]);
4365
4642
  const handleClearCommand = useCallback(() => {
4366
4643
  setTerminalHistory([
4367
- { type: "system", content: "YieldFabric Agent", timestamp: /* @__PURE__ */ new Date() },
4644
+ { type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
4368
4645
  { type: "system", content: "Terminal cleared.", timestamp: /* @__PURE__ */ new Date() }
4369
4646
  ]);
4370
4647
  setCurrentCommand("");
@@ -4387,11 +4664,11 @@ function useTerminalCore({
4387
4664
  addTerminalLine("info", `Uploading ${files.length} file(s)...`);
4388
4665
  setIsExecuting(true);
4389
4666
  try {
4390
- const result = await onRagFileUpload(files, workingGroupContext);
4391
- if (result.success) {
4392
- addTerminalLine("success", `Started ${result.pipelineRuns?.length ?? result.documentsIngested ?? files.length} ingestion pipeline(s)`);
4393
- if (result.message) addTerminalLine("response", result.message);
4394
- const runs = result.pipelineRuns ?? [];
4667
+ const result2 = await onRagFileUpload(files, workingGroupContext);
4668
+ if (result2.success) {
4669
+ addTerminalLine("success", `Started ${result2.pipelineRuns?.length ?? result2.documentsIngested ?? files.length} ingestion pipeline(s)`);
4670
+ if (result2.message) addTerminalLine("response", result2.message);
4671
+ const runs = result2.pipelineRuns ?? [];
4395
4672
  if (runs.length > 0) {
4396
4673
  const apiUrl = config.agentsApiUrl || "http://localhost:3001";
4397
4674
  const remaining = new Set(runs.map((r) => r.run_id));
@@ -4478,7 +4755,7 @@ function useTerminalCore({
4478
4755
  await handleListFilesCommand();
4479
4756
  }
4480
4757
  } else {
4481
- addTerminalLine("error", `Upload failed${result.message ? `: ${result.message}` : ""}`);
4758
+ addTerminalLine("error", `Upload failed${result2.message ? `: ${result2.message}` : ""}`);
4482
4759
  }
4483
4760
  } catch (error) {
4484
4761
  addTerminalLine("error", `Upload exception: ${error?.message || "Unknown error"}`);
@@ -4487,7 +4764,7 @@ function useTerminalCore({
4487
4764
  if (fileInputRef.current) fileInputRef.current.value = "";
4488
4765
  setTimeout(() => focusInput(), 50);
4489
4766
  }
4490
- }, [onRagFileUpload, onListRagFiles, workingGroupContext, addTerminalLine, setIsExecuting, focusInput, config.agentsApiUrl]);
4767
+ }, [onRagFileUpload, onListRagFiles, workingGroupContext, addTerminalLine, setIsExecuting, focusInput, config.agentsApiUrl, authToken]);
4491
4768
  const handleListFilesCommand = useCallback(async () => {
4492
4769
  addTerminalLine("info", "");
4493
4770
  addTerminalLine("command", "files");
@@ -4497,12 +4774,12 @@ function useTerminalCore({
4497
4774
  }
4498
4775
  setIsExecuting(true);
4499
4776
  try {
4500
- const result = await onListRagFiles(workingGroupContext);
4501
- if (!result.success) {
4502
- addTerminalLine("error", `Could not load files${result.message ? `: ${result.message}` : ""}`);
4777
+ const result2 = await onListRagFiles(workingGroupContext);
4778
+ if (!result2.success) {
4779
+ addTerminalLine("error", `Could not load files${result2.message ? `: ${result2.message}` : ""}`);
4503
4780
  return;
4504
4781
  }
4505
- const files = result.files || [];
4782
+ const files = result2.files || [];
4506
4783
  if (files.length === 0) {
4507
4784
  addTerminalLine("info", "No files uploaded yet for this page working group.");
4508
4785
  return;
@@ -4531,12 +4808,12 @@ function useTerminalCore({
4531
4808
  return;
4532
4809
  }
4533
4810
  const title = payload.title || payload.document_id;
4534
- const result = await onDeleteRagFile(String(payload.document_id), workingGroupContext);
4535
- if (result.success) {
4811
+ const result2 = await onDeleteRagFile(String(payload.document_id), workingGroupContext);
4812
+ if (result2.success) {
4536
4813
  addTerminalLine("success", `Removed ${title}`);
4537
4814
  await handleListFilesCommand();
4538
4815
  } else {
4539
- addTerminalLine("error", `Failed to remove ${title}${result.message ? `: ${result.message}` : ""}`);
4816
+ addTerminalLine("error", `Failed to remove ${title}${result2.message ? `: ${result2.message}` : ""}`);
4540
4817
  }
4541
4818
  return;
4542
4819
  }
@@ -4546,9 +4823,9 @@ function useTerminalCore({
4546
4823
  return;
4547
4824
  }
4548
4825
  const title = payload.title || payload.document_id;
4549
- const result = await onDownloadRagFile(String(payload.document_id), title, workingGroupContext);
4550
- if (result.success) addTerminalLine("success", `Download started: ${title}`);
4551
- else addTerminalLine("error", `Download failed for ${title}${result.message ? `: ${result.message}` : ""}`);
4826
+ const result2 = await onDownloadRagFile(String(payload.document_id), title, workingGroupContext);
4827
+ if (result2.success) addTerminalLine("success", `Download started: ${title}`);
4828
+ else addTerminalLine("error", `Download failed for ${title}${result2.message ? `: ${result2.message}` : ""}`);
4552
4829
  return;
4553
4830
  }
4554
4831
  if (actionType === "resume_pipeline_run") {
@@ -4587,6 +4864,8 @@ function useTerminalCore({
4587
4864
  window.dispatchEvent(new CustomEvent("terminal-action-execute", { detail: updatedAction, bubbles: true }));
4588
4865
  }, [onDeleteRagFile, onDownloadRagFile, workingGroupContext, addTerminalLine, handleListFilesCommand, config.agentsApiUrl]);
4589
4866
  return {
4867
+ // Identity
4868
+ agentLabel,
4590
4869
  // History
4591
4870
  terminalHistory,
4592
4871
  setTerminalHistory,
@@ -4615,6 +4894,8 @@ function useTerminalCore({
4615
4894
  // Command input
4616
4895
  currentCommand,
4617
4896
  setCurrentCommand,
4897
+ pendingSubmit,
4898
+ setPendingSubmit,
4618
4899
  commandPaletteItems,
4619
4900
  setCommandPaletteItems,
4620
4901
  selectedPaletteItem,
@@ -4737,6 +5018,7 @@ function extractQuery(input, caret, enabledCommands, requireSlashCommand) {
4737
5018
  return { query: tail, command: cmd };
4738
5019
  }
4739
5020
  function StandardTerminal({
5021
+ showBusyIndicator,
4740
5022
  theme: themeOverrides,
4741
5023
  config,
4742
5024
  onCommandExecute,
@@ -4756,9 +5038,15 @@ function StandardTerminal({
4756
5038
  onDeleteRagFile,
4757
5039
  onDownloadRagFile,
4758
5040
  workingGroupContext: workingGroupContextProp = null,
5041
+ showWorkingGroupBanner = true,
5042
+ autoFocusInput = true,
5043
+ inputPlaceholder,
5044
+ submitRequest,
5045
+ onSubmitRequest,
4759
5046
  onPipelineDraftEdit,
4760
5047
  onPipelineDraftReject,
4761
5048
  onSubmitNote,
5049
+ onSubmitLog,
4762
5050
  onMentionResolve,
4763
5051
  onMentionPicked,
4764
5052
  availableKGs,
@@ -4779,6 +5067,7 @@ function StandardTerminal({
4779
5067
  widgets,
4780
5068
  slots,
4781
5069
  onSourcesActivate,
5070
+ onSourceActivate,
4782
5071
  onPollMessages,
4783
5072
  pollIntervalMs,
4784
5073
  historyRef
@@ -4794,6 +5083,7 @@ function StandardTerminal({
4794
5083
  reasoningRef,
4795
5084
  workingGroupContextProp,
4796
5085
  onResolveWorkingGroup,
5086
+ autoFocusInput,
4797
5087
  onRagFileUpload,
4798
5088
  onListRagFiles,
4799
5089
  onDeleteRagFile,
@@ -4809,17 +5099,32 @@ function StandardTerminal({
4809
5099
  showWelcomeMessage
4810
5100
  });
4811
5101
  const { pushCommand, navigateUp, navigateDown, resetIndex } = useCommandHistory();
5102
+ const consumedRequest = useRef(null);
5103
+ React15.useEffect(() => {
5104
+ if (!submitRequest || consumedRequest.current === submitRequest.id || !submitRequest.value.trim() || !onStreamRequest || core.isExecuting || core.isStreaming || core.currentStreamingLineId.current) return;
5105
+ consumedRequest.current = submitRequest.id;
5106
+ onSubmitRequest?.(submitRequest.id);
5107
+ void core.handleStreamingChat(submitRequest.value.trim());
5108
+ }, [
5109
+ submitRequest,
5110
+ onSubmitRequest,
5111
+ onStreamRequest,
5112
+ core.isExecuting,
5113
+ core.isStreaming,
5114
+ core.currentStreamingLineId,
5115
+ core.handleStreamingChat
5116
+ ]);
4812
5117
  const [suggestions, setSuggestions] = useState([]);
4813
5118
  const [selectedSuggestion, setSelectedSuggestion] = useState(0);
4814
5119
  const [internalAuthToken, setInternalAuthToken] = useState(authToken);
4815
5120
  const authTokenRef = useRef(internalAuthToken);
4816
5121
  authTokenRef.current = internalAuthToken;
4817
- React12.useEffect(() => {
5122
+ React15.useEffect(() => {
4818
5123
  if (authToken !== internalAuthToken) setInternalAuthToken(authToken);
4819
5124
  }, [authToken]);
4820
5125
  const [caretIndex, setCaretIndex] = useState(0);
4821
5126
  const [slashPickedNames, setSlashPickedNames] = useState([]);
4822
- const liveSlashPickedNames = React12.useMemo(
5127
+ const liveSlashPickedNames = React15.useMemo(
4823
5128
  () => slashPickedNames.filter(
4824
5129
  (n) => core.currentCommand.toLowerCase().includes(`@${n.toLowerCase()}`)
4825
5130
  ),
@@ -4906,6 +5211,11 @@ function StandardTerminal({
4906
5211
  setSuggestions([]);
4907
5212
  }
4908
5213
  };
5214
+ React15.useEffect(() => {
5215
+ if (!core.pendingSubmit) return;
5216
+ core.setPendingSubmit(null);
5217
+ void handleSubmit();
5218
+ }, [core.pendingSubmit]);
4909
5219
  const handleSubmit = async () => {
4910
5220
  if (!core.currentCommand.trim() || core.isExecuting || core.isStreaming || core.currentStreamingLineId.current) return;
4911
5221
  const rawCmd = core.currentCommand.trim();
@@ -4953,6 +5263,21 @@ function StandardTerminal({
4953
5263
  setTimeout(() => core.focusInput(), 50);
4954
5264
  return;
4955
5265
  }
5266
+ if (command === "log") {
5267
+ const prose = args.join(" ");
5268
+ core.addTerminalLine("command", prose.trim() ? `log ${prose}` : "log");
5269
+ if (!onSubmitLog) {
5270
+ core.addTerminalLine("error", "Work capture is not available in this context.");
5271
+ } else if (!prose.trim()) {
5272
+ core.addTerminalLine("info", "Usage: /log <what you did or decided>");
5273
+ } else {
5274
+ const result2 = await onSubmitLog(prose);
5275
+ core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
5276
+ }
5277
+ core.setCurrentCommand("");
5278
+ setTimeout(() => core.focusInput(), 50);
5279
+ return;
5280
+ }
4956
5281
  if (isNaturalLanguage(cmd, config.endpoints) && onStreamRequest) {
4957
5282
  await core.handleStreamingChat(cmd);
4958
5283
  core.setCurrentCommand("");
@@ -5008,8 +5333,8 @@ function StandardTerminal({
5008
5333
  );
5009
5334
  return;
5010
5335
  }
5011
- const result = await onSubmitNote(prose, scope);
5012
- core.addTerminalLine(result.ok ? "success" : "error", result.message);
5336
+ const result2 = await onSubmitNote(prose, scope);
5337
+ core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
5013
5338
  };
5014
5339
  const handleTokenCommand = (args) => {
5015
5340
  core.addTerminalLine("command", `token ${args.join(" ")}`);
@@ -5037,18 +5362,18 @@ Method: ${parsed.endpoint.method}
5037
5362
  Path: ${parsed.endpoint.path}`);
5038
5363
  core.addTerminalLine("info", "");
5039
5364
  try {
5040
- const result = await onCommandExecute(cmd, parsed.endpoint, parsed.args);
5041
- if (result.success) {
5042
- core.addTerminalLine("success", result.message || "RESPONSE: SUCCESS");
5043
- if (result.data) core.addTerminalLine("response", JSON.stringify(result.data, null, 2));
5044
- if (parsed.endpoint.id.includes("login") && result.data?.token) {
5045
- setInternalAuthToken(result.data.token);
5046
- onAuthTokenChange?.(result.data.token);
5365
+ const result2 = await onCommandExecute(cmd, parsed.endpoint, parsed.args);
5366
+ if (result2.success) {
5367
+ core.addTerminalLine("success", result2.message || "RESPONSE: SUCCESS");
5368
+ if (result2.data) core.addTerminalLine("response", JSON.stringify(result2.data, null, 2));
5369
+ if (parsed.endpoint.id.includes("login") && result2.data?.token) {
5370
+ setInternalAuthToken(result2.data.token);
5371
+ onAuthTokenChange?.(result2.data.token);
5047
5372
  core.addTerminalLine("success", "AUTH TOKEN AUTO-SAVED");
5048
5373
  }
5049
5374
  } else {
5050
- core.addTerminalLine("error", `ERROR: ${result.error || "Request failed"}`);
5051
- if (result.data) core.addTerminalLine("response", JSON.stringify(result.data, null, 2));
5375
+ core.addTerminalLine("error", `ERROR: ${result2.error || "Request failed"}`);
5376
+ if (result2.data) core.addTerminalLine("response", JSON.stringify(result2.data, null, 2));
5052
5377
  }
5053
5378
  } catch (error) {
5054
5379
  core.addTerminalLine("error", `SYSTEM ERROR: ${error.message}`);
@@ -5071,14 +5396,17 @@ Path: ${parsed.endpoint.path}`);
5071
5396
  className,
5072
5397
  style,
5073
5398
  showHeader,
5399
+ agentLabel: core.agentLabel,
5074
5400
  focusInput: core.focusInput,
5075
5401
  setTerminalHistory: core.setTerminalHistory,
5076
5402
  terminalBodyRef: core.terminalBodyRef,
5077
5403
  workingGroupContext: core.workingGroupContext,
5404
+ showWorkingGroupBanner,
5078
5405
  progressState: core.progressState,
5079
5406
  streamTransparency: core.streamTransparency,
5080
5407
  streamNowMs: core.streamNowMs,
5081
5408
  isExecuting: core.isExecuting,
5409
+ showBusyIndicator,
5082
5410
  handleCancelReasoning: core.handleCancelReasoning,
5083
5411
  onViewKnowledgeGraph,
5084
5412
  onLiveKGUpdate,
@@ -5153,11 +5481,12 @@ Path: ${parsed.endpoint.path}`);
5153
5481
  inputBar: /* @__PURE__ */ jsx(
5154
5482
  TerminalInputBar,
5155
5483
  {
5484
+ autoFocus: autoFocusInput,
5156
5485
  inputRef: core.inputRef,
5157
5486
  fileInputRef: core.fileInputRef,
5158
5487
  currentCommand: core.currentCommand,
5159
5488
  isExecuting: core.isExecuting,
5160
- placeholder: activeKGScope ? `Ask about ${activeKGScope.label}...` : "Ask anything...",
5489
+ placeholder: activeKGScope ? `Ask about ${activeKGScope.label}...` : inputPlaceholder ?? "Ask anything...",
5161
5490
  onInputChange: handleInputChange,
5162
5491
  onKeyDown: handleKeyDown,
5163
5492
  onSubmit: handleSubmit,
@@ -5194,6 +5523,7 @@ Path: ${parsed.endpoint.path}`);
5194
5523
  authToken: authTokenRef.current,
5195
5524
  onPageNavigation,
5196
5525
  onSourcesActivate,
5526
+ onSourceActivate,
5197
5527
  renderEntryExtra,
5198
5528
  renderEntry,
5199
5529
  widgets,
@@ -5484,6 +5814,7 @@ function useMentions(currentCommand, participants, mentionTargets) {
5484
5814
  };
5485
5815
  }
5486
5816
  function ChatTerminal({
5817
+ showBusyIndicator,
5487
5818
  theme: themeOverrides,
5488
5819
  config,
5489
5820
  className = "",
@@ -5499,6 +5830,8 @@ function ChatTerminal({
5499
5830
  onDeleteRagFile,
5500
5831
  onDownloadRagFile,
5501
5832
  workingGroupContext: workingGroupContextProp = null,
5833
+ showWorkingGroupBanner = true,
5834
+ autoFocusInput = true,
5502
5835
  onPipelineDraftEdit,
5503
5836
  onPipelineDraftReject,
5504
5837
  onPageNavigation,
@@ -5521,6 +5854,7 @@ function ChatTerminal({
5521
5854
  widgets,
5522
5855
  slots,
5523
5856
  onSourcesActivate,
5857
+ onSourceActivate,
5524
5858
  historyRef,
5525
5859
  currentUser,
5526
5860
  onSendMessage,
@@ -5530,8 +5864,10 @@ function ChatTerminal({
5530
5864
  typingUsers,
5531
5865
  onTyping,
5532
5866
  onSubmitNote,
5867
+ onSubmitLog,
5533
5868
  onMentionResolve,
5534
- onMentionPicked
5869
+ onMentionPicked,
5870
+ authToken
5535
5871
  }) {
5536
5872
  const core = useTerminalCore({
5537
5873
  config,
@@ -5544,6 +5880,7 @@ function ChatTerminal({
5544
5880
  reasoningRef,
5545
5881
  workingGroupContextProp,
5546
5882
  onResolveWorkingGroup,
5883
+ autoFocusInput,
5547
5884
  onRagFileUpload,
5548
5885
  onListRagFiles,
5549
5886
  onDeleteRagFile,
@@ -5557,7 +5894,8 @@ function ChatTerminal({
5557
5894
  showWelcomeMessage,
5558
5895
  currentUser,
5559
5896
  onPollMessages,
5560
- pollIntervalMs
5897
+ pollIntervalMs,
5898
+ authToken
5561
5899
  });
5562
5900
  useEffect(() => {
5563
5901
  onActivityEventsChange?.(core.activityEvents);
@@ -5701,11 +6039,26 @@ function ChatTerminal({
5701
6039
  `Usage: /${command} <prose>. Use @name to link an entity.`
5702
6040
  );
5703
6041
  } else {
5704
- const result = await onSubmitNote(
6042
+ const result2 = await onSubmitNote(
5705
6043
  prose,
5706
6044
  command === "personal" ? "personal" : "workspace"
5707
6045
  );
5708
- core.addTerminalLine(result.ok ? "success" : "error", result.message);
6046
+ core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
6047
+ }
6048
+ core.setCurrentCommand("");
6049
+ setTimeout(() => core.focusInput(), 50);
6050
+ return;
6051
+ }
6052
+ if (command === "log") {
6053
+ const prose = args.join(" ");
6054
+ core.addTerminalLine("command", prose.trim() ? `log ${prose}` : "log");
6055
+ if (!onSubmitLog) {
6056
+ core.addTerminalLine("error", "Work capture is not available in this context.");
6057
+ } else if (!prose.trim()) {
6058
+ core.addTerminalLine("info", "Usage: /log <what you did or decided>");
6059
+ } else {
6060
+ const result2 = await onSubmitLog(prose);
6061
+ core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
5709
6062
  }
5710
6063
  core.setCurrentCommand("");
5711
6064
  setTimeout(() => core.focusInput(), 50);
@@ -5752,14 +6105,17 @@ function ChatTerminal({
5752
6105
  className,
5753
6106
  style,
5754
6107
  showHeader,
6108
+ agentLabel: core.agentLabel,
5755
6109
  focusInput: core.focusInput,
5756
6110
  setTerminalHistory: core.setTerminalHistory,
5757
6111
  terminalBodyRef: core.terminalBodyRef,
5758
6112
  workingGroupContext: core.workingGroupContext,
6113
+ showWorkingGroupBanner,
5759
6114
  progressState: core.progressState,
5760
6115
  streamTransparency: core.streamTransparency,
5761
6116
  streamNowMs: core.streamNowMs,
5762
6117
  isExecuting: core.isExecuting,
6118
+ showBusyIndicator,
5763
6119
  handleCancelReasoning: core.handleCancelReasoning,
5764
6120
  onViewKnowledgeGraph,
5765
6121
  onLiveKGUpdate,
@@ -5796,6 +6152,7 @@ function ChatTerminal({
5796
6152
  inputBar: /* @__PURE__ */ jsx(
5797
6153
  TerminalInputBar,
5798
6154
  {
6155
+ autoFocus: autoFocusInput,
5799
6156
  inputRef: core.inputRef,
5800
6157
  fileInputRef: core.fileInputRef,
5801
6158
  currentCommand: core.currentCommand,
@@ -5848,6 +6205,7 @@ function ChatTerminal({
5848
6205
  config,
5849
6206
  onPageNavigation,
5850
6207
  onSourcesActivate,
6208
+ onSourceActivate,
5851
6209
  renderEntryExtra,
5852
6210
  renderEntry,
5853
6211
  widgets,
@@ -7004,6 +7362,227 @@ function ReasoningHistoryCard({
7004
7362
  }
7005
7363
  );
7006
7364
  }
7365
+ function subject(step) {
7366
+ const idx = step.detail.indexOf(": ");
7367
+ const s = idx > -1 ? step.detail.slice(idx + 2).trim() : "";
7368
+ return s.length ? s : null;
7369
+ }
7370
+ function bare(tool) {
7371
+ return tool.replace(/^yf_kg_/, "").replace(/^yf_/, "");
7372
+ }
7373
+ function action(step) {
7374
+ const subj = subject(step);
7375
+ const quoted = subj ? `\u201C${subj}\u201D` : null;
7376
+ switch (bare(step.tool)) {
7377
+ case "graphs":
7378
+ return "Listed knowledge collections";
7379
+ case "search":
7380
+ return quoted ? `Searched for ${quoted}` : "Searched the documents";
7381
+ case "count":
7382
+ return quoted ? `Counted mentions of ${quoted}` : "Counted mentions";
7383
+ case "enumerate":
7384
+ return quoted ? `Listed every match for ${quoted}` : "Listed every match";
7385
+ case "fetch":
7386
+ return "Read a document";
7387
+ case "entities":
7388
+ return "Listed the people and things found";
7389
+ case "explore":
7390
+ return quoted ? `Followed connections from ${quoted}` : "Followed connections";
7391
+ case "sets":
7392
+ return "Listed frozen document sets";
7393
+ case "get_set":
7394
+ return "Read a frozen document set";
7395
+ case "count_in_set":
7396
+ return quoted ? `Counted ${quoted} inside a set` : "Counted inside a set";
7397
+ case "think":
7398
+ return "Thought it through";
7399
+ default:
7400
+ return subj ? `${bare(step.tool).replace(/_/g, " ")} ${subj}` : bare(step.tool).replace(/_/g, " ");
7401
+ }
7402
+ }
7403
+ function took(step) {
7404
+ if (step.status === "running") return null;
7405
+ const ms = Number(step.ms);
7406
+ if (!Number.isFinite(ms) || ms < 1e3) return null;
7407
+ return ms < 1e4 ? `${(ms / 1e3).toFixed(1)}s` : `${Math.round(ms / 1e3)}s`;
7408
+ }
7409
+ function groupTook(g) {
7410
+ const slowest = g.steps.reduce(
7411
+ (worst, s) => Number(s.ms) > Number(worst.ms) ? s : worst,
7412
+ g.steps[0]
7413
+ );
7414
+ return took(slowest);
7415
+ }
7416
+ function result(step) {
7417
+ if (step.status === "running") return null;
7418
+ if (step.status === "error") return "unavailable";
7419
+ const n = Number(step.outcome);
7420
+ if (!Number.isFinite(n)) return null;
7421
+ const [one, many] = {
7422
+ graphs: ["collection", "collections"],
7423
+ search: ["result", "results"],
7424
+ count: ["document", "documents"],
7425
+ enumerate: ["match", "matches"],
7426
+ entities: ["entity", "entities"],
7427
+ explore: ["connection", "connections"],
7428
+ sets: ["set", "sets"]
7429
+ }[bare(step.tool)] ?? ["result", "results"];
7430
+ if (n === 0) return "nothing found";
7431
+ return `${n} ${n === 1 ? one : many}`;
7432
+ }
7433
+ function group(steps) {
7434
+ const out = [];
7435
+ const byKey = /* @__PURE__ */ new Map();
7436
+ for (const step of steps) {
7437
+ const label = action(step);
7438
+ const key = `${step.round ?? ""}\0${label}`;
7439
+ const existing = byKey.get(key);
7440
+ if (existing) {
7441
+ existing.steps.push(step);
7442
+ continue;
7443
+ }
7444
+ const g = { key: step.seq, label, round: step.round, steps: [step] };
7445
+ byKey.set(key, g);
7446
+ out.push(g);
7447
+ }
7448
+ return out;
7449
+ }
7450
+ function groupResult(g) {
7451
+ if (g.steps.length === 1) return result(g.steps[0]);
7452
+ const done = g.steps.filter((s) => s.status !== "running");
7453
+ if (!done.length) return null;
7454
+ const hits = done.filter((s) => Number(s.outcome) > 0).length;
7455
+ if (hits === 0) return "nothing found";
7456
+ return `found in ${hits} of ${done.length}`;
7457
+ }
7458
+ function roundCount(steps) {
7459
+ const seen = /* @__PURE__ */ new Set();
7460
+ for (const s of steps) if (typeof s.round === "number") seen.add(s.round);
7461
+ return seen.size ? seen.size : null;
7462
+ }
7463
+ function AgentStepTrace({ steps, working }) {
7464
+ const t = useTheme();
7465
+ const failed = steps.some((s) => s.status === "error");
7466
+ const prominent = working || failed;
7467
+ const [open, setOpen] = useState(prominent);
7468
+ const [touched, setTouched] = useState(false);
7469
+ const [hover, setHover] = useState(false);
7470
+ useEffect(() => {
7471
+ if (!touched) setOpen(prominent);
7472
+ }, [prominent, touched]);
7473
+ if (!steps.length) return null;
7474
+ const groups = group(steps);
7475
+ const rounds = roundCount(steps);
7476
+ const n = rounds ?? groups.length;
7477
+ const count = `${n} ${rounds ? "round" : "step"}${n === 1 ? "" : "s"}`;
7478
+ const only = groups.length === 1 ? groups[0] : null;
7479
+ const summary = working ? `${action(steps[steps.length - 1])}\u2026` : failed ? `${count}, some unavailable` : only ? [
7480
+ only.label + (only.steps.length > 1 ? ` \xD7${only.steps.length}` : ""),
7481
+ groupResult(only)
7482
+ ].filter(Boolean).join(" \u2014 ") : count;
7483
+ const toggle = /* @__PURE__ */ jsxs(
7484
+ "button",
7485
+ {
7486
+ type: "button",
7487
+ onClick: () => {
7488
+ setTouched(true);
7489
+ setOpen((o) => !o);
7490
+ },
7491
+ onMouseEnter: () => setHover(true),
7492
+ onMouseLeave: () => setHover(false),
7493
+ "aria-expanded": open,
7494
+ className: "flex w-full items-center gap-2 text-left text-xs",
7495
+ style: { color: failed ? t.error : hover ? t.text : t.textMuted },
7496
+ children: [
7497
+ working && /* @__PURE__ */ jsx(
7498
+ "span",
7499
+ {
7500
+ "aria-hidden": true,
7501
+ className: "inline-block h-1.5 w-1.5 shrink-0 rounded-full motion-safe:animate-pulse",
7502
+ style: { backgroundColor: t.primary }
7503
+ }
7504
+ ),
7505
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: summary }),
7506
+ !(only && !working && !failed) && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "shrink-0", children: open ? "\u2212" : "+" })
7507
+ ]
7508
+ }
7509
+ );
7510
+ const rows = /* @__PURE__ */ jsx("ol", { className: "mt-2 space-y-1", children: groups.map((g, i) => {
7511
+ const res = groupResult(g);
7512
+ const slow = groupTook(g);
7513
+ const anyError = g.steps.some((s) => s.status === "error");
7514
+ const running = g.steps.some((s) => s.status === "running");
7515
+ const startsRound = g.round !== void 0 && g.round !== groups[i - 1]?.round;
7516
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-baseline gap-2 text-xs", children: [
7517
+ rounds !== null && /* @__PURE__ */ jsx(
7518
+ "span",
7519
+ {
7520
+ className: "w-3 shrink-0 text-right tabular-nums",
7521
+ style: { color: t.textMuted },
7522
+ "aria-hidden": !startsRound,
7523
+ children: startsRound ? g.round : ""
7524
+ }
7525
+ ),
7526
+ /* @__PURE__ */ jsx(
7527
+ "span",
7528
+ {
7529
+ "aria-hidden": true,
7530
+ className: "w-3 shrink-0 text-[10px]",
7531
+ style: { color: anyError ? t.error : t.textMuted },
7532
+ children: running ? "\xB7" : anyError ? "!" : "\u2713"
7533
+ }
7534
+ ),
7535
+ /* @__PURE__ */ jsxs(
7536
+ "span",
7537
+ {
7538
+ className: "min-w-0 flex-1 truncate",
7539
+ style: { color: t.textSecondary },
7540
+ title: g.label,
7541
+ children: [
7542
+ g.label,
7543
+ g.steps.length > 1 && /* @__PURE__ */ jsxs("span", { style: { color: t.textMuted }, children: [
7544
+ " \xD7",
7545
+ g.steps.length
7546
+ ] })
7547
+ ]
7548
+ }
7549
+ ),
7550
+ slow && /* @__PURE__ */ jsx(
7551
+ "span",
7552
+ {
7553
+ className: "shrink-0 tabular-nums",
7554
+ style: { color: t.textMuted },
7555
+ children: slow
7556
+ }
7557
+ ),
7558
+ res && /* @__PURE__ */ jsx("span", { className: "shrink-0", style: { color: anyError ? t.error : t.textMuted }, children: res })
7559
+ ] }, g.key);
7560
+ }) });
7561
+ if (!prominent) {
7562
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
7563
+ toggle,
7564
+ open && !only && rows
7565
+ ] });
7566
+ }
7567
+ return /* @__PURE__ */ jsxs(
7568
+ "div",
7569
+ {
7570
+ className: "mt-2 rounded-lg p-3",
7571
+ style: { backgroundColor: t.bgRaisedAlt, border: `1px solid ${t.border}` },
7572
+ children: [
7573
+ toggle,
7574
+ open && rows
7575
+ ]
7576
+ }
7577
+ );
7578
+ }
7579
+ function agentStepTraceExtra(entry) {
7580
+ const meta = entry.metadata;
7581
+ const steps = meta?.agentSteps;
7582
+ if (!steps?.length) return null;
7583
+ const working = meta?.agentStepsLive ?? entry.content.endsWith("\u258B");
7584
+ return /* @__PURE__ */ jsx(AgentStepTrace, { steps, working });
7585
+ }
7007
7586
 
7008
7587
  // src/knowledge/graphTheme.ts
7009
7588
  var NODE_TYPE_COLORS = {
@@ -7479,7 +8058,7 @@ var MarkdownContent = memo(function MarkdownContent2({
7479
8058
  if (!entities || entities.length === 0) return MARKDOWN_COMPONENTS;
7480
8059
  return { ...MARKDOWN_COMPONENTS, ...buildHighlightOverrides(entities, onEntityClick) };
7481
8060
  }, [entities, onEntityClick]);
7482
- return /* @__PURE__ */ jsx("div", { className: `text-xs leading-relaxed text-gray-300 break-words ${className}`, children: /* @__PURE__ */ jsx(ReactMarkdown, { components, children }) });
8061
+ return /* @__PURE__ */ jsx("div", { className: `text-xs leading-relaxed text-gray-300 break-words ${className}`, children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children }) });
7483
8062
  });
7484
8063
  function escapeRegex(s) {
7485
8064
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -7545,13 +8124,13 @@ function highlightText(text, regex, entityMap, onEntityClick) {
7545
8124
  return parts;
7546
8125
  }
7547
8126
  function highlightChildren(children, regex, entityMap, onEntityClick) {
7548
- return React12.Children.map(children, (child) => {
8127
+ return React15.Children.map(children, (child) => {
7549
8128
  if (typeof child === "string") {
7550
8129
  const highlighted = highlightText(child, regex, entityMap, onEntityClick);
7551
8130
  return highlighted.length === 1 && typeof highlighted[0] === "string" ? child : /* @__PURE__ */ jsx(Fragment, { children: highlighted });
7552
8131
  }
7553
- if (React12.isValidElement(child) && child.props.children) {
7554
- return React12.cloneElement(child, {
8132
+ if (React15.isValidElement(child) && child.props.children) {
8133
+ return React15.cloneElement(child, {
7555
8134
  ...child.props,
7556
8135
  children: highlightChildren(child.props.children, regex, entityMap, onEntityClick)
7557
8136
  });
@@ -8022,10 +8601,10 @@ var SAVE_STAGE_MESSAGES = {
8022
8601
  extracting: "re-analyzing entities with AI\u2026",
8023
8602
  finishing: "almost done \xB7 finalizing graph\u2026"
8024
8603
  };
8025
- function summarizeSaveResult(result) {
8026
- if (!result?.diff) return "Saved";
8027
- const added = result.diff.added_node_keys?.length ?? 0;
8028
- const removed = result.diff.removed_node_keys?.length ?? 0;
8604
+ function summarizeSaveResult(result2) {
8605
+ if (!result2?.diff) return "Saved";
8606
+ const added = result2.diff.added_node_keys?.length ?? 0;
8607
+ const removed = result2.diff.removed_node_keys?.length ?? 0;
8029
8608
  if (added === 0 && removed === 0) return "Saved \xB7 graph unchanged";
8030
8609
  const parts = [];
8031
8610
  if (added > 0) parts.push(`+${added}`);
@@ -8104,11 +8683,11 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
8104
8683
  setIsSaving(true);
8105
8684
  try {
8106
8685
  const rawResult = await onSaveDescription(draftAtSaveTime);
8107
- const result = rawResult ?? null;
8686
+ const result2 = rawResult ?? null;
8108
8687
  if (currentNodeIdRef.current === savingForNodeId) {
8109
8688
  setLocalDescription(draftAtSaveTime);
8110
8689
  setIsEditing(false);
8111
- setLastSaveResult(result);
8690
+ setLastSaveResult(result2);
8112
8691
  if (savedPillTimerRef.current) clearTimeout(savedPillTimerRef.current);
8113
8692
  savedPillTimerRef.current = setTimeout(() => {
8114
8693
  setLastSaveResult(null);
@@ -8644,11 +9223,11 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
8644
9223
  renderedClaims.length,
8645
9224
  ")"
8646
9225
  ] }),
8647
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: claimGroups.map((group) => {
8648
- const isRelated = group.predicate === "(related)";
9226
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: claimGroups.map((group2) => {
9227
+ const isRelated = group2.predicate === "(related)";
8649
9228
  return /* @__PURE__ */ jsxs("div", { children: [
8650
- group.items.length > 1 && /* @__PURE__ */ jsx("div", { className: "text-[10px] text-gray-500 italic mb-0.5 px-2", children: group.predicate }),
8651
- /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: group.items.map((claim) => {
9229
+ group2.items.length > 1 && /* @__PURE__ */ jsx("div", { className: "text-[10px] text-gray-500 italic mb-0.5 px-2", children: group2.predicate }),
9230
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: group2.items.map((claim) => {
8652
9231
  const cnColors = getNodeColors(claim.targetType);
8653
9232
  return /* @__PURE__ */ jsxs(
8654
9233
  "button",
@@ -8686,7 +9265,7 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
8686
9265
  claim.key
8687
9266
  );
8688
9267
  }) })
8689
- ] }, group.predicate);
9268
+ ] }, group2.predicate);
8690
9269
  }) })
8691
9270
  ] }),
8692
9271
  Object.keys(visibleProperties).length > 0 && /* @__PURE__ */ jsxs("div", { children: [
@@ -9301,7 +9880,7 @@ var RECRUITING_LINES = [
9301
9880
  ];
9302
9881
  function RecruitingHint() {
9303
9882
  const [idx, setIdx] = useState(0);
9304
- React12.useEffect(() => {
9883
+ React15.useEffect(() => {
9305
9884
  const t = setInterval(() => setIdx((i) => (i + 1) % RECRUITING_LINES.length), 2500);
9306
9885
  return () => clearInterval(t);
9307
9886
  }, []);
@@ -9404,7 +9983,7 @@ function RelationshipSentence({ rel }) {
9404
9983
  const hasRange = rel.range.length > 0;
9405
9984
  return /* @__PURE__ */ jsxs("div", { style: { lineHeight: 2, color: "#888", fontSize: 13, wordBreak: "break-word" }, children: [
9406
9985
  hasDomain && /* @__PURE__ */ jsxs(Fragment, { children: [
9407
- rel.domain.map((d, i) => /* @__PURE__ */ jsxs(React12.Fragment, { children: [
9986
+ rel.domain.map((d, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
9408
9987
  i > 0 && /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: " or " }),
9409
9988
  /* @__PURE__ */ jsx(TypeChip, { name: d })
9410
9989
  ] }, d)),
@@ -9413,7 +9992,7 @@ function RelationshipSentence({ rel }) {
9413
9992
  /* @__PURE__ */ jsx("span", { style: { color: "#ddd", fontStyle: "italic", fontWeight: 500 }, children: verb }),
9414
9993
  hasRange && /* @__PURE__ */ jsxs(Fragment, { children: [
9415
9994
  " ",
9416
- rel.range.map((r, i) => /* @__PURE__ */ jsxs(React12.Fragment, { children: [
9995
+ rel.range.map((r, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
9417
9996
  i > 0 && /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: " and " }),
9418
9997
  /* @__PURE__ */ jsx(TypeChip, { name: r })
9419
9998
  ] }, r))
@@ -9933,7 +10512,7 @@ function DocumentProcessingProgress() {
9933
10512
  if (!state) return null;
9934
10513
  const currentIdx = DOCUMENT_PIPELINE_STEPS.findIndex((s) => s.key === state.step);
9935
10514
  return /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex flex-col gap-1", style: { borderBottom: "1px solid #282828", backgroundColor: "#1a1a1a" }, children: [
9936
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0", children: DOCUMENT_PIPELINE_STEPS.map((step, i) => /* @__PURE__ */ jsxs(React12.Fragment, { children: [
10515
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0", children: DOCUMENT_PIPELINE_STEPS.map((step, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
9937
10516
  i > 0 && /* @__PURE__ */ jsx("div", { className: "w-2 h-px mx-0.5", style: { backgroundColor: i <= currentIdx ? "#10b981" : "#333" } }),
9938
10517
  /* @__PURE__ */ jsx(
9939
10518
  "span",
@@ -10217,10 +10796,10 @@ function hydrateAgentIds(ids) {
10217
10796
  };
10218
10797
  });
10219
10798
  }
10220
- function stageReducer(state, action) {
10221
- switch (action.type) {
10799
+ function stageReducer(state, action2) {
10800
+ switch (action2.type) {
10222
10801
  case "TEAM_SETUP": {
10223
- const incomingIds = new Set(action.agents.map((a) => a.id));
10802
+ const incomingIds = new Set(action2.agents.map((a) => a.id));
10224
10803
  let isWholesaleReplace = state.lastBackendTeamIds.size > 0;
10225
10804
  if (isWholesaleReplace) {
10226
10805
  state.lastBackendTeamIds.forEach((id) => {
@@ -10238,48 +10817,48 @@ function stageReducer(state, action) {
10238
10817
  return {
10239
10818
  ...state,
10240
10819
  stage: "team_formation",
10241
- team: [...action.agents, ...surviving],
10820
+ team: [...action2.agents, ...surviving],
10242
10821
  localOnlyAgentIds: nextLocalOnly,
10243
10822
  lastBackendTeamIds: incomingIds
10244
10823
  };
10245
10824
  }
10246
10825
  case "PHASE_ADVANCED": {
10247
- const to = action.to;
10826
+ const to = action2.to;
10248
10827
  if (to === "team_formation") return { ...state, stage: "team_formation" };
10249
10828
  if (to === "schema_seeding") return { ...state, stage: "schema_seeding" };
10250
10829
  if (to === "construction" || to === "synthesis" || to === "done") return { ...state, stage: "graph" };
10251
10830
  return state;
10252
10831
  }
10253
10832
  case "UPDATE_AGENT":
10254
- return { ...state, team: state.team.map((a) => a.id === action.id ? { ...a, ...action.updates } : a) };
10833
+ return { ...state, team: state.team.map((a) => a.id === action2.id ? { ...a, ...action2.updates } : a) };
10255
10834
  case "REMOVE_AGENT": {
10256
10835
  const nextLocalOnly = new Set(state.localOnlyAgentIds);
10257
- nextLocalOnly.delete(action.id);
10836
+ nextLocalOnly.delete(action2.id);
10258
10837
  return {
10259
10838
  ...state,
10260
- team: state.team.filter((a) => a.id !== action.id),
10839
+ team: state.team.filter((a) => a.id !== action2.id),
10261
10840
  localOnlyAgentIds: nextLocalOnly
10262
10841
  };
10263
10842
  }
10264
10843
  case "ADD_AGENT": {
10265
10844
  const nextLocalOnly = new Set(state.localOnlyAgentIds);
10266
- nextLocalOnly.add(action.agent.id);
10845
+ nextLocalOnly.add(action2.agent.id);
10267
10846
  return {
10268
10847
  ...state,
10269
- team: [...state.team, action.agent],
10848
+ team: [...state.team, action2.agent],
10270
10849
  localOnlyAgentIds: nextLocalOnly
10271
10850
  };
10272
10851
  }
10273
10852
  case "SCHEMA_SEEDED":
10274
- return { ...state, schemaNodeTypeCount: action.nodeTypeCount, schemaEdgeTypeCount: action.edgeTypeCount };
10853
+ return { ...state, schemaNodeTypeCount: action2.nodeTypeCount, schemaEdgeTypeCount: action2.edgeTypeCount };
10275
10854
  case "SCHEMA_TYPE_ADDED":
10276
- return { ...state, schemaNodeTypes: state.schemaNodeTypes.includes(action.typeName) ? state.schemaNodeTypes : [...state.schemaNodeTypes, action.typeName] };
10855
+ return { ...state, schemaNodeTypes: state.schemaNodeTypes.includes(action2.typeName) ? state.schemaNodeTypes : [...state.schemaNodeTypes, action2.typeName] };
10277
10856
  case "SCHEMA_TEXT": {
10278
10857
  const rels = [];
10279
10858
  const nodeTypes2 = new Set(state.schemaNodeTypes);
10280
10859
  const relPattern = /(\w+)\s*:\s*\[([^\]]*)\]\s*→\s*\[([^\]]*)\]/g;
10281
10860
  let m;
10282
- while ((m = relPattern.exec(action.text)) !== null) {
10861
+ while ((m = relPattern.exec(action2.text)) !== null) {
10283
10862
  const name = m[1];
10284
10863
  const domain = m[2].split(",").map((s) => s.replace(/"/g, "").trim()).filter(Boolean);
10285
10864
  const range = m[3].split(",").map((s) => s.replace(/"/g, "").trim()).filter(Boolean);
@@ -10294,7 +10873,7 @@ function stageReducer(state, action) {
10294
10873
  };
10295
10874
  }
10296
10875
  case "DOC_STEP": {
10297
- const step = action.step;
10876
+ const step = action2.step;
10298
10877
  if (step === "complete") return { ...state, stage: "graph" };
10299
10878
  if (step === "processing" || step === "vocabulary") return { ...state, stage: "doc_preparing" };
10300
10879
  if (step === "extracting") return { ...state, stage: "doc_extracting" };
@@ -10303,7 +10882,7 @@ function stageReducer(state, action) {
10303
10882
  return state;
10304
10883
  }
10305
10884
  case "DOC_ACTIVITY":
10306
- return { ...state, docActivity: [...state.docActivity, action.item] };
10885
+ return { ...state, docActivity: [...state.docActivity, action2.item] };
10307
10886
  case "FORCE_GRAPH":
10308
10887
  return { ...state, stage: "graph" };
10309
10888
  default:
@@ -11169,7 +11748,7 @@ function PipelineProgressBar({ listenForEvents = true, currentPhase: currentPhas
11169
11748
  PIPELINE_STEPS.map((step, i) => {
11170
11749
  const isCompleted = completed.has(step.key) || i < currentIdx;
11171
11750
  const isCurrent = step.key === currentPhase;
11172
- return /* @__PURE__ */ jsxs(React12.Fragment, { children: [
11751
+ return /* @__PURE__ */ jsxs(React15.Fragment, { children: [
11173
11752
  i > 0 && /* @__PURE__ */ jsx(
11174
11753
  "div",
11175
11754
  {
@@ -12957,19 +13536,19 @@ function KnowledgeGraphView({
12957
13536
  setSearching(true);
12958
13537
  searchTimerRef.current = setTimeout(async () => {
12959
13538
  try {
12960
- const result = data.onSearchNodes ? await data.onSearchNodes(groupId, kgId, q, 10, 2) : { hits: [], traversal: [] };
12961
- setSearchResult(result);
12962
- if (result.hits.length === 0 && localMatchIds.size === 0) {
13539
+ const result2 = data.onSearchNodes ? await data.onSearchNodes(groupId, kgId, q, 10, 2) : { hits: [], traversal: [] };
13540
+ setSearchResult(result2);
13541
+ if (result2.hits.length === 0 && localMatchIds.size === 0) {
12963
13542
  restoreFullGraph();
12964
13543
  setSearching(false);
12965
13544
  return;
12966
13545
  }
12967
- if (result.hits.length === 0) {
13546
+ if (result2.hits.length === 0) {
12968
13547
  setSearching(false);
12969
13548
  return;
12970
13549
  }
12971
13550
  const scoreMap = /* @__PURE__ */ new Map();
12972
- result.hits.forEach((h) => {
13551
+ result2.hits.forEach((h) => {
12973
13552
  const existing = scoreMap.get(h.node_key) ?? 0;
12974
13553
  if ((h.score ?? 0) > existing) scoreMap.set(h.node_key, h.score ?? 0);
12975
13554
  });
@@ -12977,9 +13556,9 @@ function KnowledgeGraphView({
12977
13556
  if (!scoreMap.has(id)) scoreMap.set(id, 0.5);
12978
13557
  });
12979
13558
  const traversalIds = /* @__PURE__ */ new Set();
12980
- result.traversal.forEach((t) => traversalIds.add(t.node_key));
13559
+ result2.traversal.forEach((t) => traversalIds.add(t.node_key));
12981
13560
  const neighborIds = /* @__PURE__ */ new Set();
12982
- result.hits.forEach((h) => {
13561
+ result2.hits.forEach((h) => {
12983
13562
  h.neighbors?.forEach((nk) => {
12984
13563
  if (!scoreMap.has(nk)) neighborIds.add(nk);
12985
13564
  });
@@ -13468,9 +14047,9 @@ function KnowledgeGraphView({
13468
14047
  if (!data.onCreateNote || !draftNote || !draftNote.trim()) return;
13469
14048
  setSavingDraft(true);
13470
14049
  try {
13471
- const result = await data.onCreateNote(groupId, kgId, draftNote);
14050
+ const result2 = await data.onCreateNote(groupId, kgId, draftNote);
13472
14051
  setDraftNote(null);
13473
- setSelectedNodeId(`chunk:${result.chunk_id}`);
14052
+ setSelectedNodeId(`chunk:${result2.chunk_id}`);
13474
14053
  if (data.onLoadAllChunks) {
13475
14054
  try {
13476
14055
  const fresh = await data.onLoadAllChunks(groupId, kgId);
@@ -13479,10 +14058,10 @@ function KnowledgeGraphView({
13479
14058
  console.warn("[KGV] post-create chunk refetch failed", err);
13480
14059
  }
13481
14060
  }
13482
- if (result.run_id && config?.agentsApiUrl) {
14061
+ if (result2.run_id && config?.agentsApiUrl) {
13483
14062
  setNoteRuns((prev) => [
13484
14063
  ...prev,
13485
- { run_id: result.run_id, kg_id: kgId }
14064
+ { run_id: result2.run_id, kg_id: kgId }
13486
14065
  ]);
13487
14066
  }
13488
14067
  } catch (err) {
@@ -14037,4 +14616,4 @@ var terminalClassNames = {
14037
14616
  promptSymbol: "terminal-prompt-symbol"
14038
14617
  };
14039
14618
 
14040
- export { ADVANCE_PHASE_SIGNAL, AGENT_PALETTE, AgentAvatar, AgentPresenceBar, AnnotationThread, CLAIM_STATUS_COLORS, ChatTerminal, CheckpointCard, ClaimNode, ConstructionProgress, CoreTerminal, DOCUMENT_PIPELINE_STEPS, DocumentProcessingProgress, EDGE_TYPE_COLORS, EdgeDetailDrawer, EdgeMarkerDefs, CoreTerminal as EmbeddedTerminal, ExpandableTerminal, GraphChatPanel, GraphEdge, GraphNode, InlineTerminal, KnowledgeGraphView, LIVE_KG_ID, LiveActivityTicker, MarkdownContent, MarkdownEditor, NODE_TYPE_COLORS, NODE_TYPE_LABELS, NodeDetailDrawer, PROGRESS_EVENT_NAME, PipelineProgressBar, ReasoningHistoryCard, ReasoningOverlay, ReasoningView, SYNTHESIS_DONE_SIGNAL, ScopedReasoningProvider, SettlementBar, SlashMentionPicker, StageCanvas, StandardTerminal, TerminalInputBar, TerminalThemeProvider, agentSeed, avatarColor, blueScope, buildClaimsGraph, buildTerminalCommand, buttonShadow, captureReasoningSnapshot, defaultTheme, dispatchProgressEvent, documentEventToActivity, emeraldCollab, emeraldRevised, eventToActivity, extractKGSources, extractKgId, filterCommands, formatAssetDisplay, formatPaymentAmount, formatTokenAssetId, getAgentColor, getBuiltInCommands, getClaimStatusColors, getEdgeColor, getEdgeTypeLabel, getNodeColors, getNodeTypeLabel, getVocabTypeColors, getVocabTypeLabel, greenAction, handleSSEStream, handleStreamingResponse, hostApp, initials, isFixedKgId, isNaturalLanguage, layoutGraph, mergeTheme, openPipelineEventStream, orangeRebuttal, parseTerminalCommand, pipelineBg, processStreamLines, purple, reduceProgress, renderMarkdownBlock, resolvePaymentAssetDisplay, snapshotToSubgraph, terminalClassNames, terminalColors, useScopedProgressEvent, useSlashMentionPicker, useTheme, warmBg };
14619
+ export { ADVANCE_PHASE_SIGNAL, AGENT_PALETTE, AgentAvatar, AgentPresenceBar, AgentStepTrace, AnnotationThread, CLAIM_STATUS_COLORS, ChatTerminal, CheckpointCard, ClaimNode, ConstructionProgress, CoreTerminal, DEFAULT_AGENT_LABEL, DOCUMENT_PIPELINE_STEPS, DocumentProcessingProgress, EDGE_TYPE_COLORS, EdgeDetailDrawer, EdgeMarkerDefs, CoreTerminal as EmbeddedTerminal, ExpandableTerminal, GraphChatPanel, GraphEdge, GraphNode, InlineTerminal, KnowledgeGraphView, LIVE_KG_ID, LiveActivityTicker, MarkdownContent, MarkdownEditor, NODE_TYPE_COLORS, NODE_TYPE_LABELS, NodeDetailDrawer, PROGRESS_EVENT_NAME, PipelineProgressBar, ReasoningHistoryCard, ReasoningOverlay, ReasoningView, SSE_KEEPALIVE_MS, SSE_STALL_MS, SYNTHESIS_DONE_SIGNAL, ScopedReasoningProvider, SettlementBar, SlashMentionPicker, StageCanvas, StandardTerminal, TerminalInputBar, TerminalThemeProvider, agentSeed, agentStepTraceExtra, avatarColor, blueScope, buildClaimsGraph, buildTerminalCommand, buttonShadow, captureReasoningSnapshot, defaultTheme, dispatchProgressEvent, documentEventToActivity, emeraldCollab, emeraldRevised, eventToActivity, extractKGSources, extractKgId, filterCommands, formatAssetDisplay, formatPaymentAmount, formatTokenAssetId, getAgentColor, getBuiltInCommands, getClaimStatusColors, getEdgeColor, getEdgeTypeLabel, getNodeColors, getNodeTypeLabel, getVocabTypeColors, getVocabTypeLabel, greenAction, handleSSEStream, handleStreamingResponse, hostApp, initials, isFixedKgId, isNaturalLanguage, layoutGraph, mergeTheme, openPipelineEventStream, orangeRebuttal, parseTerminalCommand, pipelineBg, processStreamLines, purple, reduceProgress, renderMarkdownBlock, resolvePaymentAssetDisplay, snapshotToSubgraph, terminalClassNames, terminalColors, useScopedProgressEvent, useSlashMentionPicker, useTheme, warmBg, withStallTimeout };