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
|
-
##
|
|
86
|
+
## How it Works
|
|
86
87
|
|
|
87
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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-
|
|
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.
|
|
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-
|
|
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.
|
|
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-
|
|
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
|
-
|
|
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
|
|
1652
|
-
const
|
|
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 ===
|
|
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 (!
|
|
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,
|
|
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 || !
|
|
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,
|
|
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
|
] }),
|