replicas-cli 0.2.455 → 0.2.456

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 +411 -90
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7730,29 +7730,51 @@ function getClaudePartialMessageStreamId(event) {
7730
7730
  if (event.type !== CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE) return null;
7731
7731
  return typeof event.payload.streamId === "string" && event.payload.streamId ? event.payload.streamId : null;
7732
7732
  }
7733
- function getEventSignature(event) {
7734
- const streamId = getClaudePartialMessageStreamId(event);
7735
- if (streamId) {
7736
- return `${CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE}:${streamId}`;
7737
- }
7738
- const normalize = (input) => {
7739
- if (Array.isArray(input)) return input.map(normalize);
7740
- if (input && typeof input === "object") {
7741
- const entries = Object.entries(input).sort(([a], [b]) => a.localeCompare(b)).map(([key, val]) => [key, normalize(val)]);
7742
- return Object.fromEntries(entries);
7743
- }
7744
- return input;
7745
- };
7746
- try {
7747
- return JSON.stringify(normalize(event));
7748
- } catch {
7749
- return String(event);
7750
- }
7751
- }
7733
+ var ACCEPTED_USER_MESSAGE_SOURCE = "replicas-chat-turn-accepted";
7752
7734
  var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
7753
7735
  var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
7736
+ var CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE = "codex-asp-transcript-updated";
7754
7737
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
7755
7738
  var CHAT_INTERRUPTED_EVENT_TYPE = "replicas-interrupted";
7739
+ var CHAT_GOAL_EVENT_TYPE = "chat-goal";
7740
+ var CHAT_GOAL_STATUSES = [
7741
+ "active",
7742
+ "paused",
7743
+ "blocked",
7744
+ "usageLimited",
7745
+ "budgetLimited",
7746
+ "complete"
7747
+ ];
7748
+ function isChatGoalStatus(value) {
7749
+ return typeof value === "string" && CHAT_GOAL_STATUSES.some((status) => status === value);
7750
+ }
7751
+ function coerceChatGoalPayload(payload) {
7752
+ const goal = payload.goal;
7753
+ if (goal === null || goal === void 0) return null;
7754
+ if (typeof goal !== "object") return null;
7755
+ const candidate = goal;
7756
+ const threadId = candidate.threadId;
7757
+ const objective = candidate.objective;
7758
+ const status = candidate.status;
7759
+ const tokensUsed = candidate.tokensUsed;
7760
+ const timeUsedSeconds = candidate.timeUsedSeconds;
7761
+ const createdAt = candidate.createdAt;
7762
+ const updatedAt = candidate.updatedAt;
7763
+ const tokenBudget = candidate.tokenBudget ?? null;
7764
+ if (typeof threadId !== "string" || typeof objective !== "string" || !isChatGoalStatus(status) || typeof tokensUsed !== "number" || typeof timeUsedSeconds !== "number" || typeof createdAt !== "string" || typeof updatedAt !== "string" || tokenBudget !== null && typeof tokenBudget !== "number") {
7765
+ return null;
7766
+ }
7767
+ return {
7768
+ threadId,
7769
+ objective,
7770
+ status,
7771
+ tokenBudget,
7772
+ tokensUsed,
7773
+ timeUsedSeconds,
7774
+ createdAt,
7775
+ updatedAt
7776
+ };
7777
+ }
7756
7778
 
7757
7779
  // ../shared/src/credentials/types.ts
