replicas-cli 0.2.40 → 0.2.41

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/README.md CHANGED
@@ -63,11 +63,12 @@ Create a `replicas.json` or `replicas.yaml` file in your repository root:
63
63
  }
64
64
  ```
65
65
 
66
- Or use YAML:
66
+ Or use YAML for better readability (especially for multiline system prompts):
67
67
 
68
68
  ```yaml
69
69
  systemPrompt: |
70
70
  Custom instructions for coding agents.
71
+ Supports multiline text.
71
72
 
72
73
  startHook:
73
74
  commands:
@@ -77,20 +78,19 @@ startHook:
77
78
 
78
79
  ## Features
79
80
 
80
- - **Interactive Dashboard**: Full-featured TUI with workspace management, chat, and environment monitoring
81
81
  - **Secure Authentication**: OAuth-based login with token refresh
82
82
  - **Quick SSH Access**: Connect to workspaces with a single command
83
+ - **SSH Key Caching**: Reuse SSH keys across sessions
83
84
  - **Multi-Organization**: Switch between different organizations
84
85
 
85
- ## Development
86
+ ## How it Works
86
87
 
87
- ```bash
88
- # Run from source
89
- bun run dev
88
+ 1. **SSH Key Management**: The CLI securely caches SSH keys in `~/.replicas/keys/`
90
89
 
91
- # Build
92
- bun run build
93
- ```
90
+ ## Requirements
91
+
92
+ - Node.js 18+
93
+ - SSH client (openssh)
94
94
 
95
95
  ## Support
96
96
 
@@ -7524,6 +7524,22 @@ var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
7524
7524
  // ../shared/src/replicas-config.ts
7525
7525
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
7526
7526
 
7527
+ // ../shared/src/engine/types.ts
7528
+ var DEFAULT_CHAT_TITLES = {
7529
+ claude: "Claude Code",
7530
+ codex: "Codex"
7531
+ };
7532
+ function getInitialChatId(chats, preferredProvider = "claude") {
7533
+ if (chats.length === 0) return null;
7534
+ const isDefault = (c) => c.title === DEFAULT_CHAT_TITLES[c.provider];
7535
+ const hasActivity = (c) => c.updatedAt > c.createdAt;
7536
+ const mostActive = (list) => list.filter(hasActivity).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))[0] ?? null;
7537
+ const fallbackProvider = preferredProvider === "claude" ? "codex" : "claude";
7538
+ const preferred = chats.filter((c) => c.provider === preferredProvider);
7539
+ const fallback = chats.filter((c) => c.provider === fallbackProvider);
7540
+ return mostActive(preferred)?.id ?? mostActive(fallback)?.id ?? preferred.find(isDefault)?.id ?? fallback.find(isDefault)?.id ?? chats[0]?.id ?? null;
7541
+ }
7542
+
7527
7543
  // ../shared/src/prompts.ts
7528
7544
  var REPLICAS_INSTRUCTIONS_TAG = "replicas_instructions";
7529
7545
  function removeTag(text, tag) {
@@ -8237,6 +8253,7 @@ export {
8237
8253
  getCurrentUser,
8238
8254
  SANDBOX_PATHS,
8239
8255
  REPLICAS_CONFIG_FILENAMES,
8256
+ getInitialChatId,
8240
8257
  parseAgentEvents,
8241
8258
  createUserMessage,
8242
8259
  isAgentBackendEvent,
package/dist/index.mjs CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  setIdeCommand,
16
16
  setOrganizationId,
17
17
  writeConfig
18
- } from "./chunk-WCKZW4VV.mjs";
18
+ } from "./chunk-IO4QHXPW.mjs";
19
19
 
20
20
  // src/index.ts
21
21
  import "dotenv/config";
