@guildai/cli 0.12.0 → 0.12.1

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 (31) hide show
  1. package/dist/{auth-CRMO5O3N.js → auth-67G3BIAW.js} +2 -2
  2. package/dist/{chat-5VX2WJH2.js → chat-ALOJ22JR.js} +7 -7
  3. package/dist/{chat-SIKDYZQK.js → chat-SG2I727J.js} +8 -6
  4. package/dist/{chunk-IBRKVGMZ.js → chunk-7JJT3RNI.js} +607 -376
  5. package/dist/{chunk-IBRKVGMZ.js.map → chunk-7JJT3RNI.js.map} +4 -4
  6. package/dist/{chunk-B7VAF5UG.js → chunk-EQUW4M5A.js} +3 -3
  7. package/dist/{chunk-SPZPZXUN.js → chunk-F3F5CUO3.js} +18 -3
  8. package/dist/chunk-F3F5CUO3.js.map +7 -0
  9. package/dist/{chunk-LFMQJOKC.js → chunk-JQRJ4A4S.js} +2 -2
  10. package/dist/{chunk-RIG2HZWM.js → chunk-RJHD6XTV.js} +2 -2
  11. package/dist/{chunk-DOIYVBNY.js → chunk-YQWI6SUV.js} +2 -2
  12. package/dist/commands/chat.d.ts +21 -0
  13. package/dist/index.js +8 -8
  14. package/dist/lib/display-message.d.ts +11 -0
  15. package/dist/lib/markdown.d.ts +2 -9
  16. package/dist/lib/response-stream-display-state.d.ts +51 -0
  17. package/dist/lib/session-events.d.ts +4 -0
  18. package/dist/lib/session-resume.d.ts +2 -6
  19. package/dist/{server-JYVH64FD.js → server-CKXFV2JC.js} +4 -4
  20. package/dist/{test-SNIYRJ32.js → test-VEA4ENOR.js} +7 -7
  21. package/package.json +1 -1
  22. package/dist/chunk-SPZPZXUN.js.map +0 -7
  23. /package/dist/{auth-CRMO5O3N.js.map → auth-67G3BIAW.js.map} +0 -0
  24. /package/dist/{chat-5VX2WJH2.js.map → chat-ALOJ22JR.js.map} +0 -0
  25. /package/dist/{chat-SIKDYZQK.js.map → chat-SG2I727J.js.map} +0 -0
  26. /package/dist/{chunk-B7VAF5UG.js.map → chunk-EQUW4M5A.js.map} +0 -0
  27. /package/dist/{chunk-LFMQJOKC.js.map → chunk-JQRJ4A4S.js.map} +0 -0
  28. /package/dist/{chunk-RIG2HZWM.js.map → chunk-RJHD6XTV.js.map} +0 -0
  29. /package/dist/{chunk-DOIYVBNY.js.map → chunk-YQWI6SUV.js.map} +0 -0
  30. /package/dist/{server-JYVH64FD.js.map → server-CKXFV2JC.js.map} +0 -0
  31. /package/dist/{test-SNIYRJ32.js.map → test-VEA4ENOR.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  Option,
5
5
  getOutputMode,
6
6
  isQuietMode
7
- } from "./chunk-DOIYVBNY.js";
7
+ } from "./chunk-YQWI6SUV.js";
8
8
  import {
9
9
  open_default
10
10
  } from "./chunk-56YCMGL3.js";
@@ -14,6 +14,7 @@ import {
14
14
  fetchTasks,
15
15
  getAgentName,
16
16
  getAgentNotificationText,
17
+ getEventAgentName,
17
18
  getTaskDisplayName,
18
19
  isDoneResponseStreamEvent,
19
20
  isFilteredTaskName,
@@ -21,7 +22,7 @@ import {
21
22
  isRootTaskEvent,
22
23
  isUnfulfilledAgentInstallRequest,
23
24
  pollForOnce
24
- } from "./chunk-SPZPZXUN.js";
25
+ } from "./chunk-F3F5CUO3.js";
25
26
  import {
26
27
  DEFAULT_EVENT_TYPES,
27
28
  GuildAPIClient,
@@ -29,7 +30,7 @@ import {
29
30
  getWorkspaceSourceLabel,
30
31
  parseEventFilter,
31
32
  shouldShowEvent
32
- } from "./chunk-RIG2HZWM.js";
33
+ } from "./chunk-RJHD6XTV.js";
33
34
  import {
34
35
  BRAND_COLOR,
35
36
  ErrorCodes,
@@ -54,7 +55,7 @@ import {
54
55
  source_default,
55
56
  stringWidth,
56
57
  stripAnsi
57
- } from "./chunk-LFMQJOKC.js";
58
+ } from "./chunk-JQRJ4A4S.js";
58
59
  import {
59
60
  require_ansi_styles,
60
61
  require_is_fullwidth_code_point
@@ -87752,18 +87753,28 @@ function sanitizeTab(tab2, fallbackTab) {
87752
87753
  }
87753
87754
  }
87754
87755
 
87755
- // src/lib/session-resume.ts
87756
+ // src/lib/markdown.ts
87756
87757
  marked.use(markedTerminal({}, { theme: {} }));
87757
- function renderMarkdown(text) {
87758
- let rendered = marked.parse(text);
87759
- rendered = rendered.replace(/\*\*([^*]+)\*\*/g, (_, content) => source_default.bold(content));
87760
- rendered = rendered.replace(/`([^`]+)`/g, (_, content) => code(content));
87761
- rendered = rendered.replace(
87758
+ function fixListItemMarkdown(text) {
87759
+ text = text.replace(/\*\*([^*]+)\*\*/g, (_, content) => source_default.bold(content));
87760
+ text = text.replace(/`([^`]+)`/g, (_, content) => code(content));
87761
+ text = text.replace(
87762
87762
  /(?<![\\w])_([^_]+)_(?![\\w])/g,
87763
87763
  (_, content) => source_default.italic(content)
87764
87764
  );
87765
- return rendered;
87765
+ return text;
87766
+ }
87767
+ function renderMarkdownSync(content) {
87768
+ const rendered = marked.parse(content);
87769
+ return fixListItemMarkdown(rendered);
87770
+ }
87771
+ function renderAssistantMessageContent(text, taskName) {
87772
+ const rendered = renderMarkdownSync(text);
87773
+ return `${source_default.green("\u25CF")} ${source_default.bold(taskName)}
87774
+ ${rendered.trim().split("\n").join("\n ")}`;
87766
87775
  }
87776
+
87777
+ // src/lib/session-resume.ts
87767
87778
  function printResumeHint(sessionId, command) {
87768
87779
  console.error("");
87769
87780
  console.error(source_default.dim("[Session interrupted]"));
@@ -87777,19 +87788,22 @@ async function fetchSession(client, sessionId) {
87777
87788
  const session = await client.get(`/sessions/${sessionId}`);
87778
87789
  return session;
87779
87790
  }
87780
- function renderAssistantText(key, text, timestamp) {
87781
- const rendered = renderMarkdown(text);
87782
- const messageContent = `${source_default.green("\u25CF")} ${source_default.bold("assistant")}
87783
- ${rendered.trim()}`;
87791
+ function renderAssistantText(key, text, timestamp, taskName) {
87784
87792
  return {
87785
87793
  key,
87786
- content: messageContent,
87794
+ content: renderAssistantMessageContent(text, taskName),
87787
87795
  type: "assistant",
87788
87796
  timestamp
87789
87797
  };
87790
87798
  }
87791
87799
  function textMatches(left, right) {
87792
- return left === right;
87800
+ return left.trim() === right.trim();
87801
+ }
87802
+ function isTerminalTaskStatus(status) {
87803
+ return status === "DONE" || status === "ERROR" || status === "INTERRUPTED";
87804
+ }
87805
+ function shouldTrackResumeEntry(entry) {
87806
+ return !isTerminalTaskStatus(entry.taskStatus);
87793
87807
  }
87794
87808
  function formatDisplayTimestamp(timestamp) {
87795
87809
  if (timestamp === void 0) return void 0;
@@ -87857,7 +87871,9 @@ function collectResponseStreamResumeEntries(events) {
87857
87871
  text,
87858
87872
  status: latest.content.status,
87859
87873
  timestamp: formatDisplayTimestamp(latest.created_at),
87860
- taskId
87874
+ taskId,
87875
+ taskName: getEventAgentName(latest),
87876
+ taskStatus: latest.task?.status
87861
87877
  });
87862
87878
  }
87863
87879
  }
@@ -87873,6 +87889,7 @@ function responseStreamResumeStateFromEntries(entries) {
87873
87889
  keysByTask: /* @__PURE__ */ new Map()
87874
87890
  };
