@molecule/app-ide-react 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-08-28T09:55:58.055Z
6
+ Generated: 2026-08-29T01:05:39.979Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-ide-react
@@ -318,6 +318,16 @@ interface ChatPanelProps {
318
318
  onRegisterPushHandler?: (
319
319
  handler: ((conversationId: string, event: ChatStreamEvent) => void) | null,
320
320
  ) => void
321
+ /**
322
+ * Called on mount with a function that reloads chat history and converges the
323
+ * panel on the persisted transcript; called with null on unmount. The host
324
+ * should invoke it whenever its chat push channel (re)connects: a broadcast
325
+ * sent while that socket was down (a teammate's team note against a
326
+ * backgrounded tab or a slept laptop) is otherwise lost until a page
327
+ * lifecycle event happens to fire. Cheap when nothing changed — an identical
328
+ * transcript is never re-applied.
329
+ */
330
+ onRegisterHistoryReconcile?: (reconcile: (() => Promise<void>) | null) => void
321
331
  /** Changing this value submits the current input draft — used to send a prefilled prompt after the prompt→chat morph docks. */
322
332
  autoSubmitSignal?: number
323
333
  /** Seeds the input with this text on mount (prompt→chat morph), so the chat input shows the prompt before it is sent. */
@@ -1770,6 +1780,7 @@ function ChatPanel({
1770
1780
  onLoadingChange,
1771
1781
  onNavigatePreview,
1772
1782
  onRegisterPushHandler,
1783
+ onRegisterHistoryReconcile,
1773
1784
  autoSubmitSignal,
1774
1785
  initialInputValue,
1775
1786
  hideConversationMenu,
@@ -2484,6 +2495,7 @@ function ShareLinkManager({
2484
2495
  canRevoke = canManage,
2485
2496
  roles = [DEFAULT_SHARE_ROLE],
2486
2497
  initialRole = DEFAULT_SHARE_ROLE,
2498
+ refreshSignal,
2487
2499
  onCreated,
2488
2500
  onRevoked,
2489
2501
  }: {
@@ -2493,6 +2505,7 @@ function ShareLinkManager({
2493
2505
  canRevoke?: boolean
2494
2506
  roles?: readonly ShareRole[]
2495
2507
  initialRole?: ShareRole
2508
+ refreshSignal?: number
2496
2509
  onCreated?: (result: ShareLinkResult) => void
2497
2510
  onRevoked?: (id: string) => void
2498
2511
  }): JSX.Element
@@ -151,6 +151,8 @@ export interface ChatInnerProps {
151
151
  onNavigatePreview?: (path: string) => void;
152
152
  /** Registers the broadcast-chat-event handler with the host — see {@link ChatPanelProps.onRegisterPushHandler}. */
153
153
  onRegisterPushHandler?: ChatPanelProps['onRegisterPushHandler'];
154
+ /** Registers the history reconcile with the host — see {@link ChatPanelProps.onRegisterHistoryReconcile}. */
155
+ onRegisterHistoryReconcile?: ChatPanelProps['onRegisterHistoryReconcile'];
154
156
  /** Changing this value submits the current input draft (used by the prompt→chat morph). */
155
157
  autoSubmitSignal?: number;
156
158
  /** Changing this value opens the `/settings` view (used by the header gear button). */
@@ -197,7 +199,7 @@ export interface ChatInnerProps {
197
199
  * @param props - Component props (see {@link MessageItemProps}).
198
200
  * @returns The rendered chat panel element.
199
201
  */
200
- export declare function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, className, }: ChatPanelProps): JSX.Element;
202
+ export declare function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, className, }: ChatPanelProps): JSX.Element;
201
203
  export declare namespace ChatPanel {
202
204
  var displayName: string;
203
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../src/components/ChatPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAa,MAAM,OAAO,CAAA;AAY3C,OAAO,KAAK,EAAa,WAAW,EAAmB,MAAM,uBAAuB,CAAA;AAuCpF,OAAO,KAAK,EAAE,cAAc,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAevD,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,oBAAoB,CAAA;AAW3B,OAAO,KAAK,EAAsB,SAAS,EAAE,MAAM,gCAAgC,CAAA;AA6LnF,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AA+ND,UAAU,WAAW;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAm+BD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CACzD,GAAG,GAAG,CAAC,OAAO,CAoPd;AAMD,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAA;IAChB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACjD,SAAS,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,mGAAmG;IACnG,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACzD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IAClF,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,oBAAoB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAA;IACxE;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,wGAAwG;IACxG,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,mGAAmG;IACnG,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAA;IACnD,6FAA6F;IAC7F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2IAA2I;IAC3I,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAwkBD,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8FAA8F;IAC9F,eAAe,CAAC,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAA;IACnD,0GAA0G;IAC1G,uBAAuB,CAAC,EAAE,cAAc,CAAC,yBAAyB,CAAC,CAAA;IACnE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IAC/D,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IAClF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,iHAAiH;IACjH,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IAC9C,gDAAgD;IAChD,aAAa,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAA;IAC/C,6GAA6G;IAC7G,cAAc,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAA;IACjD,qHAAqH;IACrH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,8IAA8I;IAC9I,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,+GAA+G;IAC/G,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;IAClD,kHAAkH;IAClH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,iGAAiG;IACjG,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5C,iHAAiH;IACjH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,mHAAmH;IACnH,qBAAqB,CAAC,EAAE,cAAc,CAAC,uBAAuB,CAAC,CAAA;IAC/D,6GAA6G;IAC7G,0BAA0B,CAAC,EAAE,cAAc,CAAC,4BAA4B,CAAC,CAAA;IACzE,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qHAAqH;IACrH,oBAAoB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,KAAK,IAAI,CAAA;IACxE,kGAAkG;IAClG,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,yLAAyL;IACzL,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,uMAAuM;IACvM,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,4HAA4H;IAC5H,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yIAAyI;IACzI,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,8GAA8G;IAC9G,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oGAAoG;IACpG,aAAa,CAAC,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AA0zQD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,wBAA+B,EAC/B,cAAc,EAAE,wBAAwB,EACxC,OAAO,EAAE,iBAAiB,EAC1B,gBAAgB,EAAE,0BAA0B,EAC5C,eAAe,EAAE,qBAAqB,EACtC,gBAAgB,EAAE,sBAAsB,EACxC,kBAAkB,EAAE,wBAAwB,EAC5C,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,0BAA0B,EAC1B,2BAA2B,EAC3B,cAAc,EACd,iBAAiB,EACjB,KAAK,EACL,WAAW,EACX,OAAc,EACd,QAAQ,EACR,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,SAAS,EACT,WAAW,EACX,OAAO,EACP,aAAa,EACb,WAAW,EACX,SAAS,GACV,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CA2c9B;yBApgBe,SAAS"}
@@ -1218,7 +1218,7 @@ const MessageItem = memo(function MessageItem(props) {
1218
1218
  * @param props - Component props (see {@link MessageItemProps}).
1219
1219
  * @returns The rendered chat inner component.
1220
1220
  */
1221
- function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, openSettingsSignal, onManageCustomModels, modelSelectionSignal, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version, extraCommands,
1221
+ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, openSettingsSignal, onManageCustomModels, modelSelectionSignal, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version, extraCommands,
1222
1222
  // feedbackUrl: prop kept for back-compat (callers still pass it), but no longer
1223
1223
  // consumed here — its only use was the command-menu footer link removed in P3-21.
1224
1224
  }) {
@@ -1301,16 +1301,11 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1301
1301
  clearInterval(autoFixIntervalRef.current);
1302
1302
  }, []);
1303
1303
  // Ref so the stream-event callback can push activity cards without depending
1304
- // on the state setter (mirrors appendCardMessageRef).
1304
+ // on the state setter.
1305
1305
  const addActivityCardRef = useRef(() => { });
1306
- // Ref to useChat's appendCardMessage, so the broadcast path (a teammate's `card` event,
1307
- // applied through handleStreamEvent) can append a card-message to the ONE message store.
1308
- // This client's OWN `card` events are appended internally by useChat's stream handler.
1309
- const appendCardMessageRef = useRef(() => { });
1310
- // Ref to useChat's appendCompleteMessage — same contract as appendCardMessageRef, for a
1311
- // teammate's broadcast `message` event (a complete non-streaming message, e.g. a
1312
- // human-only team note). This client's OWN `message` events append internally in useChat.
1313
- const appendCompleteMessageRef = useRef(() => { });
1306
+ // (A teammate's broadcast `card` / `message` events are ingested by
1307
+ // useChat.applyRemoteEvent applyPushedStreamEvent routes every pushed frame
1308
+ // through it before this panel's handler runs, so no append refs live here.)
1314
1309
  // Kept current each render so handleStreamEvent (memoized) always calls the latest.
1315
1310
  const onReadyToBuildRef = useRef(onReadyToBuild);
1316
1311
  onReadyToBuildRef.current = onReadyToBuild;
@@ -1328,9 +1323,15 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1328
1323
  contextWindow: event.usage.contextWindow,
1329
1324
  });
1330
1325
  }
