@industry-theme/xterm-terminal-panel 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,5 @@
1
1
  import "./styles.css";
2
2
  // src/components/ThemedTerminal.tsx
3
- import {
4
- DATA_TYPES as DATA_TYPES2,
5
- sanitizePath,
6
- useDropZone
7
- } from "@principal-ade/panel-framework-core";
8
3
  import { FitAddon } from "@xterm/addon-fit";
9
4
  import { SearchAddon } from "@xterm/addon-search";
10
5
  import { WebLinksAddon } from "@xterm/addon-web-links";
@@ -20,7 +15,7 @@ import {
20
15
  } from "lucide-react";
21
16
  import {
22
17
  forwardRef,
23
- useCallback,
18
+ useCallback as useCallback2,
24
19
  useEffect,
25
20
  useImperativeHandle,
26
21
  useRef,
@@ -28,6 +23,132 @@ import {
28
23
  } from "react";
29
24
  import "@xterm/xterm/css/xterm.css";
30
25
 
26
+ // src/hooks/useTerminalDropZone.tsx
27
+ import {
28
+ DATA_TYPES,
29
+ sanitizePath,
30
+ useDropZone
31
+ } from "@principal-ade/panel-framework-core";
32
+ import { useCallback } from "react";
33
+ import { jsx } from "react/jsx-runtime";
34
+ var FocusDelayMs = 10;
35
+ function getDroppedImageFiles(e) {
36
+ const list = e.dataTransfer?.files;
37
+ if (!list || list.length === 0) return [];
38
+ return Array.from(list).filter((f) => f.type.startsWith("image/"));
39
+ }
40
+ function useTerminalDropZone({
41
+ insertText,
42
+ focus,
43
+ onFilesDropped
44
+ }) {
45
+ const handleDroppedContent = useCallback(
46
+ (content) => {
47
+ insertText(content);
48
+ if (focus) {
49
+ setTimeout(focus, FocusDelayMs);
50
+ }
51
+ },
52
+ [insertText, focus]
53
+ );
54
+ const handleDroppedImageFiles = useCallback(
55
+ async (files) => {
56
+ if (!onFilesDropped || files.length === 0) return;
57
+ try {
58
+ const payload = await Promise.all(
59
+ files.map(async (file) => ({
60
+ name: file.name || "pasted-image.png",
61
+ mimeType: file.type || "image/png",
62
+ data: new Uint8Array(await file.arrayBuffer())
63
+ }))
64
+ );
65
+ const paths = await onFilesDropped(payload);
66
+ if (paths && paths.length > 0) {
67
+ handleDroppedContent(`${paths.map(sanitizePath).join(" ")} `);
68
+ }
69
+ } catch (err) {
70
+ console.error("[useTerminalDropZone] Failed to handle dropped files:", err);
71
+ }
72
+ },
73
+ [onFilesDropped, handleDroppedContent]
74
+ );
75
+ const {
76
+ isDragOver,
77
+ onDrop: handlePanelDrop,
78
+ ...dropZoneProps
79
+ } = useDropZone({
80
+ handlers: [
81
+ {
82
+ dataType: [DATA_TYPES.FILE_PATH, DATA_TYPES.DIRECTORY_PATH],
83
+ onDrop: (data) => {
84
+ const safePath = sanitizePath(data.primaryData);
85
+ handleDroppedContent(safePath);
86
+ }
87
+ },
88
+ {
89
+ dataType: DATA_TYPES.TEXT_SELECTION,
90
+ onDrop: (data) => {
91
+ handleDroppedContent(data.primaryData);
92
+ }
93
+ }
94
+ ],
95
+ onPlainTextDrop: (text, e) => {
96
+ if (getDroppedImageFiles(e).length > 0) return;
97
+ handleDroppedContent(text);
98
+ },
99
+ showVisualFeedback: true
100
+ });
101
+ const handleDrop = useCallback(
102
+ (e) => {
103
+ const imageFiles = getDroppedImageFiles(e);
104
+ handlePanelDrop(e);
105
+ if (imageFiles.length > 0) {
106
+ void handleDroppedImageFiles(imageFiles);
107
+ }
108
+ },
109
+ [handlePanelDrop, handleDroppedImageFiles]
110
+ );
111
+ return {
112
+ isDragOver,
113
+ dropZoneProps,
114
+ handleDrop,
115
+ dropIndicator: isDragOver ? /* @__PURE__ */ jsx(TerminalDropIndicator, {}) : null
116
+ };
117
+ }
118
+ function TerminalDropIndicator() {
119
+ return /* @__PURE__ */ jsx(
120
+ "div",
121
+ {
122
+ style: {
123
+ position: "absolute",
124
+ inset: 0,
125
+ background: "rgba(59, 130, 246, 0.1)",
126
+ border: "2px dashed #3b82f6",
127
+ borderRadius: "4px",
128
+ display: "flex",
129
+ alignItems: "center",
130
+ justifyContent: "center",
131
+ pointerEvents: "none",
132
+ zIndex: 1e3
133
+ },
134
+ children: /* @__PURE__ */ jsx(
135
+ "div",
136
+ {
137
+ style: {
138
+ padding: "8px 16px",
139
+ background: "#3b82f6",
140
+ color: "white",
141
+ borderRadius: "4px",
142
+ fontSize: "13px",
143
+ fontWeight: 500
144
+ },
145
+ children: "Drop to insert"
146
+ }
147
+ )
148
+ }
149
+ );
150
+ }
151
+
31
152
  // src/telemetry.ts
32
153
  import {
33
154
  trace,
@@ -38,7 +159,7 @@ import {
38
159
  // package.json
39
160
  var package_default = {
40
161
  name: "@industry-theme/xterm-terminal-panel",
41
- version: "0.9.5",
162
+ version: "0.9.6",
42
163
  description: "Industry-themed xterm.js terminal components with panel framework integration",
43
164
  type: "module",
44
165
  sideEffects: [
@@ -249,13 +370,13 @@ function getTerminalCSSVariables(theme) {
249
370
  // src/components/SelectionDragChip.tsx
250
371
  import {
251
372
  createDragPreview,
252
- DATA_TYPES,
373
+ DATA_TYPES as DATA_TYPES2,
253
374
  DRAG_ACTIONS,
254
375
  PANEL_TYPES,
255
376
  useDraggable
256
377
  } from "@principal-ade/panel-framework-core";
257
378
  import { GripVertical } from "lucide-react";
258
- import { jsx, jsxs } from "react/jsx-runtime";
379
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
259
380
  function SelectionDragChip({
260
381
  text,
261
382
  x,
@@ -269,7 +390,7 @@ function SelectionDragChip({
269
390
  }) {
270
391
  const snippet = text.length > 80 ? `${text.slice(0, 77)}\u2026` : text;
271
392
  const { isDragging, ...dragProps } = useDraggable({
272
- dataType: DATA_TYPES.TEXT_SELECTION,
393
+ dataType: DATA_TYPES2.TEXT_SELECTION,
273
394
  primaryData: text,
274
395
  sourcePanel,
275
396
  suggestedActions: [DRAG_ACTIONS.INSERT_CONTENT, DRAG_ACTIONS.REFERENCE],
@@ -319,7 +440,7 @@ function SelectionDragChip({
319
440
  title: `Drag selection \u2014 ${label}`,
320
441
  "aria-label": `Drag selected terminal text \u2014 ${label}`,
321
442
  children: [
322
- /* @__PURE__ */ jsx(GripVertical, { size: 13, color: theme.colors.textSecondary }),
443
+ /* @__PURE__ */ jsx2(GripVertical, { size: 13, color: theme.colors.textSecondary }),
323
444
  label
324
445
  ]
325
446
  }
@@ -327,7 +448,7 @@ function SelectionDragChip({
327
448
  }
328
449
 
329
450
  // src/components/WorkingOverlay.tsx
330
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
451
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
331
452
  var WorkingOverlay = ({
332
453
  theme,
333
454
  message = "Agent working...",
@@ -370,7 +491,7 @@ var WorkingOverlay = ({
370
491
  marginBottom: "8px"
371
492
  },
372
493
  children: [
373
- /* @__PURE__ */ jsx2(
494
+ /* @__PURE__ */ jsx3(
374
495
  "div",
375
496
  {
376
497
  className: "working-dot",
@@ -383,7 +504,7 @@ var WorkingOverlay = ({
383
504
  }
384
505
  }
385
506
  ),
386
- /* @__PURE__ */ jsx2(
507
+ /* @__PURE__ */ jsx3(
387
508
  "div",
388
509
  {
389
510
  className: "working-dot",
@@ -396,7 +517,7 @@ var WorkingOverlay = ({
396
517
  }
397
518
  }
398
519
  ),
399
- /* @__PURE__ */ jsx2(
520
+ /* @__PURE__ */ jsx3(
400
521
  "div",
401
522
  {
402
523
  className: "working-dot",
@@ -412,7 +533,7 @@ var WorkingOverlay = ({
412
533
  ]
413
534
  }
414
535
  ),
415
- /* @__PURE__ */ jsx2(
536
+ /* @__PURE__ */ jsx3(
416
537
  "div",
417
538
  {
418
539
  style: {
@@ -424,7 +545,7 @@ var WorkingOverlay = ({
424
545
  children: message
425
546
  }
426
547
  ),
427
- subtitle && /* @__PURE__ */ jsx2(
548
+ subtitle && /* @__PURE__ */ jsx3(
428
549
  "div",
429
550
  {
430
551
  style: {
@@ -441,7 +562,7 @@ var WorkingOverlay = ({
441
562
  };
442
563
 
443
564
  // src/components/ThemedTerminal.tsx
444
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
565
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
445
566
  var DEBUG_RESIZE = true;
446
567
  var ThemedTerminal = forwardRef(
447
568
  ({
@@ -530,7 +651,7 @@ var ThemedTerminal = forwardRef(
530
651
  setIsClosingOverlay(true);
531
652
  }
532
653
  }, [isWorking]);
533
- const handleOverlayCloseComplete = useCallback(() => {
654
+ const handleOverlayCloseComplete = useCallback2(() => {
534
655
  setShowWorkingOverlay(false);
535
656
  setIsClosingOverlay(false);
536
657
  const tracer = getTracer();
@@ -543,7 +664,7 @@ var ThemedTerminal = forwardRef(
543
664
  span.setStatus({ code: SpanStatusCode.OK });
544
665
  span.end();
545
666
  }, []);
546
- const trackActivity = useCallback(() => {
667
+ const trackActivity = useCallback2(() => {
547
668
  if (!activityDetection) return;
548
669
  if (activityTimeoutRef.current) {
549
670
  clearTimeout(activityTimeoutRef.current);
@@ -599,78 +720,20 @@ var ThemedTerminal = forwardRef(
599
720
  }
600
721
  };
601
722
  }, []);
602
- const handleDroppedContent = useCallback(
723
+ const insertDroppedText = useCallback2(
603
724
  (content) => {
604
- if (terminal) {
605
- terminal.paste(content);
606
- setTimeout(() => {
607
- terminal.focus();
608
- }, 10);
609
- }
725
+ terminal?.paste(content);
610
726
  },
611
727
  [terminal]
612
728
  );
613
- const getDroppedImageFiles = useCallback(
614
- (e) => {
615
- const list = e.dataTransfer?.files;
616
- if (!list || list.length === 0) return [];
617
- return Array.from(list).filter((f) => f.type.startsWith("image/"));
618
- },
619
- []
620
- );
621
- const handleDroppedImageFiles = useCallback(
622
- async (files) => {
623
- if (!onFilesDropped || files.length === 0) return;
624
- try {
625
- const payload = await Promise.all(
626
- files.map(async (file) => ({
627
- name: file.name || "pasted-image.png",
628
- mimeType: file.type || "image/png",
629
- data: new Uint8Array(await file.arrayBuffer())
630
- }))
631
- );
632
- const paths = await onFilesDropped(payload);
633
- if (paths && paths.length > 0) {
634
- handleDroppedContent(`${paths.map(sanitizePath).join(" ")} `);
635
- }
636
- } catch (err) {
637
- console.error("[ThemedTerminal] Failed to handle dropped files:", err);
638
- }
639
- },
640
- [onFilesDropped, handleDroppedContent]
641
- );
642
- const { isDragOver, onDrop: handlePanelDrop, ...dropZoneProps } = useDropZone({
643
- handlers: [
644
- {
645
- dataType: [DATA_TYPES2.FILE_PATH, DATA_TYPES2.DIRECTORY_PATH],
646
- onDrop: (data) => {
647
- const safePath = sanitizePath(data.primaryData);
648
- handleDroppedContent(safePath);
649
- }
650
- },
651
- {
652
- dataType: DATA_TYPES2.TEXT_SELECTION,
653
- onDrop: (data) => {
654
- handleDroppedContent(data.primaryData);
655
- }
656
- }
657
- ],
658
- onPlainTextDrop: (text, e) => {
659
- if (getDroppedImageFiles(e).length > 0) return;
660
- handleDroppedContent(text);
661
- },
662
- showVisualFeedback: true
729
+ const focusTerminal = useCallback2(() => {
730
+ terminal?.focus();
731
+ }, [terminal]);
732
+ const { dropZoneProps, handleDrop, dropIndicator } = useTerminalDropZone({
733
+ insertText: insertDroppedText,
734
+ focus: focusTerminal,
735
+ onFilesDropped
663
736
  });
664
- const handleDrop = useCallback(
665
- (e) => {
666
- const imageFiles = getDroppedImageFiles(e);
667
- handlePanelDrop(e);
668
- if (imageFiles.length > 0) {
669
- void handleDroppedImageFiles(imageFiles);
670
- }
671
- },
672
- [handlePanelDrop, getDroppedImageFiles, handleDroppedImageFiles]
673
- );
674
737
  useEffect(() => {
675
738
  isVisibleRef.current = isVisible;
676
739
  }, [isVisible]);
@@ -1192,8 +1255,8 @@ var ThemedTerminal = forwardRef(
1192
1255
  },
1193
1256
  children: [
1194
1257
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1195
- /* @__PURE__ */ jsx3(TerminalIcon, { size: 16, color: theme.colors.text }),
1196
- /* @__PURE__ */ jsx3(
1258
+ /* @__PURE__ */ jsx4(TerminalIcon, { size: 16, color: theme.colors.text }),
1259
+ /* @__PURE__ */ jsx4(
1197
1260
  "span",
1198
1261
  {
1199
1262
  style: {
@@ -1204,7 +1267,7 @@ var ThemedTerminal = forwardRef(
1204
1267
  children: headerTitle
1205
1268
  }
1206
1269
  ),
1207
- headerSubtitle && /* @__PURE__ */ jsx3(
1270
+ headerSubtitle && /* @__PURE__ */ jsx4(
1208
1271
  "span",
1209
1272
  {
1210
1273
  style: {
@@ -1215,7 +1278,7 @@ var ThemedTerminal = forwardRef(
1215
1278
  }
1216
1279
  ),
1217
1280
  headerBadge && /* @__PURE__ */ jsxs3(Fragment, { children: [
1218
- /* @__PURE__ */ jsx3(
1281
+ /* @__PURE__ */ jsx4(
1219
1282
  "span",
1220
1283
  {
1221
1284
  style: {
@@ -1225,7 +1288,7 @@ var ThemedTerminal = forwardRef(
1225
1288
  children: "\u2022"
1226
1289
  }
1227
1290
  ),
1228
- /* @__PURE__ */ jsx3(
1291
+ /* @__PURE__ */ jsx4(
1229
1292
  "span",
1230
1293
  {
1231
1294
  style: {
@@ -1238,7 +1301,7 @@ var ThemedTerminal = forwardRef(
1238
1301
  ] })
1239
1302
  ] }),
1240
1303
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
1241
- onPopOut && /* @__PURE__ */ jsx3(
1304
+ onPopOut && /* @__PURE__ */ jsx4(
1242
1305
  "button",
1243
1306
  {
1244
1307
  type: "button",
@@ -1265,10 +1328,10 @@ var ThemedTerminal = forwardRef(
1265
1328
  e.currentTarget.style.color = theme.colors.textSecondary;
1266
1329
  },
1267
1330
  title: "Open terminal in new window",
1268
- children: /* @__PURE__ */ jsx3(ExternalLink, { size: 16 })
1331
+ children: /* @__PURE__ */ jsx4(ExternalLink, { size: 16 })
1269
1332
  }
1270
1333
  ),
1271
- onClose && /* @__PURE__ */ jsx3(
1334
+ onClose && /* @__PURE__ */ jsx4(
1272
1335
  "button",
1273
1336
  {
1274
1337
  type: "button",
@@ -1295,10 +1358,10 @@ var ThemedTerminal = forwardRef(
1295
1358
  e.currentTarget.style.color = theme.colors.textSecondary;
1296
1359
  },
1297
1360
  title: "Hide terminal (keeps session running)",
1298
- children: /* @__PURE__ */ jsx3(ChevronDown, { size: 16 })
1361
+ children: /* @__PURE__ */ jsx4(ChevronDown, { size: 16 })
1299
1362
  }
1300
1363
  ),
1301
- onDestroy && /* @__PURE__ */ jsx3(
1364
+ onDestroy && /* @__PURE__ */ jsx4(
1302
1365
  "button",
1303
1366
  {
1304
1367
  type: "button",
@@ -1325,7 +1388,7 @@ var ThemedTerminal = forwardRef(
1325
1388
  e.currentTarget.style.color = theme.colors.textSecondary;
1326
1389
  },
1327
1390
  title: "Close terminal session (terminate process)",
1328
- children: /* @__PURE__ */ jsx3(X, { size: 16 })
1391
+ children: /* @__PURE__ */ jsx4(X, { size: 16 })
1329
1392
  }
1330
1393
  )
1331
1394
  ] })
@@ -1348,38 +1411,8 @@ var ThemedTerminal = forwardRef(
1348
1411
  minHeight: 0
1349
1412
  },
1350
1413
  children: [
1351
- isDragOver && /* @__PURE__ */ jsx3(
1352
- "div",
1353
- {
1354
- style: {
1355
- position: "absolute",
1356
- inset: 0,
1357
- background: "rgba(59, 130, 246, 0.1)",
1358
- border: "2px dashed #3b82f6",
1359
- borderRadius: "4px",
1360
- display: "flex",
1361
- alignItems: "center",
1362
- justifyContent: "center",
1363
- pointerEvents: "none",
1364
- zIndex: 1e3
1365
- },
1366
- children: /* @__PURE__ */ jsx3(
1367
- "div",
1368
- {
1369
- style: {
1370
- padding: "8px 16px",
1371
- background: "#3b82f6",
1372
- color: "white",
1373
- borderRadius: "4px",
1374
- fontSize: "13px",
1375
- fontWeight: 500
1376
- },
1377
- children: "Drop to insert"
1378
- }
1379
- )
1380
- }
1381
- ),
1382
- enableSelectionDrag && selectionDrag && /* @__PURE__ */ jsx3(
1414
+ dropIndicator,
1415
+ enableSelectionDrag && selectionDrag && /* @__PURE__ */ jsx4(
1383
1416
  SelectionDragChip,
1384
1417
  {
1385
1418
  text: selectionDrag.text,
@@ -1416,7 +1449,7 @@ var ThemedTerminal = forwardRef(
1416
1449
  animation: "copy-feedback-in 0.15s ease-out"
1417
1450
  },
1418
1451
  children: [
1419
- /* @__PURE__ */ jsx3(Check, { size: 14, strokeWidth: 3 }),
1452
+ /* @__PURE__ */ jsx4(Check, { size: 14, strokeWidth: 3 }),
1420
1453
  "Copied!"
1421
1454
  ]
1422
1455
  }
@@ -1441,8 +1474,8 @@ var ThemedTerminal = forwardRef(
1441
1474
  zIndex: 10
1442
1475
  },
1443
1476
  children: [
1444
- /* @__PURE__ */ jsx3(Monitor, { size: 48, color: theme.colors.textSecondary }),
1445
- /* @__PURE__ */ jsx3(
1477
+ /* @__PURE__ */ jsx4(Monitor, { size: 48, color: theme.colors.textSecondary }),
1478
+ /* @__PURE__ */ jsx4(
1446
1479
  "div",
1447
1480
  {
1448
1481
  style: {
@@ -1454,7 +1487,7 @@ var ThemedTerminal = forwardRef(
1454
1487
  children: overlayState.message
1455
1488
  }
1456
1489
  ),
1457
- overlayState.subtitle && /* @__PURE__ */ jsx3(
1490
+ overlayState.subtitle && /* @__PURE__ */ jsx4(
1458
1491
  "div",
1459
1492
  {
1460
1493
  style: {
@@ -1466,7 +1499,7 @@ var ThemedTerminal = forwardRef(
1466
1499
  children: overlayState.subtitle
1467
1500
  }
1468
1501
  ),
1469
- overlayState.actions && overlayState.actions.length > 0 && /* @__PURE__ */ jsx3(
1502
+ overlayState.actions && overlayState.actions.length > 0 && /* @__PURE__ */ jsx4(
1470
1503
  "div",
1471
1504
  {
1472
1505
  style: {
@@ -1519,7 +1552,7 @@ var ThemedTerminal = forwardRef(
1519
1552
  ]
1520
1553
  }
1521
1554
  ),
1522
- showWorkingOverlay && !overlayState && /* @__PURE__ */ jsx3(
1555
+ showWorkingOverlay && !overlayState && /* @__PURE__ */ jsx4(
1523
1556
  WorkingOverlay,
1524
1557
  {
1525
1558
  theme,
@@ -1542,16 +1575,16 @@ ThemedTerminal.displayName = "ThemedTerminal";
1542
1575
  // src/components/ThemedTerminalWithProvider.tsx
1543
1576
  import { useTheme } from "@principal-ade/industry-theme";
1544
1577
  import { forwardRef as forwardRef2 } from "react";
1545
- import { jsx as jsx4 } from "react/jsx-runtime";
1578
+ import { jsx as jsx5 } from "react/jsx-runtime";
1546
1579
  var ThemedTerminalWithProvider = forwardRef2((props, ref) => {
1547
1580
  const { theme } = useTheme();
1548
- return /* @__PURE__ */ jsx4(ThemedTerminal, { ref, theme, ...props });
1581
+ return /* @__PURE__ */ jsx5(ThemedTerminal, { ref, theme, ...props });
1549
1582
  });
1550
1583
  ThemedTerminalWithProvider.displayName = "ThemedTerminalWithProvider";
1551
1584
 
1552
1585
  // src/components/ProgramStatusBadge.tsx
1553
1586
  import { useTheme as useTheme2 } from "@principal-ade/industry-theme";
1554
- import { jsx as jsx5 } from "react/jsx-runtime";
1587
+ import { jsx as jsx6 } from "react/jsx-runtime";
1555
1588
  var blockedColor = (kind, colors) => {
1556
1589
  switch (kind) {
1557
1590
  case "auth":
@@ -1572,7 +1605,7 @@ var formatProgramStatusRecord = (record) => {
1572
1605
  if (record.title) parts.push(`title=${record.title}`);
1573
1606
  return parts.join("; ");
1574
1607
  };
1575
- var WaveBars = ({ color, animate }) => /* @__PURE__ */ jsx5("div", { style: { display: "flex", gap: 1, alignItems: "center", height: 12 }, children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx5(
1608
+ var WaveBars = ({ color, animate }) => /* @__PURE__ */ jsx6("div", { style: { display: "flex", gap: 1, alignItems: "center", height: 12 }, children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx6(
1576
1609
  "div",
1577
1610
  {
1578
1611
  style: {
@@ -1594,17 +1627,17 @@ var ProgramStatusBadge = ({
1594
1627
  const { theme } = useTheme2();
1595
1628
  switch (record.state) {
1596
1629
  case "working":
1597
- return /* @__PURE__ */ jsx5(
1630
+ return /* @__PURE__ */ jsx6(
1598
1631
  "span",
1599
1632
  {
1600
1633
  title: formatProgramStatusRecord(record),
1601
1634
  style: { display: "flex", alignItems: "center" },
1602
- children: /* @__PURE__ */ jsx5(WaveBars, { color: theme.colors.primary, animate })
1635
+ children: /* @__PURE__ */ jsx6(WaveBars, { color: theme.colors.primary, animate })
1603
1636
  }
1604
1637
  );
1605
1638
  case "blocked": {
1606
1639
  const color = blockedColor(record.kind, theme.colors);
1607
- return /* @__PURE__ */ jsx5(
1640
+ return /* @__PURE__ */ jsx6(
1608
1641
  "span",
1609
1642
  {
1610
1643
  title: formatProgramStatusRecord(record),
@@ -1628,7 +1661,7 @@ var ProgramStatusBadge = ({
1628
1661
  );
1629
1662
  }
1630
1663
  case "done":
1631
- return /* @__PURE__ */ jsx5(
1664
+ return /* @__PURE__ */ jsx6(
1632
1665
  "span",
1633
1666
  {
1634
1667
  title: formatProgramStatusRecord(record),
@@ -1642,7 +1675,7 @@ var ProgramStatusBadge = ({
1642
1675
  }
1643
1676
  );
1644
1677
  case "error":
1645
- return /* @__PURE__ */ jsx5(
1678
+ return /* @__PURE__ */ jsx6(
1646
1679
  "span",
1647
1680
  {
1648
1681
  title: formatProgramStatusRecord(record),
@@ -1664,7 +1697,7 @@ ProgramStatusBadge.displayName = "ProgramStatusBadge";
1664
1697
 
1665
1698
  // src/renderer/XtermRenderer.tsx
1666
1699
  import { forwardRef as forwardRef3, useImperativeHandle as useImperativeHandle2, useRef as useRef2 } from "react";
1667
- import { jsx as jsx6 } from "react/jsx-runtime";
1700
+ import { jsx as jsx7 } from "react/jsx-runtime";
1668
1701
  var XtermRenderer = forwardRef3(
1669
1702
  (props, ref) => {
1670
1703
  const {
@@ -1703,7 +1736,7 @@ var XtermRenderer = forwardRef3(
1703
1736
  }),
1704
1737
  []
1705
1738
  );
1706
- return /* @__PURE__ */ jsx6(
1739
+ return /* @__PURE__ */ jsx7(
1707
1740
  ThemedTerminalWithProvider,
1708
1741
  {
1709
1742
  ref: innerRef,
@@ -1724,7 +1757,7 @@ XtermRenderer.displayName = "XtermRenderer";
1724
1757
  // src/renderer/GhosttyRenderer.tsx
1725
1758
  import { useTheme as useTheme3 } from "@principal-ade/industry-theme";
1726
1759
  import { FitAddon as FitAddon2, Terminal as Terminal2 } from "ghostty-web";
1727
- import { forwardRef as forwardRef4, useCallback as useCallback2, useEffect as useEffect2, useImperativeHandle as useImperativeHandle3, useRef as useRef3 } from "react";
1760
+ import { forwardRef as forwardRef4, useCallback as useCallback3, useEffect as useEffect2, useImperativeHandle as useImperativeHandle3, useRef as useRef3 } from "react";
1728
1761
 
1729
1762
  // src/renderer/ghosttyInit.ts
1730
1763
  import { init } from "ghostty-web";
@@ -1737,7 +1770,7 @@ function ensureGhostty() {
1737
1770
  }
1738
1771
 
1739
1772
  // src/renderer/GhosttyRenderer.tsx
1740
- import { jsx as jsx7 } from "react/jsx-runtime";
1773
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1741
1774
  var DEFAULT_FONT_STACK = "JetBrains Mono, Menlo, Monaco, monospace";
1742
1775
  var GhosttyRenderer = forwardRef4(
1743
1776
  (props, ref) => {
@@ -1755,9 +1788,10 @@ var GhosttyRenderer = forwardRef4(
1755
1788
  cursorBlink = true,
1756
1789
  cursorStyle,
1757
1790
  fontFamily,
1758
- fontSize = 14
1791
+ fontSize = 14,
1792
+ onFilesDropped
1759
1793
  // Accepted but intentionally not implemented yet:
1760
- // onLinkClick, onFilesDropped
1794
+ // onLinkClick
1761
1795
  } = props;
1762
1796
  const { theme } = useTheme3();
1763
1797
  const containerRef = useRef3(null);
@@ -1769,7 +1803,7 @@ var GhosttyRenderer = forwardRef4(
1769
1803
  autoFocusRef.current = autoFocus;
1770
1804
  const callbacks = useRef3({ onData, onResize, onReady, onScrollPositionChange, onShortcut });
1771
1805
  callbacks.current = { onData, onResize, onReady, onScrollPositionChange, onShortcut };
1772
- const readScrollPosition = useCallback2(() => {
1806
+ const readScrollPosition = useCallback3(() => {
1773
1807
  const term = termRef.current;
1774
1808
  if (!term) return { isAtTop: false, isAtBottom: true };
1775
1809
  const viewportY = typeof term.viewportY === "number" ? term.viewportY : 0;
@@ -1779,7 +1813,7 @@ var GhosttyRenderer = forwardRef4(
1779
1813
  isAtTop: scrollbackLength <= 0 || viewportY >= scrollbackLength - 0.5
1780
1814
  };
1781
1815
  }, []);
1782
- const fit = useCallback2(() => {
1816
+ const fit = useCallback3(() => {
1783
1817
  const term = termRef.current;
1784
1818
  const addon = fitRef.current;
1785
1819
  if (!term || !addon) return;
@@ -1794,7 +1828,7 @@ var GhosttyRenderer = forwardRef4(
1794
1828
  }
1795
1829
  }
1796
1830
  }, []);
1797
- const write = useCallback2((data) => {
1831
+ const write = useCallback3((data) => {
1798
1832
  const term = termRef.current;
1799
1833
  if (term) {
1800
1834
  term.write(data);
@@ -1849,6 +1883,16 @@ var GhosttyRenderer = forwardRef4(
1849
1883
  }
1850
1884
  return false;
1851
1885
  });
1886
+ term.attachCustomWheelEventHandler((event) => {
1887
+ if (term.hasMouseTracking() && !event.shiftKey) return false;
1888
+ if (term.buffer.active.type !== "alternate") return false;
1889
+ const appCursor = term.getMode(1, false);
1890
+ const scrollingUp = event.deltaY < 0;
1891
+ const lines = Math.min(Math.abs(Math.round(event.deltaY / 33)), 5);
1892
+ const sequence = appCursor ? scrollingUp ? "\x1BOA" : "\x1BOB" : scrollingUp ? "\x1B[A" : "\x1B[B";
1893
+ for (let i = 0; i < lines; i += 1) callbacks.current.onData?.(sequence);
1894
+ return true;
1895
+ });
1852
1896
  fit();
1853
1897
  if (pendingWritesRef.current.length > 0) {
1854
1898
  const pending = pendingWritesRef.current;
@@ -1893,6 +1937,17 @@ var GhosttyRenderer = forwardRef4(
1893
1937
  useEffect2(() => {
1894
1938
  if (isVisible && autoFocus) termRef.current?.focus();
1895
1939
  }, [isVisible, autoFocus]);
1940
+ const insertDroppedText = useCallback3((content) => {
1941
+ termRef.current?.paste(content);
1942
+ }, []);
1943
+ const focusTerminal = useCallback3(() => {
1944
+ termRef.current?.focus();
1945
+ }, []);
1946
+ const { dropZoneProps, handleDrop, dropIndicator } = useTerminalDropZone({
1947
+ insertText: insertDroppedText,
1948
+ focus: focusTerminal,
1949
+ onFilesDropped
1950
+ });
1896
1951
  useImperativeHandle3(
1897
1952
  ref,
1898
1953
  () => ({
@@ -1913,20 +1968,30 @@ var GhosttyRenderer = forwardRef4(
1913
1968
  }),
1914
1969
  [fit, readScrollPosition, write]
1915
1970
  );
1916
- return /* @__PURE__ */ jsx7(
1917
- "div",
1918
- {
1919
- ref: containerRef,
1920
- style: {
1921
- width: "100%",
1922
- height: "100%",
1923
- backgroundColor: transparent ? "transparent" : theme.colors.background,
1924
- // ghostty-web's open() sets contenteditable on this container, so the
1925
- // browser would draw its own text caret on top of the canvas cursor.
1926
- // Hide it — the terminal renders its own cursor.
1927
- caretColor: "transparent"
1928
- }
1929
- }
1971
+ return (
1972
+ // ghostty-web owns its container's children (open() appends the canvas and
1973
+ // a hidden textarea), so the drop indicator lives on a wrapper instead of
1974
+ // inside it — no imperative/React child conflicts.
1975
+ /* @__PURE__ */ jsxs4("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
1976
+ /* @__PURE__ */ jsx8(
1977
+ "div",
1978
+ {
1979
+ ref: containerRef,
1980
+ ...dropZoneProps,
1981
+ onDrop: handleDrop,
1982
+ style: {
1983
+ width: "100%",
1984
+ height: "100%",
1985
+ backgroundColor: transparent ? "transparent" : theme.colors.background,
1986
+ // ghostty-web's open() sets contenteditable on this container, so the
1987
+ // browser would draw its own text caret on top of the canvas cursor.
1988
+ // Hide it — the terminal renders its own cursor.
1989
+ caretColor: "transparent"
1990
+ }
1991
+ }
1992
+ ),
1993
+ dropIndicator
1994
+ ] })
1930
1995
  );
1931
1996
  }
1932
1997
  );
@@ -1944,7 +2009,7 @@ function resolveRenderer(choice) {
1944
2009
  import { useTheme as useTheme4 } from "@principal-ade/industry-theme";
1945
2010
  import {
1946
2011
  forwardRef as forwardRef5,
1947
- useCallback as useCallback3,
2012
+ useCallback as useCallback4,
1948
2013
  useEffect as useEffect3,
1949
2014
  useImperativeHandle as useImperativeHandle4,
1950
2015
  useRef as useRef4,
@@ -1953,8 +2018,8 @@ import {
1953
2018
 
1954
2019
  // src/components/TerminalOverlay.tsx
1955
2020
  import { Monitor as Monitor2 } from "lucide-react";
1956
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1957
- var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
2021
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
2022
+ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs5(
1958
2023
  "div",
1959
2024
  {
1960
2025
  style: {
@@ -1974,8 +2039,8 @@ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
1974
2039
  zIndex: 10
1975
2040
  },
1976
2041
  children: [
1977
- /* @__PURE__ */ jsx8(Monitor2, { size: 48, color: theme.colors.textSecondary }),
1978
- /* @__PURE__ */ jsx8(
2042
+ /* @__PURE__ */ jsx9(Monitor2, { size: 48, color: theme.colors.textSecondary }),
2043
+ /* @__PURE__ */ jsx9(
1979
2044
  "div",
1980
2045
  {
1981
2046
  style: {
@@ -1987,7 +2052,7 @@ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
1987
2052
  children: state.message
1988
2053
  }
1989
2054
  ),
1990
- state.subtitle && /* @__PURE__ */ jsx8(
2055
+ state.subtitle && /* @__PURE__ */ jsx9(
1991
2056
  "div",
1992
2057
  {
1993
2058
  style: {
@@ -1999,7 +2064,7 @@ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
1999
2064
  children: state.subtitle
2000
2065
  }
2001
2066
  ),
2002
- state.actions && state.actions.length > 0 && /* @__PURE__ */ jsx8(
2067
+ state.actions && state.actions.length > 0 && /* @__PURE__ */ jsx9(
2003
2068
  "div",
2004
2069
  {
2005
2070
  style: {
@@ -2007,7 +2072,7 @@ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
2007
2072
  gap: "12px",
2008
2073
  marginTop: "8px"
2009
2074
  },
2010
- children: state.actions.map((action) => /* @__PURE__ */ jsxs4(
2075
+ children: state.actions.map((action) => /* @__PURE__ */ jsxs5(
2011
2076
  "button",
2012
2077
  {
2013
2078
  type: "button",
@@ -2054,7 +2119,7 @@ var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs4(
2054
2119
  );
2055
2120
 
2056
2121
  // src/components/TerminalSession.tsx
2057
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
2122
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2058
2123
  var TerminalSession = forwardRef5(
2059
2124
  (props, ref) => {
2060
2125
  const {
@@ -2098,7 +2163,7 @@ var TerminalSession = forwardRef5(
2098
2163
  const isActiveRef = useRef4(false);
2099
2164
  const activityStartedAtRef = useRef4(0);
2100
2165
  const activityTimerRef = useRef4(null);
2101
- const claimAndConnect = useCallback3(
2166
+ const claimAndConnect = useCallback4(
2102
2167
  async (targetSessionId, force = false) => {
2103
2168
  if (!enableOwnership) return;
2104
2169
  try {
@@ -2223,7 +2288,7 @@ var TerminalSession = forwardRef5(
2223
2288
  }
2224
2289
  };
2225
2290
  }, []);
2226
- const observeActivity = useCallback3(() => {
2291
+ const observeActivity = useCallback4(() => {
2227
2292
  if (!activityDetection) return;
2228
2293
  const now = Date.now();
2229
2294
  const emitBus = (isWorking2) => {
@@ -2273,7 +2338,7 @@ var TerminalSession = forwardRef5(
2273
2338
  if (activityTimerRef.current) clearTimeout(activityTimerRef.current);
2274
2339
  };
2275
2340
  }, []);
2276
- const handleData = useCallback3(
2341
+ const handleData = useCallback4(
2277
2342
  (data) => {
2278
2343
  if (localSessionId && actions.writeToTerminal) {
2279
2344
  actions.writeToTerminal(localSessionId, data);
@@ -2281,14 +2346,14 @@ var TerminalSession = forwardRef5(
2281
2346
  },
2282
2347
  [localSessionId, actions]
2283
2348
  );
2284
- const handleFilesDropped = useCallback3(
2349
+ const handleFilesDropped = useCallback4(
2285
2350
  async (files) => {
2286
2351
  if (!localSessionId || !actions.saveDroppedFiles) return [];
2287
2352
  return actions.saveDroppedFiles(files, localSessionId);
2288
2353
  },
2289
2354
  [localSessionId, actions]
2290
2355
  );
2291
- const handleResize = useCallback3(
2356
+ const handleResize = useCallback4(
2292
2357
  (cols, rows) => {
2293
2358
  if (localSessionId && actions.resizeTerminal) {
2294
2359
  actions.resizeTerminal(localSessionId, cols, rows);
@@ -2296,7 +2361,7 @@ var TerminalSession = forwardRef5(
2296
2361
  },
2297
2362
  [localSessionId, actions]
2298
2363
  );
2299
- const handleReady = useCallback3(
2364
+ const handleReady = useCallback4(
2300
2365
  (cols, rows) => {
2301
2366
  if (!localSessionId || !actions.resizeTerminal) return;
2302
2367
  const shouldForce = needsRefreshOnResizeRef.current;
@@ -2324,7 +2389,7 @@ var TerminalSession = forwardRef5(
2324
2389
  },
2325
2390
  [localSessionId, actions]
2326
2391
  );
2327
- const handleLinkClickInternal = useCallback3(
2392
+ const handleLinkClickInternal = useCallback4(
2328
2393
  (url, modifiers) => {
2329
2394
  onLinkClick?.(url, modifiers);
2330
2395
  if (localSessionId && events) {
@@ -2345,7 +2410,7 @@ var TerminalSession = forwardRef5(
2345
2410
  },
2346
2411
  [localSessionId, events, onLinkClick]
2347
2412
  );
2348
- const handleShortcutInternal = useCallback3(
2413
+ const handleShortcutInternal = useCallback4(
2349
2414
  (evt) => {
2350
2415
  onShortcut?.(evt);
2351
2416
  if (localSessionId && events) {
@@ -2362,7 +2427,7 @@ var TerminalSession = forwardRef5(
2362
2427
  },
2363
2428
  [localSessionId, events, onShortcut]
2364
2429
  );
2365
- const handleScrollPositionChangeInternal = useCallback3(
2430
+ const handleScrollPositionChangeInternal = useCallback4(
2366
2431
  (p) => {
2367
2432
  onScrollPositionChange?.(p);
2368
2433
  },
@@ -2381,7 +2446,7 @@ var TerminalSession = forwardRef5(
2381
2446
  unsubscribe();
2382
2447
  };
2383
2448
  }, [enableOwnership, localSessionId, actions]);
2384
- const handleTakeControl = useCallback3(async () => {
2449
+ const handleTakeControl = useCallback4(async () => {
2385
2450
  if (!localSessionId) return;
2386
2451
  await claimAndConnect(localSessionId, true);
2387
2452
  }, [localSessionId, claimAndConnect]);
@@ -2396,7 +2461,7 @@ var TerminalSession = forwardRef5(
2396
2461
  [localSessionId]
2397
2462
  );
2398
2463
  if (!isInitialized) {
2399
- return /* @__PURE__ */ jsxs5(
2464
+ return /* @__PURE__ */ jsxs6(
2400
2465
  "div",
2401
2466
  {
2402
2467
  style: {
@@ -2407,7 +2472,7 @@ var TerminalSession = forwardRef5(
2407
2472
  padding: "10px 0 0 10px"
2408
2473
  },
2409
2474
  children: [
2410
- /* @__PURE__ */ jsx9(
2475
+ /* @__PURE__ */ jsx10(
2411
2476
  "div",
2412
2477
  {
2413
2478
  style: {
@@ -2418,7 +2483,7 @@ var TerminalSession = forwardRef5(
2418
2483
  }
2419
2484
  }
2420
2485
  ),
2421
- /* @__PURE__ */ jsx9("style", { children: `@keyframes terminal-session-cursor-blink {
2486
+ /* @__PURE__ */ jsx10("style", { children: `@keyframes terminal-session-cursor-blink {
2422
2487
  0%, 100% { opacity: 1; }
2423
2488
  50% { opacity: 0; }
2424
2489
  }` })
@@ -2439,8 +2504,8 @@ var TerminalSession = forwardRef5(
2439
2504
  opacity: 1
2440
2505
  } : void 0;
2441
2506
  const effectiveOverlay = ownershipLostOverlay ?? overlayState;
2442
- return /* @__PURE__ */ jsxs5("div", { style: { position: "relative", height: "100%", width: "100%" }, children: [
2443
- /* @__PURE__ */ jsx9(
2507
+ return /* @__PURE__ */ jsxs6("div", { style: { position: "relative", height: "100%", width: "100%" }, children: [
2508
+ /* @__PURE__ */ jsx10(
2444
2509
  Renderer,
2445
2510
  {
2446
2511
  ref: rendererRef,
@@ -2459,8 +2524,8 @@ var TerminalSession = forwardRef5(
2459
2524
  },
2460
2525
  shouldRenderTerminal ? "active" : "overlay"
2461
2526
  ),
2462
- effectiveOverlay && /* @__PURE__ */ jsx9(TerminalOverlay, { state: effectiveOverlay, theme }),
2463
- isWorking && !effectiveOverlay && /* @__PURE__ */ jsx9(
2527
+ effectiveOverlay && /* @__PURE__ */ jsx10(TerminalOverlay, { state: effectiveOverlay, theme }),
2528
+ isWorking && !effectiveOverlay && /* @__PURE__ */ jsx10(
2464
2529
  WorkingOverlay,
2465
2530
  {
2466
2531
  theme,
@@ -2516,12 +2581,16 @@ function useThemedTerminal() {
2516
2581
  // src/components/TabBar/TabBar.tsx
2517
2582
  import { useTheme as useTheme7 } from "@principal-ade/industry-theme";
2518
2583
  import { Plus } from "lucide-react";
2519
- import { useState as useState3, useCallback as useCallback5 } from "react";
2584
+ import React2, { useState as useState3, useCallback as useCallback6 } from "react";
2520
2585
 
2521
2586
  // src/components/TabBar/TabButton.tsx
2522
2587
  import { useTheme as useTheme6 } from "@principal-ade/industry-theme";
2523
- import { useCallback as useCallback4 } from "react";
2524
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2588
+ import { useCallback as useCallback5 } from "react";
2589
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2590
+ var CLOSE_BUTTON_LEFT = 8;
2591
+ var CLOSE_BUTTON_SIZE = 16;
2592
+ var CLOSE_BUTTON_GAP = 6;
2593
+ var CLOSE_BUTTON_GUTTER = CLOSE_BUTTON_LEFT + CLOSE_BUTTON_SIZE + CLOSE_BUTTON_GAP;
2525
2594
  var TabButton = ({
2526
2595
  tab,
2527
2596
  isActive,
@@ -2548,7 +2617,7 @@ var TabButton = ({
2548
2617
  const { theme } = useTheme6();
2549
2618
  const showCloseButton = isHovered || isActive;
2550
2619
  const closable = tab.closable !== false;
2551
- const handleDragStart = useCallback4(
2620
+ const handleDragStart = useCallback5(
2552
2621
  (e) => {
2553
2622
  const target = e.currentTarget;
2554
2623
  e.dataTransfer.setData("application/x-tab-association", tab.id);
@@ -2576,10 +2645,10 @@ var TabButton = ({
2576
2645
  },
2577
2646
  [tab.id, onDragStart]
2578
2647
  );
2579
- const handleDragEnd = useCallback4(() => {
2648
+ const handleDragEnd = useCallback5(() => {
2580
2649
  onDragEnd?.();
2581
2650
  }, [onDragEnd]);
2582
- const handleDragOver = useCallback4(
2651
+ const handleDragOver = useCallback5(
2583
2652
  (e) => {
2584
2653
  if (canAcceptDrop) {
2585
2654
  e.preventDefault();
@@ -2588,7 +2657,7 @@ var TabButton = ({
2588
2657
  },
2589
2658
  [canAcceptDrop]
2590
2659
  );
2591
- const handleDrop = useCallback4(
2660
+ const handleDrop = useCallback5(
2592
2661
  (e) => {
2593
2662
  e.preventDefault();
2594
2663
  const draggedTabId = e.dataTransfer.getData("application/x-tab-association");
@@ -2598,14 +2667,14 @@ var TabButton = ({
2598
2667
  },
2599
2668
  [tab.id, onDrop]
2600
2669
  );
2601
- const handleDragEnter = useCallback4(
2670
+ const handleDragEnter = useCallback5(
2602
2671
  (e) => {
2603
2672
  e.preventDefault();
2604
2673
  onDragEnter?.();
2605
2674
  },
2606
2675
  [onDragEnter]
2607
2676
  );
2608
- const handleDragLeave = useCallback4(
2677
+ const handleDragLeave = useCallback5(
2609
2678
  (e) => {
2610
2679
  e.preventDefault();
2611
2680
  onDragLeave?.();
@@ -2622,7 +2691,7 @@ var TabButton = ({
2622
2691
  }
2623
2692
  return {};
2624
2693
  };
2625
- return /* @__PURE__ */ jsxs6(
2694
+ return /* @__PURE__ */ jsxs7(
2626
2695
  "div",
2627
2696
  {
2628
2697
  "data-tab-id": tab.id,
@@ -2642,6 +2711,10 @@ var TabButton = ({
2642
2711
  justifyContent: "center",
2643
2712
  gap: "6px",
2644
2713
  padding: "6px 8px",
2714
+ // Reserve the close button's gutter so a long, ellipsized label never
2715
+ // renders underneath it. Reserved whenever the tab is closable (not
2716
+ // just when the button is shown) so the layout doesn't shift on hover.
2717
+ paddingLeft: closable ? `${CLOSE_BUTTON_GUTTER}px` : "8px",
2645
2718
  backgroundColor: isActive ? theme.colors.backgroundDark ?? theme.colors.backgroundSecondary : theme.colors.background,
2646
2719
  // The tab bar's bottom border lives on each tab: inactive tabs draw
2647
2720
  // it, the active tab leaves a gap so it reads as connected to the
@@ -2664,7 +2737,7 @@ var TabButton = ({
2664
2737
  ...getDragOverStyles()
2665
2738
  },
2666
2739
  children: [
2667
- closable && showCloseButton && /* @__PURE__ */ jsx10(
2740
+ closable && showCloseButton && /* @__PURE__ */ jsx11(
2668
2741
  "button",
2669
2742
  {
2670
2743
  onClick: (e) => {
@@ -2675,8 +2748,8 @@ var TabButton = ({
2675
2748
  display: "flex",
2676
2749
  alignItems: "center",
2677
2750
  justifyContent: "center",
2678
- width: "16px",
2679
- height: "16px",
2751
+ width: `${CLOSE_BUTTON_SIZE}px`,
2752
+ height: `${CLOSE_BUTTON_SIZE}px`,
2680
2753
  borderRadius: "3px",
2681
2754
  border: "none",
2682
2755
  backgroundColor: "transparent",
@@ -2684,7 +2757,7 @@ var TabButton = ({
2684
2757
  color: theme.colors.textSecondary,
2685
2758
  padding: 0,
2686
2759
  position: "absolute",
2687
- left: "8px"
2760
+ left: `${CLOSE_BUTTON_LEFT}px`
2688
2761
  },
2689
2762
  onMouseEnter: (e) => {
2690
2763
  e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
@@ -2699,12 +2772,12 @@ var TabButton = ({
2699
2772
  (() => {
2700
2773
  const icon = renderIcon ? renderIcon(tab) : void 0;
2701
2774
  const displayIcon = icon !== void 0 ? icon : tab.icon;
2702
- return displayIcon ? /* @__PURE__ */ jsx10("div", { style: { flexShrink: 0, display: "flex", alignItems: "center", pointerEvents: "none" }, children: displayIcon }) : null;
2775
+ return displayIcon ? /* @__PURE__ */ jsx11("div", { style: { flexShrink: 0, display: "flex", alignItems: "center", pointerEvents: "none" }, children: displayIcon }) : null;
2703
2776
  })(),
2704
2777
  (() => {
2705
2778
  const label = renderLabel ? renderLabel(tab) : void 0;
2706
2779
  const displayLabel = label !== void 0 ? label : tab.label;
2707
- return /* @__PURE__ */ jsx10(
2780
+ return /* @__PURE__ */ jsx11(
2708
2781
  "span",
2709
2782
  {
2710
2783
  style: {
@@ -2718,7 +2791,7 @@ var TabButton = ({
2718
2791
  }
2719
2792
  );
2720
2793
  })(),
2721
- renderAccessory ? renderAccessory(tab) : keyboardHint && /* @__PURE__ */ jsx10(
2794
+ renderAccessory ? renderAccessory(tab) : keyboardHint && /* @__PURE__ */ jsx11(
2722
2795
  "span",
2723
2796
  {
2724
2797
  style: {
@@ -2737,7 +2810,7 @@ var TabButton = ({
2737
2810
  TabButton.displayName = "TabButton";
2738
2811
 
2739
2812
  // src/components/TabBar/TabBar.tsx
2740
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2813
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2741
2814
  var TabBar = ({
2742
2815
  tabs,
2743
2816
  activeTabId,
@@ -2760,14 +2833,14 @@ var TabBar = ({
2760
2833
  const [hoveredTabId, setHoveredTabId] = useState3(null);
2761
2834
  const [draggedTabId, setDraggedTabId] = useState3(null);
2762
2835
  const [dragOverTabId, setDragOverTabId] = useState3(null);
2763
- const handleDragStart = useCallback5((tabId) => {
2836
+ const handleDragStart = useCallback6((tabId) => {
2764
2837
  setDraggedTabId(tabId);
2765
2838
  }, []);
2766
- const handleDragEnd = useCallback5(() => {
2839
+ const handleDragEnd = useCallback6(() => {
2767
2840
  setDraggedTabId(null);
2768
2841
  setDragOverTabId(null);
2769
2842
  }, []);
2770
- const handleDrop = useCallback5(
2843
+ const handleDrop = useCallback6(
2771
2844
  (targetTabId, draggedId) => {
2772
2845
  if (draggedId !== targetTabId) {
2773
2846
  onTabDrop?.(draggedId, targetTabId);
@@ -2777,13 +2850,13 @@ var TabBar = ({
2777
2850
  },
2778
2851
  [onTabDrop]
2779
2852
  );
2780
- const handleDragEnter = useCallback5((tabId) => {
2853
+ const handleDragEnter = useCallback6((tabId) => {
2781
2854
  setDragOverTabId(tabId);
2782
2855
  }, []);
2783
- const handleDragLeave = useCallback5(() => {
2856
+ const handleDragLeave = useCallback6(() => {
2784
2857
  setDragOverTabId(null);
2785
2858
  }, []);
2786
- return /* @__PURE__ */ jsxs7(
2859
+ return /* @__PURE__ */ jsxs8(
2787
2860
  "div",
2788
2861
  {
2789
2862
  className,
@@ -2795,7 +2868,7 @@ var TabBar = ({
2795
2868
  boxSizing: "border-box"
2796
2869
  },
2797
2870
  children: [
2798
- leftSection && /* @__PURE__ */ jsx11(
2871
+ leftSection && /* @__PURE__ */ jsx12(
2799
2872
  "div",
2800
2873
  {
2801
2874
  style: {
@@ -2811,7 +2884,7 @@ var TabBar = ({
2811
2884
  children: leftSection
2812
2885
  }
2813
2886
  ),
2814
- /* @__PURE__ */ jsx11(
2887
+ /* @__PURE__ */ jsx12(
2815
2888
  "div",
2816
2889
  {
2817
2890
  style: {
@@ -2824,36 +2897,51 @@ var TabBar = ({
2824
2897
  },
2825
2898
  children: tabs.map((tab, index) => {
2826
2899
  const canDrop = enableDragAndDrop && draggedTabId !== null && draggedTabId !== tab.id ? canDropOnTab ? canDropOnTab(draggedTabId, tab.id) : true : false;
2827
- return /* @__PURE__ */ jsx11(
2828
- TabButton,
2829
- {
2830
- tab,
2831
- isActive: tab.id === activeTabId,
2832
- isHovered: tab.id === hoveredTabId,
2833
- onMouseEnter: () => setHoveredTabId(tab.id),
2834
- onMouseLeave: () => setHoveredTabId(null),
2835
- onClick: () => onTabClick(tab.id),
2836
- onClose: () => onTabClose(tab.id),
2837
- keyboardHint: showKeyboardHints && index < 9 ? `\u2318 ${index + 1}` : void 0,
2838
- renderAccessory: renderTabAccessory,
2839
- renderIcon: renderTabIcon,
2840
- renderLabel: renderTabLabel,
2841
- draggable: enableDragAndDrop,
2842
- onDragStart: handleDragStart,
2843
- onDragEnd: handleDragEnd,
2844
- onDrop: (draggedId) => handleDrop(tab.id, draggedId),
2845
- canAcceptDrop: canDrop,
2846
- isDragOver: dragOverTabId === tab.id,
2847
- isBeingDragged: draggedTabId === tab.id,
2848
- onDragEnter: () => handleDragEnter(tab.id),
2849
- onDragLeave: handleDragLeave
2850
- },
2851
- tab.id
2852
- );
2900
+ const prevTab = index > 0 ? tabs[index - 1] : void 0;
2901
+ const showDivider = prevTab !== void 0 && prevTab.id !== activeTabId && tab.id !== activeTabId;
2902
+ return /* @__PURE__ */ jsxs8(React2.Fragment, { children: [
2903
+ showDivider && /* @__PURE__ */ jsx12(
2904
+ "div",
2905
+ {
2906
+ "aria-hidden": "true",
2907
+ style: {
2908
+ flexShrink: 0,
2909
+ width: "1px",
2910
+ height: "16px",
2911
+ backgroundColor: theme.colors.border
2912
+ }
2913
+ }
2914
+ ),
2915
+ /* @__PURE__ */ jsx12(
2916
+ TabButton,
2917
+ {
2918
+ tab,
2919
+ isActive: tab.id === activeTabId,
2920
+ isHovered: tab.id === hoveredTabId,
2921
+ onMouseEnter: () => setHoveredTabId(tab.id),
2922
+ onMouseLeave: () => setHoveredTabId(null),
2923
+ onClick: () => onTabClick(tab.id),
2924
+ onClose: () => onTabClose(tab.id),
2925
+ keyboardHint: showKeyboardHints && index < 9 ? `\u2318 ${index + 1}` : void 0,
2926
+ renderAccessory: renderTabAccessory,
2927
+ renderIcon: renderTabIcon,
2928
+ renderLabel: renderTabLabel,
2929
+ draggable: enableDragAndDrop,
2930
+ onDragStart: handleDragStart,
2931
+ onDragEnd: handleDragEnd,
2932
+ onDrop: (draggedId) => handleDrop(tab.id, draggedId),
2933
+ canAcceptDrop: canDrop,
2934
+ isDragOver: dragOverTabId === tab.id,
2935
+ isBeingDragged: draggedTabId === tab.id,
2936
+ onDragEnter: () => handleDragEnter(tab.id),
2937
+ onDragLeave: handleDragLeave
2938
+ }
2939
+ )
2940
+ ] }, tab.id);
2853
2941
  })
2854
2942
  }
2855
2943
  ),
2856
- rightSection !== void 0 ? rightSection && /* @__PURE__ */ jsx11(
2944
+ rightSection !== void 0 ? rightSection && /* @__PURE__ */ jsx12(
2857
2945
  "div",
2858
2946
  {
2859
2947
  style: {
@@ -2868,7 +2956,7 @@ var TabBar = ({
2868
2956
  },
2869
2957
  children: rightSection
2870
2958
  }
2871
- ) : onNewTab && /* @__PURE__ */ jsx11(
2959
+ ) : onNewTab && /* @__PURE__ */ jsx12(
2872
2960
  "div",
2873
2961
  {
2874
2962
  style: {
@@ -2881,7 +2969,7 @@ var TabBar = ({
2881
2969
  borderBottom: `1px solid ${theme.colors.border}`,
2882
2970
  boxSizing: "border-box"
2883
2971
  },
2884
- children: /* @__PURE__ */ jsx11(
2972
+ children: /* @__PURE__ */ jsx12(
2885
2973
  "button",
2886
2974
  {
2887
2975
  onClick: onNewTab,
@@ -2904,7 +2992,7 @@ var TabBar = ({
2904
2992
  e.currentTarget.style.backgroundColor = "transparent";
2905
2993
  },
2906
2994
  title: "New Tab (\u2318T)",
2907
- children: /* @__PURE__ */ jsx11(Plus, { size: 14 })
2995
+ children: /* @__PURE__ */ jsx12(Plus, { size: 14 })
2908
2996
  }
2909
2997
  )
2910
2998
  }
@@ -2963,7 +3051,7 @@ import { CollapsibleSplitPane } from "@principal-ade/panels";
2963
3051
  import { Terminal as TerminalIcon2, Box, Boxes, Paperclip } from "lucide-react";
2964
3052
  import React4, {
2965
3053
  useState as useState4,
2966
- useCallback as useCallback6,
3054
+ useCallback as useCallback7,
2967
3055
  useEffect as useEffect5,
2968
3056
  useRef as useRef5
2969
3057
  } from "react";
@@ -2972,7 +3060,7 @@ import React4, {
2972
3060
  import { useTheme as useTheme8 } from "@principal-ade/industry-theme";
2973
3061
  import { Folder, GitBranch } from "lucide-react";
2974
3062
  import React3 from "react";
2975
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
3063
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2976
3064
  var AVATAR_SIZE = 14;
2977
3065
  var TerminalStatusBar = ({
2978
3066
  directory,
@@ -3002,13 +3090,13 @@ var TerminalStatusBar = ({
3002
3090
  if (repo) {
3003
3091
  const avatarUrl = repo.avatarUrl ?? `https://github.com/${repo.owner}.png?size=48`;
3004
3092
  const showAvatar = Boolean(repo.owner) && !avatarFailed;
3005
- return /* @__PURE__ */ jsxs8(
3093
+ return /* @__PURE__ */ jsxs9(
3006
3094
  "div",
3007
3095
  {
3008
3096
  style: containerStyle,
3009
3097
  title: `${repo.owner}/${repo.repo}${repo.branch ? ` \u2014 ${repo.branch}` : ""}`,
3010
3098
  children: [
3011
- showAvatar ? /* @__PURE__ */ jsx12(
3099
+ showAvatar ? /* @__PURE__ */ jsx13(
3012
3100
  "img",
3013
3101
  {
3014
3102
  src: avatarUrl,
@@ -3023,8 +3111,8 @@ var TerminalStatusBar = ({
3023
3111
  borderRadius: "50%"
3024
3112
  }
3025
3113
  }
3026
- ) : /* @__PURE__ */ jsx12(Folder, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3027
- /* @__PURE__ */ jsxs8(
3114
+ ) : /* @__PURE__ */ jsx13(Folder, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3115
+ /* @__PURE__ */ jsxs9(
3028
3116
  "span",
3029
3117
  {
3030
3118
  style: {
@@ -3034,15 +3122,15 @@ var TerminalStatusBar = ({
3034
3122
  minWidth: 0
3035
3123
  },
3036
3124
  children: [
3037
- /* @__PURE__ */ jsxs8("span", { style: { opacity: 0.7 }, children: [
3125
+ /* @__PURE__ */ jsxs9("span", { style: { opacity: 0.7 }, children: [
3038
3126
  repo.owner,
3039
3127
  "/"
3040
3128
  ] }),
3041
- /* @__PURE__ */ jsx12("span", { style: { color: theme.colors.text }, children: repo.repo })
3129
+ /* @__PURE__ */ jsx13("span", { style: { color: theme.colors.text }, children: repo.repo })
3042
3130
  ]
3043
3131
  }
3044
3132
  ),
3045
- repo.branch && /* @__PURE__ */ jsxs8(
3133
+ repo.branch && /* @__PURE__ */ jsxs9(
3046
3134
  "span",
3047
3135
  {
3048
3136
  style: {
@@ -3053,9 +3141,9 @@ var TerminalStatusBar = ({
3053
3141
  opacity: 0.85
3054
3142
  },
3055
3143
  children: [
3056
- /* @__PURE__ */ jsx12(GitBranch, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3057
- /* @__PURE__ */ jsx12("span", { children: repo.branch }),
3058
- repo.isDirty && /* @__PURE__ */ jsx12(
3144
+ /* @__PURE__ */ jsx13(GitBranch, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3145
+ /* @__PURE__ */ jsx13("span", { children: repo.branch }),
3146
+ repo.isDirty && /* @__PURE__ */ jsx13(
3059
3147
  "span",
3060
3148
  {
3061
3149
  title: "Uncommitted changes",
@@ -3071,7 +3159,7 @@ var TerminalStatusBar = ({
3071
3159
  ]
3072
3160
  }
3073
3161
  ),
3074
- (repo.ahead || repo.behind) && /* @__PURE__ */ jsxs8("span", { style: { flex: "0 0 auto", opacity: 0.7 }, children: [
3162
+ (repo.ahead || repo.behind) && /* @__PURE__ */ jsxs9("span", { style: { flex: "0 0 auto", opacity: 0.7 }, children: [
3075
3163
  repo.ahead ? `\u2191${repo.ahead}` : "",
3076
3164
  repo.behind ? `\u2193${repo.behind}` : ""
3077
3165
  ] })
@@ -3082,9 +3170,9 @@ var TerminalStatusBar = ({
3082
3170
  if (!directory) {
3083
3171
  return null;
3084
3172
  }
3085
- return /* @__PURE__ */ jsxs8("div", { style: containerStyle, title: directory, children: [
3086
- /* @__PURE__ */ jsx12(Folder, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3087
- /* @__PURE__ */ jsx12(
3173
+ return /* @__PURE__ */ jsxs9("div", { style: containerStyle, title: directory, children: [
3174
+ /* @__PURE__ */ jsx13(Folder, { size: 12, style: { flex: "0 0 auto", opacity: 0.7 } }),
3175
+ /* @__PURE__ */ jsx13(
3088
3176
  "span",
3089
3177
  {
3090
3178
  style: {
@@ -3095,7 +3183,7 @@ var TerminalStatusBar = ({
3095
3183
  textOverflow: "ellipsis",
3096
3184
  minWidth: 0
3097
3185
  },
3098
- children: /* @__PURE__ */ jsx12("bdi", { children: directory })
3186
+ children: /* @__PURE__ */ jsx13("bdi", { children: directory })
3099
3187
  }
3100
3188
  )
3101
3189
  ] });
@@ -3103,9 +3191,9 @@ var TerminalStatusBar = ({
3103
3191
  TerminalStatusBar.displayName = "TerminalStatusBar";
3104
3192
 
3105
3193
  // src/panels/TabbedTerminalPanel.tsx
3106
- import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
3107
- var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: 1, alignItems: "center", height: 12 }, children: [
3108
- [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx13(
3194
+ import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3195
+ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs10("div", { style: { display: "flex", gap: 1, alignItems: "center", height: 12 }, children: [
3196
+ [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx14(
3109
3197
  "div",
3110
3198
  {
3111
3199
  style: {
@@ -3120,7 +3208,7 @@ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs9("div",
3120
3208
  },
3121
3209
  i
3122
3210
  )),
3123
- /* @__PURE__ */ jsx13("style", { children: `
3211
+ /* @__PURE__ */ jsx14("style", { children: `
3124
3212
  @keyframes waveSine {
3125
3213
  0%, 100% { transform: scaleY(0.4); }
3126
3214
  50% { transform: scaleY(1); }
@@ -3147,17 +3235,17 @@ function TerminalTabContentInner(props, ref) {
3147
3235
  } = props;
3148
3236
  const [isWorkingFromActivity, setIsWorkingFromActivity] = useState4(false);
3149
3237
  const sessionRef = useRef5(null);
3150
- const handleSessionCreated = useCallback6(
3238
+ const handleSessionCreated = useCallback7(
3151
3239
  (sid) => onSessionCreated(tab.id, sid),
3152
3240
  [onSessionCreated, tab.id]
3153
3241
  );
3154
- const handleScrollPositionChange = useCallback6(
3242
+ const handleScrollPositionChange = useCallback7(
3155
3243
  (position) => {
3156
3244
  onScrollPositionChange?.(tab.id, position);
3157
3245
  },
3158
3246
  [onScrollPositionChange, tab.id]
3159
3247
  );
3160
- const handleActivityChange = useCallback6(
3248
+ const handleActivityChange = useCallback7(
3161
3249
  (state) => {
3162
3250
  const sid = sessionRef.current?.getSessionId();
3163
3251
  if (sid) {
@@ -3176,7 +3264,7 @@ function TerminalTabContentInner(props, ref) {
3176
3264
  }),
3177
3265
  []
3178
3266
  );
3179
- return /* @__PURE__ */ jsx13(
3267
+ return /* @__PURE__ */ jsx14(
3180
3268
  "div",
3181
3269
  {
3182
3270
  style: {
@@ -3190,7 +3278,7 @@ function TerminalTabContentInner(props, ref) {
3190
3278
  height: "100%",
3191
3279
  width: "100%"
3192
3280
  },
3193
- children: /* @__PURE__ */ jsx13(
3281
+ children: /* @__PURE__ */ jsx14(
3194
3282
  TerminalSession,
3195
3283
  {
3196
3284
  ref: sessionRef,
@@ -3254,6 +3342,7 @@ var TabbedTerminalPanelInner = ({
3254
3342
  renderTabContent,
3255
3343
  renderTabIcon,
3256
3344
  renderTabLabel,
3345
+ renderEmptyState,
3257
3346
  width,
3258
3347
  activeTabId: activeTabIdProp,
3259
3348
  onActiveTabChange,
@@ -3349,7 +3438,7 @@ var TabbedTerminalPanelInner = ({
3349
3438
  onFocusTabHandled?.();
3350
3439
  }
3351
3440
  }, [requestFocusTabId, ownedTabs, foreignTabs, setActiveTabId, onFocusTabHandled, activeTabId]);
3352
- const getOwnedTabLabel = useCallback6((index, _directory) => {
3441
+ const getOwnedTabLabel = useCallback7((index, _directory) => {
3353
3442
  if (tabLabelPrefix) {
3354
3443
  return `${tabLabelPrefix} ${index + 1}`;
3355
3444
  }
@@ -3381,7 +3470,7 @@ var TabbedTerminalPanelInner = ({
3381
3470
  }, [tabs]);
3382
3471
  const tabRefsMap = useRef5(/* @__PURE__ */ new Map());
3383
3472
  const refCallbacksMap = useRef5(/* @__PURE__ */ new Map());
3384
- const getRefCallback = useCallback6((tabId) => {
3473
+ const getRefCallback = useCallback7((tabId) => {
3385
3474
  let callback = refCallbacksMap.current.get(tabId);
3386
3475
  if (!callback) {
3387
3476
  callback = (ref) => {
@@ -3398,7 +3487,7 @@ var TabbedTerminalPanelInner = ({
3398
3487
  const hasInitializedRef = useRef5(false);
3399
3488
  const isCreatingTabRef = useRef5(false);
3400
3489
  const headerRef = useRef5(null);
3401
- const restoreOwnedSessions = useCallback6(async () => {
3490
+ const restoreOwnedSessions = useCallback7(async () => {
3402
3491
  try {
3403
3492
  let sessions = [];
3404
3493
  if (actions.listTerminalSessions) {
@@ -3447,7 +3536,7 @@ var TabbedTerminalPanelInner = ({
3447
3536
  console.error("[TabbedTerminalPanel] Failed to restore owned sessions:", err);
3448
3537
  }
3449
3538
  }, [terminalContext, sessionIds, activeTabId, onTabsChange, actions, directory, setActiveTabId]);
3450
- const fetchForeignSessions = useCallback6(async () => {
3539
+ const fetchForeignSessions = useCallback7(async () => {
3451
3540
  try {
3452
3541
  if (!actions.listTerminalSessions) {
3453
3542
  return;
@@ -3481,7 +3570,7 @@ var TabbedTerminalPanelInner = ({
3481
3570
  console.error("[TabbedTerminalPanel] Failed to fetch foreign sessions:", err);
3482
3571
  }
3483
3572
  }, [terminalContext, actions]);
3484
- const clearForeignTabs = useCallback6(() => {
3573
+ const clearForeignTabs = useCallback7(() => {
3485
3574
  setForeignTabs((prevForeign) => {
3486
3575
  const foreignTabIds = new Set(prevForeign.map((t) => t.id));
3487
3576
  setSessionIds((prev) => {
@@ -3518,10 +3607,10 @@ var TabbedTerminalPanelInner = ({
3518
3607
  clearForeignTabs();
3519
3608
  }
3520
3609
  }, [showAllTerminals, fetchForeignSessions, clearForeignTabs]);
3521
- const switchTab = useCallback6((tabId) => {
3610
+ const switchTab = useCallback7((tabId) => {
3522
3611
  setActiveTabId(tabId);
3523
3612
  }, [setActiveTabId]);
3524
- const addNewTab = useCallback6(
3613
+ const addNewTab = useCallback7(
3525
3614
  (label, command, targetDirectory) => {
3526
3615
  const targetDir = targetDirectory || directory;
3527
3616
  const directoryName = targetDir.split("/").pop() || targetDir;
@@ -3542,10 +3631,10 @@ var TabbedTerminalPanelInner = ({
3542
3631
  },
3543
3632
  [directory, onTabsChange]
3544
3633
  );
3545
- const isForeignTab = useCallback6((tabId) => {
3634
+ const isForeignTab = useCallback7((tabId) => {
3546
3635
  return tabId.startsWith("tab-foreign-");
3547
3636
  }, []);
3548
- const closeTab = useCallback6(
3637
+ const closeTab = useCallback7(
3549
3638
  async (tabId) => {
3550
3639
  const sessionId = sessionIds.get(tabId);
3551
3640
  const isForeign = isForeignTab(tabId);
@@ -3628,10 +3717,10 @@ var TabbedTerminalPanelInner = ({
3628
3717
  if (!requestCloseTabId) return;
3629
3718
  closeTab(requestCloseTabId);
3630
3719
  }, [requestCloseTabId]);
3631
- const handleSessionCreated = useCallback6((tabId, sessionId) => {
3720
+ const handleSessionCreated = useCallback7((tabId, sessionId) => {
3632
3721
  setSessionIds((prev) => new Map(prev).set(tabId, sessionId));
3633
3722
  }, []);
3634
- const handleActivityStateChange = useCallback6((sessionId, isActive) => {
3723
+ const handleActivityStateChange = useCallback7((sessionId, isActive) => {
3635
3724
  setActivityStates((prev) => {
3636
3725
  const next = new Map(prev);
3637
3726
  if (isActive) {
@@ -3663,12 +3752,12 @@ var TabbedTerminalPanelInner = ({
3663
3752
  }
3664
3753
  }
3665
3754
  });
3666
- const renderTabAccessory = useCallback6((tab) => {
3755
+ const renderTabAccessory = useCallback7((tab) => {
3667
3756
  const tabSessionId = sessionIds.get(tab.id);
3668
3757
  const isActive = tab.id === activeTabId;
3669
3758
  const record = tabSessionId ? programStatus?.[tabSessionId] : void 0;
3670
3759
  if (record && record.state !== "idle" && record.state !== "clear") {
3671
- return /* @__PURE__ */ jsx13(
3760
+ return /* @__PURE__ */ jsx14(
3672
3761
  "div",
3673
3762
  {
3674
3763
  style: {
@@ -3680,7 +3769,7 @@ var TabbedTerminalPanelInner = ({
3680
3769
  width: "16px",
3681
3770
  height: "16px"
3682
3771
  },
3683
- children: /* @__PURE__ */ jsx13(ProgramStatusBadge, { record })
3772
+ children: /* @__PURE__ */ jsx14(ProgramStatusBadge, { record })
3684
3773
  }
3685
3774
  );
3686
3775
  }
@@ -3688,7 +3777,7 @@ var TabbedTerminalPanelInner = ({
3688
3777
  const hasInternalActivity = tabSessionId ? activityStates.get(tabSessionId) : false;
3689
3778
  const isWorking = hasExternalWorkingState || hasInternalActivity;
3690
3779
  if (!isActive) return null;
3691
- return /* @__PURE__ */ jsx13(Fragment2, { children: /* @__PURE__ */ jsx13(
3780
+ return /* @__PURE__ */ jsx14(Fragment2, { children: /* @__PURE__ */ jsx14(
3692
3781
  "div",
3693
3782
  {
3694
3783
  style: {
@@ -3701,12 +3790,12 @@ var TabbedTerminalPanelInner = ({
3701
3790
  height: "16px"
3702
3791
  },
3703
3792
  title: isWorking ? "Terminal active" : "Terminal idle",
3704
- children: /* @__PURE__ */ jsx13(ActivityIndicator, { color: theme.colors.primary, isAnimating: isWorking ?? false })
3793
+ children: /* @__PURE__ */ jsx14(ActivityIndicator, { color: theme.colors.primary, isAnimating: isWorking ?? false })
3705
3794
  }
3706
3795
  ) });
3707
3796
  }, [activeTabId, theme, sessionIds, workingStates, activityStates, programStatus]);
3708
- const renderTerminalWithAssociation = useCallback6((tab, isActive, sessionId, association) => {
3709
- const terminalContent = /* @__PURE__ */ jsx13(
3797
+ const renderTerminalWithAssociation = useCallback7((tab, isActive, sessionId, association) => {
3798
+ const terminalContent = /* @__PURE__ */ jsx14(
3710
3799
  TerminalTabContent,
3711
3800
  {
3712
3801
  ref: getRefCallback(tab.id),
@@ -3728,7 +3817,7 @@ var TabbedTerminalPanelInner = ({
3728
3817
  `terminal-${tab.id}`
3729
3818
  );
3730
3819
  const hasAssociation = !!association;
3731
- const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */ jsx13("div", { style: {
3820
+ const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */ jsx14("div", { style: {
3732
3821
  height: "100%",
3733
3822
  display: "flex",
3734
3823
  alignItems: "center",
@@ -3737,10 +3826,10 @@ var TabbedTerminalPanelInner = ({
3737
3826
  fontSize: "13px",
3738
3827
  backgroundColor: theme.colors.backgroundSecondary
3739
3828
  }, children: "Drag a tab here to associate it with this terminal" });
3740
- const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */ jsx13(Paperclip, { size: 14 }) };
3829
+ const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */ jsx14(Paperclip, { size: 14 }) };
3741
3830
  const isCollapsed = hasAssociation ? association.collapsed : true;
3742
3831
  const handleCollapsedChange = hasAssociation ? (collapsed) => onAssociationCollapsedChange?.(tab.id, collapsed) : void 0;
3743
- return /* @__PURE__ */ jsx13(
3832
+ return /* @__PURE__ */ jsx14(
3744
3833
  CollapsibleSplitPane,
3745
3834
  {
3746
3835
  style: { height: "100%" },
@@ -3772,7 +3861,7 @@ var TabbedTerminalPanelInner = ({
3772
3861
  onAssociationRatioChange,
3773
3862
  theme
3774
3863
  ]);
3775
- const handleTabDrop = useCallback6(
3864
+ const handleTabDrop = useCallback7(
3776
3865
  (draggedTabId, targetTabId) => {
3777
3866
  const draggedTab = tabs.find((t) => t.id === draggedTabId);
3778
3867
  const targetTab = tabs.find((t) => t.id === targetTabId);
@@ -3783,7 +3872,7 @@ var TabbedTerminalPanelInner = ({
3783
3872
  },
3784
3873
  [tabs, onTabAssociate, setActiveTabId]
3785
3874
  );
3786
- const canDropOnTab = useCallback6(
3875
+ const canDropOnTab = useCallback7(
3787
3876
  (draggedTabId, targetTabId) => {
3788
3877
  const draggedTab = tabs.find((t) => t.id === draggedTabId);
3789
3878
  const targetTab = tabs.find((t) => t.id === targetTabId);
@@ -3792,7 +3881,7 @@ var TabbedTerminalPanelInner = ({
3792
3881
  [tabs]
3793
3882
  );
3794
3883
  const [isDragOverContent, setIsDragOverContent] = useState4(false);
3795
- const handleContentDragEnter = useCallback6((e) => {
3884
+ const handleContentDragEnter = useCallback7((e) => {
3796
3885
  e.preventDefault();
3797
3886
  if (activeTabId) {
3798
3887
  const activeTab = tabs.find((t) => t.id === activeTabId);
@@ -3801,13 +3890,13 @@ var TabbedTerminalPanelInner = ({
3801
3890
  }
3802
3891
  }
3803
3892
  }, [activeTabId, tabs]);
3804
- const handleContentDragLeave = useCallback6((e) => {
3893
+ const handleContentDragLeave = useCallback7((e) => {
3805
3894
  const relatedTarget = e.relatedTarget;
3806
3895
  if (!e.currentTarget.contains(relatedTarget)) {
3807
3896
  setIsDragOverContent(false);
3808
3897
  }
3809
3898
  }, []);
3810
- const handleContentDrop = useCallback6((e) => {
3899
+ const handleContentDrop = useCallback7((e) => {
3811
3900
  e.preventDefault();
3812
3901
  e.stopPropagation();
3813
3902
  setIsDragOverContent(false);
@@ -3822,7 +3911,7 @@ var TabbedTerminalPanelInner = ({
3822
3911
  setActiveTabId(activeTabId);
3823
3912
  }
3824
3913
  }, [activeTabId, tabs, onTabAssociate, setActiveTabId]);
3825
- return /* @__PURE__ */ jsxs9(
3914
+ return /* @__PURE__ */ jsxs10(
3826
3915
  "div",
3827
3916
  {
3828
3917
  style: {
@@ -3832,7 +3921,7 @@ var TabbedTerminalPanelInner = ({
3832
3921
  backgroundColor: theme.colors.background
3833
3922
  },
3834
3923
  children: [
3835
- !hideHeader && /* @__PURE__ */ jsx13("div", { ref: headerRef, children: /* @__PURE__ */ jsx13(
3924
+ !hideHeader && /* @__PURE__ */ jsx14("div", { ref: headerRef, children: /* @__PURE__ */ jsx14(
3836
3925
  TabBar,
3837
3926
  {
3838
3927
  tabs: genericTabs,
@@ -3840,7 +3929,7 @@ var TabbedTerminalPanelInner = ({
3840
3929
  onTabClick: switchTab,
3841
3930
  onTabClose: closeTab,
3842
3931
  onNewTab: addNewTab,
3843
- leftSection: hideShowAllTerminalsButton ? void 0 : /* @__PURE__ */ jsx13(
3932
+ leftSection: hideShowAllTerminalsButton ? void 0 : /* @__PURE__ */ jsx14(
3844
3933
  "button",
3845
3934
  {
3846
3935
  onClick: () => onShowAllTerminalsChange?.(!showAllTerminals),
@@ -3867,7 +3956,7 @@ var TabbedTerminalPanelInner = ({
3867
3956
  }
3868
3957
  },
3869
3958
  title: showAllTerminals ? "Showing all terminals (click to filter by context)" : "Show all terminals",
3870
- children: showAllTerminals ? /* @__PURE__ */ jsx13(Boxes, { size: 14 }) : /* @__PURE__ */ jsx13(Box, { size: 14 })
3959
+ children: showAllTerminals ? /* @__PURE__ */ jsx14(Boxes, { size: 14 }) : /* @__PURE__ */ jsx14(Box, { size: 14 })
3871
3960
  }
3872
3961
  ),
3873
3962
  renderTabAccessory,
@@ -3879,7 +3968,7 @@ var TabbedTerminalPanelInner = ({
3879
3968
  canDropOnTab
3880
3969
  }
3881
3970
  ) }),
3882
- /* @__PURE__ */ jsxs9(
3971
+ /* @__PURE__ */ jsxs10(
3883
3972
  "div",
3884
3973
  {
3885
3974
  style: {
@@ -3928,7 +4017,7 @@ var TabbedTerminalPanelInner = ({
3928
4017
  const customContent = renderTabContent(tab, isActive, sessionId, width);
3929
4018
  if (customContent === null && tab.contentType === "terminal") {
3930
4019
  const association = associations?.[tab.id];
3931
- return /* @__PURE__ */ jsx13(
4020
+ return /* @__PURE__ */ jsx14(
3932
4021
  "div",
3933
4022
  {
3934
4023
  inert: !isActive,
@@ -3956,7 +4045,7 @@ var TabbedTerminalPanelInner = ({
3956
4045
  );
3957
4046
  }
3958
4047
  const hasBeenActivated = activatedTabs.has(tab.id);
3959
- return /* @__PURE__ */ jsx13(
4048
+ return /* @__PURE__ */ jsx14(
3960
4049
  "div",
3961
4050
  {
3962
4051
  inert: !isActive,
@@ -3976,7 +4065,7 @@ var TabbedTerminalPanelInner = ({
3976
4065
  }
3977
4066
  if (tab.contentType === "terminal") {
3978
4067
  const association = associations?.[tab.id];
3979
- return /* @__PURE__ */ jsx13(
4068
+ return /* @__PURE__ */ jsx14(
3980
4069
  "div",
3981
4070
  {
3982
4071
  inert: !isActive,
@@ -3994,7 +4083,7 @@ var TabbedTerminalPanelInner = ({
3994
4083
  tab.id
3995
4084
  );
3996
4085
  }
3997
- return /* @__PURE__ */ jsxs9(
4086
+ return /* @__PURE__ */ jsxs10(
3998
4087
  "div",
3999
4088
  {
4000
4089
  inert: !isActive,
@@ -4010,71 +4099,77 @@ var TabbedTerminalPanelInner = ({
4010
4099
  color: theme.colors.textSecondary
4011
4100
  },
4012
4101
  children: [
4013
- /* @__PURE__ */ jsxs9("p", { children: [
4102
+ /* @__PURE__ */ jsxs10("p", { children: [
4014
4103
  "Unknown content type: ",
4015
4104
  tab.contentType
4016
4105
  ] }),
4017
- /* @__PURE__ */ jsx13("p", { style: { fontSize: theme.fontSizes[0], marginTop: "8px" }, children: "Provide a renderTabContent prop to render custom tab types" })
4106
+ /* @__PURE__ */ jsx14("p", { style: { fontSize: theme.fontSizes[0], marginTop: "8px" }, children: "Provide a renderTabContent prop to render custom tab types" })
4018
4107
  ]
4019
4108
  },
4020
4109
  tab.id
4021
4110
  );
4022
4111
  }),
4023
- tabs.length === 0 && /* @__PURE__ */ jsxs9(
4024
- "div",
4025
- {
4026
- style: {
4027
- display: "flex",
4028
- flexDirection: "column",
4029
- alignItems: "center",
4030
- justifyContent: "center",
4031
- height: "100%",
4032
- color: theme.colors.textSecondary
4033
- },
4034
- children: [
4035
- /* @__PURE__ */ jsx13(
4036
- TerminalIcon2,
4037
- {
4038
- size: 32,
4039
- style: { opacity: 0.5, marginBottom: "16px" }
4040
- }
4041
- ),
4042
- /* @__PURE__ */ jsx13(
4043
- "button",
4044
- {
4045
- onClick: () => addNewTab(),
4046
- style: {
4047
- marginTop: "16px",
4048
- padding: "8px 16px",
4049
- backgroundColor: theme.colors.primary,
4050
- color: theme.colors.background,
4051
- border: "none",
4052
- borderRadius: "4px",
4053
- cursor: "pointer",
4054
- fontSize: theme.fontSizes[1],
4055
- fontFamily: theme.fonts.body
4056
- },
4057
- children: "New Terminal"
4058
- }
4059
- )
4060
- ]
4112
+ tabs.length === 0 && (() => {
4113
+ const customEmptyState = renderEmptyState?.();
4114
+ if (customEmptyState !== void 0 && customEmptyState !== null) {
4115
+ return customEmptyState;
4061
4116
  }
4062
- )
4117
+ return /* @__PURE__ */ jsxs10(
4118
+ "div",
4119
+ {
4120
+ style: {
4121
+ display: "flex",
4122
+ flexDirection: "column",
4123
+ alignItems: "center",
4124
+ justifyContent: "center",
4125
+ height: "100%",
4126
+ color: theme.colors.textSecondary
4127
+ },
4128
+ children: [
4129
+ /* @__PURE__ */ jsx14(
4130
+ TerminalIcon2,
4131
+ {
4132
+ size: 32,
4133
+ style: { opacity: 0.5, marginBottom: "16px" }
4134
+ }
4135
+ ),
4136
+ /* @__PURE__ */ jsx14(
4137
+ "button",
4138
+ {
4139
+ onClick: () => addNewTab(),
4140
+ style: {
4141
+ marginTop: "16px",
4142
+ padding: "8px 16px",
4143
+ backgroundColor: theme.colors.primary,
4144
+ color: theme.colors.background,
4145
+ border: "none",
4146
+ borderRadius: "4px",
4147
+ cursor: "pointer",
4148
+ fontSize: theme.fontSizes[1],
4149
+ fontFamily: theme.fonts.body
4150
+ },
4151
+ children: "New Terminal"
4152
+ }
4153
+ )
4154
+ ]
4155
+ }
4156
+ );
4157
+ })()
4063
4158
  ]
4064
4159
  }
4065
4160
  ),
4066
4161
  (() => {
4067
4162
  const activeTab = tabs.find((t) => t.id === activeTabId);
4068
4163
  const activeDir = activeTab?.directory;
4069
- return /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", flex: "0 0 auto" }, children: [
4070
- /* @__PURE__ */ jsx13(
4164
+ return /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", flex: "0 0 auto" }, children: [
4165
+ /* @__PURE__ */ jsx14(
4071
4166
  TerminalStatusBar,
4072
4167
  {
4073
4168
  directory: activeDir,
4074
4169
  repo: activeDir ? getRepoInfo?.(activeDir) : void 0
4075
4170
  }
4076
4171
  ),
4077
- bottomBarContent && /* @__PURE__ */ jsx13("div", { style: { marginLeft: "auto", display: "flex", alignItems: "center", height: 22 }, children: bottomBarContent })
4172
+ bottomBarContent && /* @__PURE__ */ jsx14("div", { style: { marginLeft: "auto", display: "flex", alignItems: "center", height: 22 }, children: bottomBarContent })
4078
4173
  ] });
4079
4174
  })()
4080
4175
  ]
@@ -4098,6 +4193,7 @@ var TabbedTerminalPanelMemoized = React4.memo(TabbedTerminalPanelInner, (prevPro
4098
4193
  if (prevProps.onShowAllTerminalsChange !== nextProps.onShowAllTerminalsChange) changes.push("onShowAllTerminalsChange");
4099
4194
  if (prevProps.initialTabs !== nextProps.initialTabs) changes.push("initialTabs");
4100
4195
  if (prevProps.renderTabContent !== nextProps.renderTabContent) changes.push("renderTabContent");
4196
+ if (prevProps.renderEmptyState !== nextProps.renderEmptyState) changes.push("renderEmptyState");
4101
4197
  if (prevProps.requestFocusTabId !== nextProps.requestFocusTabId) changes.push("requestFocusTabId");
4102
4198
  if (prevProps.requestCloseTabId !== nextProps.requestCloseTabId) changes.push("requestCloseTabId");
4103
4199
  if (prevProps.onFocusTabHandled !== nextProps.onFocusTabHandled) changes.push("onFocusTabHandled");