87875
87891
  for (const entry of entries) {
87892
+ if (!shouldTrackResumeEntry(entry)) continue;
87876
87893
  state.keys.set(entry.streamId, entry.key);
87877
87894
  state.contents.set(entry.streamId, entry.contents);
87878
87895
  state.texts.set(entry.streamId, entry.text);
@@ -87911,21 +87928,34 @@ function eventsToDisplayMessagesWithResponseStreamEntries(events, responseStream
87911
87928
  if (!streamEntry) continue;
87912
87929
  renderedResponseStreamIds.add(streamId);
87913
87930
  messages.push(
87914
- renderAssistantText(streamEntry.key, streamEntry.text, streamEntry.timestamp)
87931
+ renderAssistantText(
87932
+ streamEntry.key,
87933
+ streamEntry.text,
87934
+ streamEntry.timestamp,
87935
+ streamEntry.taskName
87936
+ )
87915
87937
  );
87916
87938
  continue;
87917
87939
  }
87918
87940
  const text = getAgentNotificationText(event);
87919
87941
  if (text.trim()) {
87920
- messages.push(renderAssistantText(event.id, text, event.created_at));
87942
+ messages.push(
87943
+ renderAssistantText(
87944
+ event.id,
87945
+ text,
87946
+ event.created_at,
87947
+ getEventAgentName(event)
87948
+ )
87949
+ );
87921
87950
  }
87922
87951
  } else if (event.type === "agent_notification_error") {
87923
87952
  const text = typeof event.content === "string" ? event.content : event.content?.data || "";
87924
87953
  if (text.trim()) {
87954
+ const taskName = getEventAgentName(event);
87925
87955
  messages.push({
87926
87956
  key: event.id,
87927
- content: `${source_default.red("\u25CF")} ${source_default.bold("assistant")}
87928
- ${source_default.red(text)}`,
87957
+ content: `${source_default.red("\u25CF")} ${source_default.bold(taskName)}
87958
+ ${source_default.red(text)}`,
87929
87959
  type: "assistant",
87930
87960
  timestamp: event.created_at
87931
87961
  });
@@ -87945,6 +87975,165 @@ function prepareSessionResumeDisplay(events) {
87945
87975
  };
87946
87976
  }
87947
87977
 
87978
+ // src/lib/response-stream-display-state.ts
87979
+ function deleteTrackedResponseStream(state, streamId) {
87980
+ state.keys.delete(streamId);
87981
+ state.contents.delete(streamId);
87982
+ state.texts.delete(streamId);
87983
+ state.timestamps.delete(streamId);
87984
+ state.statuses.delete(streamId);
87985
+ }
87986
+ function updateTaskKeys(state, taskId, inactiveKeys) {
87987
+ const keys = state.keysByTask.get(taskId);
87988
+ if (!keys?.size) return;
87989
+ const remainingKeys = new Set([...keys].filter((key) => !inactiveKeys.has(key)));
87990
+ if (remainingKeys.size > 0) {
87991
+ state.keysByTask.set(taskId, remainingKeys);
87992
+ } else {
87993
+ state.keysByTask.delete(taskId);
87994
+ }
87995
+ }
87996
+ function textMatchesForDisplay(left, right) {
87997
+ if (left === void 0 || right === void 0) return false;
87998
+ return left.trim() === right.trim();
87999
+ }
88000
+ function splitResponseStreamDisplayMessages(displayMessages, responseStreamState) {
88001
+ const responseStreamKeys = new Set(responseStreamState?.keys.values() ?? []);
88002
+ const firstActiveIndex = displayMessages.findIndex(
88003
+ (message) => responseStreamKeys.has(message.key)
88004
+ );
88005
+ if (firstActiveIndex === -1) {
88006
+ return {
88007
+ transcriptMessages: displayMessages,
88008
+ dynamicMessages: [],
88009
+ activeMessages: []
88010
+ };
88011
+ }
88012
+ const dynamicMessages = displayMessages.slice(firstActiveIndex);
88013
+ return {
88014
+ transcriptMessages: displayMessages.slice(0, firstActiveIndex),
88015
+ dynamicMessages,
88016
+ activeMessages: dynamicMessages.filter(
88017
+ (message) => responseStreamKeys.has(message.key)
88018
+ )
88019
+ };
88020
+ }
88021
+ function createActiveResponseStreamMessageMap(messages) {
88022
+ return new Map(messages.map((message) => [message.key, message]));
88023
+ }
88024
+ function upsertDynamicResponseStreamMessage(dynamicMessages, activeMessagesByKey, message) {
88025
+ const existingIndex = dynamicMessages.findIndex((item) => item.key === message.key);
88026
+ if (existingIndex === -1) {
88027
+ activeMessagesByKey.set(message.key, message);
88028
+ return [...dynamicMessages, message];
88029
+ }
88030
+ const currentMessage = dynamicMessages[existingIndex];
88031
+ if (currentMessage?.content === message.content && currentMessage.type === message.type && currentMessage.timestamp === message.timestamp) {
88032
+ activeMessagesByKey.set(message.key, currentMessage);
88033
+ return dynamicMessages;
88034
+ }
88035
+ activeMessagesByKey.set(message.key, message);
88036
+ const nextMessages = [...dynamicMessages];
88037
+ nextMessages[existingIndex] = message;
88038
+ return nextMessages;
88039
+ }
88040
+ function removeDynamicResponseStreamMessages(dynamicMessages, activeMessagesByKey, keys) {
88041
+ const affectedMessages = [];
88042
+ for (const key of keys) {
88043
+ const message = activeMessagesByKey.get(key);
88044
+ if (message) affectedMessages.push(message);
88045
+ activeMessagesByKey.delete(key);
88046
+ }
88047
+ return {
88048
+ dynamicMessages: dynamicMessages.filter((message) => !keys.has(message.key)),
88049
+ affectedMessages
88050
+ };
88051
+ }
88052
+ function commitDynamicResponseStreamMessages(dynamicMessages, activeMessagesByKey, keys) {
88053
+ const affectedMessages = [];
88054
+ for (const key of keys) {
88055
+ const message = activeMessagesByKey.get(key);
88056
+ if (message) affectedMessages.push(message);
88057
+ activeMessagesByKey.delete(key);
88058
+ }
88059
+ if (affectedMessages.length === 0) {
88060
+ return {
88061
+ dynamicMessages,
88062
+ committedMessages: [],
88063
+ affectedMessages
88064
+ };
88065
+ }
88066
+ const existingKeys = new Set(dynamicMessages.map((message) => message.key));
88067
+ const committedMessages = affectedMessages.filter(
88068
+ (message) => !existingKeys.has(message.key)
88069
+ );
88070
+ return {
88071
+ dynamicMessages: committedMessages.length > 0 ? [...dynamicMessages, ...committedMessages] : dynamicMessages,
88072
+ committedMessages,
88073
+ affectedMessages
88074
+ };
88075
+ }
88076
+ function flushDynamicMessagesIntoTranscript(transcriptMessages, dynamicMessages) {
88077
+ if (dynamicMessages.length === 0) return transcriptMessages;
88078
+ const existingKeys = new Set(transcriptMessages.map((message) => message.key));
88079
+ const newMessages = dynamicMessages.filter(
88080
+ (message) => !existingKeys.has(message.key)
88081
+ );
88082
+ return newMessages.length > 0 ? [...transcriptMessages, ...newMessages] : transcriptMessages;
88083
+ }
88084
+ function abortTrackedResponseStream(state, streamId, taskId) {
88085
+ const key = state.keys.get(streamId);
88086
+ const removedKeys = key ? /* @__PURE__ */ new Set([key]) : /* @__PURE__ */ new Set();
88087
+ deleteTrackedResponseStream(state, streamId);
88088
+ if (taskId) updateTaskKeys(state, taskId, removedKeys);
88089
+ return removedKeys;
88090
+ }
88091
+ function clearTrackedResponseStreamsForTask(state, taskId, options2 = {}) {
88092
+ const removedKeys = /* @__PURE__ */ new Set();
88093
+ const detachedKeys = /* @__PURE__ */ new Set();
88094
+ if (!taskId) return { removedKeys, detachedKeys };
88095
+ const keys = state.keysByTask.get(taskId);
88096
+ if (!keys?.size) return { removedKeys, detachedKeys };
88097
+ for (const [streamId, key] of state.keys.entries()) {
88098
+ if (!keys.has(key)) continue;
88099
+ if (options2.preserveContinued && state.statuses.get(streamId) === "continued" && !textMatchesForDisplay(state.texts.get(streamId), options2.finalText)) {
88100
+ deleteTrackedResponseStream(state, streamId);
88101
+ detachedKeys.add(key);
88102
+ continue;
88103
+ }
88104
+ deleteTrackedResponseStream(state, streamId);
88105
+ removedKeys.add(key);
88106
+ }
88107
+ updateTaskKeys(state, taskId, /* @__PURE__ */ new Set([...removedKeys, ...detachedKeys]));
88108
+ return { removedKeys, detachedKeys };
88109
+ }
88110
+ function commitTerminalTrackedResponseStreamsForTask(state, taskId) {
88111
+ const committedKeys = /* @__PURE__ */ new Set();
88112
+ if (!taskId) return committedKeys;
88113
+ const keys = state.keysByTask.get(taskId);
88114
+ if (!keys?.size) return committedKeys;
88115
+ for (const [streamId, key] of state.keys.entries()) {
88116
+ if (!keys.has(key)) continue;
88117
+ if (state.statuses.get(streamId) === "streaming") continue;
88118
+ deleteTrackedResponseStream(state, streamId);
88119
+ committedKeys.add(key);
88120
+ }
88121
+ updateTaskKeys(state, taskId, committedKeys);
88122
+ return committedKeys;
88123
+ }
88124
+ function commitAllTerminalTrackedResponseStreams(state) {
88125
+ const committedKeys = /* @__PURE__ */ new Set();
88126
+ for (const [streamId, key] of [...state.keys.entries()]) {
88127
+ if (state.statuses.get(streamId) === "streaming") continue;
88128
+ deleteTrackedResponseStream(state, streamId);
88129
+ committedKeys.add(key);
88130
+ }
88131
+ for (const taskId of [...state.keysByTask.keys()]) {
88132
+ updateTaskKeys(state, taskId, committedKeys);
88133
+ }
88134
+ return committedKeys;
88135
+ }
88136
+
87948
88137
  // src/components/AgentInstallPrompt.tsx
87949
88138
  var import_react22 = __toESM(require_react(), 1);
87950
88139
  var brand2 = (text) => source_default.hex("#F97316")(text);
@@ -95613,6 +95802,7 @@ function createRainSpinner() {
95613
95802
 
95614
95803
  // src/commands/chat.tsx
95615
95804
  var cliVersion = getCliVersion();
95805
+ var RENDERED_STREAM_TEXT_DEDUPE_LIMIT = 100;
95616
95806
  var WorkspaceNotConfiguredError = class extends Error {
95617
95807
  constructor() {
95618
95808
  super("No workspace configured.");
@@ -95629,16 +95819,6 @@ var WorkspaceNotFoundError = class extends Error {
95629
95819
  };
95630
95820
  var WORKSPACE_NOT_CONFIGURED_MSG = "No workspace configured. Pass a --workspace <id_or_name> argument or run guild workspace select";
95631
95821
  var WORKSPACE_NOT_FOUND_MSG = "The workspace doesn't exist.";
95632
- marked.use(markedTerminal({}, { theme: {} }));
95633
- function fixListItemMarkdown(text) {
95634
- text = text.replace(/\*\*([^*]+)\*\*/g, (_, content) => source_default.bold(content));
95635
- text = text.replace(/`([^`]+)`/g, (_, content) => code(content));
95636
- text = text.replace(
95637
- /(?<![\\w])_([^_]+)_(?![\\w])/g,
95638
- (_, content) => source_default.italic(content)
95639
- );
95640
- return text;
95641
- }
95642
95822
  function extractMessageText(text) {
95643
95823
  const trimmed = text.trim();
95644
95824
  if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return text;
@@ -95667,23 +95847,7 @@ function extractRuntimeDoneText(content) {
95667
95847
  return JSON.stringify(content);
95668
95848
  }
95669
95849
  function renderAssistantMessage(text, taskName) {
95670
- const rendered = fixListItemMarkdown(marked.parse(text));
95671
- return `${source_default.green("\u25CF")} ${source_default.bold(taskName)}
95672
- ${rendered.trim().split("\n").join("\n ")}`;
95673
- }
95674
- function getEventAgentName(event, fallbackName) {
95675
- const task = event.task;
95676
- if (!task) return fallbackName;
95677
- if ("agent" in task && task.agent) {
95678
- return getAgentName(task.agent);
95679
- }
95680
- if ("parent_task" in task && task.parent_task) {
95681
- const parent = task.parent_task;
95682
- if ("agent" in parent && parent.agent) {
95683
- return getAgentName(parent.agent);
95684
- }
95685
- }
95686
- return fallbackName;
95850
+ return renderAssistantMessageContent(text, taskName);
95687
95851
  }
95688
95852
  function applyResponseStreamContentsInSequence(contents) {
95689
95853
  return [...contents].sort((left, right) => left.sequence - right.sequence).reduce(
@@ -95691,6 +95855,33 @@ function applyResponseStreamContentsInSequence(contents) {
95691
95855
  ""
95692
95856
  );
95693
95857
  }
95858
+ function cloneResponseStreamResumeState(state) {
95859
+ if (!state) {
95860
+ return {
95861
+ keys: /* @__PURE__ */ new Map(),
95862
+ contents: /* @__PURE__ */ new Map(),
95863
+ texts: /* @__PURE__ */ new Map(),
95864
+ timestamps: /* @__PURE__ */ new Map(),
95865
+ statuses: /* @__PURE__ */ new Map(),
95866
+ keysByTask: /* @__PURE__ */ new Map()
95867
+ };
95868
+ }
95869
+ return {
95870
+ keys: new Map(state.keys),
95871
+ contents: new Map(
95872
+ [...state.contents.entries()].map(([streamId, contents]) => [
95873
+ streamId,
95874
+ [...contents]
95875
+ ])
95876
+ ),
95877
+ texts: new Map(state.texts),
95878
+ timestamps: new Map(state.timestamps),
95879
+ statuses: new Map(state.statuses),
95880
+ keysByTask: new Map(
95881
+ [...state.keysByTask.entries()].map(([taskId, keys]) => [taskId, new Set(keys)])
95882
+ )
95883
+ };
95884
+ }
95694
95885
  async function outputOnceResult(sessionId, events, mode) {
95695
95886
  if (mode === "json") {
95696
95887
  console.log(JSON.stringify({ session_id: sessionId, events }, null, 2));
@@ -95927,7 +96118,7 @@ function ChatApp({
95927
96118
  }
95928
96119
  }
95929
96120
  }
95930
- ), phase === "chat" && /* @__PURE__ */ import_react25.default.createElement(
96121
+ ), phase === "chat" && (!connectedSession || !connectedClient) && /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react25.default.createElement(Text, null, `${brand(">")} ${initialPrompt}`), /* @__PURE__ */ import_react25.default.createElement(Box_default, { height: 1 }, /* @__PURE__ */ import_react25.default.createElement(Text, { color: "gray" }, "> "), /* @__PURE__ */ import_react25.default.createElement(Text, null, source_default.dim("(connecting...)")))), connectedSession && connectedClient && /* @__PURE__ */ import_react25.default.createElement(
95931
96122
  ChatUIWithConnection,
95932
96123
  {
95933
96124
  key: chatInstanceKey,
@@ -95938,24 +96129,12 @@ function ChatApp({
95938
96129
  client: connectedClient,
95939
96130
  session: connectedSession,
95940
96131
  onFirstMessage: () => setFirstMessageReceived(true),
96132
+ isVisible: phase === "chat",
95941
96133
  resumeEvents,
95942
96134
  resumeCommand,
95943
96135
  eventFilter
95944
96136
  }
95945
- ), (phase === "splash" || phase === "finalizing") && connectedSession && connectedClient && /* @__PURE__ */ import_react25.default.createElement(Box_default, { display: "none" }, /* @__PURE__ */ import_react25.default.createElement(
95946
- ChatUIWithConnection,
95947
- {
95948
- initialPrompt,
95949
- version,
95950
- versionId,
95951
- agentName,
95952
- client: connectedClient,
95953
- session: connectedSession,
95954
- onFirstMessage: () => setFirstMessageReceived(true),
95955
- isActive: false,
95956
- eventFilter
95957
- }
95958
- )));
96137
+ ));
95959
96138
  }
95960
96139
  function ChatUIWithConnection({
95961
96140
  initialPrompt,
@@ -95965,41 +96144,71 @@ function ChatUIWithConnection({
95965
96144
  client: preConnectedClient,
95966
96145
  session: preConnectedSession,
95967
96146
  onFirstMessage,
95968
- isActive = true,
96147
+ isVisible = true,
95969
96148
  resumeEvents,
95970
96149
  resumeCommand,
95971
- eventFilter
96150
+ eventFilter,
96151
+ fetchEventsFn = fetchEvents,
96152
+ fetchTasksFn = fetchTasks
95972
96153
  }) {
95973
96154
  const activeFilter = eventFilter ?? DEFAULT_EVENT_TYPES;
95974
96155
  const [showTaskPanel, setShowTaskPanel] = (0, import_react25.useState)(true);
95975
96156
  const [tasks, setTasks] = (0, import_react25.useState)([]);
95976
96157
  const [pendingInstallRequest, setPendingInstallRequest] = (0, import_react25.useState)(null);
95977
96158
  const promptedEventIds = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
95978
- const [resumeDisplay] = (0, import_react25.useState)(
95979
- () => resumeEvents ? prepareSessionResumeDisplay(resumeEvents) : null
95980
- );
95981
- const resumeDisplayMessages = resumeDisplay?.displayMessages ?? null;
95982
- const responseStreamResumeState = resumeDisplay?.responseStreamState ?? null;
95983
- const sessionLinkMessage = isActive && preConnectedSession?.session_url ? [
95984
- {
95985
- key: "session-link",
95986
- content: source_default.dim(
95987
- `Session: ${hyperlink(preConnectedSession.id, preConnectedSession.session_url)}`
95988
- ),
95989
- type: "progress"
95990
- }
95991
- ] : [];
95992
- const [messages, setMessages] = (0, import_react25.useState)(
95993
- resumeDisplayMessages ? resumeDisplayMessages : isActive ? [
95994
- ...sessionLinkMessage,
96159
+ const [initialChatState] = (0, import_react25.useState)(() => {
96160
+ const resumeDisplay = resumeEvents ? prepareSessionResumeDisplay(resumeEvents) : null;
96161
+ const splitResumeDisplay = splitResponseStreamDisplayMessages(
96162
+ resumeDisplay?.displayMessages ?? [],
96163
+ resumeDisplay?.responseStreamState
96164
+ );
96165
+ const sessionLinkMessage = preConnectedSession?.session_url ? [
95995
96166
  {
95996
- key: "initial",
95997
- content: `${brand(">")} ${initialPrompt}`,
95998
- type: "user"
96167
+ key: "session-link",
96168
+ content: source_default.dim(
96169
+ `Session: ${hyperlink(preConnectedSession.id, preConnectedSession.session_url)}`
96170
+ ),
96171
+ type: "progress"
95999
96172
  }
96000
- ] : []
96173
+ ] : [];
96174
+ return {
96175
+ responseStreamResumeState: resumeDisplay?.responseStreamState ?? null,
96176
+ transcriptMessages: resumeDisplay ? splitResumeDisplay.transcriptMessages : [
96177
+ ...sessionLinkMessage,
96178
+ {
96179
+ key: "initial",
96180
+ content: `${brand(">")} ${initialPrompt}`,
96181
+ type: "user"
96182
+ }
96183
+ ],
96184
+ dynamicMessages: splitResumeDisplay.dynamicMessages,
96185
+ activeStreamMessages: splitResumeDisplay.activeMessages
96186
+ };
96187
+ });
96188
+ const messagesRef = (0, import_react25.useRef)(initialChatState.transcriptMessages);
96189
+ const [messages, setMessagesState] = (0, import_react25.useState)(
96190
+ initialChatState.transcriptMessages
96191
+ );
96192
+ const setMessages = (update) => {
96193
+ const nextMessages = typeof update === "function" ? update(messagesRef.current) : update;
96194
+ messagesRef.current = nextMessages;
96195
+ setMessagesState(nextMessages);
96196
+ };
96197
+ const dynamicMessagesRef = (0, import_react25.useRef)(initialChatState.dynamicMessages);
96198
+ const [dynamicMessages, setDynamicMessagesState] = (0, import_react25.useState)(
96199
+ initialChatState.dynamicMessages
96200
+ );
96201
+ const setDynamicMessages = (update) => {
96202
+ const nextMessages = typeof update === "function" ? update(dynamicMessagesRef.current) : update;
96203
+ dynamicMessagesRef.current = nextMessages;
96204
+ setDynamicMessagesState(nextMessages);
96205
+ };
96206
+ const [responseStreamMessagesByKey] = (0, import_react25.useState)(
96207
+ () => createActiveResponseStreamMessageMap(initialChatState.activeStreamMessages)
96208
+ );
96209
+ const [responseStreamState] = (0, import_react25.useState)(
96210
+ () => cloneResponseStreamResumeState(initialChatState.responseStreamResumeState)
96001
96211
  );
96002
- const [streamingMessage, setStreamingMessage] = (0, import_react25.useState)(null);
96003
96212
  const [input, setInput] = (0, import_react25.useState)("");
96004
96213
  const inputTextRef = (0, import_react25.useRef)("");
96005
96214
  const updateInput = (value) => {
@@ -96019,6 +96228,9 @@ function ChatUIWithConnection({
96019
96228
  width: process.stdout.columns || 80,
96020
96229
  height: process.stdout.rows || 24
96021
96230
  });
96231
+ const client = preConnectedClient;
96232
+ const session = preConnectedSession;
96233
+ const isReady = session !== null;
96022
96234
  const resizeTimeout = (0, import_react25.useRef)(null);
96023
96235
  (0, import_react25.useEffect)(() => {
96024
96236
  const handleResize = () => {
@@ -96040,57 +96252,60 @@ function ChatUIWithConnection({
96040
96252
  }
96041
96253
  };
96042
96254
  }, []);
96043
- use_input_default((input2, key) => {
96044
- if (key.escape && client && session && currentOperation && !isInterrupting.current && Date.now() - mountedAt.current > 300) {
96045
- isInterrupting.current = true;
96046
- client.post(`/sessions/${session.id}/interrupt`, {}).then(() => {
96047
- debug("Session interrupted");
96048
- }).catch((err) => {
96049
- debug("Interrupt failed (session may already be done):", err);
96050
- }).finally(() => {
96051
- isInterrupting.current = false;
96052
- });
96053
- return;
96054
- }
96055
- const isCtrlC = input2 === "" || key.ctrl && input2 === "c";
96056
- if (isCtrlC) {
96057
- if (inputTextRef.current && !exitKeyPressed.current) {
96058
- updateInput("");
96255
+ use_input_default(
96256
+ (input2, key) => {
96257
+ if (key.escape && isVisible && client && session && currentOperation && !isInterrupting.current && Date.now() - mountedAt.current > 300) {
96258
+ isInterrupting.current = true;
96259
+ client.post(`/sessions/${session.id}/interrupt`, {}).then(() => {
96260
+ debug("Session interrupted");
96261
+ }).catch((err) => {
96262
+ debug("Interrupt failed (session may already be done):", err);
96263
+ }).finally(() => {
96264
+ isInterrupting.current = false;
96265
+ });
96059
96266
  return;
96060
96267
  }
96061
- if (exitKeyPressed.current) {
96062
- if (preConnectedSession?.id && resumeCommand) {
96063
- printResumeHint(preConnectedSession.id, resumeCommand);
96268
+ const isCtrlC = input2 === "" || key.ctrl && input2 === "c";
96269
+ if (isCtrlC) {
96270
+ if (inputTextRef.current && !exitKeyPressed.current) {
96271
+ updateInput("");
96272
+ return;
96064
96273
  }
96065
- process.exit(0);
96274
+ if (exitKeyPressed.current) {
96275
+ if (preConnectedSession?.id && resumeCommand) {
96276
+ printResumeHint(preConnectedSession.id, resumeCommand);
96277
+ }
96278
+ process.exit(0);
96279
+ }
96280
+ exitKeyPressed.current = true;
96281
+ setExitHint("ctrl-c");
96282
+ if (exitKeyTimeout.current) clearTimeout(exitKeyTimeout.current);
96283
+ exitKeyTimeout.current = setTimeout(() => {
96284
+ exitKeyPressed.current = false;
96285
+ setExitHint(null);
96286
+ }, 2e3);
96287
+ return;
96066
96288
  }
96067
- exitKeyPressed.current = true;
96068
- setExitHint("ctrl-c");
96069
- if (exitKeyTimeout.current) clearTimeout(exitKeyTimeout.current);
96070
- exitKeyTimeout.current = setTimeout(() => {
96071
- exitKeyPressed.current = false;
96072
- setExitHint(null);
96073
- }, 2e3);
96074
- return;
96075
- }
96076
- const isCtrlD = input2 === "" || key.ctrl && input2 === "d";
96077
- if (isCtrlD) {
96078
- if (exitKeyPressed.current) {
96079
- if (preConnectedSession?.id && resumeCommand) {
96080
- printResumeHint(preConnectedSession.id, resumeCommand);
96081
- }
96082
- process.exit(0);
96083
- }
96084
- exitKeyPressed.current = true;
96085
- setExitHint("ctrl-d");
96086
- if (exitKeyTimeout.current) clearTimeout(exitKeyTimeout.current);
96087
- exitKeyTimeout.current = setTimeout(() => {
96088
- exitKeyPressed.current = false;
96089
- setExitHint(null);
96090
- }, 2e3);
96091
- return;
96092
- }
96093
- });
96289
+ const isCtrlD = input2 === "" || key.ctrl && input2 === "d";
96290
+ if (isCtrlD) {
96291
+ if (exitKeyPressed.current) {
96292
+ if (preConnectedSession?.id && resumeCommand) {
96293
+ printResumeHint(preConnectedSession.id, resumeCommand);
96294
+ }
96295
+ process.exit(0);
96296
+ }
96297
+ exitKeyPressed.current = true;
96298
+ setExitHint("ctrl-d");
96299
+ if (exitKeyTimeout.current) clearTimeout(exitKeyTimeout.current);
96300
+ exitKeyTimeout.current = setTimeout(() => {
96301
+ exitKeyPressed.current = false;
96302
+ setExitHint(null);
96303
+ }, 2e3);
96304
+ return;
96305
+ }
96306
+ },
96307
+ { isActive: isReady && isVisible }
96308
+ );
96094
96309
  (0, import_react25.useEffect)(() => {
96095
96310
  return () => {
96096
96311
  if (exitKeyTimeout.current) {
@@ -96098,9 +96313,6 @@ function ChatUIWithConnection({
96098
96313
  }
96099
96314
  };
96100
96315
  }, []);
96101
- const client = preConnectedClient;
96102
- const session = preConnectedSession;
96103
- const isReady = session !== null;
96104
96316
  const animatedSpinner = (0, import_react25.useRef)(null);
96105
96317
  const spinnerSwapInterval = (0, import_react25.useRef)(null);
96106
96318
  const spinnerTheme = process.env.GUILD_SPINNER_THEME;
@@ -96120,85 +96332,150 @@ function ChatUIWithConnection({
96120
96332
  const isPolling = (0, import_react25.useRef)(false);
96121
96333
  const receivedResponseSinceLastInput = (0, import_react25.useRef)(false);
96122
96334
  const firstMessageNotified = (0, import_react25.useRef)(!!resumeEvents);
96123
- const responseStreamKeys = (0, import_react25.useRef)(
96124
- responseStreamResumeState?.keys ?? /* @__PURE__ */ new Map()
96125
- );
96126
- const responseStreamContents = (0, import_react25.useRef)(
96127
- responseStreamResumeState?.contents ?? /* @__PURE__ */ new Map()
96128
- );
96129
- const responseStreamTexts = (0, import_react25.useRef)(
96130
- responseStreamResumeState?.texts ?? /* @__PURE__ */ new Map()
96131
- );
96132
- const responseStreamTimestamps = (0, import_react25.useRef)(
96133
- responseStreamResumeState?.timestamps ?? /* @__PURE__ */ new Map()
96134
- );
96135
- const responseStreamStatuses = (0, import_react25.useRef)(
96136
- responseStreamResumeState?.statuses ?? /* @__PURE__ */ new Map()
96137
- );
96138
- const responseStreamKeysByTask = (0, import_react25.useRef)(
96139
- responseStreamResumeState?.keysByTask ?? /* @__PURE__ */ new Map()
96140
- );
96141
- const renderedStreamTexts = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
96142
- const clearResponseStreamsForTask = (taskId, options2 = {}) => {
96143
- if (!taskId) return;
96144
- const keys = responseStreamKeysByTask.current.get(taskId);
96145
- if (!keys?.size) return;
96146
- const removedKeys = /* @__PURE__ */ new Set();
96147
- const detachedKeys = /* @__PURE__ */ new Set();
96148
- for (const [streamId, key] of responseStreamKeys.current.entries()) {
96149
- if (keys.has(key)) {
96150
- if (options2.preserveContinued && responseStreamStatuses.current.get(streamId) === "continued" && responseStreamTexts.current.get(streamId) !== options2.finalText) {
96151
- responseStreamKeys.current.delete(streamId);
96152
- responseStreamContents.current.delete(streamId);
96153
- responseStreamTexts.current.delete(streamId);
96154
- responseStreamTimestamps.current.delete(streamId);
96155
- responseStreamStatuses.current.delete(streamId);
96156
- detachedKeys.add(key);
96157
- continue;
96158
- }
96159
- responseStreamKeys.current.delete(streamId);
96160
- responseStreamContents.current.delete(streamId);
96161
- responseStreamTexts.current.delete(streamId);
96162
- responseStreamTimestamps.current.delete(streamId);
96163
- responseStreamStatuses.current.delete(streamId);
96164
- removedKeys.add(key);
96335
+ const closedResponseStreamIds = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
96336
+ const flushDynamicMessagesIfIdle = () => {
96337
+ if (responseStreamMessagesByKey.size > 0) return;
96338
+ if (dynamicMessagesRef.current.length === 0) return;
96339
+ setMessages(
96340
+ (prev) => flushDynamicMessagesIntoTranscript(prev, dynamicMessagesRef.current)
96341
+ );
96342
+ setDynamicMessages([]);
96343
+ };
96344
+ const appendDisplayMessage = (message) => {
96345
+ if (dynamicMessagesRef.current.length > 0) {
96346
+ setDynamicMessages((prev) => [...prev, message]);
96347
+ return;
96348
+ }
96349
+ setMessages((prev) => [...prev, message]);
96350
+ };
96351
+ const setActiveResponseStreamMessage = (message) => {
96352
+ setDynamicMessages(
96353
+ (prev) => upsertDynamicResponseStreamMessage(prev, responseStreamMessagesByKey, message)
96354
+ );
96355
+ };
96356
+ const removeActiveResponseStreamMessageKeys = (keys) => {
96357
+ const { dynamicMessages: dynamicMessages2, affectedMessages } = removeDynamicResponseStreamMessages(
96358
+ dynamicMessagesRef.current,
96359
+ responseStreamMessagesByKey,
96360
+ keys
96361
+ );
96362
+ if (affectedMessages.length > 0 || dynamicMessages2.length !== dynamicMessagesRef.current.length) {
96363
+ setDynamicMessages(dynamicMessages2);
96364
+ flushDynamicMessagesIfIdle();
96365
+ }
96366
+ return affectedMessages;
96367
+ };
96368
+ const commitActiveResponseStreamMessageKeys = (keys) => {
96369
+ const result = commitDynamicResponseStreamMessages(
96370
+ dynamicMessagesRef.current,
96371
+ responseStreamMessagesByKey,
96372
+ keys
96373
+ );
96374
+ if (result.affectedMessages.length === 0) return;
96375
+ setDynamicMessages(result.dynamicMessages);
96376
+ flushDynamicMessagesIfIdle();
96377
+ };
96378
+ const renderedStreamTextLru = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
96379
+ const trackedStreamIdsForTask = (taskId, options2 = {}) => {
96380
+ const streamIds = /* @__PURE__ */ new Set();
96381
+ if (!taskId) return streamIds;
96382
+ const keys = responseStreamState.keysByTask.get(taskId);
96383
+ if (!keys?.size) return streamIds;
96384
+ for (const [streamId, key] of responseStreamState.keys.entries()) {
96385
+ if (!keys.has(key)) continue;
96386
+ if (options2.terminalOnly && responseStreamState.statuses.get(streamId) === "streaming") {
96387
+ continue;
96165
96388
  }
96389
+ streamIds.add(streamId);
96166
96390
  }
96167
- const inactiveKeys = /* @__PURE__ */ new Set([...removedKeys, ...detachedKeys]);
96168
- const remainingKeys = new Set([...keys].filter((key) => !inactiveKeys.has(key)));
96169
- if (remainingKeys.size > 0) {
96170
- responseStreamKeysByTask.current.set(taskId, remainingKeys);
96171
- } else {
96172
- responseStreamKeysByTask.current.delete(taskId);
96391
+ return streamIds;
96392
+ };
96393
+ const allTerminalTrackedStreamIds = () => {
96394
+ const streamIds = /* @__PURE__ */ new Set();
96395
+ for (const streamId of responseStreamState.keys.keys()) {
96396
+ if (responseStreamState.statuses.get(streamId) !== "streaming") {
96397
+ streamIds.add(streamId);
96398
+ }
96399
+ }
96400
+ return streamIds;
96401
+ };
96402
+ const closeResponseStreamIds = (streamIds) => {
96403
+ for (const streamId of streamIds) {
96404
+ closedResponseStreamIds.current.add(streamId);
96405
+ }
96406
+ };
96407
+ const rememberRenderedStreamText = (text) => {
96408
+ const trimmed = text.trim();
96409
+ if (!trimmed) return;
96410
+ renderedStreamTextLru.current.delete(trimmed);
96411
+ renderedStreamTextLru.current.add(trimmed);
96412
+ while (renderedStreamTextLru.current.size > RENDERED_STREAM_TEXT_DEDUPE_LIMIT) {
96413
+ const oldestKey = renderedStreamTextLru.current.keys().next().value;
96414
+ if (oldestKey === void 0) break;
96415
+ renderedStreamTextLru.current.delete(oldestKey);
96173
96416
  }
96174
- setMessages((prev) => prev.filter((message) => !removedKeys.has(message.key)));
96175
- setStreamingMessage(
96176
- (prev) => prev && (removedKeys.has(prev.key) || detachedKeys.has(prev.key)) ? null : prev
96417
+ };
96418
+ const consumeRenderedStreamText = (text) => {
96419
+ const trimmed = text.trim();
96420
+ if (!trimmed) return false;
96421
+ return renderedStreamTextLru.current.delete(trimmed);
96422
+ };
96423
+ const clearResponseStreamsForTask = (taskId, options2 = {}) => {
96424
+ const streamIdsToClose = trackedStreamIdsForTask(taskId);
96425
+ const { removedKeys, detachedKeys } = clearTrackedResponseStreamsForTask(
96426
+ responseStreamState,
96427
+ taskId,
96428
+ options2
96177
96429
  );
96430
+ if (removedKeys.size > 0 || detachedKeys.size > 0) {
96431
+ closeResponseStreamIds(streamIdsToClose);
96432
+ }
96433
+ removeActiveResponseStreamMessageKeys(removedKeys);
96434
+ commitActiveResponseStreamMessageKeys(detachedKeys);
96435
+ if (removedKeys.size > 0) {
96436
+ setMessages((prev) => prev.filter((message) => !removedKeys.has(message.key)));
96437
+ }
96438
+ };
96439
+ const commitTerminalResponseStreamsForTask = (taskId) => {
96440
+ const streamIdsToClose = trackedStreamIdsForTask(taskId, { terminalOnly: true });
96441
+ const committedKeys = commitTerminalTrackedResponseStreamsForTask(
96442
+ responseStreamState,
96443
+ taskId
96444
+ );
96445
+ if (committedKeys.size > 0) {
96446
+ closeResponseStreamIds(streamIdsToClose);
96447
+ }
96448
+ commitActiveResponseStreamMessageKeys(committedKeys);
96449
+ };
96450
+ const commitAllTerminalResponseStreams = () => {
96451
+ const streamIdsToClose = allTerminalTrackedStreamIds();
96452
+ const committedKeys = commitAllTerminalTrackedResponseStreams(responseStreamState);
96453
+ if (committedKeys.size > 0) {
96454
+ closeResponseStreamIds(streamIdsToClose);
96455
+ }
96456
+ commitActiveResponseStreamMessageKeys(committedKeys);
96178
96457
  };
96179
96458
  const upsertResponseStreamMessage = (event) => {
96180
96459
  if (!isResponseStreamEvent(event)) return;
96181
96460
  if (!isRootTaskEvent(event)) return;
96182
96461
  const streamId = event.content.stream_id;
96462
+ if (closedResponseStreamIds.current.has(streamId)) return;
96183
96463
  const taskId = event.task?.id;
96184
- const existingKey = responseStreamKeys.current.get(streamId);
96464
+ const existingKey = responseStreamState.keys.get(streamId);
96185
96465
  if (event.content.status === "aborted") {
96186
- responseStreamContents.current.delete(streamId);
96187
- responseStreamTexts.current.delete(streamId);
96188
- responseStreamTimestamps.current.delete(streamId);
96189
- responseStreamStatuses.current.delete(streamId);
96190
- if (existingKey) {
96191
- responseStreamKeys.current.delete(streamId);
96192
- if (taskId) {
96193
- const keys = responseStreamKeysByTask.current.get(taskId);
96194
- keys?.delete(existingKey);
96195
- if (keys?.size === 0) responseStreamKeysByTask.current.delete(taskId);
96196
- }
96197
- setMessages((prev) => prev.filter((message2) => message2.key !== existingKey));
96466
+ closeResponseStreamIds(/* @__PURE__ */ new Set([streamId]));
96467
+ const removedKeys = abortTrackedResponseStream(
96468
+ responseStreamState,
96469
+ streamId,
96470
+ taskId
96471
+ );
96472
+ removeActiveResponseStreamMessageKeys(removedKeys);
96473
+ if (removedKeys.size > 0) {
96474
+ setMessages((prev) => prev.filter((message) => !removedKeys.has(message.key)));
96198
96475
  }
96199
96476
  return;
96200
96477
  }
96201
- const streamContents = responseStreamContents.current.get(streamId) ?? [];
96478
+ const streamContents = responseStreamState.contents.get(streamId) ?? [];
96202
96479
  const existingContentIndex = streamContents.findIndex(
96203
96480
  (content) => content.sequence === event.content.sequence
96204
96481
  );
@@ -96207,45 +96484,32 @@ function ChatUIWithConnection({
96207
96484
  } else {
96208
96485
  streamContents[existingContentIndex] = event.content;
96209
96486
  }
96210
- responseStreamContents.current.set(streamId, streamContents);
96487
+ responseStreamState.contents.set(streamId, streamContents);
96211
96488
  const text = applyResponseStreamContentsInSequence(streamContents);
96212
96489
  if (!text.trim()) return;
96213
96490
  const key = existingKey ?? `response-stream-${streamId}`;
96214
- responseStreamKeys.current.set(streamId, key);
96215
- responseStreamTexts.current.set(streamId, text);
96216
- responseStreamStatuses.current.set(streamId, event.content.status);
96491
+ responseStreamState.keys.set(streamId, key);
96492
+ responseStreamState.texts.set(streamId, text);
96493
+ responseStreamState.statuses.set(streamId, event.content.status);
96217
96494
  if (taskId) {
96218
- const keys = responseStreamKeysByTask.current.get(taskId) ?? /* @__PURE__ */ new Set();
96495
+ const keys = responseStreamState.keysByTask.get(taskId) ?? /* @__PURE__ */ new Set();
96219
96496
  keys.add(key);
96220
- responseStreamKeysByTask.current.set(taskId, keys);
96497
+ responseStreamState.keysByTask.set(taskId, keys);
96221
96498
  }
96222
- const taskName = agentName || "assistant";
96499
+ const taskName = getEventAgentName(event, agentName || "assistant");
96223
96500
  const messageContent = renderAssistantMessage(text, taskName);
96224
- const timestamp = responseStreamTimestamps.current.get(streamId) ?? (/* @__PURE__ */ new Date()).toLocaleTimeString();
96225
- responseStreamTimestamps.current.set(streamId, timestamp);
96226
- const message = {
96501
+ const timestamp = responseStreamState.timestamps.get(streamId) ?? (/* @__PURE__ */ new Date()).toLocaleTimeString();
96502
+ responseStreamState.timestamps.set(streamId, timestamp);
96503
+ setActiveResponseStreamMessage({
96227
96504
  key,
96228
96505
  content: messageContent,
96229
96506
  type: "assistant",
96230
96507
  timestamp
96231
- };
96232
- if (event.content.status === "done" || event.content.status === "continued") {
96233
- setStreamingMessage(null);
96234
- setMessages((prev) => {
96235
- const index = prev.findIndex((m) => m.key === key);
96236
- if (index === -1) return [...prev, message];
96237
- const next = [...prev];
96238
- next[index] = message;
96239
- return next;
96240
- });
96241
- if (event.content.status === "done") {
96242
- const trimmed = text.trim();
96243
- if (trimmed) renderedStreamTexts.current.add(trimmed);
96244
- receivedResponseSinceLastInput.current = true;
96245
- setCurrentOperation("");
96246
- }
96247
- } else {
96248
- setStreamingMessage(message);
96508
+ });
96509
+ if (event.content.status === "done") {
96510
+ rememberRenderedStreamText(text);
96511
+ receivedResponseSinceLastInput.current = true;
96512
+ setCurrentOperation("");
96249
96513
  }
96250
96514
  if (!firstMessageNotified.current && onFirstMessage) {
96251
96515
  firstMessageNotified.current = true;
@@ -96295,7 +96559,7 @@ function ChatUIWithConnection({
96295
96559
  if (isPollingTasks.current) return;
96296
96560
  isPollingTasks.current = true;
96297
96561
  try {
96298
- const tasksList = await fetchTasks(client, session.id);
96562
+ const tasksList = await fetchTasksFn(client, session.id);
96299
96563
  setTasks(tasksList);
96300
96564
  } catch (error) {
96301
96565
  debug("Tasks poll error:", error);
@@ -96308,7 +96572,7 @@ function ChatUIWithConnection({
96308
96572
  return () => {
96309
96573
  clearInterval(interval);
96310
96574
  };
96311
- }, [client, session, isReady]);
96575
+ }, [client, session, isReady, fetchTasksFn]);
96312
96576
  (0, import_react25.useEffect)(() => {
96313
96577
  if (!client || !session || !isReady) return;
96314
96578
  const poll = async () => {
@@ -96316,7 +96580,7 @@ function ChatUIWithConnection({
96316
96580
  isPolling.current = true;
96317
96581
  debug(`poll() called, session=${session.id}, fromId=${lastEventIdRef.current}`);
96318
96582
  try {
96319
- const newEvents = await fetchEvents(client, session.id, {
96583
+ const newEvents = await fetchEventsFn(client, session.id, {
96320
96584
  fromId: lastEventIdRef.current
96321
96585
  });
96322
96586
  debug(`Events: fromId=${lastEventIdRef.current}, new=${newEvents.length}`);
@@ -96338,100 +96602,76 @@ function ChatUIWithConnection({
96338
96602
  if (shouldShowEvent("runtime_error", activeFilter)) {
96339
96603
  const errorText = typeof event.content === "string" ? event.content : "Unknown error";
96340
96604
  const taskName = getEventAgentName(event, agentName || "assistant");
96341
- setMessages((prev) => [
96342
- ...prev,
96343
- {
96344
- key: `error-${Date.now()}`,
96345
- content: `${source_default.red("\u25CF")} ${source_default.bold(taskName)}
96605
+ appendDisplayMessage({
96606
+ key: `error-${Date.now()}`,
96607
+ content: `${source_default.red("\u25CF")} ${source_default.bold(taskName)}
96346
96608
  ${source_default.red(`Error: ${errorText}`)}`,
96347
- type: "assistant"
96348
- }
96349
- ]);
96609
+ type: "assistant"
96610
+ });
96350
96611
  }