7758
7780
  var CREDENTIAL_SCOPE = {
@@ -10056,7 +10078,7 @@ function formatTurnElapsed(ms) {
10056
10078
  }
10057
10079
 
10058
10080
  // ../shared/src/cli-version.ts
10059
- var CLI_VERSION = "0.2.455";
10081
+ var CLI_VERSION = "0.2.456";
10060
10082
 
10061
10083
  // ../shared/src/version.ts
10062
10084
  function compareVersions(v1, v2) {
@@ -24651,6 +24673,90 @@ function normalizeCodexAspTranscriptStatus(status, failed = false) {
24651
24673
  if (status === "completed") return "completed";
24652
24674
  return "in_progress";
24653
24675
  }
24676
+ function isCodexAspTranscript(value) {
24677
+ if (!isRecord(value)) return false;
24678
+ return typeof value.threadId === "string" && typeof value.updatedAt === "string" && Array.isArray(value.turns);
24679
+ }
24680
+ function isCodexAspTranscriptDelta(value) {
24681
+ if (!isRecord(value)) return false;
24682
+ if (typeof value.threadId !== "string" || typeof value.updatedAt !== "string" || !Array.isArray(value.turns) || value.reset !== void 0 && value.reset !== null && !isCodexAspTranscript(value.reset)) {
24683
+ return false;
24684
+ }
24685
+ return value.turns.every((turn) => isRecord(turn) && typeof turn.id === "string" && typeof turn.status === "string" && typeof turn.startedAt === "string" && (turn.completedAt === null || typeof turn.completedAt === "string") && Array.isArray(turn.items) && turn.items.every((item) => isRecord(item) && typeof item.id === "string" && (item.item === void 0 || isRecord(item.item) && typeof item.item.type === "string" && typeof item.item.id === "string" && typeof item.item.timestamp === "string") && (item.appendText === void 0 || typeof item.appendText === "string") && (item.appendOutput === void 0 || typeof item.appendOutput === "string")));
24686
+ }
24687
+ function appendCodexAspTranscriptField(current, append) {
24688
+ return append === void 0 ? current : `${current ?? ""}${append}`;
24689
+ }
24690
+ function patchCodexAspTranscriptItem(current, delta) {
24691
+ const base = delta.item ?? current;
24692
+ if (!base) {
24693
+ return null;
24694
+ }
24695
+ if (base.type === "agentMessage" && delta.appendText !== void 0) {
24696
+ return {
24697
+ ...base,
24698
+ text: appendCodexAspTranscriptField(base.text, delta.appendText) ?? ""
24699
+ };
24700
+ }
24701
+ if ((base.type === "commandExecution" || base.type === "fileChange") && delta.appendOutput !== void 0) {
24702
+ return {
24703
+ ...base,
24704
+ output: appendCodexAspTranscriptField(base.output, delta.appendOutput)
24705
+ };
24706
+ }
24707
+ return base;
24708
+ }
24709
+ function applyCodexAspTranscriptDelta(current, delta) {
24710
+ if (!delta) return current ?? null;
24711
+ if (delta.reset === null) {
24712
+ return null;
24713
+ }
24714
+ const base = delta.reset ?? (current?.threadId === delta.threadId ? current : {
24715
+ threadId: delta.threadId,
24716
+ updatedAt: delta.updatedAt,
24717
+ turns: []
24718
+ });
24719
+ const turns = base.turns.map((turn) => ({
24720
+ ...turn,
24721
+ items: [...turn.items]
24722
+ }));
24723
+ for (const turnDelta of delta.turns) {
24724
+ let turn = turns.find((candidate) => candidate.id === turnDelta.id);
24725
+ if (!turn) {
24726
+ turn = {
24727
+ id: turnDelta.id,
24728
+ status: turnDelta.status,
24729
+ startedAt: turnDelta.startedAt,
24730
+ completedAt: turnDelta.completedAt,
24731
+ items: []
24732
+ };
24733
+ turns.push(turn);
24734
+ } else {
24735
+ turn.status = turnDelta.status;
24736
+ turn.startedAt = turnDelta.startedAt;
24737
+ turn.completedAt = turnDelta.completedAt;
24738
+ }
24739
+ for (const itemDelta of turnDelta.items) {
24740
+ const itemIndex = turn.items.findIndex((item) => item.id === itemDelta.id);
24741
+ const patched = patchCodexAspTranscriptItem(turn.items[itemIndex], itemDelta);
24742
+ if (!patched) continue;
24743
+ if (itemIndex === -1) {
24744
+ turn.items.push(patched);
24745
+ } else {
24746
+ turn.items[itemIndex] = patched;
24747
+ }
24748
+ }
24749
+ }
24750
+ turns.sort((a, b) => Date.parse(a.startedAt) - Date.parse(b.startedAt));
24751
+ for (const turn of turns) {
24752
+ turn.items.sort((a, b) => (a.sequence ?? Number.MAX_SAFE_INTEGER) - (b.sequence ?? Number.MAX_SAFE_INTEGER) || Date.parse(a.timestamp) - Date.parse(b.timestamp));
24753
+ }
24754
+ return {
24755
+ threadId: delta.threadId,
24756
+ updatedAt: delta.updatedAt,
24757
+ turns
24758
+ };
24759
+ }
24654
24760
 
24655
24761
  // ../shared/src/routes/workspaces.ts
24656
24762
  var WORKSPACE_STATUSES = ["active", "sleeping", "archived", "preparing", "error"];
@@ -24997,6 +25103,49 @@ function areUserMessagesWithinMatchWindow(a, b) {
24997
25103
  return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
24998
25104
  }
24999
25105
 
25106
+ // ../shared/src/agent-event-utils.ts
25107
+ function getUserMessage(event) {
25108
+ return event.type === "event_msg" && event.payload.type === "user_message" && typeof event.payload.message === "string" ? event.payload.message : null;
25109
+ }
25110
+ function getUserMessageId(event) {
25111
+ const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
25112
+ return typeof messageId === "string" ? messageId : null;
25113
+ }
25114
+ function getUserMessageItemId(event) {
25115
+ const itemId = event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY];
25116
+ return typeof itemId === "string" ? itemId : null;
25117
+ }
25118
+ function areSameUserMessageEvents(a, b) {
25119
+ const aMessage = getUserMessage(a);
25120
+ const bMessage = getUserMessage(b);
25121
+ if (!aMessage || aMessage !== bMessage) return false;
25122
+ const aMessageId = getUserMessageId(a);
25123
+ const bMessageId = getUserMessageId(b);
25124
+ if (aMessageId || bMessageId) return aMessageId === bMessageId;
25125
+ const aItemId = getUserMessageItemId(a);
25126
+ const bItemId = getUserMessageItemId(b);
25127
+ if (aItemId || bItemId) return aItemId === bItemId;
25128
+ return areUserMessagesWithinMatchWindow(
25129
+ { content: aMessage, timestamp: a.timestamp },
25130
+ { content: bMessage, timestamp: b.timestamp }
25131
+ );
25132
+ }
25133
+ function mergeAgentEvents(primary, supplemental, options) {
25134
+ const merged = [...primary];
25135
+ const { areDuplicates, mergeEvent } = options;
25136
+ for (const event of supplemental) {
25137
+ const existingIndex = merged.findIndex((existing) => areDuplicates(existing, event));
25138
+ if (existingIndex === -1) {
25139
+ merged.push(event);
25140
+ continue;
25141
+ }
25142
+ if (mergeEvent) {
25143
+ merged[existingIndex] = mergeEvent(merged[existingIndex], event);
25144
+ }
25145
+ }
25146
+ return merged;
25147
+ }
25148
+
25000
25149
  // ../shared/src/display-message/parsers/codex-parser.ts
25001
25150
  function getStatusFromExitCode(exitCode) {
25002
25151
  return exitCode === 0 ? "completed" : "failed";
@@ -33766,7 +33915,31 @@ function useGenerateWorkspaceName() {
33766
33915
  // ../shared/src/hooks/useWorkspaceEngine.ts
33767
33916
  import { useCallback as useCallback4 } from "react";
33768
33917
  import { useQuery as useQuery2, useMutation as useMutation2 } from "@tanstack/react-query";
33769
- function upsertChat(chats, chat) {
33918
+
33919
+ // ../shared/src/workspace-chat.ts
33920
+ import { queryOptions } from "@tanstack/react-query";
33921
+ var workspaceChatKeys = {
33922
+ chats: (workspaceId) => ["workspace-chats", workspaceId],
33923
+ allChats: (workspaceId) => ["workspace-all-chats", workspaceId],
33924
+ histories: (workspaceId) => ["chat-history", workspaceId],
33925
+ history: (workspaceId, chatId) => ["chat-history", workspaceId, chatId],
33926
+ queues: (workspaceId) => ["chat-queue", workspaceId],
33927
+ queue: (workspaceId, chatId) => ["chat-queue", workspaceId, chatId]
33928
+ };
33929
+ function workspaceChatsQueryOptions({
33930
+ workspaceId,
33931
+ fetchChats,
33932
+ enabled = true,
33933
+ staleTime = 6e4
33934
+ }) {
33935
+ return queryOptions({
33936
+ queryKey: workspaceChatKeys.chats(workspaceId),
33937
+ queryFn: fetchChats,
33938
+ enabled: Boolean(workspaceId) && enabled,
33939
+ staleTime
33940
+ });
33941
+ }
33942
+ function upsertWorkspaceChat(chats, chat) {
33770
33943
  const existingIndex = chats.findIndex((item) => item.id === chat.id);
33771
33944
  if (existingIndex === -1) {
33772
33945
  return [chat, ...chats].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
@@ -33775,7 +33948,7 @@ function upsertChat(chats, chat) {
33775
33948
  next[existingIndex] = chat;
33776
33949
  return next.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
33777
33950
  }
33778
- function patchChat(chats, chatId, patch) {
33951
+ function patchWorkspaceChat(chats, chatId, patch) {
33779
33952
  let changed = false;
33780
33953
  const next = chats.map((chat) => {
33781
33954
  if (chat.id !== chatId) return chat;
@@ -33784,21 +33957,229 @@ function patchChat(chats, chatId, patch) {
33784
33957
  });
33785
33958
  return changed ? next.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)) : chats;
33786
33959
  }
33960
+ function isAcceptedUserMessage(event) {
33961
+ return getUserMessage(event) !== null && event.payload.source === ACCEPTED_USER_MESSAGE_SOURCE;
33962
+ }
33963
+ function areDuplicateUserMessages(a, b) {
33964
+ if (areSameUserMessageEvents(a, b)) return true;
33965
+ const aMessage = getUserMessage(a);
33966
+ const bMessage = getUserMessage(b);
33967
+ if (!aMessage || aMessage !== bMessage) return false;
33968
+ const aAccepted = isAcceptedUserMessage(a);
33969
+ const bAccepted = isAcceptedUserMessage(b);
33970
+ return aAccepted !== bAccepted ? areUserMessagesWithinMatchWindow(
33971
+ { content: aMessage, timestamp: a.timestamp },
33972
+ { content: bMessage, timestamp: b.timestamp }
33973
+ ) : false;
33974
+ }
33975
+ function areDuplicateWorkspaceChatEvents(a, b) {
33976
+ const aPartialStreamId = getClaudePartialMessageStreamId(a);
33977
+ const bPartialStreamId = getClaudePartialMessageStreamId(b);
33978
+ return aPartialStreamId !== null && aPartialStreamId === bPartialStreamId || JSON.stringify(a) === JSON.stringify(b) || areDuplicateUserMessages(a, b);
33979
+ }
33980
+ function mergeWorkspaceChatHistoryEvents(primary, supplemental) {
33981
+ return mergeAgentEvents(primary, supplemental, {
33982
+ areDuplicates: areDuplicateWorkspaceChatEvents,
33983
+ mergeEvent: (current, candidate) => getClaudePartialMessageStreamId(candidate) !== null ? candidate : current
33984
+ });
33985
+ }
33986
+ function isSameChatSender(a, b) {
33987
+ return a.senderUserId === b.senderUserId && a.recordedAt === b.recordedAt;
33988
+ }
33989
+ function codexAspTranscriptUpdateFromEvent(event) {
33990
+ if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) return null;
33991
+ const { payload } = event;
33992
+ const updatedAt = payload.updatedAt;
33993
+ const transcript = payload.transcript;
33994
+ const transcriptDelta = payload.transcriptDelta;
33995
+ if (typeof updatedAt !== "string" || transcript !== null && !isCodexAspTranscript(transcript) || transcriptDelta !== void 0 && !isCodexAspTranscriptDelta(transcriptDelta)) {
33996
+ return null;
33997
+ }
33998
+ const threadId = typeof payload.threadId === "string" ? payload.threadId : void 0;
33999
+ return {
34000
+ updatedAt,
34001
+ transcript,
34002
+ ...transcriptDelta ? { transcriptDelta } : {},
34003
+ ...threadId ? { threadId } : {}
34004
+ };
34005
+ }
34006
+ function patchCachedChats(queryClient2, workspaceId, chatId, patch) {
34007
+ for (const queryKey of [
34008
+ workspaceChatKeys.chats(workspaceId),
34009
+ workspaceChatKeys.allChats(workspaceId)
34010
+ ]) {
34011
+ queryClient2.setQueryData(
34012
+ queryKey,
34013
+ (current) => current ? {
34014
+ ...current,
34015
+ chats: patchWorkspaceChat(current.chats, chatId, patch)
34016
+ } : current
34017
+ );
34018
+ }
34019
+ }
34020
+ function applyWorkspaceChatEvent(queryClient2, workspaceId, event, options = {}) {
34021
+ if (event.type === "chat.created" || event.type === "chat.updated") {
34022
+ const { chat } = event.payload;
34023
+ queryClient2.setQueryData(
34024
+ workspaceChatKeys.allChats(workspaceId),
34025
+ (current) => current ? { ...current, chats: upsertWorkspaceChat(current.chats, chat) } : current
34026
+ );
34027
+ if (chat.parentChatId === null && !options.skipRootChatUpsert) {
34028
+ queryClient2.setQueryData(
34029
+ workspaceChatKeys.chats(workspaceId),
34030
+ (current) => ({
34031
+ ...current ?? {},
34032
+ chats: upsertWorkspaceChat(current?.chats ?? [], chat),
34033
+ deletedChats: (current?.deletedChats ?? []).filter((item) => item.id !== chat.id)
34034
+ })
34035
+ );
34036
+ }
34037
+ return "chat-list-changed";
34038
+ }
34039
+ if (event.type === "chat.deleted") {
34040
+ queryClient2.setQueryData(workspaceChatKeys.chats(workspaceId), (current) => {
34041
+ if (!current) return current;
34042
+ const deletedChat = event.payload.chat;
34043
+ return {
34044
+ ...current,
34045
+ chats: current.chats.filter((chat) => chat.id !== event.payload.chatId),
34046
+ deletedChats: deletedChat?.deletedAt ? [
34047
+ deletedChat,
34048
+ ...(current.deletedChats ?? []).filter((chat) => chat.id !== deletedChat.id)
34049
+ ] : (current.deletedChats ?? []).filter((chat) => chat.id !== event.payload.chatId)
34050
+ };
34051
+ });
34052
+ queryClient2.setQueryData(
34053
+ workspaceChatKeys.allChats(workspaceId),
34054
+ (current) => current ? {
34055
+ ...current,
34056
+ chats: current.chats.filter((chat) => chat.id !== event.payload.chatId)
34057
+ } : current
34058
+ );
34059
+ queryClient2.removeQueries({
34060
+ queryKey: workspaceChatKeys.history(workspaceId, event.payload.chatId)
34061
+ });
34062
+ return "chat-list-changed";
34063
+ }
34064
+ if (event.type === "chat.turn.accepted") {
34065
+ if (event.payload.queued) {
34066
+ queryClient2.invalidateQueries({
34067
+ queryKey: workspaceChatKeys.queue(workspaceId, event.payload.chatId)
34068
+ });
34069
+ return "queue-changed";
34070
+ }
34071
+ const sender = event.payload.sender;
34072
+ const acceptedEvent = event.payload.event;
34073
+ if (sender || acceptedEvent) {
34074
+ queryClient2.setQueryData(
34075
+ workspaceChatKeys.history(workspaceId, event.payload.chatId),
34076
+ (current) => ({
34077
+ ...current ?? { thread_id: null },
34078
+ events: acceptedEvent ? mergeWorkspaceChatHistoryEvents(current?.events ?? [], [acceptedEvent]) : current?.events ?? [],
34079
+ senders: sender ? [
34080
+ ...(current?.senders ?? []).filter(
34081
+ (candidate) => !isSameChatSender(candidate, sender)
34082
+ ),
34083
+ sender
34084
+ ] : current?.senders
34085
+ })
34086
+ );
34087
+ }
34088
+ patchCachedChats(queryClient2, workspaceId, event.payload.chatId, {
34089
+ processing: true,
34090
+ awaitingInput: false,
34091
+ updatedAt: event.ts
34092
+ });
34093
+ return "chat-list-changed";
34094
+ }
34095
+ if (event.type === "chat.turn.started") {
34096
+ queryClient2.setQueryData(
34097
+ workspaceChatKeys.queue(workspaceId, event.payload.chatId),
34098
+ (current) => current ? {
34099
+ ...current,
34100
+ queue: current.queue.filter((message) => message.id !== event.payload.messageId)
34101
+ } : current
34102
+ );
34103
+ queryClient2.invalidateQueries({
34104
+ queryKey: workspaceChatKeys.queue(workspaceId, event.payload.chatId)
34105
+ });
34106
+ patchCachedChats(queryClient2, workspaceId, event.payload.chatId, {
34107
+ processing: true,
34108
+ awaitingInput: false,
34109
+ updatedAt: event.ts
34110
+ });
34111
+ const history = queryClient2.getQueryData(
34112
+ workspaceChatKeys.history(workspaceId, event.payload.chatId)
34113
+ );
34114
+ if (!history?.events.some((candidate) => getUserMessageId(candidate) === event.payload.messageId)) {
34115
+ queryClient2.invalidateQueries({
34116
+ queryKey: workspaceChatKeys.history(workspaceId, event.payload.chatId)
34117
+ });
34118
+ }
34119
+ return "chat-list-changed";
34120
+ }
34121
+ if (event.type === "chat.turn.delta") {
34122
+ const historyKey = workspaceChatKeys.history(workspaceId, event.payload.chatId);
34123
+ const transcriptUpdate = codexAspTranscriptUpdateFromEvent(event.payload.event);
34124
+ if (transcriptUpdate) {
34125
+ queryClient2.setQueryData(historyKey, (current) => {
34126
+ const transcript = transcriptUpdate.transcriptDelta ? applyCodexAspTranscriptDelta(
34127
+ current?.codexAspTranscript ?? transcriptUpdate.transcript ?? null,
34128
+ transcriptUpdate.transcriptDelta
34129
+ ) : transcriptUpdate.transcript ?? current?.codexAspTranscript ?? null;
34130
+ return {
34131
+ ...current ?? { events: [] },
34132
+ thread_id: current?.thread_id ?? transcript?.threadId ?? transcriptUpdate.threadId ?? null,
34133
+ codexAspTranscript: transcript
34134
+ };
34135
+ });
34136
+ return "turn-delta";
34137
+ }
34138
+ queryClient2.setQueryData(historyKey, (current) => ({
34139
+ ...current ?? { thread_id: null },
34140
+ events: mergeWorkspaceChatHistoryEvents(current?.events ?? [], [event.payload.event]),
34141
+ goal: event.payload.event.type === CHAT_GOAL_EVENT_TYPE ? coerceChatGoalPayload(event.payload.event.payload) : current?.goal
34142
+ }));
34143
+ return "turn-delta";
34144
+ }
34145
+ if (event.type === "chat.turn.completed" || event.type === "chat.interrupted") {
34146
+ patchCachedChats(queryClient2, workspaceId, event.payload.chatId, {
34147
+ processing: getTerminalChatProcessing(event),
34148
+ awaitingInput: false,
34149
+ isAuthRetrying: false,
34150
+ updatedAt: event.ts
34151
+ });
34152
+ queryClient2.invalidateQueries({
34153
+ queryKey: workspaceChatKeys.history(workspaceId, event.payload.chatId)
34154
+ });
34155
+ queryClient2.invalidateQueries({
34156
+ queryKey: workspaceChatKeys.queue(workspaceId, event.payload.chatId)
34157
+ });
34158
+ queryClient2.invalidateQueries({
34159
+ queryKey: workspaceChatKeys.allChats(workspaceId)
34160
+ });
34161
+ return "turn-completed";
34162
+ }
34163
+ return null;
34164
+ }
34165
+
34166
+ // ../shared/src/hooks/useWorkspaceEngine.ts
33787
34167
  function useWorkspaceChats(workspaceId) {
33788
34168
  const auth = useReplicasAuth();
33789
34169
  const orgFetch = useOrgFetch();
33790
- return useQuery2({
33791
- queryKey: ["workspace-chats", workspaceId],
33792
- queryFn: () => orgFetch(`/v1/workspaces/${workspaceId}/chats`),
33793
- enabled: !!workspaceId,
33794
- staleTime: 6e4
33795
- }, auth.queryClient);
34170
+ return useQuery2(
34171
+ workspaceChatsQueryOptions({
34172
+ workspaceId,
34173
+ fetchChats: () => orgFetch(`/v1/workspaces/${workspaceId}/chats`)
34174
+ }),
34175
+ auth.queryClient
34176
+ );
33796
34177
  }
33797
34178
  function useChatHistory(workspaceId, chatId) {
33798
34179
  const auth = useReplicasAuth();
33799
34180
  const orgFetch = useOrgFetch();
33800
34181
  return useQuery2({
33801
- queryKey: ["chat-history", workspaceId, chatId],
34182
+ queryKey: workspaceChatKeys.history(workspaceId, chatId),
33802
34183
  queryFn: () => orgFetch(`/v1/workspaces/${workspaceId}/chats/${chatId}/history`),
33803
34184
  enabled: !!workspaceId && !!chatId
33804
34185
  }, auth.queryClient);
@@ -33875,67 +34256,7 @@ function useWorkspaceEvents(workspaceId, enabled = true) {
33875
34256
  const qc = auth.queryClient;
33876
34257
  const handleEvent = useCallback4((event) => {
33877
34258
  if (!workspaceId) return;
33878
- const chatsKey = ["workspace-chats", workspaceId];
33879
- if (event.type === "chat.created" || event.type === "chat.updated") {
33880
- if (event.payload.chat.parentChatId === null) {
33881
- qc.setQueryData(chatsKey, (current) => {
33882
- if (!current) return { chats: [event.payload.chat] };
33883
- return { chats: upsertChat(current.chats, event.payload.chat) };
33884
- });
33885
- }
33886
- return;
33887
- }
33888
- if (event.type === "chat.deleted") {
33889
- qc.setQueryData(chatsKey, (current) => {
33890
- if (!current) return current;
33891
- return { chats: current.chats.filter((chat) => chat.id !== event.payload.chatId) };
33892
- });
33893
- qc.removeQueries({ queryKey: ["chat-history", workspaceId, event.payload.chatId] });
33894
- return;
33895
- }
33896
- if (event.type === "chat.turn.accepted") {
33897
- if (!event.payload.queued) {
33898
- qc.setQueryData(chatsKey, (current) => {
33899
- if (!current) return current;
33900
- return { chats: patchChat(current.chats, event.payload.chatId, { processing: true, updatedAt: event.ts }) };
33901
- });
33902
- }
33903
- return;
33904
- }
33905
- if (event.type === "chat.turn.started") {
33906
- qc.setQueryData(chatsKey, (current) => {
33907
- if (!current) return current;
33908
- return { chats: patchChat(current.chats, event.payload.chatId, { processing: true, updatedAt: event.ts }) };
33909
- });
33910
- return;
33911
- }
33912
- if (event.type === "chat.turn.completed" || event.type === "chat.interrupted") {
33913
- qc.setQueryData(chatsKey, (current) => {
33914
- if (!current) return current;
33915
- return { chats: patchChat(current.chats, event.payload.chatId, { processing: getTerminalChatProcessing(event), updatedAt: event.ts }) };
33916
- });
33917
- qc.invalidateQueries({ queryKey: ["chat-history", workspaceId, event.payload.chatId] });
33918
- return;
33919
- }
33920
- if (event.type === "chat.turn.delta") {
33921
- qc.setQueryData(
33922
- ["chat-history", workspaceId, event.payload.chatId],
33923
- (current) => {
33924
- const incomingSignature = getEventSignature(event.payload.event);
33925
- if (!current) {
33926
- return { thread_id: null, events: [event.payload.event] };
33927
- }
33928
- const existingIndex = current.events.findIndex((e) => getEventSignature(e) === incomingSignature);
33929
- if (existingIndex !== -1) {
33930
- const events = current.events.slice();
33931
- events[existingIndex] = event.payload.event;
33932
- return { ...current, events };
33933
- }
33934
- return { ...current, events: [...current.events, event.payload.event] };
33935
- }
33936
- );
33937
- return;
33938
- }
34259
+ if (applyWorkspaceChatEvent(qc, workspaceId, event)) return;
33939
34260
  if (event.type === "repo.status.changed") {
33940
34261
  qc.setQueryData(["workspace-status", workspaceId, false], (current) => {
33941
34262
  if (!current) return current;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.455",
3
+ "version": "0.2.456",
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": {