replicas-cli 0.2.340 → 0.2.342

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.
Files changed (2) hide show
  1. package/dist/index.mjs +173 -131
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7721,6 +7721,7 @@ var AGENT_MODELS = {
7721
7721
  "gpt-5-mini",
7722
7722
  "gemini-3.1-pro",
7723
7723
  "gemini-3-flash",
7724
+ "grok-4.5",
7724
7725
  "grok-4.3",
7725
7726
  CLAUDE_HAIKU_4_5_MODEL,
7726
7727
  "kimi-k2.5"
@@ -7758,6 +7759,7 @@ var MODEL_LABELS = {
7758
7759
  [CLAUDE_HAIKU_4_5_MODEL]: "Haiku 4.5",
7759
7760
  "gemini-3.1-pro": "Gemini 3.1 Pro",
7760
7761
  "gemini-3-flash": "Gemini 3 Flash",
7762
+ "grok-4.5": "Grok 4.5",
7761
7763
  "grok-4.3": "Grok 4.3",
7762
7764
  "kimi-k2.5": "Kimi K2.5"
7763
7765
  };
@@ -9597,7 +9599,7 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
9597
9599
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
9598
9600
 
9599
9601
  // ../shared/src/cli-version.ts
9600
- var CLI_VERSION = "0.2.340";
9602
+ var CLI_VERSION = "0.2.342";
9601
9603
 
9602
9604
  // ../shared/src/engine/environment.ts
9603
9605
  var DESKTOP_NOVNC_PORT = 6080;
@@ -16298,7 +16300,7 @@ import { createCliRenderer } from "@opentui/core";
16298
16300
  import { createRoot } from "@opentui/react";
16299
16301
 
16300
16302
  // src/interactive/App.tsx
16301
- import { useState as useState8, useEffect as useEffect3, useMemo as useMemo6, useCallback as useCallback8, useRef as useRef5 } from "react";
16303
+ import { useState as useState7, useEffect as useEffect2, useMemo as useMemo5, useCallback as useCallback9, useRef as useRef6 } from "react";
16302
16304
  import { useKeyboard as useKeyboard5, useRenderer, useTerminalDimensions as useTerminalDimensions3 } from "@opentui/react";
16303
16305
  import { QueryClient } from "@tanstack/react-query";
16304
16306
 
@@ -16320,8 +16322,74 @@ function useEffectOnMount(effect) {
16320
16322
  useEffect(effect, []);
16321
16323
  }
16322
16324
 
16325
+ // ../shared/src/hooks/useReconnectingSseStream.ts
16326
+ import { useCallback, useRef, useSyncExternalStore } from "react";
16327
+ function useReconnectingSseStream(options) {
16328
+ const { enabled, openStream, onEvent, onConnect, onNotOk, reconnectDelayMs = 1e3, coalesceMs } = options;
16329
+ const connectedRef = useRef(false);
16330
+ const subscribe = useCallback(
16331
+ (notify) => {
16332
+ if (!enabled) return () => {
16333
+ };
16334
+ const controller = new AbortController();
16335
+ let cancelled = false;
16336
+ let debounce = null;
16337
+ const setConnected = (value) => {
16338
+ if (connectedRef.current === value) return;
16339
+ connectedRef.current = value;
16340
+ notify();
16341
+ };
16342
+ const emit = (event) => {
16343
+ if (coalesceMs === void 0) {
16344
+ void onEvent(event);
16345
+ return;
16346
+ }
16347
+ if (debounce) clearTimeout(debounce);
16348
+ debounce = setTimeout(() => void onEvent(event), coalesceMs);
16349
+ };
16350
+ const connect = async () => {
16351
+ try {
16352
+ const response = await openStream(controller.signal);
16353
+ if (!response.ok || !response.body) {
16354
+ setConnected(false);
16355
+ return onNotOk?.(response) === "stop";
16356
+ }
16357
+ setConnected(true);
16358
+ onConnect?.();
16359
+ await readSseStream(response.body, emit, () => !cancelled);
16360
+ return false;
16361
+ } catch {
16362
+ setConnected(false);
16363
+ return false;
16364
+ }
16365
+ };
16366
+ const run = async () => {
16367
+ while (!cancelled) {
16368
+ const stop = await connect();
16369
+ if (cancelled || stop) break;
16370
+ await new Promise((resolve2) => setTimeout(resolve2, reconnectDelayMs));
16371
+ }
16372
+ };
16373
+ run().catch(() => setConnected(false));
16374
+ return () => {
16375
+ cancelled = true;
16376
+ controller.abort();
16377
+ if (debounce) clearTimeout(debounce);
16378
+ setConnected(false);
16379
+ };
16380
+ },
16381
+ [enabled, openStream, onEvent, onConnect, onNotOk, reconnectDelayMs, coalesceMs]
16382
+ );
16383
+ const connected = useSyncExternalStore(
16384
+ subscribe,
16385
+ () => connectedRef.current,
16386
+ () => false
16387
+ );
16388
+ return { connected };
16389
+ }
16390
+
16323
16391
  // ../shared/src/hooks/fetch.ts
16324
- import { useCallback } from "react";
16392
+ import { useCallback as useCallback2 } from "react";
16325
16393
  var REDIRECT_STATUSES2 = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
16326
16394
  var MAX_REDIRECTS2 = 5;
16327
16395
  async function fetchWithRedirects2(url, init, attempt = 0) {
@@ -16347,7 +16415,7 @@ async function fetchWithRedirects2(url, init, attempt = 0) {
16347
16415
  }
16348
16416
  function useOrgFetch() {
16349
16417
  const auth = useReplicasAuth();
16350
- return useCallback(
16418
+ return useCallback2(
16351
16419
  async function orgFetch(url, options) {
16352
16420
  const token = await auth.getAccessToken();
16353
16421
  const orgId = auth.getOrganizationId();
@@ -16375,7 +16443,7 @@ function useOrgFetch() {
16375
16443
  }
16376
16444
  function useRawOrgFetch() {
16377
16445
  const auth = useReplicasAuth();
16378
- return useCallback(
16446
+ return useCallback2(
16379
16447
  async function rawOrgFetch(url, options) {
16380
16448
  const token = await auth.getAccessToken();
16381
16449
  const orgId = auth.getOrganizationId();
@@ -16392,7 +16460,7 @@ function useRawOrgFetch() {
16392
16460
  }
16393
16461
 
16394
16462
  // ../shared/src/hooks/useWorkspaces.ts
16395
- import { useCallback as useCallback2 } from "react";
16463
+ import { useCallback as useCallback3 } from "react";
16396
16464
  import { useQuery, useMutation } from "@tanstack/react-query";
16397
16465
  function useWorkspaces(viewModes, page = 1, limit = 100) {
16398
16466
  const auth = useReplicasAuth();
@@ -16444,7 +16512,7 @@ function useWaitForWorkspaceActive() {
16444
16512
  const auth = useReplicasAuth();
16445
16513
  const orgFetch = useOrgFetch();
16446
16514
  const orgId = auth.getOrganizationId();
16447
- return useCallback2(async (workspaceId) => {
16515
+ return useCallback3(async (workspaceId) => {
16448
16516
  try {
16449
16517
  const result = await auth.queryClient.fetchQuery({
16450
16518
  queryKey: ["workspace-wait-active", orgId, workspaceId],
@@ -16516,7 +16584,7 @@ function useGenerateWorkspaceName() {
16516
16584
  }
16517
16585
 
16518
16586
  // ../shared/src/hooks/useWorkspaceEngine.ts
16519
- import { useCallback as useCallback3, useEffect as useEffect2, useMemo, useState } from "react";
16587
+ import { useCallback as useCallback4 } from "react";
16520
16588
  import { useQuery as useQuery2, useMutation as useMutation2 } from "@tanstack/react-query";
16521
16589
  function upsertChat(chats, chat) {
16522
16590
  const existingIndex = chats.findIndex((item) => item.id === chat.id);
@@ -16644,8 +16712,7 @@ function useWorkspaceEvents(workspaceId, enabled = true) {
16644
16712
  const auth = useReplicasAuth();
16645
16713
  const rawFetch = useRawOrgFetch();
16646
16714
  const qc = auth.queryClient;
16647
- const [connected, setConnected] = useState(false);
16648
- const handleEvent = useCallback3((event) => {
16715
+ const handleEvent = useCallback4((event) => {
16649
16716
  if (!workspaceId) return;
16650
16717
  const chatsKey = ["workspace-chats", workspaceId];
16651
16718
  if (event.type === "chat.created" || event.type === "chat.updated") {
@@ -16723,43 +16790,18 @@ function useWorkspaceEvents(workspaceId, enabled = true) {
16723
16790
  return;
16724
16791
  }
16725
16792
  }, [qc, workspaceId]);
16726
- useEffect2(() => {
16727
- if (!workspaceId || !enabled) return;
16728
- const controller = new AbortController();
16729
- let cancelled = false;
16730
- const connect = async () => {
16731
- try {
16732
- const response = await rawFetch(`/v1/workspaces/${workspaceId}/events`, {
16733
- headers: { "Accept": "text/event-stream" },
16734
- signal: controller.signal
16735
- });
16736
- if (!response.ok || !response.body) {
16737
- setConnected(false);
16738
- return false;
16739
- }
16740
- setConnected(true);
16741
- await readSseStream(response.body, handleEvent, () => !cancelled);
16742
- return false;
16743
- } catch {
16744
- setConnected(false);
16745
- return false;
16746
- }
16747
- };
16748
- const run = async () => {
16749
- while (!cancelled) {
16750
- await connect();
16751
- if (cancelled) break;
16752
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
16753
- }
16754
- };
16755
- run().catch(() => setConnected(false));
16756
- return () => {
16757
- cancelled = true;
16758
- controller.abort();
16759
- setConnected(false);
16760
- };
16761
- }, [enabled, handleEvent, rawFetch, workspaceId]);
16762
- return useMemo(() => ({ connected }), [connected]);
16793
+ const openStream = useCallback4(
16794
+ (signal) => rawFetch(`/v1/workspaces/${workspaceId}/events`, {
16795
+ headers: { Accept: "text/event-stream" },
16796
+ signal
16797
+ }),
16798
+ [rawFetch, workspaceId]
16799
+ );
16800
+ return useReconnectingSseStream({
16801
+ enabled: workspaceId != null && enabled,
16802
+ openStream,
16803
+ onEvent: handleEvent
16804
+ });
16763
16805
  }
16764
16806
 
16765
16807
  // ../shared/src/hooks/useRepositories.ts
@@ -16839,7 +16881,7 @@ function StatusBar({ focusPanel, viewingDiff, hasDiffAvailable }) {
16839
16881
  }
16840
16882
 
16841
16883
  // src/interactive/components/WorkspaceSidebar.tsx
16842
- import { useState as useState2, useMemo as useMemo2, useCallback as useCallback4 } from "react";
16884
+ import { useState, useMemo, useCallback as useCallback5 } from "react";
16843
16885
  import { useKeyboard, useTerminalDimensions } from "@opentui/react";
16844
16886
  import { jsx as jsx2, jsxs as jsxs2 } from "@opentui/react/jsx-runtime";
16845
16887
  function flattenGroups(groups, collapsedGroups) {
@@ -16885,17 +16927,17 @@ function WorkspaceSidebar({
16885
16927
  loading
16886
16928
  }) {
16887
16929
  const { height: termHeight } = useTerminalDimensions();
16888
- const [collapsedGroups, setCollapsedGroups] = useState2(/* @__PURE__ */ new Set());
16889
- const [cursorIndex, setCursorIndex] = useState2(0);
16890
- const [scrollOffset, setScrollOffset] = useState2(0);
16891
- const [confirmArchive, setConfirmArchive] = useState2(null);
16892
- const items = useMemo2(() => flattenGroups(groups, collapsedGroups), [groups, collapsedGroups]);
16930
+ const [collapsedGroups, setCollapsedGroups] = useState(/* @__PURE__ */ new Set());
16931
+ const [cursorIndex, setCursorIndex] = useState(0);
16932
+ const [scrollOffset, setScrollOffset] = useState(0);
16933
+ const [confirmArchive, setConfirmArchive] = useState(null);
16934
+ const items = useMemo(() => flattenGroups(groups, collapsedGroups), [groups, collapsedGroups]);
16893
16935
  const clampedCursor = Math.min(cursorIndex, Math.max(0, items.length - 1));
16894
16936
  if (clampedCursor !== cursorIndex) {
16895
16937
  setCursorIndex(clampedCursor);
16896
16938
  }
16897
16939
  const visibleHeight = Math.max(1, termHeight - 4);
16898
- const adjustScroll = useCallback4(
16940
+ const adjustScroll = useCallback5(
16899
16941
  (newCursor) => {
16900
16942
  let newOffset = scrollOffset;
16901
16943
  if (newCursor < newOffset) {
@@ -16907,7 +16949,7 @@ function WorkspaceSidebar({
16907
16949
  },
16908
16950
  [scrollOffset, visibleHeight]
16909
16951
  );
16910
- const moveCursor = useCallback4(
16952
+ const moveCursor = useCallback5(
16911
16953
  (next) => {
16912
16954
  const len = items.length;
16913
16955
  if (len === 0) return;
@@ -16917,7 +16959,7 @@ function WorkspaceSidebar({
16917
16959
  },
16918
16960
  [items.length, adjustScroll]
16919
16961
  );
16920
- const handleAction = useCallback4(
16962
+ const handleAction = useCallback5(
16921
16963
  (item) => {
16922
16964
  if (item.type === "group") {
16923
16965
  setCollapsedGroups((prev) => {
@@ -16937,7 +16979,7 @@ function WorkspaceSidebar({
16937
16979
  },
16938
16980
  [onSelectWorkspace, onCreateWorkspace]
16939
16981
  );
16940
- const handleArchive = useCallback4(() => {
16982
+ const handleArchive = useCallback5(() => {
16941
16983
  const item = items[cursorIndex];
16942
16984
  if (!item || item.type !== "workspace") return;
16943
16985
  if (confirmArchive === item.workspaceId) {
@@ -16947,7 +16989,7 @@ function WorkspaceSidebar({
16947
16989
  setConfirmArchive(item.workspaceId);
16948
16990
  }
16949
16991
  }, [items, cursorIndex, confirmArchive, onArchiveWorkspace]);
16950
- const moveCursorAndClearConfirm = useCallback4(
16992
+ const moveCursorAndClearConfirm = useCallback5(
16951
16993
  (next) => {
16952
16994
  setConfirmArchive(null);
16953
16995
  moveCursor(next);
@@ -17015,7 +17057,7 @@ function WorkspaceSidebar({
17015
17057
  return;
17016
17058
  }
17017
17059
  });
17018
- const handleItemClick = useCallback4(
17060
+ const handleItemClick = useCallback5(
17019
17061
  (globalIndex) => {
17020
17062
  setConfirmArchive(null);
17021
17063
  setCursorIndex(globalIndex);
@@ -17024,7 +17066,7 @@ function WorkspaceSidebar({
17024
17066
  },
17025
17067
  [items, handleAction]
17026
17068
  );
17027
- const handleArchiveClick = useCallback4(
17069
+ const handleArchiveClick = useCallback5(
17028
17070
  (workspaceId, e) => {
17029
17071
  e?.preventDefault?.();
17030
17072
  if (confirmArchive === workspaceId) {
@@ -17162,11 +17204,11 @@ function WorkspaceSidebar({
17162
17204
  }
17163
17205
 
17164
17206
  // src/interactive/components/ChatArea.tsx
17165
- import { useRef as useRef2 } from "react";
17207
+ import { useRef as useRef3 } from "react";
17166
17208
  import { useKeyboard as useKeyboard3 } from "@opentui/react";
17167
17209
 
17168
17210
  // src/interactive/components/ChatMessage.tsx
17169
- import { useState as useState5, useMemo as useMemo4 } from "react";
17211
+ import { useState as useState4, useMemo as useMemo3 } from "react";
17170
17212
 
17171
17213
  // src/interactive/components/Spinner.tsx
17172
17214
  import "opentui-spinner/react";
@@ -17181,10 +17223,10 @@ function SpinnerLabel({ color, label }) {
17181
17223
  }
17182
17224
 
17183
17225
  // src/interactive/components/StructuredUserMessage.tsx
17184
- import { useState as useState4 } from "react";
17226
+ import { useState as useState3 } from "react";
17185
17227
 
17186
17228
  // src/interactive/components/diff-utils.tsx
17187
- import React2, { useState as useState3, useMemo as useMemo3, useCallback as useCallback5, useRef } from "react";
17229
+ import React2, { useState as useState2, useMemo as useMemo2, useCallback as useCallback6, useRef as useRef2 } from "react";
17188
17230
  import { SyntaxStyle } from "@opentui/core";
17189
17231
  import { useKeyboard as useKeyboard2 } from "@opentui/react";
17190
17232
  import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "@opentui/react/jsx-runtime";
@@ -17314,7 +17356,7 @@ function diffProps(filePath) {
17314
17356
  };
17315
17357
  }
17316
17358
  function DiffView({ diff, filePath }) {
17317
- const hunks = useMemo3(() => splitDiffByHunks(diff), [diff]);
17359
+ const hunks = useMemo2(() => splitDiffByHunks(diff), [diff]);
17318
17360
  const props = diffProps(filePath);
17319
17361
  if (hunks.length <= 1) {
17320
17362
  return /* @__PURE__ */ jsx4("diff", { diff: ensureUnifiedHeaders(diff, filePath), ...props });
@@ -17427,16 +17469,16 @@ function buildFileTree(files) {
17427
17469
  }
17428
17470
  var FILE_PANEL_WIDTH = 32;
17429
17471
  function DiffViewer({ diff, repoName, focused }) {
17430
- const files = useMemo3(() => splitDiffByFile(diff), [diff]);
17431
- const tree = useMemo3(() => buildFileTree(files), [files]);
17432
- const [selectedFileIndex, setSelectedFileIndex] = useState3(0);
17433
- const [collapsedFolders, setCollapsedFolders] = useState3(/* @__PURE__ */ new Set());
17434
- const [cursorIndex, setCursorIndex] = useState3(0);
17435
- const [innerFocus, setInnerFocus] = useState3("files");
17472
+ const files = useMemo2(() => splitDiffByFile(diff), [diff]);
17473
+ const tree = useMemo2(() => buildFileTree(files), [files]);
17474
+ const [selectedFileIndex, setSelectedFileIndex] = useState2(0);
17475
+ const [collapsedFolders, setCollapsedFolders] = useState2(/* @__PURE__ */ new Set());
17476
+ const [cursorIndex, setCursorIndex] = useState2(0);
17477
+ const [innerFocus, setInnerFocus] = useState2("files");
17436
17478
  const safeFileIndex = Math.min(selectedFileIndex, Math.max(0, files.length - 1));
17437
- const diffScrollRef = useRef(null);
17438
- const fileTreeScrollRef = useRef(null);
17439
- const visibleTree = useMemo3(() => {
17479
+ const diffScrollRef = useRef2(null);
17480
+ const fileTreeScrollRef = useRef2(null);
17481
+ const visibleTree = useMemo2(() => {
17440
17482
  const result = [];
17441
17483
  let hideUntilDepth = null;
17442
17484
  for (const node of tree) {
@@ -17452,12 +17494,12 @@ function DiffViewer({ diff, repoName, focused }) {
17452
17494
  return result;
17453
17495
  }, [tree, collapsedFolders]);
17454
17496
  const safeCursorIndex = Math.min(cursorIndex, Math.max(0, visibleTree.length - 1));
17455
- const scrollCursorIntoView = useCallback5((treeIdx) => {
17497
+ const scrollCursorIntoView = useCallback6((treeIdx) => {
17456
17498
  const node = visibleTree[treeIdx];
17457
17499
  if (!node) return;
17458
17500
  fileTreeScrollRef.current?.scrollChildIntoView(`tree-${node.path}`);
17459
17501
  }, [visibleTree]);
17460
- const moveCursor = useCallback5((next) => {
17502
+ const moveCursor = useCallback6((next) => {
17461
17503
  const len = visibleTree.length;
17462
17504
  if (len === 0) return;
17463
17505
  const wrapped = (next % len + len) % len;
@@ -17468,7 +17510,7 @@ function DiffViewer({ diff, repoName, focused }) {
17468
17510
  setSelectedFileIndex(node.fileIndex);
17469
17511
  }
17470
17512
  }, [visibleTree, scrollCursorIntoView]);
17471
- const toggleFolder = useCallback5((folderPath) => {
17513
+ const toggleFolder = useCallback6((folderPath) => {
17472
17514
  setCollapsedFolders((prev) => {
17473
17515
  const next = new Set(prev);
17474
17516
  if (next.has(folderPath)) next.delete(folderPath);
@@ -17476,7 +17518,7 @@ function DiffViewer({ diff, repoName, focused }) {
17476
17518
  return next;
17477
17519
  });
17478
17520
  }, []);
17479
- const selectFile = useCallback5((fileIndex, treeIndex) => {
17521
+ const selectFile = useCallback6((fileIndex, treeIndex) => {
17480
17522
  setSelectedFileIndex(fileIndex);
17481
17523
  setCursorIndex(treeIndex);
17482
17524
  scrollCursorIntoView(treeIndex);
@@ -17513,7 +17555,7 @@ function DiffViewer({ diff, repoName, focused }) {
17513
17555
  }
17514
17556
  }
17515
17557
  });
17516
- const statsColumnWidth = useMemo3(() => {
17558
+ const statsColumnWidth = useMemo2(() => {
17517
17559
  let max = 0;
17518
17560
  for (const f of files) {
17519
17561
  const a = f.added > 0 ? `+${f.added}`.length : 0;
@@ -17697,7 +17739,7 @@ function MessageBody({ children }) {
17697
17739
  return /* @__PURE__ */ jsx5("text", { fg: "#ffffff", selectable: true, children });
17698
17740
  }
17699
17741
  function ExpandableSection({ label, children }) {
17700
- const [expanded, setExpanded] = useState4(false);
17742
+ const [expanded, setExpanded] = useState3(false);
17701
17743
  if (!children) return null;
17702
17744
  return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
17703
17745
  /* @__PURE__ */ jsx5("box", { onMouseDown: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsxs5("text", { children: [
@@ -17711,7 +17753,7 @@ function ExpandableSection({ label, children }) {
17711
17753
  ] });
17712
17754
  }
17713
17755
  function ExpandableDiffSection({ label, diffContent, filePath }) {
17714
- const [expanded, setExpanded] = useState4(false);
17756
+ const [expanded, setExpanded] = useState3(false);
17715
17757
  if (!diffContent) return null;
17716
17758
  return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
17717
17759
  /* @__PURE__ */ jsx5("box", { onMouseDown: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsxs5("text", { children: [
@@ -17954,7 +17996,7 @@ function ExpandableAction({
17954
17996
  status,
17955
17997
  children
17956
17998
  }) {
17957
- const [expanded, setExpanded] = useState5(false);
17999
+ const [expanded, setExpanded] = useState4(false);
17958
18000
  return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
17959
18001
  /* @__PURE__ */ jsx6(
17960
18002
  ActionLine,
@@ -17979,9 +18021,9 @@ function getChangeStyle(action) {
17979
18021
  return CHANGE_STYLE[action] ?? DEFAULT_CHANGE_STYLE;
17980
18022
  }
17981
18023
  function PatchOperation({ op, defaultExpanded = false }) {
17982
- const [expanded, setExpanded] = useState5(defaultExpanded);
18024
+ const [expanded, setExpanded] = useState4(defaultExpanded);
17983
18025
  const { color, sign } = getChangeStyle(op.action);
17984
- const stats = useMemo4(() => op.diff ? countDiffStats(op.diff) : null, [op.diff]);
18026
+ const stats = useMemo3(() => op.diff ? countDiffStats(op.diff) : null, [op.diff]);
17985
18027
  if (!op.diff) {
17986
18028
  return /* @__PURE__ */ jsxs6("text", { children: [
17987
18029
  /* @__PURE__ */ jsx6("span", { fg: color, children: sign }),
@@ -18021,7 +18063,7 @@ function isStructuredPrompt(p) {
18021
18063
  return p.source !== "raw";
18022
18064
  }
18023
18065
  function UserMessageContent({ content }) {
18024
- const parsed = useMemo4(() => parseUserMessage(content), [content]);
18066
+ const parsed = useMemo3(() => parseUserMessage(content), [content]);
18025
18067
  return /* @__PURE__ */ jsx6(
18026
18068
  "box",
18027
18069
  {
@@ -18158,10 +18200,10 @@ function ChatArea({
18158
18200
  agentLabel,
18159
18201
  agentConnectHelp
18160
18202
  }) {
18161
- const textareaRef = useRef2(null);
18162
- const scrollboxRef = useRef2(null);
18163
- const isAtBottomRef = useRef2(true);
18164
- const onSendMessageRef = useRef2(onSendMessage);
18203
+ const textareaRef = useRef3(null);
18204
+ const scrollboxRef = useRef3(null);
18205
+ const isAtBottomRef = useRef3(true);
18206
+ const onSendMessageRef = useRef3(onSendMessage);
18165
18207
  onSendMessageRef.current = onSendMessage;
18166
18208
  const inputFocused = focusPanel === "chat-input";
18167
18209
  const tabsFocused = focusPanel === "chat-tabs";
@@ -18333,7 +18375,7 @@ function ChatArea({
18333
18375
  }
18334
18376
 
18335
18377
  // src/interactive/components/WorkspaceInfo.tsx
18336
- import React6, { useState as useState6, useMemo as useMemo5, useCallback as useCallback6, useRef as useRef3 } from "react";
18378
+ import React6, { useState as useState5, useMemo as useMemo4, useCallback as useCallback7, useRef as useRef4 } from "react";
18337
18379
  import open4 from "open";
18338
18380
  import { useKeyboard as useKeyboard4 } from "@opentui/react";
18339
18381
  import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
@@ -18521,19 +18563,19 @@ function ViewModeRow({
18521
18563
  }
18522
18564
  function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, agentAvailability, previews, onWakeWorkspace, onViewDiff, wakingWorkspaceId, viewMode, viewingDiffRepoName, onSelectChatMode, onSelectDiffMode, onCreatePr, isPlanMode }) {
18523
18565
  const borderColor = focused ? "#3eeba3" : "#333333";
18524
- const [cursorIndex, setCursorIndex] = useState6(0);
18525
- const interactiveItems = useMemo5(() => {
18566
+ const [cursorIndex, setCursorIndex] = useState5(0);
18567
+ const interactiveItems = useMemo4(() => {
18526
18568
  if (!status || !workspaceName) return [];
18527
18569
  return buildInteractiveItems(workspaceId, status, previews, wakingWorkspaceId);
18528
18570
  }, [workspaceId, workspaceName, status, previews, wakingWorkspaceId]);
18529
- const diffItems = useMemo5(
18571
+ const diffItems = useMemo4(
18530
18572
  () => interactiveItems.filter((item) => item.type === "diff"),
18531
18573
  [interactiveItems]
18532
18574
  );
18533
18575
  const hasAnyDiff = diffItems.length > 0;
18534
18576
  const safeCursor = interactiveItems.length > 0 ? Math.min(cursorIndex, interactiveItems.length - 1) : 0;
18535
- const scrollboxRef = useRef3(null);
18536
- const moveCursor = useCallback6(
18577
+ const scrollboxRef = useRef4(null);
18578
+ const moveCursor = useCallback7(
18537
18579
  (next) => {
18538
18580
  const len = interactiveItems.length;
18539
18581
  if (len === 0) return;
@@ -18544,7 +18586,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
18544
18586
  },
18545
18587
  [interactiveItems]
18546
18588
  );
18547
- const handleAction = useCallback6(
18589
+ const handleAction = useCallback7(
18548
18590
  (item) => {
18549
18591
  if (!item) return;
18550
18592
  switch (item.type) {
@@ -18613,7 +18655,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
18613
18655
  return;
18614
18656
  }
18615
18657
  });
18616
- const isHighlighted = useCallback6(
18658
+ const isHighlighted = useCallback7(
18617
18659
  (item) => {
18618
18660
  if (!focused) return false;
18619
18661
  const idx = interactiveItems.indexOf(item);
@@ -18621,7 +18663,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
18621
18663
  },
18622
18664
  [focused, interactiveItems, safeCursor]
18623
18665
  );
18624
- const findItem = useCallback6(
18666
+ const findItem = useCallback7(
18625
18667
  (type, key) => {
18626
18668
  return interactiveItems.find((item) => {
18627
18669
  if (item.type !== type) return false;
@@ -18915,7 +18957,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
18915
18957
  import { useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
18916
18958
 
18917
18959
  // src/interactive/toast-context.tsx
18918
- import { createContext as createContext2, useContext as useContext2, useState as useState7, useCallback as useCallback7, useRef as useRef4 } from "react";
18960
+ import { createContext as createContext2, useContext as useContext2, useState as useState6, useCallback as useCallback8, useRef as useRef5 } from "react";
18919
18961
  import { jsx as jsx9 } from "@opentui/react/jsx-runtime";
18920
18962
  var ToastContext = createContext2(null);
18921
18963
  function useToast() {
@@ -18924,9 +18966,9 @@ function useToast() {
18924
18966
  return ctx;
18925
18967
  }
18926
18968
  function ToastProvider({ children }) {
18927
- const [current, setCurrent] = useState7(null);
18928
- const timeoutRef = useRef4(null);
18929
- const show = useCallback7((options) => {
18969
+ const [current, setCurrent] = useState6(null);
18970
+ const timeoutRef = useRef5(null);
18971
+ const show = useCallback8((options) => {
18930
18972
  const { message, variant = "info", duration = 3e3 } = options;
18931
18973
  setCurrent({ message, variant });
18932
18974
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
@@ -18934,7 +18976,7 @@ function ToastProvider({ children }) {
18934
18976
  setCurrent(null);
18935
18977
  }, duration);
18936
18978
  }, []);
18937
- const error = useCallback7((err) => {
18979
+ const error = useCallback8((err) => {
18938
18980
  const message = err instanceof Error ? err.message : "An error occurred";
18939
18981
  show({ message, variant: "error", duration: 5e3 });
18940
18982
  }, [show]);
@@ -19013,7 +19055,7 @@ function AppInner() {
19013
19055
  const renderer = useRenderer();
19014
19056
  const { width } = useTerminalDimensions3();
19015
19057
  const toast = useToast();
19016
- const rendererRef = useRef5(renderer);
19058
+ const rendererRef = useRef6(renderer);
19017
19059
  rendererRef.current = renderer;
19018
19060
  if (!workspacePollingStarted) {
19019
19061
  workspacePollingStarted = true;
@@ -19022,7 +19064,7 @@ function AppInner() {
19022
19064
  rendererRef.current.requestRender();
19023
19065
  }, 3e4);
19024
19066
  }
19025
- useEffect3(() => {
19067
+ useEffect2(() => {
19026
19068
  const handler = (selection) => {
19027
19069
  const text = selection.getSelectedText();
19028
19070
  if (text) {
@@ -19035,15 +19077,15 @@ function AppInner() {
19035
19077
  renderer.off("selection", handler);
19036
19078
  };
19037
19079
  }, [renderer, toast]);
19038
- const [selectedWorkspaceId, setSelectedWorkspaceId] = useState8(null);
19039
- const [selectedChatId, setSelectedChatId] = useState8(null);
19040
- const [focusPanel, setFocusPanel] = useState8("sidebar");
19041
- const [taskMode, setTaskMode] = useState8("build");
19042
- const [mockMessages, setMockMessages] = useState8([]);
19043
- const [mockThinking, setMockThinking] = useState8(false);
19044
- const pendingMessageRef = useRef5(/* @__PURE__ */ new Map());
19045
- const [viewingDiff, setViewingDiff] = useState8(null);
19046
- const [lastViewedDiff, setLastViewedDiff] = useState8(null);
19080
+ const [selectedWorkspaceId, setSelectedWorkspaceId] = useState7(null);
19081
+ const [selectedChatId, setSelectedChatId] = useState7(null);
19082
+ const [focusPanel, setFocusPanel] = useState7("sidebar");
19083
+ const [taskMode, setTaskMode] = useState7("build");
19084
+ const [mockMessages, setMockMessages] = useState7([]);
19085
+ const [mockThinking, setMockThinking] = useState7(false);
19086
+ const pendingMessageRef = useRef6(/* @__PURE__ */ new Map());
19087
+ const [viewingDiff, setViewingDiff] = useState7(null);
19088
+ const [lastViewedDiff, setLastViewedDiff] = useState7(null);
19047
19089
  const { data: workspacesData, isLoading: loadingWorkspaces } = useWorkspaces(WORKSPACE_SIDEBAR_VIEWS);
19048
19090
  const { data: setsData } = useRepositorySets();
19049
19091
  const { data: envsData } = useEnvironments();
@@ -19059,7 +19101,7 @@ function AppInner() {
19059
19101
  );
19060
19102
  const { data: chatsData } = useWorkspaceChats(isMockSelected ? null : selectedWorkspaceId);
19061
19103
  const chats = isMockSelected ? MOCK_CHATS : chatsData?.chats ?? [];
19062
- const resolvedChatId = useMemo6(() => {
19104
+ const resolvedChatId = useMemo5(() => {
19063
19105
  if (selectedChatId && chats.find((c) => c.id === selectedChatId)) {
19064
19106
  return selectedChatId;
19065
19107
  }
@@ -19078,13 +19120,13 @@ function AppInner() {
19078
19120
  const archiveWorkspaceMutation = useArchiveWorkspace();
19079
19121
  const wakeWorkspaceMutation = useWakeWorkspace();
19080
19122
  const generateNameMutation = useGenerateWorkspaceName();
19081
- const [wakingWorkspaceId, setWakingWorkspaceId] = useState8(null);
19123
+ const [wakingWorkspaceId, setWakingWorkspaceId] = useState7(null);
19082
19124
  const sendMessageMutation = useSendChatMessage(selectedWorkspaceId, resolvedChatId);
19083
19125
  const interruptMutation = useInterruptChat(selectedWorkspaceId, resolvedChatId);
19084
19126
  const repositorySets = setsData?.repository_sets ?? [];
19085
19127
  const environments = envsData?.environments ?? [];
19086
19128
  const previews = previewsData?.previews ?? [];
19087
- const groups = useMemo6(
19129
+ const groups = useMemo5(
19088
19130
  () => buildGroups(workspaces, workspacesData, environments, repositorySets),
19089
19131
  [workspaces, workspacesData, environments, repositorySets]
19090
19132
  );
@@ -19094,7 +19136,7 @@ function AppInner() {
19094
19136
  const agentAvailable = agentAvailability ? selectedAgent === "codex" ? agentAvailability.codex.available : selectedAgent === "cursor" ? agentAvailability.cursor.available : selectedAgent === "relay" ? agentAvailability.relay.available : agentAvailability.claude.available : true;
19095
19137
  const agentLabel = getProviderDisplayName(selectedAgent, "long");
19096
19138
  const agentConnectHelp = getAgentConnectHelp(selectedAgent);
19097
- const displayMessages = useMemo6(() => {
19139
+ const displayMessages = useMemo5(() => {
19098
19140
  if (isMockSelected) return mockMessages;
19099
19141
  const rawEvents = historyData?.events ?? [];
19100
19142
  const events = rawEvents.filter(isAgentBackendEvent);
@@ -19103,7 +19145,7 @@ function AppInner() {
19103
19145
  }, [isMockSelected, mockMessages, historyData, selectedChat?.provider]);
19104
19146
  const showInfoPanel = width >= 100;
19105
19147
  const showWorkspacePanel = width >= 60;
19106
- const [prevIsMockSelected, setPrevIsMockSelected] = useState8(isMockSelected);
19148
+ const [prevIsMockSelected, setPrevIsMockSelected] = useState7(isMockSelected);
19107
19149
  if (prevIsMockSelected !== isMockSelected) {
19108
19150
  setPrevIsMockSelected(isMockSelected);
19109
19151
  if (prevIsMockSelected && !isMockSelected) {
@@ -19112,7 +19154,7 @@ function AppInner() {
19112
19154
  setMockThinking(false);
19113
19155
  }
19114
19156
  }
19115
- useEffect3(() => {
19157
+ useEffect2(() => {
19116
19158
  if (!selectedWorkspaceId || isMockSelected) return;
19117
19159
  if (!resolvedChatId || resolvedChatId.startsWith("mock-")) return;
19118
19160
  if (statusData?.status !== "active") return;
@@ -19126,7 +19168,7 @@ function AppInner() {
19126
19168
  }
19127
19169
  sendMessageMutation.mutate({ message: pending });
19128
19170
  }, [selectedWorkspaceId, resolvedChatId, isMockSelected, statusData?.status]);
19129
- const handleSelectWorkspace = useCallback8((workspaceId) => {
19171
+ const handleSelectWorkspace = useCallback9((workspaceId) => {
19130
19172
  setSelectedWorkspaceId(workspaceId);
19131
19173
  setSelectedChatId(null);
19132
19174
  setMockMessages([]);
@@ -19135,13 +19177,13 @@ function AppInner() {
19135
19177
  setLastViewedDiff(null);
19136
19178
  setFocusPanel("chat-input");
19137
19179
  }, []);
19138
- const handleFocus = useCallback8((panel) => {
19180
+ const handleFocus = useCallback9((panel) => {
19139
19181
  if (panel === "sidebar") {
19140
19182
  queryClient.invalidateQueries({ queryKey: ["workspaces"] });
19141
19183
  }
19142
19184
  setFocusPanel(panel);
19143
19185
  }, []);
19144
- const handleCreateWorkspace = useCallback8(
19186
+ const handleCreateWorkspace = useCallback9(
19145
19187
  async (group) => {
19146
19188
  if (group.id === "__ungrouped__") {
19147
19189
  toast.error("Cannot create a workspace in the Other / Ungrouped folder");
@@ -19159,7 +19201,7 @@ function AppInner() {
19159
19201
  },
19160
19202
  [createWorkspaceMutation, toast]
19161
19203
  );
19162
- const handleArchiveWorkspace = useCallback8(
19204
+ const handleArchiveWorkspace = useCallback9(
19163
19205
  async (workspaceId) => {
19164
19206
  try {
19165
19207
  await archiveWorkspaceMutation.mutateAsync(workspaceId);
@@ -19170,7 +19212,7 @@ function AppInner() {
19170
19212
  },
19171
19213
  [archiveWorkspaceMutation]
19172
19214
  );
19173
- const handleWakeWorkspace = useCallback8(
19215
+ const handleWakeWorkspace = useCallback9(
19174
19216
  async (workspaceId) => {
19175
19217
  setWakingWorkspaceId(workspaceId);
19176
19218
  try {
@@ -19184,7 +19226,7 @@ function AppInner() {
19184
19226
  },
19185
19227
  [wakeWorkspaceMutation, toast]
19186
19228
  );
19187
- const handleSelectChat = useCallback8((chatId) => {
19229
+ const handleSelectChat = useCallback9((chatId) => {
19188
19230
  setSelectedChatId(chatId);
19189
19231
  }, []);
19190
19232
  useKeyboard5((key) => {
@@ -19242,16 +19284,16 @@ function AppInner() {
19242
19284
  }
19243
19285
  if (focusPanel === "chat-input") return;
19244
19286
  });
19245
- const handleViewDiff = useCallback8((diff, repoName) => {
19287
+ const handleViewDiff = useCallback9((diff, repoName) => {
19246
19288
  setViewingDiff({ diff, repoName });
19247
19289
  setLastViewedDiff({ diff, repoName });
19248
19290
  setFocusPanel("chat-history");
19249
19291
  }, []);
19250
- const handleSelectChatMode = useCallback8(() => {
19292
+ const handleSelectChatMode = useCallback9(() => {
19251
19293
  setViewingDiff(null);
19252
19294
  setFocusPanel("chat-history");
19253
19295
  }, []);
19254
- const firstAvailableDiff = useMemo6(() => {
19296
+ const firstAvailableDiff = useMemo5(() => {
19255
19297
  if (lastViewedDiff) return lastViewedDiff;
19256
19298
  const repos2 = statusData?.repoStatuses ?? [];
19257
19299
  for (const repo of repos2) {
@@ -19261,14 +19303,14 @@ function AppInner() {
19261
19303
  }
19262
19304
  return null;
19263
19305
  }, [lastViewedDiff, statusData?.repoStatuses]);
19264
- const handleSelectDiffMode = useCallback8(() => {
19306
+ const handleSelectDiffMode = useCallback9(() => {
19265
19307
  if (firstAvailableDiff) {
19266
19308
  setViewingDiff(firstAvailableDiff);
19267
19309
  setLastViewedDiff(firstAvailableDiff);
19268
19310
  setFocusPanel("chat-history");
19269
19311
  }
19270
19312
  }, [firstAvailableDiff]);
19271
- const handleSendMessage = useCallback8(
19313
+ const handleSendMessage = useCallback9(
19272
19314
  async (message) => {
19273
19315
  if (!selectedWorkspaceId || !resolvedChatId) return;
19274
19316
  if (isMockSelected) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.340",
3
+ "version": "0.2.342",
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": {