96351
96612
  } else if (event.type === "runtime_start") {
96352
96613
  if (shouldShowEvent("runtime_start", activeFilter)) {
96353
96614
  const taskName = getEventAgentName(event, agentName || "assistant");
96354
- setMessages((prev) => [
96355
- ...prev,
96356
- {
96357
- key: `runtime-start-${Date.now()}`,
96358
- content: source_default.dim(`${source_default.green("\u25B6")} Started ${taskName}`),
96359
- type: "assistant"
96360
- }
96361
- ]);
96615
+ appendDisplayMessage({
96616
+ key: `runtime-start-${Date.now()}`,
96617
+ content: source_default.dim(`${source_default.green("\u25B6")} Started ${taskName}`),
96618
+ type: "assistant"
96619
+ });
96362
96620
  }
96363
96621
  } else if (event.type === "runtime_running") {
96364
96622
  if (shouldShowEvent("runtime_running", activeFilter)) {
96365
- setMessages((prev) => [
96366
- ...prev,
96367
- {
96368
- key: `runtime-running-${Date.now()}`,
96369
- content: source_default.dim(`${source_default.blue("\u25CF")} Running`),
96370
- type: "assistant"
96371
- }
96372
- ]);
96623
+ appendDisplayMessage({
96624
+ key: `runtime-running-${Date.now()}`,
96625
+ content: source_default.dim(`${source_default.blue("\u25CF")} Running`),
96626
+ type: "assistant"
96627
+ });
96373
96628
  }
96374
96629
  } else if (event.type === "runtime_waiting") {
96375
96630
  if (shouldShowEvent("runtime_waiting", activeFilter)) {
96376
- setMessages((prev) => [
96377
- ...prev,
96378
- {
96379
- key: `runtime-waiting-${Date.now()}`,
96380
- content: source_default.dim(`${source_default.yellow("\u25D0")} Waiting for input`),
96381
- type: "assistant"
96382
- }
96383
- ]);
96631
+ appendDisplayMessage({
96632
+ key: `runtime-waiting-${Date.now()}`,
96633
+ content: source_default.dim(`${source_default.yellow("\u25D0")} Waiting for input`),
96634
+ type: "assistant"
96635
+ });
96384
96636
  }
96385
96637
  } else if (event.type === "trigger_message") {
96386
96638
  if (shouldShowEvent("trigger_message", activeFilter)) {
96387
96639
  const triggerText = typeof event.content === "object" ? event.content?.data || "" : "";
96388
- setMessages((prev) => [
96389
- ...prev,
96390
- {
96391
- key: `trigger-${Date.now()}`,
96392
- content: `${source_default.cyan("\u26A1")} ${source_default.cyan("Trigger")} ${triggerText}`,
96393
- type: "assistant"
96394
- }
96395
- ]);
96640
+ appendDisplayMessage({
96641
+ key: `trigger-${Date.now()}`,
96642
+ content: `${source_default.cyan("\u26A1")} ${source_default.cyan("Trigger")} ${triggerText}`,
96643
+ type: "assistant"
96644
+ });
96396
96645
  }
96397
96646
  } else if (event.type === "system_error") {
96398
96647
  if (shouldShowEvent("system_error", activeFilter)) {
96399
96648
  const errText = typeof event.content === "object" ? event.content?.data || "" : "";
96400
- setMessages((prev) => [
96401
- ...prev,
96402
- {
96403
- key: `system-error-${Date.now()}`,
96404
- content: `${source_default.red("\u2717")} ${source_default.red("System error:")} ${errText}`,
96405
- type: "assistant"
96406
- }
96407
- ]);
96649
+ appendDisplayMessage({
96650
+ key: `system-error-${Date.now()}`,
96651
+ content: `${source_default.red("\u2717")} ${source_default.red("System error:")} ${errText}`,
96652
+ type: "assistant"
96653
+ });
96408
96654
  }
96409
96655
  } else if (event.type === "llm_start") {
96410
96656
  if (shouldShowEvent("llm_start", activeFilter)) {
96411
- setMessages((prev) => [
96412
- ...prev,
96413
- {
96414
- key: `llm-start-${Date.now()}`,
96415
- content: source_default.dim(
96416
- `${source_default.magenta("\u2726")} LLM request \u2192 ${event.provider}`
96417
- ),
96418
- type: "assistant"
96419
- }
96420
- ]);
96657
+ appendDisplayMessage({
96658
+ key: `llm-start-${Date.now()}`,
96659
+ content: source_default.dim(
96660
+ `${source_default.magenta("\u2726")} LLM request \u2192 ${event.provider}`
96661
+ ),
96662
+ type: "assistant"
96663
+ });
96421
96664
  }
96422
96665
  } else if (event.type === "llm_done") {
96423
96666
  if (shouldShowEvent("llm_done", activeFilter)) {
96424
96667
  const statusColor = event.status_code < 400 ? source_default.green : source_default.red;
96425
- setMessages((prev) => [
96426
- ...prev,
96427
- {
96428
- key: `llm-done-${Date.now()}`,
96429
- content: source_default.dim(
96430
- `${source_default.magenta("\u2726")} LLM response ${statusColor(`${event.status_code}`)}`
96431
- ),
96432
- type: "assistant"
96433
- }
96434
- ]);
96668
+ appendDisplayMessage({
96669
+ key: `llm-done-${Date.now()}`,
96670
+ content: source_default.dim(
96671
+ `${source_default.magenta("\u2726")} LLM response ${statusColor(`${event.status_code}`)}`
96672
+ ),
96673
+ type: "assistant"
96674
+ });
96435
96675
  }
96436
96676
  } else if (event.type === "agent_notification_progress") {
96437
96677
  const rawProgressText = typeof event.content === "string" ? event.content : event.content?.data || "";
@@ -96446,8 +96686,8 @@ function ChatUIWithConnection({
96446
96686
  const text = extractMessageText(getAgentNotificationText(event));
96447
96687
  const trimmedText = text.trim();
96448
96688
  if (trimmedText) {
96449
- if (renderedStreamTexts.current.has(trimmedText)) {
96450
- renderedStreamTexts.current.delete(trimmedText);
96689
+ if (consumeRenderedStreamText(trimmedText)) {
96690
+ commitTerminalResponseStreamsForTask(taskInfo?.id);
96451
96691
  receivedResponseSinceLastInput.current = true;
96452
96692
  setCurrentOperation("");
96453
96693
  continue;
@@ -96458,15 +96698,12 @@ function ChatUIWithConnection({
96458
96698
  });
96459
96699
  const taskName = getEventAgentName(event, agentName || "assistant");
96460
96700
  const messageContent = renderAssistantMessage(text, taskName);
96461
- setMessages((prev) => [
96462
- ...prev,
96463
- {
96464
- key: `msg-${Date.now()}-${Math.random()}`,
96465
- content: messageContent,
96466
- type: "assistant",
96467
- timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
96468
- }
96469
- ]);
96701
+ appendDisplayMessage({
96702
+ key: `msg-${Date.now()}-${Math.random()}`,
96703
+ content: messageContent,
96704
+ type: "assistant",
96705
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
96706
+ });
96470
96707
  if (!firstMessageNotified.current && onFirstMessage) {
96471
96708
  firstMessageNotified.current = true;
96472
96709
  onFirstMessage();
@@ -96478,42 +96715,34 @@ function ChatUIWithConnection({
96478
96715
  clearResponseStreamsForTask(taskInfo?.id);
96479
96716
  const errorText = typeof event.content === "string" ? event.content : event.content?.data || "Unknown error";
96480
96717
  const taskName = getEventAgentName(event, agentName || "assistant");
96481
- setMessages((prev) => [
96482
- ...prev,
96483
- {
96484
- key: `error-${Date.now()}`,
96485
- content: `${source_default.red("\u25CF")} ${source_default.bold(taskName)}
96718
+ appendDisplayMessage({
96719
+ key: `error-${Date.now()}`,
96720
+ content: `${source_default.red("\u25CF")} ${source_default.bold(taskName)}
96486
96721
  ${source_default.red(`Error: ${errorText}`)}`,
96487
- type: "assistant"
96488
- }
96489
- ]);
96722
+ type: "assistant"
96723
+ });
96490
96724
  setCurrentOperation("");
96491
96725
  } else if (event.type === "agent_console") {
96492
96726
  if (shouldShowEvent("agent_console", activeFilter) || isDebugMode()) {
96493
96727
  const content = typeof event.content === "string" ? event.content : "";
96494
96728
  const levelIcon = event.level === "error" ? source_default.red("\u2717") : event.level === "warn" ? source_default.yellow("\u26A0") : source_default.dim("\u25AA");
96495
96729
  const levelColor = event.level === "error" ? source_default.red : event.level === "warn" ? source_default.yellow : source_default.dim;
96496
- setMessages((prev) => [
96497
- ...prev,
96498
- {
96499
- key: `console-${Date.now()}-${Math.random()}`,
96500
- content: `${levelIcon} ${levelColor(`console.${event.level}`)} ${source_default.dim(content)}`,
96501
- type: "assistant"
96502
- }
96503
- ]);
96730
+ appendDisplayMessage({
96731
+ key: `console-${Date.now()}-${Math.random()}`,
96732
+ content: `${levelIcon} ${levelColor(`console.${event.level}`)} ${source_default.dim(content)}`,
96733
+ type: "assistant"
96734
+ });
96504
96735
  }
96505
96736
  } else if (event.type === "runtime_done") {
96506
96737
  if (shouldShowEvent("runtime_done", activeFilter)) {
96507
96738
  const taskName = getEventAgentName(event, agentName || "assistant");
96508
- setMessages((prev) => [
96509
- ...prev,
96510
- {
96511
- key: `runtime-done-${Date.now()}`,
96512
- content: source_default.dim(`${source_default.green("\u2713")} Done ${taskName}`),
96513
- type: "assistant"
96514
- }
96515
- ]);
96739
+ appendDisplayMessage({
96740
+ key: `runtime-done-${Date.now()}`,
96741
+ content: source_default.dim(`${source_default.green("\u2713")} Done ${taskName}`),
96742
+ type: "assistant"
96743
+ });
96516
96744
  }
96745
+ commitTerminalResponseStreamsForTask(taskInfo?.id);
96517
96746
  if (!receivedResponseSinceLastInput.current && event.content !== void 0 && taskInfo && "agent" in taskInfo) {
96518
96747
  const contentStr = typeof event.content === "string" ? event.content : JSON.stringify(event.content);
96519
96748
  clearResponseStreamsForTask(taskInfo.id, {
@@ -96523,15 +96752,12 @@ function ChatUIWithConnection({
96523
96752
  if (contentStr && contentStr !== "{}" && contentStr !== "null") {
96524
96753
  const taskName = getEventAgentName(event, agentName || "assistant");
96525
96754
  const messageContent = renderAssistantMessage(contentStr, taskName);
96526
- setMessages((prev) => [
96527
- ...prev,
96528
- {
96529
- key: `msg-${Date.now()}-${Math.random()}`,
96530
- content: messageContent,
96531
- type: "assistant",
96532
- timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
96533
- }
96534
- ]);
96755
+ appendDisplayMessage({
96756
+ key: `msg-${Date.now()}-${Math.random()}`,
96757
+ content: messageContent,
96758
+ type: "assistant",
96759
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
96760
+ });
96535
96761
  if (!firstMessageNotified.current && onFirstMessage) {
96536
96762
  firstMessageNotified.current = true;
96537
96763
  onFirstMessage();
@@ -96542,14 +96768,11 @@ function ChatUIWithConnection({
96542
96768
  }
96543
96769
  } else if (event.type === "interrupted") {
96544
96770
  clearResponseStreamsForTask(taskInfo?.id);
96545
- setMessages((prev) => [
96546
- ...prev,
96547
- {
96548
- key: `interrupted-${Date.now()}`,
96549
- content: source_default.dim("\u2298 Interrupted"),
96550
- type: "assistant"
96551
- }
96552
- ]);
96771
+ appendDisplayMessage({
96772
+ key: `interrupted-${Date.now()}`,
96773
+ content: source_default.dim("\u2298 Interrupted"),
96774
+ type: "assistant"
96775
+ });
96553
96776
  setCurrentOperation("");
96554
96777
  setIsInterrupted(true);
96555
96778
  } else if (isUnfulfilledAgentInstallRequest(event)) {
@@ -96575,7 +96798,7 @@ function ChatUIWithConnection({
96575
96798
  pollInterval.current = null;
96576
96799
  }
96577
96800
  };
96578
- }, [client, session, isReady, pendingInstallRequest]);
96801
+ }, [client, session, isReady, pendingInstallRequest, fetchEventsFn]);
96579
96802
  const handleSubmit = async (value) => {
96580
96803
  const text = value.trim();
96581
96804
  if (text === "exit" || text === "quit") {
@@ -96586,32 +96809,27 @@ function ChatUIWithConnection({
96586
96809
  }
96587
96810
  if (!text || !client || !session || !isReady) return;
96588
96811
  sentMessages.current.add(value);
96589
- setMessages((prev) => [
96590
- ...prev,
96591
- {
96592
- key: `user-${Date.now()}`,
96593
- content: `${brand(">")} ${value}`,
96594
- type: "user"
96595
- }
96596
- ]);
96812
+ commitAllTerminalResponseStreams();
96813
+ appendDisplayMessage({
96814
+ key: `user-${Date.now()}`,
96815
+ content: `${brand(">")} ${value}`,
96816
+ type: "user"
96817
+ });
96597
96818
  updateInput("");
96598
96819
  try {
96599
96820
  await client.post(`/sessions/${session.id}/events`, {
96600
96821
  content: value
96601
96822
  });
96602
96823
  receivedResponseSinceLastInput.current = false;
96603
- renderedStreamTexts.current.clear();
96824
+ renderedStreamTextLru.current.clear();
96604
96825
  setCurrentOperation("Waiting for response...");
96605
96826
  } catch (error) {
96606
96827
  debug("Send error:", error);
96607
- setMessages((prev) => [
96608
- ...prev,
96609
- {
96610
- key: `error-${Date.now()}`,
96611
- content: source_default.red("Failed to send message"),
96612
- type: "assistant"
96613
- }
96614
- ]);
96828
+ appendDisplayMessage({
96829
+ key: `error-${Date.now()}`,
96830
+ content: source_default.red("Failed to send message"),
96831
+ type: "assistant"
96832
+ });
96615
96833
  }
96616
96834
  };
96617
96835
  const activeTasksList = tasks.filter(
@@ -96701,6 +96919,18 @@ function ChatUIWithConnection({
96701
96919
  const handleInstallComplete = () => {
96702
96920
  setPendingInstallRequest(null);
96703
96921
  };
96922
+ if (!isVisible) {
96923
+ return null;
96924
+ }
96925
+ const dynamicMessageBlock = dynamicMessages.length === 0 ? null : /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column" }, dynamicMessages.map((msg, index) => /* @__PURE__ */ import_react25.default.createElement(
96926
+ Box_default,
96927
+ {
96928
+ key: msg.key,
96929
+ flexDirection: "column",
96930
+ marginTop: msg.type === "user" && index > 0 ? 1 : 0
96931
+ },
96932
+ /* @__PURE__ */ import_react25.default.createElement(Text, null, msg.content)
96933
+ )));
96704
96934
  return /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react25.default.createElement(Static, { items: messages }, (msg, index) => /* @__PURE__ */ import_react25.default.createElement(
96705
96935
  Box_default,
96706
96936
  {
@@ -96709,7 +96939,7 @@ function ChatUIWithConnection({
96709
96939
  marginTop: msg.type === "user" && index > 0 ? 1 : 0
96710
96940
  },
96711
96941
  /* @__PURE__ */ import_react25.default.createElement(Text, null, msg.content)
96712
- )), streamingMessage && /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react25.default.createElement(Text, null, streamingMessage.content)), showTaskPanel && tasks.length > 0 && currentOperation && /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ import_react25.default.createElement(TaskView, { tasks })), pendingInstallRequest && /* @__PURE__ */ import_react25.default.createElement(
96942
+ )), dynamicMessageBlock, showTaskPanel && tasks.length > 0 && currentOperation && /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ import_react25.default.createElement(TaskView, { tasks })), pendingInstallRequest && /* @__PURE__ */ import_react25.default.createElement(
96713
96943
  AgentInstallPrompt,
96714
96944
  {
96715
96945
  event: pendingInstallRequest,
@@ -96727,7 +96957,7 @@ function ChatUIWithConnection({
96727
96957
  handleSubmit,
96728
96958
  trackedTasksSize: tasks.length,
96729
96959
  setShowTaskPanel,
96730
- isActive
96960
+ isActive: isVisible
96731
96961
  }
96732
96962
  ));
96733
96963
  }
@@ -96741,7 +96971,7 @@ async function ensureAuthenticated() {
96741
96971
  const client = new GuildAPIClient();
96742
96972
  await client.get("/me");
96743
96973
  } catch {
96744
- const { clearAuthToken } = await import("./auth-CRMO5O3N.js");
96974
+ const { clearAuthToken } = await import("./auth-67G3BIAW.js");
96745
96975
  await clearAuthToken();
96746
96976
  format.error("Session expired. Run: guild auth login");
96747
96977
  process.exit(1);
@@ -96943,6 +97173,7 @@ export {
96943
97173
  WorkspaceNotConfiguredError,
96944
97174
  WorkspaceNotFoundError,
96945
97175
  ChatApp,
97176
+ ChatUIWithConnection,
96946
97177
  ensureAuthenticated,
96947
97178
  createSession,
96948
97179
  createChatCommand,
@@ -97038,4 +97269,4 @@ react-reconciler/cjs/react-reconciler-constants.development.js:
97038
97269
  * LICENSE file in the root directory of this source tree.
97039
97270
  *)
97040
97271
  */
97041
- //# sourceMappingURL=chunk-IBRKVGMZ.js.map
97272
+ //# sourceMappingURL=chunk-7JJT3RNI.js.map