1331
- // Capture verification errors to trigger countdown after stream ends.
1326
+ // Capture verification errors to trigger countdown after stream ends
1327
+ // SENDER-ONLY: a pushed frame from a teammate's turn must not arm this
1328
+ // client's auto-fix (the sender's client owns the follow-up; two clients
1329
+ // arming it would double-send the fix).
1332
1330
  // Also drop any deferred preview error — verification's countdown handles it.
1333
- if (event.type === 'verification_result' && event.status === 'error' && event.output) {
1331
+ if (!applyingPushedRef.current &&
1332
+ event.type === 'verification_result' &&
1333
+ event.status === 'error' &&
1334
+ event.output) {
1334
1335
  pendingVerificationRef.current = {
1335
1336
  output: event.output,
1336
1337
  categories: event.categories ?? [],
@@ -1348,22 +1349,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1348
1349
  if (event.type === 'verification_result' && event.status === 'ok') {
1349
1350
  pendingVerificationRef.current = null;
1350
1351
  }
1351
- // Inline transcript CARD (model / mode / skills / custom notice). The server records it
1352
- // into the ONE message transcript and emits it here; this client's OWN stream appends
1353
- // the card-message via useChat (case 'card'). Here we ONLY handle a TEAMMATE's broadcast
1354
- // (applied through applyPushedStreamEvent → handleStreamEvent): append it to the local
1355
- // store so it shows live for the collaborator too (de-duped by id; never re-persisted —
1356
- // the originating server already persisted it, and on reload it loads with the messages).
1357
- if (event.type === 'card' && applyingPushedRef.current) {
1358
- appendCardMessageRef.current(event.id, event.timestamp, event.card);
1359
- }
1360
- // A teammate's broadcast complete message (e.g. a human-only team note) — append it
1361
- // to the local store so it shows live for the collaborator too (de-duped by id;
1362
- // never re-persisted — the originating server already persisted it). This client's
1363
- // OWN `message` stream events are appended internally by useChat.
1364
- if (event.type === 'message' && applyingPushedRef.current && event.message) {
1365
- appendCompleteMessageRef.current(event.message);
1366
- }
1352
+ // NOTE: pushed `card` / `message` events are ingested into the message store by
1353
+ // useChat.applyRemoteEvent (applyPushedStreamEvent calls it before this handler),
1354
+ // through the same append helpers as an own stream no panel-side append here.
1367
1355
  // Captured outbound side effect (email/sms/push/webhook/channel) — push an
1368
1356
  // inline activity card into the timeline. Non-text card, mirroring how
1369
1357
  // system cards are appended.
@@ -1371,9 +1359,11 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1371
1359
  addActivityCardRef.current(activityFromEvent(event.activity));
1372
1360
  }
1373
1361
  // Discovery finished and the server selected a starting point — boot the
1374
- // sandbox. The template choice is internal; this event carries no
1375
- // user-facing payload and is never rendered in the transcript.
1376
- if (event.type === 'ready_to_build') {
1362
+ // sandbox. SENDER-ONLY: the sender's client drives the boot; a watching
1363
+ // client's host follows the project's sandbox status instead of racing a
1364
+ // second boot request. The template choice is internal; this event carries
1365
+ // no user-facing payload and is never rendered in the transcript.
1366
+ if (event.type === 'ready_to_build' && !applyingPushedRef.current) {
1377
1367
  onReadyToBuildRef.current?.();
1378
1368
  }
1379
1369
  // The agent asked the IDE to reload/navigate the preview, open a file, or drive the
@@ -1501,10 +1491,13 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1501
1491
  }
1502
1492
  onFileChange?.(path, content);
1503
1493
  }, [onFileChange, onFileOpen, autoFixCountdown]);
