replicas-cli 0.2.41 → 0.2.42

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.mjs CHANGED
@@ -1855,12 +1855,12 @@ async function interactiveCommand() {
1855
1855
  );
1856
1856
  }
1857
1857
  console.log(chalk17.gray("Starting interactive mode..."));
1858
- const { launchInteractive } = await import("./interactive-EQDMW2E3.mjs");
1858
+ const { launchInteractive } = await import("./interactive-M3UR4H6X.mjs");
1859
1859
  await launchInteractive();
1860
1860
  }
1861
1861
 
1862
1862
  // src/index.ts
1863
- var CLI_VERSION = "0.2.41";
1863
+ var CLI_VERSION = "0.2.42";
1864
1864
  var program = new Command();
1865
1865
  program.name("replicas").description("CLI for managing Replicas workspaces").version(CLI_VERSION);
1866
1866
  program.command("login").description("Authenticate with your Replicas account").action(async () => {
@@ -16,8 +16,8 @@ import { createCliRenderer } from "@opentui/core";
16
16
  import { createRoot } from "@opentui/react";
17
17
 
18
18
  // src/interactive/App.tsx
19
- import { useState as useState5, useEffect as useEffect3, useMemo as useMemo3, useCallback as useCallback5, useRef as useRef3 } from "react";
20
- import { useKeyboard as useKeyboard3, useRenderer, useTerminalDimensions as useTerminalDimensions3 } from "@opentui/react";
19
+ import { useState as useState6, useEffect as useEffect3, useMemo as useMemo4, useCallback as useCallback6, useRef as useRef3 } from "react";
20
+ import { useKeyboard as useKeyboard4, useRenderer, useTerminalDimensions as useTerminalDimensions3 } from "@opentui/react";
21
21
  import { QueryClient } from "@tanstack/react-query";
22
22
 
23
23
  // ../shared/src/hooks/auth-context.ts
@@ -488,7 +488,7 @@ var KEYBINDS = {
488
488
  "chat-tabs": "\u2190/\u2192 switch tabs",
489
489
  "chat-history": "j/k scroll",
490
490
  "chat-input": "\u21B5 send \u21E5 plan/build",
491
- info: "j/k scroll o dashboard w wake"
491
+ info: "j/k nav \u21B5 open o dashboard w wake"
492
492
  };
493
493
  function StatusBar({ focusPanel }) {
494
494
  return /* @__PURE__ */ jsxs(
@@ -1298,10 +1298,45 @@ function ChatArea({
1298
1298
  }
1299
1299
 
1300
1300
  // src/interactive/components/WorkspaceInfo.tsx
1301
- import React4 from "react";
1301
+ import React4, { useState as useState4, useMemo as useMemo3, useCallback as useCallback4 } from "react";
1302
1302
  import open from "open";
1303
+ import { useKeyboard as useKeyboard3 } from "@opentui/react";
1303
1304
  import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
1304
1305
  var WEB_APP_URL = process.env.REPLICAS_WEB_URL || "https://replicas.dev";
1306
+ function buildInteractiveItems(workspaceId, status, previews, wakingWorkspaceId) {
1307
+ const items = [];
1308
+ if (workspaceId) {
1309
+ items.push({ type: "dashboard", workspaceId });
1310
+ }
1311
+ if (workspaceId && status.status === "sleeping" && wakingWorkspaceId !== workspaceId) {
1312
+ items.push({ type: "wake", workspaceId });
1313
+ }
1314
+ for (const preview of previews) {
1315
+ if (preview.publicUrl) {
1316
+ items.push({ type: "preview", url: preview.publicUrl, port: preview.port });
1317
+ }
1318
+ }
1319
+ if (status.repoStatuses) {
1320
+ for (const repo of status.repoStatuses) {
1321
+ if (repo.prUrl) {
1322
+ items.push({ type: "pr", url: repo.prUrl, repoName: repo.name });
1323
+ }
1324
+ }
1325
+ }
1326
+ return items;
1327
+ }
1328
+ function getItemLabel(item) {
1329
+ switch (item.type) {
1330
+ case "dashboard":
1331
+ return "\u2197 Open in Dashboard";
1332
+ case "wake":
1333
+ return "\u25B6 Wake";
1334
+ case "preview":
1335
+ return `\u2197 Preview :${item.port}`;
1336
+ case "pr":
1337
+ return `\u2197 View PR (${item.repoName})`;
1338
+ }
1339
+ }
1305
1340
  var AUTH_METHOD_LABELS = {
1306
1341
  oauth: "OAuth",
1307
1342
  api_key: "API Key",
@@ -1352,8 +1387,108 @@ function DetailList({
1352
1387
  if (rows.length === 0) return null;
1353
1388
  return /* @__PURE__ */ jsx6(Fragment, { children: rows.map((item, i) => /* @__PURE__ */ jsx6(CardItem, { label: item, status: actualSet.has(item) }, i)) });
1354
1389
  }
1390
+ function InteractiveRow({ label, highlighted, onClick }) {
1391
+ return /* @__PURE__ */ jsx6(
1392
+ "box",
1393
+ {
1394
+ paddingX: 1,
1395
+ backgroundColor: highlighted ? "#1a2a1a" : "#111111",
1396
+ onMouseDown: onClick,
1397
+ children: /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: highlighted ? "#66bb6a" : "#7dcfff", children: label }) })
1398
+ }
1399
+ );
1400
+ }
1355
1401
  function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, envConfig, previews, onWakeWorkspace, wakingWorkspaceId }) {
1356
1402
  const borderColor = focused ? "#66bb6a" : "#333333";
1403
+ const [cursorIndex, setCursorIndex] = useState4(0);
1404
+ const interactiveItems = useMemo3(() => {
1405
+ if (!status || !workspaceName) return [];
1406
+ return buildInteractiveItems(workspaceId, status, previews, wakingWorkspaceId);
1407
+ }, [workspaceId, workspaceName, status, previews, wakingWorkspaceId]);
1408
+ const safeCursor = interactiveItems.length > 0 ? Math.min(cursorIndex, interactiveItems.length - 1) : 0;
1409
+ const moveCursor = useCallback4(
1410
+ (next) => {
1411
+ const clamped = Math.max(0, Math.min(interactiveItems.length - 1, next));
1412
+ setCursorIndex(clamped);
1413
+ },
1414
+ [interactiveItems.length]
1415
+ );
1416
+ const handleAction = useCallback4(
1417
+ (item) => {
1418
+ if (!item) return;
1419
+ switch (item.type) {
1420
+ case "dashboard":
1421
+ open(`${WEB_APP_URL}/dashboard?workspaceId=${item.workspaceId}`).catch(() => {
1422
+ });
1423
+ break;
1424
+ case "wake":
1425
+ onWakeWorkspace(item.workspaceId);
1426
+ break;
1427
+ case "preview":
1428
+ open(item.url).catch(() => {
1429
+ });
1430
+ break;
1431
+ case "pr":
1432
+ open(item.url).catch(() => {
1433
+ });
1434
+ break;
1435
+ }
1436
+ },
1437
+ [onWakeWorkspace]
1438
+ );
1439
+ useKeyboard3((key) => {
1440
+ if (!focused) return;
1441
+ if (interactiveItems.length === 0) return;
1442
+ if (key.name === "j" || key.name === "down") {
1443
+ moveCursor(safeCursor + 1);
1444
+ return;
1445
+ }
1446
+ if (key.name === "k" || key.name === "up") {
1447
+ moveCursor(safeCursor - 1);
1448
+ return;
1449
+ }
1450
+ if (key.name === "g" && !key.shift) {
1451
+ moveCursor(0);
1452
+ return;
1453
+ }
1454
+ if (key.name === "g" && key.shift) {
1455
+ moveCursor(interactiveItems.length - 1);
1456
+ return;
1457
+ }
1458
+ if (key.name === "enter" || key.name === "return") {
1459
+ handleAction(interactiveItems[safeCursor]);
1460
+ return;
1461
+ }
1462
+ if (key.name === "o") {
1463
+ const dashboardItem2 = interactiveItems.find((item) => item.type === "dashboard");
1464
+ if (dashboardItem2) handleAction(dashboardItem2);
1465
+ return;
1466
+ }
1467
+ if (key.name === "w") {
1468
+ const wakeItem2 = interactiveItems.find((item) => item.type === "wake");
1469
+ if (wakeItem2) handleAction(wakeItem2);
1470
+ return;
1471
+ }
1472
+ });
1473
+ const isHighlighted = useCallback4(
1474
+ (item) => {
1475
+ if (!focused) return false;
1476
+ const idx = interactiveItems.indexOf(item);
1477
+ return idx === safeCursor;
1478
+ },
1479
+ [focused, interactiveItems, safeCursor]
1480
+ );
1481
+ const findItem = useCallback4(
1482
+ (type, key) => {
1483
+ return interactiveItems.find((item) => {
1484
+ if (item.type !== type) return false;
1485
+ if (type === "preview" && key) return item.port === Number(key);
1486
+ if (type === "pr" && key) return item.repoName === key;
1487
+ return true;
1488
+ });
1489
+ },
1490
+ [interactiveItems]
1491
+ );
1357
1492
  if (!workspaceName) {
1358
1493
  return /* @__PURE__ */ jsx6(
1359
1494
  "box",
@@ -1393,6 +1528,8 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, e
1393
1528
  const expectedSkills = (envConfig.skills?.environment_skills ?? []).map((s) => s.source);
1394
1529
  const expectedGlobalVars = (envConfig.variables?.environment_variables ?? []).filter((v) => v.scope_type === "global").map((v) => v.key);
1395
1530
  const expectedGlobalFiles = (envConfig.files?.environment_files ?? []).filter((f) => f.scope_type === "global").map((f) => f.path);
1531
+ const dashboardItem = findItem("dashboard");
1532
+ const wakeItem = findItem("wake");
1396
1533
  return /* @__PURE__ */ jsx6(
1397
1534
  "box",
1398
1535
  {
@@ -1419,36 +1556,24 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, e
1419
1556
  " ",
1420
1557
  env.engineVersion
1421
1558
  ] })
1422
- ] }),
1423
- workspaceId && /* @__PURE__ */ jsx6(
1424
- "box",
1425
- {
1426
- onMouseDown: () => {
1427
- open(`${WEB_APP_URL}/dashboard?workspaceId=${workspaceId}`).catch(() => {
1428
- });
1429
- },
1430
- children: /* @__PURE__ */ jsxs6("text", { children: [
1431
- /* @__PURE__ */ jsxs6("span", { fg: "#7dcfff", children: [
1432
- "\u2197",
1433
- " Open in Dashboard"
1434
- ] }),
1435
- /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " (o)" })
1436
- ] })
1437
- }
1438
- ),
1439
- workspaceId && status.status === "sleeping" && /* @__PURE__ */ jsx6(
1440
- "box",
1441
- {
1442
- onMouseDown: () => {
1443
- if (wakingWorkspaceId !== workspaceId) onWakeWorkspace(workspaceId);
1444
- },
1445
- children: /* @__PURE__ */ jsxs6("text", { children: [
1446
- /* @__PURE__ */ jsx6("span", { fg: wakingWorkspaceId === workspaceId ? "#888888" : "#66bb6a", children: wakingWorkspaceId === workspaceId ? "\u25CC Waking..." : "\u25B6 Wake" }),
1447
- /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " (w)" })
1448
- ] })
1449
- }
1450
- )
1559
+ ] })
1451
1560
  ] }) }),
