@industry-theme/xterm-terminal-panel 0.5.36 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +724 -791
- package/dist/src/components/TerminalOverlay.d.ts +8 -0
- package/dist/src/components/TerminalOverlay.d.ts.map +1 -0
- package/dist/src/components/TerminalSession.d.ts +43 -0
- package/dist/src/components/TerminalSession.d.ts.map +1 -0
- package/dist/src/panel-exports.d.ts +1 -2
- package/dist/src/panel-exports.d.ts.map +1 -1
- package/dist/src/panels/TabbedTerminalPanel.d.ts.map +1 -1
- package/dist/src/renderer/TerminalRenderer.d.ts +34 -0
- package/dist/src/renderer/TerminalRenderer.d.ts.map +1 -0
- package/dist/src/renderer/XtermRenderer.d.ts +14 -0
- package/dist/src/renderer/XtermRenderer.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/src/panels/TerminalPanel.d.ts +0 -3
- package/dist/src/panels/TerminalPanel.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
// package.json
|
|
36
36
|
var package_default = {
|
|
37
37
|
name: "@industry-theme/xterm-terminal-panel",
|
|
38
|
-
version: "0.
|
|
38
|
+
version: "0.7.0",
|
|
39
39
|
description: "Industry-themed xterm.js terminal components with panel framework integration",
|
|
40
40
|
type: "module",
|
|
41
41
|
main: "dist/index.js",
|
|
@@ -1281,11 +1281,568 @@ var ThemedTerminalWithProvider = forwardRef2((props, ref) => {
|
|
|
1281
1281
|
});
|
|
1282
1282
|
});
|
|
1283
1283
|
ThemedTerminalWithProvider.displayName = "ThemedTerminalWithProvider";
|
|
1284
|
-
// src/
|
|
1284
|
+
// src/renderer/XtermRenderer.tsx
|
|
1285
|
+
import { forwardRef as forwardRef3, useImperativeHandle as useImperativeHandle2, useRef as useRef2 } from "react";
|
|
1286
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1287
|
+
var XtermRenderer = forwardRef3((props, ref) => {
|
|
1288
|
+
const {
|
|
1289
|
+
transparent,
|
|
1290
|
+
enableSearch = true,
|
|
1291
|
+
enableWebLinks = true,
|
|
1292
|
+
cursorBlink = true,
|
|
1293
|
+
convertEol = true,
|
|
1294
|
+
...rest
|
|
1295
|
+
} = props;
|
|
1296
|
+
const innerRef = useRef2(null);
|
|
1297
|
+
useImperativeHandle2(ref, () => ({
|
|
1298
|
+
write: (data) => innerRef.current?.write(data),
|
|
1299
|
+
clear: () => innerRef.current?.clear(),
|
|
1300
|
+
focus: () => innerRef.current?.focus(),
|
|
1301
|
+
blur: () => innerRef.current?.blur(),
|
|
1302
|
+
fit: () => innerRef.current?.fit(),
|
|
1303
|
+
resize: (cols, rows) => innerRef.current?.resize(cols, rows),
|
|
1304
|
+
scrollToBottom: () => innerRef.current?.scrollToBottom(),
|
|
1305
|
+
scrollLines: (delta) => {
|
|
1306
|
+
innerRef.current?.getTerminal()?.scrollLines(delta);
|
|
1307
|
+
},
|
|
1308
|
+
getDimensions: () => {
|
|
1309
|
+
const term = innerRef.current?.getTerminal();
|
|
1310
|
+
if (!term || !term.cols || !term.rows)
|
|
1311
|
+
return null;
|
|
1312
|
+
return { cols: term.cols, rows: term.rows };
|
|
1313
|
+
},
|
|
1314
|
+
getScrollPosition: () => innerRef.current?.getScrollPosition() ?? {
|
|
1315
|
+
isAtTop: false,
|
|
1316
|
+
isAtBottom: true,
|
|
1317
|
+
isScrollLocked: false
|
|
1318
|
+
},
|
|
1319
|
+
isScrollLocked: () => innerRef.current?.isScrollLocked() ?? false
|
|
1320
|
+
}), []);
|
|
1321
|
+
return /* @__PURE__ */ jsx4(ThemedTerminalWithProvider, {
|
|
1322
|
+
ref: innerRef,
|
|
1323
|
+
...rest,
|
|
1324
|
+
enableSearch,
|
|
1325
|
+
enableWebLinks,
|
|
1326
|
+
cursorBlink,
|
|
1327
|
+
convertEol,
|
|
1328
|
+
hideHeader: true,
|
|
1329
|
+
activityDetection: false,
|
|
1330
|
+
allowTransparency: transparent
|
|
1331
|
+
});
|
|
1332
|
+
});
|
|
1333
|
+
XtermRenderer.displayName = "XtermRenderer";
|
|
1334
|
+
// src/components/TerminalSession.tsx
|
|
1285
1335
|
import { useTheme as useTheme2 } from "@principal-ade/industry-theme";
|
|
1336
|
+
import {
|
|
1337
|
+
forwardRef as forwardRef4,
|
|
1338
|
+
useCallback as useCallback2,
|
|
1339
|
+
useEffect as useEffect2,
|
|
1340
|
+
useImperativeHandle as useImperativeHandle3,
|
|
1341
|
+
useRef as useRef3,
|
|
1342
|
+
useState as useState2
|
|
1343
|
+
} from "react";
|
|
1344
|
+
|
|
1345
|
+
// src/components/TerminalOverlay.tsx
|
|
1346
|
+
import { Monitor as Monitor2 } from "lucide-react";
|
|
1347
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1348
|
+
var TerminalOverlay = ({ state, theme }) => /* @__PURE__ */ jsxs3("div", {
|
|
1349
|
+
style: {
|
|
1350
|
+
position: "absolute",
|
|
1351
|
+
top: 0,
|
|
1352
|
+
left: 0,
|
|
1353
|
+
right: 0,
|
|
1354
|
+
bottom: 0,
|
|
1355
|
+
display: "flex",
|
|
1356
|
+
flexDirection: "column",
|
|
1357
|
+
alignItems: "center",
|
|
1358
|
+
justifyContent: "center",
|
|
1359
|
+
backgroundColor: theme.colors.background,
|
|
1360
|
+
opacity: state.opacity ?? 1,
|
|
1361
|
+
gap: "16px",
|
|
1362
|
+
padding: "32px",
|
|
1363
|
+
zIndex: 10
|
|
1364
|
+
},
|
|
1365
|
+
children: [
|
|
1366
|
+
/* @__PURE__ */ jsx5(Monitor2, {
|
|
1367
|
+
size: 48,
|
|
1368
|
+
color: theme.colors.textSecondary
|
|
1369
|
+
}),
|
|
1370
|
+
/* @__PURE__ */ jsx5("div", {
|
|
1371
|
+
style: {
|
|
1372
|
+
fontSize: "16px",
|
|
1373
|
+
fontWeight: "500",
|
|
1374
|
+
color: theme.colors.text,
|
|
1375
|
+
textAlign: "center"
|
|
1376
|
+
},
|
|
1377
|
+
children: state.message
|
|
1378
|
+
}),
|
|
1379
|
+
state.subtitle && /* @__PURE__ */ jsx5("div", {
|
|
1380
|
+
style: {
|
|
1381
|
+
fontSize: "14px",
|
|
1382
|
+
color: theme.colors.textSecondary,
|
|
1383
|
+
textAlign: "center",
|
|
1384
|
+
maxWidth: "400px"
|
|
1385
|
+
},
|
|
1386
|
+
children: state.subtitle
|
|
1387
|
+
}),
|
|
1388
|
+
state.actions && state.actions.length > 0 && /* @__PURE__ */ jsx5("div", {
|
|
1389
|
+
style: {
|
|
1390
|
+
display: "flex",
|
|
1391
|
+
gap: "12px",
|
|
1392
|
+
marginTop: "8px"
|
|
1393
|
+
},
|
|
1394
|
+
children: state.actions.map((action) => /* @__PURE__ */ jsxs3("button", {
|
|
1395
|
+
type: "button",
|
|
1396
|
+
onClick: action.onClick,
|
|
1397
|
+
style: {
|
|
1398
|
+
padding: "8px 16px",
|
|
1399
|
+
backgroundColor: action.primary ? theme.colors.primary : "transparent",
|
|
1400
|
+
color: action.primary ? "#ffffff" : theme.colors.text,
|
|
1401
|
+
border: action.primary ? "none" : `1px solid ${theme.colors.border}`,
|
|
1402
|
+
borderRadius: "6px",
|
|
1403
|
+
cursor: "pointer",
|
|
1404
|
+
fontSize: "14px",
|
|
1405
|
+
fontWeight: "500",
|
|
1406
|
+
display: "flex",
|
|
1407
|
+
alignItems: "center",
|
|
1408
|
+
gap: "8px",
|
|
1409
|
+
transition: "all 0.2s"
|
|
1410
|
+
},
|
|
1411
|
+
onMouseEnter: (e) => {
|
|
1412
|
+
if (action.primary) {
|
|
1413
|
+
e.currentTarget.style.opacity = "0.8";
|
|
1414
|
+
} else {
|
|
1415
|
+
e.currentTarget.style.backgroundColor = theme.colors.backgroundSecondary;
|
|
1416
|
+
}
|
|
1417
|
+
},
|
|
1418
|
+
onMouseLeave: (e) => {
|
|
1419
|
+
if (action.primary) {
|
|
1420
|
+
e.currentTarget.style.opacity = "1";
|
|
1421
|
+
} else {
|
|
1422
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
1423
|
+
}
|
|
1424
|
+
},
|
|
1425
|
+
children: [
|
|
1426
|
+
action.icon,
|
|
1427
|
+
action.label
|
|
1428
|
+
]
|
|
1429
|
+
}, action.label))
|
|
1430
|
+
})
|
|
1431
|
+
]
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
// src/components/TerminalSession.tsx
|
|
1435
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1436
|
+
var TerminalSession = forwardRef4((props, ref) => {
|
|
1437
|
+
const {
|
|
1438
|
+
actions,
|
|
1439
|
+
renderer: Renderer = XtermRenderer,
|
|
1440
|
+
transparent,
|
|
1441
|
+
backgroundColor,
|
|
1442
|
+
defaultScrollLocked,
|
|
1443
|
+
autoFocus = true,
|
|
1444
|
+
isVisible = true,
|
|
1445
|
+
scrollback = 1e4,
|
|
1446
|
+
sessionId: sessionIdProp = null,
|
|
1447
|
+
onSessionCreated,
|
|
1448
|
+
cwd,
|
|
1449
|
+
command,
|
|
1450
|
+
sessionContext,
|
|
1451
|
+
persistOnUnmount = false,
|
|
1452
|
+
enableOwnership = false,
|
|
1453
|
+
isForeign = false,
|
|
1454
|
+
events,
|
|
1455
|
+
activityDetection = false,
|
|
1456
|
+
activityTimeout = 500,
|
|
1457
|
+
onActivityChange,
|
|
1458
|
+
onScrollPositionChange,
|
|
1459
|
+
onLinkClick,
|
|
1460
|
+
onShortcut,
|
|
1461
|
+
overlayState,
|
|
1462
|
+
isWorking = false,
|
|
1463
|
+
workingMessage,
|
|
1464
|
+
workingSubtitle
|
|
1465
|
+
} = props;
|
|
1466
|
+
const { theme } = useTheme2();
|
|
1467
|
+
const rendererRef = useRef3(null);
|
|
1468
|
+
const [localSessionId, setLocalSessionId] = useState2(sessionIdProp);
|
|
1469
|
+
const [isInitialized, setIsInitialized] = useState2(false);
|
|
1470
|
+
const hasInitializedRef = useRef3(false);
|
|
1471
|
+
const pendingSessionIdRef = useRef3(null);
|
|
1472
|
+
const [shouldRenderTerminal, setShouldRenderTerminal] = useState2(true);
|
|
1473
|
+
const [ownerWindowId, setOwnerWindowId] = useState2(null);
|
|
1474
|
+
const needsRefreshOnResizeRef = useRef3(false);
|
|
1475
|
+
const [scrollPosition, setScrollPosition] = useState2({
|
|
1476
|
+
isAtTop: false,
|
|
1477
|
+
isAtBottom: true,
|
|
1478
|
+
isScrollLocked: defaultScrollLocked ?? false
|
|
1479
|
+
});
|
|
1480
|
+
const isActiveRef = useRef3(false);
|
|
1481
|
+
const activityStartedAtRef = useRef3(0);
|
|
1482
|
+
const activityTimerRef = useRef3(null);
|
|
1483
|
+
const claimAndConnect = useCallback2(async (targetSessionId, force = false) => {
|
|
1484
|
+
if (!enableOwnership)
|
|
1485
|
+
return;
|
|
1486
|
+
try {
|
|
1487
|
+
if (actions.claimTerminalOwnership) {
|
|
1488
|
+
await actions.claimTerminalOwnership(targetSessionId, force);
|
|
1489
|
+
}
|
|
1490
|
+
if (force && actions.requestTerminalDataPort) {
|
|
1491
|
+
await actions.requestTerminalDataPort(targetSessionId);
|
|
1492
|
+
}
|
|
1493
|
+
setShouldRenderTerminal(true);
|
|
1494
|
+
setOwnerWindowId(null);
|
|
1495
|
+
if (force) {
|
|
1496
|
+
needsRefreshOnResizeRef.current = true;
|
|
1497
|
+
}
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
console.error("[TerminalSession] Failed to claim ownership:", error);
|
|
1500
|
+
throw error;
|
|
1501
|
+
}
|
|
1502
|
+
}, [actions, enableOwnership]);
|
|
1503
|
+
useEffect2(() => {
|
|
1504
|
+
if (hasInitializedRef.current)
|
|
1505
|
+
return;
|
|
1506
|
+
hasInitializedRef.current = true;
|
|
1507
|
+
let mounted = true;
|
|
1508
|
+
const tracer = getTracer();
|
|
1509
|
+
const init = async () => {
|
|
1510
|
+
try {
|
|
1511
|
+
if (sessionIdProp) {
|
|
1512
|
+
const span2 = tracer.startSpan("terminal.session.reconnect", {
|
|
1513
|
+
attributes: {
|
|
1514
|
+
"session.id": sessionIdProp,
|
|
1515
|
+
"session.context": sessionContext ?? "",
|
|
1516
|
+
"session.isForeign": isForeign
|
|
1517
|
+
}
|
|
1518
|
+
});
|
|
1519
|
+
if (enableOwnership) {
|
|
1520
|
+
if (isForeign && actions.checkTerminalOwnership) {
|
|
1521
|
+
const status = await actions.checkTerminalOwnership(sessionIdProp);
|
|
1522
|
+
if (status.ownedByWindowId && !status.ownedByThisWindow) {
|
|
1523
|
+
setShouldRenderTerminal(false);
|
|
1524
|
+
setOwnerWindowId(status.ownedByWindowId);
|
|
1525
|
+
span2.addEvent("terminal.session.reconnect_blocked", {
|
|
1526
|
+
"owner.windowId": status.ownedByWindowId
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
} else {
|
|
1530
|
+
await claimAndConnect(sessionIdProp);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (mounted) {
|
|
1534
|
+
setLocalSessionId(sessionIdProp);
|
|
1535
|
+
setIsInitialized(true);
|
|
1536
|
+
}
|
|
1537
|
+
span2.setStatus({ code: SpanStatusCode.OK });
|
|
1538
|
+
span2.end();
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
if (!actions.createTerminalSession) {
|
|
1542
|
+
if (mounted)
|
|
1543
|
+
setIsInitialized(true);
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
const span = tracer.startSpan("terminal.session.create", {
|
|
1547
|
+
attributes: {
|
|
1548
|
+
"session.cwd": cwd ?? "",
|
|
1549
|
+
"session.context": sessionContext ?? ""
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1552
|
+
const newId = await actions.createTerminalSession({
|
|
1553
|
+
cwd,
|
|
1554
|
+
command,
|
|
1555
|
+
context: sessionContext
|
|
1556
|
+
});
|
|
1557
|
+
pendingSessionIdRef.current = newId;
|
|
1558
|
+
span.setAttribute("session.id", newId);
|
|
1559
|
+
if (!mounted) {
|
|
1560
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1561
|
+
span.end();
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
if (enableOwnership) {
|
|
1565
|
+
await claimAndConnect(newId);
|
|
1566
|
+
}
|
|
1567
|
+
setLocalSessionId(newId);
|
|
1568
|
+
setIsInitialized(true);
|
|
1569
|
+
onSessionCreated?.(newId);
|
|
1570
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1571
|
+
span.end();
|
|
1572
|
+
} catch (err) {
|
|
1573
|
+
console.error("[TerminalSession] init failed:", err);
|
|
1574
|
+
const errSpan = tracer.startSpan("terminal.session.error", {
|
|
1575
|
+
attributes: {
|
|
1576
|
+
"session.context": sessionContext ?? "",
|
|
1577
|
+
"session.action": sessionIdProp ? "reconnect" : "create"
|
|
1578
|
+
}
|
|
1579
|
+
});
|
|
1580
|
+
errSpan.recordException(err);
|
|
1581
|
+
errSpan.setStatus({
|
|
1582
|
+
code: SpanStatusCode.ERROR,
|
|
1583
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
|
1584
|
+
});
|
|
1585
|
+
errSpan.end();
|
|
1586
|
+
if (mounted)
|
|
1587
|
+
setIsInitialized(true);
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
init();
|
|
1591
|
+
return () => {
|
|
1592
|
+
mounted = false;
|
|
1593
|
+
if (!persistOnUnmount && pendingSessionIdRef.current && actions.destroyTerminalSession) {
|
|
1594
|
+
const tracer2 = getTracer();
|
|
1595
|
+
const span = tracer2.startSpan("terminal.session.destroy", {
|
|
1596
|
+
attributes: { "session.id": pendingSessionIdRef.current }
|
|
1597
|
+
});
|
|
1598
|
+
Promise.resolve(actions.destroyTerminalSession(pendingSessionIdRef.current)).then(() => {
|
|
1599
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1600
|
+
span.end();
|
|
1601
|
+
}).catch((err) => {
|
|
1602
|
+
span.recordException(err);
|
|
1603
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1604
|
+
span.end();
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
};
|
|
1608
|
+
}, []);
|
|
1609
|
+
const observeActivity = useCallback2(() => {
|
|
1610
|
+
if (!activityDetection)
|
|
1611
|
+
return;
|
|
1612
|
+
const now = Date.now();
|
|
1613
|
+
const emitBus = (isWorking2) => {
|
|
1614
|
+
if (!events || !localSessionId)
|
|
1615
|
+
return;
|
|
1616
|
+
events.emit({
|
|
1617
|
+
type: "terminal:activity-changed",
|
|
1618
|
+
source: "TerminalSession",
|
|
1619
|
+
timestamp: Date.now(),
|
|
1620
|
+
payload: {
|
|
1621
|
+
sessionId: localSessionId,
|
|
1622
|
+
activityType: isWorking2 ? "started" : "stopped",
|
|
1623
|
+
isWorking: isWorking2
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
};
|
|
1627
|
+
if (!isActiveRef.current) {
|
|
1628
|
+
isActiveRef.current = true;
|
|
1629
|
+
activityStartedAtRef.current = now;
|
|
1630
|
+
onActivityChange?.({ isActive: true, startedAt: now });
|
|
1631
|
+
emitBus(true);
|
|
1632
|
+
}
|
|
1633
|
+
if (activityTimerRef.current)
|
|
1634
|
+
clearTimeout(activityTimerRef.current);
|
|
1635
|
+
activityTimerRef.current = setTimeout(() => {
|
|
1636
|
+
if (isActiveRef.current) {
|
|
1637
|
+
isActiveRef.current = false;
|
|
1638
|
+
onActivityChange?.({
|
|
1639
|
+
isActive: false,
|
|
1640
|
+
duration: Date.now() - activityStartedAtRef.current
|
|
1641
|
+
});
|
|
1642
|
+
emitBus(false);
|
|
1643
|
+
}
|
|
1644
|
+
}, activityTimeout);
|
|
1645
|
+
}, [activityDetection, activityTimeout, onActivityChange, events, localSessionId]);
|
|
1646
|
+
useEffect2(() => {
|
|
1647
|
+
if (!localSessionId || !isInitialized || !shouldRenderTerminal)
|
|
1648
|
+
return;
|
|
1649
|
+
if (!actions.onTerminalData)
|
|
1650
|
+
return;
|
|
1651
|
+
const unsubscribe = actions.onTerminalData(localSessionId, (data) => {
|
|
1652
|
+
rendererRef.current?.write(data);
|
|
1653
|
+
observeActivity();
|
|
1654
|
+
});
|
|
1655
|
+
return () => {
|
|
1656
|
+
unsubscribe();
|
|
1657
|
+
};
|
|
1658
|
+
}, [localSessionId, isInitialized, shouldRenderTerminal, actions, observeActivity]);
|
|
1659
|
+
useEffect2(() => {
|
|
1660
|
+
return () => {
|
|
1661
|
+
if (activityTimerRef.current)
|
|
1662
|
+
clearTimeout(activityTimerRef.current);
|
|
1663
|
+
};
|
|
1664
|
+
}, []);
|
|
1665
|
+
const handleData = useCallback2((data) => {
|
|
1666
|
+
if (localSessionId && actions.writeToTerminal) {
|
|
1667
|
+
actions.writeToTerminal(localSessionId, data);
|
|
1668
|
+
}
|
|
1669
|
+
}, [localSessionId, actions]);
|
|
1670
|
+
const handleResize = useCallback2((cols, rows) => {
|
|
1671
|
+
if (localSessionId && actions.resizeTerminal) {
|
|
1672
|
+
actions.resizeTerminal(localSessionId, cols, rows);
|
|
1673
|
+
}
|
|
1674
|
+
}, [localSessionId, actions]);
|
|
1675
|
+
const handleReady = useCallback2((cols, rows) => {
|
|
1676
|
+
if (!localSessionId || !actions.resizeTerminal)
|
|
1677
|
+
return;
|
|
1678
|
+
const shouldForce = needsRefreshOnResizeRef.current;
|
|
1679
|
+
if (!shouldForce) {
|
|
1680
|
+
actions.resizeTerminal(localSessionId, cols, rows, false);
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
needsRefreshOnResizeRef.current = false;
|
|
1684
|
+
const restoreAndResize = async () => {
|
|
1685
|
+
let bufferRestored = false;
|
|
1686
|
+
if (actions.getTerminalBuffer && rendererRef.current) {
|
|
1687
|
+
try {
|
|
1688
|
+
const buffer = await actions.getTerminalBuffer(localSessionId);
|
|
1689
|
+
if (buffer) {
|
|
1690
|
+
rendererRef.current.write(buffer);
|
|
1691
|
+
bufferRestored = true;
|
|
1692
|
+
}
|
|
1693
|
+
} catch (err) {
|
|
1694
|
+
console.warn("[TerminalSession] Failed to restore buffer:", err);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
actions.resizeTerminal(localSessionId, cols, rows, !bufferRestored);
|
|
1698
|
+
};
|
|
1699
|
+
restoreAndResize();
|
|
1700
|
+
}, [localSessionId, actions]);
|
|
1701
|
+
const handleLinkClickInternal = useCallback2((url, modifiers) => {
|
|
1702
|
+
onLinkClick?.(url, modifiers);
|
|
1703
|
+
if (localSessionId && events) {
|
|
1704
|
+
events.emit({
|
|
1705
|
+
type: "terminal:link-click",
|
|
1706
|
+
source: "TerminalSession",
|
|
1707
|
+
timestamp: Date.now(),
|
|
1708
|
+
payload: {
|
|
1709
|
+
url,
|
|
1710
|
+
sessionId: localSessionId,
|
|
1711
|
+
shiftKey: modifiers.shiftKey,
|
|
1712
|
+
metaKey: modifiers.metaKey,
|
|
1713
|
+
ctrlKey: modifiers.ctrlKey,
|
|
1714
|
+
altKey: modifiers.altKey
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
}, [localSessionId, events, onLinkClick]);
|
|
1719
|
+
const handleShortcutInternal = useCallback2((evt) => {
|
|
1720
|
+
onShortcut?.(evt);
|
|
1721
|
+
if (localSessionId && events) {
|
|
1722
|
+
events.emit({
|
|
1723
|
+
type: "terminal:shortcut",
|
|
1724
|
+
source: "TerminalSession",
|
|
1725
|
+
timestamp: Date.now(),
|
|
1726
|
+
payload: {
|
|
1727
|
+
shortcut: evt.shortcut,
|
|
1728
|
+
sessionId: localSessionId
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
}, [localSessionId, events, onShortcut]);
|
|
1733
|
+
const handleScrollPositionChangeInternal = useCallback2((p) => {
|
|
1734
|
+
setScrollPosition(p);
|
|
1735
|
+
onScrollPositionChange?.(p);
|
|
1736
|
+
}, [onScrollPositionChange]);
|
|
1737
|
+
useEffect2(() => {
|
|
1738
|
+
if (!enableOwnership)
|
|
1739
|
+
return;
|
|
1740
|
+
if (!localSessionId || !actions.onOwnershipLost)
|
|
1741
|
+
return;
|
|
1742
|
+
const unsubscribe = actions.onOwnershipLost((data) => {
|
|
1743
|
+
if (data.sessionId === localSessionId) {
|
|
1744
|
+
setShouldRenderTerminal(false);
|
|
1745
|
+
setOwnerWindowId(data.newOwnerWindowId);
|
|
1746
|
+
}
|
|
1747
|
+
});
|
|
1748
|
+
return () => {
|
|
1749
|
+
unsubscribe();
|
|
1750
|
+
};
|
|
1751
|
+
}, [enableOwnership, localSessionId, actions]);
|
|
1752
|
+
const handleTakeControl = useCallback2(async () => {
|
|
1753
|
+
if (!localSessionId)
|
|
1754
|
+
return;
|
|
1755
|
+
await claimAndConnect(localSessionId, true);
|
|
1756
|
+
}, [localSessionId, claimAndConnect]);
|
|
1757
|
+
useImperativeHandle3(ref, () => ({
|
|
1758
|
+
scrollToBottom: () => rendererRef.current?.scrollToBottom(),
|
|
1759
|
+
toggleScrollLock: () => {
|
|
1760
|
+
if (scrollPosition.isScrollLocked) {
|
|
1761
|
+
rendererRef.current?.scrollLines(-1);
|
|
1762
|
+
} else {
|
|
1763
|
+
rendererRef.current?.scrollToBottom();
|
|
1764
|
+
}
|
|
1765
|
+
},
|
|
1766
|
+
focus: () => rendererRef.current?.focus(),
|
|
1767
|
+
clear: () => rendererRef.current?.clear(),
|
|
1768
|
+
getSessionId: () => localSessionId
|
|
1769
|
+
}), [scrollPosition.isScrollLocked, localSessionId]);
|
|
1770
|
+
if (!isInitialized) {
|
|
1771
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
1772
|
+
style: {
|
|
1773
|
+
display: "flex",
|
|
1774
|
+
height: "100%",
|
|
1775
|
+
width: "100%",
|
|
1776
|
+
backgroundColor: transparent ? "transparent" : theme.colors.background,
|
|
1777
|
+
padding: "10px 0 0 10px"
|
|
1778
|
+
},
|
|
1779
|
+
children: [
|
|
1780
|
+
/* @__PURE__ */ jsx6("div", {
|
|
1781
|
+
style: {
|
|
1782
|
+
width: "8px",
|
|
1783
|
+
height: "17px",
|
|
1784
|
+
backgroundColor: theme.colors.text,
|
|
1785
|
+
animation: "terminal-session-cursor-blink 1s step-end infinite"
|
|
1786
|
+
}
|
|
1787
|
+
}),
|
|
1788
|
+
/* @__PURE__ */ jsx6("style", {
|
|
1789
|
+
children: `@keyframes terminal-session-cursor-blink {
|
|
1790
|
+
0%, 100% { opacity: 1; }
|
|
1791
|
+
50% { opacity: 0; }
|
|
1792
|
+
}`
|
|
1793
|
+
})
|
|
1794
|
+
]
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
const ownershipLostOverlay = enableOwnership && !shouldRenderTerminal ? {
|
|
1798
|
+
message: "This terminal is active in another window",
|
|
1799
|
+
subtitle: ownerWindowId ? `Window ID: ${ownerWindowId}` : "Another window owns this terminal session",
|
|
1800
|
+
actions: [
|
|
1801
|
+
{
|
|
1802
|
+
label: "Take Control",
|
|
1803
|
+
onClick: handleTakeControl,
|
|
1804
|
+
primary: true
|
|
1805
|
+
}
|
|
1806
|
+
],
|
|
1807
|
+
opacity: 1
|
|
1808
|
+
} : undefined;
|
|
1809
|
+
const effectiveOverlay = ownershipLostOverlay ?? overlayState;
|
|
1810
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
1811
|
+
style: { position: "relative", height: "100%", width: "100%" },
|
|
1812
|
+
children: [
|
|
1813
|
+
/* @__PURE__ */ jsx6(Renderer, {
|
|
1814
|
+
ref: rendererRef,
|
|
1815
|
+
onData: shouldRenderTerminal ? handleData : undefined,
|
|
1816
|
+
onResize: shouldRenderTerminal ? handleResize : undefined,
|
|
1817
|
+
onReady: shouldRenderTerminal ? handleReady : undefined,
|
|
1818
|
+
onLinkClick: shouldRenderTerminal ? handleLinkClickInternal : undefined,
|
|
1819
|
+
onScrollPositionChange: shouldRenderTerminal ? handleScrollPositionChangeInternal : undefined,
|
|
1820
|
+
onShortcut: handleShortcutInternal,
|
|
1821
|
+
autoFocus: autoFocus && shouldRenderTerminal,
|
|
1822
|
+
isVisible,
|
|
1823
|
+
defaultScrollLocked,
|
|
1824
|
+
scrollback,
|
|
1825
|
+
transparent,
|
|
1826
|
+
backgroundColor
|
|
1827
|
+
}, shouldRenderTerminal ? "active" : "overlay"),
|
|
1828
|
+
effectiveOverlay && /* @__PURE__ */ jsx6(TerminalOverlay, {
|
|
1829
|
+
state: effectiveOverlay,
|
|
1830
|
+
theme
|
|
1831
|
+
}),
|
|
1832
|
+
isWorking && !effectiveOverlay && /* @__PURE__ */ jsx6(WorkingOverlay, {
|
|
1833
|
+
theme,
|
|
1834
|
+
message: workingMessage,
|
|
1835
|
+
subtitle: workingSubtitle
|
|
1836
|
+
})
|
|
1837
|
+
]
|
|
1838
|
+
});
|
|
1839
|
+
});
|
|
1840
|
+
TerminalSession.displayName = "TerminalSession";
|
|
1841
|
+
// src/hooks/useThemedTerminal.ts
|
|
1842
|
+
import { useTheme as useTheme3 } from "@principal-ade/industry-theme";
|
|
1286
1843
|
import { useMemo } from "react";
|
|
1287
1844
|
function useThemedTerminal() {
|
|
1288
|
-
const { theme } =
|
|
1845
|
+
const { theme } = useTheme3();
|
|
1289
1846
|
const terminalOptions = useMemo(() => ({
|
|
1290
1847
|
cursorBlink: true,
|
|
1291
1848
|
fontSize: 14,
|
|
@@ -1317,14 +1874,14 @@ function useThemedTerminal() {
|
|
|
1317
1874
|
};
|
|
1318
1875
|
}
|
|
1319
1876
|
// src/components/TabBar/TabBar.tsx
|
|
1320
|
-
import { useTheme as
|
|
1877
|
+
import { useTheme as useTheme5 } from "@principal-ade/industry-theme";
|
|
1321
1878
|
import { Plus } from "lucide-react";
|
|
1322
|
-
import { useState as
|
|
1879
|
+
import { useState as useState3, useCallback as useCallback4 } from "react";
|
|
1323
1880
|
|
|
1324
1881
|
// src/components/TabBar/TabButton.tsx
|
|
1325
|
-
import { useTheme as
|
|
1326
|
-
import { useCallback as
|
|
1327
|
-
import { jsx as
|
|
1882
|
+
import { useTheme as useTheme4 } from "@principal-ade/industry-theme";
|
|
1883
|
+
import { useCallback as useCallback3 } from "react";
|
|
1884
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1328
1885
|
var TabButton = ({
|
|
1329
1886
|
tab,
|
|
1330
1887
|
isActive,
|
|
@@ -1347,10 +1904,10 @@ var TabButton = ({
|
|
|
1347
1904
|
onDragLeave,
|
|
1348
1905
|
isBeingDragged: _isBeingDragged = false
|
|
1349
1906
|
}) => {
|
|
1350
|
-
const { theme } =
|
|
1907
|
+
const { theme } = useTheme4();
|
|
1351
1908
|
const showCloseButton = isHovered || isActive;
|
|
1352
1909
|
const closable = tab.closable !== false;
|
|
1353
|
-
const handleDragStart =
|
|
1910
|
+
const handleDragStart = useCallback3((e) => {
|
|
1354
1911
|
const target = e.currentTarget;
|
|
1355
1912
|
e.dataTransfer.setData("application/x-tab-association", tab.id);
|
|
1356
1913
|
e.dataTransfer.effectAllowed = "move";
|
|
@@ -1375,27 +1932,27 @@ var TabButton = ({
|
|
|
1375
1932
|
}
|
|
1376
1933
|
onDragStart?.(tab.id);
|
|
1377
1934
|
}, [tab.id, onDragStart]);
|
|
1378
|
-
const handleDragEnd =
|
|
1935
|
+
const handleDragEnd = useCallback3(() => {
|
|
1379
1936
|
onDragEnd?.();
|
|
1380
1937
|
}, [onDragEnd]);
|
|
1381
|
-
const handleDragOver =
|
|
1938
|
+
const handleDragOver = useCallback3((e) => {
|
|
1382
1939
|
if (canAcceptDrop) {
|
|
1383
1940
|
e.preventDefault();
|
|
1384
1941
|
e.dataTransfer.dropEffect = "move";
|
|
1385
1942
|
}
|
|
1386
1943
|
}, [canAcceptDrop]);
|
|
1387
|
-
const handleDrop =
|
|
1944
|
+
const handleDrop = useCallback3((e) => {
|
|
1388
1945
|
e.preventDefault();
|
|
1389
1946
|
const draggedTabId = e.dataTransfer.getData("application/x-tab-association");
|
|
1390
1947
|
if (draggedTabId && draggedTabId !== tab.id) {
|
|
1391
1948
|
onDrop?.(draggedTabId);
|
|
1392
1949
|
}
|
|
1393
1950
|
}, [tab.id, onDrop]);
|
|
1394
|
-
const handleDragEnter =
|
|
1951
|
+
const handleDragEnter = useCallback3((e) => {
|
|
1395
1952
|
e.preventDefault();
|
|
1396
1953
|
onDragEnter?.();
|
|
1397
1954
|
}, [onDragEnter]);
|
|
1398
|
-
const handleDragLeave =
|
|
1955
|
+
const handleDragLeave = useCallback3((e) => {
|
|
1399
1956
|
e.preventDefault();
|
|
1400
1957
|
onDragLeave?.();
|
|
1401
1958
|
}, [onDragLeave]);
|
|
@@ -1409,7 +1966,7 @@ var TabButton = ({
|
|
|
1409
1966
|
}
|
|
1410
1967
|
return {};
|
|
1411
1968
|
};
|
|
1412
|
-
return /* @__PURE__ */
|
|
1969
|
+
return /* @__PURE__ */ jsxs5("div", {
|
|
1413
1970
|
"data-tab-id": tab.id,
|
|
1414
1971
|
draggable,
|
|
1415
1972
|
onDragStart: draggable ? handleDragStart : undefined,
|
|
@@ -1445,7 +2002,7 @@ var TabButton = ({
|
|
|
1445
2002
|
...getDragOverStyles()
|
|
1446
2003
|
},
|
|
1447
2004
|
children: [
|
|
1448
|
-
closable && showCloseButton && /* @__PURE__ */
|
|
2005
|
+
closable && showCloseButton && /* @__PURE__ */ jsx7("button", {
|
|
1449
2006
|
onClick: (e) => {
|
|
1450
2007
|
e.stopPropagation();
|
|
1451
2008
|
onClose();
|
|
@@ -1477,7 +2034,7 @@ var TabButton = ({
|
|
|
1477
2034
|
(() => {
|
|
1478
2035
|
const icon = renderIcon ? renderIcon(tab) : undefined;
|
|
1479
2036
|
const displayIcon = icon !== undefined ? icon : tab.icon;
|
|
1480
|
-
return displayIcon ? /* @__PURE__ */
|
|
2037
|
+
return displayIcon ? /* @__PURE__ */ jsx7("div", {
|
|
1481
2038
|
style: { flexShrink: 0, display: "flex", alignItems: "center", pointerEvents: "none" },
|
|
1482
2039
|
children: displayIcon
|
|
1483
2040
|
}) : null;
|
|
@@ -1485,7 +2042,7 @@ var TabButton = ({
|
|
|
1485
2042
|
(() => {
|
|
1486
2043
|
const label = renderLabel ? renderLabel(tab) : undefined;
|
|
1487
2044
|
const displayLabel = label !== undefined ? label : tab.label;
|
|
1488
|
-
return /* @__PURE__ */
|
|
2045
|
+
return /* @__PURE__ */ jsx7("span", {
|
|
1489
2046
|
style: {
|
|
1490
2047
|
overflow: "hidden",
|
|
1491
2048
|
textOverflow: "ellipsis",
|
|
@@ -1496,7 +2053,7 @@ var TabButton = ({
|
|
|
1496
2053
|
children: displayLabel
|
|
1497
2054
|
});
|
|
1498
2055
|
})(),
|
|
1499
|
-
renderAccessory ? renderAccessory(tab) : keyboardHint && /* @__PURE__ */
|
|
2056
|
+
renderAccessory ? renderAccessory(tab) : keyboardHint && /* @__PURE__ */ jsx7("span", {
|
|
1500
2057
|
style: {
|
|
1501
2058
|
fontSize: theme.fontSizes[0],
|
|
1502
2059
|
color: theme.colors.textSecondary,
|
|
@@ -1511,7 +2068,7 @@ var TabButton = ({
|
|
|
1511
2068
|
TabButton.displayName = "TabButton";
|
|
1512
2069
|
|
|
1513
2070
|
// src/components/TabBar/TabBar.tsx
|
|
1514
|
-
import { jsx as
|
|
2071
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1515
2072
|
var TabBar = ({
|
|
1516
2073
|
tabs,
|
|
1517
2074
|
activeTabId,
|
|
@@ -1529,31 +2086,31 @@ var TabBar = ({
|
|
|
1529
2086
|
canDropOnTab,
|
|
1530
2087
|
enableDragAndDrop = false
|
|
1531
2088
|
}) => {
|
|
1532
|
-
const { theme } =
|
|
1533
|
-
const [hoveredTabId, setHoveredTabId] =
|
|
1534
|
-
const [draggedTabId, setDraggedTabId] =
|
|
1535
|
-
const [dragOverTabId, setDragOverTabId] =
|
|
1536
|
-
const handleDragStart =
|
|
2089
|
+
const { theme } = useTheme5();
|
|
2090
|
+
const [hoveredTabId, setHoveredTabId] = useState3(null);
|
|
2091
|
+
const [draggedTabId, setDraggedTabId] = useState3(null);
|
|
2092
|
+
const [dragOverTabId, setDragOverTabId] = useState3(null);
|
|
2093
|
+
const handleDragStart = useCallback4((tabId) => {
|
|
1537
2094
|
setDraggedTabId(tabId);
|
|
1538
2095
|
}, []);
|
|
1539
|
-
const handleDragEnd =
|
|
2096
|
+
const handleDragEnd = useCallback4(() => {
|
|
1540
2097
|
setDraggedTabId(null);
|
|
1541
2098
|
setDragOverTabId(null);
|
|
1542
2099
|
}, []);
|
|
1543
|
-
const handleDrop =
|
|
2100
|
+
const handleDrop = useCallback4((targetTabId, draggedId) => {
|
|
1544
2101
|
if (draggedId !== targetTabId) {
|
|
1545
2102
|
onTabDrop?.(draggedId, targetTabId);
|
|
1546
2103
|
}
|
|
1547
2104
|
setDraggedTabId(null);
|
|
1548
2105
|
setDragOverTabId(null);
|
|
1549
2106
|
}, [onTabDrop]);
|
|
1550
|
-
const handleDragEnter =
|
|
2107
|
+
const handleDragEnter = useCallback4((tabId) => {
|
|
1551
2108
|
setDragOverTabId(tabId);
|
|
1552
2109
|
}, []);
|
|
1553
|
-
const handleDragLeave =
|
|
2110
|
+
const handleDragLeave = useCallback4(() => {
|
|
1554
2111
|
setDragOverTabId(null);
|
|
1555
2112
|
}, []);
|
|
1556
|
-
return /* @__PURE__ */
|
|
2113
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
1557
2114
|
className,
|
|
1558
2115
|
style: {
|
|
1559
2116
|
display: "flex",
|
|
@@ -1563,7 +2120,7 @@ var TabBar = ({
|
|
|
1563
2120
|
boxSizing: "border-box"
|
|
1564
2121
|
},
|
|
1565
2122
|
children: [
|
|
1566
|
-
leftSection && /* @__PURE__ */
|
|
2123
|
+
leftSection && /* @__PURE__ */ jsx8("div", {
|
|
1567
2124
|
style: {
|
|
1568
2125
|
display: "flex",
|
|
1569
2126
|
alignItems: "center",
|
|
@@ -1576,7 +2133,7 @@ var TabBar = ({
|
|
|
1576
2133
|
},
|
|
1577
2134
|
children: leftSection
|
|
1578
2135
|
}),
|
|
1579
|
-
/* @__PURE__ */
|
|
2136
|
+
/* @__PURE__ */ jsx8("div", {
|
|
1580
2137
|
style: {
|
|
1581
2138
|
display: "flex",
|
|
1582
2139
|
alignItems: "center",
|
|
@@ -1588,7 +2145,7 @@ var TabBar = ({
|
|
|
1588
2145
|
},
|
|
1589
2146
|
children: tabs.map((tab, index) => {
|
|
1590
2147
|
const canDrop = enableDragAndDrop && draggedTabId !== null && draggedTabId !== tab.id ? canDropOnTab ? canDropOnTab(draggedTabId, tab.id) : true : false;
|
|
1591
|
-
return /* @__PURE__ */
|
|
2148
|
+
return /* @__PURE__ */ jsx8(TabButton, {
|
|
1592
2149
|
tab,
|
|
1593
2150
|
isActive: tab.id === activeTabId,
|
|
1594
2151
|
isHovered: tab.id === hoveredTabId,
|
|
@@ -1612,7 +2169,7 @@ var TabBar = ({
|
|
|
1612
2169
|
}, tab.id);
|
|
1613
2170
|
})
|
|
1614
2171
|
}),
|
|
1615
|
-
rightSection !== undefined ? rightSection && /* @__PURE__ */
|
|
2172
|
+
rightSection !== undefined ? rightSection && /* @__PURE__ */ jsx8("div", {
|
|
1616
2173
|
style: {
|
|
1617
2174
|
display: "flex",
|
|
1618
2175
|
alignItems: "center",
|
|
@@ -1624,7 +2181,7 @@ var TabBar = ({
|
|
|
1624
2181
|
boxSizing: "border-box"
|
|
1625
2182
|
},
|
|
1626
2183
|
children: rightSection
|
|
1627
|
-
}) : onNewTab && /* @__PURE__ */
|
|
2184
|
+
}) : onNewTab && /* @__PURE__ */ jsx8("div", {
|
|
1628
2185
|
style: {
|
|
1629
2186
|
display: "flex",
|
|
1630
2187
|
alignItems: "center",
|
|
@@ -1635,7 +2192,7 @@ var TabBar = ({
|
|
|
1635
2192
|
borderBottom: `1px solid ${theme.colors.border}`,
|
|
1636
2193
|
boxSizing: "border-box"
|
|
1637
2194
|
},
|
|
1638
|
-
children: /* @__PURE__ */
|
|
2195
|
+
children: /* @__PURE__ */ jsx8("button", {
|
|
1639
2196
|
onClick: onNewTab,
|
|
1640
2197
|
style: {
|
|
1641
2198
|
display: "flex",
|
|
@@ -1656,7 +2213,7 @@ var TabBar = ({
|
|
|
1656
2213
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1657
2214
|
},
|
|
1658
2215
|
title: "New Tab (⌘T)",
|
|
1659
|
-
children: /* @__PURE__ */
|
|
2216
|
+
children: /* @__PURE__ */ jsx8(Plus, {
|
|
1660
2217
|
size: 14
|
|
1661
2218
|
})
|
|
1662
2219
|
})
|
|
@@ -1670,14 +2227,14 @@ function isTabOfType(tab, contentType) {
|
|
|
1670
2227
|
return tab.contentType === contentType;
|
|
1671
2228
|
}
|
|
1672
2229
|
// src/hooks/useTabKeyboardShortcuts.ts
|
|
1673
|
-
import { useEffect as
|
|
2230
|
+
import { useEffect as useEffect3 } from "react";
|
|
1674
2231
|
var useTabKeyboardShortcuts = ({
|
|
1675
2232
|
onNewTab,
|
|
1676
2233
|
onCloseTab,
|
|
1677
2234
|
onSwitchToTab,
|
|
1678
2235
|
enabled = true
|
|
1679
2236
|
}) => {
|
|
1680
|
-
|
|
2237
|
+
useEffect3(() => {
|
|
1681
2238
|
if (!enabled)
|
|
1682
2239
|
return;
|
|
1683
2240
|
const handleKeyDown = (e) => {
|
|
@@ -1698,358 +2255,29 @@ var useTabKeyboardShortcuts = ({
|
|
|
1698
2255
|
e.preventDefault();
|
|
1699
2256
|
e.stopPropagation();
|
|
1700
2257
|
const index = parseInt(e.key, 10) - 1;
|
|
1701
|
-
onSwitchToTab(index);
|
|
1702
|
-
return;
|
|
1703
|
-
}
|
|
1704
|
-
};
|
|
1705
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1706
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1707
|
-
}, [enabled, onNewTab, onCloseTab, onSwitchToTab]);
|
|
1708
|
-
};
|
|
1709
|
-
// src/panels/TerminalPanel.tsx
|
|
1710
|
-
import { useTheme as useTheme5 } from "@principal-ade/industry-theme";
|
|
1711
|
-
import { Lock, Unlock, ArrowDown } from "lucide-react";
|
|
1712
|
-
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
1713
|
-
|
|
1714
|
-
// src/panel-types/index.ts
|
|
1715
|
-
function getTerminalSessions(context2) {
|
|
1716
|
-
return context2.terminal?.data ?? [];
|
|
1717
|
-
}
|
|
1718
|
-
function getTerminalSession(context2, sessionId) {
|
|
1719
|
-
const sessions = getTerminalSessions(context2);
|
|
1720
|
-
return sessions.find((s) => s.id === sessionId);
|
|
1721
|
-
}
|
|
1722
|
-
function isTerminalLoading(context2) {
|
|
1723
|
-
return context2.terminal?.loading ?? false;
|
|
1724
|
-
}
|
|
1725
|
-
function getRepositoryPath(context2) {
|
|
1726
|
-
return context2.currentScope.repository?.path ?? null;
|
|
1727
|
-
}
|
|
1728
|
-
function getWorkspacePath(context2) {
|
|
1729
|
-
return context2.currentScope.workspace?.path ?? null;
|
|
1730
|
-
}
|
|
1731
|
-
function getTerminalDirectory(context2, terminalScope = "repository") {
|
|
1732
|
-
switch (terminalScope) {
|
|
1733
|
-
case "workspace":
|
|
1734
|
-
return getWorkspacePath(context2);
|
|
1735
|
-
case "repository":
|
|
1736
|
-
return getRepositoryPath(context2) ?? getWorkspacePath(context2);
|
|
1737
|
-
default:
|
|
1738
|
-
return getRepositoryPath(context2) ?? getWorkspacePath(context2);
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
function getTerminalSlice(context2) {
|
|
1742
|
-
return context2.terminal;
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
// src/panels/TerminalPanel.tsx
|
|
1746
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1747
|
-
var TerminalPanel = ({
|
|
1748
|
-
context: context2,
|
|
1749
|
-
actions,
|
|
1750
|
-
events: _events,
|
|
1751
|
-
terminalScope = "repository",
|
|
1752
|
-
allowTransparency = false,
|
|
1753
|
-
backgroundColor
|
|
1754
|
-
}) => {
|
|
1755
|
-
const { theme } = useTheme5();
|
|
1756
|
-
const [sessionId, setSessionId] = useState3(null);
|
|
1757
|
-
const [error, setError] = useState3(null);
|
|
1758
|
-
const [isInitializing, setIsInitializing] = useState3(true);
|
|
1759
|
-
const [scrollPosition, setScrollPosition] = useState3({
|
|
1760
|
-
isAtTop: false,
|
|
1761
|
-
isAtBottom: true,
|
|
1762
|
-
isScrollLocked: false
|
|
1763
|
-
});
|
|
1764
|
-
const terminalRef = useRef2(null);
|
|
1765
|
-
const isScrollLockedRef = useRef2(scrollPosition.isScrollLocked);
|
|
1766
|
-
const terminalDirectory = getTerminalDirectory(context2, terminalScope);
|
|
1767
|
-
const pendingSessionIdRef = useRef2(null);
|
|
1768
|
-
useEffect3(() => {
|
|
1769
|
-
let mounted = true;
|
|
1770
|
-
const initTerminal = async () => {
|
|
1771
|
-
try {
|
|
1772
|
-
if (!actions.createTerminalSession) {
|
|
1773
|
-
throw new Error("Terminal actions not available. Host must provide createTerminalSession action.");
|
|
1774
|
-
}
|
|
1775
|
-
const id = await actions.createTerminalSession({
|
|
1776
|
-
cwd: terminalDirectory || undefined
|
|
1777
|
-
});
|
|
1778
|
-
pendingSessionIdRef.current = id;
|
|
1779
|
-
if (actions.claimTerminalOwnership) {
|
|
1780
|
-
await actions.claimTerminalOwnership(id);
|
|
1781
|
-
}
|
|
1782
|
-
if (mounted) {
|
|
1783
|
-
setSessionId(id);
|
|
1784
|
-
setIsInitializing(false);
|
|
1785
|
-
}
|
|
1786
|
-
} catch (err) {
|
|
1787
|
-
if (mounted) {
|
|
1788
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
1789
|
-
setIsInitializing(false);
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
};
|
|
1793
|
-
initTerminal();
|
|
1794
|
-
return () => {
|
|
1795
|
-
mounted = false;
|
|
1796
|
-
if (pendingSessionIdRef.current && actions.destroyTerminalSession) {
|
|
1797
|
-
actions.destroyTerminalSession(pendingSessionIdRef.current);
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1800
|
-
}, []);
|
|
1801
|
-
useEffect3(() => {
|
|
1802
|
-
if (!sessionId)
|
|
1803
|
-
return;
|
|
1804
|
-
if (!actions.onTerminalData) {
|
|
1805
|
-
setError("Host does not provide onTerminalData. Terminal data cannot be displayed.");
|
|
1806
|
-
return;
|
|
1807
|
-
}
|
|
1808
|
-
let cursorMovedToHome = false;
|
|
1809
|
-
let lastWriteTime = 0;
|
|
1810
|
-
let autoScrollTimeout = null;
|
|
1811
|
-
const unsubscribe = actions.onTerminalData(sessionId, (data) => {
|
|
1812
|
-
if (!terminalRef.current)
|
|
1813
|
-
return;
|
|
1814
|
-
if (data.includes("\x1B[H")) {
|
|
1815
|
-
cursorMovedToHome = true;
|
|
1816
|
-
lastWriteTime = Date.now();
|
|
1817
|
-
}
|
|
1818
|
-
terminalRef.current.write(data);
|
|
1819
|
-
if (cursorMovedToHome && isScrollLockedRef.current) {
|
|
1820
|
-
if (autoScrollTimeout)
|
|
1821
|
-
clearTimeout(autoScrollTimeout);
|
|
1822
|
-
autoScrollTimeout = setTimeout(() => {
|
|
1823
|
-
const timeSinceLastWrite = Date.now() - lastWriteTime;
|
|
1824
|
-
if (timeSinceLastWrite >= 100 && cursorMovedToHome && terminalRef.current) {
|
|
1825
|
-
terminalRef.current.write("\x1B[9999;1H");
|
|
1826
|
-
cursorMovedToHome = false;
|
|
1827
|
-
}
|
|
1828
|
-
}, 100);
|
|
1829
|
-
}
|
|
1830
|
-
lastWriteTime = Date.now();
|
|
1831
|
-
});
|
|
1832
|
-
return () => {
|
|
1833
|
-
if (autoScrollTimeout)
|
|
1834
|
-
clearTimeout(autoScrollTimeout);
|
|
1835
|
-
unsubscribe();
|
|
1836
|
-
};
|
|
1837
|
-
}, [sessionId, actions.onTerminalData]);
|
|
1838
|
-
const handleTerminalData = useCallback4((data) => {
|
|
1839
|
-
if (sessionId && actions.writeToTerminal) {
|
|
1840
|
-
actions.writeToTerminal(sessionId, data);
|
|
1841
|
-
}
|
|
1842
|
-
}, [sessionId, actions.writeToTerminal]);
|
|
1843
|
-
const hasNotifiedPtyRef = useRef2(false);
|
|
1844
|
-
const handleTerminalResize = useCallback4((cols, rows) => {
|
|
1845
|
-
if (sessionId && actions.resizeTerminal) {
|
|
1846
|
-
const isInitialNotification = !hasNotifiedPtyRef.current;
|
|
1847
|
-
actions.resizeTerminal(sessionId, cols, rows);
|
|
1848
|
-
if (isInitialNotification && actions.writeToTerminal) {
|
|
1849
|
-
setTimeout(() => {
|
|
1850
|
-
actions.writeToTerminal(sessionId, "\f");
|
|
1851
|
-
}, 50);
|
|
1852
|
-
}
|
|
1853
|
-
hasNotifiedPtyRef.current = true;
|
|
1854
|
-
}
|
|
1855
|
-
}, [sessionId, actions.resizeTerminal, actions.writeToTerminal]);
|
|
1856
|
-
useEffect3(() => {
|
|
1857
|
-
hasNotifiedPtyRef.current = false;
|
|
1858
|
-
}, [sessionId]);
|
|
1859
|
-
useEffect3(() => {
|
|
1860
|
-
if (!sessionId || !actions.resizeTerminal)
|
|
1861
|
-
return;
|
|
1862
|
-
if (hasNotifiedPtyRef.current)
|
|
1863
|
-
return;
|
|
1864
|
-
const term = terminalRef.current?.getTerminal();
|
|
1865
|
-
if (!term || !term.cols || !term.rows)
|
|
1866
|
-
return;
|
|
1867
|
-
actions.resizeTerminal(sessionId, term.cols, term.rows);
|
|
1868
|
-
hasNotifiedPtyRef.current = true;
|
|
1869
|
-
if (actions.writeToTerminal) {
|
|
1870
|
-
const writeFn = actions.writeToTerminal;
|
|
1871
|
-
setTimeout(() => writeFn(sessionId, "\f"), 50);
|
|
1872
|
-
}
|
|
1873
|
-
}, [sessionId, actions.resizeTerminal, actions.writeToTerminal]);
|
|
1874
|
-
const handleScrollPositionChange = useCallback4((position) => {
|
|
1875
|
-
setScrollPosition(position);
|
|
1876
|
-
isScrollLockedRef.current = position.isScrollLocked;
|
|
1877
|
-
}, []);
|
|
1878
|
-
const sessionInfo = sessionId ? getTerminalSession(context2, sessionId) : undefined;
|
|
1879
|
-
if (error) {
|
|
1880
|
-
return /* @__PURE__ */ jsxs5("div", {
|
|
1881
|
-
style: {
|
|
1882
|
-
padding: "20px",
|
|
1883
|
-
color: "#ef4444",
|
|
1884
|
-
backgroundColor: allowTransparency ? "transparent" : "#1a1a1a",
|
|
1885
|
-
height: "100%",
|
|
1886
|
-
display: "flex",
|
|
1887
|
-
alignItems: "center",
|
|
1888
|
-
justifyContent: "center",
|
|
1889
|
-
flexDirection: "column",
|
|
1890
|
-
gap: "10px"
|
|
1891
|
-
},
|
|
1892
|
-
children: [
|
|
1893
|
-
/* @__PURE__ */ jsx6("div", {
|
|
1894
|
-
style: { fontSize: "16px", fontWeight: "bold" },
|
|
1895
|
-
children: "Terminal Error"
|
|
1896
|
-
}),
|
|
1897
|
-
/* @__PURE__ */ jsx6("div", {
|
|
1898
|
-
style: { fontSize: "14px", opacity: 0.8 },
|
|
1899
|
-
children: error
|
|
1900
|
-
})
|
|
1901
|
-
]
|
|
1902
|
-
});
|
|
1903
|
-
}
|
|
1904
|
-
if (isInitializing || !sessionId) {
|
|
1905
|
-
return /* @__PURE__ */ jsx6("div", {
|
|
1906
|
-
style: {
|
|
1907
|
-
padding: "20px",
|
|
1908
|
-
color: "#a0a0a0",
|
|
1909
|
-
backgroundColor: allowTransparency ? "transparent" : "#1a1a1a",
|
|
1910
|
-
height: "100%",
|
|
1911
|
-
display: "flex",
|
|
1912
|
-
alignItems: "center",
|
|
1913
|
-
justifyContent: "center"
|
|
1914
|
-
},
|
|
1915
|
-
children: "Initializing terminal..."
|
|
1916
|
-
});
|
|
1917
|
-
}
|
|
1918
|
-
const handleScrollToBottom = () => {
|
|
1919
|
-
terminalRef.current?.scrollToBottom();
|
|
1920
|
-
};
|
|
1921
|
-
const handleToggleScrollLock = () => {
|
|
1922
|
-
if (scrollPosition.isScrollLocked) {
|
|
1923
|
-
const terminal = terminalRef.current?.getTerminal();
|
|
1924
|
-
if (terminal) {
|
|
1925
|
-
terminal.scrollLines(-1);
|
|
1926
|
-
}
|
|
1927
|
-
} else {
|
|
1928
|
-
terminalRef.current?.scrollToBottom();
|
|
1929
|
-
}
|
|
1930
|
-
};
|
|
1931
|
-
return /* @__PURE__ */ jsxs5("div", {
|
|
1932
|
-
style: { height: "100%", width: "100%", display: "flex", flexDirection: "column" },
|
|
1933
|
-
children: [
|
|
1934
|
-
/* @__PURE__ */ jsxs5("div", {
|
|
1935
|
-
style: {
|
|
1936
|
-
display: "flex",
|
|
1937
|
-
gap: "8px",
|
|
1938
|
-
padding: "8px 12px",
|
|
1939
|
-
backgroundColor: allowTransparency ? "transparent" : theme.colors.backgroundSecondary,
|
|
1940
|
-
borderBottom: `1px solid ${theme.colors.border}`,
|
|
1941
|
-
alignItems: "center"
|
|
1942
|
-
},
|
|
1943
|
-
children: [
|
|
1944
|
-
/* @__PURE__ */ jsxs5("span", {
|
|
1945
|
-
style: {
|
|
1946
|
-
fontSize: "12px",
|
|
1947
|
-
color: theme.colors.textSecondary,
|
|
1948
|
-
marginRight: "auto",
|
|
1949
|
-
fontFamily: theme.fonts.monospace
|
|
1950
|
-
},
|
|
1951
|
-
children: [
|
|
1952
|
-
sessionInfo?.cwd || "Terminal",
|
|
1953
|
-
" • ",
|
|
1954
|
-
sessionInfo?.shell
|
|
1955
|
-
]
|
|
1956
|
-
}),
|
|
1957
|
-
/* @__PURE__ */ jsxs5("button", {
|
|
1958
|
-
onClick: handleToggleScrollLock,
|
|
1959
|
-
style: {
|
|
1960
|
-
display: "flex",
|
|
1961
|
-
alignItems: "center",
|
|
1962
|
-
gap: "4px",
|
|
1963
|
-
fontSize: "11px",
|
|
1964
|
-
padding: "4px 8px",
|
|
1965
|
-
borderRadius: "4px",
|
|
1966
|
-
backgroundColor: scrollPosition.isScrollLocked ? `${theme.colors.success}22` : `${theme.colors.warning}22`,
|
|
1967
|
-
color: scrollPosition.isScrollLocked ? theme.colors.success : theme.colors.warning,
|
|
1968
|
-
border: `1px solid ${scrollPosition.isScrollLocked ? `${theme.colors.success}44` : `${theme.colors.warning}44`}`,
|
|
1969
|
-
cursor: "pointer",
|
|
1970
|
-
transition: "opacity 0.2s"
|
|
1971
|
-
},
|
|
1972
|
-
onMouseEnter: (e) => e.currentTarget.style.opacity = "0.8",
|
|
1973
|
-
onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
|
|
1974
|
-
title: scrollPosition.isScrollLocked ? "Click to unlock scroll" : "Click to lock scroll to bottom",
|
|
1975
|
-
children: [
|
|
1976
|
-
scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx6(Lock, {
|
|
1977
|
-
size: 12
|
|
1978
|
-
}) : /* @__PURE__ */ jsx6(Unlock, {
|
|
1979
|
-
size: 12
|
|
1980
|
-
}),
|
|
1981
|
-
/* @__PURE__ */ jsx6("span", {
|
|
1982
|
-
children: scrollPosition.isScrollLocked ? "Locked" : "Unlocked"
|
|
1983
|
-
})
|
|
1984
|
-
]
|
|
1985
|
-
}),
|
|
1986
|
-
/* @__PURE__ */ jsxs5("button", {
|
|
1987
|
-
onClick: handleScrollToBottom,
|
|
1988
|
-
disabled: scrollPosition.isAtBottom,
|
|
1989
|
-
style: {
|
|
1990
|
-
display: "flex",
|
|
1991
|
-
alignItems: "center",
|
|
1992
|
-
gap: "4px",
|
|
1993
|
-
fontSize: "11px",
|
|
1994
|
-
padding: "4px 10px",
|
|
1995
|
-
borderRadius: "4px",
|
|
1996
|
-
backgroundColor: scrollPosition.isAtBottom ? theme.colors.backgroundHover : theme.colors.accent,
|
|
1997
|
-
color: scrollPosition.isAtBottom ? theme.colors.textTertiary : theme.colors.text,
|
|
1998
|
-
border: `1px solid ${theme.colors.border}`,
|
|
1999
|
-
cursor: scrollPosition.isAtBottom ? "not-allowed" : "pointer",
|
|
2000
|
-
transition: "opacity 0.2s",
|
|
2001
|
-
opacity: scrollPosition.isAtBottom ? 0.5 : 1
|
|
2002
|
-
},
|
|
2003
|
-
onMouseEnter: (e) => !scrollPosition.isAtBottom && (e.currentTarget.style.opacity = "0.8"),
|
|
2004
|
-
onMouseLeave: (e) => !scrollPosition.isAtBottom && (e.currentTarget.style.opacity = "1"),
|
|
2005
|
-
title: "Scroll to bottom and lock",
|
|
2006
|
-
children: [
|
|
2007
|
-
/* @__PURE__ */ jsx6(ArrowDown, {
|
|
2008
|
-
size: 12
|
|
2009
|
-
}),
|
|
2010
|
-
/* @__PURE__ */ jsx6("span", {
|
|
2011
|
-
children: "Bottom"
|
|
2012
|
-
})
|
|
2013
|
-
]
|
|
2014
|
-
})
|
|
2015
|
-
]
|
|
2016
|
-
}),
|
|
2017
|
-
/* @__PURE__ */ jsx6("div", {
|
|
2018
|
-
style: { flex: 1 },
|
|
2019
|
-
children: /* @__PURE__ */ jsx6(ThemedTerminalWithProvider, {
|
|
2020
|
-
ref: terminalRef,
|
|
2021
|
-
onData: handleTerminalData,
|
|
2022
|
-
onResize: handleTerminalResize,
|
|
2023
|
-
onScrollPositionChange: handleScrollPositionChange,
|
|
2024
|
-
hideHeader: true,
|
|
2025
|
-
autoFocus: true,
|
|
2026
|
-
convertEol: true,
|
|
2027
|
-
cursorBlink: true,
|
|
2028
|
-
scrollback: 1e4,
|
|
2029
|
-
enableSearch: true,
|
|
2030
|
-
enableWebLinks: true,
|
|
2031
|
-
allowTransparency,
|
|
2032
|
-
backgroundColor
|
|
2033
|
-
})
|
|
2034
|
-
})
|
|
2035
|
-
]
|
|
2036
|
-
});
|
|
2258
|
+
onSwitchToTab(index);
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2263
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2264
|
+
}, [enabled, onNewTab, onCloseTab, onSwitchToTab]);
|
|
2037
2265
|
};
|
|
2038
2266
|
// src/panels/TabbedTerminalPanel.tsx
|
|
2039
2267
|
import { useTheme as useTheme6 } from "@principal-ade/industry-theme";
|
|
2040
2268
|
import { CollapsibleSplitPane } from "@principal-ade/panels";
|
|
2041
|
-
import { Terminal as TerminalIcon2, Lock
|
|
2269
|
+
import { Terminal as TerminalIcon2, Lock, Unlock, Box, Boxes, Paperclip } from "lucide-react";
|
|
2042
2270
|
import React3, {
|
|
2043
2271
|
useState as useState4,
|
|
2044
2272
|
useCallback as useCallback5,
|
|
2045
2273
|
useEffect as useEffect4,
|
|
2046
|
-
useRef as
|
|
2274
|
+
useRef as useRef4
|
|
2047
2275
|
} from "react";
|
|
2048
|
-
import { jsx as
|
|
2049
|
-
var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */
|
|
2276
|
+
import { jsx as jsx9, jsxs as jsxs7, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
2277
|
+
var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs7("div", {
|
|
2050
2278
|
style: { display: "flex", gap: 1, alignItems: "center", height: 12 },
|
|
2051
2279
|
children: [
|
|
2052
|
-
[0, 1, 2, 3, 4].map((i) => /* @__PURE__ */
|
|
2280
|
+
[0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx9("div", {
|
|
2053
2281
|
style: {
|
|
2054
2282
|
width: 2,
|
|
2055
2283
|
height: 10,
|
|
@@ -2060,7 +2288,7 @@ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs6("div",
|
|
|
2060
2288
|
animation: isAnimating ? `waveSine 1.2s ease-in-out ${i * 0.1}s infinite` : "none"
|
|
2061
2289
|
}
|
|
2062
2290
|
}, i)),
|
|
2063
|
-
/* @__PURE__ */
|
|
2291
|
+
/* @__PURE__ */ jsx9("style", {
|
|
2064
2292
|
children: `
|
|
2065
2293
|
@keyframes waveSine {
|
|
2066
2294
|
0%, 100% { transform: scaleY(0.4); }
|
|
@@ -2071,376 +2299,69 @@ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs6("div",
|
|
|
2071
2299
|
]
|
|
2072
2300
|
});
|
|
2073
2301
|
function TerminalTabContentInner(props, ref) {
|
|
2074
|
-
const {
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
await actions.requestTerminalDataPort(targetSessionId);
|
|
2095
|
-
}
|
|
2096
|
-
setShouldRenderTerminal(true);
|
|
2097
|
-
setOwnerWindowId(null);
|
|
2098
|
-
if (force) {
|
|
2099
|
-
needsRefreshOnResizeRef.current = true;
|
|
2100
|
-
}
|
|
2101
|
-
} catch (error) {
|
|
2102
|
-
console.error("[TerminalTabContent] Failed to claim ownership:", error);
|
|
2103
|
-
throw error;
|
|
2104
|
-
}
|
|
2105
|
-
}, [actions]);
|
|
2106
|
-
useEffect4(() => {
|
|
2107
|
-
if (hasInitializedRef.current) {
|
|
2108
|
-
return;
|
|
2109
|
-
}
|
|
2110
|
-
hasInitializedRef.current = true;
|
|
2111
|
-
let mounted = true;
|
|
2112
|
-
const initSession = async () => {
|
|
2113
|
-
try {
|
|
2114
|
-
if (sessionId) {
|
|
2115
|
-
const tracer2 = getTracer();
|
|
2116
|
-
const reconnectSpan = tracer2.startSpan("terminal.session.reconnect", {
|
|
2117
|
-
attributes: {
|
|
2118
|
-
"session.id": sessionId,
|
|
2119
|
-
"session.context": `${terminalContext}:${tab.id}`,
|
|
2120
|
-
"session.isForeign": isForeign
|
|
2121
|
-
}
|
|
2122
|
-
});
|
|
2123
|
-
reconnectSpan.addEvent("terminal.session.reconnecting", {
|
|
2124
|
-
"session.id": sessionId,
|
|
2125
|
-
"reconnect.reason": "component_remount"
|
|
2126
|
-
});
|
|
2127
|
-
if (isForeign && actions.checkTerminalOwnership) {
|
|
2128
|
-
const status = await actions.checkTerminalOwnership(sessionId);
|
|
2129
|
-
if (status.ownedByWindowId && !status.ownedByThisWindow) {
|
|
2130
|
-
setShouldRenderTerminal(false);
|
|
2131
|
-
setOwnerWindowId(status.ownedByWindowId);
|
|
2132
|
-
reconnectSpan.addEvent("terminal.session.reconnect_blocked", {
|
|
2133
|
-
"session.id": sessionId,
|
|
2134
|
-
"owner.windowId": status.ownedByWindowId
|
|
2135
|
-
});
|
|
2136
|
-
}
|
|
2137
|
-
} else {
|
|
2138
|
-
await claimAndConnect(sessionId);
|
|
2139
|
-
reconnectSpan.addEvent("terminal.session.reconnected", {
|
|
2140
|
-
"session.id": sessionId
|
|
2141
|
-
});
|
|
2142
|
-
}
|
|
2143
|
-
reconnectSpan.setStatus({ code: SpanStatusCode.OK });
|
|
2144
|
-
reconnectSpan.end();
|
|
2145
|
-
setLocalSessionId(sessionId);
|
|
2146
|
-
setIsInitialized(true);
|
|
2147
|
-
return;
|
|
2148
|
-
}
|
|
2149
|
-
if (!actions.createTerminalSession) {
|
|
2150
|
-
return;
|
|
2151
|
-
}
|
|
2152
|
-
const newSessionId = await actions.createTerminalSession({
|
|
2153
|
-
cwd: tab.directory,
|
|
2154
|
-
command: tab.command,
|
|
2155
|
-
context: `${terminalContext}:${tab.id}`
|
|
2156
|
-
});
|
|
2157
|
-
if (!mounted)
|
|
2158
|
-
return;
|
|
2159
|
-
const tracer = getTracer();
|
|
2160
|
-
const span = tracer.startSpan("terminal.session", {
|
|
2161
|
-
attributes: {
|
|
2162
|
-
"session.id": newSessionId,
|
|
2163
|
-
"session.cwd": tab.directory,
|
|
2164
|
-
"session.context": `${terminalContext}:${tab.id}`
|
|
2165
|
-
}
|
|
2166
|
-
});
|
|
2167
|
-
span.addEvent("terminal.session.created", {
|
|
2168
|
-
"session.id": newSessionId,
|
|
2169
|
-
"session.cwd": tab.directory
|
|
2170
|
-
});
|
|
2171
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
2172
|
-
span.end();
|
|
2173
|
-
setLocalSessionId(newSessionId);
|
|
2174
|
-
setIsInitialized(true);
|
|
2175
|
-
onSessionCreated(tab.id, newSessionId);
|
|
2176
|
-
await claimAndConnect(newSessionId);
|
|
2177
|
-
} catch (error) {
|
|
2178
|
-
console.error("[TerminalTabContent] Failed to create session:", error);
|
|
2179
|
-
const tracer = getTracer();
|
|
2180
|
-
const span = tracer.startSpan("terminal.session", {
|
|
2181
|
-
attributes: {
|
|
2182
|
-
"session.action": "create",
|
|
2183
|
-
"error.occurred": true
|
|
2184
|
-
}
|
|
2185
|
-
});
|
|
2186
|
-
span.addEvent("terminal.session.error", {
|
|
2187
|
-
"error.message": error instanceof Error ? error.message : "Unknown error"
|
|
2188
|
-
});
|
|
2189
|
-
span.recordException(error);
|
|
2190
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: "Session creation failed" });
|
|
2191
|
-
span.end();
|
|
2192
|
-
}
|
|
2193
|
-
};
|
|
2194
|
-
initSession();
|
|
2195
|
-
return () => {
|
|
2196
|
-
mounted = false;
|
|
2197
|
-
};
|
|
2198
|
-
}, []);
|
|
2199
|
-
useEffect4(() => {
|
|
2200
|
-
if (!localSessionId || !isInitialized || !shouldRenderTerminal) {
|
|
2201
|
-
return;
|
|
2202
|
-
}
|
|
2203
|
-
if (!actions.onTerminalData) {
|
|
2204
|
-
return;
|
|
2205
|
-
}
|
|
2206
|
-
const tracer = getTracer();
|
|
2207
|
-
const subscribeSpan = tracer.startSpan("terminal.data.subscribe", {
|
|
2208
|
-
attributes: {
|
|
2209
|
-
"session.id": localSessionId,
|
|
2210
|
-
"tab.id": tab.id
|
|
2211
|
-
}
|
|
2212
|
-
});
|
|
2213
|
-
subscribeSpan.addEvent("terminal.data.subscribed", {
|
|
2214
|
-
"session.id": localSessionId
|
|
2215
|
-
});
|
|
2216
|
-
console.log("[TerminalTabContent] SUBSCRIBING to terminal data", { tabId: tab.id, sessionId: localSessionId });
|
|
2217
|
-
let hasReceivedData = false;
|
|
2218
|
-
const unsubscribe = actions.onTerminalData(localSessionId, (data) => {
|
|
2219
|
-
if (terminalRef.current) {
|
|
2220
|
-
if (!hasReceivedData) {
|
|
2221
|
-
hasReceivedData = true;
|
|
2222
|
-
subscribeSpan.addEvent("terminal.data.first_received", {
|
|
2223
|
-
"session.id": localSessionId,
|
|
2224
|
-
"data.length": data.length
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
terminalRef.current.write(data);
|
|
2228
|
-
}
|
|
2229
|
-
});
|
|
2230
|
-
subscribeSpan.setStatus({ code: SpanStatusCode.OK });
|
|
2231
|
-
subscribeSpan.end();
|
|
2232
|
-
return () => {
|
|
2233
|
-
const unsubscribeSpan = tracer.startSpan("terminal.data.unsubscribe", {
|
|
2234
|
-
attributes: {
|
|
2235
|
-
"session.id": localSessionId,
|
|
2236
|
-
"tab.id": tab.id,
|
|
2237
|
-
"data.wasReceived": hasReceivedData
|
|
2238
|
-
}
|
|
2239
|
-
});
|
|
2240
|
-
unsubscribeSpan.addEvent("terminal.data.unsubscribed", {
|
|
2241
|
-
"session.id": localSessionId
|
|
2242
|
-
});
|
|
2243
|
-
unsubscribeSpan.setStatus({ code: SpanStatusCode.OK });
|
|
2244
|
-
unsubscribeSpan.end();
|
|
2245
|
-
console.log("[TerminalTabContent] UNSUBSCRIBING from terminal data", { tabId: tab.id, sessionId: localSessionId });
|
|
2246
|
-
unsubscribe();
|
|
2247
|
-
};
|
|
2248
|
-
}, [localSessionId, isInitialized, actions, shouldRenderTerminal, tab.id]);
|
|
2249
|
-
const handleData = useCallback5((data) => {
|
|
2250
|
-
if (localSessionId && actions.writeToTerminal) {
|
|
2251
|
-
actions.writeToTerminal(localSessionId, data);
|
|
2252
|
-
}
|
|
2253
|
-
}, [localSessionId, actions]);
|
|
2254
|
-
const handleResize = useCallback5((cols, rows) => {
|
|
2255
|
-
if (localSessionId && actions.resizeTerminal) {
|
|
2256
|
-
actions.resizeTerminal(localSessionId, cols, rows);
|
|
2257
|
-
}
|
|
2258
|
-
}, [localSessionId, actions]);
|
|
2259
|
-
const handleReady = useCallback5((cols, rows) => {
|
|
2260
|
-
if (!localSessionId || !actions.resizeTerminal) {
|
|
2261
|
-
return;
|
|
2262
|
-
}
|
|
2263
|
-
const shouldForce = needsRefreshOnResizeRef.current;
|
|
2264
|
-
if (!shouldForce) {
|
|
2265
|
-
actions.resizeTerminal(localSessionId, cols, rows, false);
|
|
2266
|
-
return;
|
|
2267
|
-
}
|
|
2268
|
-
needsRefreshOnResizeRef.current = false;
|
|
2269
|
-
const restoreBufferAndResize = async () => {
|
|
2270
|
-
let bufferRestored = false;
|
|
2271
|
-
if (actions.getTerminalBuffer && terminalRef.current) {
|
|
2272
|
-
try {
|
|
2273
|
-
const buffer = await actions.getTerminalBuffer(localSessionId);
|
|
2274
|
-
if (buffer) {
|
|
2275
|
-
terminalRef.current.write(buffer);
|
|
2276
|
-
bufferRestored = true;
|
|
2277
|
-
}
|
|
2278
|
-
} catch (error) {
|
|
2279
|
-
console.warn("[TabbedTerminalPanel] Failed to restore buffer:", error);
|
|
2280
|
-
}
|
|
2281
|
-
}
|
|
2282
|
-
const forceResize = !bufferRestored;
|
|
2283
|
-
actions.resizeTerminal(localSessionId, cols, rows, forceResize);
|
|
2284
|
-
};
|
|
2285
|
-
restoreBufferAndResize();
|
|
2286
|
-
}, [localSessionId, actions]);
|
|
2287
|
-
const handleLinkClick = useCallback5((url, modifiers) => {
|
|
2288
|
-
if (localSessionId) {
|
|
2289
|
-
events.emit({
|
|
2290
|
-
type: "terminal:link-click",
|
|
2291
|
-
source: "TabbedTerminalPanel",
|
|
2292
|
-
timestamp: Date.now(),
|
|
2293
|
-
payload: {
|
|
2294
|
-
url,
|
|
2295
|
-
sessionId: localSessionId,
|
|
2296
|
-
shiftKey: modifiers.shiftKey,
|
|
2297
|
-
metaKey: modifiers.metaKey,
|
|
2298
|
-
ctrlKey: modifiers.ctrlKey,
|
|
2299
|
-
altKey: modifiers.altKey
|
|
2300
|
-
}
|
|
2301
|
-
});
|
|
2302
|
-
}
|
|
2303
|
-
}, [localSessionId, events]);
|
|
2304
|
-
useEffect4(() => {
|
|
2305
|
-
if (!localSessionId || !actions.onOwnershipLost) {
|
|
2306
|
-
return;
|
|
2307
|
-
}
|
|
2308
|
-
const unsubscribe = actions.onOwnershipLost((data) => {
|
|
2309
|
-
if (data.sessionId === localSessionId) {
|
|
2310
|
-
setShouldRenderTerminal(false);
|
|
2311
|
-
setOwnerWindowId(data.newOwnerWindowId);
|
|
2312
|
-
}
|
|
2313
|
-
});
|
|
2314
|
-
return () => {
|
|
2315
|
-
unsubscribe();
|
|
2316
|
-
};
|
|
2317
|
-
}, [localSessionId, actions]);
|
|
2318
|
-
const handleTakeControl = useCallback5(async () => {
|
|
2319
|
-
if (!localSessionId) {
|
|
2320
|
-
return;
|
|
2321
|
-
}
|
|
2322
|
-
await claimAndConnect(localSessionId, true);
|
|
2323
|
-
}, [localSessionId, claimAndConnect]);
|
|
2302
|
+
const {
|
|
2303
|
+
tab,
|
|
2304
|
+
sessionId,
|
|
2305
|
+
isActive,
|
|
2306
|
+
isVisible,
|
|
2307
|
+
actions,
|
|
2308
|
+
events,
|
|
2309
|
+
terminalContext,
|
|
2310
|
+
onSessionCreated,
|
|
2311
|
+
onScrollPositionChange,
|
|
2312
|
+
isForeign = false,
|
|
2313
|
+
defaultScrollLocked,
|
|
2314
|
+
activityDetection = true,
|
|
2315
|
+
activityTimeout = 500,
|
|
2316
|
+
autoShowBlinds = false,
|
|
2317
|
+
onActivityStateChange
|
|
2318
|
+
} = props;
|
|
2319
|
+
const [isWorkingFromActivity, setIsWorkingFromActivity] = useState4(false);
|
|
2320
|
+
const sessionRef = useRef4(null);
|
|
2321
|
+
const handleSessionCreated = useCallback5((sid) => onSessionCreated(tab.id, sid), [onSessionCreated, tab.id]);
|
|
2324
2322
|
const handleScrollPositionChange = useCallback5((position) => {
|
|
2325
|
-
setScrollPosition(position);
|
|
2326
2323
|
onScrollPositionChange?.(tab.id, position);
|
|
2327
|
-
}, [tab.id
|
|
2328
|
-
const handleShortcut = useCallback5((shortcutEvent) => {
|
|
2329
|
-
if (localSessionId) {
|
|
2330
|
-
events.emit({
|
|
2331
|
-
type: "terminal:shortcut",
|
|
2332
|
-
source: "TabbedTerminalPanel",
|
|
2333
|
-
timestamp: Date.now(),
|
|
2334
|
-
payload: {
|
|
2335
|
-
shortcut: shortcutEvent.shortcut,
|
|
2336
|
-
sessionId: localSessionId
|
|
2337
|
-
}
|
|
2338
|
-
});
|
|
2339
|
-
}
|
|
2340
|
-
}, [localSessionId, events]);
|
|
2324
|
+
}, [onScrollPositionChange, tab.id]);
|
|
2341
2325
|
const handleActivityChange = useCallback5((state) => {
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
type: "terminal:activity-changed",
|
|
2346
|
-
source: "TabbedTerminalPanel",
|
|
2347
|
-
timestamp: Date.now(),
|
|
2348
|
-
payload: {
|
|
2349
|
-
sessionId: localSessionId,
|
|
2350
|
-
activityType: state.isActive ? "started" : "stopped",
|
|
2351
|
-
isWorking: state.isActive
|
|
2352
|
-
}
|
|
2353
|
-
});
|
|
2326
|
+
const sid = sessionRef.current?.getSessionId();
|
|
2327
|
+
if (sid) {
|
|
2328
|
+
onActivityStateChange?.(sid, state.isActive);
|
|
2354
2329
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
terminalRef.current?.scrollToBottom();
|
|
2358
|
-
}, []);
|
|
2359
|
-
const handleToggleScrollLock = useCallback5(() => {
|
|
2360
|
-
if (scrollPosition.isScrollLocked) {
|
|
2361
|
-
const terminal = terminalRef.current?.getTerminal();
|
|
2362
|
-
if (terminal) {
|
|
2363
|
-
terminal.scrollLines(-1);
|
|
2364
|
-
}
|
|
2365
|
-
} else {
|
|
2366
|
-
terminalRef.current?.scrollToBottom();
|
|
2330
|
+
if (autoShowBlinds) {
|
|
2331
|
+
setIsWorkingFromActivity(state.isActive);
|
|
2367
2332
|
}
|
|
2368
|
-
}, [
|
|
2333
|
+
}, [autoShowBlinds, onActivityStateChange]);
|
|
2369
2334
|
React3.useImperativeHandle(ref, () => ({
|
|
2370
|
-
scrollToBottom:
|
|
2371
|
-
toggleScrollLock:
|
|
2372
|
-
}), [
|
|
2373
|
-
|
|
2374
|
-
return /* @__PURE__ */ jsxs6("div", {
|
|
2375
|
-
style: {
|
|
2376
|
-
display: isActive ? "flex" : "none",
|
|
2377
|
-
height: "100%",
|
|
2378
|
-
width: "100%",
|
|
2379
|
-
backgroundColor: theme.colors.background,
|
|
2380
|
-
padding: "10px 0 0 10px"
|
|
2381
|
-
},
|
|
2382
|
-
children: [
|
|
2383
|
-
/* @__PURE__ */ jsx7("div", {
|
|
2384
|
-
style: {
|
|
2385
|
-
width: "8px",
|
|
2386
|
-
height: "17px",
|
|
2387
|
-
backgroundColor: theme.colors.text,
|
|
2388
|
-
animation: "blink 1s step-end infinite"
|
|
2389
|
-
}
|
|
2390
|
-
}),
|
|
2391
|
-
/* @__PURE__ */ jsx7("style", {
|
|
2392
|
-
children: `
|
|
2393
|
-
@keyframes blink {
|
|
2394
|
-
0%, 100% { opacity: 1; }
|
|
2395
|
-
50% { opacity: 0; }
|
|
2396
|
-
}
|
|
2397
|
-
`
|
|
2398
|
-
})
|
|
2399
|
-
]
|
|
2400
|
-
});
|
|
2401
|
-
}
|
|
2402
|
-
const overlayState = !shouldRenderTerminal ? {
|
|
2403
|
-
message: "This terminal is active in another window",
|
|
2404
|
-
subtitle: ownerWindowId ? `Window ID: ${ownerWindowId}` : "Another window owns this terminal session",
|
|
2405
|
-
actions: [
|
|
2406
|
-
{
|
|
2407
|
-
label: "Take Control",
|
|
2408
|
-
onClick: handleTakeControl,
|
|
2409
|
-
primary: true
|
|
2410
|
-
}
|
|
2411
|
-
],
|
|
2412
|
-
opacity: 1
|
|
2413
|
-
} : undefined;
|
|
2414
|
-
return /* @__PURE__ */ jsx7("div", {
|
|
2335
|
+
scrollToBottom: () => sessionRef.current?.scrollToBottom(),
|
|
2336
|
+
toggleScrollLock: () => sessionRef.current?.toggleScrollLock()
|
|
2337
|
+
}), []);
|
|
2338
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
2415
2339
|
style: {
|
|
2416
2340
|
display: isActive ? "flex" : "none",
|
|
2417
2341
|
flexDirection: "column",
|
|
2418
2342
|
height: "100%",
|
|
2419
2343
|
width: "100%"
|
|
2420
2344
|
},
|
|
2421
|
-
children: /* @__PURE__ */
|
|
2422
|
-
ref:
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
defaultScrollLocked,
|
|
2433
|
-
convertEol: true,
|
|
2434
|
-
cursorBlink: shouldRenderTerminal,
|
|
2435
|
-
scrollback: 1e4,
|
|
2436
|
-
enableSearch: true,
|
|
2345
|
+
children: /* @__PURE__ */ jsx9(TerminalSession, {
|
|
2346
|
+
ref: sessionRef,
|
|
2347
|
+
actions,
|
|
2348
|
+
events,
|
|
2349
|
+
sessionId,
|
|
2350
|
+
onSessionCreated: handleSessionCreated,
|
|
2351
|
+
cwd: tab.directory,
|
|
2352
|
+
command: tab.command,
|
|
2353
|
+
sessionContext: `${terminalContext}:${tab.id}`,
|
|
2354
|
+
enableOwnership: true,
|
|
2355
|
+
isForeign,
|
|
2437
2356
|
activityDetection,
|
|
2438
2357
|
activityTimeout,
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2358
|
+
onActivityChange: handleActivityChange,
|
|
2359
|
+
onScrollPositionChange: handleScrollPositionChange,
|
|
2360
|
+
defaultScrollLocked,
|
|
2361
|
+
autoFocus: isActive,
|
|
2362
|
+
isVisible: isVisible && isActive,
|
|
2363
|
+
isWorking: autoShowBlinds && isWorkingFromActivity
|
|
2364
|
+
})
|
|
2444
2365
|
});
|
|
2445
2366
|
}
|
|
2446
2367
|
var areTerminalTabContentPropsEqual = (prevProps, nextProps) => {
|
|
@@ -2597,8 +2518,8 @@ var TabbedTerminalPanelInner = ({
|
|
|
2597
2518
|
}
|
|
2598
2519
|
}));
|
|
2599
2520
|
}, [tabs]);
|
|
2600
|
-
const tabRefsMap =
|
|
2601
|
-
const refCallbacksMap =
|
|
2521
|
+
const tabRefsMap = useRef4(new Map);
|
|
2522
|
+
const refCallbacksMap = useRef4(new Map);
|
|
2602
2523
|
const getRefCallback = useCallback5((tabId) => {
|
|
2603
2524
|
let callback = refCallbacksMap.current.get(tabId);
|
|
2604
2525
|
if (!callback) {
|
|
@@ -2613,9 +2534,9 @@ var TabbedTerminalPanelInner = ({
|
|
|
2613
2534
|
}
|
|
2614
2535
|
return callback;
|
|
2615
2536
|
}, []);
|
|
2616
|
-
const hasInitializedRef =
|
|
2617
|
-
const isCreatingTabRef =
|
|
2618
|
-
const headerRef =
|
|
2537
|
+
const hasInitializedRef = useRef4(false);
|
|
2538
|
+
const isCreatingTabRef = useRef4(false);
|
|
2539
|
+
const headerRef = useRef4(null);
|
|
2619
2540
|
const handleTabScrollPositionChange = useCallback5((tabId, position) => {
|
|
2620
2541
|
setScrollPositions((prev) => new Map(prev).set(tabId, position));
|
|
2621
2542
|
}, []);
|
|
@@ -2888,9 +2809,9 @@ var TabbedTerminalPanelInner = ({
|
|
|
2888
2809
|
if (!isActive)
|
|
2889
2810
|
return null;
|
|
2890
2811
|
const scrollPosition = scrollPositions.get(tab.id) ?? defaultScrollPosition;
|
|
2891
|
-
return /* @__PURE__ */
|
|
2812
|
+
return /* @__PURE__ */ jsxs7(Fragment2, {
|
|
2892
2813
|
children: [
|
|
2893
|
-
/* @__PURE__ */
|
|
2814
|
+
/* @__PURE__ */ jsx9("button", {
|
|
2894
2815
|
onClick: (e) => {
|
|
2895
2816
|
e.stopPropagation();
|
|
2896
2817
|
handleToggleScrollLock();
|
|
@@ -2915,13 +2836,13 @@ var TabbedTerminalPanelInner = ({
|
|
|
2915
2836
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
2916
2837
|
},
|
|
2917
2838
|
title: scrollPosition.isScrollLocked ? "Scroll locked" : "Scroll unlocked",
|
|
2918
|
-
children: scrollPosition.isScrollLocked ? /* @__PURE__ */
|
|
2839
|
+
children: scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx9(Lock, {
|
|
2919
2840
|
size: 10
|
|
2920
|
-
}) : /* @__PURE__ */
|
|
2841
|
+
}) : /* @__PURE__ */ jsx9(Unlock, {
|
|
2921
2842
|
size: 10
|
|
2922
2843
|
})
|
|
2923
2844
|
}),
|
|
2924
|
-
/* @__PURE__ */
|
|
2845
|
+
/* @__PURE__ */ jsx9("div", {
|
|
2925
2846
|
style: {
|
|
2926
2847
|
position: "absolute",
|
|
2927
2848
|
right: "8px",
|
|
@@ -2932,7 +2853,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
2932
2853
|
height: "16px"
|
|
2933
2854
|
},
|
|
2934
2855
|
title: isWorking ? "Terminal active" : "Terminal idle",
|
|
2935
|
-
children: /* @__PURE__ */
|
|
2856
|
+
children: /* @__PURE__ */ jsx9(ActivityIndicator, {
|
|
2936
2857
|
color: theme.colors.primary,
|
|
2937
2858
|
isAnimating: isWorking ?? false
|
|
2938
2859
|
})
|
|
@@ -2941,7 +2862,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
2941
2862
|
});
|
|
2942
2863
|
}, [activeTabId, scrollPositions, defaultScrollPosition, handleToggleScrollLock, theme, sessionIds, workingStates, activityStates]);
|
|
2943
2864
|
const renderTerminalWithAssociation = useCallback5((tab, isActive, sessionId, association) => {
|
|
2944
|
-
const terminalContent = /* @__PURE__ */
|
|
2865
|
+
const terminalContent = /* @__PURE__ */ jsx9(TerminalTabContent, {
|
|
2945
2866
|
ref: getRefCallback(tab.id),
|
|
2946
2867
|
tab,
|
|
2947
2868
|
sessionId,
|
|
@@ -2960,7 +2881,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
2960
2881
|
onActivityStateChange: handleActivityStateChange
|
|
2961
2882
|
}, `terminal-${tab.id}`);
|
|
2962
2883
|
const hasAssociation = !!association;
|
|
2963
|
-
const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */
|
|
2884
|
+
const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */ jsx9("div", {
|
|
2964
2885
|
style: {
|
|
2965
2886
|
height: "100%",
|
|
2966
2887
|
display: "flex",
|
|
@@ -2972,12 +2893,12 @@ var TabbedTerminalPanelInner = ({
|
|
|
2972
2893
|
},
|
|
2973
2894
|
children: "Drag a tab here to associate it with this terminal"
|
|
2974
2895
|
});
|
|
2975
|
-
const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */
|
|
2896
|
+
const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */ jsx9(Paperclip, {
|
|
2976
2897
|
size: 14
|
|
2977
2898
|
}) };
|
|
2978
2899
|
const isCollapsed = hasAssociation ? association.collapsed : true;
|
|
2979
2900
|
const handleCollapsedChange = hasAssociation ? (collapsed) => onAssociationCollapsedChange?.(tab.id, collapsed) : undefined;
|
|
2980
|
-
return /* @__PURE__ */
|
|
2901
|
+
return /* @__PURE__ */ jsx9(CollapsibleSplitPane, {
|
|
2981
2902
|
style: { height: "100%" },
|
|
2982
2903
|
primaryContent: terminalContent,
|
|
2983
2904
|
secondaryContent,
|
|
@@ -3052,7 +2973,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3052
2973
|
setActiveTabId(activeTabId);
|
|
3053
2974
|
}
|
|
3054
2975
|
}, [activeTabId, tabs, onTabAssociate, setActiveTabId]);
|
|
3055
|
-
return /* @__PURE__ */
|
|
2976
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
3056
2977
|
style: {
|
|
3057
2978
|
display: "flex",
|
|
3058
2979
|
flexDirection: "column",
|
|
@@ -3060,15 +2981,15 @@ var TabbedTerminalPanelInner = ({
|
|
|
3060
2981
|
backgroundColor: theme.colors.background
|
|
3061
2982
|
},
|
|
3062
2983
|
children: [
|
|
3063
|
-
!hideHeader && /* @__PURE__ */
|
|
2984
|
+
!hideHeader && /* @__PURE__ */ jsx9("div", {
|
|
3064
2985
|
ref: headerRef,
|
|
3065
|
-
children: /* @__PURE__ */
|
|
2986
|
+
children: /* @__PURE__ */ jsx9(TabBar, {
|
|
3066
2987
|
tabs: genericTabs,
|
|
3067
2988
|
activeTabId,
|
|
3068
2989
|
onTabClick: switchTab,
|
|
3069
2990
|
onTabClose: closeTab,
|
|
3070
2991
|
onNewTab: addNewTab,
|
|
3071
|
-
leftSection: /* @__PURE__ */
|
|
2992
|
+
leftSection: /* @__PURE__ */ jsx9("button", {
|
|
3072
2993
|
onClick: () => onShowAllTerminalsChange?.(!showAllTerminals),
|
|
3073
2994
|
style: {
|
|
3074
2995
|
display: "flex",
|
|
@@ -3093,9 +3014,9 @@ var TabbedTerminalPanelInner = ({
|
|
|
3093
3014
|
}
|
|
3094
3015
|
},
|
|
3095
3016
|
title: showAllTerminals ? "Showing all terminals (click to filter by context)" : "Show all terminals",
|
|
3096
|
-
children: showAllTerminals ? /* @__PURE__ */
|
|
3017
|
+
children: showAllTerminals ? /* @__PURE__ */ jsx9(Boxes, {
|
|
3097
3018
|
size: 14
|
|
3098
|
-
}) : /* @__PURE__ */
|
|
3019
|
+
}) : /* @__PURE__ */ jsx9(Box, {
|
|
3099
3020
|
size: 14
|
|
3100
3021
|
})
|
|
3101
3022
|
}),
|
|
@@ -3108,7 +3029,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3108
3029
|
canDropOnTab
|
|
3109
3030
|
})
|
|
3110
3031
|
}),
|
|
3111
|
-
/* @__PURE__ */
|
|
3032
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
3112
3033
|
style: {
|
|
3113
3034
|
flex: 1,
|
|
3114
3035
|
display: "flex",
|
|
@@ -3162,7 +3083,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3162
3083
|
const customContent = renderTabContent(tab, isActive, sessionId, width);
|
|
3163
3084
|
if (customContent === null && tab.contentType === "terminal") {
|
|
3164
3085
|
const association = associations?.[tab.id];
|
|
3165
|
-
return /* @__PURE__ */
|
|
3086
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
3166
3087
|
style: {
|
|
3167
3088
|
display: isActive ? "flex" : "none",
|
|
3168
3089
|
flexDirection: "column",
|
|
@@ -3173,7 +3094,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3173
3094
|
}, tab.id);
|
|
3174
3095
|
}
|
|
3175
3096
|
const hasBeenActivated = activatedTabs.has(tab.id);
|
|
3176
|
-
return /* @__PURE__ */
|
|
3097
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
3177
3098
|
style: {
|
|
3178
3099
|
display: isActive ? "flex" : "none",
|
|
3179
3100
|
flexDirection: "column",
|
|
@@ -3185,7 +3106,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3185
3106
|
}
|
|
3186
3107
|
if (tab.contentType === "terminal") {
|
|
3187
3108
|
const association = associations?.[tab.id];
|
|
3188
|
-
return /* @__PURE__ */
|
|
3109
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
3189
3110
|
style: {
|
|
3190
3111
|
display: isActive ? "flex" : "none",
|
|
3191
3112
|
flexDirection: "column",
|
|
@@ -3195,7 +3116,7 @@ var TabbedTerminalPanelInner = ({
|
|
|
3195
3116
|
children: renderTerminalWithAssociation(tab, isActive, sessionId, association)
|
|
3196
3117
|
}, tab.id);
|
|
3197
3118
|
}
|
|
3198
|
-
return /* @__PURE__ */
|
|
3119
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
3199
3120
|
style: {
|
|
3200
3121
|
display: isActive ? "flex" : "none",
|
|
3201
3122
|
alignItems: "center",
|
|
@@ -3204,20 +3125,20 @@ var TabbedTerminalPanelInner = ({
|
|
|
3204
3125
|
color: theme.colors.textSecondary
|
|
3205
3126
|
},
|
|
3206
3127
|
children: [
|
|
3207
|
-
/* @__PURE__ */
|
|
3128
|
+
/* @__PURE__ */ jsxs7("p", {
|
|
3208
3129
|
children: [
|
|
3209
3130
|
"Unknown content type: ",
|
|
3210
3131
|
tab.contentType
|
|
3211
3132
|
]
|
|
3212
3133
|
}),
|
|
3213
|
-
/* @__PURE__ */
|
|
3134
|
+
/* @__PURE__ */ jsx9("p", {
|
|
3214
3135
|
style: { fontSize: theme.fontSizes[0], marginTop: "8px" },
|
|
3215
3136
|
children: "Provide a renderTabContent prop to render custom tab types"
|
|
3216
3137
|
})
|
|
3217
3138
|
]
|
|
3218
3139
|
}, tab.id);
|
|
3219
3140
|
}),
|
|
3220
|
-
tabs.length === 0 && /* @__PURE__ */
|
|
3141
|
+
tabs.length === 0 && /* @__PURE__ */ jsxs7("div", {
|
|
3221
3142
|
style: {
|
|
3222
3143
|
display: "flex",
|
|
3223
3144
|
flexDirection: "column",
|
|
@@ -3227,11 +3148,11 @@ var TabbedTerminalPanelInner = ({
|
|
|
3227
3148
|
color: theme.colors.textSecondary
|
|
3228
3149
|
},
|
|
3229
3150
|
children: [
|
|
3230
|
-
/* @__PURE__ */
|
|
3151
|
+
/* @__PURE__ */ jsx9(TerminalIcon2, {
|
|
3231
3152
|
size: 32,
|
|
3232
3153
|
style: { opacity: 0.5, marginBottom: "16px" }
|
|
3233
3154
|
}),
|
|
3234
|
-
/* @__PURE__ */
|
|
3155
|
+
/* @__PURE__ */ jsx9("button", {
|
|
3235
3156
|
onClick: () => addNewTab(),
|
|
3236
3157
|
style: {
|
|
3237
3158
|
marginTop: "16px",
|
|
@@ -3460,33 +3381,43 @@ var terminalPanelToolsMetadata = {
|
|
|
3460
3381
|
};
|
|
3461
3382
|
|
|
3462
3383
|
// src/panel-exports.ts
|
|
3463
|
-
var panels = [
|
|
3464
|
-
{
|
|
3465
|
-
metadata: {
|
|
3466
|
-
id: "com.principal.terminal",
|
|
3467
|
-
name: "Terminal",
|
|
3468
|
-
icon: "terminal",
|
|
3469
|
-
version: "0.1.0",
|
|
3470
|
-
author: "Principal",
|
|
3471
|
-
description: "Integrated terminal emulator with industry theming",
|
|
3472
|
-
slices: ["terminal"],
|
|
3473
|
-
tools: terminalPanelTools
|
|
3474
|
-
},
|
|
3475
|
-
component: TerminalPanel,
|
|
3476
|
-
onMount: async (_context) => {
|
|
3477
|
-
console.log("Terminal Panel mounted for repository:", _context.currentScope.repository?.path);
|
|
3478
|
-
},
|
|
3479
|
-
onUnmount: async (_context) => {
|
|
3480
|
-
console.log("Terminal Panel unmounting");
|
|
3481
|
-
}
|
|
3482
|
-
}
|
|
3483
|
-
];
|
|
3384
|
+
var panels = [];
|
|
3484
3385
|
var onPackageLoad = async () => {
|
|
3485
3386
|
console.log("Panel package loaded - Terminal Panel Extension");
|
|
3486
3387
|
};
|
|
3487
3388
|
var onPackageUnload = async () => {
|
|
3488
3389
|
console.log("Panel package unloading - Terminal Panel Extension");
|
|
3489
3390
|
};
|
|
3391
|
+
// src/panel-types/index.ts
|
|
3392
|
+
function getTerminalSessions(context2) {
|
|
3393
|
+
return context2.terminal?.data ?? [];
|
|
3394
|
+
}
|
|
3395
|
+
function getTerminalSession(context2, sessionId) {
|
|
3396
|
+
const sessions = getTerminalSessions(context2);
|
|
3397
|
+
return sessions.find((s) => s.id === sessionId);
|
|
3398
|
+
}
|
|
3399
|
+
function isTerminalLoading(context2) {
|
|
3400
|
+
return context2.terminal?.loading ?? false;
|
|
3401
|
+
}
|
|
3402
|
+
function getRepositoryPath(context2) {
|
|
3403
|
+
return context2.currentScope.repository?.path ?? null;
|
|
3404
|
+
}
|
|
3405
|
+
function getWorkspacePath(context2) {
|
|
3406
|
+
return context2.currentScope.workspace?.path ?? null;
|
|
3407
|
+
}
|
|
3408
|
+
function getTerminalDirectory(context2, terminalScope = "repository") {
|
|
3409
|
+
switch (terminalScope) {
|
|
3410
|
+
case "workspace":
|
|
3411
|
+
return getWorkspacePath(context2);
|
|
3412
|
+
case "repository":
|
|
3413
|
+
return getRepositoryPath(context2) ?? getWorkspacePath(context2);
|
|
3414
|
+
default:
|
|
3415
|
+
return getRepositoryPath(context2) ?? getWorkspacePath(context2);
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
function getTerminalSlice(context2) {
|
|
3419
|
+
return context2.terminal;
|
|
3420
|
+
}
|
|
3490
3421
|
export {
|
|
3491
3422
|
writeToTerminalTool,
|
|
3492
3423
|
withSpanSync,
|
|
@@ -3516,10 +3447,12 @@ export {
|
|
|
3516
3447
|
context,
|
|
3517
3448
|
closeTerminalSessionTool,
|
|
3518
3449
|
clearTerminalTool,
|
|
3450
|
+
XtermRenderer,
|
|
3519
3451
|
WorkingOverlay,
|
|
3520
3452
|
ThemedTerminalWithProvider,
|
|
3521
3453
|
ThemedTerminal,
|
|
3522
|
-
|
|
3454
|
+
TerminalSession,
|
|
3455
|
+
TerminalOverlay,
|
|
3523
3456
|
TabbedTerminalPanel,
|
|
3524
3457
|
TabButton,
|
|
3525
3458
|
TabBar,
|