1504
- const { messages, isLoading, isRemoteStreaming, noteRemoteStreamEvent, error, errorMeta, mode, fastMode, streamingStatus, setMode, setFastMode, sendMessage, abort, clearHistory, editQueuedMessage, deleteQueuedMessage, clearQueuedForFile, appendCardMessage, appendCompleteMessage, retryCountdown, cancelRetry, } = useChat({
1494
+ const { messages, isLoading, isRemoteStreaming, noteRemoteStreamEvent, error, errorMeta, mode, fastMode, streamingStatus, setMode, setFastMode, sendMessage, abort, clearHistory, editQueuedMessage, deleteQueuedMessage, clearQueuedForFile, applyRemoteEvent, reconcileHistory, retryCountdown, cancelRetry, } = useChat({
1505
1495
  endpoint,
1506
1496
  projectId,
1507
1497
  agentName,
1498
+ // A read-only viewer never issues chat POSTs (no resume/retry) — a live turn
1499
+ // is watched via pushed frames + the reconcile poll instead.
1500
+ readOnly: canEdit === false,
1508
1501
  // ALWAYS load history on mount. A persisted conversation MUST restore on refresh,
1509
1502
  // even when an initialMessage / initialInputValue is also present. The old condition
1510
1503
  // suppressed the load whenever a fresh message was about to be auto-sent — but on a
@@ -1530,13 +1523,15 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1530
1523
  // model. This replaces the old default of writing the legacy `chatModel`
1531
1524
  // (which silently moved BOTH modes).
1532
1525
  const liveModelMode = mode === 'plan' ? 'plan' : 'execute';
1526
+ // Target for a settings PATCH that changes agent behavior (model / effort /
1527
+ // max loops / region / auto-fix / auto-approve): name the OPEN conversation so
1528
+ // the server's shared setting card lands in the transcript members are
1529
+ // actually watching (a project can hold several conversations).
1530
+ const settingsPatchUrl = useCallback(() => `/projects/${projectId}${conversationIdRef.current
1531
+ ? `?conversationId=${encodeURIComponent(conversationIdRef.current)}`
1532
+ : ''}`, [projectId]);
1533
1533
  // Keep sendMessageRef in sync so the countdown effect can call the latest sendMessage
1534
1534
  sendMessageRef.current = sendMessage;
1535
- // Keep the card-append ref current so handleStreamEvent (memoized) can append a teammate's
1536
- // broadcast `card` event to the message store.
1537
- appendCardMessageRef.current = appendCardMessage;
1538
- // Same for a teammate's broadcast complete `message` event (e.g. a team note).
1539
- appendCompleteMessageRef.current = appendCompleteMessage;
1540
1535
  // User Stop. A stop is a user decision the platform must not overrule — so
1541
1536
  // beyond killing the stream (useChat.abort also records the stop client-side
1542
1537
  // and, via chat-abort's userInitiated flag, server-side), drop every pending
@@ -2226,17 +2221,24 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2226
2221
  }
2227
2222
  }, []);
2228
2223
  // Apply a chat event broadcast by another project member (the chat push channel). The
2229
- // originating member's SERVER already persisted everything (the transcript card-messages and
2230
- // the activity cards); this viewer only renders the broadcast live and gets the durable copy
2231
- // on reload. A pushed `card` event appends an ephemeral card-message (never persisted by this
2232
- // viewer); a pushed `activity` is flagged `received` so it renders but is not re-PUT.
2224
+ // originating member's SERVER already persisted everything; this client renders the
2225
+ // broadcast live and gets the durable copy on reload. EVERY frame of a remote turn
2226
+ // arrives here text/thinking deltas, tool events, verification, cards, the user
2227
+ // message, done and is ingested into the message store through useChat's
2228
+ // applyRemoteEvent (the same content applier as an own SSE stream), so watching a
2229
+ // teammate's turn looks exactly like running one. handleStreamEvent then handles the
2230
+ // panel-level concerns (context usage, sounds, activity cards) with the
2231
+ // applyingPushed flag gating the sender-only side effects (auto-fix, ready_to_build).
2233
2232
  const applyPushedStreamEvent = useCallback((frameConversationId, event) => {
2234
2233
  // Only apply broadcasts for the conversation this panel has open.
2235
2234
  if (frameConversationId !== conversationIdRef.current)
2236
2235
  return;
2237
- // Flag the window so a pushed activity card is marked `received` (rendered, not re-PUT);
2238
- // a pushed card-message is appended ephemerally. handleStreamEvent is synchronous, so the
2239
- // flag is set for exactly this event's handling.
2236
+ // Store ingestion first, so the transcript is current before any panel
2237
+ // side effect reads it.
2238
+ applyRemoteEvent(event);
2239
+ // Flag the window so a pushed activity card is marked `received` (rendered, not
2240
+ // re-PUT) and sender-only side effects are skipped. handleStreamEvent is
2241
+ // synchronous, so the flag is set for exactly this event's handling.
2240
2242
  applyingPushedRef.current = true;
2241
2243
  try {
2242
2244
  handleStreamEvent(event);
@@ -2249,13 +2251,22 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2249
2251
  // continuation), tell useChat so it confirms against the server's streaming
2250
2252
  // flag and keeps the Stop button visible + functional for the remote turn.
2251
2253
  noteRemoteStreamEvent();
2252
- }, [handleStreamEvent, noteRemoteStreamEvent]);
2254
+ }, [applyRemoteEvent, handleStreamEvent, noteRemoteStreamEvent]);
2253
2255
  // Register the pushed-event handler with the parent (Workspace) so it can deliver
