@hachej/boring-agent 0.1.17 → 0.1.18

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.
Files changed (39) hide show
  1. package/dist/{sandbox-handle-store-hK76cTjn.d.ts → agentPluginEvents-zyIvVjsA.d.ts} +28 -32
  2. package/dist/{chunk-F3CE5CNW.js → chunk-B5JECXMG.js} +5 -7
  3. package/dist/front/index.d.ts +23 -7
  4. package/dist/front/index.js +764 -421
  5. package/dist/front/styles.css +61 -0
  6. package/dist/{tool-ui-DSmWuqGe.d.ts → harness-DRrTn_5T.d.ts} +43 -24
  7. package/dist/server/index.d.ts +79 -10
  8. package/dist/server/index.js +243 -54
  9. package/dist/shared/index.d.ts +5 -3
  10. package/dist/shared/index.js +3 -1
  11. package/dist/tool-ui-DIFNGwYd.d.ts +20 -0
  12. package/docs/ACCESSIBILITY.md +55 -0
  13. package/docs/API.md +64 -0
  14. package/docs/CSP.md +40 -0
  15. package/docs/ERROR_CODES.md +54 -0
  16. package/docs/KNOWN_LIMITATIONS.md +100 -0
  17. package/docs/MIGRATION.md +50 -0
  18. package/docs/PERFORMANCE.md +68 -0
  19. package/docs/PLUGINS.md +108 -0
  20. package/docs/README.md +17 -0
  21. package/docs/RISKS-MULTI-TAB.md +46 -0
  22. package/docs/STYLING.md +71 -0
  23. package/docs/UI-SHADCN.md +56 -0
  24. package/docs/VERCEL_COSTS.md +103 -0
  25. package/docs/plans/AGENT_EVAL_FRAMEWORK.md +466 -0
  26. package/docs/plans/agent-package-spec.md +1777 -0
  27. package/docs/plans/harness-followup-capabilities.md +440 -0
  28. package/docs/plans/harness-tool-ui-capabilities.md +144 -0
  29. package/docs/plans/pi-followup-history-projection.md +229 -0
  30. package/docs/plans/pi-tools-migration.md +1061 -0
  31. package/docs/plans/reviews/pi-followup-history-codex-review.md +11 -0
  32. package/docs/plans/reviews/pi-followup-history-gpt-review.md +64 -0
  33. package/docs/plans/reviews/pi-followup-history-opus-review.md +43 -0
  34. package/docs/plans/reviews/pi-followup-history-xai-review.md +43 -0
  35. package/docs/plans/vercel-base-snapshot-template-plan.md +527 -0
  36. package/docs/plans/vercel-persistent-sandbox-adapter.md +553 -0
  37. package/docs/runtime.md +56 -0
  38. package/docs/tools.md +75 -0
  39. package/package.json +4 -3
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  PI_AGENT_RUNTIME_CAPABILITIES,
3
+ WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
3
4
  extractToolUiMetadata
4
- } from "../chunk-F3CE5CNW.js";
5
+ } from "../chunk-B5JECXMG.js";
5
6
  import {
6
7
  DebugDrawer,
7
8
  cn
@@ -46,7 +47,7 @@ async function uploadFile(file, opts = {}) {
46
47
  // src/front/ChatPanel.tsx
47
48
  import { isToolUIPart as isToolUIPart2 } from "ai";
48
49
  import { motion as motion2 } from "motion/react";
49
- import { lazy, Suspense, useCallback as useCallback16, useEffect as useEffect17, useMemo as useMemo12, useRef as useRef13, useState as useState20 } from "react";
50
+ import { lazy, Suspense, useCallback as useCallback16, useEffect as useEffect18, useMemo as useMemo12, useRef as useRef13, useState as useState20 } from "react";
50
51
 
51
52
  // src/front/primitives/mention-picker.tsx
52
53
  import { useEffect as useEffect2, useRef as useRef2, useState, useCallback } from "react";
@@ -1019,6 +1020,23 @@ var builtinCommands = [
1019
1020
  ctx.resetSession();
1020
1021
  return "Session reset.";
1021
1022
  }
1023
+ },
1024
+ {
1025
+ name: "reload",
1026
+ description: "Reload agent plugins",
1027
+ handler(_, ctx) {
1028
+ if (ctx.pluginUpdate) return ctx.pluginUpdate.run();
1029
+ return ctx.reloadAgentPlugins();
1030
+ }
1031
+ },
1032
+ {
1033
+ name: "help",
1034
+ description: "Show available commands",
1035
+ handler(_, ctx) {
1036
+ const cmds = ctx.listCommands();
1037
+ if (cmds.length === 0) return "No commands available.";
1038
+ return cmds.map((c) => `/${c.name} \u2014 ${c.description}`).join("\n");
1039
+ }
1022
1040
  }
1023
1041
  ];
1024
1042
 
@@ -1048,6 +1066,192 @@ function createCommandRegistry(initial) {
1048
1066
  };
1049
1067
  }
1050
1068
 
1069
+ // src/front/composer/PluginUpdateStatus.tsx
1070
+ import { useEffect as useEffect7 } from "react";
1071
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1072
+ function PluginUpdateStatus({
1073
+ state,
1074
+ onDismiss,
1075
+ onRetry,
1076
+ successAutoDismissMs = 4e3
1077
+ }) {
1078
+ useEffect7(() => {
1079
+ if (!state || state.kind !== "success" || successAutoDismissMs <= 0) return;
1080
+ const hasDetails = (state.restartWarnings?.length ?? 0) > 0 || (state.diagnostics?.length ?? 0) > 0 || (state.frontEvents?.length ?? 0) > 0;
1081
+ if (hasDetails) return;
1082
+ const timeout = window.setTimeout(onDismiss, successAutoDismissMs);
1083
+ return () => window.clearTimeout(timeout);
1084
+ }, [state, onDismiss, successAutoDismissMs]);
1085
+ if (!state) return null;
1086
+ if (state.kind === "running") {
1087
+ return /* @__PURE__ */ jsxs3(
1088
+ "div",
1089
+ {
1090
+ "data-boring-plugin-update": "running",
1091
+ role: "status",
1092
+ "aria-live": "polite",
1093
+ className: cn(
1094
+ "mx-auto mb-2 w-full max-w-3xl rounded-[var(--radius-md)] border border-accent/30 bg-[color:var(--accent-soft)]",
1095
+ "px-3 py-2 text-xs text-foreground flex items-center gap-2"
1096
+ ),
1097
+ children: [
1098
+ /* @__PURE__ */ jsx3("span", { className: "inline-block h-2 w-2 animate-pulse rounded-full bg-accent", "aria-hidden": "true" }),
1099
+ /* @__PURE__ */ jsx3("span", { children: "Updating plugins\u2026" })
1100
+ ]
1101
+ }
1102
+ );
1103
+ }
1104
+ if (state.kind === "success") {
1105
+ const warnings = state.restartWarnings ?? [];
1106
+ const diagnostics = state.diagnostics ?? [];
1107
+ const frontEvents = state.frontEvents ?? [];
1108
+ return /* @__PURE__ */ jsxs3(
1109
+ "div",
1110
+ {
1111
+ "data-boring-plugin-update": "success",
1112
+ role: "status",
1113
+ "aria-live": "polite",
1114
+ className: cn(
1115
+ "mx-auto mb-2 w-full max-w-3xl rounded-[var(--radius-md)] border border-[oklch(0.78_0.13_148)]/40 bg-[oklch(0.95_0.05_148/0.3)]",
1116
+ "px-3 py-2 text-xs text-foreground"
1117
+ ),
1118
+ children: [
1119
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
1120
+ /* @__PURE__ */ jsx3("span", { className: "text-[oklch(0.45_0.13_148)]", "aria-hidden": "true", children: "\u2713" }),
1121
+ /* @__PURE__ */ jsx3("span", { className: "flex-1", children: state.reloaded ? warnings.length > 0 || diagnostics.length > 0 ? "Plugins updated with warnings." : frontEvents.length > 0 ? "Plugins updated. Browser modules reloaded." : "Plugins updated." : "Plugins will reload on the next message." }),
1122
+ /* @__PURE__ */ jsx3(
1123
+ "button",
1124
+ {
1125
+ type: "button",
1126
+ onClick: onDismiss,
1127
+ className: "rounded border border-transparent px-2 py-0.5 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground",
1128
+ "aria-label": "Dismiss plugin update status",
1129
+ children: "Dismiss"
1130
+ }
1131
+ )
1132
+ ] }),
1133
+ diagnostics.length > 0 ? /* @__PURE__ */ jsxs3(
1134
+ "div",
1135
+ {
1136
+ "data-boring-plugin-update-diagnostics": "",
1137
+ className: cn(
1138
+ "mt-2 rounded border border-[oklch(0.78_0.15_85)]/40 bg-[oklch(0.95_0.06_85/0.4)]",
1139
+ "px-2 py-1.5 text-[11px] text-foreground"
1140
+ ),
1141
+ children: [
1142
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 font-medium text-[oklch(0.48_0.15_60)]", children: [
1143
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u26A0" }),
1144
+ /* @__PURE__ */ jsxs3("span", { children: [
1145
+ "Reload diagnostics for ",
1146
+ diagnostics.length,
1147
+ " plugin",
1148
+ diagnostics.length === 1 ? "" : "s"
1149
+ ] })
1150
+ ] }),
1151
+ /* @__PURE__ */ jsx3("ul", { className: "mt-1 ml-4 list-disc text-foreground/85", children: diagnostics.map((diagnostic, index) => /* @__PURE__ */ jsxs3("li", { children: [
1152
+ /* @__PURE__ */ jsx3("code", { className: "font-mono text-[10.5px]", children: diagnostic.pluginId ?? diagnostic.source ?? "plugin" }),
1153
+ " \u2014 ",
1154
+ diagnostic.message ?? "reload diagnostic"
1155
+ ] }, `${diagnostic.pluginId ?? diagnostic.source ?? "plugin"}-${index}`)) })
1156
+ ]
1157
+ }
1158
+ ) : null,
1159
+ frontEvents.length > 0 ? /* @__PURE__ */ jsxs3(
1160
+ "div",
1161
+ {
1162
+ "data-boring-plugin-update-front-events": "",
1163
+ className: cn(
1164
+ "mt-2 rounded border border-[oklch(0.78_0.13_148)]/35 bg-[oklch(0.95_0.05_148/0.25)]",
1165
+ "px-2 py-1.5 text-[11px] text-foreground"
1166
+ ),
1167
+ children: [
1168
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 font-medium text-[oklch(0.45_0.13_148)]", children: [
1169
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2713" }),
1170
+ /* @__PURE__ */ jsxs3("span", { children: [
1171
+ "Browser plugin modules updated (",
1172
+ frontEvents.length,
1173
+ ")"
1174
+ ] })
1175
+ ] }),
1176
+ /* @__PURE__ */ jsx3("ul", { className: "mt-1 ml-4 list-disc text-foreground/85", children: frontEvents.map((event, index) => /* @__PURE__ */ jsxs3("li", { children: [
1177
+ /* @__PURE__ */ jsx3("code", { className: "font-mono text-[10.5px]", children: event.pluginId ?? event.source ?? "plugin" }),
1178
+ " \u2014 ",
1179
+ event.message ?? "front module updated"
1180
+ ] }, `${event.pluginId ?? event.source ?? "plugin"}-${index}`)) })
1181
+ ]
1182
+ }
1183
+ ) : null,
1184
+ warnings.length > 0 ? /* @__PURE__ */ jsxs3(
1185
+ "div",
1186
+ {
1187
+ "data-boring-plugin-update-restart-warning": "",
1188
+ className: cn(
1189
+ "mt-2 rounded border border-[oklch(0.78_0.15_85)]/40 bg-[oklch(0.95_0.06_85/0.4)]",
1190
+ "px-2 py-1.5 text-[11px] text-foreground"
1191
+ ),
1192
+ children: [
1193
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 font-medium text-[oklch(0.48_0.15_60)]", children: [
1194
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u26A0" }),
1195
+ /* @__PURE__ */ jsxs3("span", { children: [
1196
+ "Restart needed for ",
1197
+ warnings.length,
1198
+ " plugin",
1199
+ warnings.length === 1 ? "" : "s"
1200
+ ] })
1201
+ ] }),
1202
+ /* @__PURE__ */ jsx3("ul", { className: "mt-1 ml-4 list-disc text-foreground/85", children: warnings.map((w) => /* @__PURE__ */ jsxs3("li", { children: [
1203
+ /* @__PURE__ */ jsx3("code", { className: "font-mono text-[10.5px]", children: w.id }),
1204
+ " \u2014 ",
1205
+ w.surfaces.join(" + ")
1206
+ ] }, w.id)) }),
1207
+ /* @__PURE__ */ jsx3("p", { className: "mt-1 text-foreground/70", children: "The front bundle reloaded successfully, but routes and agent tools were wired at boot. Stop and restart the workspace process (Ctrl-C, then re-run your dev command) to pick up the new code." })
1208
+ ]
1209
+ }
1210
+ ) : null
1211
+ ]
1212
+ }
1213
+ );
1214
+ }
1215
+ return /* @__PURE__ */ jsxs3(
1216
+ "div",
1217
+ {
1218
+ "data-boring-plugin-update": "error",
1219
+ role: "status",
1220
+ "aria-live": "polite",
1221
+ className: cn(
1222
+ "mx-auto mb-2 w-full max-w-3xl rounded-[var(--radius-md)] border border-destructive/40 bg-destructive/10",
1223
+ "px-3 py-2 text-xs text-foreground"
1224
+ ),
1225
+ children: [
1226
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
1227
+ /* @__PURE__ */ jsx3("span", { className: "text-destructive", "aria-hidden": "true", children: "\u26A0" }),
1228
+ /* @__PURE__ */ jsx3("span", { className: "flex-1 font-medium", children: "Plugin update failed." }),
1229
+ /* @__PURE__ */ jsx3(
1230
+ "button",
1231
+ {
1232
+ type: "button",
1233
+ onClick: onRetry,
1234
+ className: "rounded border border-destructive/40 px-2 py-0.5 text-[11px] font-medium hover:bg-destructive/10",
1235
+ children: "Try again"
1236
+ }
1237
+ ),
1238
+ /* @__PURE__ */ jsx3(
1239
+ "button",
1240
+ {
1241
+ type: "button",
1242
+ onClick: onDismiss,
1243
+ className: "rounded border border-transparent px-2 py-0.5 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground",
1244
+ "aria-label": "Dismiss plugin update status",
1245
+ children: "Dismiss"
1246
+ }
1247
+ )
1248
+ ] }),
1249
+ /* @__PURE__ */ jsx3("pre", { className: "mt-2 whitespace-pre-wrap break-words text-[11px] text-destructive/90", children: state.message })
1250
+ ]
1251
+ }
1252
+ );
1253
+ }
1254
+
1051
1255
  // src/front/primitives/tool-call-group.tsx
1052
1256
  import { getToolName, isToolUIPart } from "ai";
1053
1257
  import { ChevronDownIcon } from "lucide-react";
@@ -1058,7 +1262,7 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@hachej/bor
1058
1262
  import { useState as useState6 } from "react";
1059
1263
  import { createPatch } from "diff";
1060
1264
  import { Button } from "@hachej/boring-ui-kit";
1061
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1265
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1062
1266
  var COLLAPSE_THRESHOLD = 30;
