@industry-theme/xterm-terminal-panel 0.6.0 → 0.7.1

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
@@ -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.6.0",
38
+ version: "0.7.1",
39
39
  description: "Industry-themed xterm.js terminal components with panel framework integration",
40
40
  type: "module",
41
41
  main: "dist/index.js",
@@ -1285,7 +1285,14 @@ ThemedTerminalWithProvider.displayName = "ThemedTerminalWithProvider";
1285
1285
  import { forwardRef as forwardRef3, useImperativeHandle as useImperativeHandle2, useRef as useRef2 } from "react";
1286
1286
  import { jsx as jsx4 } from "react/jsx-runtime";
1287
1287
  var XtermRenderer = forwardRef3((props, ref) => {
1288
- const { transparent, ...rest } = props;
1288
+ const {
1289
+ transparent,
1290
+ enableSearch = true,
1291
+ enableWebLinks = true,
1292
+ cursorBlink = true,
1293
+ convertEol = true,
1294
+ ...rest
1295
+ } = props;
1289
1296
  const innerRef = useRef2(null);
1290
1297
  useImperativeHandle2(ref, () => ({
1291
1298
  write: (data) => innerRef.current?.write(data),
@@ -1314,6 +1321,10 @@ var XtermRenderer = forwardRef3((props, ref) => {
1314
1321
  return /* @__PURE__ */ jsx4(ThemedTerminalWithProvider, {
1315
1322
  ref: innerRef,
1316
1323
  ...rest,
1324
+ enableSearch,
1325
+ enableWebLinks,
1326
+ cursorBlink,
1327
+ convertEol,
1317
1328
  hideHeader: true,
1318
1329
  activityDetection: false,
1319
1330
  allowTransparency: transparent
@@ -1494,15 +1505,26 @@ var TerminalSession = forwardRef4((props, ref) => {
1494
1505
  return;
1495
1506
  hasInitializedRef.current = true;
1496
1507
  let mounted = true;
1508
+ const tracer = getTracer();
1497
1509
  const init = async () => {
1498
1510
  try {
1499
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
+ });
1500
1519
  if (enableOwnership) {
1501
1520
  if (isForeign && actions.checkTerminalOwnership) {
1502
1521
  const status = await actions.checkTerminalOwnership(sessionIdProp);
1503
1522
  if (status.ownedByWindowId && !status.ownedByThisWindow) {
1504
1523
  setShouldRenderTerminal(false);
1505
1524
  setOwnerWindowId(status.ownedByWindowId);
1525
+ span2.addEvent("terminal.session.reconnect_blocked", {
1526
+ "owner.windowId": status.ownedByWindowId
1527
+ });
1506
1528
  }
1507
1529
  } else {
1508
1530
  await claimAndConnect(sessionIdProp);
@@ -1512,6 +1534,8 @@ var TerminalSession = forwardRef4((props, ref) => {
1512
1534
  setLocalSessionId(sessionIdProp);
1513
1535
  setIsInitialized(true);
1514
1536
  }
1537
+ span2.setStatus({ code: SpanStatusCode.OK });
1538
+ span2.end();
1515
1539
  return;
1516
1540
  }
1517
1541
  if (!actions.createTerminalSession) {
@@ -1519,22 +1543,46 @@ var TerminalSession = forwardRef4((props, ref) => {
1519
1543
  setIsInitialized(true);
1520
1544
  return;
1521
1545
  }
1546
+ const span = tracer.startSpan("terminal.session.create", {
1547
+ attributes: {
1548
+ "session.cwd": cwd ?? "",
1549
+ "session.context": sessionContext ?? ""
1550
+ }
1551
+ });
1522
1552
  const newId = await actions.createTerminalSession({
1523
1553
  cwd,
1524
1554
  command,
1525
1555
  context: sessionContext
1526
1556
  });
1527
1557
  pendingSessionIdRef.current = newId;
1528
- if (!mounted)
1558
+ span.setAttribute("session.id", newId);
1559
+ if (!mounted) {
1560
+ span.setStatus({ code: SpanStatusCode.OK });
1561
+ span.end();
1529
1562
  return;
1563
+ }
1530
1564
  if (enableOwnership) {
1531
1565
  await claimAndConnect(newId);
1532
1566
  }
1533
1567
  setLocalSessionId(newId);
1534
1568
  setIsInitialized(true);
1535
1569
  onSessionCreated?.(newId);
1570
+ span.setStatus({ code: SpanStatusCode.OK });
1571
+ span.end();
1536
1572
  } catch (err) {
1537
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();
1538
1586
  if (mounted)
1539
1587
  setIsInitialized(true);
1540
1588
  }
@@ -1543,7 +1591,18 @@ var TerminalSession = forwardRef4((props, ref) => {
1543
1591
  return () => {
1544
1592
  mounted = false;
1545
1593
  if (!persistOnUnmount && pendingSessionIdRef.current && actions.destroyTerminalSession) {
1546
- actions.destroyTerminalSession(pendingSessionIdRef.current);
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
+ });
1547
1606
  }
1548
1607
  };
1549
1608
  }, []);
@@ -2204,350 +2263,21 @@ var useTabKeyboardShortcuts = ({
2204
2263
  return () => window.removeEventListener("keydown", handleKeyDown);
2205
2264
  }, [enabled, onNewTab, onCloseTab, onSwitchToTab]);
2206
2265
  };
2207
- // src/panels/TerminalPanel.tsx
2208
- import { useTheme as useTheme6 } from "@principal-ade/industry-theme";
2209
- import { Lock, Unlock, ArrowDown } from "lucide-react";
2210
- import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
2211
-
2212
- // src/panel-types/index.ts
2213
- function getTerminalSessions(context2) {
2214
- return context2.terminal?.data ?? [];
2215
- }
2216
- function getTerminalSession(context2, sessionId) {
2217
- const sessions = getTerminalSessions(context2);
2218
- return sessions.find((s) => s.id === sessionId);
2219
- }
2220
- function isTerminalLoading(context2) {
2221
- return context2.terminal?.loading ?? false;
2222
- }
2223
- function getRepositoryPath(context2) {
2224
- return context2.currentScope.repository?.path ?? null;
2225
- }
2226
- function getWorkspacePath(context2) {
2227
- return context2.currentScope.workspace?.path ?? null;
2228
- }
2229
- function getTerminalDirectory(context2, terminalScope = "repository") {
2230
- switch (terminalScope) {
2231
- case "workspace":
2232
- return getWorkspacePath(context2);
2233
- case "repository":
2234
- return getRepositoryPath(context2) ?? getWorkspacePath(context2);
2235
- default:
2236
- return getRepositoryPath(context2) ?? getWorkspacePath(context2);
2237
- }
2238
- }
2239
- function getTerminalSlice(context2) {
2240
- return context2.terminal;
2241
- }
2242
-
2243
- // src/panels/TerminalPanel.tsx
2244
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2245
- var TerminalPanel = ({
2246
- context: context2,
2247
- actions,
2248
- events: _events,
2249
- terminalScope = "repository",
2250
- allowTransparency = false,
2251
- backgroundColor
2252
- }) => {
2253
- const { theme } = useTheme6();
2254
- const [sessionId, setSessionId] = useState4(null);
2255
- const [error, setError] = useState4(null);
2256
- const [isInitializing, setIsInitializing] = useState4(true);
2257
- const [scrollPosition, setScrollPosition] = useState4({
2258
- isAtTop: false,
2259
- isAtBottom: true,
2260
- isScrollLocked: false
2261
- });
2262
- const terminalRef = useRef4(null);
2263
- const isScrollLockedRef = useRef4(scrollPosition.isScrollLocked);
2264
- const terminalDirectory = getTerminalDirectory(context2, terminalScope);
2265
- const pendingSessionIdRef = useRef4(null);
2266
- useEffect4(() => {
2267
- let mounted = true;
2268
- const initTerminal = async () => {
2269
- try {
2270
- if (!actions.createTerminalSession) {
2271
- throw new Error("Terminal actions not available. Host must provide createTerminalSession action.");
2272
- }
2273
- const id = await actions.createTerminalSession({
2274
- cwd: terminalDirectory || undefined
2275
- });
2276
- pendingSessionIdRef.current = id;
2277
- if (actions.claimTerminalOwnership) {
2278
- await actions.claimTerminalOwnership(id);
2279
- }
2280
- if (mounted) {
2281
- setSessionId(id);
2282
- setIsInitializing(false);
2283
- }
2284
- } catch (err) {
2285
- if (mounted) {
2286
- setError(err instanceof Error ? err.message : String(err));
2287
- setIsInitializing(false);
2288
- }
2289
- }
2290
- };
2291
- initTerminal();
2292
- return () => {
2293
- mounted = false;
2294
- if (pendingSessionIdRef.current && actions.destroyTerminalSession) {
2295
- actions.destroyTerminalSession(pendingSessionIdRef.current);
2296
- }
2297
- };
2298
- }, []);
2299
- useEffect4(() => {
2300
- if (!sessionId)
2301
- return;
2302
- if (!actions.onTerminalData) {
2303
- setError("Host does not provide onTerminalData. Terminal data cannot be displayed.");
2304
- return;
2305
- }
2306
- let cursorMovedToHome = false;
2307
- let lastWriteTime = 0;
2308
- let autoScrollTimeout = null;
2309
- const unsubscribe = actions.onTerminalData(sessionId, (data) => {
2310
- if (!terminalRef.current)
2311
- return;
2312
- if (data.includes("\x1B[H")) {
2313
- cursorMovedToHome = true;
2314
- lastWriteTime = Date.now();
2315
- }
2316
- terminalRef.current.write(data);
2317
- if (cursorMovedToHome && isScrollLockedRef.current) {
2318
- if (autoScrollTimeout)
2319
- clearTimeout(autoScrollTimeout);
2320
- autoScrollTimeout = setTimeout(() => {
2321
- const timeSinceLastWrite = Date.now() - lastWriteTime;
2322
- if (timeSinceLastWrite >= 100 && cursorMovedToHome && terminalRef.current) {
2323
- terminalRef.current.write("\x1B[9999;1H");
2324
- cursorMovedToHome = false;
2325
- }
2326
- }, 100);
2327
- }
2328
- lastWriteTime = Date.now();
2329
- });
2330
- return () => {
2331
- if (autoScrollTimeout)
2332
- clearTimeout(autoScrollTimeout);
2333
- unsubscribe();
2334
- };
2335
- }, [sessionId, actions.onTerminalData]);
2336
- const handleTerminalData = useCallback5((data) => {
2337
- if (sessionId && actions.writeToTerminal) {
2338
- actions.writeToTerminal(sessionId, data);
2339
- }
2340
- }, [sessionId, actions.writeToTerminal]);
2341
- const hasNotifiedPtyRef = useRef4(false);
2342
- const handleTerminalResize = useCallback5((cols, rows) => {
2343
- if (sessionId && actions.resizeTerminal) {
2344
- const isInitialNotification = !hasNotifiedPtyRef.current;
2345
- actions.resizeTerminal(sessionId, cols, rows);
2346
- if (isInitialNotification && actions.writeToTerminal) {
2347
- setTimeout(() => {
2348
- actions.writeToTerminal(sessionId, "\f");
2349
- }, 50);
2350
- }
2351
- hasNotifiedPtyRef.current = true;
2352
- }
2353
- }, [sessionId, actions.resizeTerminal, actions.writeToTerminal]);
2354
- useEffect4(() => {
2355
- hasNotifiedPtyRef.current = false;
2356
- }, [sessionId]);
2357
- useEffect4(() => {
2358
- if (!sessionId || !actions.resizeTerminal)
2359
- return;
2360
- if (hasNotifiedPtyRef.current)
2361
- return;
2362
- const term = terminalRef.current?.getTerminal();
2363
- if (!term || !term.cols || !term.rows)
2364
- return;
2365
- actions.resizeTerminal(sessionId, term.cols, term.rows);
2366
- hasNotifiedPtyRef.current = true;
2367
- if (actions.writeToTerminal) {
2368
- const writeFn = actions.writeToTerminal;
2369
- setTimeout(() => writeFn(sessionId, "\f"), 50);
2370
- }
2371
- }, [sessionId, actions.resizeTerminal, actions.writeToTerminal]);
2372
- const handleScrollPositionChange = useCallback5((position) => {
2373
- setScrollPosition(position);
2374
- isScrollLockedRef.current = position.isScrollLocked;
2375
- }, []);
2376
- const sessionInfo = sessionId ? getTerminalSession(context2, sessionId) : undefined;
2377
- if (error) {
2378
- return /* @__PURE__ */ jsxs7("div", {
2379
- style: {
2380
- padding: "20px",
2381
- color: "#ef4444",
2382
- backgroundColor: allowTransparency ? "transparent" : "#1a1a1a",
2383
- height: "100%",
2384
- display: "flex",
2385
- alignItems: "center",
2386
- justifyContent: "center",
2387
- flexDirection: "column",
2388
- gap: "10px"
2389
- },
2390
- children: [
2391
- /* @__PURE__ */ jsx9("div", {
2392
- style: { fontSize: "16px", fontWeight: "bold" },
2393
- children: "Terminal Error"
2394
- }),
2395
- /* @__PURE__ */ jsx9("div", {
2396
- style: { fontSize: "14px", opacity: 0.8 },
2397
- children: error
2398
- })
2399
- ]
2400
- });
2401
- }
2402
- if (isInitializing || !sessionId) {
2403
- return /* @__PURE__ */ jsx9("div", {
2404
- style: {
2405
- padding: "20px",
2406
- color: "#a0a0a0",
2407
- backgroundColor: allowTransparency ? "transparent" : "#1a1a1a",
2408
- height: "100%",
2409
- display: "flex",
2410
- alignItems: "center",
2411
- justifyContent: "center"
2412
- },
2413
- children: "Initializing terminal..."
2414
- });
2415
- }
2416
- const handleScrollToBottom = () => {
2417
- terminalRef.current?.scrollToBottom();
2418
- };
2419
- const handleToggleScrollLock = () => {
2420
- if (scrollPosition.isScrollLocked) {
2421
- const terminal = terminalRef.current?.getTerminal();
2422
- if (terminal) {
2423
- terminal.scrollLines(-1);
2424
- }
2425
- } else {
2426
- terminalRef.current?.scrollToBottom();
2427
- }
2428
- };
2429
- return /* @__PURE__ */ jsxs7("div", {
2430
- style: { height: "100%", width: "100%", display: "flex", flexDirection: "column" },
2431
- children: [
2432
- /* @__PURE__ */ jsxs7("div", {
2433
- style: {
2434
- display: "flex",
2435
- gap: "8px",
2436
- padding: "8px 12px",
2437
- backgroundColor: allowTransparency ? "transparent" : theme.colors.backgroundSecondary,
2438
- borderBottom: `1px solid ${theme.colors.border}`,
2439
- alignItems: "center"
2440
- },
2441
- children: [
2442
- /* @__PURE__ */ jsxs7("span", {
2443
- style: {
2444
- fontSize: "12px",
2445
- color: theme.colors.textSecondary,
2446
- marginRight: "auto",
2447
- fontFamily: theme.fonts.monospace
2448
- },
2449
- children: [
2450
- sessionInfo?.cwd || "Terminal",
2451
- " • ",
2452
- sessionInfo?.shell
2453
- ]
2454
- }),
2455
- /* @__PURE__ */ jsxs7("button", {
2456
- onClick: handleToggleScrollLock,
2457
- style: {
2458
- display: "flex",
2459
- alignItems: "center",
2460
- gap: "4px",
2461
- fontSize: "11px",
2462
- padding: "4px 8px",
2463
- borderRadius: "4px",
2464
- backgroundColor: scrollPosition.isScrollLocked ? `${theme.colors.success}22` : `${theme.colors.warning}22`,
2465
- color: scrollPosition.isScrollLocked ? theme.colors.success : theme.colors.warning,
2466
- border: `1px solid ${scrollPosition.isScrollLocked ? `${theme.colors.success}44` : `${theme.colors.warning}44`}`,
2467
- cursor: "pointer",
2468
- transition: "opacity 0.2s"
2469
- },
2470
- onMouseEnter: (e) => e.currentTarget.style.opacity = "0.8",
2471
- onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
2472
- title: scrollPosition.isScrollLocked ? "Click to unlock scroll" : "Click to lock scroll to bottom",
2473
- children: [
2474
- scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx9(Lock, {
2475
- size: 12
2476
- }) : /* @__PURE__ */ jsx9(Unlock, {
2477
- size: 12
2478
- }),
2479
- /* @__PURE__ */ jsx9("span", {
2480
- children: scrollPosition.isScrollLocked ? "Locked" : "Unlocked"
2481
- })
2482
- ]
2483
- }),
2484
- /* @__PURE__ */ jsxs7("button", {
2485
- onClick: handleScrollToBottom,
2486
- disabled: scrollPosition.isAtBottom,
2487
- style: {
2488
- display: "flex",
2489
- alignItems: "center",
2490
- gap: "4px",
2491
- fontSize: "11px",
2492
- padding: "4px 10px",
2493
- borderRadius: "4px",
2494
- backgroundColor: scrollPosition.isAtBottom ? theme.colors.backgroundHover : theme.colors.accent,
2495
- color: scrollPosition.isAtBottom ? theme.colors.textTertiary : theme.colors.text,
2496
- border: `1px solid ${theme.colors.border}`,
2497
- cursor: scrollPosition.isAtBottom ? "not-allowed" : "pointer",
2498
- transition: "opacity 0.2s",
2499
- opacity: scrollPosition.isAtBottom ? 0.5 : 1
2500
- },
2501
- onMouseEnter: (e) => !scrollPosition.isAtBottom && (e.currentTarget.style.opacity = "0.8"),
2502
- onMouseLeave: (e) => !scrollPosition.isAtBottom && (e.currentTarget.style.opacity = "1"),
2503
- title: "Scroll to bottom and lock",
2504
- children: [
2505
- /* @__PURE__ */ jsx9(ArrowDown, {
2506
- size: 12
2507
- }),
2508
- /* @__PURE__ */ jsx9("span", {
2509
- children: "Bottom"
2510
- })
2511
- ]
2512
- })
2513
- ]
2514
- }),
2515
- /* @__PURE__ */ jsx9("div", {
2516
- style: { flex: 1 },
2517
- children: /* @__PURE__ */ jsx9(ThemedTerminalWithProvider, {
2518
- ref: terminalRef,
2519
- onData: handleTerminalData,
2520
- onResize: handleTerminalResize,
2521
- onScrollPositionChange: handleScrollPositionChange,
2522
- hideHeader: true,
2523
- autoFocus: true,
2524
- convertEol: true,
2525
- cursorBlink: true,
2526
- scrollback: 1e4,
2527
- enableSearch: true,
2528
- enableWebLinks: true,
2529
- allowTransparency,
2530
- backgroundColor
2531
- })
2532
- })
2533
- ]
2534
- });
2535
- };
2536
2266
  // src/panels/TabbedTerminalPanel.tsx
2537
- import { useTheme as useTheme7 } from "@principal-ade/industry-theme";
2267
+ import { useTheme as useTheme6 } from "@principal-ade/industry-theme";
2538
2268
  import { CollapsibleSplitPane } from "@principal-ade/panels";
2539
- import { Terminal as TerminalIcon2, Lock as Lock2, Unlock as Unlock2, Box, Boxes, Paperclip } from "lucide-react";
2269
+ import { Terminal as TerminalIcon2, Lock, Unlock, Box, Boxes, Paperclip } from "lucide-react";
2540
2270
  import React3, {
2541
- useState as useState5,
2542
- useCallback as useCallback6,
2543
- useEffect as useEffect5,
2544
- useRef as useRef5
2271
+ useState as useState4,
2272
+ useCallback as useCallback5,
2273
+ useEffect as useEffect4,
2274
+ useRef as useRef4
2545
2275
  } from "react";
2546
- import { jsx as jsx10, jsxs as jsxs8, Fragment as Fragment2 } from "react/jsx-runtime";
2547
- var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs8("div", {
2276
+ import { jsx as jsx9, jsxs as jsxs7, Fragment as Fragment2 } from "react/jsx-runtime";
2277
+ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs7("div", {
2548
2278
  style: { display: "flex", gap: 1, alignItems: "center", height: 12 },
2549
2279
  children: [
2550
- [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx10("div", {
2280
+ [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx9("div", {
2551
2281
  style: {
2552
2282
  width: 2,
2553
2283
  height: 10,
@@ -2558,7 +2288,7 @@ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs8("div",
2558
2288
  animation: isAnimating ? `waveSine 1.2s ease-in-out ${i * 0.1}s infinite` : "none"
2559
2289
  }
2560
2290
  }, i)),
2561
- /* @__PURE__ */ jsx10("style", {
2291
+ /* @__PURE__ */ jsx9("style", {
2562
2292
  children: `
2563
2293
  @keyframes waveSine {
2564
2294
  0%, 100% { transform: scaleY(0.4); }
@@ -2569,376 +2299,69 @@ var ActivityIndicator = ({ color, isAnimating }) => /* @__PURE__ */ jsxs8("div",
2569
2299
  ]
2570
2300
  });
2571
2301
  function TerminalTabContentInner(props, ref) {
2572
- const { tab, sessionId, isActive, isVisible, actions, events, terminalContext, onSessionCreated, onScrollPositionChange, isForeign = false, defaultScrollLocked, activityDetection = true, activityTimeout = 500, autoShowBlinds = false, onActivityStateChange } = props;
2573
- const { theme } = useTheme7();
2574
- const terminalRef = useRef5(null);
2575
- const [localSessionId, setLocalSessionId] = useState5(sessionId);
2576
- const [isInitialized, setIsInitialized] = useState5(false);
2577
- const hasInitializedRef = useRef5(false);
2578
- const [scrollPosition, setScrollPosition] = useState5({
2579
- isAtTop: false,
2580
- isAtBottom: true,
2581
- isScrollLocked: false
2582
- });
2583
- const [shouldRenderTerminal, setShouldRenderTerminal] = useState5(true);
2584
- const [ownerWindowId, setOwnerWindowId] = useState5(null);
2585
- const needsRefreshOnResizeRef = useRef5(false);
2586
- const claimAndConnect = useCallback6(async (targetSessionId, force = false) => {
2587
- try {
2588
- if (actions.claimTerminalOwnership) {
2589
- await actions.claimTerminalOwnership(targetSessionId, force);
2590
- }
2591
- if (force && actions.requestTerminalDataPort) {
2592
- await actions.requestTerminalDataPort(targetSessionId);
2593
- }
2594
- setShouldRenderTerminal(true);
2595
- setOwnerWindowId(null);
2596
- if (force) {
2597
- needsRefreshOnResizeRef.current = true;
2598
- }
2599
- } catch (error) {
2600
- console.error("[TerminalTabContent] Failed to claim ownership:", error);
2601
- throw error;
2602
- }
2603
- }, [actions]);
2604
- useEffect5(() => {
2605
- if (hasInitializedRef.current) {
2606
- return;
2607
- }
2608
- hasInitializedRef.current = true;
2609
- let mounted = true;
2610
- const initSession = async () => {
2611
- try {
2612
- if (sessionId) {
2613
- const tracer2 = getTracer();
2614
- const reconnectSpan = tracer2.startSpan("terminal.session.reconnect", {
2615
- attributes: {
2616
- "session.id": sessionId,
2617
- "session.context": `${terminalContext}:${tab.id}`,
2618
- "session.isForeign": isForeign
2619
- }
2620
- });
2621
- reconnectSpan.addEvent("terminal.session.reconnecting", {
2622
- "session.id": sessionId,
2623
- "reconnect.reason": "component_remount"
2624
- });
2625
- if (isForeign && actions.checkTerminalOwnership) {
2626
- const status = await actions.checkTerminalOwnership(sessionId);
2627
- if (status.ownedByWindowId && !status.ownedByThisWindow) {
2628
- setShouldRenderTerminal(false);
2629
- setOwnerWindowId(status.ownedByWindowId);
2630
- reconnectSpan.addEvent("terminal.session.reconnect_blocked", {
2631
- "session.id": sessionId,
2632
- "owner.windowId": status.ownedByWindowId
2633
- });
2634
- }
2635
- } else {
2636
- await claimAndConnect(sessionId);
2637
- reconnectSpan.addEvent("terminal.session.reconnected", {
2638
- "session.id": sessionId
2639
- });
2640
- }
2641
- reconnectSpan.setStatus({ code: SpanStatusCode.OK });
2642
- reconnectSpan.end();
2643
- setLocalSessionId(sessionId);
2644
- setIsInitialized(true);
2645
- return;
2646
- }
2647
- if (!actions.createTerminalSession) {
2648
- return;
2649
- }
2650
- const newSessionId = await actions.createTerminalSession({
2651
- cwd: tab.directory,
2652
- command: tab.command,
2653
- context: `${terminalContext}:${tab.id}`
2654
- });
2655
- if (!mounted)
2656
- return;
2657
- const tracer = getTracer();
2658
- const span = tracer.startSpan("terminal.session", {
2659
- attributes: {
2660
- "session.id": newSessionId,
2661
- "session.cwd": tab.directory,
2662
- "session.context": `${terminalContext}:${tab.id}`
2663
- }
2664
- });
2665
- span.addEvent("terminal.session.created", {
2666
- "session.id": newSessionId,
2667
- "session.cwd": tab.directory
2668
- });
2669
- span.setStatus({ code: SpanStatusCode.OK });
2670
- span.end();
2671
- setLocalSessionId(newSessionId);
2672
- setIsInitialized(true);
2673
- onSessionCreated(tab.id, newSessionId);
2674
- await claimAndConnect(newSessionId);
2675
- } catch (error) {
2676
- console.error("[TerminalTabContent] Failed to create session:", error);
2677
- const tracer = getTracer();
2678
- const span = tracer.startSpan("terminal.session", {
2679
- attributes: {
2680
- "session.action": "create",
2681
- "error.occurred": true
2682
- }
2683
- });
2684
- span.addEvent("terminal.session.error", {
2685
- "error.message": error instanceof Error ? error.message : "Unknown error"
2686
- });
2687
- span.recordException(error);
2688
- span.setStatus({ code: SpanStatusCode.ERROR, message: "Session creation failed" });
2689
- span.end();
2690
- }
2691
- };
2692
- initSession();
2693
- return () => {
2694
- mounted = false;
2695
- };
2696
- }, []);
2697
- useEffect5(() => {
2698
- if (!localSessionId || !isInitialized || !shouldRenderTerminal) {
2699
- return;
2700
- }
2701
- if (!actions.onTerminalData) {
2702
- return;
2703
- }
2704
- const tracer = getTracer();
2705
- const subscribeSpan = tracer.startSpan("terminal.data.subscribe", {
2706
- attributes: {
2707
- "session.id": localSessionId,
2708
- "tab.id": tab.id
2709
- }
2710
- });
2711
- subscribeSpan.addEvent("terminal.data.subscribed", {
2712
- "session.id": localSessionId
2713
- });
2714
- console.log("[TerminalTabContent] SUBSCRIBING to terminal data", { tabId: tab.id, sessionId: localSessionId });
2715
- let hasReceivedData = false;
2716
- const unsubscribe = actions.onTerminalData(localSessionId, (data) => {
2717
- if (terminalRef.current) {
2718
- if (!hasReceivedData) {
2719
- hasReceivedData = true;
2720
- subscribeSpan.addEvent("terminal.data.first_received", {
2721
- "session.id": localSessionId,
2722
- "data.length": data.length
2723
- });
2724
- }
2725
- terminalRef.current.write(data);
2726
- }
2727
- });
2728
- subscribeSpan.setStatus({ code: SpanStatusCode.OK });
2729
- subscribeSpan.end();
2730
- return () => {
2731
- const unsubscribeSpan = tracer.startSpan("terminal.data.unsubscribe", {
2732
- attributes: {
2733
- "session.id": localSessionId,
2734
- "tab.id": tab.id,
2735
- "data.wasReceived": hasReceivedData
2736
- }
2737
- });
2738
- unsubscribeSpan.addEvent("terminal.data.unsubscribed", {
2739
- "session.id": localSessionId
2740
- });
2741
- unsubscribeSpan.setStatus({ code: SpanStatusCode.OK });
2742
- unsubscribeSpan.end();
2743
- console.log("[TerminalTabContent] UNSUBSCRIBING from terminal data", { tabId: tab.id, sessionId: localSessionId });
2744
- unsubscribe();
2745
- };
2746
- }, [localSessionId, isInitialized, actions, shouldRenderTerminal, tab.id]);
2747
- const handleData = useCallback6((data) => {
2748
- if (localSessionId && actions.writeToTerminal) {
2749
- actions.writeToTerminal(localSessionId, data);
2750
- }
2751
- }, [localSessionId, actions]);
2752
- const handleResize = useCallback6((cols, rows) => {
2753
- if (localSessionId && actions.resizeTerminal) {
2754
- actions.resizeTerminal(localSessionId, cols, rows);
2755
- }
2756
- }, [localSessionId, actions]);
2757
- const handleReady = useCallback6((cols, rows) => {
2758
- if (!localSessionId || !actions.resizeTerminal) {
2759
- return;
2760
- }
2761
- const shouldForce = needsRefreshOnResizeRef.current;
2762
- if (!shouldForce) {
2763
- actions.resizeTerminal(localSessionId, cols, rows, false);
2764
- return;
2765
- }
2766
- needsRefreshOnResizeRef.current = false;
2767
- const restoreBufferAndResize = async () => {
2768
- let bufferRestored = false;
2769
- if (actions.getTerminalBuffer && terminalRef.current) {
2770
- try {
2771
- const buffer = await actions.getTerminalBuffer(localSessionId);
2772
- if (buffer) {
2773
- terminalRef.current.write(buffer);
2774
- bufferRestored = true;
2775
- }
2776
- } catch (error) {
2777
- console.warn("[TabbedTerminalPanel] Failed to restore buffer:", error);
2778
- }
2779
- }
2780
- const forceResize = !bufferRestored;
2781
- actions.resizeTerminal(localSessionId, cols, rows, forceResize);
2782
- };
2783
- restoreBufferAndResize();
2784
- }, [localSessionId, actions]);
2785
- const handleLinkClick = useCallback6((url, modifiers) => {
2786
- if (localSessionId) {
2787
- events.emit({
2788
- type: "terminal:link-click",
2789
- source: "TabbedTerminalPanel",
2790
- timestamp: Date.now(),
2791
- payload: {
2792
- url,
2793
- sessionId: localSessionId,
2794
- shiftKey: modifiers.shiftKey,
2795
- metaKey: modifiers.metaKey,
2796
- ctrlKey: modifiers.ctrlKey,
2797
- altKey: modifiers.altKey
2798
- }
2799
- });
2800
- }
2801
- }, [localSessionId, events]);
2802
- useEffect5(() => {
2803
- if (!localSessionId || !actions.onOwnershipLost) {
2804
- return;
2805
- }
2806
- const unsubscribe = actions.onOwnershipLost((data) => {
2807
- if (data.sessionId === localSessionId) {
2808
- setShouldRenderTerminal(false);
2809
- setOwnerWindowId(data.newOwnerWindowId);
2810
- }
2811
- });
2812
- return () => {
2813
- unsubscribe();
2814
- };
2815
- }, [localSessionId, actions]);
2816
- const handleTakeControl = useCallback6(async () => {
2817
- if (!localSessionId) {
2818
- return;
2819
- }
2820
- await claimAndConnect(localSessionId, true);
2821
- }, [localSessionId, claimAndConnect]);
2822
- const handleScrollPositionChange = useCallback6((position) => {
2823
- setScrollPosition(position);
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]);
2322
+ const handleScrollPositionChange = useCallback5((position) => {
2824
2323
  onScrollPositionChange?.(tab.id, position);
2825
- }, [tab.id, onScrollPositionChange]);
2826
- const handleShortcut = useCallback6((shortcutEvent) => {
2827
- if (localSessionId) {
2828
- events.emit({
2829
- type: "terminal:shortcut",
2830
- source: "TabbedTerminalPanel",
2831
- timestamp: Date.now(),
2832
- payload: {
2833
- shortcut: shortcutEvent.shortcut,
2834
- sessionId: localSessionId
2835
- }
2836
- });
2324
+ }, [onScrollPositionChange, tab.id]);
2325
+ const handleActivityChange = useCallback5((state) => {
2326
+ const sid = sessionRef.current?.getSessionId();
2327
+ if (sid) {
2328
+ onActivityStateChange?.(sid, state.isActive);
2837
2329
  }
2838
- }, [localSessionId, events]);
2839
- const handleActivityChange = useCallback6((state) => {
2840
- if (localSessionId) {
2841
- onActivityStateChange?.(localSessionId, state.isActive);
2842
- events.emit({
2843
- type: "terminal:activity-changed",
2844
- source: "TabbedTerminalPanel",
2845
- timestamp: Date.now(),
2846
- payload: {
2847
- sessionId: localSessionId,
2848
- activityType: state.isActive ? "started" : "stopped",
2849
- isWorking: state.isActive
2850
- }
2851
- });
2330
+ if (autoShowBlinds) {
2331
+ setIsWorkingFromActivity(state.isActive);
2852
2332
  }
2853
- }, [localSessionId, events, onActivityStateChange]);
2854
- const handleScrollToBottom = useCallback6(() => {
2855
- terminalRef.current?.scrollToBottom();
2856
- }, []);
2857
- const handleToggleScrollLock = useCallback6(() => {
2858
- if (scrollPosition.isScrollLocked) {
2859
- const terminal = terminalRef.current?.getTerminal();
2860
- if (terminal) {
2861
- terminal.scrollLines(-1);
2862
- }
2863
- } else {
2864
- terminalRef.current?.scrollToBottom();
2865
- }
2866
- }, [scrollPosition.isScrollLocked]);
2333
+ }, [autoShowBlinds, onActivityStateChange]);
2867
2334
  React3.useImperativeHandle(ref, () => ({
2868
- scrollToBottom: handleScrollToBottom,
2869
- toggleScrollLock: handleToggleScrollLock
2870
- }), [handleScrollToBottom, handleToggleScrollLock]);
2871
- if (!isInitialized) {
2872
- return /* @__PURE__ */ jsxs8("div", {
2873
- style: {
2874
- display: isActive ? "flex" : "none",
2875
- height: "100%",
2876
- width: "100%",
2877
- backgroundColor: theme.colors.background,
2878
- padding: "10px 0 0 10px"
2879
- },
2880
- children: [
2881
- /* @__PURE__ */ jsx10("div", {
2882
- style: {
2883
- width: "8px",
2884
- height: "17px",
2885
- backgroundColor: theme.colors.text,
2886
- animation: "blink 1s step-end infinite"
2887
- }
2888
- }),
2889
- /* @__PURE__ */ jsx10("style", {
2890
- children: `
2891
- @keyframes blink {
2892
- 0%, 100% { opacity: 1; }
2893
- 50% { opacity: 0; }
2894
- }
2895
- `
2896
- })
2897
- ]
2898
- });
2899
- }
2900
- const overlayState = !shouldRenderTerminal ? {
2901
- message: "This terminal is active in another window",
2902
- subtitle: ownerWindowId ? `Window ID: ${ownerWindowId}` : "Another window owns this terminal session",
2903
- actions: [
2904
- {
2905
- label: "Take Control",
2906
- onClick: handleTakeControl,
2907
- primary: true
2908
- }
2909
- ],
2910
- opacity: 1
2911
- } : undefined;
2912
- return /* @__PURE__ */ jsx10("div", {
2335
+ scrollToBottom: () => sessionRef.current?.scrollToBottom(),
2336
+ toggleScrollLock: () => sessionRef.current?.toggleScrollLock()
2337
+ }), []);
2338
+ return /* @__PURE__ */ jsx9("div", {
2913
2339
  style: {
2914
- display: isActive ? "flex" : "none",
2340
+ display: "flex",
2915
2341
  flexDirection: "column",
2916
2342
  height: "100%",
2917
2343
  width: "100%"
2918
2344
  },
2919
- children: /* @__PURE__ */ jsx10(ThemedTerminalWithProvider, {
2920
- ref: terminalRef,
2921
- onData: shouldRenderTerminal ? handleData : undefined,
2922
- onResize: shouldRenderTerminal ? handleResize : undefined,
2923
- onReady: shouldRenderTerminal ? handleReady : undefined,
2924
- onLinkClick: shouldRenderTerminal ? handleLinkClick : undefined,
2925
- onScrollPositionChange: shouldRenderTerminal ? handleScrollPositionChange : undefined,
2926
- onShortcut: handleShortcut,
2927
- hideHeader: true,
2928
- autoFocus: isActive && shouldRenderTerminal,
2929
- isVisible: isVisible && isActive,
2930
- defaultScrollLocked,
2931
- convertEol: true,
2932
- cursorBlink: shouldRenderTerminal,
2933
- scrollback: 1e4,
2934
- 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,
2935
2356
  activityDetection,
2936
2357
  activityTimeout,
2937
- autoShowBlinds,
2938
- onActivityChange: shouldRenderTerminal ? handleActivityChange : undefined,
2939
- enableWebLinks: true,
2940
- overlayState
2941
- }, shouldRenderTerminal ? "active" : "overlay")
2358
+ onActivityChange: handleActivityChange,
2359
+ onScrollPositionChange: handleScrollPositionChange,
2360
+ defaultScrollLocked,
2361
+ autoFocus: isActive,
2362
+ isVisible: isVisible && isActive,
2363
+ isWorking: autoShowBlinds && isWorkingFromActivity
2364
+ })
2942
2365
  });
2943
2366
  }
2944
2367
  var areTerminalTabContentPropsEqual = (prevProps, nextProps) => {
@@ -3005,11 +2428,11 @@ var TabbedTerminalPanelInner = ({
3005
2428
  onTabAssociate: onTabAssociateProp,
3006
2429
  onTabDissociate: _onTabDissociate
3007
2430
  }) => {
3008
- const { theme } = useTheme7();
2431
+ const { theme } = useTheme6();
3009
2432
  const onTabAssociate = actions.onTabAssociate ?? onTabAssociateProp;
3010
- const [ownedTabs, setOwnedTabs] = useState5(initialTabs);
3011
- const [foreignTabs, setForeignTabs] = useState5([]);
3012
- const [internalActiveTabId, setInternalActiveTabId] = useState5(null);
2433
+ const [ownedTabs, setOwnedTabs] = useState4(initialTabs);
2434
+ const [foreignTabs, setForeignTabs] = useState4([]);
2435
+ const [internalActiveTabId, setInternalActiveTabId] = useState4(null);
3013
2436
  const isControlled = activeTabIdProp !== undefined;
3014
2437
  const activeTabId = isControlled ? activeTabIdProp : internalActiveTabId;
3015
2438
  const setActiveTabId = React3.useCallback((tabId) => {
@@ -3020,20 +2443,20 @@ var TabbedTerminalPanelInner = ({
3020
2443
  onActiveTabChange?.(tabId);
3021
2444
  }
3022
2445
  }, [isControlled, onActiveTabChange]);
3023
- const [activatedTabs, setActivatedTabs] = useState5(() => new Set);
2446
+ const [activatedTabs, setActivatedTabs] = useState4(() => new Set);
3024
2447
  React3.useEffect(() => {
3025
2448
  if (activeTabId && !activatedTabs.has(activeTabId)) {
3026
2449
  setActivatedTabs((prev) => new Set(prev).add(activeTabId));
3027
2450
  }
3028
2451
  }, [activeTabId, activatedTabs]);
3029
- const [sessionIds, setSessionIds] = useState5(new Map);
3030
- const [scrollPositions, setScrollPositions] = useState5(new Map);
3031
- const [activityStates, setActivityStates] = useState5(new Map);
2452
+ const [sessionIds, setSessionIds] = useState4(new Map);
2453
+ const [scrollPositions, setScrollPositions] = useState4(new Map);
2454
+ const [activityStates, setActivityStates] = useState4(new Map);
3032
2455
  const customTabsKey = React3.useMemo(() => {
3033
2456
  const customTabs = initialTabs.filter((tab) => tab.contentType !== "terminal");
3034
2457
  return JSON.stringify(customTabs);
3035
2458
  }, [initialTabs]);
3036
- useEffect5(() => {
2459
+ useEffect4(() => {
3037
2460
  const customTabsFromProp = initialTabs.filter((tab) => tab.contentType !== "terminal");
3038
2461
  setOwnedTabs((prevTabs) => {
3039
2462
  const existingTerminalTabs = prevTabs.filter((tab) => tab.contentType === "terminal");
@@ -3054,7 +2477,7 @@ var TabbedTerminalPanelInner = ({
3054
2477
  return mergedTabs;
3055
2478
  });
3056
2479
  }, [customTabsKey]);
3057
- useEffect5(() => {
2480
+ useEffect4(() => {
3058
2481
  if (!requestFocusTabId) {
3059
2482
  return;
3060
2483
  }
@@ -3069,7 +2492,7 @@ var TabbedTerminalPanelInner = ({
3069
2492
  onFocusTabHandled?.();
3070
2493
  }
3071
2494
  }, [requestFocusTabId, ownedTabs, foreignTabs, setActiveTabId, onFocusTabHandled, activeTabId]);
3072
- const getOwnedTabLabel = useCallback6((index, _directory) => {
2495
+ const getOwnedTabLabel = useCallback5((index, _directory) => {
3073
2496
  if (tabLabelPrefix) {
3074
2497
  return `${tabLabelPrefix} ${index + 1}`;
3075
2498
  }
@@ -3095,9 +2518,9 @@ var TabbedTerminalPanelInner = ({
3095
2518
  }
3096
2519
  }));
3097
2520
  }, [tabs]);
3098
- const tabRefsMap = useRef5(new Map);
3099
- const refCallbacksMap = useRef5(new Map);
3100
- const getRefCallback = useCallback6((tabId) => {
2521
+ const tabRefsMap = useRef4(new Map);
2522
+ const refCallbacksMap = useRef4(new Map);
2523
+ const getRefCallback = useCallback5((tabId) => {
3101
2524
  let callback = refCallbacksMap.current.get(tabId);
3102
2525
  if (!callback) {
3103
2526
  callback = (ref) => {
@@ -3111,10 +2534,10 @@ var TabbedTerminalPanelInner = ({
3111
2534
  }
3112
2535
  return callback;
3113
2536
  }, []);
3114
- const hasInitializedRef = useRef5(false);
3115
- const isCreatingTabRef = useRef5(false);
3116
- const headerRef = useRef5(null);
3117
- const handleTabScrollPositionChange = useCallback6((tabId, position) => {
2537
+ const hasInitializedRef = useRef4(false);
2538
+ const isCreatingTabRef = useRef4(false);
2539
+ const headerRef = useRef4(null);
2540
+ const handleTabScrollPositionChange = useCallback5((tabId, position) => {
3118
2541
  setScrollPositions((prev) => new Map(prev).set(tabId, position));
3119
2542
  }, []);
3120
2543
  const defaultScrollPosition = {
@@ -3122,12 +2545,12 @@ var TabbedTerminalPanelInner = ({
3122
2545
  isAtBottom: true,
3123
2546
  isScrollLocked: false
3124
2547
  };
3125
- const handleToggleScrollLock = useCallback6(() => {
2548
+ const handleToggleScrollLock = useCallback5(() => {
3126
2549
  if (activeTabId) {
3127
2550
  tabRefsMap.current.get(activeTabId)?.toggleScrollLock();
3128
2551
  }
3129
2552
  }, [activeTabId]);
3130
- const restoreOwnedSessions = useCallback6(async () => {
2553
+ const restoreOwnedSessions = useCallback5(async () => {
3131
2554
  try {
3132
2555
  let sessions = [];
3133
2556
  if (actions.listTerminalSessions) {
@@ -3179,7 +2602,7 @@ var TabbedTerminalPanelInner = ({
3179
2602
  console.error("[TabbedTerminalPanel] Failed to restore owned sessions:", err);
3180
2603
  }
3181
2604
  }, [terminalContext, sessionIds, activeTabId, onTabsChange, actions, directory, setActiveTabId]);
3182
- const fetchForeignSessions = useCallback6(async () => {
2605
+ const fetchForeignSessions = useCallback5(async () => {
3183
2606
  try {
3184
2607
  if (!actions.listTerminalSessions) {
3185
2608
  return;
@@ -3211,7 +2634,7 @@ var TabbedTerminalPanelInner = ({
3211
2634
  console.error("[TabbedTerminalPanel] Failed to fetch foreign sessions:", err);
3212
2635
  }
3213
2636
  }, [terminalContext, actions]);
3214
- const clearForeignTabs = useCallback6(() => {
2637
+ const clearForeignTabs = useCallback5(() => {
3215
2638
  setForeignTabs((prevForeign) => {
3216
2639
  const foreignTabIds = new Set(prevForeign.map((t) => t.id));
3217
2640
  setSessionIds((prev) => {
@@ -3222,13 +2645,13 @@ var TabbedTerminalPanelInner = ({
3222
2645
  return [];
3223
2646
  });
3224
2647
  }, []);
3225
- useEffect5(() => {
2648
+ useEffect4(() => {
3226
2649
  if (hasInitializedRef.current)
3227
2650
  return;
3228
2651
  hasInitializedRef.current = true;
3229
2652
  restoreOwnedSessions();
3230
2653
  }, []);
3231
- useEffect5(() => {
2654
+ useEffect4(() => {
3232
2655
  const handleSessionCreated2 = (event) => {
3233
2656
  const customEvent = event;
3234
2657
  const { context: context2 } = customEvent.detail || {};
@@ -3242,17 +2665,17 @@ var TabbedTerminalPanelInner = ({
3242
2665
  window.removeEventListener("terminal-session-created", handleSessionCreated2);
3243
2666
  };
3244
2667
  }, [terminalContext, restoreOwnedSessions]);
3245
- useEffect5(() => {
2668
+ useEffect4(() => {
3246
2669
  if (showAllTerminals) {
3247
2670
  fetchForeignSessions();
3248
2671
  } else {
3249
2672
  clearForeignTabs();
3250
2673
  }
3251
2674
  }, [showAllTerminals, fetchForeignSessions, clearForeignTabs]);
3252
- const switchTab = useCallback6((tabId) => {
2675
+ const switchTab = useCallback5((tabId) => {
3253
2676
  setActiveTabId(tabId);
3254
2677
  }, [setActiveTabId]);
3255
- const addNewTab = useCallback6((label, command, targetDirectory) => {
2678
+ const addNewTab = useCallback5((label, command, targetDirectory) => {
3256
2679
  const targetDir = targetDirectory || directory;
3257
2680
  const directoryName = targetDir.split("/").pop() || targetDir;
3258
2681
  const newTab = {
@@ -3270,10 +2693,10 @@ var TabbedTerminalPanelInner = ({
3270
2693
  });
3271
2694
  setActiveTabId(newTab.id);
3272
2695
  }, [directory, onTabsChange]);
3273
- const isForeignTab = useCallback6((tabId) => {
2696
+ const isForeignTab = useCallback5((tabId) => {
3274
2697
  return tabId.startsWith("tab-foreign-");
3275
2698
  }, []);
3276
- const closeTab = useCallback6(async (tabId) => {
2699
+ const closeTab = useCallback5(async (tabId) => {
3277
2700
  const sessionId = sessionIds.get(tabId);
3278
2701
  const isForeign = isForeignTab(tabId);
3279
2702
  if (!isForeign && sessionId && actions.destroyTerminalSession) {
@@ -3343,10 +2766,10 @@ var TabbedTerminalPanelInner = ({
3343
2766
  });
3344
2767
  }
3345
2768
  }, [activeTabId, sessionIds, actions, onTabsChange, isForeignTab, ownedTabs, foreignTabs]);
3346
- const handleSessionCreated = useCallback6((tabId, sessionId) => {
2769
+ const handleSessionCreated = useCallback5((tabId, sessionId) => {
3347
2770
  setSessionIds((prev) => new Map(prev).set(tabId, sessionId));
3348
2771
  }, []);
3349
- const handleActivityStateChange = useCallback6((sessionId, isActive) => {
2772
+ const handleActivityStateChange = useCallback5((sessionId, isActive) => {
3350
2773
  setActivityStates((prev) => {
3351
2774
  const next = new Map(prev);
3352
2775
  if (isActive) {
@@ -3377,7 +2800,7 @@ var TabbedTerminalPanelInner = ({
3377
2800
  }
3378
2801
  }
3379
2802
  });
3380
- const renderTabAccessory = useCallback6((tab) => {
2803
+ const renderTabAccessory = useCallback5((tab) => {
3381
2804
  const tabSessionId = sessionIds.get(tab.id);
3382
2805
  const hasExternalWorkingState = tabSessionId ? workingStates?.[tabSessionId]?.isWorking : false;
3383
2806
  const hasInternalActivity = tabSessionId ? activityStates.get(tabSessionId) : false;
@@ -3386,9 +2809,9 @@ var TabbedTerminalPanelInner = ({
3386
2809
  if (!isActive)
3387
2810
  return null;
3388
2811
  const scrollPosition = scrollPositions.get(tab.id) ?? defaultScrollPosition;
3389
- return /* @__PURE__ */ jsxs8(Fragment2, {
2812
+ return /* @__PURE__ */ jsxs7(Fragment2, {
3390
2813
  children: [
3391
- /* @__PURE__ */ jsx10("button", {
2814
+ /* @__PURE__ */ jsx9("button", {
3392
2815
  onClick: (e) => {
3393
2816
  e.stopPropagation();
3394
2817
  handleToggleScrollLock();
@@ -3413,13 +2836,13 @@ var TabbedTerminalPanelInner = ({
3413
2836
  e.currentTarget.style.backgroundColor = "transparent";
3414
2837
  },
3415
2838
  title: scrollPosition.isScrollLocked ? "Scroll locked" : "Scroll unlocked",
3416
- children: scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx10(Lock2, {
2839
+ children: scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx9(Lock, {
3417
2840
  size: 10
3418
- }) : /* @__PURE__ */ jsx10(Unlock2, {
2841
+ }) : /* @__PURE__ */ jsx9(Unlock, {
3419
2842
  size: 10
3420
2843
  })
3421
2844
  }),
3422
- /* @__PURE__ */ jsx10("div", {
2845
+ /* @__PURE__ */ jsx9("div", {
3423
2846
  style: {
3424
2847
  position: "absolute",
3425
2848
  right: "8px",
@@ -3430,7 +2853,7 @@ var TabbedTerminalPanelInner = ({
3430
2853
  height: "16px"
3431
2854
  },
3432
2855
  title: isWorking ? "Terminal active" : "Terminal idle",
3433
- children: /* @__PURE__ */ jsx10(ActivityIndicator, {
2856
+ children: /* @__PURE__ */ jsx9(ActivityIndicator, {
3434
2857
  color: theme.colors.primary,
3435
2858
  isAnimating: isWorking ?? false
3436
2859
  })
@@ -3438,8 +2861,8 @@ var TabbedTerminalPanelInner = ({
3438
2861
  ]
3439
2862
  });
3440
2863
  }, [activeTabId, scrollPositions, defaultScrollPosition, handleToggleScrollLock, theme, sessionIds, workingStates, activityStates]);
3441
- const renderTerminalWithAssociation = useCallback6((tab, isActive, sessionId, association) => {
3442
- const terminalContent = /* @__PURE__ */ jsx10(TerminalTabContent, {
2864
+ const renderTerminalWithAssociation = useCallback5((tab, isActive, sessionId, association) => {
2865
+ const terminalContent = /* @__PURE__ */ jsx9(TerminalTabContent, {
3443
2866
  ref: getRefCallback(tab.id),
3444
2867
  tab,
3445
2868
  sessionId,
@@ -3458,7 +2881,7 @@ var TabbedTerminalPanelInner = ({
3458
2881
  onActivityStateChange: handleActivityStateChange
3459
2882
  }, `terminal-${tab.id}`);
3460
2883
  const hasAssociation = !!association;
3461
- const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */ jsx10("div", {
2884
+ const secondaryContent = hasAssociation && renderAssociatedContent ? renderAssociatedContent(association.associatedTabId, isActive) : /* @__PURE__ */ jsx9("div", {
3462
2885
  style: {
3463
2886
  height: "100%",
3464
2887
  display: "flex",
@@ -3470,12 +2893,12 @@ var TabbedTerminalPanelInner = ({
3470
2893
  },
3471
2894
  children: "Drag a tab here to associate it with this terminal"
3472
2895
  });
3473
- const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */ jsx10(Paperclip, {
2896
+ const headerConfig = hasAssociation && getAssociatedHeader ? getAssociatedHeader(association.associatedTabId) : { title: "Drop zone", icon: /* @__PURE__ */ jsx9(Paperclip, {
3474
2897
  size: 14
3475
2898
  }) };
3476
2899
  const isCollapsed = hasAssociation ? association.collapsed : true;
3477
2900
  const handleCollapsedChange = hasAssociation ? (collapsed) => onAssociationCollapsedChange?.(tab.id, collapsed) : undefined;
3478
- return /* @__PURE__ */ jsx10(CollapsibleSplitPane, {
2901
+ return /* @__PURE__ */ jsx9(CollapsibleSplitPane, {
3479
2902
  style: { height: "100%" },
3480
2903
  primaryContent: terminalContent,
3481
2904
  secondaryContent,
@@ -3506,7 +2929,7 @@ var TabbedTerminalPanelInner = ({
3506
2929
  onAssociationRatioChange,
3507
2930
  theme
3508
2931
  ]);
3509
- const handleTabDrop = useCallback6((draggedTabId, targetTabId) => {
2932
+ const handleTabDrop = useCallback5((draggedTabId, targetTabId) => {
3510
2933
  const draggedTab = tabs.find((t) => t.id === draggedTabId);
3511
2934
  const targetTab = tabs.find((t) => t.id === targetTabId);
3512
2935
  if (targetTab?.contentType === "terminal" && draggedTab?.contentType !== "terminal") {
@@ -3514,13 +2937,13 @@ var TabbedTerminalPanelInner = ({
3514
2937
  setActiveTabId(targetTabId);
3515
2938
  }
3516
2939
  }, [tabs, onTabAssociate, setActiveTabId]);
3517
- const canDropOnTab = useCallback6((draggedTabId, targetTabId) => {
2940
+ const canDropOnTab = useCallback5((draggedTabId, targetTabId) => {
3518
2941
  const draggedTab = tabs.find((t) => t.id === draggedTabId);
3519
2942
  const targetTab = tabs.find((t) => t.id === targetTabId);
3520
2943
  return targetTab?.contentType === "terminal" && draggedTab?.contentType !== "terminal";
3521
2944
  }, [tabs]);
3522
- const [isDragOverContent, setIsDragOverContent] = useState5(false);
3523
- const handleContentDragEnter = useCallback6((e) => {
2945
+ const [isDragOverContent, setIsDragOverContent] = useState4(false);
2946
+ const handleContentDragEnter = useCallback5((e) => {
3524
2947
  e.preventDefault();
3525
2948
  if (activeTabId) {
3526
2949
  const activeTab = tabs.find((t) => t.id === activeTabId);
@@ -3529,13 +2952,13 @@ var TabbedTerminalPanelInner = ({
3529
2952
  }
3530
2953
  }
3531
2954
  }, [activeTabId, tabs]);
3532
- const handleContentDragLeave = useCallback6((e) => {
2955
+ const handleContentDragLeave = useCallback5((e) => {
3533
2956
  const relatedTarget = e.relatedTarget;
3534
2957
  if (!e.currentTarget.contains(relatedTarget)) {
3535
2958
  setIsDragOverContent(false);
3536
2959
  }
3537
2960
  }, []);
3538
- const handleContentDrop = useCallback6((e) => {
2961
+ const handleContentDrop = useCallback5((e) => {
3539
2962
  e.preventDefault();
3540
2963
  e.stopPropagation();
3541
2964
  setIsDragOverContent(false);
@@ -3550,7 +2973,7 @@ var TabbedTerminalPanelInner = ({
3550
2973
  setActiveTabId(activeTabId);
3551
2974
  }
3552
2975
  }, [activeTabId, tabs, onTabAssociate, setActiveTabId]);
3553
- return /* @__PURE__ */ jsxs8("div", {
2976
+ return /* @__PURE__ */ jsxs7("div", {
3554
2977
  style: {
3555
2978
  display: "flex",
3556
2979
  flexDirection: "column",
@@ -3558,15 +2981,15 @@ var TabbedTerminalPanelInner = ({
3558
2981
  backgroundColor: theme.colors.background
3559
2982
  },
3560
2983
  children: [
3561
- !hideHeader && /* @__PURE__ */ jsx10("div", {
2984
+ !hideHeader && /* @__PURE__ */ jsx9("div", {
3562
2985
  ref: headerRef,
3563
- children: /* @__PURE__ */ jsx10(TabBar, {
2986
+ children: /* @__PURE__ */ jsx9(TabBar, {
3564
2987
  tabs: genericTabs,
3565
2988
  activeTabId,
3566
2989
  onTabClick: switchTab,
3567
2990
  onTabClose: closeTab,
3568
2991
  onNewTab: addNewTab,
3569
- leftSection: /* @__PURE__ */ jsx10("button", {
2992
+ leftSection: /* @__PURE__ */ jsx9("button", {
3570
2993
  onClick: () => onShowAllTerminalsChange?.(!showAllTerminals),
3571
2994
  style: {
3572
2995
  display: "flex",
@@ -3591,9 +3014,9 @@ var TabbedTerminalPanelInner = ({
3591
3014
  }
3592
3015
  },
3593
3016
  title: showAllTerminals ? "Showing all terminals (click to filter by context)" : "Show all terminals",
3594
- children: showAllTerminals ? /* @__PURE__ */ jsx10(Boxes, {
3017
+ children: showAllTerminals ? /* @__PURE__ */ jsx9(Boxes, {
3595
3018
  size: 14
3596
- }) : /* @__PURE__ */ jsx10(Box, {
3019
+ }) : /* @__PURE__ */ jsx9(Box, {
3597
3020
  size: 14
3598
3021
  })
3599
3022
  }),
@@ -3606,7 +3029,7 @@ var TabbedTerminalPanelInner = ({
3606
3029
  canDropOnTab
3607
3030
  })
3608
3031
  }),
3609
- /* @__PURE__ */ jsxs8("div", {
3032
+ /* @__PURE__ */ jsxs7("div", {
3610
3033
  style: {
3611
3034
  flex: 1,
3612
3035
  display: "flex",
@@ -3660,62 +3083,71 @@ var TabbedTerminalPanelInner = ({
3660
3083
  const customContent = renderTabContent(tab, isActive, sessionId, width);
3661
3084
  if (customContent === null && tab.contentType === "terminal") {
3662
3085
  const association = associations?.[tab.id];
3663
- return /* @__PURE__ */ jsx10("div", {
3086
+ return /* @__PURE__ */ jsx9("div", {
3664
3087
  style: {
3665
- display: isActive ? "flex" : "none",
3088
+ position: "absolute",
3089
+ inset: 0,
3090
+ display: "flex",
3666
3091
  flexDirection: "column",
3667
- height: "100%",
3668
- width: "100%"
3092
+ visibility: isActive ? "visible" : "hidden",
3093
+ pointerEvents: isActive ? "auto" : "none"
3669
3094
  },
3670
3095
  children: renderTerminalWithAssociation(tab, isActive, sessionId, association)
3671
3096
  }, tab.id);
3672
3097
  }
3673
3098
  const hasBeenActivated = activatedTabs.has(tab.id);
3674
- return /* @__PURE__ */ jsx10("div", {
3099
+ return /* @__PURE__ */ jsx9("div", {
3675
3100
  style: {
3676
- display: isActive ? "flex" : "none",
3101
+ position: "absolute",
3102
+ inset: 0,
3103
+ display: "flex",
3677
3104
  flexDirection: "column",
3678
- height: "100%",
3679
- width: "100%"
3105
+ visibility: isActive ? "visible" : "hidden",
3106
+ pointerEvents: isActive ? "auto" : "none"
3680
3107
  },
3681
3108
  children: hasBeenActivated && customContent
3682
3109
  }, tab.id);
3683
3110
  }
3684
3111
  if (tab.contentType === "terminal") {
3685
3112
  const association = associations?.[tab.id];
3686
- return /* @__PURE__ */ jsx10("div", {
3113
+ return /* @__PURE__ */ jsx9("div", {
3687
3114
  style: {
3688
- display: isActive ? "flex" : "none",
3115
+ position: "absolute",
3116
+ inset: 0,
3117
+ display: "flex",
3689
3118
  flexDirection: "column",
3690
- height: "100%",
3691
- width: "100%"
3119
+ visibility: isActive ? "visible" : "hidden",
3120
+ pointerEvents: isActive ? "auto" : "none"
3692
3121
  },
3693
3122
  children: renderTerminalWithAssociation(tab, isActive, sessionId, association)
3694
3123
  }, tab.id);
3695
3124
  }
3696
- return /* @__PURE__ */ jsxs8("div", {
3125
+ return /* @__PURE__ */ jsxs7("div", {
3697
3126
  style: {
3698
- display: isActive ? "flex" : "none",
3127
+ position: "absolute",
3128
+ inset: 0,
3129
+ display: "flex",
3699
3130
  alignItems: "center",
3700
3131
  justifyContent: "center",
3701
- height: "100%",
3132
+ visibility: isActive ? "visible" : "hidden",
3133
+ pointerEvents: isActive ? "auto" : "none",
3702
3134
  color: theme.colors.textSecondary
3703
3135
  },
3704
3136
  children: [
3705
- /* @__PURE__ */ jsxs8("p", {
3137
+ /* @__PURE__ */ jsxs7("p", {
3706
3138
  children: [
3707
3139
  "Unknown content type: ",
3708
3140
  tab.contentType
3709
3141
  ]
3710
3142
  }),
3711
- /* @__PURE__ */ jsx10("p", {
3143
+ /* @__PURE__ */ jsx9("p", {
3712
3144
  style: { fontSize: theme.fontSizes[0], marginTop: "8px" },
3713
3145
  children: "Provide a renderTabContent prop to render custom tab types"
3714
3146
  })
3715
3147
  ]
3716
3148
  }, tab.id);
3717
3149
  }),
3718
- tabs.length === 0 && /* @__PURE__ */ jsxs8("div", {
3150
+ tabs.length === 0 && /* @__PURE__ */ jsxs7("div", {
3719
3151
  style: {
3720
3152
  display: "flex",
3721
3153
  flexDirection: "column",
@@ -3725,11 +3157,11 @@ var TabbedTerminalPanelInner = ({
3725
3157
  color: theme.colors.textSecondary
3726
3158
  },
3727
3159
  children: [
3728
- /* @__PURE__ */ jsx10(TerminalIcon2, {
3160
+ /* @__PURE__ */ jsx9(TerminalIcon2, {
3729
3161
  size: 32,
3730
3162
  style: { opacity: 0.5, marginBottom: "16px" }
3731
3163
  }),
3732
- /* @__PURE__ */ jsx10("button", {
3164
+ /* @__PURE__ */ jsx9("button", {
3733
3165
  onClick: () => addNewTab(),
3734
3166
  style: {
3735
3167
  marginTop: "16px",
@@ -3958,33 +3390,43 @@ var terminalPanelToolsMetadata = {
3958
3390
  };
3959
3391
 
3960
3392
  // src/panel-exports.ts
3961
- var panels = [
3962
- {
3963
- metadata: {
3964
- id: "com.principal.terminal",
3965
- name: "Terminal",
3966
- icon: "terminal",
3967
- version: "0.1.0",
3968
- author: "Principal",
3969
- description: "Integrated terminal emulator with industry theming",
3970
- slices: ["terminal"],
3971
- tools: terminalPanelTools
3972
- },
3973
- component: TerminalPanel,
3974
- onMount: async (_context) => {
3975
- console.log("Terminal Panel mounted for repository:", _context.currentScope.repository?.path);
3976
- },
3977
- onUnmount: async (_context) => {
3978
- console.log("Terminal Panel unmounting");
3979
- }
3980
- }
3981
- ];
3393
+ var panels = [];
3982
3394
  var onPackageLoad = async () => {
3983
3395
  console.log("Panel package loaded - Terminal Panel Extension");
3984
3396
  };
3985
3397
  var onPackageUnload = async () => {
3986
3398
  console.log("Panel package unloading - Terminal Panel Extension");
3987
3399
  };
3400
+ // src/panel-types/index.ts
3401
+ function getTerminalSessions(context2) {
3402
+ return context2.terminal?.data ?? [];
3403
+ }
3404
+ function getTerminalSession(context2, sessionId) {
3405
+ const sessions = getTerminalSessions(context2);
3406
+ return sessions.find((s) => s.id === sessionId);
3407
+ }
3408
+ function isTerminalLoading(context2) {
3409
+ return context2.terminal?.loading ?? false;
3410
+ }
3411
+ function getRepositoryPath(context2) {
3412
+ return context2.currentScope.repository?.path ?? null;
3413
+ }
3414
+ function getWorkspacePath(context2) {
3415
+ return context2.currentScope.workspace?.path ?? null;
3416
+ }
3417
+ function getTerminalDirectory(context2, terminalScope = "repository") {
3418
+ switch (terminalScope) {
3419
+ case "workspace":
3420
+ return getWorkspacePath(context2);
3421
+ case "repository":
3422
+ return getRepositoryPath(context2) ?? getWorkspacePath(context2);
3423
+ default:
3424
+ return getRepositoryPath(context2) ?? getWorkspacePath(context2);
3425
+ }
3426
+ }
3427
+ function getTerminalSlice(context2) {
3428
+ return context2.terminal;
3429
+ }
3988
3430
  export {
3989
3431
  writeToTerminalTool,
3990
3432
  withSpanSync,
@@ -4019,7 +3461,6 @@ export {
4019
3461
  ThemedTerminalWithProvider,
4020
3462
  ThemedTerminal,
4021
3463
  TerminalSession,
4022
- TerminalPanel,
4023
3464
  TerminalOverlay,
4024
3465
  TabbedTerminalPanel,
4025
3466
  TabButton,