2254
2256
  // broadcast chat events from other project members; deregister on unmount.
2255
2257
  useEffect(() => {
2256
2258
  onRegisterPushHandler?.(applyPushedStreamEvent);
2257
2259
  return () => onRegisterPushHandler?.(null);
2258
2260
  }, [onRegisterPushHandler, applyPushedStreamEvent]);
2261
+ // Register the history reconcile with the parent so it can converge this
2262
+ // panel on the persisted transcript whenever its push channel (re)connects —
2263
+ // a broadcast sent while that socket was down (a teammate's team note against
2264
+ // a backgrounded tab or a slept laptop) is otherwise lost until a page
2265
+ // lifecycle event happens to fire.
2266
+ useEffect(() => {
2267
+ onRegisterHistoryReconcile?.(reconcileHistory);
2268
+ return () => onRegisterHistoryReconcile?.(null);
2269
+ }, [onRegisterHistoryReconcile, reconcileHistory]);
2259
2270
  // Inject the user-message accent-stripe styles once (the gradient `::before` + its
2260
2271
  // keyframe can't live inline; gated on the row's data-mol-id, so no other row is
2261
2272
  // touched). Guarded by id so it injects a single time across the app.
@@ -2318,11 +2329,6 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2318
2329
  activityCardsLoadedConvRef.current = null;