1561
+ dashboardItem && /* @__PURE__ */ jsx6(
1562
+ InteractiveRow,
1563
+ {
1564
+ label: getItemLabel(dashboardItem),
1565
+ highlighted: isHighlighted(dashboardItem),
1566
+ onClick: () => handleAction(dashboardItem)
1567
+ }
1568
+ ),
1569
+ wakeItem && /* @__PURE__ */ jsx6(
1570
+ InteractiveRow,
1571
+ {
1572
+ label: getItemLabel(wakeItem),
1573
+ highlighted: isHighlighted(wakeItem),
1574
+ onClick: () => handleAction(wakeItem)
1575
+ }
1576
+ ),
1452
1577
  (status.isClaudeProcessing || status.isCodexProcessing) && /* @__PURE__ */ jsxs6("box", { backgroundColor: "#1a1500", paddingX: 1, marginX: 1, marginBottom: 1, children: [
1453
1578
  status.isClaudeProcessing && /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsxs6("span", { fg: "#ffaa00", children: [
1454
1579
  "\u25C6",
@@ -1474,42 +1599,60 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, e
1474
1599
  /* @__PURE__ */ jsx6(CardItem, { label: "Slack", status: env.slackAccessConfigured }),
1475
1600
  /* @__PURE__ */ jsx6(CardItem, { label: "Linear", status: env.linearAccessConfigured })
1476
1601
  ] }),
1477
- previews.length > 0 && /* @__PURE__ */ jsx6(Section, { title: "Previews", children: previews.map((preview, i) => /* @__PURE__ */ jsxs6("box", { flexDirection: "row", justifyContent: "space-between", paddingX: 1, backgroundColor: "#111111", children: [
1478
- /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsxs6("span", { fg: "#cccccc", children: [
1479
- ":",
1480
- preview.port
1481
- ] }) }),
1482
- /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("a", { href: preview.publicUrl, children: /* @__PURE__ */ jsx6("span", { fg: "#66bb6a", children: "\u2197" }) }) })
1483
- ] }, i)) }),
1484
- status.repoStatuses && status.repoStatuses.length > 0 && /* @__PURE__ */ jsx6(Section, { title: "Repositories", children: status.repoStatuses.map((repo, i) => /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
1485
- /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, children: /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: "#ffffff", children: /* @__PURE__ */ jsx6("strong", { children: repo.name }) }) }) }),
1486
- /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, flexDirection: "row", justifyContent: "space-between", children: /* @__PURE__ */ jsxs6("text", { children: [
1487
- /* @__PURE__ */ jsxs6("span", { fg: "#555555", children: [
1488
- "\u2514",
1489
- " "
1490
- ] }),
1491
- /* @__PURE__ */ jsx6("span", { fg: repo.currentBranch !== repo.defaultBranch ? "#ffaa00" : "#66bb6a", children: repo.currentBranch })
1492
- ] }) }),
1493
- repo.gitDiff && (repo.gitDiff.added > 0 || repo.gitDiff.removed > 0) && /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, flexDirection: "row", children: /* @__PURE__ */ jsxs6("text", { children: [
1494
- /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " " }),
1495
- /* @__PURE__ */ jsxs6("span", { fg: "#66bb6a", children: [
1496
- "+",
1497
- repo.gitDiff.added
1498
- ] }),
1499
- /* @__PURE__ */ jsx6("span", { fg: "#444444", children: " / " }),
1500
- /* @__PURE__ */ jsxs6("span", { fg: "#ff4444", children: [
1501
- "-",
1502
- repo.gitDiff.removed
1503
- ] })
1504
- ] }) }),
1505
- repo.prUrl && /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, children: /* @__PURE__ */ jsxs6("text", { children: [
1506
- /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " " }),
1507
- /* @__PURE__ */ jsx6("a", { href: repo.prUrl, children: /* @__PURE__ */ jsxs6("span", { fg: "#66bb6a", children: [
1508
- "View PR ",
1509
- "\u2197"
1510
- ] }) })
1511
- ] }) })
1512
- ] }, i)) }),
1602
+ previews.length > 0 && /* @__PURE__ */ jsx6(Section, { title: "Previews", children: previews.map((preview, i) => {
1603
+ const previewItem = findItem("preview", String(preview.port));
1604
+ return /* @__PURE__ */ jsxs6(
1605
+ "box",
1606
+ {
1607
+ flexDirection: "row",
1608
+ justifyContent: "space-between",
1609
+ paddingX: 1,
1610
+ backgroundColor: previewItem && isHighlighted(previewItem) ? "#1a2a1a" : "#111111",
1611
+ onMouseDown: () => previewItem && handleAction(previewItem),
1612
+ children: [
1613
+ /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsxs6("span", { fg: "#cccccc", children: [
1614
+ ":",
1615
+ preview.port
1616
+ ] }) }),
1617
+ /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: previewItem && isHighlighted(previewItem) ? "#66bb6a" : "#7dcfff", children: "\u2197" }) })
1618
+ ]
1619
+ },
1620
+ i
1621
+ );
1622
+ }) }),
1623
+ status.repoStatuses && status.repoStatuses.length > 0 && /* @__PURE__ */ jsx6(Section, { title: "Repositories", children: status.repoStatuses.map((repo, i) => {
1624
+ const prItem = findItem("pr", repo.name);
1625
+ return /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
1626
+ /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, children: /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: "#ffffff", children: /* @__PURE__ */ jsx6("strong", { children: repo.name }) }) }) }),
1627
+ /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, flexDirection: "row", justifyContent: "space-between", children: /* @__PURE__ */ jsxs6("text", { children: [
1628
+ /* @__PURE__ */ jsxs6("span", { fg: "#555555", children: [
1629
+ "\u2514",
1630
+ " "
1631
+ ] }),
1632
+ /* @__PURE__ */ jsx6("span", { fg: repo.currentBranch !== repo.defaultBranch ? "#ffaa00" : "#66bb6a", children: repo.currentBranch })
1633
+ ] }) }),
1634
+ repo.gitDiff && (repo.gitDiff.added > 0 || repo.gitDiff.removed > 0) && /* @__PURE__ */ jsx6("box", { backgroundColor: "#111111", paddingX: 1, flexDirection: "row", children: /* @__PURE__ */ jsxs6("text", { children: [
1635
+ /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " " }),
1636
+ /* @__PURE__ */ jsxs6("span", { fg: "#66bb6a", children: [
1637
+ "+",
1638
+ repo.gitDiff.added
1639
+ ] }),
1640
+ /* @__PURE__ */ jsx6("span", { fg: "#444444", children: " / " }),
1641
+ /* @__PURE__ */ jsxs6("span", { fg: "#ff4444", children: [
1642
+ "-",
1643
+ repo.gitDiff.removed
1644
+ ] })
1645
+ ] }) }),
1646
+ prItem && /* @__PURE__ */ jsx6(
1647
+ InteractiveRow,
1648
+ {
1649
+ label: ` ${getItemLabel(prItem)}`,
1650
+ highlighted: isHighlighted(prItem),
1651
+ onClick: () => handleAction(prItem)
1652
+ }
1653
+ )
1654
+ ] }, i);
1655
+ }) }),
1513
1656
  env && /* @__PURE__ */ jsxs6(Section, { title: "Hooks", children: [
1514
1657
  /* @__PURE__ */ jsx6(CardItem, { label: "Global warm", status: env.globalWarmHookCompleted.status }),
1515
1658
  env.repositories.map((repo, i) => /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
@@ -1548,7 +1691,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, e
1548
1691
  import { useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
1549
1692
 
1550
1693
  // src/interactive/toast-context.tsx
1551
- import { createContext as createContext2, useContext as useContext2, useState as useState4, useCallback as useCallback4, useRef as useRef2 } from "react";
1694
+ import { createContext as createContext2, useContext as useContext2, useState as useState5, useCallback as useCallback5, useRef as useRef2 } from "react";
1552
1695
  import { jsx as jsx7 } from "@opentui/react/jsx-runtime";
1553
1696
  var ToastContext = createContext2(null);
1554
1697
  function useToast() {
@@ -1557,9 +1700,9 @@ function useToast() {
1557
1700
  return ctx;
1558
1701
  }
1559
1702
  function ToastProvider({ children }) {
1560
- const [current, setCurrent] = useState4(null);
1703
+ const [current, setCurrent] = useState5(null);
1561
1704
  const timeoutRef = useRef2(null);
1562
- const show = useCallback4((options) => {
1705
+ const show = useCallback5((options) => {
1563
1706
  const { message, variant = "info", duration = 3e3 } = options;
1564
1707
  setCurrent({ message, variant });
1565
1708
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
@@ -1567,7 +1710,7 @@ function ToastProvider({ children }) {
1567
1710
  setCurrent(null);
1568
1711
  }, duration);
1569
1712
  }, []);
1570
- const error = useCallback4((err) => {
1713
+ const error = useCallback5((err) => {
1571
1714
  const message = err instanceof Error ? err.message : "An error occurred";
1572
1715
  show({ message, variant: "error", duration: 5e3 });
1573
1716
  }, [show]);
@@ -1652,17 +1795,17 @@ function AppInner() {
1652
1795
  renderer.off("selection", handler);
1653
1796
  };
1654
1797
  }, [renderer, toast]);
1655
- const [selectedWorkspaceId, setSelectedWorkspaceId] = useState5(null);
1656
- const [selectedChatId, setSelectedChatId] = useState5(null);
1657
- const [focusPanel, setFocusPanel] = useState5("sidebar");
1658
- const [taskMode, setTaskMode] = useState5("build");
1659
- const [mockWorkspaces, setMockWorkspaces] = useState5([]);
1798
+ const [selectedWorkspaceId, setSelectedWorkspaceId] = useState6(null);
1799
+ const [selectedChatId, setSelectedChatId] = useState6(null);
1800
+ const [focusPanel, setFocusPanel] = useState6("sidebar");
1801
+ const [taskMode, setTaskMode] = useState6("build");
1802
+ const [mockWorkspaces, setMockWorkspaces] = useState6([]);
1660
1803
  const mockToRealRef = useRef3(/* @__PURE__ */ new Map());
1661
1804
  const mockGroupRef = useRef3(/* @__PURE__ */ new Map());
1662
- const [mockMessages, setMockMessages] = useState5([]);
1663
- const [mockThinking, setMockThinking] = useState5(false);
1805
+ const [mockMessages, setMockMessages] = useState6([]);
1806
+ const [mockThinking, setMockThinking] = useState6(false);
1664
1807
  const pendingMessageRef = useRef3(/* @__PURE__ */ new Map());
1665
- const mockIds = useMemo3(() => new Set(mockWorkspaces.map((m) => m.id)), [mockWorkspaces]);
1808
+ const mockIds = useMemo4(() => new Set(mockWorkspaces.map((m) => m.id)), [mockWorkspaces]);
1666
1809
  const isMockSelected = selectedWorkspaceId ? mockIds.has(selectedWorkspaceId) : false;
1667
1810
  const { data: workspacesData, isLoading: loadingWorkspaces } = useWorkspaces(1, 100, "organization");
1668
1811
  const { data: reposData } = useRepositories();
@@ -1676,7 +1819,7 @@ function AppInner() {
1676
1819
  );
1677
1820
  const { data: chatsData } = useWorkspaceChats(isMockSelected ? null : selectedWorkspaceId);
1678
1821
  const chats = isMockSelected ? MOCK_CHATS : chatsData?.chats ?? [];
1679
- const resolvedChatId = useMemo3(() => {
1822
+ const resolvedChatId = useMemo4(() => {
1680
1823
  if (selectedChatId && chats.find((c) => c.id === selectedChatId)) {
1681
1824
  return selectedChatId;
1682
1825
  }
@@ -1694,22 +1837,22 @@ function AppInner() {
1694
1837
  const deleteWorkspaceMutation = useDeleteWorkspace();
1695
1838
  const wakeWorkspaceMutation = useWakeWorkspace();
1696
1839
  const generateNameMutation = useGenerateWorkspaceName();
1697
- const [wakingWorkspaceId, setWakingWorkspaceId] = useState5(null);
1840
+ const [wakingWorkspaceId, setWakingWorkspaceId] = useState6(null);
1698
1841
  const sendMessageMutation = useSendChatMessage(selectedWorkspaceId, resolvedChatId);
1699
1842
  const interruptMutation = useInterruptChat(selectedWorkspaceId, resolvedChatId);
1700
1843
  const workspaces = workspacesData?.workspaces ?? [];
1701
1844
  const repositories = reposData?.repositories ?? [];
1702
1845
  const repositorySets = setsData?.repository_sets ?? [];
1703
1846
  const previews = previewsData?.previews ?? [];
1704
- const allWorkspaces = useMemo3(() => [...mockWorkspaces, ...workspaces], [mockWorkspaces, workspaces]);
1705
- const groups = useMemo3(
1847
+ const allWorkspaces = useMemo4(() => [...mockWorkspaces, ...workspaces], [mockWorkspaces, workspaces]);
1848
+ const groups = useMemo4(
1706
1849
  () => buildGroups(allWorkspaces, workspacesData, repositories, repositorySets, mockGroupRef.current),
1707
1850
  [allWorkspaces, workspacesData, repositories, repositorySets]
1708
1851
  );
1709
1852
  const selectedWorkspace = allWorkspaces.find((ws) => ws.id === selectedWorkspaceId) ?? null;
1710
1853
  const selectedChat = chats.find((c) => c.id === resolvedChatId) ?? null;
1711
1854
  const isProcessing = mockThinking || (selectedChat?.processing ?? false);
1712
- const displayMessages = useMemo3(() => {
1855
+ const displayMessages = useMemo4(() => {
1713
1856
  if (isMockSelected) return mockMessages;
1714
1857
  const rawEvents = historyData?.events ?? [];
1715
1858
  const events = rawEvents.filter(isAgentBackendEvent);
@@ -1773,17 +1916,17 @@ function AppInner() {
1773
1916
  }, 5e3);
1774
1917
  return () => clearInterval(interval);
1775
1918
  }, [mockWorkspaces.length]);
1776
- const handleSelectWorkspace = useCallback5((workspaceId) => {
1919
+ const handleSelectWorkspace = useCallback6((workspaceId) => {
1777
1920
  setSelectedWorkspaceId(workspaceId);
1778
1921
  setSelectedChatId(null);
1779
1922
  setMockMessages([]);
1780
1923
  setMockThinking(false);
1781
1924
  setFocusPanel("chat-input");
1782
1925
  }, []);
1783
- const handleFocus = useCallback5((panel) => {
1926
+ const handleFocus = useCallback6((panel) => {
1784
1927
  setFocusPanel(panel);
1785
1928
  }, []);
1786
- const handleCreateWorkspace = useCallback5(
1929
+ const handleCreateWorkspace = useCallback6(
1787
1930
  async (groupId, groupType) => {
1788
1931
  const orgId = getOrganizationId() ?? "";
1789
1932
  const mock = createMockWorkspaceRecord(orgId);
@@ -1802,7 +1945,7 @@ function AppInner() {
1802
1945
  },
1803
1946
  [createWorkspaceMutation, toast]
1804
1947
  );
1805
- const handleDeleteWorkspace = useCallback5(
1948
+ const handleDeleteWorkspace = useCallback6(
1806
1949
  async (workspaceId) => {
1807
1950
  if (mockIds.has(workspaceId)) {
1808
1951
  mockGroupRef.current.delete(workspaceId);
@@ -1821,7 +1964,7 @@ function AppInner() {
1821
1964
  },
1822
1965
  [mockIds, selectedWorkspaceId, deleteWorkspaceMutation]
1823
1966
  );
1824
- const handleWakeWorkspace = useCallback5(
1967
+ const handleWakeWorkspace = useCallback6(
1825
1968
  async (workspaceId) => {
1826
1969
  setWakingWorkspaceId(workspaceId);
1827
1970
  try {
@@ -1835,10 +1978,10 @@ function AppInner() {
1835
1978
  },
1836
1979
  [wakeWorkspaceMutation, toast]
1837
1980
  );
1838
- const handleSelectChat = useCallback5((chatId) => {
1981
+ const handleSelectChat = useCallback6((chatId) => {
1839
1982
  setSelectedChatId(chatId);
1840
1983
  }, []);
1841
- useKeyboard3((key) => {
1984
+ useKeyboard4((key) => {
1842
1985
  if (key.name === "f12") {
1843
1986
  renderer.console.toggle();
1844
1987
  return;
@@ -1871,13 +2014,7 @@ function AppInner() {
1871
2014
  setTaskMode((m) => m === "build" ? "plan" : "build");
1872
2015
  return;
1873
2016
  }
1874
- if (key.name === "o" && focusPanel === "info" && selectedWorkspaceId) {
1875
- const webUrl = process.env.REPLICAS_WEB_URL || "https://replicas.dev";
1876
- import("open").then((mod) => mod.default(`${webUrl}/dashboard?workspaceId=${selectedWorkspaceId}`)).catch(() => {
1877
- });
1878
- return;
1879
- }
1880
- if (key.name === "w" && focusPanel !== "sidebar" && selectedWorkspaceId) {
2017
+ if (key.name === "w" && focusPanel !== "sidebar" && focusPanel !== "info" && selectedWorkspaceId) {
1881
2018
  if (statusData?.status === "sleeping" && !wakingWorkspaceId) {
1882
2019
  handleWakeWorkspace(selectedWorkspaceId);
1883
2020
  }
@@ -1885,7 +2022,7 @@ function AppInner() {
1885
2022
  }
1886
2023
  if (focusPanel === "chat-input") return;
1887
2024
  });
1888
- const handleSendMessage = useCallback5(
2025
+ const handleSendMessage = useCallback6(
1889
2026
  async (message) => {
1890
2027
  if (!selectedWorkspaceId || !resolvedChatId) return;
1891
2028
  if (isMockSelected) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.41",
3
+ "version": "0.2.42",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.mjs",
6
6
  "bin": {