1063
1267
  function parsePatch(patch) {
1064
1268
  const lines = patch.split("\n");
@@ -1083,22 +1287,22 @@ var prefixMap = { "+": "+", "-": "-", " ": " " };
1083
1287
  function DiffView({ oldString, newString, path, replaceAll }) {
1084
1288
  const [expanded, setExpanded] = useState6(false);
1085
1289
  if (oldString === newString) {
1086
- return /* @__PURE__ */ jsx3("div", { "data-testid": "diff-no-change", className: "py-2 italic opacity-60", children: "No changes" });
1290
+ return /* @__PURE__ */ jsx4("div", { "data-testid": "diff-no-change", className: "py-2 italic opacity-60", children: "No changes" });
1087
1291
  }
1088
1292
  const patch = createPatch(path, oldString, newString, "", "", { context: 3 });
1089
1293
  const lines = parsePatch(patch);
1090
1294
  const collapsed = !expanded && lines.length > COLLAPSE_THRESHOLD;
1091
1295
  const visible = collapsed ? lines.slice(0, COLLAPSE_THRESHOLD) : lines;
1092
- return /* @__PURE__ */ jsxs3("div", { "data-testid": "diff-view", children: [
1093
- /* @__PURE__ */ jsxs3("div", { className: "px-3 py-1.5 font-[family-name:var(--boring-agent-font-mono,monospace)] text-xs opacity-70", children: [
1296
+ return /* @__PURE__ */ jsxs4("div", { "data-testid": "diff-view", children: [
1297
+ /* @__PURE__ */ jsxs4("div", { className: "px-3 py-1.5 font-[family-name:var(--boring-agent-font-mono,monospace)] text-xs opacity-70", children: [
1094
1298
  path,
1095
1299
  replaceAll ? " (replace all)" : ""
1096
1300
  ] }),
1097
- /* @__PURE__ */ jsx3("pre", { className: "m-0 overflow-auto py-2 font-[family-name:var(--boring-agent-font-mono,monospace)] text-[0.8125rem] leading-relaxed", children: visible.map((line, i) => /* @__PURE__ */ jsxs3("div", { className: cn("px-3", lineClass[line.type]), children: [
1098
- /* @__PURE__ */ jsx3("span", { className: "inline-block w-[1.5ch] select-none opacity-50", children: prefixMap[line.type] }),
1301
+ /* @__PURE__ */ jsx4("pre", { className: "m-0 overflow-auto py-2 font-[family-name:var(--boring-agent-font-mono,monospace)] text-[0.8125rem] leading-relaxed", children: visible.map((line, i) => /* @__PURE__ */ jsxs4("div", { className: cn("px-3", lineClass[line.type]), children: [
1302
+ /* @__PURE__ */ jsx4("span", { className: "inline-block w-[1.5ch] select-none opacity-50", children: prefixMap[line.type] }),
1099
1303
  line.text
1100
1304
  ] }, i)) }),
1101
- collapsed && /* @__PURE__ */ jsxs3(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setExpanded(true), className: "w-full rounded-none text-xs opacity-60", children: [
1305
+ collapsed && /* @__PURE__ */ jsxs4(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setExpanded(true), className: "w-full rounded-none text-xs opacity-60", children: [
1102
1306
  "Show ",
1103
1307
  lines.length - COLLAPSE_THRESHOLD,
1104
1308
  " more lines"
@@ -1107,9 +1311,9 @@ function DiffView({ oldString, newString, path, replaceAll }) {
1107
1311
  }
1108
1312
 
1109
1313
  // src/front/barePrimitives/Tool.tsx
1110
- import { useEffect as useEffect7, useRef as useRef7, useState as useState7 } from "react";
1314
+ import { useEffect as useEffect8, useRef as useRef7, useState as useState7 } from "react";
1111
1315
  import { Button as Button2 } from "@hachej/boring-ui-kit";
1112
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1316
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1113
1317
  function stateLabel(state) {
1114
1318
  switch (state) {
1115
1319
  case "input-streaming":
@@ -1128,7 +1332,7 @@ function stateLabel(state) {
1128
1332
  }
1129
1333
  }
1130
1334
  function ToolValue({ value }) {
1131
- return /* @__PURE__ */ jsx4("pre", { className: "m-0 whitespace-pre-wrap text-[0.8125rem]", children: typeof value === "string" ? value : JSON.stringify(value, null, 2) });
1335
+ return /* @__PURE__ */ jsx5("pre", { className: "m-0 whitespace-pre-wrap text-[0.8125rem]", children: typeof value === "string" ? value : JSON.stringify(value, null, 2) });
1132
1336
  }
1133
1337
  function Tool({
1134
1338
  toolName,
@@ -1147,7 +1351,7 @@ function Tool({
1147
1351
  const isComplete = state === "output-available" || state === "output-error" || state === "output-denied";
1148
1352
  const [elapsedSec, setElapsedSec] = useState7(0);
1149
1353
  const startRef = useRef7(0);
1150
- useEffect7(() => {
1354
+ useEffect8(() => {
1151
1355
  if (!isRunning) {
1152
1356
  setElapsedSec(0);
1153
1357
  return;
@@ -1158,7 +1362,7 @@ function Tool({
1158
1362
  }, 1e3);
1159
1363
  return () => clearInterval(timer);
1160
1364
  }, [isRunning]);
1161
- return /* @__PURE__ */ jsxs4(
1365
+ return /* @__PURE__ */ jsxs5(
1162
1366
  "div",
1163
1367
  {
1164
1368
  className: cn(
@@ -1167,7 +1371,7 @@ function Tool({
1167
1371
  ),
1168
1372
  "data-tool-state": state,
1169
1373
  children: [
1170
- /* @__PURE__ */ jsxs4(
1374
+ /* @__PURE__ */ jsxs5(
1171
1375
  Button2,
1172
1376
  {
1173
1377
  type: "button",
@@ -1176,17 +1380,17 @@ function Tool({
1176
1380
  className: "h-auto w-full justify-start gap-2 rounded-none bg-[var(--boring-agent-tool-header-bg,#f9fafb)] px-3 py-2 text-left font-[family-name:var(--boring-agent-font-mono,monospace)] text-[0.8125rem]",
1177
1381
  "aria-expanded": expanded,
1178
1382
  children: [
1179
- /* @__PURE__ */ jsx4("span", { className: cn("transition-transform duration-150", expanded && "rotate-90"), children: "\u25B6" }),
1180
- /* @__PURE__ */ jsx4("span", { className: "font-medium", children: toolName }),
1181
- /* @__PURE__ */ jsx4("span", { className: "ml-auto text-xs opacity-60", children: isRunning && elapsedSec >= 1 ? `Running\u2026 (${elapsedSec}s)` : stateLabel(state) }),
1182
- !isComplete && /* @__PURE__ */ jsx4("span", { className: "size-2 rounded-full bg-[var(--boring-agent-tool-running,#3b82f6)]", "aria-label": "running" })
1383
+ /* @__PURE__ */ jsx5("span", { className: cn("transition-transform duration-150", expanded && "rotate-90"), children: "\u25B6" }),
1384
+ /* @__PURE__ */ jsx5("span", { className: "font-medium", children: toolName }),
1385
+ /* @__PURE__ */ jsx5("span", { className: "ml-auto text-xs opacity-60", children: isRunning && elapsedSec >= 1 ? `Running\u2026 (${elapsedSec}s)` : stateLabel(state) }),
1386
+ !isComplete && /* @__PURE__ */ jsx5("span", { className: "size-2 rounded-full bg-[var(--boring-agent-tool-running,#3b82f6)]", "aria-label": "running" })
1183
1387
  ]
1184
1388
  }
1185
1389
  ),
1186
- expanded && /* @__PURE__ */ jsx4("div", { className: "border-t border-[var(--boring-agent-tool-border,#e5e7eb)] px-3 py-2", children: children ?? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1187
- input !== void 0 && /* @__PURE__ */ jsx4("div", { "data-testid": "tool-input", children: renderInput ? renderInput(input) : /* @__PURE__ */ jsx4(ToolValue, { value: input }) }),
1188
- output !== void 0 && /* @__PURE__ */ jsx4("div", { "data-testid": "tool-output", className: "mt-2", children: renderOutput ? renderOutput(output) : /* @__PURE__ */ jsx4(ToolValue, { value: output }) }),
1189
- errorText && /* @__PURE__ */ jsx4("div", { "data-testid": "tool-error", className: "mt-2 text-[var(--boring-agent-tool-error,#ef4444)]", children: errorText })
1390
+ expanded && /* @__PURE__ */ jsx5("div", { className: "border-t border-[var(--boring-agent-tool-border,#e5e7eb)] px-3 py-2", children: children ?? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1391
+ input !== void 0 && /* @__PURE__ */ jsx5("div", { "data-testid": "tool-input", children: renderInput ? renderInput(input) : /* @__PURE__ */ jsx5(ToolValue, { value: input }) }),
1392
+ output !== void 0 && /* @__PURE__ */ jsx5("div", { "data-testid": "tool-output", className: "mt-2", children: renderOutput ? renderOutput(output) : /* @__PURE__ */ jsx5(ToolValue, { value: output }) }),
1393
+ errorText && /* @__PURE__ */ jsx5("div", { "data-testid": "tool-error", className: "mt-2 text-[var(--boring-agent-tool-error,#ef4444)]", children: errorText })
1190
1394
  ] }) })
1191
1395
  ]
1192
1396
  }
@@ -1194,7 +1398,7 @@ function Tool({
1194
1398
  }
1195
1399
 
1196
1400
  // src/front/barePrimitives/Terminal.tsx
1197
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1401
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1198
1402
  function Terminal({
1199
1403
  children,
1200
1404
  stdout,
@@ -1203,7 +1407,7 @@ function Terminal({
1203
1407
  className,
1204
1408
  title
1205
1409
  }) {
1206
- return /* @__PURE__ */ jsxs5(
1410
+ return /* @__PURE__ */ jsxs6(
1207
1411
  "div",
1208
1412
  {
1209
1413
  className: cn(
@@ -1211,10 +1415,10 @@ function Terminal({
1211
1415
  className
1212
1416
  ),
1213
1417
  children: [
1214
- title && /* @__PURE__ */ jsx5("div", { className: "border-b border-[var(--boring-agent-terminal-border,#404040)] bg-[var(--boring-agent-terminal-header-bg,#2d2d2d)] px-3 py-1.5 text-xs opacity-80", children: title }),
1215
- /* @__PURE__ */ jsx5("div", { className: "p-3", children: children ?? /* @__PURE__ */ jsxs5(Fragment3, { children: [
1216
- stdout && /* @__PURE__ */ jsx5("pre", { "data-stream": "stdout", className: "m-0 whitespace-pre-wrap", children: stdout }),
1217
- stderr && /* @__PURE__ */ jsx5(
1418
+ title && /* @__PURE__ */ jsx6("div", { className: "border-b border-[var(--boring-agent-terminal-border,#404040)] bg-[var(--boring-agent-terminal-header-bg,#2d2d2d)] px-3 py-1.5 text-xs opacity-80", children: title }),
1419
+ /* @__PURE__ */ jsx6("div", { className: "p-3", children: children ?? /* @__PURE__ */ jsxs6(Fragment3, { children: [
1420
+ stdout && /* @__PURE__ */ jsx6("pre", { "data-stream": "stdout", className: "m-0 whitespace-pre-wrap", children: stdout }),
1421
+ stderr && /* @__PURE__ */ jsx6(
1218
1422
  "pre",
1219
1423
  {
1220
1424
  "data-stream": "stderr",
@@ -1226,7 +1430,7 @@ function Terminal({
1226
1430
  }
1227
1431
  )
1228
1432
  ] }) }),
1229
- exitCode != null && /* @__PURE__ */ jsxs5(
1433
+ exitCode != null && /* @__PURE__ */ jsxs6(
1230
1434
  "div",
1231
1435
  {
1232
1436
  "data-testid": "exit-code",
@@ -1248,7 +1452,7 @@ function Terminal({
1248
1452
  // src/front/barePrimitives/CodeBlock.tsx
1249
1453
  import { useCallback as useCallback5, useState as useState8 } from "react";
1250
1454
  import { Button as Button3 } from "@hachej/boring-ui-kit";
1251
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1455
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1252
1456
  function CodeBlock({
1253
1457
  code: code3,
1254
1458
  language,
@@ -1266,7 +1470,7 @@ function CodeBlock({
1266
1470
  }, [code3]);
1267
1471
  const lines = code3.split("\n");
1268
1472
  const lineNumberWidth = `${String(lines.length).length + 1}ch`;
1269
- return /* @__PURE__ */ jsxs6(
1473
+ return /* @__PURE__ */ jsxs7(
1270
1474
  "div",
1271
1475
  {
1272
1476
  className: cn(
@@ -1274,15 +1478,15 @@ function CodeBlock({
1274
1478
  className
1275
1479
  ),
1276
1480
  children: [
1277
- (filename || language) && /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-[var(--boring-agent-code-border,#404040)] bg-[var(--boring-agent-code-header-bg,#2d2d2d)] px-3 py-1.5 text-xs", children: [
1278
- /* @__PURE__ */ jsx6("span", { className: "opacity-70", children: filename ?? language }),
1279
- copyable && /* @__PURE__ */ jsx6(Button3, { type: "button", variant: "ghost", size: "xs", onClick: handleCopy, "aria-label": "Copy code", className: "h-6 px-1.5 text-xs text-inherit opacity-60", children: copied ? "Copied" : "Copy" })
1481
+ (filename || language) && /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between border-b border-[var(--boring-agent-code-border,#404040)] bg-[var(--boring-agent-code-header-bg,#2d2d2d)] px-3 py-1.5 text-xs", children: [
1482
+ /* @__PURE__ */ jsx7("span", { className: "opacity-70", children: filename ?? language }),
1483
+ copyable && /* @__PURE__ */ jsx7(Button3, { type: "button", variant: "ghost", size: "xs", onClick: handleCopy, "aria-label": "Copy code", className: "h-6 px-1.5 text-xs text-inherit opacity-60", children: copied ? "Copied" : "Copy" })
1280
1484
  ] }),
1281
- /* @__PURE__ */ jsx6("pre", { className: "m-0 overflow-auto p-3", children: /* @__PURE__ */ jsx6("code", { "data-language": language, children: showLineNumbers ? lines.map((line, i) => /* @__PURE__ */ jsxs6("span", { className: "block", children: [
1282
- /* @__PURE__ */ jsx6("span", { className: "mr-4 inline-block select-none text-right opacity-40", style: { width: lineNumberWidth }, children: i + 1 }),
1485
+ /* @__PURE__ */ jsx7("pre", { className: "m-0 overflow-auto p-3", children: /* @__PURE__ */ jsx7("code", { "data-language": language, children: showLineNumbers ? lines.map((line, i) => /* @__PURE__ */ jsxs7("span", { className: "block", children: [
1486
+ /* @__PURE__ */ jsx7("span", { className: "mr-4 inline-block select-none text-right opacity-40", style: { width: lineNumberWidth }, children: i + 1 }),
1283
1487
  line
1284
1488
  ] }, i)) : code3 }) }),
1285
- copyable && !filename && !language && /* @__PURE__ */ jsx6(
1489
+ copyable && !filename && !language && /* @__PURE__ */ jsx7(
1286
1490
  Button3,
1287
1491
  {
1288
1492
  type: "button",
@@ -1300,7 +1504,7 @@ function CodeBlock({
1300
1504
  }
1301
1505
 
1302
1506
  // src/front/bareToolRenderers/renderers.tsx
1303
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1507
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1304
1508
  var FALLBACK_RENDERER_KEY = "__fallback";
1305
1509
  function asRecord(v) {
1306
1510
  return typeof v === "object" && v !== null ? v : {};
@@ -1352,14 +1556,14 @@ function renderBash(part) {
1352
1556
  const stdout = typeof output.stdout === "string" ? output.stdout : output.content ? JSON.stringify(output.content) : void 0;
1353
1557
  const stderr = typeof output.stderr === "string" ? output.stderr : void 0;
1354
1558
  const exitCode = typeof output.exitCode === "number" ? output.exitCode : void 0;
1355
- return /* @__PURE__ */ jsx7(Tool, { toolName: "bash", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsx7(Terminal, { title: `$ ${command}`, stdout, stderr, exitCode: exitCode ?? null }) });
1559
+ return /* @__PURE__ */ jsx8(Tool, { toolName: "bash", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsx8(Terminal, { title: `$ ${command}`, stdout, stderr, exitCode: exitCode ?? null }) });
1356
1560
  }
1357
1561
  function renderRead(part) {
1358
1562
  const input = asRecord(part.input);
1359
1563
  const output = asRecord(part.output);
1360
1564
  const path = String(input.path ?? "");
1361
1565
  const content = typeof output.text === "string" ? output.text : Array.isArray(output.content) ? output.content.map((c) => c.text ?? "").join("") : typeof output.content === "string" ? output.content : void 0;
1362
- return /* @__PURE__ */ jsx7(Tool, { toolName: "read", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, children: content != null ? /* @__PURE__ */ jsx7(CodeBlock, { code: content, language: langFromPath(path), filename: path }) : /* @__PURE__ */ jsxs7("span", { style: { opacity: 0.6 }, children: [
1566
+ return /* @__PURE__ */ jsx8(Tool, { toolName: "read", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, children: content != null ? /* @__PURE__ */ jsx8(CodeBlock, { code: content, language: langFromPath(path), filename: path }) : /* @__PURE__ */ jsxs8("span", { style: { opacity: 0.6 }, children: [
1363
1567
  "Reading ",
1364
1568
  path,
1365
1569
  "\u2026"
@@ -1369,11 +1573,11 @@ function renderWrite(part) {
1369
1573
  const input = asRecord(part.input);
1370
1574
  const path = String(input.path ?? "");
1371
1575
  const content = typeof input.content === "string" ? input.content : "";
1372
- return /* @__PURE__ */ jsx7(Tool, { toolName: "write", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsxs7("span", { style: { fontFamily: "var(--boring-agent-font-mono, monospace)", fontSize: "0.8125rem" }, children: [
1576
+ return /* @__PURE__ */ jsx8(Tool, { toolName: "write", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsxs8("span", { style: { fontFamily: "var(--boring-agent-font-mono, monospace)", fontSize: "0.8125rem" }, children: [
1373
1577
  "Wrote ",
1374
1578
  content.length,
1375
1579
  " bytes to ",
1376
- /* @__PURE__ */ jsx7("strong", { children: path })
1580
+ /* @__PURE__ */ jsx8("strong", { children: path })
1377
1581
  ] }) });
1378
1582
  }
1379
1583
  function renderEdit(part) {
@@ -1382,7 +1586,7 @@ function renderEdit(part) {
1382
1586
  const oldString = typeof input.oldString === "string" ? input.oldString : "";
1383
1587
  const newString = typeof input.newString === "string" ? input.newString : "";
1384
1588
  const replaceAll = Boolean(input.replaceAll);
1385
- return /* @__PURE__ */ jsx7(Tool, { toolName: "edit", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsx7(DiffView, { oldString, newString, path, replaceAll }) });
1589
+ return /* @__PURE__ */ jsx8(Tool, { toolName: "edit", toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, defaultExpanded: true, children: /* @__PURE__ */ jsx8(DiffView, { oldString, newString, path, replaceAll }) });
1386
1590
  }
1387
1591
  function renderSearchLike(toolName, part) {
1388
1592
  const input = asRecord(part.input);
@@ -1391,17 +1595,17 @@ function renderSearchLike(toolName, part) {
1391
1595
  const path = typeof input.path === "string" ? input.path : "";
1392
1596
  const pattern = typeof input.pattern === "string" ? input.pattern : "";
1393
1597
  const title = [toolName, pattern || path].filter(Boolean).join(" ");
1394
- return /* @__PURE__ */ jsx7(Tool, { toolName, toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, children: content ? /* @__PURE__ */ jsx7(CodeBlock, { code: content, language: "text", filename: title }) : /* @__PURE__ */ jsx7("span", { style: { opacity: 0.6 }, children: toolName === "ls" ? `Listing ${path || "."}...` : `Searching ${pattern || path || "."}...` }) });
1598
+ return /* @__PURE__ */ jsx8(Tool, { toolName, toolCallId: part.toolCallId, state: part.state, errorText: part.errorText, children: content ? /* @__PURE__ */ jsx8(CodeBlock, { code: content, language: "text", filename: title }) : /* @__PURE__ */ jsx8("span", { style: { opacity: 0.6 }, children: toolName === "ls" ? `Listing ${path || "."}...` : `Searching ${pattern || path || "."}...` }) });
1395
1599
  }
1396
1600
  function renderGetUiState(part) {
1397
- return /* @__PURE__ */ jsx7(
1601
+ return /* @__PURE__ */ jsx8(
1398
1602
  Tool,
1399
1603
  {
1400
1604
  toolName: "get_ui_state",
1401
1605
  toolCallId: part.toolCallId,
1402
1606
  state: part.state,
1403
1607
  errorText: part.errorText,
1404
- renderOutput: (output) => /* @__PURE__ */ jsx7("pre", { style: { margin: 0, whiteSpace: "pre-wrap", fontSize: "0.8125rem", fontFamily: "var(--boring-agent-font-mono, monospace)" }, children: typeof output === "string" ? output : JSON.stringify(output, null, 2) }),
1608
+ renderOutput: (output) => /* @__PURE__ */ jsx8("pre", { style: { margin: 0, whiteSpace: "pre-wrap", fontSize: "0.8125rem", fontFamily: "var(--boring-agent-font-mono, monospace)" }, children: typeof output === "string" ? output : JSON.stringify(output, null, 2) }),
1405
1609
  input: part.input,
1406
1610
  output: part.output
1407
1611
  }
@@ -1413,7 +1617,7 @@ function renderExecUi(part) {
1413
1617
  const params = input.params;
1414
1618
  const paramsText = params !== void 0 && params !== null ? typeof params === "string" ? params : JSON.stringify(params) : "";
1415
1619
  const summary = kind ? `${kind}${paramsText ? `(${paramsText})` : ""}` : "(empty)";
1416
- return /* @__PURE__ */ jsx7(
1620
+ return /* @__PURE__ */ jsx8(
1417
1621
  Tool,
1418
1622
  {
1419
1623
  toolName: "exec_ui",
@@ -1421,8 +1625,8 @@ function renderExecUi(part) {
1421
1625
  state: part.state,
1422
1626
  errorText: part.errorText,
1423
1627
  defaultExpanded: true,
1424
- children: /* @__PURE__ */ jsxs7("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
1425
- /* @__PURE__ */ jsxs7(
1628
+ children: /* @__PURE__ */ jsxs8("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
1629
+ /* @__PURE__ */ jsxs8(
1426
1630
  "span",
1427
1631
  {
1428
1632
  style: {
@@ -1436,7 +1640,7 @@ function renderExecUi(part) {
1436
1640
  ]
1437
1641
  }
1438
1642
  ),
1439
- part.errorText && /* @__PURE__ */ jsx7(
1643
+ part.errorText && /* @__PURE__ */ jsx8(
1440
1644
  "span",
1441
1645
  {
1442
1646
  "data-testid": "tool-error",
@@ -1453,7 +1657,7 @@ function renderExecUi(part) {
1453
1657
  );
1454
1658
  }
1455
1659
  function renderFallback(part) {
1456
- const renderJson = (value) => /* @__PURE__ */ jsx7(
1660
+ const renderJson = (value) => /* @__PURE__ */ jsx8(
1457
1661
  "pre",
1458
1662
  {
1459
1663
  style: {
@@ -1465,7 +1669,7 @@ function renderFallback(part) {
1465
1669
  children: typeof value === "string" ? value : JSON.stringify(value, null, 2)
1466
1670
  }
1467
1671
  );
1468
- return /* @__PURE__ */ jsx7(
1672
+ return /* @__PURE__ */ jsx8(
1469
1673
  Tool,
1470
1674
  {
1471
1675
  toolName: part.toolName,
@@ -1507,7 +1711,7 @@ function resolveToolRenderer(toolName, overrides) {
1507
1711
  // src/front/primitives/shimmer.tsx
1508
1712
  import { motion } from "motion/react";
1509
1713
  import { memo, useMemo as useMemo4 } from "react";
1510
- import { jsx as jsx8 } from "react/jsx-runtime";
1714
+ import { jsx as jsx9 } from "react/jsx-runtime";
1511
1715
  var motionComponentCache = /* @__PURE__ */ new Map();
1512
1716
  var getMotionComponent = (element) => {
1513
1717
  let component = motionComponentCache.get(element);
@@ -1531,7 +1735,7 @@ var ShimmerComponent = ({
1531
1735
  () => (children?.length ?? 0) * spread,
1532
1736
  [children, spread]
1533
1737
  );
1534
- return /* @__PURE__ */ jsx8(
1738
+ return /* @__PURE__ */ jsx9(
1535
1739
  MotionComponent,
1536
1740
  {
1537
1741
  animate: { backgroundPosition: "0% center" },
@@ -1557,7 +1761,7 @@ var ShimmerComponent = ({
1557
1761
  var Shimmer = memo(ShimmerComponent);
1558
1762
 
1559
1763
  // src/front/primitives/tool-call-group.tsx
1560
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1764
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1561
1765
  function isSettledState(state) {
1562
1766
  return state === "output-available" || state === "output-error" || state === "output-denied" || state === "approval-responded";
1563
1767
  }
@@ -1598,8 +1802,8 @@ var ToolCallGroup = memo2(({ tools, mergedToolRenderers }) => {
1598
1802
  const [isOpen, setIsOpen] = useState9(false);
1599
1803
  const handleOpenChange = useCallback6((open) => setIsOpen(open), []);
1600
1804
  const title = useMemo5(() => buildTitle(tools, isSettled), [tools, isSettled]);
1601
- return /* @__PURE__ */ jsxs8(Collapsible, { open: isOpen, onOpenChange: handleOpenChange, className: "not-prose my-1.5", children: [
1602
- /* @__PURE__ */ jsxs8(
1805
+ return /* @__PURE__ */ jsxs9(Collapsible, { open: isOpen, onOpenChange: handleOpenChange, className: "not-prose my-1.5", children: [
1806
+ /* @__PURE__ */ jsxs9(
1603
1807
  CollapsibleTrigger,
1604
1808
  {
1605
1809
  className: cn(
@@ -1609,7 +1813,7 @@ var ToolCallGroup = memo2(({ tools, mergedToolRenderers }) => {
1609
1813
  hasError && "border-destructive/30 text-destructive/60 hover:text-destructive/80"
1610
1814
  ),
1611
1815
  children: [
1612
- /* @__PURE__ */ jsx9(
1816
+ /* @__PURE__ */ jsx10(
1613
1817
  "span",
1614
1818
  {
1615
1819
  className: cn(
@@ -1618,7 +1822,7 @@ var ToolCallGroup = memo2(({ tools, mergedToolRenderers }) => {
1618
1822
  )
1619
1823
  }
1620
1824
  ),
1621
- /* @__PURE__ */ jsx9(
1825
+ /* @__PURE__ */ jsx10(
1622
1826
  ChevronDownIcon,
1623
1827
  {
1624
1828
  className: cn(
@@ -1627,23 +1831,23 @@ var ToolCallGroup = memo2(({ tools, mergedToolRenderers }) => {
1627
1831
  )
1628
1832
  }
1629
1833
  ),
1630
- !isSettled ? /* @__PURE__ */ jsx9(Shimmer, { as: "span", duration: 1.5, children: title }) : /* @__PURE__ */ jsx9("span", { children: title }),
1631
- /* @__PURE__ */ jsx9("span", { className: cn(
1834
+ !isSettled ? /* @__PURE__ */ jsx10(Shimmer, { as: "span", duration: 1.5, children: title }) : /* @__PURE__ */ jsx10("span", { children: title }),
1835
+ /* @__PURE__ */ jsx10("span", { className: cn(
1632
1836
  "ml-1 shrink-0 rounded-sm border border-border/40 px-1 tabular-nums",
1633
1837
  "text-[10px] text-muted-foreground/50"
1634
1838
  ), children: tools.length })
1635
1839
  ]
1636
1840
  }
1637
1841
  ),
1638
- /* @__PURE__ */ jsx9(CollapsibleContent, { className: "overflow-hidden data-[state=closed]:animate-[boring-collapse-close_200ms_ease] data-[state=open]:animate-[boring-collapse-open_200ms_ease]", children: /* @__PURE__ */ jsxs8("div", { className: "relative mt-1.5 pl-[18px]", children: [
1639
- /* @__PURE__ */ jsx9("div", { className: "absolute left-[5px] top-0 bottom-2 w-px bg-border/35" }),
1640
- /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-0", children: tools.map(({ part, key }) => {
1842
+ /* @__PURE__ */ jsx10(CollapsibleContent, { className: "overflow-hidden data-[state=closed]:animate-[boring-collapse-close_200ms_ease] data-[state=open]:animate-[boring-collapse-open_200ms_ease]", children: /* @__PURE__ */ jsxs9("div", { className: "relative mt-1.5 pl-[18px]", children: [
1843
+ /* @__PURE__ */ jsx10("div", { className: "absolute left-[5px] top-0 bottom-2 w-px bg-border/35" }),
1844
+ /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-0", children: tools.map(({ part, key }) => {
1641
1845
  if (!isToolUIPart(part)) return null;
1642
1846
  const tp = part;
1643
1847
  const name = getToolName(part);
1644
1848
  const ui = extractToolUiMetadata(tp.output);
1645
1849
  const render = resolveToolRenderer(ui?.rendererId ?? name, mergedToolRenderers);
1646
- return /* @__PURE__ */ jsx9("div", { className: "min-w-0", children: render({ ...tp, toolName: name, ui }) }, key);
1850
+ return /* @__PURE__ */ jsx10("div", { className: "min-w-0", children: render({ ...tp, toolName: name, ui }) }, key);
1647
1851
  }) })
1648
1852
  ] }) })
1649
1853
  ] });
@@ -1677,13 +1881,13 @@ import {
1677
1881
  memo as memo3,
1678
1882
  useCallback as useCallback7,
1679
1883
  useContext,
1680
- useEffect as useEffect8,
1884
+ useEffect as useEffect9,
1681
1885
  useMemo as useMemo6,
1682
1886
  useRef as useRef8,
1683
1887
  useState as useState10
1684
1888
  } from "react";
1685
1889
  import { createHighlighter } from "shiki";
1686
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1890
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1687
1891
  var isItalic = (fontStyle) => fontStyle && fontStyle & 1;
1688
1892
  var isBold = (fontStyle) => fontStyle && fontStyle & 2;
1689
1893
  var isUnderline = (fontStyle) => (
@@ -1697,7 +1901,7 @@ var addKeysToTokens = (lines) => lines.map((line, lineIdx) => ({
1697
1901
  token
1698
1902
  }))
1699
1903
  }));
1700
- var TokenSpan = ({ token }) => /* @__PURE__ */ jsx10(
1904
+ var TokenSpan = ({ token }) => /* @__PURE__ */ jsx11(
1701
1905
  "span",
1702
1906
  {
1703
1907
  className: "dark:!text-[var(--shiki-dark)]",
@@ -1727,7 +1931,7 @@ var LINE_NUMBER_CLASSES = cn(
1727
1931
  var LineSpan = ({
1728
1932
  keyedLine,
1729
1933
  showLineNumbers
1730
- }) => /* @__PURE__ */ jsx10("span", { className: showLineNumbers ? LINE_NUMBER_CLASSES : "block", children: keyedLine.tokens.length === 0 ? "\n" : keyedLine.tokens.map(({ token, key }) => /* @__PURE__ */ jsx10(TokenSpan, { token }, key)) });
1934
+ }) => /* @__PURE__ */ jsx11("span", { className: showLineNumbers ? LINE_NUMBER_CLASSES : "block", children: keyedLine.tokens.length === 0 ? "\n" : keyedLine.tokens.map(({ token, key }) => /* @__PURE__ */ jsx11(TokenSpan, { token }, key)) });
1731
1935
  var CodeBlockContext = createContext({
1732
1936
  code: ""
1733
1937
  });
@@ -1820,7 +2024,7 @@ var CodeBlockBody = memo3(
1820
2024
  () => addKeysToTokens(tokenized.tokens),
1821
2025
  [tokenized.tokens]
1822
2026
  );
1823
- return /* @__PURE__ */ jsx10(
2027
+ return /* @__PURE__ */ jsx11(
1824
2028
  "pre",
1825
2029
  {
1826
2030
  className: cn(
@@ -1828,14 +2032,14 @@ var CodeBlockBody = memo3(
1828
2032
  className
1829
2033
  ),
1830
2034
  style: preStyle,
1831
- children: /* @__PURE__ */ jsx10(
2035
+ children: /* @__PURE__ */ jsx11(
1832
2036
  "code",
1833
2037
  {
1834
2038
  className: cn(
1835
2039
  "font-mono text-sm",
1836
2040
  showLineNumbers && "[counter-increment:line_0] [counter-reset:line]"
1837
2041
  ),
1838
- children: keyedLines.map((keyedLine) => /* @__PURE__ */ jsx10(
2042
+ children: keyedLines.map((keyedLine) => /* @__PURE__ */ jsx11(
1839
2043
  LineSpan,
1840
2044
  {
1841
2045
  keyedLine,
@@ -1856,7 +2060,7 @@ var CodeBlockContainer = ({
1856
2060
  language,
1857
2061
  style,
1858
2062
  ...props
1859
- }) => /* @__PURE__ */ jsx10(
2063
+ }) => /* @__PURE__ */ jsx11(
1860
2064
  "div",
1861
2065
  {
1862
2066
  className: cn(
@@ -1876,7 +2080,7 @@ var CodeBlockHeader = ({
1876
2080
  children,
1877
2081
  className,
1878
2082
  ...props
1879
- }) => /* @__PURE__ */ jsx10(
2083
+ }) => /* @__PURE__ */ jsx11(
1880
2084
  "div",
1881
2085
  {
1882
2086
  className: cn(
@@ -1891,12 +2095,12 @@ var CodeBlockTitle = ({
1891
2095
  children,
1892
2096
  className,
1893
2097
  ...props
1894
- }) => /* @__PURE__ */ jsx10("div", { className: cn("flex items-center gap-2", className), ...props, children });
2098
+ }) => /* @__PURE__ */ jsx11("div", { className: cn("flex items-center gap-2", className), ...props, children });
1895
2099
  var CodeBlockFilename = ({
1896
2100
  children,
1897
2101
  className,
1898
2102
  ...props
1899
- }) => /* @__PURE__ */ jsx10(
2103
+ }) => /* @__PURE__ */ jsx11(
1900
2104
  "span",
1901
2105
  {
1902
2106
  className: cn(
@@ -1924,7 +2128,7 @@ var CodeBlockContent = ({
1924
2128
  asyncKeyRef.current = { code: code3, language };
1925
2129
  setAsyncTokens(null);
1926
2130
  }
1927
- useEffect8(() => {
2131
+ useEffect9(() => {
1928
2132
  let cancelled = false;
1929
2133
  highlightCode(code3, lang, (result) => {
1930
2134
  if (!cancelled) {
@@ -1936,7 +2140,7 @@ var CodeBlockContent = ({
1936
2140
  };
1937
2141
  }, [code3, language]);
1938
2142
  const tokenized = asyncTokens ?? syncTokens;
1939
- return /* @__PURE__ */ jsx10("div", { className: "relative overflow-auto", children: /* @__PURE__ */ jsx10(CodeBlockBody, { showLineNumbers, tokenized }) });
2143
+ return /* @__PURE__ */ jsx11("div", { className: "relative overflow-auto", children: /* @__PURE__ */ jsx11(CodeBlockBody, { showLineNumbers, tokenized }) });
1940
2144
  };
1941
2145
  var CodeBlock2 = ({
1942
2146
  code: code3,
@@ -1947,9 +2151,9 @@ var CodeBlock2 = ({
1947
2151
  ...props
1948
2152
  }) => {
1949
2153
  const contextValue = useMemo6(() => ({ code: code3 }), [code3]);
1950
- return /* @__PURE__ */ jsx10(CodeBlockContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs9(CodeBlockContainer, { className, language, ...props, children: [
2154
+ return /* @__PURE__ */ jsx11(CodeBlockContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs10(CodeBlockContainer, { className, language, ...props, children: [
1951
2155
  children,
1952
- /* @__PURE__ */ jsx10(
2156
+ /* @__PURE__ */ jsx11(
1953
2157
  CodeBlockContent,
1954
2158
  {
1955
2159
  code: code3,
@@ -1989,14 +2193,14 @@ var CodeBlockCopyButton = ({
1989
2193
  onError?.(error);
1990
2194
  }
1991
2195
  }, [code3, onCopy, onError, timeout, isCopied]);
1992
- useEffect8(
2196
+ useEffect9(
1993
2197
  () => () => {
1994
2198
  window.clearTimeout(timeoutRef.current);
1995
2199
  },
1996
2200
  []
1997
2201
  );
1998
2202
  const Icon = isCopied ? CheckIcon : CopyIcon;
1999
- return /* @__PURE__ */ jsx10(
2203
+ return /* @__PURE__ */ jsx11(
2000
2204
  Button4,
2001
2205
  {
2002
2206
  className: cn("shrink-0", className),
@@ -2004,14 +2208,14 @@ var CodeBlockCopyButton = ({
2004
2208
  size: "icon",
2005
2209
  variant: "ghost",
2006
2210
  ...props,
2007
- children: children ?? /* @__PURE__ */ jsx10(Icon, { size: 14 })
2211
+ children: children ?? /* @__PURE__ */ jsx11(Icon, { size: 14 })
2008
2212
  }
2009
2213
  );
2010
2214
  };
2011
2215
 
2012
2216
  // src/front/primitives/tool.tsx
2013
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2014
- var Tool2 = ({ className, ...props }) => /* @__PURE__ */ jsx11(
2217
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2218
+ var Tool2 = ({ className, ...props }) => /* @__PURE__ */ jsx12(
2015
2219
  Collapsible2,
2016
2220
  {
2017
2221
  "data-boring-agent-part": "tool-card",
@@ -2038,15 +2242,15 @@ var statusLabels = {
2038
2242
  "output-error": "Error"
2039
2243
  };
2040
2244
  var statusIcons = {
2041
- "approval-requested": /* @__PURE__ */ jsx11(ClockIcon, { className: "size-4 text-accent" }),
2042
- "approval-responded": /* @__PURE__ */ jsx11(CheckCircleIcon, { className: "size-4 text-accent" }),
2043
- "input-available": /* @__PURE__ */ jsx11(ClockIcon, { className: "size-4 animate-pulse text-muted-foreground" }),
2044
- "input-streaming": /* @__PURE__ */ jsx11(CircleIcon, { className: "size-4 text-muted-foreground" }),
2045
- "output-available": /* @__PURE__ */ jsx11(CheckCircleIcon, { className: "size-4 text-accent" }),
2046
- "output-denied": /* @__PURE__ */ jsx11(XCircleIcon, { className: "size-4 text-destructive" }),
2047
- "output-error": /* @__PURE__ */ jsx11(XCircleIcon, { className: "size-4 text-destructive" })
2245
+ "approval-requested": /* @__PURE__ */ jsx12(ClockIcon, { className: "size-4 text-accent" }),
2246
+ "approval-responded": /* @__PURE__ */ jsx12(CheckCircleIcon, { className: "size-4 text-accent" }),
2247
+ "input-available": /* @__PURE__ */ jsx12(ClockIcon, { className: "size-4 animate-pulse text-muted-foreground" }),
2248
+ "input-streaming": /* @__PURE__ */ jsx12(CircleIcon, { className: "size-4 text-muted-foreground" }),
2249
+ "output-available": /* @__PURE__ */ jsx12(CheckCircleIcon, { className: "size-4 text-accent" }),
2250
+ "output-denied": /* @__PURE__ */ jsx12(XCircleIcon, { className: "size-4 text-destructive" }),
2251
+ "output-error": /* @__PURE__ */ jsx12(XCircleIcon, { className: "size-4 text-destructive" })
2048
2252
  };
2049
- var getStatusBadge = (status) => /* @__PURE__ */ jsxs10(Badge, { className: "gap-1.5 rounded-full text-xs", variant: "secondary", children: [
2253
+ var getStatusBadge = (status) => /* @__PURE__ */ jsxs11(Badge, { className: "gap-1.5 rounded-full text-xs", variant: "secondary", children: [
2050
2254
  statusIcons[status],
2051
2255
  statusLabels[status]
2052
2256
  ] });
@@ -2060,7 +2264,7 @@ var ToolHeader = ({
2060
2264
  ...props
2061
2265
  }) => {
2062
2266
  const derivedName = type === "dynamic-tool" ? toolName : type.split("-").slice(1).join("-");
2063
- return /* @__PURE__ */ jsxs10(
2267
+ return /* @__PURE__ */ jsxs11(
2064
2268
  CollapsibleTrigger2,
2065
2269
  {
2066
2270
  className: cn(
@@ -2069,17 +2273,17 @@ var ToolHeader = ({
2069
2273
  ),
2070
2274
  ...props,
2071
2275
  children: [
2072
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2073
- icon ?? /* @__PURE__ */ jsx11(WrenchIcon, { className: "size-4 text-muted-foreground" }),
2074
- /* @__PURE__ */ jsx11("span", { className: "font-medium text-sm", children: title ?? derivedName }),
2276
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
2277
+ icon ?? /* @__PURE__ */ jsx12(WrenchIcon, { className: "size-4 text-muted-foreground" }),
2278
+ /* @__PURE__ */ jsx12("span", { className: "font-medium text-sm", children: title ?? derivedName }),
2075
2279
  getStatusBadge(state)
2076
2280
  ] }),
2077
- /* @__PURE__ */ jsx11(ChevronDownIcon2, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
2281
+ /* @__PURE__ */ jsx12(ChevronDownIcon2, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
2078
2282
  ]
2079
2283
  }
2080
2284
  );
2081
2285
  };
2082
- var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx11(
2286
+ var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx12(
2083
2287
  CollapsibleContent2,
2084
2288
  {
2085
2289
  className: cn(
@@ -2089,9 +2293,9 @@ var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx11(
2089
2293
  ...props
2090
2294
  }
2091
2295
  );
2092
- var ToolInput = ({ className, input, ...props }) => /* @__PURE__ */ jsxs10("div", { className: cn("space-y-2 overflow-hidden", className), ...props, children: [
2093
- /* @__PURE__ */ jsx11("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Parameters" }),
2094
- /* @__PURE__ */ jsx11("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx11(CodeBlock2, { code: JSON.stringify(input, null, 2), language: "json" }) })
2296
+ var ToolInput = ({ className, input, ...props }) => /* @__PURE__ */ jsxs11("div", { className: cn("space-y-2 overflow-hidden", className), ...props, children: [
2297
+ /* @__PURE__ */ jsx12("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Parameters" }),
2298
+ /* @__PURE__ */ jsx12("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx12(CodeBlock2, { code: JSON.stringify(input, null, 2), language: "json" }) })
2095
2299
  ] });
2096
2300
  var ToolOutput = ({
2097
2301
  className,
@@ -2102,15 +2306,15 @@ var ToolOutput = ({
2102
2306
  if (!(output || errorText)) {
2103
2307
  return null;
2104
2308
  }
2105
- let Output = /* @__PURE__ */ jsx11("div", { children: output });
2309
+ let Output = /* @__PURE__ */ jsx12("div", { children: output });
2106
2310
  if (typeof output === "object" && !isValidElement(output)) {
2107
- Output = /* @__PURE__ */ jsx11(CodeBlock2, { code: JSON.stringify(output, null, 2), language: "json" });
2311
+ Output = /* @__PURE__ */ jsx12(CodeBlock2, { code: JSON.stringify(output, null, 2), language: "json" });
2108
2312
  } else if (typeof output === "string") {
2109
- Output = /* @__PURE__ */ jsx11(CodeBlock2, { code: output, language: "text" });
2313
+ Output = /* @__PURE__ */ jsx12(CodeBlock2, { code: output, language: "text" });
2110
2314
  }
2111
- return /* @__PURE__ */ jsxs10("div", { "data-boring-agent-part": "tool-result", className: cn("space-y-2", className), ...props, children: [
2112
- /* @__PURE__ */ jsx11("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: errorText ? "Error" : "Result" }),
2113
- /* @__PURE__ */ jsxs10(
2315
+ return /* @__PURE__ */ jsxs11("div", { "data-boring-agent-part": "tool-result", className: cn("space-y-2", className), ...props, children: [
2316
+ /* @__PURE__ */ jsx12("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: errorText ? "Error" : "Result" }),
2317
+ /* @__PURE__ */ jsxs11(
2114
2318
  "div",
2115
2319
  {
2116
2320
  className: cn(
@@ -2118,7 +2322,7 @@ var ToolOutput = ({
2118
2322
  errorText ? "bg-destructive/10 text-destructive" : "bg-muted/30 text-foreground"
2119
2323
  ),
2120
2324
  children: [
2121
- errorText && /* @__PURE__ */ jsx11("div", { className: "p-3", children: errorText }),
2325
+ errorText && /* @__PURE__ */ jsx12("div", { className: "p-3", children: errorText }),
2122
2326
  Output
2123
2327
  ]
2124
2328
  }
@@ -2132,10 +2336,10 @@ import { ChevronDownIcon as ChevronDownIcon3, ExternalLinkIcon, FileDiffIcon, Fi
2132
2336
 
2133
2337
  // src/front/ArtifactOpenContext.tsx
2134
2338
  import { createContext as createContext2, useContext as useContext2 } from "react";
2135
- import { jsx as jsx12 } from "react/jsx-runtime";
2339
+ import { jsx as jsx13 } from "react/jsx-runtime";
2136
2340
  var ArtifactOpenContext = createContext2(null);
2137
2341
  function ArtifactOpenProvider({ onOpenArtifact, children }) {
2138
- return /* @__PURE__ */ jsx12(ArtifactOpenContext.Provider, { value: onOpenArtifact ?? null, children });
2342
+ return /* @__PURE__ */ jsx13(ArtifactOpenContext.Provider, { value: onOpenArtifact ?? null, children });
2139
2343
  }
2140
2344
  function useOpenArtifact() {
2141
2345
  return useContext2(ArtifactOpenContext);
@@ -2150,8 +2354,8 @@ import {
2150
2354
  TooltipTrigger
2151
2355
  } from "@hachej/boring-ui-kit";
2152
2356
  import { XIcon } from "lucide-react";
2153
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2154
- var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsx13(
2357
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2358
+ var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsx14(
2155
2359
  "div",
2156
2360
  {
2157
2361
  className: cn(
@@ -2164,7 +2368,7 @@ var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsx13(
2164
2368
  var ArtifactHeader = ({
2165
2369
  className,
2166
2370
  ...props
2167
- }) => /* @__PURE__ */ jsx13(
2371
+ }) => /* @__PURE__ */ jsx14(
2168
2372
  "div",
2169
2373
  {
2170
2374
  className: cn(
@@ -2174,7 +2378,7 @@ var ArtifactHeader = ({
2174
2378
  ...props
2175
2379
  }
2176
2380
  );
2177
- var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx13(
2381
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx14(
2178
2382
  "p",
2179
2383
  {
2180
2384
  className: cn("font-medium text-foreground text-sm", className),
@@ -2184,11 +2388,11 @@ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx13(
2184
2388
  var ArtifactDescription = ({
2185
2389
  className,
2186
2390
  ...props
2187
- }) => /* @__PURE__ */ jsx13("p", { className: cn("text-muted-foreground text-sm", className), ...props });
2391
+ }) => /* @__PURE__ */ jsx14("p", { className: cn("text-muted-foreground text-sm", className), ...props });
2188
2392
  var ArtifactActions = ({
2189
2393
  className,
2190
2394
  ...props
2191
- }) => /* @__PURE__ */ jsx13("div", { className: cn("flex items-center gap-1", className), ...props });
2395
+ }) => /* @__PURE__ */ jsx14("div", { className: cn("flex items-center gap-1", className), ...props });
2192
2396
  var ArtifactAction = ({
2193
2397
  tooltip,
2194
2398
  label,
@@ -2199,7 +2403,7 @@ var ArtifactAction = ({
2199
2403
  variant = "ghost",
2200
2404
  ...props
2201
2405
  }) => {
2202
- const button = /* @__PURE__ */ jsxs11(
2406
+ const button = /* @__PURE__ */ jsxs12(
2203
2407
  Button5,
2204
2408
  {
2205
2409
  className: cn(
@@ -2211,15 +2415,15 @@ var ArtifactAction = ({
2211
2415
  variant,
2212
2416
  ...props,
2213
2417
  children: [
2214
- Icon ? /* @__PURE__ */ jsx13(Icon, { className: "size-4" }) : children,
2215
- /* @__PURE__ */ jsx13("span", { className: "sr-only", children: label || tooltip })
2418
+ Icon ? /* @__PURE__ */ jsx14(Icon, { className: "size-4" }) : children,
2419
+ /* @__PURE__ */ jsx14("span", { className: "sr-only", children: label || tooltip })
2216
2420
  ]
2217
2421
  }
2218
2422
  );
2219
2423
  if (tooltip) {
2220
- return /* @__PURE__ */ jsx13(TooltipProvider, { children: /* @__PURE__ */ jsxs11(Tooltip, { children: [
2221
- /* @__PURE__ */ jsx13(TooltipTrigger, { asChild: true, children: button }),
2222
- /* @__PURE__ */ jsx13(TooltipContent, { children: /* @__PURE__ */ jsx13("p", { children: tooltip }) })
2424
+ return /* @__PURE__ */ jsx14(TooltipProvider, { children: /* @__PURE__ */ jsxs12(Tooltip, { children: [
2425
+ /* @__PURE__ */ jsx14(TooltipTrigger, { asChild: true, children: button }),
2426
+ /* @__PURE__ */ jsx14(TooltipContent, { children: /* @__PURE__ */ jsx14("p", { children: tooltip }) })
2223
2427
  ] }) });
2224
2428
  }
2225
2429
  return button;
@@ -2227,11 +2431,11 @@ var ArtifactAction = ({
2227
2431
  var ArtifactContent = ({
2228
2432
  className,
2229
2433
  ...props
2230
- }) => /* @__PURE__ */ jsx13("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });
2434
+ }) => /* @__PURE__ */ jsx14("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });
2231
2435
 
2232
2436
  // src/front/toolRenderers.tsx
2233
2437
  import { CopyIcon as CopyIcon2, DownloadIcon } from "lucide-react";
2234
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2438
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2235
2439
  function asRecord2(value) {
2236
2440
  return typeof value === "object" && value !== null ? value : {};
2237
2441
  }
@@ -2255,7 +2459,7 @@ function toHeaderProps(part) {
2255
2459
  function PathLabel({ path }) {
2256
2460
  const onOpen = useOpenArtifact();
2257
2461
  if (!onOpen) {
2258
- return /* @__PURE__ */ jsx14("span", { className: "font-mono text-[12.5px] text-foreground/85", children: path });
2462
+ return /* @__PURE__ */ jsx15("span", { className: "font-mono text-[12.5px] text-foreground/85", children: path });
2259
2463
  }
2260
2464
  const open = (e) => {
2261
2465
  e.preventDefault();
@@ -2265,7 +2469,7 @@ function PathLabel({ path }) {
2265
2469
  const handleKeyDown = (e) => {
2266
2470
  if (e.key === "Enter" || e.key === " ") open(e);
2267
2471
  };
2268
- return /* @__PURE__ */ jsxs12(
2472
+ return /* @__PURE__ */ jsxs13(
2269
2473
  "span",
2270
2474
  {
2271
2475
  role: "button",
@@ -2281,8 +2485,8 @@ function PathLabel({ path }) {
2281
2485
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[color:var(--accent)]/40"
2282
2486
  ),
2283
2487
  children: [
2284
- /* @__PURE__ */ jsx14("span", { className: "truncate", children: path }),
2285
- /* @__PURE__ */ jsx14(
2488
+ /* @__PURE__ */ jsx15("span", { className: "truncate", children: path }),
2489
+ /* @__PURE__ */ jsx15(
2286
2490
  ExternalLinkIcon,
2287
2491
  {
2288
2492
  className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover/path:opacity-100",
@@ -2295,10 +2499,10 @@ function PathLabel({ path }) {
2295
2499
  );
2296
2500
  }
2297
2501
  function pathTitle(prefix, path) {
2298
- return /* @__PURE__ */ jsxs12("span", { className: "flex min-w-0 items-center gap-1.5", children: [
2299
- /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: prefix }),
2300
- /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground/40", "aria-hidden": "true", children: "\xB7" }),
2301
- /* @__PURE__ */ jsx14(PathLabel, { path })
2502
+ return /* @__PURE__ */ jsxs13("span", { className: "flex min-w-0 items-center gap-1.5", children: [
2503
+ /* @__PURE__ */ jsx15("span", { className: "text-muted-foreground", children: prefix }),
2504
+ /* @__PURE__ */ jsx15("span", { className: "text-muted-foreground/40", "aria-hidden": "true", children: "\xB7" }),
2505
+ /* @__PURE__ */ jsx15(PathLabel, { path })
2302
2506
  ] });
2303
2507
  }
2304
2508
  function renderBash2(part) {
@@ -2311,21 +2515,21 @@ function renderBash2(part) {
2311
2515
  const exitCode = typeof output.exitCode === "number" ? output.exitCode : null;
2312
2516
  const title = description || (command.length > 64 ? command.slice(0, 64) + "\u2026" : command) || "bash";
2313
2517
  const errorText = part.errorText || (stderr && (exitCode ?? 0) !== 0 ? stderr : void 0);
2314
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2315
- /* @__PURE__ */ jsx14(ToolHeader, { icon: /* @__PURE__ */ jsx14(SquareTerminalIcon, { className: "size-4 text-muted-foreground" }), title: `bash \xB7 ${title}`, ...toHeaderProps(part) }),
2316
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2317
- command && /* @__PURE__ */ jsxs12("section", { className: "space-y-2", children: [
2318
- /* @__PURE__ */ jsx14("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Command" }),
2319
- /* @__PURE__ */ jsx14(CodeBlock2, { code: command, language: "bash" })
2518
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2519
+ /* @__PURE__ */ jsx15(ToolHeader, { icon: /* @__PURE__ */ jsx15(SquareTerminalIcon, { className: "size-4 text-muted-foreground" }), title: `bash \xB7 ${title}`, ...toHeaderProps(part) }),
2520
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2521
+ command && /* @__PURE__ */ jsxs13("section", { className: "space-y-2", children: [
2522
+ /* @__PURE__ */ jsx15("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Command" }),
2523
+ /* @__PURE__ */ jsx15(CodeBlock2, { code: command, language: "bash" })
2320
2524
  ] }),
2321
- /* @__PURE__ */ jsx14(
2525
+ /* @__PURE__ */ jsx15(
2322
2526
  ToolOutput,
2323
2527
  {
2324
2528
  output: stdout && !errorText ? stdout : void 0,
2325
2529
  errorText
2326
2530
  }
2327
2531
  ),
2328
- exitCode !== null && exitCode !== 0 && !errorText && /* @__PURE__ */ jsxs12("div", { className: "text-xs text-destructive", children: [
2532
+ exitCode !== null && exitCode !== 0 && !errorText && /* @__PURE__ */ jsxs13("div", { className: "text-xs text-destructive", children: [
2329
2533
  "exit ",
2330
2534
  exitCode
2331
2535
  ] })
@@ -2338,13 +2542,13 @@ function renderRead2(part) {
2338
2542
  const path = typeof input.path === "string" ? input.path : "";
2339
2543
  const content = extractTextContent(output);
2340
2544
  const lang = langFromPath(path);
2341
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2342
- /* @__PURE__ */ jsx14(ToolHeader, { icon: /* @__PURE__ */ jsx14(FileTextIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("read", path), ...toHeaderProps(part) }),
2343
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2344
- /* @__PURE__ */ jsx14(ToolInput, { input }),
2345
- content && /* @__PURE__ */ jsxs12("section", { className: "space-y-2", children: [
2346
- /* @__PURE__ */ jsx14("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Content" }),
2347
- /* @__PURE__ */ jsx14(CodeBlock2, { code: content, language: lang ?? "text" })
2545
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2546
+ /* @__PURE__ */ jsx15(ToolHeader, { icon: /* @__PURE__ */ jsx15(FileTextIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("read", path), ...toHeaderProps(part) }),
2547
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2548
+ /* @__PURE__ */ jsx15(ToolInput, { input }),
2549
+ content && /* @__PURE__ */ jsxs13("section", { className: "space-y-2", children: [
2550
+ /* @__PURE__ */ jsx15("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Content" }),
2551
+ /* @__PURE__ */ jsx15(CodeBlock2, { code: content, language: lang ?? "text" })
2348
2552
  ] })
2349
2553
  ] })
2350
2554
  ] });
@@ -2355,21 +2559,21 @@ function renderWrite2(part) {
2355
2559
  const content = typeof input.content === "string" ? input.content : "";
2356
2560
  const bytes = content.length;
2357
2561
  const lang = langFromPath(path);
2358
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2359
- /* @__PURE__ */ jsx14(ToolHeader, { icon: /* @__PURE__ */ jsx14(FilePlus2Icon, { className: "size-4 text-muted-foreground" }), title: pathTitle("write", path), ...toHeaderProps(part) }),
2360
- /* @__PURE__ */ jsx14(ToolContent, { children: /* @__PURE__ */ jsxs12(Artifact, { className: "rounded-none border-0 bg-transparent shadow-none", children: [
2361
- /* @__PURE__ */ jsxs12(ArtifactHeader, { className: "border-0 px-0 pt-0 pb-2", children: [
2362
- /* @__PURE__ */ jsxs12("div", { children: [
2363
- /* @__PURE__ */ jsx14(ArtifactTitle, { children: path || "untitled" }),
2364
- /* @__PURE__ */ jsxs12(ArtifactDescription, { children: [
2562
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2563
+ /* @__PURE__ */ jsx15(ToolHeader, { icon: /* @__PURE__ */ jsx15(FilePlus2Icon, { className: "size-4 text-muted-foreground" }), title: pathTitle("write", path), ...toHeaderProps(part) }),
2564
+ /* @__PURE__ */ jsx15(ToolContent, { children: /* @__PURE__ */ jsxs13(Artifact, { className: "rounded-none border-0 bg-transparent shadow-none", children: [
2565
+ /* @__PURE__ */ jsxs13(ArtifactHeader, { className: "border-0 px-0 pt-0 pb-2", children: [
2566
+ /* @__PURE__ */ jsxs13("div", { children: [
2567
+ /* @__PURE__ */ jsx15(ArtifactTitle, { children: path || "untitled" }),
2568
+ /* @__PURE__ */ jsxs13(ArtifactDescription, { children: [
2365
2569
  bytes.toLocaleString(),
2366
2570
  " ",
2367
2571
  bytes === 1 ? "byte" : "bytes",
2368
2572
  lang ? ` \xB7 ${lang}` : ""
2369
2573
  ] })
2370
2574
  ] }),
2371
- /* @__PURE__ */ jsxs12(ArtifactActions, { children: [
2372
- /* @__PURE__ */ jsx14(
2575
+ /* @__PURE__ */ jsxs13(ArtifactActions, { children: [
2576
+ /* @__PURE__ */ jsx15(
2373
2577
  ArtifactAction,
2374
2578
  {
2375
2579
  icon: CopyIcon2,
@@ -2383,7 +2587,7 @@ function renderWrite2(part) {
2383
2587
  }
2384
2588
  }
2385
2589
  ),
2386
- /* @__PURE__ */ jsx14(
2590
+ /* @__PURE__ */ jsx15(
2387
2591
  ArtifactAction,
2388
2592
  {
2389
2593
  icon: DownloadIcon,
@@ -2407,7 +2611,7 @@ function renderWrite2(part) {
2407
2611
  )
2408
2612
  ] })
2409
2613
  ] }),
2410
- content && /* @__PURE__ */ jsx14(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ jsx14(CodeBlock2, { code: content, language: lang ?? "text", showLineNumbers: true }) })
2614
+ content && /* @__PURE__ */ jsx15(ArtifactContent, { className: "p-0", children: /* @__PURE__ */ jsx15(CodeBlock2, { code: content, language: lang ?? "text", showLineNumbers: true }) })
2411
2615
  ] }) })
2412
2616
  ] });
2413
2617
  }
@@ -2416,23 +2620,23 @@ function renderEdit2(part) {
2416
2620
  const path = typeof input.path === "string" ? input.path : "";
2417
2621
  const oldString = typeof input.oldString === "string" ? input.oldString : "";
2418
2622
  const newString = typeof input.newString === "string" ? input.newString : "";
2419
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2420
- /* @__PURE__ */ jsx14(ToolHeader, { icon: /* @__PURE__ */ jsx14(FileDiffIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("edit", path), ...toHeaderProps(part) }),
2421
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2422
- /* @__PURE__ */ jsxs12("section", { className: "space-y-2", children: [
2423
- /* @__PURE__ */ jsx14("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Diff" }),
2424
- /* @__PURE__ */ jsxs12("div", { className: "overflow-hidden rounded-sm border border-input/60 bg-muted/30 font-mono text-[13px] leading-relaxed", children: [
2425
- oldString && /* @__PURE__ */ jsxs12("div", { className: "grid grid-cols-[auto_1fr] gap-2 border-b border-input/40 bg-destructive/5 px-3 py-2", children: [
2426
- /* @__PURE__ */ jsx14("span", { className: "select-none text-destructive/70", children: "-" }),
2427
- /* @__PURE__ */ jsx14("span", { className: cn("whitespace-pre-wrap break-all text-destructive/90"), children: oldString })
2623
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2624
+ /* @__PURE__ */ jsx15(ToolHeader, { icon: /* @__PURE__ */ jsx15(FileDiffIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("edit", path), ...toHeaderProps(part) }),
2625
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2626
+ /* @__PURE__ */ jsxs13("section", { className: "space-y-2", children: [
2627
+ /* @__PURE__ */ jsx15("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Diff" }),
2628
+ /* @__PURE__ */ jsxs13("div", { className: "overflow-hidden rounded-sm border border-input/60 bg-muted/30 font-mono text-[13px] leading-relaxed", children: [
2629
+ oldString && /* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-[auto_1fr] gap-2 border-b border-input/40 bg-destructive/5 px-3 py-2", children: [
2630
+ /* @__PURE__ */ jsx15("span", { className: "select-none text-destructive/70", children: "-" }),
2631
+ /* @__PURE__ */ jsx15("span", { className: cn("whitespace-pre-wrap break-all text-destructive/90"), children: oldString })
2428
2632
  ] }),
2429
- newString && /* @__PURE__ */ jsxs12("div", { className: "grid grid-cols-[auto_1fr] gap-2 bg-accent/5 px-3 py-2", children: [
2430
- /* @__PURE__ */ jsx14("span", { className: "select-none text-accent/80", children: "+" }),
2431
- /* @__PURE__ */ jsx14("span", { className: "whitespace-pre-wrap break-all text-accent", children: newString })
2633
+ newString && /* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-[auto_1fr] gap-2 bg-accent/5 px-3 py-2", children: [
2634
+ /* @__PURE__ */ jsx15("span", { className: "select-none text-accent/80", children: "+" }),
2635
+ /* @__PURE__ */ jsx15("span", { className: "whitespace-pre-wrap break-all text-accent", children: newString })
2432
2636
  ] })
2433
2637
  ] })
2434
2638
  ] }),
2435
- /* @__PURE__ */ jsx14(ToolOutput, { output: part.output, errorText: part.errorText })
2639
+ /* @__PURE__ */ jsx15(ToolOutput, { output: part.output, errorText: part.errorText })
2436
2640
  ] })
2437
2641
  ] });
2438
2642
  }
@@ -2443,18 +2647,18 @@ function renderSearchLike2(toolName, part) {
2443
2647
  const path = typeof input.path === "string" ? input.path : "";
2444
2648
  const glob = typeof input.glob === "string" ? input.glob : "";
2445
2649
  const summary = [pattern, path, glob].filter(Boolean).join(" \xB7 ");
2446
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2447
- /* @__PURE__ */ jsx14(
2650
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2651
+ /* @__PURE__ */ jsx15(
2448
2652
  ToolHeader,
2449
2653
  {
2450
- icon: /* @__PURE__ */ jsx14(SearchLikeIcon, { className: "size-4 text-muted-foreground" }),
2654
+ icon: /* @__PURE__ */ jsx15(SearchLikeIcon, { className: "size-4 text-muted-foreground" }),
2451
2655
  title: summary ? `${toolName} \xB7 ${summary}` : toolName,
2452
2656
  ...toHeaderProps(part)
2453
2657
  }
2454
2658
  ),
2455
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2456
- /* @__PURE__ */ jsx14(ToolInput, { input }),
2457
- /* @__PURE__ */ jsx14(ToolOutput, { output: part.output, errorText: part.errorText })
2659
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2660
+ /* @__PURE__ */ jsx15(ToolInput, { input }),
2661
+ /* @__PURE__ */ jsx15(ToolOutput, { output: part.output, errorText: part.errorText })
2458
2662
  ] })
2459
2663
  ] });
2460
2664
  }
@@ -2477,8 +2681,8 @@ function renderExecUi2(part) {
2477
2681
  const kind = typeof input.kind === "string" ? input.kind : "(empty)";
2478
2682
  const tokens = extractParamTokens(input.params);
2479
2683
  const headerProps = toHeaderProps(part);
2480
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2481
- /* @__PURE__ */ jsxs12(
2684
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2685
+ /* @__PURE__ */ jsxs13(
2482
2686
  CollapsibleTrigger3,
2483
2687
  {
2484
2688
  className: cn(
@@ -2486,17 +2690,17 @@ function renderExecUi2(part) {
2486
2690
  "hover:bg-muted/40 transition-colors"
2487
2691
  ),
2488
2692
  children: [
2489
- /* @__PURE__ */ jsx14(
2693
+ /* @__PURE__ */ jsx15(
2490
2694
  ZapIcon,
2491
2695
  {
2492
2696
  className: "size-3.5 shrink-0 text-muted-foreground/70",
2493
2697
  "aria-hidden": "true"
2494
2698
  }
2495
2699
  ),
2496
- /* @__PURE__ */ jsx14("span", { className: "font-medium text-sm", children: kind }),
2497
- tokens.length > 0 && /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-center gap-1.5 overflow-hidden", children: [
2498
- /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground/40", "aria-hidden": "true", children: "\xB7" }),
2499
- tokens.map((tok, i) => /* @__PURE__ */ jsx14(
2700
+ /* @__PURE__ */ jsx15("span", { className: "font-medium text-sm", children: kind }),
2701
+ tokens.length > 0 && /* @__PURE__ */ jsxs13("div", { className: "flex min-w-0 items-center gap-1.5 overflow-hidden", children: [
2702
+ /* @__PURE__ */ jsx15("span", { className: "text-muted-foreground/40", "aria-hidden": "true", children: "\xB7" }),
2703
+ tokens.map((tok, i) => /* @__PURE__ */ jsx15(
2500
2704
  "span",
2501
2705
  {
2502
2706
  className: cn(
@@ -2509,9 +2713,9 @@ function renderExecUi2(part) {
2509
2713
  i
2510
2714
  ))
2511
2715
  ] }),
2512
- /* @__PURE__ */ jsxs12("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
2716
+ /* @__PURE__ */ jsxs13("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
2513
2717
  getStatusBadge(headerProps.state),
2514
- /* @__PURE__ */ jsx14(
2718
+ /* @__PURE__ */ jsx15(
2515
2719
  ChevronDownIcon3,
2516
2720
  {
2517
2721
  className: "size-4 text-muted-foreground/60 transition-transform group-data-[state=open]/exec-ui:rotate-180",
@@ -2522,18 +2726,18 @@ function renderExecUi2(part) {
2522
2726
  ]
2523
2727
  }
2524
2728
  ),
2525
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2526
- part.input !== void 0 && part.input !== null && /* @__PURE__ */ jsx14(ToolInput, { input: part.input }),
2527
- /* @__PURE__ */ jsx14(ToolOutput, { output: part.output, errorText: part.errorText })
2729
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2730
+ part.input !== void 0 && part.input !== null && /* @__PURE__ */ jsx15(ToolInput, { input: part.input }),
2731
+ /* @__PURE__ */ jsx15(ToolOutput, { output: part.output, errorText: part.errorText })
2528
2732
  ] })
2529
2733
  ] });
2530
2734
  }
2531
2735
  function renderFallback2(part) {
2532
- return /* @__PURE__ */ jsxs12(Tool2, { children: [
2533
- /* @__PURE__ */ jsx14(ToolHeader, { title: part.toolName, ...toHeaderProps(part) }),
2534
- /* @__PURE__ */ jsxs12(ToolContent, { children: [
2535
- part.input !== void 0 && part.input !== null && /* @__PURE__ */ jsx14(ToolInput, { input: part.input }),
2536
- /* @__PURE__ */ jsx14(ToolOutput, { output: part.output, errorText: part.errorText })
2736
+ return /* @__PURE__ */ jsxs13(Tool2, { children: [
2737
+ /* @__PURE__ */ jsx15(ToolHeader, { title: part.toolName, ...toHeaderProps(part) }),
2738
+ /* @__PURE__ */ jsxs13(ToolContent, { children: [
2739
+ part.input !== void 0 && part.input !== null && /* @__PURE__ */ jsx15(ToolInput, { input: part.input }),
2740
+ /* @__PURE__ */ jsx15(ToolOutput, { output: part.output, errorText: part.errorText })
2537
2741
  ] })
2538
2742
  ] });
2539
2743
  }
@@ -2560,14 +2764,14 @@ function mergeShadcnToolRenderers(overrides) {
2560
2764
  // src/front/primitives/conversation.tsx
2561
2765
  import { Button as Button6 } from "@hachej/boring-ui-kit";
2562
2766
  import { ArrowDownIcon, DownloadIcon as DownloadIcon2 } from "lucide-react";
2563
- import { useCallback as useCallback8, useEffect as useEffect9 } from "react";
2767
+ import { useCallback as useCallback8, useEffect as useEffect10 } from "react";
2564
2768
  import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
2565
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2769
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2566
2770
  var ConversationScrollController = ({
2567
2771
  onScrollToBottomReady
2568
2772
  }) => {
2569
2773
  const { scrollToBottom } = useStickToBottomContext();
2570
- useEffect9(() => {
2774
+ useEffect10(() => {
2571
2775
  onScrollToBottomReady?.(scrollToBottom);
2572
2776
  return () => onScrollToBottomReady?.(() => {
2573
2777
  });
@@ -2579,7 +2783,7 @@ var Conversation = ({
2579
2783
  children,
2580
2784
  onScrollToBottomReady,
2581
2785
  ...props
2582
- }) => /* @__PURE__ */ jsxs13(
2786
+ }) => /* @__PURE__ */ jsxs14(
2583
2787
  StickToBottom,
2584
2788
  {
2585
2789
  className: cn("relative flex-1 overflow-y-hidden", className),
@@ -2588,7 +2792,7 @@ var Conversation = ({
2588
2792
  role: "log",
2589
2793
  ...props,
2590
2794
  children: [
2591
- /* @__PURE__ */ jsx15(ConversationScrollController, { onScrollToBottomReady }),
2795
+ /* @__PURE__ */ jsx16(ConversationScrollController, { onScrollToBottomReady }),
2592
2796
  children
2593
2797
  ]
2594
2798
  }
@@ -2596,7 +2800,7 @@ var Conversation = ({
2596
2800
  var ConversationContent = ({
2597
2801
  className,
2598
2802
  ...props
2599
- }) => /* @__PURE__ */ jsx15(
2803
+ }) => /* @__PURE__ */ jsx16(
2600
2804
  StickToBottom.Content,
2601
2805
  {
2602
2806
  className: cn("flex flex-col gap-8 p-4", className),
@@ -2611,7 +2815,7 @@ var ConversationScrollButton = ({
2611
2815
  const handleScrollToBottom = useCallback8(() => {
2612
2816
  scrollToBottom();
2613
2817
  }, [scrollToBottom]);
2614
- return !isAtBottom && /* @__PURE__ */ jsx15(
2818
+ return !isAtBottom && /* @__PURE__ */ jsx16(
2615
2819
  Button6,
2616
2820
  {
2617
2821
  className: cn(
@@ -2624,7 +2828,7 @@ var ConversationScrollButton = ({
2624
2828
  variant: "outline",
2625
2829
  "aria-label": "Scroll to latest message",
2626
2830
  ...props,
2627
- children: /* @__PURE__ */ jsx15(ArrowDownIcon, { className: "size-4" })
2831
+ children: /* @__PURE__ */ jsx16(ArrowDownIcon, { className: "size-4" })
2628
2832
  }
2629
2833
  );
2630
2834
  };
@@ -2632,7 +2836,7 @@ var ConversationScrollButton = ({
2632
2836
  // src/front/ChatEmptyState.tsx
2633
2837
  import { ArrowUpRight, BookOpen, Code2, FileSearch, Wand2 } from "lucide-react";
2634
2838
  import { Button as Button7 } from "@hachej/boring-ui-kit";
2635
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2839
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2636
2840
  var defaultChatSuggestions = [
2637
2841
  {
2638
2842
  label: "Summarize the README",
@@ -2668,7 +2872,7 @@ function ChatEmptyState({
2668
2872
  footer,
2669
2873
  className
2670
2874
  }) {
2671
- return /* @__PURE__ */ jsxs14(
2875
+ return /* @__PURE__ */ jsxs15(
2672
2876
  "div",
2673
2877
  {
2674
2878
  "data-boring-agent-part": "empty-state",
@@ -2677,20 +2881,20 @@ function ChatEmptyState({
2677
2881
  className
2678
2882
  ),
2679
2883
  children: [
2680
- eyebrow && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 text-[10.5px] font-medium uppercase tracking-[0.16em] text-muted-foreground dark:text-zinc-300", children: [
2681
- /* @__PURE__ */ jsx16("span", { className: "inline-block h-px w-4 bg-[color:var(--accent)]", "aria-hidden": "true" }),
2884
+ eyebrow && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-[10.5px] font-medium uppercase tracking-[0.16em] text-muted-foreground dark:text-zinc-300", children: [
2885
+ /* @__PURE__ */ jsx17("span", { className: "inline-block h-px w-4 bg-[color:var(--accent)]", "aria-hidden": "true" }),
2682
2886
  eyebrow
2683
2887
  ] }),
2684
- title && /* @__PURE__ */ jsx16("h3", { className: "mt-3 text-[34px] font-medium leading-[1.05] tracking-[-0.02em] text-foreground dark:text-zinc-50", children: title }),
2685
- description && /* @__PURE__ */ jsx16("p", { className: "mt-3 max-w-[440px] text-[14px] leading-relaxed text-muted-foreground dark:text-zinc-300", children: description }),
2686
- suggestions.length > 0 && /* @__PURE__ */ jsx16(
2888
+ title && /* @__PURE__ */ jsx17("h3", { className: "mt-3 text-[34px] font-medium leading-[1.05] tracking-[-0.02em] text-foreground dark:text-zinc-50", children: title }),
2889
+ description && /* @__PURE__ */ jsx17("p", { className: "mt-3 max-w-[440px] text-[14px] leading-relaxed text-muted-foreground dark:text-zinc-300", children: description }),
2890
+ suggestions.length > 0 && /* @__PURE__ */ jsx17(
2687
2891
  "div",
2688
2892
  {
2689
2893
  "data-boring-agent-part": "suggestion-grid",
2690
2894
  className: "mt-8 grid w-full grid-cols-1 gap-px overflow-hidden rounded-xl bg-border/70 ring-1 ring-border/70 sm:grid-cols-2",
2691
2895
  children: suggestions.map((suggestion) => {
2692
2896
  const Icon = suggestion.icon;
2693
- return /* @__PURE__ */ jsxs14(
2897
+ return /* @__PURE__ */ jsxs15(
2694
2898
  Button7,
2695
2899
  {
2696
2900
  type: "button",
@@ -2705,18 +2909,18 @@ function ChatEmptyState({
2705
2909
  },
2706
2910
  className: "group h-auto justify-start gap-3 rounded-none bg-background px-4 py-3.5 text-left hover:bg-[color:var(--accent-soft)] focus-visible:bg-[color:var(--accent-soft)]",
2707
2911
  children: [
2708
- Icon && /* @__PURE__ */ jsx16(
2912
+ Icon && /* @__PURE__ */ jsx17(
2709
2913
  Icon,
2710
2914
  {
2711
2915
  className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground transition-colors group-hover:text-[color:var(--accent)]",
2712
2916
  strokeWidth: 1.75
2713
2917
  }
2714
2918
  ),
2715
- /* @__PURE__ */ jsxs14("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
2716
- /* @__PURE__ */ jsx16("span", { className: "truncate text-[13px] font-medium text-foreground", children: suggestion.label }),
2717
- suggestion.hint && /* @__PURE__ */ jsx16("span", { className: "truncate text-[12px] text-muted-foreground", children: suggestion.hint })
2919
+ /* @__PURE__ */ jsxs15("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
2920
+ /* @__PURE__ */ jsx17("span", { className: "truncate text-[13px] font-medium text-foreground", children: suggestion.label }),
2921
+ suggestion.hint && /* @__PURE__ */ jsx17("span", { className: "truncate text-[12px] text-muted-foreground", children: suggestion.hint })
2718
2922
  ] }),
2719
- /* @__PURE__ */ jsx16(
2923
+ /* @__PURE__ */ jsx17(
2720
2924
  ArrowUpRight,
2721
2925
  {
2722
2926
  className: cn(
@@ -2757,13 +2961,13 @@ import {
2757
2961
  memo as memo4,
2758
2962
  useCallback as useCallback9,
2759
2963
  useContext as useContext3,
2760
- useEffect as useEffect10,
2964
+ useEffect as useEffect11,
2761
2965
  useMemo as useMemo7,
2762
2966
  useState as useState11
2763
2967
  } from "react";
2764
2968
  import { Streamdown } from "streamdown";
2765
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2766
- var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx17(
2969
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2970
+ var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx18(
2767
2971
  "div",
2768
2972
  {
2769
2973
  "data-boring-agent-message-role": from,
@@ -2779,7 +2983,7 @@ var MessageContent = ({
2779
2983
  children,
2780
2984
  className,
2781
2985
  ...props
2782
- }) => /* @__PURE__ */ jsx17(
2986
+ }) => /* @__PURE__ */ jsx18(
2783
2987
  "div",
2784
2988
  {
2785
2989
  className: cn(
@@ -2796,7 +3000,7 @@ var MessageActions = ({
2796
3000
  className,
2797
3001
  children,
2798
3002
  ...props
2799
- }) => /* @__PURE__ */ jsx17("div", { className: cn("flex items-center gap-1", className), ...props, children });
3003
+ }) => /* @__PURE__ */ jsx18("div", { className: cn("flex items-center gap-1", className), ...props, children });
2800
3004
  var MessageAction = ({
2801
3005
  tooltip,
2802
3006
  children,
@@ -2805,14 +3009,14 @@ var MessageAction = ({
2805
3009
  size = "icon-sm",
2806
3010
  ...props
2807
3011
  }) => {
2808
- const button = /* @__PURE__ */ jsxs15(Button8, { size, type: "button", variant, ...props, children: [
3012
+ const button = /* @__PURE__ */ jsxs16(Button8, { size, type: "button", variant, ...props, children: [
2809
3013
  children,
2810
- /* @__PURE__ */ jsx17("span", { className: "sr-only", children: label || tooltip })
3014
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: label || tooltip })
2811
3015
  ] });
2812
3016
  if (tooltip) {
2813
- return /* @__PURE__ */ jsx17(TooltipProvider2, { children: /* @__PURE__ */ jsxs15(Tooltip2, { children: [
2814
- /* @__PURE__ */ jsx17(TooltipTrigger2, { asChild: true, children: button }),
2815
- /* @__PURE__ */ jsx17(TooltipContent2, { children: /* @__PURE__ */ jsx17("p", { children: tooltip }) })
3017
+ return /* @__PURE__ */ jsx18(TooltipProvider2, { children: /* @__PURE__ */ jsxs16(Tooltip2, { children: [
3018
+ /* @__PURE__ */ jsx18(TooltipTrigger2, { asChild: true, children: button }),
3019
+ /* @__PURE__ */ jsx18(TooltipContent2, { children: /* @__PURE__ */ jsx18("p", { children: tooltip }) })
2816
3020
  ] }) });
2817
3021
  }
2818
3022
  return button;
@@ -2853,9 +3057,9 @@ function extractCodeBlockText(children) {
2853
3057
  var MarkdownPre = ({ children }) => {
2854
3058
  const code3 = extractCodeBlockText(children).replace(/\n$/, "");
2855
3059
  const language = extractCodeBlockLanguage(children);
2856
- return /* @__PURE__ */ jsx17(CodeBlock2, { code: code3, language: language ?? "text", className: "my-3", children: /* @__PURE__ */ jsxs15(CodeBlockHeader, { children: [
2857
- /* @__PURE__ */ jsx17(CodeBlockTitle, { children: /* @__PURE__ */ jsx17(CodeBlockFilename, { children: language ?? "text" }) }),
2858
- /* @__PURE__ */ jsx17(CodeBlockCopyButton, {})
3060
+ return /* @__PURE__ */ jsx18(CodeBlock2, { code: code3, language: language ?? "text", className: "my-3", children: /* @__PURE__ */ jsxs16(CodeBlockHeader, { children: [
3061
+ /* @__PURE__ */ jsx18(CodeBlockTitle, { children: /* @__PURE__ */ jsx18(CodeBlockFilename, { children: language ?? "text" }) }),
3062
+ /* @__PURE__ */ jsx18(CodeBlockCopyButton, {})
2859
3063
  ] }) });
2860
3064
  };
2861
3065
  var MarkdownCode = ({
@@ -2865,9 +3069,9 @@ var MarkdownCode = ({
2865
3069
  ...props
2866
3070
  }) => {
2867
3071
  if (inline === false) {
2868
- return /* @__PURE__ */ jsx17("code", { className, ...props, children });
3072
+ return /* @__PURE__ */ jsx18("code", { className, ...props, children });
2869
3073
  }
2870
- return /* @__PURE__ */ jsx17(
3074
+ return /* @__PURE__ */ jsx18(
2871
3075
  "code",
2872
3076
  {
2873
3077
  className: cn(
@@ -2885,7 +3089,7 @@ var markdownComponents = {
2885
3089
  code: MarkdownCode
2886
3090
  };
2887
3091
  var MessageResponse = memo4(
2888
- ({ className, shikiTheme, components, ...props }) => /* @__PURE__ */ jsx17(
3092
+ ({ className, shikiTheme, components, ...props }) => /* @__PURE__ */ jsx18(
2889
3093
  Streamdown,
2890
3094
  {
2891
3095
  className: cn(
@@ -2919,13 +3123,13 @@ import {
2919
3123
  memo as memo5,
2920
3124
  useCallback as useCallback10,
2921
3125
  useContext as useContext4,
2922
- useEffect as useEffect11,
3126
+ useEffect as useEffect12,
2923
3127
  useMemo as useMemo8,
2924
3128
  useRef as useRef9,
2925
3129
  useState as useState12
2926
3130
  } from "react";
2927
3131
  import { Streamdown as Streamdown2 } from "streamdown";
2928
- import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3132
+ import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
2929
3133
  var ReasoningContext = createContext4(null);
2930
3134
  var useReasoning = () => {
2931
3135
  const context = useContext4(ReasoningContext);
@@ -2961,7 +3165,7 @@ var Reasoning = memo5(
2961
3165
  const hasEverStreamedRef = useRef9(isStreaming);
2962
3166
  const [hasAutoClosed, setHasAutoClosed] = useState12(false);
2963
3167
  const startTimeRef = useRef9(null);
2964
- useEffect11(() => {
3168
+ useEffect12(() => {
2965
3169
  if (isStreaming) {
2966
3170
  hasEverStreamedRef.current = true;
2967
3171
  if (startTimeRef.current === null) {
@@ -2972,12 +3176,12 @@ var Reasoning = memo5(
2972
3176
  startTimeRef.current = null;
2973
3177
  }
2974
3178
  }, [isStreaming, setDuration]);
2975
- useEffect11(() => {
3179
+ useEffect12(() => {
2976
3180
  if (isStreaming && !isOpen && !isExplicitlyClosed) {
2977
3181
  setIsOpen(true);
2978
3182
  }
2979
3183
  }, [isStreaming, isOpen, setIsOpen, isExplicitlyClosed]);
2980
- useEffect11(() => {
3184
+ useEffect12(() => {
2981
3185
  if (hasEverStreamedRef.current && !isStreaming && isOpen && !hasAutoClosed) {
2982
3186
  const timer = setTimeout(() => {
2983
3187
  setIsOpen(false);
@@ -2996,7 +3200,7 @@ var Reasoning = memo5(
2996
3200
  () => ({ duration, isOpen, isStreaming, setIsOpen }),
2997
3201
  [duration, isOpen, isStreaming, setIsOpen]
2998
3202
  );
2999
- return /* @__PURE__ */ jsx18(ReasoningContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx18(
3203
+ return /* @__PURE__ */ jsx19(ReasoningContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx19(
3000
3204
  Collapsible3,
3001
3205
  {
3002
3206
  className: cn("not-prose mb-2", className),
@@ -3010,12 +3214,12 @@ var Reasoning = memo5(
3010
3214
  );
3011
3215
  var defaultGetThinkingMessage = (isStreaming, duration) => {
3012
3216
  if (isStreaming || duration === 0) {
3013
- return /* @__PURE__ */ jsx18(Shimmer, { duration: 1, children: "thinking" });
3217
+ return /* @__PURE__ */ jsx19(Shimmer, { duration: 1, children: "thinking" });
3014
3218
  }
3015
3219
  if (duration === void 0) {
3016
- return /* @__PURE__ */ jsx18("span", { children: "thoughts" });
3220
+ return /* @__PURE__ */ jsx19("span", { children: "thoughts" });
3017
3221
  }
3018
- return /* @__PURE__ */ jsxs16("span", { children: [
3222
+ return /* @__PURE__ */ jsxs17("span", { children: [
3019
3223
  "thoughts \xB7 ",
3020
3224
  duration,
3021
3225
  "s"
@@ -3029,7 +3233,7 @@ var ReasoningTrigger = memo5(
3029
3233
  ...props
3030
3234
  }) => {
3031
3235
  const { isStreaming, isOpen, duration } = useReasoning();
3032
- return /* @__PURE__ */ jsx18(
3236
+ return /* @__PURE__ */ jsx19(
3033
3237
  CollapsibleTrigger4,
3034
3238
  {
3035
3239
  className: cn(
@@ -3037,10 +3241,10 @@ var ReasoningTrigger = memo5(
3037
3241
  className
3038
3242
  ),
3039
3243
  ...props,
3040
- children: children ?? /* @__PURE__ */ jsxs16(Fragment5, { children: [
3041
- /* @__PURE__ */ jsx18(BrainIcon, { className: "size-3" }),
3244
+ children: children ?? /* @__PURE__ */ jsxs17(Fragment5, { children: [
3245
+ /* @__PURE__ */ jsx19(BrainIcon, { className: "size-3" }),
3042
3246
  getThinkingMessage(isStreaming, duration),
3043
- /* @__PURE__ */ jsx18(
3247
+ /* @__PURE__ */ jsx19(
3044
3248
  ChevronDownIcon4,
3045
3249
  {
3046
3250
  className: cn(
@@ -3056,7 +3260,7 @@ var ReasoningTrigger = memo5(
3056
3260
  );
3057
3261
  var streamdownPlugins2 = { cjk: cjk2, code: code2, math: math2, mermaid: mermaid2 };
3058
3262
  var ReasoningContent = memo5(
3059
- ({ className, children, ...props }) => /* @__PURE__ */ jsx18(
3263
+ ({ className, children, ...props }) => /* @__PURE__ */ jsx19(
3060
3264
  CollapsibleContent3,
3061
3265
  {
3062
3266
  className: cn(
@@ -3065,7 +3269,7 @@ var ReasoningContent = memo5(
3065
3269
  className
3066
3270
  ),
3067
3271
  ...props,
3068
- children: /* @__PURE__ */ jsx18(Streamdown2, { plugins: streamdownPlugins2, children })
3272
+ children: /* @__PURE__ */ jsx19(Streamdown2, { plugins: streamdownPlugins2, children })
3069
3273
  }
3070
3274
  )
3071
3275
  );
@@ -3107,7 +3311,7 @@ import {
3107
3311
  XIcon as XIcon2
3108
3312
  } from "lucide-react";
3109
3313
  import { nanoid } from "nanoid";
3110
- import { useCallback as useCallback11, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef10, useState as useState13 } from "react";
3314
+ import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo9, useRef as useRef10, useState as useState13 } from "react";
3111
3315
 
3112
3316
  // src/front/browserFiles.ts
3113
3317
  var convertBlobUrlToDataUrl = async (url) => {
@@ -3158,11 +3362,11 @@ import {
3158
3362
  TooltipTrigger as TooltipTrigger3
3159
3363
  } from "@hachej/boring-ui-kit";
3160
3364
  import { Children } from "react";
3161
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3365
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
3162
3366
  var PromptInputFooter = ({
3163
3367
  className,
3164
3368
  ...props
3165
- }) => /* @__PURE__ */ jsx19(
3369
+ }) => /* @__PURE__ */ jsx20(
3166
3370
  InputGroupAddon,
3167
3371
  {
3168
3372
  align: "block-end",
@@ -3172,7 +3376,7 @@ var PromptInputFooter = ({
3172
3376
  );
3173
3377
 
3174
3378
  // src/front/primitives/prompt-input.tsx
3175
- import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
3379
+ import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
3176
3380
  var PromptInput = ({
3177
3381
  className,
3178
3382
  accept,
@@ -3202,7 +3406,7 @@ var PromptInput = ({
3202
3406
  const files = usingProvider ? controller.attachments.files : items;
3203
3407
  const [referencedSources, setReferencedSources] = useState13([]);
3204
3408
  const filesRef = useRef10(files);
3205
- useEffect12(() => {
3409
+ useEffect13(() => {
3206
3410
  filesRef.current = files;
3207
3411
  }, [files]);
3208
3412
  const openFileDialogLocal = useCallback11(() => {
@@ -3338,18 +3542,18 @@ var PromptInput = ({
3338
3542
  clearAttachments();
3339
3543
  clearReferencedSources();
3340
3544
  }, [clearAttachments, clearReferencedSources]);
3341
- useEffect12(() => {
3545
+ useEffect13(() => {
3342
3546
  if (!usingProvider) {
3343
3547
  return;
3344
3548
  }
3345
3549
  controller.__registerFileInput(inputRef, () => inputRef.current?.click());
3346
3550
  }, [usingProvider, controller]);
3347
- useEffect12(() => {
3551
+ useEffect13(() => {
3348
3552
  if (syncHiddenInput && inputRef.current && files.length === 0) {
3349
3553
  inputRef.current.value = "";
3350
3554
  }
3351
3555
  }, [files, syncHiddenInput]);
3352
- useEffect12(() => {
3556
+ useEffect13(() => {
3353
3557
  const form = formRef.current;
3354
3558
  if (!form) {
3355
3559
  return;
@@ -3377,7 +3581,7 @@ var PromptInput = ({
3377
3581
  form.removeEventListener("drop", onDrop);
3378
3582
  };
3379
3583
  }, [add, globalDrop]);
3380
- useEffect12(() => {
3584
+ useEffect13(() => {
3381
3585
  if (!globalDrop) {
3382
3586
  return;
3383
3587
  }
@@ -3401,7 +3605,7 @@ var PromptInput = ({
3401
3605
  document.removeEventListener("drop", onDrop);
3402
3606
  };
3403
3607
  }, [add, globalDrop]);
3404
- useEffect12(
3608
+ useEffect13(
3405
3609
  () => () => {
3406
3610
  if (!usingProvider) {
3407
3611
  for (const f of filesRef.current) {
@@ -3495,8 +3699,8 @@ var PromptInput = ({
3495
3699
  },
3496
3700
  [usingProvider, controller, files, onSubmit, clear]
3497
3701
  );
3498
- const inner = /* @__PURE__ */ jsxs18(Fragment6, { children: [
3499
- /* @__PURE__ */ jsx20(
3702
+ const inner = /* @__PURE__ */ jsxs19(Fragment6, { children: [
3703
+ /* @__PURE__ */ jsx21(
3500
3704
  Input,
3501
3705
  {
3502
3706
  accept,
@@ -3509,7 +3713,7 @@ var PromptInput = ({
3509
3713
  type: "file"
3510
3714
  }
3511
3715
  ),
3512
- /* @__PURE__ */ jsx20(
3716
+ /* @__PURE__ */ jsx21(
3513
3717
  "form",
3514
3718
  {
3515
3719
  "data-boring-agent-part": "composer",
@@ -3517,12 +3721,12 @@ var PromptInput = ({
3517
3721
  onSubmit: handleSubmit,
3518
3722
  ref: formRef,
3519
3723
  ...props,
3520
- children: /* @__PURE__ */ jsx20(InputGroup, { className: "overflow-hidden", children })
3724
+ children: /* @__PURE__ */ jsx21(InputGroup, { className: "overflow-hidden", children })
3521
3725
  }
3522
3726
  )
3523
3727
  ] });
3524
- const withReferencedSources = /* @__PURE__ */ jsx20(LocalReferencedSourcesContext.Provider, { value: refsCtx, children: inner });
3525
- return /* @__PURE__ */ jsx20(LocalAttachmentsContext.Provider, { value: attachmentsCtx, children: withReferencedSources });
3728
+ const withReferencedSources = /* @__PURE__ */ jsx21(LocalReferencedSourcesContext.Provider, { value: refsCtx, children: inner });
3729
+ return /* @__PURE__ */ jsx21(LocalAttachmentsContext.Provider, { value: attachmentsCtx, children: withReferencedSources });
3526
3730
  };
3527
3731
  var PromptInputTextarea = ({
3528
3732
  onChange,
@@ -3600,7 +3804,7 @@ var PromptInputTextarea = ({
3600
3804
  } : {
3601
3805
  onChange
3602
3806
  };
3603
- return /* @__PURE__ */ jsx20(
3807
+ return /* @__PURE__ */ jsx21(
3604
3808
  InputGroupTextarea,
3605
3809
  {
3606
3810
  "data-boring-agent-part": "composer-input",
@@ -3627,13 +3831,13 @@ var PromptInputSubmit = ({
3627
3831
  ...props
3628
3832
  }) => {
3629
3833
  const isGenerating = status === "submitted" || status === "streaming";
3630
- let Icon = /* @__PURE__ */ jsx20(CornerDownLeftIcon, { className: "size-4" });
3834
+ let Icon = /* @__PURE__ */ jsx21(CornerDownLeftIcon, { className: "size-4" });
3631
3835
  if (status === "submitted") {
3632
- Icon = /* @__PURE__ */ jsx20(Spinner, {});
3836
+ Icon = /* @__PURE__ */ jsx21(Spinner, {});
3633
3837
  } else if (status === "streaming") {
3634
- Icon = /* @__PURE__ */ jsx20(SquareIcon, { className: "size-4" });
3838
+ Icon = /* @__PURE__ */ jsx21(SquareIcon, { className: "size-4" });
3635
3839
  } else if (status === "error") {
3636
- Icon = /* @__PURE__ */ jsx20(XIcon2, { className: "size-4" });
3840
+ Icon = /* @__PURE__ */ jsx21(XIcon2, { className: "size-4" });
3637
3841
  }
3638
3842
  const handleClick = useCallback11(
3639
3843
  (e) => {
@@ -3646,7 +3850,7 @@ var PromptInputSubmit = ({
3646
3850
  },
3647
3851
  [isGenerating, onStop, onClick]
3648
3852
  );
3649
- return /* @__PURE__ */ jsx20(
3853
+ return /* @__PURE__ */ jsx21(
3650
3854
  InputGroupButton2,
3651
3855
  {
3652
3856
  "aria-label": isGenerating ? "Stop" : "Submit",
@@ -3673,7 +3877,7 @@ import {
3673
3877
  XIcon as XIcon3
3674
3878
  } from "lucide-react";
3675
3879
  import { createContext as createContext6, useCallback as useCallback12, useContext as useContext6, useMemo as useMemo10 } from "react";
3676
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
3880
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3677
3881
  var mediaCategoryIcons = {
3678
3882
  audio: Music2Icon,
3679
3883
  document: FileTextIcon2,
@@ -3708,7 +3912,7 @@ var getAttachmentLabel = (data) => {
3708
3912
  const category = getMediaCategory(data);
3709
3913
  return data.filename || (category === "image" ? "Image" : "Attachment");
3710
3914
  };
3711
- var renderAttachmentImage = (url, filename, isGrid) => isGrid ? /* @__PURE__ */ jsx21(
3915
+ var renderAttachmentImage = (url, filename, isGrid) => isGrid ? /* @__PURE__ */ jsx22(
3712
3916
  "img",
3713
3917
  {
3714
3918
  alt: filename || "Image",
@@ -3717,7 +3921,7 @@ var renderAttachmentImage = (url, filename, isGrid) => isGrid ? /* @__PURE__ */
3717
3921
  src: url,
3718
3922
  width: 96
3719
3923
  }
3720
- ) : /* @__PURE__ */ jsx21(
3924
+ ) : /* @__PURE__ */ jsx22(
3721
3925
  "img",
3722
3926
  {
3723
3927
  alt: filename || "Image",
@@ -3744,7 +3948,7 @@ var Attachments = ({
3744
3948
  ...props
3745
3949
  }) => {
3746
3950
  const contextValue = useMemo10(() => ({ variant }), [variant]);
3747
- return /* @__PURE__ */ jsx21(AttachmentsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx21(
3951
+ return /* @__PURE__ */ jsx22(AttachmentsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx22(
3748
3952
  "div",
3749
3953
  {
3750
3954
  className: cn(
@@ -3771,7 +3975,7 @@ var Attachment = ({
3771
3975
  () => ({ data, mediaCategory, onRemove, variant }),
3772
3976
  [data, mediaCategory, onRemove, variant]
3773
3977
  );
3774
- return /* @__PURE__ */ jsx21(AttachmentContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx21(
3978
+ return /* @__PURE__ */ jsx22(AttachmentContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx22(
3775
3979
  "div",
3776
3980
  {
3777
3981
  className: cn(
@@ -3801,18 +4005,18 @@ var AttachmentPreview = ({
3801
4005
  }) => {
3802
4006
  const { data, mediaCategory, variant } = useAttachmentContext();
3803
4007
  const iconSize = variant === "inline" ? "size-3" : "size-4";
3804
- const renderIcon = (Icon) => /* @__PURE__ */ jsx21(Icon, { className: cn(iconSize, "text-muted-foreground") });
4008
+ const renderIcon = (Icon) => /* @__PURE__ */ jsx22(Icon, { className: cn(iconSize, "text-muted-foreground") });
3805
4009
  const renderContent = () => {
3806
4010
  if (mediaCategory === "image" && data.type === "file" && data.url) {
3807
4011
  return renderAttachmentImage(data.url, data.filename, variant === "grid");
3808
4012
  }
3809
4013
  if (mediaCategory === "video" && data.type === "file" && data.url) {
3810
- return /* @__PURE__ */ jsx21("video", { className: "size-full object-cover", muted: true, src: data.url });
4014
+ return /* @__PURE__ */ jsx22("video", { className: "size-full object-cover", muted: true, src: data.url });
3811
4015
  }
3812
4016
  const Icon = mediaCategoryIcons[mediaCategory];
3813
4017
  return fallbackIcon ?? renderIcon(Icon);
3814
4018
  };
3815
- return /* @__PURE__ */ jsx21(
4019
+ return /* @__PURE__ */ jsx22(
3816
4020
  "div",
3817
4021
  {
3818
4022
  className: cn(
@@ -3837,9 +4041,9 @@ var AttachmentInfo = ({
3837
4041
  if (variant === "grid") {
3838
4042
  return null;
3839
4043
  }
3840
- return /* @__PURE__ */ jsxs19("div", { className: cn("min-w-0 flex-1", className), ...props, children: [
3841
- /* @__PURE__ */ jsx21("span", { className: "block truncate", children: label }),
3842
- showMediaType && data.mediaType && /* @__PURE__ */ jsx21("span", { className: "block truncate text-muted-foreground text-xs", children: data.mediaType })
4044
+ return /* @__PURE__ */ jsxs20("div", { className: cn("min-w-0 flex-1", className), ...props, children: [
4045
+ /* @__PURE__ */ jsx22("span", { className: "block truncate", children: label }),
4046
+ showMediaType && data.mediaType && /* @__PURE__ */ jsx22("span", { className: "block truncate text-muted-foreground text-xs", children: data.mediaType })
3843
4047
  ] });
3844
4048
  };
3845
4049
  var AttachmentRemove = ({
@@ -3859,7 +4063,7 @@ var AttachmentRemove = ({
3859
4063
  if (!onRemove) {
3860
4064
  return null;
3861
4065
  }
3862
- return /* @__PURE__ */ jsxs19(
4066
+ return /* @__PURE__ */ jsxs20(
3863
4067
  Button9,
3864
4068
  {
3865
4069
  "aria-label": label,
@@ -3884,8 +4088,8 @@ var AttachmentRemove = ({
3884
4088
  variant: "ghost",
3885
4089
  ...props,
3886
4090
  children: [
3887
- children ?? /* @__PURE__ */ jsx21(XIcon3, {}),
3888
- /* @__PURE__ */ jsx21("span", { className: "sr-only", children: label })
4091
+ children ?? /* @__PURE__ */ jsx22(XIcon3, {}),
4092
+ /* @__PURE__ */ jsx22("span", { className: "sr-only", children: label })
3889
4093
  ]
3890
4094
  }
3891
4095
  );
@@ -4121,7 +4325,7 @@ ${content}
4121
4325
  }
4122
4326
 
4123
4327
  // src/front/hooks/useChatModelSelection.ts
4124
- import { useCallback as useCallback15, useEffect as useEffect13, useMemo as useMemo11, useRef as useRef12, useState as useState15 } from "react";
4328
+ import { useCallback as useCallback15, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef12, useState as useState15 } from "react";
4125
4329
 
4126
4330
  // src/front/chatPanelSettings.ts
4127
4331
  var STORAGE_MODEL_KEY = "boring-agent:composer:model";
@@ -4235,7 +4439,7 @@ function useChatModelSelection({
4235
4439
  () => initialModelState.userSelected
4236
4440
  );
4237
4441
  const userSelectedModelRef = useRef12(userSelectedModel);
4238
- useEffect13(() => {
4442
+ useEffect14(() => {
4239
4443
  userSelectedModelRef.current = userSelectedModel;
4240
4444
  }, [userSelectedModel]);
4241
4445
  const setModel = useCallback15((next) => {
@@ -4243,15 +4447,15 @@ function useChatModelSelection({
4243
4447
  setModelState(next);
4244
4448
  }, []);
4245
4449
  const [availableModels, setAvailableModels] = useState15([]);
4246
- useEffect13(() => {
4450
+ useEffect14(() => {
4247
4451
  if (!userSelectedModel || !model) return;
4248
4452
  writeStoredModelSelection(model);
4249
4453
  }, [model, userSelectedModel]);
4250
- useEffect13(() => {
4454
+ useEffect14(() => {
4251
4455
  if (userSelectedModelRef.current || !defaultModel) return;
4252
4456
  setModelState(defaultModel);
4253
4457
  }, [defaultModel]);
4254
- useEffect13(() => {
4458
+ useEffect14(() => {
4255
4459
  let aborted = false;
4256
4460
  fetch("/api/v1/agent/models", { headers: requestHeaders }).then((res) => res.ok ? res.json() : null).then((payload) => {
4257
4461
  if (aborted || !payload?.models) return;
@@ -4271,7 +4475,7 @@ function useChatModelSelection({
4271
4475
  aborted = true;
4272
4476
  };
4273
4477
  }, [requestHeaders]);
4274
- useEffect13(() => {
4478
+ useEffect14(() => {
4275
4479
  const onChange = (event) => {
4276
4480
  const next = parseModelSelection(event.detail);
4277
4481
  if (next) setModel(next);
@@ -4283,13 +4487,13 @@ function useChatModelSelection({
4283
4487
  }
4284
4488
 
4285
4489
  // src/front/hooks/useServerSkills.ts
4286
- import { useEffect as useEffect14, useState as useState16 } from "react";
4490
+ import { useEffect as useEffect15, useState as useState16 } from "react";
4287
4491
  function useServerSkills({
4288
4492
  registry,
4289
4493
  requestHeaders
4290
4494
  }) {
4291
4495
  const [skillsStamp, setSkillsStamp] = useState16(0);
4292
- useEffect14(() => {
4496
+ useEffect15(() => {
4293
4497
  let aborted = false;
4294
4498
  fetch("/api/v1/agent/skills", { headers: requestHeaders }).then((res) => res.ok ? res.json() : null).then((payload) => {
4295
4499
  if (aborted || !payload?.skills) return;
@@ -4312,17 +4516,17 @@ function useServerSkills({
4312
4516
  }
4313
4517
 
4314
4518
  // src/front/hooks/useThinkingSettings.ts
4315
- import { useEffect as useEffect15, useState as useState17 } from "react";
4519
+ import { useEffect as useEffect16, useState as useState17 } from "react";
4316
4520
  function useThinkingSettings(thinkingControl) {
4317
4521
  const [thinkingLevel, setThinkingLevel] = useState17(
4318
4522
  () => thinkingControl ? readStoredThinking() : DEFAULT_THINKING
4319
4523
  );
4320
4524
  const [showThoughts, setShowThoughts] = useState17(() => readStoredShowThoughts());
4321
- useEffect15(() => {
4525
+ useEffect16(() => {
4322
4526
  if (!thinkingControl) return;
4323
4527
  writeStoredThinking(thinkingLevel);
4324
4528
  }, [thinkingControl, thinkingLevel]);
4325
- useEffect15(() => {
4529
+ useEffect16(() => {
4326
4530
  writeStoredShowThoughts(showThoughts);
4327
4531
  }, [showThoughts]);
4328
4532
  return {
@@ -4334,10 +4538,10 @@ function useThinkingSettings(thinkingControl) {
4334
4538
  }
4335
4539
 
4336
4540
  // src/front/hooks/useAttachmentNotice.ts
4337
- import { useEffect as useEffect16, useState as useState18 } from "react";
4541
+ import { useEffect as useEffect17, useState as useState18 } from "react";
4338
4542
  function useAttachmentNotice(timeoutMs = 4e3) {
4339
4543
  const [attachmentNotice, setAttachmentNotice] = useState18(null);
4340
- useEffect16(() => {
4544
+ useEffect17(() => {
4341
4545
  if (!attachmentNotice) return;
4342
4546
  const timer = setTimeout(() => setAttachmentNotice(null), timeoutMs);
4343
4547
  return () => clearTimeout(timer);
@@ -4385,7 +4589,7 @@ function displayProviderLabel(provider) {
4385
4589
  }
4386
4590
 
4387
4591
  // src/front/chatPanelComposerControls.tsx
4388
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4592
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
4389
4593
  var composerActionClass = cn(
4390
4594
  "inline-flex h-8 items-center justify-center gap-1.5 rounded-md border-0 bg-transparent",
4391
4595
  "text-muted-foreground shadow-none transition",
@@ -4426,8 +4630,8 @@ function ModelSelect({
4426
4630
  groups.set(m.provider, list);
4427
4631
  }
4428
4632
  const [open, setOpen] = useState19(false);
4429
- return /* @__PURE__ */ jsxs20(Popover, { open, onOpenChange: disabled ? void 0 : setOpen, children: [
4430
- /* @__PURE__ */ jsx22(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs20(
4633
+ return /* @__PURE__ */ jsxs21(Popover, { open, onOpenChange: disabled ? void 0 : setOpen, children: [
4634
+ /* @__PURE__ */ jsx23(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs21(
4431
4635
  "button",
4432
4636
  {
4433
4637
  type: "button",
@@ -4441,30 +4645,30 @@ function ModelSelect({
4441
4645
  open && "bg-muted/60 text-foreground"
4442
4646
  ),
4443
4647
  children: [
4444
- /* @__PURE__ */ jsx22(BotIcon, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
4445
- /* @__PURE__ */ jsx22("span", { className: "min-w-0 truncate", children: triggerLabel }),
4446
- /* @__PURE__ */ jsx22(ChevronDownIcon5, { className: "h-3 w-3 shrink-0 text-muted-foreground/60", "aria-hidden": "true" })
4648
+ /* @__PURE__ */ jsx23(BotIcon, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
4649
+ /* @__PURE__ */ jsx23("span", { className: "min-w-0 truncate", children: triggerLabel }),
4650
+ /* @__PURE__ */ jsx23(ChevronDownIcon5, { className: "h-3 w-3 shrink-0 text-muted-foreground/60", "aria-hidden": "true" })
4447
4651
  ]
4448
4652
  }
4449
4653
  ) }),
4450
- /* @__PURE__ */ jsx22(
4654
+ /* @__PURE__ */ jsx23(
4451
4655
  PopoverContent,
4452
4656
  {
4453
4657
  align: "start",
4454
4658
  sideOffset: 6,
4455
4659
  "data-boring-agent": "",
4456
4660
  className: "w-[min(90vw,260px)] rounded-xl border-border/60 bg-popover p-1 shadow-xl",
4457
- children: /* @__PURE__ */ jsxs20(Command2, { children: [
4458
- menuOptions.length > 8 && /* @__PURE__ */ jsx22(
4661
+ children: /* @__PURE__ */ jsxs21(Command2, { children: [
4662
+ menuOptions.length > 8 && /* @__PURE__ */ jsx23(
4459
4663
  CommandInput2,
4460
4664
  {
4461
4665
  placeholder: "Search models\u2026",
4462
4666
  className: "h-8 border-0 text-[13px] focus:ring-0"
4463
4667
  }
4464
4668
  ),
4465
- /* @__PURE__ */ jsxs20(CommandList2, { className: "max-h-[300px] p-0.5", children: [
4466
- /* @__PURE__ */ jsx22(CommandEmpty2, { className: "py-4 text-center text-[13px] text-muted-foreground", children: "No models found" }),
4467
- [...groups.entries()].map(([provider, list]) => /* @__PURE__ */ jsx22(
4669
+ /* @__PURE__ */ jsxs21(CommandList2, { className: "max-h-[300px] p-0.5", children: [
4670
+ /* @__PURE__ */ jsx23(CommandEmpty2, { className: "py-4 text-center text-[13px] text-muted-foreground", children: "No models found" }),
4671
+ [...groups.entries()].map(([provider, list]) => /* @__PURE__ */ jsx23(
4468
4672
  CommandGroup2,
4469
4673
  {
4470
4674
  heading: displayProviderLabel(provider),
@@ -4472,7 +4676,7 @@ function ModelSelect({
4472
4676
  children: list.map((m) => {
4473
4677
  const key = encodeModelKey(m);
4474
4678
  const label = m.label || displayModelLabel(m.id);
4475
- return /* @__PURE__ */ jsxs20(
4679
+ return /* @__PURE__ */ jsxs21(
4476
4680
  CommandItem2,
4477
4681
  {
4478
4682
  value: `${label} ${m.id} ${displayProviderLabel(m.provider)}`,
@@ -4485,7 +4689,7 @@ function ModelSelect({
4485
4689
  key === currentKey && "bg-accent text-accent-foreground"
4486
4690
  ),
4487
4691
  children: [
4488
- /* @__PURE__ */ jsx22(
4692
+ /* @__PURE__ */ jsx23(
4489
4693
  CheckIcon2,
4490
4694
  {
4491
4695
  className: cn(
@@ -4494,8 +4698,8 @@ function ModelSelect({
4494
4698
  )
4495
4699
  }
4496
4700
  ),
4497
- /* @__PURE__ */ jsx22("span", { className: "truncate", children: label }),
4498
- /* @__PURE__ */ jsx22("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground/70", children: m.id })
4701
+ /* @__PURE__ */ jsx23("span", { className: "truncate", children: label }),
4702
+ /* @__PURE__ */ jsx23("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground/70", children: m.id })
4499
4703
  ]
4500
4704
  },
4501
4705
  key
@@ -4515,7 +4719,7 @@ function ThinkingSelect({
4515
4719
  onChange,
4516
4720
  disabled
4517
4721
  }) {
4518
- return /* @__PURE__ */ jsxs20(
4722
+ return /* @__PURE__ */ jsxs21(
4519
4723
  Select2,
4520
4724
  {
4521
4725
  value,
@@ -4524,7 +4728,7 @@ function ThinkingSelect({
4524
4728
  },
4525
4729
  disabled,
4526
4730
  children: [
4527
- /* @__PURE__ */ jsxs20(
4731
+ /* @__PURE__ */ jsxs21(
4528
4732
  SelectTrigger2,
4529
4733
  {
4530
4734
  "data-boring-agent-part": "thinking-select",
@@ -4533,14 +4737,14 @@ function ThinkingSelect({
4533
4737
  "aria-label": "Thinking level",
4534
4738
  "data-testid": "thinking-select",
4535
4739
  children: [
4536
- THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx22("span", { "data-value": level, hidden: true }, level)),
4537
- /* @__PURE__ */ jsx22(BrainIcon2, { className: "h-3.5 w-3.5" })
4740
+ THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx23("span", { "data-value": level, hidden: true }, level)),
4741
+ /* @__PURE__ */ jsx23(BrainIcon2, { className: "h-3.5 w-3.5" })
4538
4742
  ]
4539
4743
  }
4540
4744
  ),
4541
- /* @__PURE__ */ jsxs20(SelectContent2, { position: "popper", side: "top", align: "end", "data-boring-agent": "", className: "w-auto min-w-0 rounded-lg border-border/70 bg-popover p-2 shadow-2xl", children: [
4542
- /* @__PURE__ */ jsx22("div", { className: "px-1 pb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/70", children: "Think" }),
4543
- /* @__PURE__ */ jsx22("div", { className: "flex items-center gap-1", children: THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx22(
4745
+ /* @__PURE__ */ jsxs21(SelectContent2, { position: "popper", side: "top", align: "end", "data-boring-agent": "", className: "w-auto min-w-0 rounded-lg border-border/70 bg-popover p-2 shadow-2xl", children: [
4746
+ /* @__PURE__ */ jsx23("div", { className: "px-1 pb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/70", children: "Think" }),
4747
+ /* @__PURE__ */ jsx23("div", { className: "flex items-center gap-1", children: THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx23(
4544
4748
  SelectItem2,
4545
4749
  {
4546
4750
  value: level,
@@ -4559,7 +4763,7 @@ function ThoughtVisibilityButton({
4559
4763
  onToggle
4560
4764
  }) {
4561
4765
  const Icon = visible ? EyeIcon : EyeOffIcon;
4562
- return /* @__PURE__ */ jsx22(
4766
+ return /* @__PURE__ */ jsx23(
4563
4767
  IconButton,
4564
4768
  {
4565
4769
  type: "button",
@@ -4572,15 +4776,15 @@ function ThoughtVisibilityButton({
4572
4776
  "aria-pressed": visible,
4573
4777
  "aria-label": visible ? "Hide thoughts" : "Show thoughts",
4574
4778
  title: visible ? "Hide thoughts" : "Show thoughts",
4575
- children: /* @__PURE__ */ jsx22(Icon, { className: "h-3.5 w-3.5" })
4779
+ children: /* @__PURE__ */ jsx23(Icon, { className: "h-3.5 w-3.5" })
4576
4780
  }
4577
4781
  );
4578
4782
  }
4579
4783
 
4580
4784
  // src/front/chatPanelKbdHints.tsx
4581
- import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
4785
+ import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
4582
4786
  function KbdHints() {
4583
- return /* @__PURE__ */ jsxs21(
4787
+ return /* @__PURE__ */ jsxs22(
4584
4788
  "kbd",
4585
4789
  {
4586
4790
  "aria-hidden": "true",
@@ -4590,7 +4794,7 @@ function KbdHints() {
4590
4794
  "sm:inline-flex"
4591
4795
  ),
4592
4796
  children: [
4593
- /* @__PURE__ */ jsx23("span", { className: "not-mono text-[9px]", children: "\u21E7" }),
4797
+ /* @__PURE__ */ jsx24("span", { className: "not-mono text-[9px]", children: "\u21E7" }),
4594
4798
  "\u21B5"
4595
4799
  ]
4596
4800
  }
@@ -4598,7 +4802,7 @@ function KbdHints() {
4598
4802
  }
4599
4803
 
4600
4804
  // src/front/ChatPanel.tsx
4601
- import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
4805
+ import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
4602
4806
  var DebugDrawer2 = lazy(() => import("../DebugDrawer-MCYZ4AWZ.js").then((m) => ({ default: m.DebugDrawer })));
4603
4807
  function hasToolPart(message) {
4604
4808
  return (message.parts ?? []).some((part) => isToolUIPart2(part));
@@ -4741,6 +4945,7 @@ function ChatPanel(props) {
4741
4945
  sessionId,
4742
4946
  toolRenderers,
4743
4947
  extraCommands,
4948
+ hotReloadEnabled = true,
4744
4949
  onSessionReset,
4745
4950
  className,
4746
4951
  chrome = true,
@@ -4788,7 +4993,7 @@ function ChatPanel(props) {
4788
4993
  sessionId,
4789
4994
  requestHeaders
4790
4995
  });
4791
- useEffect17(() => {
4996
+ useEffect18(() => {
4792
4997
  piDataHandlerRef.current = handlePiData;
4793
4998
  }, [handlePiData]);
4794
4999
  const {
@@ -4805,7 +5010,7 @@ function ChatPanel(props) {
4805
5010
  requestHeaders,
4806
5011
  stop
4807
5012
  });
4808
- useEffect17(() => {
5013
+ useEffect18(() => {
4809
5014
  followUpDataHandlerRef.current = handleFollowUpData;
4810
5015
  }, [handleFollowUpData]);
4811
5016
  const mergedToolRenderers = mergeShadcnToolRenderers(toolRenderers);
@@ -4813,8 +5018,11 @@ function ChatPanel(props) {
4813
5018
  const primaryComposerBlocker = composerBlockers[0];
4814
5019
  const composerBlockerLabel = primaryComposerBlocker?.label ?? "Complete the pending workspace action to continue.";
4815
5020
  const registry = useMemo12(
4816
- () => createCommandRegistry([...builtinCommands, ...extraCommands ?? []]),
4817
- [extraCommands]
5021
+ () => {
5022
+ const effectiveBuiltins = hotReloadEnabled ? builtinCommands : builtinCommands.filter((cmd) => cmd.name !== "reload");
5023
+ return createCommandRegistry([...effectiveBuiltins, ...extraCommands ?? []]);
5024
+ },
5025
+ [extraCommands, hotReloadEnabled]
4818
5026
  );
4819
5027
  const skillsStamp = useServerSkills({ registry, requestHeaders });
4820
5028
  const allCommands = useMemo12(() => registry.list(), [registry, skillsStamp]);
@@ -4824,6 +5032,95 @@ function ChatPanel(props) {
4824
5032
  });
4825
5033
  const { thinkingLevel, setThinkingLevel, showThoughts, setShowThoughts } = useThinkingSettings(thinkingControl);
4826
5034
  const { attachmentNotice, setAttachmentNotice } = useAttachmentNotice();
5035
+ const callPluginReload = useCallback16(async () => {
5036
+ const res = await fetch("/api/v1/agent/reload", {
5037
+ method: "POST",
5038
+ headers: { ...requestHeaders ?? {}, "content-type": "application/json" },
5039
+ body: JSON.stringify({ sessionId })
5040
+ });
5041
+ if (!res.ok) {
5042
+ const payload2 = await res.json().catch(() => ({}));
5043
+ throw new Error(payload2.error || `reload failed (${res.status})`);
5044
+ }
5045
+ const payload = await res.json().catch(() => ({}));
5046
+ if (typeof window !== "undefined") {
5047
+ window.dispatchEvent(new CustomEvent(WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, { detail: payload }));
5048
+ }
5049
+ return {
5050
+ reloaded: Boolean(payload.reloaded),
5051
+ ...payload.restart_warnings && payload.restart_warnings.length > 0 ? { restartWarnings: payload.restart_warnings } : {},
5052
+ ...payload.diagnostics && payload.diagnostics.length > 0 ? { diagnostics: payload.diagnostics } : {}
5053
+ };
5054
+ }, [requestHeaders, sessionId]);
5055
+ const reloadAgentPlugins = useCallback16(async () => {
5056
+ try {
5057
+ const { reloaded, diagnostics } = await callPluginReload();
5058
+ const base = reloaded ? "Agent plugins reloaded." : "Agent plugins will reload on the next message.";
5059
+ return diagnostics && diagnostics.length > 0 ? `${base}
5060
+
5061
+ Warnings:
5062
+ ${formatPluginReloadDiagnostics(diagnostics)}` : base;
5063
+ } catch (err) {
5064
+ return err instanceof Error ? err.message : "Agent plugin reload failed.";
5065
+ }
5066
+ }, [callPluginReload]);
5067
+ const [pluginUpdateState, setPluginUpdateState] = useState20(null);
5068
+ const activeSessionRef = useRef13(sessionId);
5069
+ useEffect18(() => {
5070
+ activeSessionRef.current = sessionId;
5071
+ setPluginUpdateState(null);
5072
+ }, [sessionId]);
5073
+ useEffect18(() => {
5074
+ if (typeof window === "undefined") return;
5075
+ const onBrowserPluginReload = (event) => {
5076
+ const detail = event.detail;
5077
+ const parsed = parseBrowserPluginReloadDetail(detail);
5078
+ if (!parsed) return;
5079
+ setPluginUpdateState((prev) => {
5080
+ if (!prev) return prev;
5081
+ if (parsed.kind === "error") {
5082
+ return { kind: "error", message: parsed.message };
5083
+ }
5084
+ if (prev.kind === "error") return prev;
5085
+ const current = prev.kind === "success" ? prev : { kind: "success", reloaded: true };
5086
+ const existing = current.frontEvents ?? [];
5087
+ if (existing.some((item) => item.pluginId === parsed.diagnostic.pluginId && item.message === parsed.diagnostic.message)) {
5088
+ return current;
5089
+ }
5090
+ return {
5091
+ ...current,
5092
+ frontEvents: [...existing, parsed.diagnostic]
5093
+ };
5094
+ });
5095
+ };
5096
+ window.addEventListener(WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, onBrowserPluginReload);
5097
+ return () => window.removeEventListener(WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, onBrowserPluginReload);
5098
+ }, []);
5099
+ const runPluginUpdate = useCallback16(async () => {
5100
+ const capturedSession = activeSessionRef.current;
5101
+ setPluginUpdateState({ kind: "running" });
5102
+ try {
5103
+ const { reloaded, restartWarnings, diagnostics } = await callPluginReload();
5104
+ if (activeSessionRef.current !== capturedSession) return "Plugins updated.";
5105
+ setPluginUpdateState({
5106
+ kind: "success",
5107
+ reloaded,
5108
+ ...restartWarnings && restartWarnings.length > 0 ? { restartWarnings } : {},
5109
+ ...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
5110
+ });
5111
+ const base = reloaded ? "Plugins updated." : "Plugins will reload on the next message.";
5112
+ return diagnostics && diagnostics.length > 0 ? `${base}
5113
+
5114
+ Warnings:
5115
+ ${formatPluginReloadDiagnostics(diagnostics)}` : base;
5116
+ } catch (err) {
5117
+ const message = err instanceof Error ? err.message : "Plugin update failed.";
5118
+ if (activeSessionRef.current !== capturedSession) return `Plugin update failed: ${message}`;
5119
+ setPluginUpdateState({ kind: "error", message });
5120
+ return `Plugin update failed: ${message}`;
5121
+ }
5122
+ }, [callPluginReload]);
5123
+ const dismissPluginUpdate = useCallback16(() => setPluginUpdateState(null), []);
4827
5124
  const isStreaming = status === "submitted" || status === "streaming";
4828
5125
  const attachmentsDisabled = isStreaming || pendingMessages.length > 0;
4829
5126
  const displayMessages = useMemo12(() => {
@@ -4854,7 +5151,7 @@ function ChatPanel(props) {
4854
5151
  const handleInterrupt = useCallback16(() => {
4855
5152
  stop();
4856
5153
  }, [stop]);
4857
- useEffect17(() => {
5154
+ useEffect18(() => {
4858
5155
  const onKeyDown = (e) => {
4859
5156
  if (e.key !== "Escape" || !isStreaming) return;
4860
5157
  const tag = e.target?.tagName;
@@ -4919,16 +5216,11 @@ ${parsed.args}` : `skill: ${parsed.name}`;
4919
5216
  });
4920
5217
  void onSessionReset?.();
4921
5218
  },
4922
- setModel: (model2) => {
4923
- const next = parseModelSelection(model2);
4924
- if (!next) return false;
4925
- writeStoredModelSelection(next);
4926
- globalThis.dispatchEvent?.(new CustomEvent("boring:model-change", { detail: next }));
4927
- return true;
4928
- },
4929
- listCommands: () => registry.list()
5219
+ listCommands: () => registry.list(),
5220
+ reloadAgentPlugins,
5221
+ pluginUpdate: { run: runPluginUpdate }
4930
5222
  };
4931
- const result = cmd.handler(parsed.args, ctx);
5223
+ const result = await Promise.resolve(cmd.handler(parsed.args, ctx));
4932
5224
  if (typeof result === "string") {
4933
5225
  setMessages((prev) => [
4934
5226
  ...prev,
@@ -4951,7 +5243,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
4951
5243
  clearMentionedFiles();
4952
5244
  if (isStreaming && files.length > 0) {
4953
5245
  setAttachmentNotice("Attachments can be sent after the current response finishes.");
4954
- throw new Error("attachments_disabled_while_streaming");
5246
+ return;
4955
5247
  }
4956
5248
  if (isStreaming && capabilities.nativeFollowUp) {
4957
5249
  scrollToBottomRef.current();
@@ -4985,7 +5277,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
4985
5277
  }
4986
5278
  );
4987
5279
  }
4988
- return /* @__PURE__ */ jsx24(ArtifactOpenProvider, { onOpenArtifact, children: /* @__PURE__ */ jsxs22(
5280
+ return /* @__PURE__ */ jsx25(ArtifactOpenProvider, { onOpenArtifact, children: /* @__PURE__ */ jsxs23(
4989
5281
  "div",
4990
5282
  {
4991
5283
  "data-boring-agent": "",
@@ -4999,7 +5291,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
4999
5291
  role: "region",
5000
5292
  "aria-label": "Agent assistant",
5001
5293
  children: [
5002
- /* @__PURE__ */ jsx24("div", { className: "flex min-h-0 min-w-0 flex-col flex-1", children: /* @__PURE__ */ jsxs22(
5294
+ /* @__PURE__ */ jsx25("div", { className: "flex min-h-0 min-w-0 flex-col flex-1", children: /* @__PURE__ */ jsxs23(
5003
5295
  "div",
5004
5296
  {
5005
5297
  className: cn(
@@ -5007,7 +5299,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
5007
5299
  chrome && "mx-3 my-3 rounded-xl bg-[color:var(--surface-chat)] shadow-[0_1px_0_oklch(0_0_0/0.02),0_1px_2px_-1px_oklch(0_0_0/0.04),inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.6)]"
5008
5300
  ),
5009
5301
  children: [
5010
- /* @__PURE__ */ jsx24(
5302
+ /* @__PURE__ */ jsx25(
5011
5303
  "div",
5012
5304
  {
5013
5305
  className: cn(
@@ -5019,7 +5311,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
5019
5311
  "aria-busy": isStreaming || void 0,
5020
5312
  "aria-hidden": !isStreaming,
5021
5313
  "aria-label": isStreaming ? "Agent working" : void 0,
5022
- children: /* @__PURE__ */ jsx24(
5314
+ children: /* @__PURE__ */ jsx25(
5023
5315
  motion2.div,
5024
5316
  {
5025
5317
  className: "absolute inset-y-0 w-1/4 bg-gradient-to-r from-transparent via-[color:var(--accent)] to-transparent",
@@ -5030,7 +5322,7 @@ ${parsed.args}` : `skill: ${parsed.name}`;
5030
5322
  )
5031
5323
  }
5032
5324
  ),
5033
- /* @__PURE__ */ jsxs22(
5325
+ /* @__PURE__ */ jsxs23(
5034
5326
  Conversation,
5035
5327
  {
5036
5328
  className: "flex-1",
@@ -5040,11 +5332,11 @@ ${parsed.args}` : `skill: ${parsed.name}`;
5040
5332
  scrollToBottomRef.current = scrollToBottom;
5041
5333
  },
5042
5334
  children: [
5043
- /* @__PURE__ */ jsxs22(ConversationContent, { className: cn(
5335
+ /* @__PURE__ */ jsxs23(ConversationContent, { className: cn(
5044
5336
  "mx-auto flex w-full flex-col gap-6",
5045
5337
  chrome ? "max-w-3xl px-6 py-8" : "max-w-[680px] px-4 py-4"
5046
5338
  ), children: [
5047
- displayMessages.length === 0 && /* @__PURE__ */ jsx24(
5339
+ displayMessages.length === 0 && /* @__PURE__ */ jsx25(
5048
5340
  ChatEmptyState,
5049
5341
  {
5050
5342
  eyebrow: emptyState?.eyebrow,
@@ -5114,13 +5406,13 @@ ${reasoningPart.text}`;
5114
5406
  }, []);
5115
5407
  const isLastMessage = messageIndex === renderMessages.length - 1;
5116
5408
  const shouldReserveStreamingActions = isStreaming && role === "assistant" && isLastMessage;
5117
- return /* @__PURE__ */ jsxs22(
5409
+ return /* @__PURE__ */ jsxs23(
5118
5410
  Message,
5119
5411
  {
5120
5412
  from: role,
5121
5413
  className: "!max-w-full !gap-1.5",
5122
5414
  children: [
5123
- /* @__PURE__ */ jsxs22(
5415
+ /* @__PURE__ */ jsxs23(
5124
5416
  MessageContent,
5125
5417
  {
5126
5418
  className: cn(
@@ -5139,9 +5431,9 @@ ${reasoningPart.text}`;
5139
5431
  ),
5140
5432
  "data-waiting-follow-up": isWaitingFollowUp ? "true" : void 0,
5141
5433
  children: [
5142
- isWaitingFollowUp && /* @__PURE__ */ jsxs22("div", { className: "mb-1 flex items-center justify-between gap-2 text-[10px] font-medium not-italic uppercase tracking-[0.16em] text-muted-foreground/70", children: [
5143
- /* @__PURE__ */ jsx24("span", { children: "Waiting\u2026" }),
5144
- /* @__PURE__ */ jsx24(
5434
+ isWaitingFollowUp && /* @__PURE__ */ jsxs23("div", { className: "mb-1 flex items-center justify-between gap-2 text-[10px] font-medium not-italic uppercase tracking-[0.16em] text-muted-foreground/70", children: [
5435
+ /* @__PURE__ */ jsx25("span", { children: "Waiting\u2026" }),
5436
+ /* @__PURE__ */ jsx25(
5145
5437
  IconButton2,
5146
5438
  {
5147
5439
  type: "button",
@@ -5151,11 +5443,11 @@ ${reasoningPart.text}`;
5151
5443
  className: "-mr-1 size-5 shrink-0 text-muted-foreground/70 hover:bg-muted hover:text-foreground",
5152
5444
  "aria-label": "Delete queued message",
5153
5445
  title: "Delete queued message",
5154
- children: /* @__PURE__ */ jsx24(XIcon4, { className: "size-3", "aria-hidden": "true" })
5446
+ children: /* @__PURE__ */ jsx25(XIcon4, { className: "size-3", "aria-hidden": "true" })
5155
5447
  }
5156
5448
  )
5157
5449
  ] }),
5158
- fileParts.length > 0 && /* @__PURE__ */ jsx24(
5450
+ fileParts.length > 0 && /* @__PURE__ */ jsx25(
5159
5451
  Attachments,
5160
5452
  {
5161
5453
  variant: "list",
@@ -5167,36 +5459,36 @@ ${reasoningPart.text}`;
5167
5459
  // messages (no bubble) keep the bordered chip.
5168
5460
  role === "user" ? "[&>div]:border-0 [&>div]:bg-transparent [&>div]:px-0 [&>div]:py-1 [&>div:hover]:bg-transparent" : void 0
5169
5461
  ),
5170
- children: fileParts.map((file, idx) => /* @__PURE__ */ jsxs22(Attachment, { data: { ...file, id: `file-${message.id}-${idx}` }, children: [
5171
- /* @__PURE__ */ jsx24(AttachmentPreview, { className: "size-10 shrink-0 rounded-[var(--radius-md)]" }),
5172
- /* @__PURE__ */ jsx24(AttachmentInfo, { className: "min-w-0 flex-1" })
5462
+ children: fileParts.map((file, idx) => /* @__PURE__ */ jsxs23(Attachment, { data: { ...file, id: `file-${message.id}-${idx}` }, children: [
5463
+ /* @__PURE__ */ jsx25(AttachmentPreview, { className: "size-10 shrink-0 rounded-[var(--radius-md)]" }),
5464
+ /* @__PURE__ */ jsx25(AttachmentInfo, { className: "min-w-0 flex-1" })
5173
5465
  ] }, `file-${message.id}-${idx}`))
5174
5466
  }
5175
5467
  ),
5176
5468
  finalParts.map((item, index) => {
5177
5469
  if (item.kind === "reasoning") {
5178
5470
  if (!showThoughts) return null;
5179
- return /* @__PURE__ */ jsxs22(
5471
+ return /* @__PURE__ */ jsxs23(
5180
5472
  Reasoning,
5181
5473
  {
5182
5474
  isStreaming: item.state === "streaming",
5183
5475
  defaultOpen: item.state === "streaming",
5184
5476
  children: [
5185
- /* @__PURE__ */ jsx24(
5477
+ /* @__PURE__ */ jsx25(
5186
5478
  ReasoningTrigger,
5187
5479
  {
5188
5480
  className: "mb-1 w-fit rounded-[var(--radius-sm)] px-0 py-0 !text-xs !font-normal !text-muted-foreground/75 hover:bg-transparent hover:!text-muted-foreground/75 [&_svg]:!text-muted-foreground/75",
5189
- getThinkingMessage: (streaming) => /* @__PURE__ */ jsx24("span", { children: streaming ? "thinking" : "thoughts" })
5481
+ getThinkingMessage: (streaming) => /* @__PURE__ */ jsx25("span", { children: streaming ? "thinking" : "thoughts" })
5190
5482
  }
5191
5483
  ),
5192
- /* @__PURE__ */ jsx24(ReasoningContent, { children: item.text })
5484
+ /* @__PURE__ */ jsx25(ReasoningContent, { children: item.text })
5193
5485
  ]
5194
5486
  },
5195
5487
  `reasoning-${item.key}`
5196
5488
  );
5197
5489
  }
5198
5490
  if (item.kind === "tool-group") {
5199
- return /* @__PURE__ */ jsx24(
5491
+ return /* @__PURE__ */ jsx25(
5200
5492
  ToolCallGroup,
5201
5493
  {
5202
5494
  tools: item.tools,
@@ -5207,7 +5499,7 @@ ${reasoningPart.text}`;
5207
5499
  }
5208
5500
  const { part } = item;
5209
5501
  if (isTextPart(part)) {
5210
- return /* @__PURE__ */ jsx24(
5502
+ return /* @__PURE__ */ jsx25(
5211
5503
  MessageResponse,
5212
5504
  {
5213
5505
  className: cn(
@@ -5244,7 +5536,7 @@ ${reasoningPart.text}`;
5244
5536
  ]
5245
5537
  }
5246
5538
  ),
5247
- role === "assistant" && (textParts.length > 0 || shouldReserveStreamingActions) && /* @__PURE__ */ jsx24(
5539
+ role === "assistant" && (textParts.length > 0 || shouldReserveStreamingActions) && /* @__PURE__ */ jsx25(
5248
5540
  MessageActionsBar,
5249
5541
  {
5250
5542
  text: textParts.map((p) => p.text).join("\n\n"),
@@ -5269,17 +5561,17 @@ ${reasoningPart.text}`;
5269
5561
  (() => {
5270
5562
  if (!error) return null;
5271
5563
  const friendly = friendlyError(error);
5272
- return /* @__PURE__ */ jsx24(Message, { from: "assistant", className: "!max-w-full", children: /* @__PURE__ */ jsx24(MessageContent, { className: "rounded-xl border border-destructive/40 bg-destructive/10 px-4 py-3", children: /* @__PURE__ */ jsxs22("div", { role: "alert", className: "flex items-start gap-3 text-sm text-destructive", children: [
5273
- /* @__PURE__ */ jsx24("div", { className: "mt-0.5 shrink-0", children: /* @__PURE__ */ jsxs22("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
5274
- /* @__PURE__ */ jsx24("circle", { cx: "12", cy: "12", r: "10" }),
5275
- /* @__PURE__ */ jsx24("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
5276
- /* @__PURE__ */ jsx24("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
5564
+ return /* @__PURE__ */ jsx25(Message, { from: "assistant", className: "!max-w-full", children: /* @__PURE__ */ jsx25(MessageContent, { className: "rounded-xl border border-destructive/40 bg-destructive/10 px-4 py-3", children: /* @__PURE__ */ jsxs23("div", { role: "alert", className: "flex items-start gap-3 text-sm text-destructive", children: [
5565
+ /* @__PURE__ */ jsx25("div", { className: "mt-0.5 shrink-0", children: /* @__PURE__ */ jsxs23("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
5566
+ /* @__PURE__ */ jsx25("circle", { cx: "12", cy: "12", r: "10" }),
5567
+ /* @__PURE__ */ jsx25("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
5568
+ /* @__PURE__ */ jsx25("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
5277
5569
  ] }) }),
5278
- /* @__PURE__ */ jsxs22("div", { className: "min-w-0 flex-1", children: [
5279
- /* @__PURE__ */ jsx24("div", { className: "font-medium", children: friendly.title }),
5280
- friendly.detail && /* @__PURE__ */ jsx24("div", { className: "mt-1 text-xs text-destructive/80", children: friendly.detail })
5570
+ /* @__PURE__ */ jsxs23("div", { className: "min-w-0 flex-1", children: [
5571
+ /* @__PURE__ */ jsx25("div", { className: "font-medium", children: friendly.title }),
5572
+ friendly.detail && /* @__PURE__ */ jsx25("div", { className: "mt-1 text-xs text-destructive/80", children: friendly.detail })
5281
5573
  ] }),
5282
- /* @__PURE__ */ jsx24(
5574
+ /* @__PURE__ */ jsx25(
5283
5575
  IconButton2,
5284
5576
  {
5285
5577
  type: "button",
@@ -5288,21 +5580,21 @@ ${reasoningPart.text}`;
5288
5580
  onClick: () => clearError(),
5289
5581
  className: "shrink-0 text-destructive/70 hover:bg-destructive/15 hover:text-destructive",
5290
5582
  "aria-label": "Dismiss",
5291
- children: /* @__PURE__ */ jsxs22("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
5292
- /* @__PURE__ */ jsx24("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
5293
- /* @__PURE__ */ jsx24("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
5583
+ children: /* @__PURE__ */ jsxs23("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
5584
+ /* @__PURE__ */ jsx25("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
5585
+ /* @__PURE__ */ jsx25("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
5294
5586
  ] })
5295
5587
  }
5296
5588
  )
5297
5589
  ] }) }) });
5298
5590
  })()
5299
5591
  ] }),
5300
- /* @__PURE__ */ jsx24(ConversationScrollButton, {})
5592
+ /* @__PURE__ */ jsx25(ConversationScrollButton, {})
5301
5593
  ]
5302
5594
  }
5303
5595
  ),
5304
- /* @__PURE__ */ jsxs22("div", { className: cn(chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-3 pt-1"), children: [
5305
- /* @__PURE__ */ jsx24(
5596
+ /* @__PURE__ */ jsxs23("div", { className: cn(chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-3 pt-1"), children: [
5597
+ /* @__PURE__ */ jsx25(
5306
5598
  "div",
5307
5599
  {
5308
5600
  className: cn(
@@ -5310,7 +5602,7 @@ ${reasoningPart.text}`;
5310
5602
  chrome ? "max-w-3xl" : "max-w-[680px]",
5311
5603
  isStreaming ? "mb-2 max-h-8" : "max-h-0"
5312
5604
  ),
5313
- children: /* @__PURE__ */ jsxs22(
5605
+ children: /* @__PURE__ */ jsxs23(
5314
5606
  "div",
5315
5607
  {
5316
5608
  "data-testid": "chat-working",
@@ -5320,7 +5612,7 @@ ${reasoningPart.text}`;
5320
5612
  "inline-flex items-center gap-2 rounded-full border border-border/50 bg-background/85 px-2.5 py-1 text-[12px] text-muted-foreground/75 shadow-sm backdrop-blur"
5321
5613
  ),
5322
5614
  children: [
5323
- /* @__PURE__ */ jsx24(
5615
+ /* @__PURE__ */ jsx25(
5324
5616
  motion2.span,
5325
5617
  {
5326
5618
  "aria-hidden": "true",
@@ -5329,13 +5621,13 @@ ${reasoningPart.text}`;
5329
5621
  transition: { duration: 1.2, repeat: Infinity, ease: "easeInOut" }
5330
5622
  }
5331
5623
  ),
5332
- /* @__PURE__ */ jsx24("span", { children: "Working\u2026" })
5624
+ /* @__PURE__ */ jsx25("span", { children: "Working\u2026" })
5333
5625
  ]
5334
5626
  }
5335
5627
  )
5336
5628
  }
5337
5629
  ),
5338
- composerBlocked && /* @__PURE__ */ jsxs22(
5630
+ composerBlocked && /* @__PURE__ */ jsxs23(
5339
5631
  "div",
5340
5632
  {
5341
5633
  role: "status",
@@ -5345,8 +5637,8 @@ ${reasoningPart.text}`;
5345
5637
  "px-3 py-2 text-xs text-foreground"
5346
5638
  ),
5347
5639
  children: [
5348
- /* @__PURE__ */ jsx24("span", { children: composerBlockerLabel }),
5349
- primaryComposerBlocker?.actions?.map((action) => /* @__PURE__ */ jsx24(
5640
+ /* @__PURE__ */ jsx25("span", { children: composerBlockerLabel }),
5641
+ primaryComposerBlocker?.actions?.map((action) => /* @__PURE__ */ jsx25(
5350
5642
  "button",
5351
5643
  {
5352
5644
  type: "button",
@@ -5359,7 +5651,15 @@ ${reasoningPart.text}`;
5359
5651
  ]
5360
5652
  }
5361
5653
  ),
5362
- attachmentNotice && /* @__PURE__ */ jsx24(
5654
+ hotReloadEnabled && /* @__PURE__ */ jsx25(
5655
+ PluginUpdateStatus,
5656
+ {
5657
+ state: pluginUpdateState,
5658
+ onDismiss: dismissPluginUpdate,
5659
+ onRetry: runPluginUpdate
5660
+ }
5661
+ ),
5662
+ attachmentNotice && /* @__PURE__ */ jsx25(
5363
5663
  "div",
5364
5664
  {
5365
5665
  role: "status",
@@ -5371,8 +5671,8 @@ ${reasoningPart.text}`;
5371
5671
  children: attachmentNotice
5372
5672
  }
5373
5673
  ),
5374
- /* @__PURE__ */ jsxs22("div", { className: cn("mx-auto w-full", chrome ? "max-w-3xl" : "max-w-[680px]"), children: [
5375
- mentionState && /* @__PURE__ */ jsx24(
5674
+ /* @__PURE__ */ jsxs23("div", { className: cn("mx-auto w-full", chrome ? "max-w-3xl" : "max-w-[680px]"), children: [
5675
+ mentionState && /* @__PURE__ */ jsx25(
5376
5676
  MentionPicker,
5377
5677
  {
5378
5678
  mention: mentionState,
@@ -5380,7 +5680,7 @@ ${reasoningPart.text}`;
5380
5680
  onDismiss: dismissMention
5381
5681
  }
5382
5682
  ),
5383
- slashQuery !== null && /* @__PURE__ */ jsx24(
5683
+ slashQuery !== null && /* @__PURE__ */ jsx25(
5384
5684
  SlashCommandPicker,
5385
5685
  {
5386
5686
  query: slashQuery,
@@ -5390,7 +5690,7 @@ ${reasoningPart.text}`;
5390
5690
  }
5391
5691
  )
5392
5692
  ] }),
5393
- /* @__PURE__ */ jsx24(
5693
+ /* @__PURE__ */ jsx25(
5394
5694
  "div",
5395
5695
  {
5396
5696
  className: cn(
@@ -5418,7 +5718,7 @@ ${reasoningPart.text}`;
5418
5718
  "[&_[data-slot=input-group]]:dark:!bg-transparent [&_[data-slot=input-group]]:!ring-0",
5419
5719
  "[&_[data-slot=input-group]]:has-[:focus]:!ring-0"
5420
5720
  ),
5421
- children: /* @__PURE__ */ jsxs22(
5721
+ children: /* @__PURE__ */ jsxs23(
5422
5722
  PromptInput,
5423
5723
  {
5424
5724
  "data-boring-state": status,
@@ -5440,8 +5740,8 @@ ${reasoningPart.text}`;
5440
5740
  }
5441
5741
  },
5442
5742
  children: [
5443
- /* @__PURE__ */ jsx24(AttachmentsList, {}),
5444
- /* @__PURE__ */ jsx24(
5743
+ /* @__PURE__ */ jsx25(AttachmentsList, {}),
5744
+ /* @__PURE__ */ jsx25(
5445
5745
  PromptInputTextarea,
5446
5746
  {
5447
5747
  placeholder: composerBlocked ? composerBlockerLabel : "Ask anything\u2026",
@@ -5456,7 +5756,7 @@ ${reasoningPart.text}`;
5456
5756
  )
5457
5757
  }
5458
5758
  ),
5459
- /* @__PURE__ */ jsxs22(
5759
+ /* @__PURE__ */ jsxs23(
5460
5760
  PromptInputFooter,
5461
5761
  {
5462
5762
  className: cn(
@@ -5464,9 +5764,9 @@ ${reasoningPart.text}`;
5464
5764
  "px-2 pb-2 pt-1.5"
5465
5765
  ),
5466
5766
  children: [
5467
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-1", children: [
5468
- /* @__PURE__ */ jsx24(AttachmentButton, { disabled: attachmentsDisabled }),
5469
- /* @__PURE__ */ jsx24(
5767
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
5768
+ /* @__PURE__ */ jsx25(AttachmentButton, { disabled: attachmentsDisabled }),
5769
+ /* @__PURE__ */ jsx25(
5470
5770
  ModelSelect,
5471
5771
  {
5472
5772
  value: model,
@@ -5476,9 +5776,9 @@ ${reasoningPart.text}`;
5476
5776
  }
5477
5777
  )
5478
5778
  ] }),
5479
- /* @__PURE__ */ jsxs22("div", { className: "ml-auto flex items-center gap-1", children: [
5480
- thinkingControl && /* @__PURE__ */ jsxs22(Fragment7, { children: [
5481
- /* @__PURE__ */ jsx24(
5779
+ /* @__PURE__ */ jsxs23("div", { className: "ml-auto flex items-center gap-1", children: [
5780
+ thinkingControl && /* @__PURE__ */ jsxs23(Fragment7, { children: [
5781
+ /* @__PURE__ */ jsx25(
5482
5782
  ThinkingSelect,
5483
5783
  {
5484
5784
  value: thinkingLevel,
@@ -5486,7 +5786,7 @@ ${reasoningPart.text}`;
5486
5786
  disabled: isStreaming
5487
5787
  }
5488
5788
  ),
5489
- /* @__PURE__ */ jsx24(
5789
+ /* @__PURE__ */ jsx25(
5490
5790
  ThoughtVisibilityButton,
5491
5791
  {
5492
5792
  visible: showThoughts,
@@ -5494,9 +5794,9 @@ ${reasoningPart.text}`;
5494
5794
  }
5495
5795
  )
5496
5796
  ] }),
5497
- /* @__PURE__ */ jsxs22("div", { className: "ml-1 flex items-center gap-1.5", children: [
5498
- /* @__PURE__ */ jsx24(KbdHints, {}),
5499
- /* @__PURE__ */ jsx24(
5797
+ /* @__PURE__ */ jsxs23("div", { className: "ml-1 flex items-center gap-1.5", children: [
5798
+ /* @__PURE__ */ jsx25(KbdHints, {}),
5799
+ /* @__PURE__ */ jsx25(
5500
5800
  PromptInputSubmit,
5501
5801
  {
5502
5802
  status,
@@ -5534,7 +5834,7 @@ ${reasoningPart.text}`;
5534
5834
  ]
5535
5835
  }
5536
5836
  ) }),
5537
- debug && /* @__PURE__ */ jsx24(Suspense, { fallback: null, children: /* @__PURE__ */ jsx24(
5837
+ debug && /* @__PURE__ */ jsx25(Suspense, { fallback: null, children: /* @__PURE__ */ jsx25(
5538
5838
  DebugDrawer2,
5539
5839
  {
5540
5840
  sessionId,
@@ -5550,7 +5850,7 @@ ${reasoningPart.text}`;
5550
5850
  }
5551
5851
  function AttachmentButton({ disabled }) {
5552
5852
  const attachments = usePromptInputAttachments();
5553
- return /* @__PURE__ */ jsx24(
5853
+ return /* @__PURE__ */ jsx25(
5554
5854
  IconButton2,
5555
5855
  {
5556
5856
  type: "button",
@@ -5563,20 +5863,20 @@ function AttachmentButton({ disabled }) {
5563
5863
  className: cn(composerActionClass, "w-8"),
5564
5864
  "aria-label": "Attach files",
5565
5865
  title: disabled ? "Attachments are available after the current response finishes." : "Attach files",
5566
- children: /* @__PURE__ */ jsx24(PaperclipIcon2, { className: "h-4 w-4" })
5866
+ children: /* @__PURE__ */ jsx25(PaperclipIcon2, { className: "h-4 w-4" })
5567
5867
  }
5568
5868
  );
5569
5869
  }
5570
5870
  function AttachmentsList() {
5571
5871
  const attachments = usePromptInputAttachments();
5572
5872
  if (attachments.files.length === 0) return null;
5573
- return /* @__PURE__ */ jsx24(
5873
+ return /* @__PURE__ */ jsx25(
5574
5874
  Attachments,
5575
5875
  {
5576
5876
  "data-align": "block-start",
5577
5877
  variant: "inline",
5578
5878
  className: "w-full flex-wrap items-center justify-start gap-2 px-5 pt-3 pb-1",
5579
- children: attachments.files.map((file) => /* @__PURE__ */ jsxs22(
5879
+ children: attachments.files.map((file) => /* @__PURE__ */ jsxs23(
5580
5880
  Attachment,
5581
5881
  {
5582
5882
  data: file,
@@ -5589,23 +5889,23 @@ function AttachmentsList() {
5589
5889
  file.status === "error" && "!border-destructive/50 !bg-destructive/10"
5590
5890
  ),
5591
5891
  children: [
5592
- /* @__PURE__ */ jsxs22("div", { className: "relative shrink-0", children: [
5593
- /* @__PURE__ */ jsx24(
5892
+ /* @__PURE__ */ jsxs23("div", { className: "relative shrink-0", children: [
5893
+ /* @__PURE__ */ jsx25(
5594
5894
  AttachmentPreview,
5595
5895
  {
5596
5896
  className: "!size-7 overflow-hidden !rounded-full bg-background/60"
5597
5897
  }
5598
5898
  ),
5599
- file.status === "uploading" && /* @__PURE__ */ jsx24("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-background/70", children: /* @__PURE__ */ jsx24(Loader2, { className: "size-3.5 animate-spin text-muted-foreground" }) }),
5600
- file.status === "error" && /* @__PURE__ */ jsx24("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-destructive/20", children: /* @__PURE__ */ jsx24(AlertCircleIcon, { className: "size-3.5 text-destructive" }) })
5899
+ file.status === "uploading" && /* @__PURE__ */ jsx25("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-background/70", children: /* @__PURE__ */ jsx25(Loader2, { className: "size-3.5 animate-spin text-muted-foreground" }) }),
5900
+ file.status === "error" && /* @__PURE__ */ jsx25("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-destructive/20", children: /* @__PURE__ */ jsx25(AlertCircleIcon, { className: "size-3.5 text-destructive" }) })
5601
5901
  ] }),
5602
- /* @__PURE__ */ jsx24(
5902
+ /* @__PURE__ */ jsx25(
5603
5903
  AttachmentInfo,
5604
5904
  {
5605
5905
  className: "min-w-0 !max-w-[180px] truncate text-[13px] font-medium"
5606
5906
  }
5607
5907
  ),
5608
- /* @__PURE__ */ jsx24(
5908
+ /* @__PURE__ */ jsx25(
5609
5909
  AttachmentRemove,
5610
5910
  {
5611
5911
  className: cn(
@@ -5622,6 +5922,49 @@ function AttachmentsList() {
5622
5922
  }
5623
5923
  );
5624
5924
  }
5925
+ function parseBrowserPluginReloadDetail(detail) {
5926
+ if (!detail || typeof detail !== "object") return null;
5927
+ const record = detail;
5928
+ if (typeof record.type !== "string") return null;
5929
+ const pluginId = typeof record.id === "string" ? record.id : void 0;
5930
+ const revision = typeof record.revision === "number" ? `revision ${record.revision}` : "updated";
5931
+ switch (record.type) {
5932
+ case "boring.plugin.load":
5933
+ return {
5934
+ kind: "success",
5935
+ diagnostic: {
5936
+ source: "browser front reload",
5937
+ ...pluginId ? { pluginId } : {},
5938
+ message: `front module loaded (${revision})`
5939
+ }
5940
+ };
5941
+ case "boring.plugin.unload":
5942
+ return {
5943
+ kind: "success",
5944
+ diagnostic: {
5945
+ source: "browser front reload",
5946
+ ...pluginId ? { pluginId } : {},
5947
+ message: `front module unloaded (${revision})`
5948
+ }
5949
+ };
5950
+ case "boring.plugin.error":
5951
+ case "boring.plugin.front-error": {
5952
+ const message = typeof record.message === "string" && record.message.length > 0 ? record.message : "browser front module failed to load";
5953
+ return {
5954
+ kind: "error",
5955
+ message: `Plugin front failed${pluginId ? ` (${pluginId})` : ""}: ${message}. Previous live version was kept.`
5956
+ };
5957
+ }
5958
+ default:
5959
+ return null;
5960
+ }
5961
+ }
5962
+ function formatPluginReloadDiagnostics(diagnostics) {
5963
+ return diagnostics.map((diagnostic) => {
5964
+ const source = diagnostic.pluginId ?? diagnostic.source ?? "plugin";
5965
+ return `${source}: ${diagnostic.message ?? "reload diagnostic"}`;
5966
+ }).join("\n");
5967
+ }
5625
5968
  function regenerateLastTurn({
5626
5969
  messages,
5627
5970
  setMessages,
@@ -5705,7 +6048,7 @@ function MessageActionsBar({
5705
6048
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[color:var(--accent)]/40"
5706
6049
  );
5707
6050
  const hiddenActionProps = visible ? {} : { tabIndex: -1 };
5708
- return /* @__PURE__ */ jsxs22(
6051
+ return /* @__PURE__ */ jsxs23(
5709
6052
  "div",
5710
6053
  {
5711
6054
  "aria-hidden": !visible,
@@ -5717,8 +6060,8 @@ function MessageActionsBar({
5717
6060
  visible ? "opacity-100" : "pointer-events-none opacity-0"
5718
6061
  ),
5719
6062
  children: [
5720
- /* @__PURE__ */ jsx24(Button10, { type: "button", variant: "ghost", size: "xs", onClick: handleCopy, className: iconActionBtnClass, "aria-label": copied ? "Copied" : "Copy message", title: copied ? "Copied" : "Copy", ...hiddenActionProps, children: copied ? /* @__PURE__ */ jsx24(CheckIcon3, { className: "h-3.5 w-3.5 text-[color:var(--accent)]" }) : /* @__PURE__ */ jsx24(CopyIcon3, { className: "h-3.5 w-3.5" }) }),
5721
- canRegenerate && /* @__PURE__ */ jsx24(Button10, { type: "button", variant: "ghost", size: "xs", onClick: visible ? onRegenerate : void 0, className: iconActionBtnClass, "aria-label": "Regenerate", title: "Regenerate", ...hiddenActionProps, children: /* @__PURE__ */ jsx24(RefreshCwIcon, { className: "h-3.5 w-3.5" }) })
6063
+ /* @__PURE__ */ jsx25(Button10, { type: "button", variant: "ghost", size: "xs", onClick: handleCopy, className: iconActionBtnClass, "aria-label": copied ? "Copied" : "Copy message", title: copied ? "Copied" : "Copy", ...hiddenActionProps, children: copied ? /* @__PURE__ */ jsx25(CheckIcon3, { className: "h-3.5 w-3.5 text-[color:var(--accent)]" }) : /* @__PURE__ */ jsx25(CopyIcon3, { className: "h-3.5 w-3.5" }) }),
6064
+ canRegenerate && /* @__PURE__ */ jsx25(Button10, { type: "button", variant: "ghost", size: "xs", onClick: visible ? onRegenerate : void 0, className: iconActionBtnClass, "aria-label": "Regenerate", title: "Regenerate", ...hiddenActionProps, children: /* @__PURE__ */ jsx25(RefreshCwIcon, { className: "h-3.5 w-3.5" }) })
5722
6065
  ]
5723
6066
  }
5724
6067
  );
@@ -5760,7 +6103,7 @@ function getAgentCommands(options = {}) {
5760
6103
  }
5761
6104
 
5762
6105
  // src/front/hooks/useSessions.ts
5763
- import { useState as useState21, useEffect as useEffect18, useCallback as useCallback17, useRef as useRef14 } from "react";
6106
+ import { useState as useState21, useEffect as useEffect19, useCallback as useCallback17, useRef as useRef14 } from "react";
5764
6107
  var API_BASE = "/api/v1/agent/sessions";
5765
6108
  var STORAGE_KEY = "boring-agent:activeSessionId";
5766
6109
  function readPersistedId(storageKey) {
@@ -5818,7 +6161,7 @@ function useSessions(opts = {}) {
5818
6161
  }
5819
6162
  }
5820
6163
  }, [requestHeaders, storageKey]);
5821
- useEffect18(() => {
6164
+ useEffect19(() => {
5822
6165
  void refresh();
5823
6166
  }, [refresh]);
5824
6167
  const create = useCallback17(