2319
2330
  if (!conversationId)
2320
2331
  return;
2321
- // Activity cards carry recipients/summaries and their routes are editor+ by
2322
- // design — a viewer's fetch/persist would just 403 on every panel open
2323
- // (observed live in prod logs). Skip both for read-only viewers.
2324
- if (canEdit === false)
2325
- return;
2326
2332
  if (prevConv && prevConv !== conversationId)
2327
2333
  setActivityCards([]);
2328
2334
  let cancelled = false;
@@ -2688,10 +2694,13 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2688
2694
  setAutoCommitLoaded(true);
2689
2695
  });
2690
2696
  }, [http, projectId]);
2691
- // Re-read ONLY the persisted model fields when the host signals a model change
2692
- // (the provider modal's "Use" button sets chatModel server-side). Targeted so
2693
- // a model pick never re-hydrates the rest of the settings (auto-commit,
2694
- // skills, effort). Skips the initial 0 value mount already read them.
2697
+ // Re-read the persisted agent-behavior settings when the host signals a
2698
+ // settings change: the provider modal's "Use" button, or a resource_change
2699
+ // broadcast saying ANOTHER member changed the project (model/effort/regions/
2700
+ // max-loops/auto-fix/auto-approve) so this browser's pickers and toggles
2701
+ // match the change instead of rendering stale values under the shared setting
2702
+ // card. Deliberately does NOT touch auto-commit or skills (they carry local
2703
+ // in-session state the mount effect owns). Skips the initial 0 value.
2695
2704
  useEffect(() => {
2696
2705
  if (!modelSelectionSignal)
2697
2706
  return;
@@ -2707,10 +2716,44 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2707
2716
  setPlanModel(s.planModel);
2708
2717
  if (typeof s?.executeModel === 'string')
2709
2718
  setExecuteModel(s.executeModel);
2719
+ if (typeof s?.commitModel === 'string')
2720
+ setCommitModel(s.commitModel);
2721
+ if (typeof s?.compactModel === 'string')
2722
+ setCompactModel(s.compactModel);
2723
+ if (typeof s?.effortLevel === 'string' && s.effortLevel)
2724
+ setEffortLevel(s.effortLevel);
2725
+ if (s?.effortByMode &&
2726
+ typeof s.effortByMode === 'object' &&
2727
+ !Array.isArray(s.effortByMode)) {
2728
+ const next = {};
2729
+ for (const m of ['plan', 'execute']) {
2730
+ const raw = s.effortByMode[m];
2731
+ if (typeof raw === 'string' && raw)
2732
+ next[m] = raw;
2733
+ }
2734
+ setEffortByMode(next);
2735
+ }
2736
+ if (s?.modelRegions &&
2737
+ typeof s.modelRegions === 'object' &&
2738
+ !Array.isArray(s.modelRegions)) {
2739
+ const nextRegions = {};
2740
+ for (const [id, raw] of Object.entries(s.modelRegions)) {
2741
+ if (typeof raw === 'string' && raw in MODEL_REGION_META)
2742
+ nextRegions[id] = raw;
2743
+ }
2744
+ setModelRegions(nextRegions);
2745
+ }
2746
+ if (typeof s?.maxToolLoops === 'number')
2747
+ setCurrentMaxLoops(s.maxToolLoops);
2748
+ if (typeof s?.autoFix === 'boolean')
2749
+ setAutoFixEnabled(s.autoFix);
2750
+ if (typeof s?.autoApproveCommands === 'boolean') {
2751
+ setAutoApproveCommandsEnabled(s.autoApproveCommands);
2752
+ }
2710
2753
  })
2711
2754
  .catch(() => {
2712
- // Non-fatal: the model was persisted server-side; the picker indicator
2713
- // just won't refresh until the next full settings read.
2755
+ // Non-fatal: the change was persisted server-side; this view just won't
2756
+ // refresh until the next signal or full settings read.
2714
2757
  });