@@ -448,7 +448,7 @@ Found ${response.workspaces.length} workspaces matching "${workspaceName}":`));
448
448
  console.log(chalk4.gray(` Status: ${selectedWorkspace.status || "unknown"}`));
449
449
  if (selectedWorkspace.status === "sleeping") {
450
450
  throw new Error(
451
- "Workspace is currently sleeping. Please wake it up in the dashboard at https://replicas.dev before connecting."
451
+ "Workspace is currently sleeping. Wake it using `replicas app` (press w on a sleeping workspace) or visit https://replicas.dev"
452
452
  );
453
453
  }
454
454
  console.log(chalk4.blue("\nRequesting SSH access token..."));
@@ -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-NB2QAJE2.mjs");
1858
+ const { launchInteractive } = await import("./interactive-EQDMW2E3.mjs");
1859
1859
  await launchInteractive();
1860
1860
  }
1861
1861
 
1862
1862
  // src/index.ts
1863
- var CLI_VERSION = "0.2.40";
1863
+ var CLI_VERSION = "0.2.41";
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 () => {
@@ -4,11 +4,12 @@ import {
4
4
  createMockWorkspaceRecord,
5
5
  createUserMessage,
6
6
  filterDisplayMessages,
7
+ getInitialChatId,
7
8
  getOrganizationId,
8
9
  getValidToken,
9
10
  isAgentBackendEvent,
10
11
  parseAgentEvents
11
- } from "./chunk-WCKZW4VV.mjs";
12
+ } from "./chunk-IO4QHXPW.mjs";
12
13
 
13
14
  // src/interactive/index.tsx
14
15
  import { createCliRenderer } from "@opentui/core";
@@ -145,6 +146,21 @@ function useDeleteWorkspace() {
145
146
  }
146
147
  }, auth.queryClient);
147
148
  }
149
+ function useWakeWorkspace() {
150
+ const auth = useReplicasAuth();
151
+ const orgFetch = useOrgFetch();
152
+ const orgId = auth.getOrganizationId();
153
+ return useMutation({
154
+ mutationFn: (workspaceId) => orgFetch(`/v1/workspaces/${workspaceId}/wake`, {
155
+ method: "POST"
156
+ }),
157
+ onSuccess: (_data, workspaceId) => {
158
+ auth.queryClient.invalidateQueries({ queryKey: ["workspaces", orgId] });
159
+ auth.queryClient.invalidateQueries({ queryKey: ["workspace-status", workspaceId] });
160
+ auth.queryClient.invalidateQueries({ queryKey: ["workspace-chats", workspaceId] });
161
+ }
162
+ }, auth.queryClient);
163
+ }
148
164
  function useGenerateWorkspaceName() {
149
165
  const auth = useReplicasAuth();
150
166
  const orgFetch = useOrgFetch();
@@ -468,11 +484,11 @@ function useEnvironmentFiles() {
468
484
  // src/interactive/components/StatusBar.tsx
469
485
  import { jsx, jsxs } from "@opentui/react/jsx-runtime";
470
486
  var KEYBINDS = {
471
- sidebar: "j/k nav \u21B5 select d del a add",
487
+ sidebar: "j/k nav \u21B5 select d del a add w wake",
472
488
  "chat-tabs": "\u2190/\u2192 switch tabs",
473
489
  "chat-history": "j/k scroll",
474
490
  "chat-input": "\u21B5 send \u21E5 plan/build",
475
- info: "j/k scroll o dashboard"
491
+ info: "j/k scroll o dashboard w wake"
476
492
  };
477
493
  function StatusBar({ focusPanel }) {
478
494
  return /* @__PURE__ */ jsxs(
@@ -541,6 +557,8 @@ function WorkspaceSidebar({
541
557
  onSelectWorkspace,
542
558
  onCreateWorkspace,
543
559
  onDeleteWorkspace,
560
+ onWakeWorkspace,
561
+ wakingWorkspaceId,
544
562
  focused,
545
563
  loading
546
564
  }) {
@@ -675,6 +693,13 @@ function WorkspaceSidebar({
675
693
  }
676
694
  return;
677
695
  }
696
+ if (key.name === "w") {
697
+ const item = items[cursorIndex];
698
+ if (item?.type === "workspace" && item.status === "sleeping" && wakingWorkspaceId !== item.workspaceId) {
699
+ onWakeWorkspace(item.workspaceId);
700
+ }
701
+ return;
702
+ }
678
703
  });
679
704
  const handleItemClick = useCallback3(
680
705
  (globalIndex) => {
@@ -814,7 +839,8 @@ function WorkspaceSidebar({
814
839
  focused && /* @__PURE__ */ jsx2("box", { height: 1, paddingX: 1, backgroundColor: "#111111", children: /* @__PURE__ */ jsxs2("text", { children: [
815
840
  /* @__PURE__ */ jsx2("span", { fg: "#555555", children: "j/k:nav " }),
816
841
  /* @__PURE__ */ jsx2("span", { fg: "#555555", children: "d:del " }),
817
- /* @__PURE__ */ jsx2("span", { fg: "#555555", children: "a:add" })
842
+ /* @__PURE__ */ jsx2("span", { fg: "#555555", children: "a:add " }),
843
+ /* @__PURE__ */ jsx2("span", { fg: "#555555", children: "w:wake" })
818
844
  ] }) })
819
845
  ]
820
846
  }
@@ -1326,7 +1352,7 @@ function DetailList({
1326
1352
  if (rows.length === 0) return null;
1327
1353
  return /* @__PURE__ */ jsx6(Fragment, { children: rows.map((item, i) => /* @__PURE__ */ jsx6(CardItem, { label: item, status: actualSet.has(item) }, i)) });
1328
1354
  }
1329
- function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, envConfig, previews }) {
1355
+ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, envConfig, previews, onWakeWorkspace, wakingWorkspaceId }) {
1330
1356
  const borderColor = focused ? "#66bb6a" : "#333333";
1331
1357
  if (!workspaceName) {
1332
1358
  return /* @__PURE__ */ jsx6(
@@ -1409,6 +1435,18 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, e
1409
1435
  /* @__PURE__ */ jsx6("span", { fg: "#555555", children: " (o)" })
1410
1436
  ] })
1411
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
+ }
1412
1450
  )
1413
1451
  ] }) }),
1414
1452
  (status.isClaudeProcessing || status.isCodexProcessing) && /* @__PURE__ */ jsxs6("box", { backgroundColor: "#1a1500", paddingX: 1, marginX: 1, marginBottom: 1, children: [
@@ -1637,9 +1675,16 @@ function AppInner() {
1637
1675
  { includeDiffs: true }
1638
1676
  );
1639
1677
  const { data: chatsData } = useWorkspaceChats(isMockSelected ? null : selectedWorkspaceId);
1678
+ const chats = isMockSelected ? MOCK_CHATS : chatsData?.chats ?? [];
1679
+ const resolvedChatId = useMemo3(() => {
1680
+ if (selectedChatId && chats.find((c) => c.id === selectedChatId)) {
1681
+ return selectedChatId;
1682
+ }
1683
+ return getInitialChatId(chats);
1684
+ }, [chats, selectedChatId]);
1640
1685
  const { data: historyData, isLoading: loadingMessages } = useChatHistory(
1641
1686
  isMockSelected ? null : selectedWorkspaceId,
1642
- selectedChatId?.startsWith("mock-") ? null : selectedChatId
1687
+ resolvedChatId?.startsWith("mock-") ? null : resolvedChatId
1643
1688
  );
1644
1689
  const { data: previewsData } = useWorkspacePreviews(isMockSelected ? null : selectedWorkspaceId);
1645
1690
  const { connected: sseConnected } = useWorkspaceEvents(
@@ -1647,13 +1692,14 @@ function AppInner() {
1647
1692
  );
1648
1693
  const createWorkspaceMutation = useCreateWorkspace();
1649
1694
  const deleteWorkspaceMutation = useDeleteWorkspace();
1695
+ const wakeWorkspaceMutation = useWakeWorkspace();
1650
1696
  const generateNameMutation = useGenerateWorkspaceName();
1651
- const sendMessageMutation = useSendChatMessage(selectedWorkspaceId, selectedChatId);
1652
- const interruptMutation = useInterruptChat(selectedWorkspaceId, selectedChatId);
1697
+ const [wakingWorkspaceId, setWakingWorkspaceId] = useState5(null);
1698
+ const sendMessageMutation = useSendChatMessage(selectedWorkspaceId, resolvedChatId);
1699
+ const interruptMutation = useInterruptChat(selectedWorkspaceId, resolvedChatId);
1653
1700
  const workspaces = workspacesData?.workspaces ?? [];
1654
1701
  const repositories = reposData?.repositories ?? [];
1655
1702
  const repositorySets = setsData?.repository_sets ?? [];
1656
- const chats = isMockSelected ? MOCK_CHATS : chatsData?.chats ?? [];
1657
1703
  const previews = previewsData?.previews ?? [];
1658
1704
  const allWorkspaces = useMemo3(() => [...mockWorkspaces, ...workspaces], [mockWorkspaces, workspaces]);
1659
1705
  const groups = useMemo3(
@@ -1661,7 +1707,7 @@ function AppInner() {
1661
1707
  [allWorkspaces, workspacesData, repositories, repositorySets]
1662
1708
  );
1663
1709
  const selectedWorkspace = allWorkspaces.find((ws) => ws.id === selectedWorkspaceId) ?? null;
1664
- const selectedChat = chats.find((c) => c.id === selectedChatId) ?? null;
1710
+ const selectedChat = chats.find((c) => c.id === resolvedChatId) ?? null;
1665
1711
  const isProcessing = mockThinking || (selectedChat?.processing ?? false);
1666
1712
  const displayMessages = useMemo3(() => {
1667
1713
  if (isMockSelected) return mockMessages;
@@ -1679,18 +1725,6 @@ function AppInner() {
1679
1725
  setSelectedWorkspaceId(workspaces[0].id);
1680
1726
  }
1681
1727
  }, [workspaces, selectedWorkspaceId]);
1682
- useEffect3(() => {
1683
- if (chats.length > 0 && !selectedChatId) {
1684
- setSelectedChatId(chats[0].id);
1685
- } else if (chats.length > 0 && selectedChatId && !chats.find((c) => c.id === selectedChatId)) {
1686
- setSelectedChatId(chats[0].id);
1687
- }
1688
- }, [chats, selectedChatId]);
1689
- useEffect3(() => {
1690
- setMockMessages([]);
1691
- setMockThinking(false);
1692
- setSelectedChatId(null);
1693
- }, [selectedWorkspaceId]);
1694
1728
  useEffect3(() => {
1695
1729
  if (mockWorkspaces.length === 0) return;
1696
1730
  const realIds = new Set(workspaces.map((w) => w.id));
@@ -1708,6 +1742,7 @@ function AppInner() {
1708
1742
  }
1709
1743
  mockToRealRef.current.delete(mock.id);
1710
1744
  mockGroupRef.current.delete(mock.id);
1745
+ setSelectedChatId(null);
1711
1746
  setMockMessages([]);
1712
1747
  setMockThinking(false);
1713
1748
  changed = true;
@@ -1719,7 +1754,7 @@ function AppInner() {
1719
1754
  }, [workspaces, mockWorkspaces, selectedWorkspaceId]);
1720
1755
  useEffect3(() => {
1721
1756
  if (!selectedWorkspaceId || isMockSelected) return;
1722
- if (!selectedChatId || selectedChatId.startsWith("mock-")) return;
1757
+ if (!resolvedChatId || resolvedChatId.startsWith("mock-")) return;
1723
1758
  if (statusData?.status !== "active") return;
1724
1759
  const pending = pendingMessageRef.current.get(selectedWorkspaceId);
1725
1760
  if (!pending) return;
@@ -1730,7 +1765,7 @@ function AppInner() {
1730
1765
  });
1731
1766
  }
1732
1767
  sendMessageMutation.mutate({ message: pending });
1733
- }, [selectedWorkspaceId, selectedChatId, isMockSelected, statusData?.status]);
1768
+ }, [selectedWorkspaceId, resolvedChatId, isMockSelected, statusData?.status]);
1734
1769
  useEffect3(() => {
1735
1770
  if (mockWorkspaces.length === 0) return;
1736
1771
  const interval = setInterval(() => {
@@ -1738,49 +1773,11 @@ function AppInner() {
1738
1773
  }, 5e3);
1739
1774
  return () => clearInterval(interval);
1740
1775
  }, [mockWorkspaces.length]);
1741
- useKeyboard3((key) => {
1742
- if (key.name === "f12") {
1743
- renderer.console.toggle();
1744
- return;
1745
- }
1746
- if (key.ctrl && key.name === "c") {
1747
- renderer.destroy();
1748
- return;
1749
- }
1750
- if (key.name === "escape") {
1751
- if (isProcessing && selectedWorkspaceId && selectedChatId) {
1752
- interruptMutation.mutate();
1753
- }
1754
- return;
1755
- }
1756
- if (key.shift && key.name === "tab") {
1757
- setFocusPanel((current) => {
1758
- const availablePanels = FOCUS_ORDER.filter((p) => {
1759
- if (p === "sidebar" && !showWorkspacePanel) return false;
1760
- if ((p === "chat-tabs" || p === "chat-history" || p === "chat-input") && !selectedWorkspaceId) return false;
1761
- if (p === "chat-tabs" && chats.length <= 1) return false;
1762
- if (p === "info" && !showInfoPanel) return false;
1763
- return true;
1764
- });
1765
- const idx = availablePanels.indexOf(current);
1766
- return availablePanels[(idx + 1) % availablePanels.length];
1767
- });
1768
- return;
1769
- }
1770
- if (key.name === "tab" && focusPanel === "chat-input") {
1771
- setTaskMode((m) => m === "build" ? "plan" : "build");
1772
- return;
1773
- }
1774
- if (key.name === "o" && focusPanel === "info" && selectedWorkspaceId) {
1775
- const webUrl = process.env.REPLICAS_WEB_URL || "https://replicas.dev";
1776
- import("open").then((mod) => mod.default(`${webUrl}/dashboard?workspaceId=${selectedWorkspaceId}`)).catch(() => {
1777
- });
1778
- return;
1779
- }
1780
- if (focusPanel === "chat-input") return;
1781
- });
1782
1776
  const handleSelectWorkspace = useCallback5((workspaceId) => {
1783
1777
  setSelectedWorkspaceId(workspaceId);
1778
+ setSelectedChatId(null);
1779
+ setMockMessages([]);
1780
+ setMockThinking(false);
1784
1781
  setFocusPanel("chat-input");
1785
1782
  }, []);
1786
1783
  const handleFocus = useCallback5((panel) => {
@@ -1824,12 +1821,73 @@ function AppInner() {
1824
1821
  },
1825
1822
  [mockIds, selectedWorkspaceId, deleteWorkspaceMutation]
1826
1823
  );
1824
+ const handleWakeWorkspace = useCallback5(
1825
+ async (workspaceId) => {
1826
+ setWakingWorkspaceId(workspaceId);
1827
+ try {
1828
+ await wakeWorkspaceMutation.mutateAsync(workspaceId);
1829
+ toast.show({ message: "Workspace waking up...", variant: "info" });
1830
+ } catch (err) {
1831
+ toast.error(err);
1832
+ } finally {
1833
+ setWakingWorkspaceId(null);
1834
+ }
1835
+ },
1836
+ [wakeWorkspaceMutation, toast]
1837
+ );
1827
1838
  const handleSelectChat = useCallback5((chatId) => {
1828
1839
  setSelectedChatId(chatId);
1829
1840
  }, []);
1841
+ useKeyboard3((key) => {
1842
+ if (key.name === "f12") {
1843
+ renderer.console.toggle();
1844
+ return;
1845
+ }
1846
+ if (key.ctrl && key.name === "c") {
1847
+ renderer.destroy();
1848
+ return;
1849
+ }
1850
+ if (key.name === "escape") {
1851
+ if (isProcessing && selectedWorkspaceId && resolvedChatId) {
1852
+ interruptMutation.mutate();
1853
+ }
1854
+ return;
1855
+ }
1856
+ if (key.shift && key.name === "tab") {
1857
+ setFocusPanel((current) => {
1858
+ const availablePanels = FOCUS_ORDER.filter((p) => {
1859
+ if (p === "sidebar" && !showWorkspacePanel) return false;
1860
+ if ((p === "chat-tabs" || p === "chat-history" || p === "chat-input") && (!selectedWorkspaceId || statusData?.status === "sleeping")) return false;
1861
+ if (p === "chat-tabs" && chats.length <= 1) return false;
1862
+ if (p === "info" && !showInfoPanel) return false;
1863
+ return true;
1864
+ });
1865
+ const idx = availablePanels.indexOf(current);
1866
+ return availablePanels[(idx + 1) % availablePanels.length];
1867
+ });
1868
+ return;
1869
+ }
1870
+ if (key.name === "tab" && focusPanel === "chat-input") {
1871
+ setTaskMode((m) => m === "build" ? "plan" : "build");
1872
+ return;
1873
+ }
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) {
1881
+ if (statusData?.status === "sleeping" && !wakingWorkspaceId) {
1882
+ handleWakeWorkspace(selectedWorkspaceId);
1883
+ }
1884
+ return;
1885
+ }
1886
+ if (focusPanel === "chat-input") return;
1887
+ });
1830
1888
  const handleSendMessage = useCallback5(
1831
1889
  async (message) => {
1832
- if (!selectedWorkspaceId || !selectedChatId) return;
1890
+ if (!selectedWorkspaceId || !resolvedChatId) return;
1833
1891
  if (isMockSelected) {
1834
1892
  const { message: userMsg } = createUserMessage(message);
1835
1893
  setMockMessages((prev) => [...prev, userMsg]);
@@ -1842,7 +1900,7 @@ function AppInner() {
1842
1900
  permissionMode: taskMode === "plan" ? "read" : void 0
1843
1901
  });
1844
1902
  },
1845
- [selectedWorkspaceId, selectedChatId, isMockSelected, sendMessageMutation, taskMode]
1903
+ [selectedWorkspaceId, resolvedChatId, isMockSelected, sendMessageMutation, taskMode]
1846
1904
  );
1847
1905
  return /* @__PURE__ */ jsxs7("box", { flexDirection: "column", width: "100%", height: "100%", backgroundColor: "#000000", children: [
1848
1906
  /* @__PURE__ */ jsxs7("box", { flexDirection: "row", flexGrow: 1, backgroundColor: "#000000", children: [
@@ -1855,15 +1913,17 @@ function AppInner() {
1855
1913
  onSelectWorkspace: handleSelectWorkspace,
1856
1914
  onCreateWorkspace: handleCreateWorkspace,
1857
1915
  onDeleteWorkspace: handleDeleteWorkspace,
1916
+ onWakeWorkspace: handleWakeWorkspace,
1917
+ wakingWorkspaceId,
1858
1918
  focused: focusPanel === "sidebar",
1859
1919
  loading: loadingWorkspaces
1860
1920
  }
1861
1921
  ),
1862
- selectedWorkspaceId ? /* @__PURE__ */ jsx9(
1922
+ selectedWorkspaceId && statusData?.status !== "sleeping" ? /* @__PURE__ */ jsx9(
1863
1923
  ChatArea,
1864
1924
  {
1865
1925
  chats,
1866
- selectedChatId,
1926
+ selectedChatId: resolvedChatId,
1867
1927
  displayMessages,
1868
1928
  onSelectChat: handleSelectChat,
1869
1929
  onSendMessage: handleSendMessage,
@@ -1873,6 +1933,30 @@ function AppInner() {
1873
1933
  isProcessing,
1874
1934
  loading: loadingMessages
1875
1935
  }
1936
+ ) : selectedWorkspaceId && statusData?.status === "sleeping" ? /* @__PURE__ */ jsxs7(
1937
+ "box",
1938
+ {
1939
+ flexGrow: 1,
1940
+ border: true,
1941
+ borderStyle: "rounded",
1942
+ borderColor: "#333333",
1943
+ backgroundColor: "#000000",
1944
+ justifyContent: "center",
1945
+ alignItems: "center",
1946
+ flexDirection: "column",
1947
+ gap: 1,
1948
+ children: [
1949
+ /* @__PURE__ */ jsxs7("text", { fg: "#888888", children: [
1950
+ "\u263E",
1951
+ " This workspace is sleeping"
1952
+ ] }),
1953
+ /* @__PURE__ */ jsxs7("text", { fg: "#555555", children: [
1954
+ "Press ",
1955
+ /* @__PURE__ */ jsx9("span", { fg: "#66bb6a", children: /* @__PURE__ */ jsx9("strong", { children: "w" }) }),
1956
+ " to wake it up"
1957
+ ] })
1958
+ ]
1959
+ }
1876
1960
  ) : /* @__PURE__ */ jsx9(
1877
1961
  "box",
1878
1962
  {
@@ -1899,7 +1983,9 @@ function AppInner() {
1899
1983
  variables: envVariables ?? null,
1900
1984
  files: envFiles ?? null
1901
1985
  },
1902
- previews
1986
+ previews,
1987
+ onWakeWorkspace: handleWakeWorkspace,
1988
+ wakingWorkspaceId
1903
1989
  }
1904
1990
  )
1905
1991
  ] }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.40",
3
+ "version": "0.2.41",
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": {