2715
2758
  }, [modelSelectionSignal, http, projectId]);
2716
2759
  // Persist the auto-commit cadence to project.settings (debounced) so it
@@ -2781,7 +2824,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
2781
2824
  // viewer's tab keeps the in-memory switch (all this session needs) and
2782
2825
  // skips a PATCH that could only 403.
2783
2826
  if (canEdit !== false) {
2784
- http.patch(`/projects/${projectId}`, { settings: { chatModel: fallback } }).catch(() => {
2827
+ http.patch(settingsPatchUrl(), { settings: { chatModel: fallback } }).catch(() => {
2785
2828
  /* persistence is best-effort; the in-memory switch is what matters */
2786
2829
  });
2787
2830
  }
@@ -3591,7 +3634,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
3591
3634
  const name = displayName ?? modelId;
3592
3635
  try {
3593
3636
  if (mode) {
3594
- await http.patch(`/projects/${projectId}`, {
3637
+ await http.patch(settingsPatchUrl(), {
3595
3638
  settings: { [modeSettingKey(mode)]: modelId },
3596
3639
  });
3597
3640
  if (mode === 'plan')
@@ -3611,7 +3654,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
3611
3654
  : t('ide.chat.compactModelSet', { name }, { defaultValue: 'Compaction model set to {{name}}' }));
3612
3655
  }
3613
3656
  else {
3614
- await http.patch(`/projects/${projectId}`, { settings: { chatModel: modelId } });
3657
+ await http.patch(settingsPatchUrl(), { settings: { chatModel: modelId } });
3615
3658
  setCurrentModel(modelId);
3616
3659
  setSavedChatModel(modelId);
3617
3660
  addSystemCard(t('ide.chat.modelSet', { name }, {
@@ -3635,7 +3678,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
3635
3678
  const nextRegions = { ...modelRegions, [modelId]: region };
3636
3679
  setModelRegions(nextRegions);
3637
3680
  try {
3638
- await http.patch(`/projects/${projectId}`, {
3681
+ await http.patch(settingsPatchUrl(), {
3639
3682
  settings: { modelRegions: nextRegions },
3640
3683
  });
3641
3684
  }
@@ -3927,7 +3970,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
3927
3970
  setInputValue('');
3928
3971
  const newValue = !autoFixEnabled;
3929
3972
  try {
3930
- await http.patch(`/projects/${projectId}`, { settings: { autoFix: newValue } });
3973
+ await http.patch(settingsPatchUrl(), { settings: { autoFix: newValue } });
3931
3974
  setAutoFixEnabled(newValue);
3932
3975
  addSystemCard(newValue
3933
3976
  ? t('ide.chat.autoFixEnabled', undefined, {
@@ -3948,7 +3991,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
3948
3991
  setInputValue('');
3949
3992
  const newValue = !autoApproveCommandsEnabled;
3950
3993
  try {
3951
- await http.patch(`/projects/${projectId}`, {
3994
+ await http.patch(settingsPatchUrl(), {
3952
3995
  settings: { autoApproveCommands: newValue },
3953
3996
  });
3954
3997
  setAutoApproveCommandsEnabled(newValue);
@@ -4320,7 +4363,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4320
4363
  }
4321
4364
  try {
4322
4365
  const nextByMode = { ...effortByMode, [targetMode]: level };
4323
- await http.patch(`/projects/${projectId}`, { settings: { effortByMode: nextByMode } });
4366
+ await http.patch(settingsPatchUrl(), { settings: { effortByMode: nextByMode } });
4324
4367
  setEffortByMode(nextByMode);
4325
4368
  addSystemCard(t('ide.chat.effort.setMode', {
4326
4369
  mode: targetMode,
@@ -4342,7 +4385,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4342
4385
  if (maxLoopsMatch) {
4343
4386
  const n = Math.max(1, Number(maxLoopsMatch[1]));
4344
4387
  try {
4345
- await http.patch(`/projects/${projectId}`, { settings: { maxToolLoops: n } });
4388
+ await http.patch(settingsPatchUrl(), { settings: { maxToolLoops: n } });
4346
4389
  setCurrentMaxLoops(n);
4347
4390
  addSystemCard(t('ide.chat.maxLoopsSet', { n }, {
4348
4391
  defaultValue: `Max tool iterations set to ${n}`,
@@ -4409,6 +4452,20 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4409
4452
  // event (persisted + broadcast to every member), which IS the visible message — so the
4410
4453
  // transcript never shows the literal "/command" text, and never shows it twice.
4411
4454
  if (matchesSideChannelCommand(allCommands, trimmed)) {
4455
+ // The sent note must not survive as a draft: the keystroke-debounced
4456
+ // persistDraft already holds the full "/teamsay …" text, and the viewer
4457
+ // re-prefill below is non-empty so setInputValue never clears it — a
4458
+ // reload then reopened the already-SENT message in the composer. Cancel
4459
+ // any pending draft write and drop the stored draft; the mount prefill
4460
+ // recreates the bare prefix.
4461
+ if (draftTimerRef.current)
4462
+ clearTimeout(draftTimerRef.current);
4463
+ try {
4464
+ sessionStorage.removeItem(draftKey);
4465
+ }
4466
+ catch (_error) {
4467
+ /* sessionStorage unavailable — draft persistence is best-effort */
4468
+ }
4412
4469
  // A viewer's composer is the team-chat box — re-fill the /teamsay prefix
4413
4470
  // after each sent team message so the next one is one keystroke away.
4414
4471
  if (canEdit === false)
@@ -4915,6 +4972,15 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4915
4972
  // unrenderable card (a custom event with no registered factory, or a non-execute mode) so
4916
4973
  // the timeline simply omits it.
4917
4974
  const cardEventToSystemCard = useCallback((cardEvent, id, timestamp) => {
4975
+ // Suffix a card's copy with the member who made the change, when the
4976
+ // server attributed one — so a teammate watching knows WHO flipped the
4977
+ // model/effort/mode, live and on reload.
4978
+ const withBy = (text) => {
4979
+ const by = cardEvent.by;
4980
+ return by
4981
+ ? t('ide.chat.cardBy', { text, name: by }, { defaultValue: '{{text}} — {{name}}' })
4982
+ : text;
4983
+ };
4918
4984
  switch (cardEvent.kind) {
4919
4985
  case 'model': {
4920
4986
  const label = cardEvent.label || cardEvent.model;
@@ -4926,9 +4992,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4926
4992
  const regionCode = def && def.provider !== 'custom' ? effectiveModelRegion(def).toUpperCase() : null;
4927
4993
  return {
4928
4994
  id,
4929
- text: regionCode
4995
+ text: withBy(regionCode
4930
4996
  ? t('ide.chat.modelInUseRegion', { model: label, region: regionCode }, { defaultValue: 'Now using {{model}} ({{region}})' })
4931
- : t('ide.chat.modelInUse', { model: label }, { defaultValue: 'Now using {{model}}' }),
4997
+ : t('ide.chat.modelInUse', { model: label }, { defaultValue: 'Now using {{model}}' })),
4932
4998
  timestamp,
4933
4999
  };
4934
5000
  }
@@ -4939,7 +5005,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4939
5005
  if (cardEvent.mode === 'plan') {
4940
5006
  return {
4941
5007
  id,
4942
- text: t('ide.chat.phasePlanning', undefined, { defaultValue: '📝 Plan mode' }),
5008
+ text: withBy(t('ide.chat.phasePlanning', undefined, { defaultValue: '📝 Plan mode' })),
4943
5009
  timestamp,
4944
5010
  };
4945
5011
  }
@@ -4947,9 +5013,56 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
4947
5013
  return null;
4948
5014
  return {
4949
5015
  id,
4950
- text: t('ide.chat.phaseBuilding', undefined, { defaultValue: '🔨 Building your app' }),
5016
+ text: withBy(t('ide.chat.phaseBuilding', undefined, { defaultValue: '🔨 Building your app' })),
4951
5017
  timestamp,
4952
5018
  };
5019
+ case 'setting': {
5020
+ // A Synthase-altering setting changed (effort / fast mode / max loops /
5021
+ // region / auto-fix / auto-approve) — announced to every member, live
5022
+ // and on reload. Copy reuses the same localized strings as the local
5023
+ // confirmation cards, so the shared card reads identically.
5024
+ let text = null;
5025
+ if (cardEvent.setting === 'effort') {
5026
+ const level = String(cardEvent.value ?? 'default');
5027
+ const cardMode = cardEvent.mode ?? '';
5028
+ text = cardEvent.label
5029
+ ? t('ide.chat.effort.setMode', { mode: cardMode, level, model: cardEvent.label }, { defaultValue: 'Reasoning effort for {{mode}} set to {{level}} ({{model}}).' })
5030
+ : t('ide.chat.setting.effort', { mode: cardMode, level }, { defaultValue: 'Reasoning effort for {{mode}} set to {{level}}.' });
5031
+ }
5032
+ else if (cardEvent.setting === 'fastMode') {
5033
+ text = cardEvent.value
5034
+ ? t('ide.chat.fastModeOn', undefined, {
5035
+ defaultValue: 'Fast mode on — faster responses at a higher rate',
5036
+ })
5037
+ : t('ide.chat.fastModeOff', undefined, { defaultValue: 'Fast mode off' });
5038
+ }
5039
+ else if (cardEvent.setting === 'maxToolLoops') {
5040
+ text = t('ide.chat.maxLoopsSet', { n: Number(cardEvent.value ?? 0) }, { defaultValue: 'Max tool iterations set to {{n}}' });
5041
+ }
5042
+ else if (cardEvent.setting === 'region') {
5043
+ text = t('ide.chat.modelInUseRegion', {
5044
+ model: cardEvent.label ?? '',
5045
+ region: String(cardEvent.value ?? '').toUpperCase(),
5046
+ }, { defaultValue: 'Now using {{model}} ({{region}})' });
5047
+ }
5048
+ else if (cardEvent.setting === 'autoFix') {
5049
+ text = cardEvent.value
5050
+ ? t('ide.chat.autoFixEnabled', undefined, { defaultValue: 'Auto-fix enabled.' })
5051
+ : t('ide.chat.autoFixDisabled', undefined, { defaultValue: 'Auto-fix disabled.' });
5052
+ }
5053
+ else if (cardEvent.setting === 'autoApprove') {
5054
+ text = cardEvent.value
5055
+ ? t('ide.chat.autoApproveEnabled', undefined, {
5056
+ defaultValue: 'Auto-approve on — destructive commands run without asking. The exfiltration guard still asks. Turn off with /autoapprove.',
5057
+ })
5058
+ : t('ide.chat.autoApproveDisabled', undefined, {
5059
+ defaultValue: 'Auto-approve off — destructive commands ask before running.',
5060
+ });
5061
+ }
5062
+ if (!text)
5063
+ return null;
5064
+ return { id, text: withBy(text), timestamp };
5065
+ }
4953
5066
  case 'skills':
4954
5067
  return {
4955
5068
  id,
@@ -5317,7 +5430,10 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
5317
5430
  }, children: [_jsx(Icon, { name: "people", size: CHAT_CARD_ICON_SIZE, "aria-hidden": "true", style: { flexShrink: 0, marginTop: 1, color: NOTICE_TONE.gold.accent } }), _jsx("span", { style: { flex: 1 }, children: t('ide.chat.viewerReadOnly', undefined, {
5318
5431
  defaultValue: "You have view-only access, so you can't run the assistant here. You can still read along and use /teamsay to message the team.",
5319
5432
  }) })] })) : null) : (_jsx("div", { className: cm.cn(cm.textSize('sm'), cm.sp('p', 2), cm.sp('mb', 2), cm.bgErrorSubtle, cm.textError), style: { borderRadius: '6px' }, children: error }))), (() => {
5320
- const showActivity = isLoading || awaitingSandboxBoot;
5433
+ // A remote turn (a teammate's send, another tab, a server-side
5434
+ // continuation) shows the same live activity indicator as an own send —
5435
+ // watchers see Synthase working, not a frozen transcript.
5436
+ const showActivity = isLoading || awaitingSandboxBoot || isRemoteStreaming;
5321
5437
  const streamingMsg = isLoading
5322
5438
  ? [...visibleMessages].reverse().find((m) => m.isStreaming)
5323
5439
  : undefined;
@@ -7068,7 +7184,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7068
7184
  * @param props - Component props (see {@link MessageItemProps}).
7069
7185
  * @returns The rendered chat panel element.
7070
7186
  */
7071
- export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit = true, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, className, }) {
7187
+ export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit = true, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, className, }) {
7072
7188
  const cm = getClassMap();
7073
7189
  // Share management may be gated ABOVE canEdit by the host (see
7074
7190
  // ChatPanelProps.canShare) — gates the built-in header share button here and
@@ -7281,7 +7397,7 @@ export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessag
7281
7397
  textOverflow: 'ellipsis',
7282
7398
  whiteSpace: 'nowrap',
7283
7399
  width: '100%',
7284
- }, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, isAnonymous: isAnonymous, canEdit: canEdit, canShare: shareAllowed, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onRenderError: onRenderError, onProfileClick: onProfileClick, currentUserId: currentUserId, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, extraCommands: extraCommands, feedbackUrl: feedbackUrl }, chatKey)] }));
7400
+ }, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, isAnonymous: isAnonymous, canEdit: canEdit, canShare: shareAllowed, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onRenderError: onRenderError, onProfileClick: onProfileClick, currentUserId: currentUserId, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, onRegisterHistoryReconcile: onRegisterHistoryReconcile, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, extraCommands: extraCommands, feedbackUrl: feedbackUrl }, chatKey)] }));
7285
7401
  }
7286
7402
  ChatPanel.displayName = 'ChatPanel';
7287
7403
  //# sourceMappingURL=ChatPanel.js.map