@percena/weft-react 0.1.4 → 0.1.5-next.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.
package/dist/index.js CHANGED
@@ -166,7 +166,13 @@ import { createContext as createContext3, useContext as useContext3 } from "reac
166
166
  import { jsx as jsx32 } from "react/jsx-runtime";
167
167
  import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
168
168
  import { jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
169
- import { useCallback as useCallback8, useRef as useRef7, useState as useState10, useEffect as useEffect6 } from "react";
169
+ import { useState as useState10, useEffect as useEffect6 } from "react";
170
+ import { jsx as jsx35 } from "react/jsx-runtime";
171
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
172
+ import { useEffect as useEffect7 } from "react";
173
+ import { jsx as jsx37 } from "react/jsx-runtime";
174
+ import { jsx as jsx38, jsxs as jsxs20 } from "react/jsx-runtime";
175
+ import { useCallback as useCallback8, useRef as useRef7, useState as useState11, useEffect as useEffect8 } from "react";
170
176
  function getAssistantTurnUiKey(turn, index) {
171
177
  if (turn.response?.messageId) {
172
178
  return `assistant:msg:${turn.response.messageId}`;
@@ -5117,6 +5123,162 @@ function PendingIndicator({
5117
5123
  delay
5118
5124
  )) }) });
5119
5125
  }
5126
+ function AssistantTurnCard({
5127
+ sessionId,
5128
+ turn,
5129
+ isLast,
5130
+ onInspectActivity
5131
+ }) {
5132
+ const [isExpanded, setIsExpanded] = useState10(true);
5133
+ const [expandedActivityGroups, setExpandedActivityGroups] = useState10(/* @__PURE__ */ new Set());
5134
+ useEffect6(() => {
5135
+ if (turn.isStreaming) {
5136
+ setIsExpanded(true);
5137
+ }
5138
+ }, [turn.isStreaming]);
5139
+ return /* @__PURE__ */ jsx35(
5140
+ TurnCard,
5141
+ {
5142
+ sessionId,
5143
+ turnId: turn.turnId,
5144
+ activities: turn.activities,
5145
+ response: turn.response,
5146
+ intent: turn.intent,
5147
+ isStreaming: turn.isStreaming,
5148
+ isComplete: turn.isComplete,
5149
+ isExpanded,
5150
+ onExpandedChange: setIsExpanded,
5151
+ expandedActivityGroups,
5152
+ onExpandedActivityGroupsChange: setExpandedActivityGroups,
5153
+ onOpenActivityDetails: onInspectActivity,
5154
+ hasEditOrWriteActivities: turn.activities.some(
5155
+ (activity) => activity.toolName === "Edit" || activity.toolName === "Write"
5156
+ ),
5157
+ todos: turn.todos,
5158
+ isLastResponse: isLast,
5159
+ displayMode: "detailed",
5160
+ animateResponse: true,
5161
+ annotationInteractionMode: "tooltip-only"
5162
+ }
5163
+ );
5164
+ }
5165
+ function ActivityInspector({
5166
+ activity,
5167
+ onClose
5168
+ }) {
5169
+ if (!activity) {
5170
+ return /* @__PURE__ */ jsx36("div", { className: "rounded-[8px] bg-background shadow-minimal p-4 text-[13px] text-muted-foreground", children: "Select an activity from the turn card to inspect its input and output." });
5171
+ }
5172
+ return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col overflow-hidden", children: [
5173
+ /* @__PURE__ */ jsxs19("div", { className: "flex items-start justify-between gap-3 border-b border-border px-4 py-3", children: [
5174
+ /* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
5175
+ /* @__PURE__ */ jsx36("div", { className: "truncate text-[13px] font-medium text-foreground", children: activity.displayName ?? activity.toolName ?? "Activity" }),
5176
+ /* @__PURE__ */ jsx36("div", { className: "mt-1 text-[12px] text-muted-foreground", children: activity.intent ?? activity.status ?? "unknown" })
5177
+ ] }),
5178
+ onClose && /* @__PURE__ */ jsx36(
5179
+ "button",
5180
+ {
5181
+ type: "button",
5182
+ onClick: onClose,
5183
+ className: "flex h-7 w-7 items-center justify-center rounded-[6px] text-[16px] leading-none text-muted-foreground transition hover:bg-foreground/[0.06] hover:text-foreground",
5184
+ "aria-label": "Close activity details",
5185
+ children: "\u2715"
5186
+ }
5187
+ )
5188
+ ] }),
5189
+ /* @__PURE__ */ jsxs19("div", { className: "overflow-y-auto space-y-4 p-4", children: [
5190
+ activity.toolInput && /* @__PURE__ */ jsxs19("div", { children: [
5191
+ /* @__PURE__ */ jsx36("div", { className: "mb-2 text-[12px] font-medium text-muted-foreground", children: "Input" }),
5192
+ /* @__PURE__ */ jsx36("pre", { className: "max-h-[280px] overflow-auto rounded-[6px] bg-foreground/[0.04] p-3 text-[12px] leading-relaxed text-foreground", children: JSON.stringify(activity.toolInput, null, 2) })
5193
+ ] }),
5194
+ activity.error && /* @__PURE__ */ jsxs19("div", { children: [
5195
+ /* @__PURE__ */ jsx36("div", { className: "mb-2 text-[12px] font-medium text-muted-foreground", children: "Error" }),
5196
+ /* @__PURE__ */ jsx36("pre", { className: "max-h-[320px] overflow-auto whitespace-pre-wrap rounded-[6px] bg-foreground/[0.04] p-3 text-[12px] leading-relaxed text-foreground", children: activity.error })
5197
+ ] }),
5198
+ activity.content && !activity.error && /* @__PURE__ */ jsxs19("div", { children: [
5199
+ /* @__PURE__ */ jsx36("div", { className: "mb-2 text-[12px] font-medium text-muted-foreground", children: "Output" }),
5200
+ /* @__PURE__ */ jsx36("div", { className: "max-h-[320px] overflow-y-auto rounded-[6px] bg-foreground/[0.04] px-3 py-2 text-[12px] text-foreground", children: /* @__PURE__ */ jsx36(Markdown, { mode: "minimal", className: "text-[12px] leading-relaxed", children: activity.content }) })
5201
+ ] })
5202
+ ] })
5203
+ ] });
5204
+ }
5205
+ function ActivityDetailsPanel({
5206
+ activity,
5207
+ onClose
5208
+ }) {
5209
+ useEffect7(() => {
5210
+ if (!activity) return;
5211
+ const handleKeyDown = (e) => {
5212
+ if (e.key === "Escape") onClose();
5213
+ };
5214
+ window.addEventListener("keydown", handleKeyDown);
5215
+ return () => window.removeEventListener("keydown", handleKeyDown);
5216
+ }, [activity, onClose]);
5217
+ if (!activity) return null;
5218
+ return /* @__PURE__ */ jsx37(
5219
+ "div",
5220
+ {
5221
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-background/60 backdrop-blur-sm",
5222
+ onClick: onClose,
5223
+ children: /* @__PURE__ */ jsx37(
5224
+ "div",
5225
+ {
5226
+ className: "relative w-full max-w-[640px] max-h-[80vh] overflow-hidden rounded-[12px] border border-border bg-background shadow-strong mx-4",
5227
+ onClick: (e) => e.stopPropagation(),
5228
+ children: /* @__PURE__ */ jsx37(ActivityInspector, { activity, onClose })
5229
+ }
5230
+ )
5231
+ }
5232
+ );
5233
+ }
5234
+ var PERMISSION_CONFIG = [
5235
+ { mode: "safe", label: "Explore", description: "Read-only planning and inspection.", icon: "\u25CE" },
5236
+ { mode: "ask", label: "Ask", description: "Review changes before execution.", icon: "\u24D8" },
5237
+ { mode: "allow-all", label: "Execute", description: "Allow edits and commands in this session.", icon: "\u21C4" }
5238
+ ];
5239
+ function PermissionModeMenu({
5240
+ value,
5241
+ onChange,
5242
+ onClose,
5243
+ isOpen,
5244
+ onToggle
5245
+ }) {
5246
+ const selected = PERMISSION_CONFIG.find((o) => o.mode === value) ?? PERMISSION_CONFIG[1];
5247
+ return /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
5248
+ isOpen && /* @__PURE__ */ jsx38("div", { className: "absolute bottom-[calc(100%+6px)] left-0 z-20 w-[204px] rounded-[9px] border border-border bg-background p-1.5 shadow-modal-small", children: /* @__PURE__ */ jsx38("div", { className: "space-y-0.5", children: PERMISSION_CONFIG.map((option) => /* @__PURE__ */ jsxs20(
5249
+ "button",
5250
+ {
5251
+ type: "button",
5252
+ onClick: () => {
5253
+ onChange(option.mode);
5254
+ onClose?.();
5255
+ },
5256
+ className: `flex h-8 w-full items-center gap-2 rounded-[6px] px-2 text-left text-[12px] transition ${option.mode === value ? "bg-foreground/[0.08] text-foreground" : "text-muted-foreground hover:bg-foreground/[0.05] hover:text-foreground"}`,
5257
+ children: [
5258
+ /* @__PURE__ */ jsx38("span", { className: "w-4 text-center text-[12px]", children: option.icon }),
5259
+ /* @__PURE__ */ jsx38("span", { className: "flex-1", children: option.label }),
5260
+ option.mode === value && /* @__PURE__ */ jsx38("span", { "aria-hidden": "true", className: "text-[12px] text-foreground", children: "\u25CF" })
5261
+ ]
5262
+ },
5263
+ option.mode
5264
+ )) }) }),
5265
+ /* @__PURE__ */ jsxs20(
5266
+ "button",
5267
+ {
5268
+ type: "button",
5269
+ "aria-haspopup": "menu",
5270
+ "aria-expanded": isOpen,
5271
+ onClick: onToggle,
5272
+ className: "inline-flex h-8 items-center gap-1.5 rounded-[7px] border border-border bg-foreground/[0.035] px-2.5 text-[12px] text-foreground transition hover:bg-foreground/[0.06]",
5273
+ children: [
5274
+ /* @__PURE__ */ jsx38("span", { className: "text-muted-foreground", children: selected.icon }),
5275
+ /* @__PURE__ */ jsx38("span", { children: selected.label }),
5276
+ /* @__PURE__ */ jsx38("span", { className: "text-muted-foreground", children: "\u2304" })
5277
+ ]
5278
+ }
5279
+ )
5280
+ ] });
5281
+ }
5120
5282
  function generateMessageId2() {
5121
5283
  return generateMessageId();
5122
5284
  }
@@ -5199,6 +5361,24 @@ function handleTextDelta(state, event) {
5199
5361
  const streamingIndex = findStreamingMessage(session.messages, event.turnId);
5200
5362
  if (streamingIndex !== -1) {
5201
5363
  const currentMsg = session.messages[streamingIndex];
5364
+ if (currentMsg.isIntermediate && !event.isIntermediate) {
5365
+ const closedSession = updateMessageAt(session, streamingIndex, {
5366
+ isStreaming: false
5367
+ });
5368
+ const newMessage2 = {
5369
+ id: generateMessageId2(),
5370
+ role: "assistant",
5371
+ content: event.delta,
5372
+ timestamp: event.timestamp ?? Date.now(),
5373
+ isStreaming: true,
5374
+ isPending: true,
5375
+ turnId: event.turnId
5376
+ };
5377
+ return {
5378
+ session: appendMessage(closedSession, newMessage2, false),
5379
+ streaming: { content: event.delta, turnId: event.turnId }
5380
+ };
5381
+ }
5202
5382
  const updatedSession = updateMessageAt(session, streamingIndex, {
5203
5383
  content: currentMsg.content + event.delta
5204
5384
  });
@@ -5211,7 +5391,8 @@ function handleTextDelta(state, event) {
5211
5391
  timestamp: event.timestamp ?? Date.now(),
5212
5392
  isStreaming: true,
5213
5393
  isPending: true,
5214
- turnId: event.turnId
5394
+ turnId: event.turnId,
5395
+ ...event.isIntermediate ? { isIntermediate: true } : {}
5215
5396
  };
5216
5397
  return {
5217
5398
  session: appendMessage(session, newMessage, false),
@@ -5221,12 +5402,15 @@ function handleTextDelta(state, event) {
5221
5402
  function handleTextComplete(state, event) {
5222
5403
  const { session, streaming } = state;
5223
5404
  let msgIndex = findStreamingMessage(session.messages, event.turnId);
5405
+ if (msgIndex !== -1 && event.isIntermediate && !session.messages[msgIndex].isIntermediate) {
5406
+ msgIndex = -1;
5407
+ }
5224
5408
  if (msgIndex === -1) {
5225
5409
  msgIndex = findAssistantMessage(session.messages, event.turnId);
5226
5410
  }
5227
5411
  if (msgIndex !== -1) {
5228
5412
  const existingMsg = session.messages[msgIndex];
5229
- if (!existingMsg.isStreaming && existingMsg.isIntermediate && event.isIntermediate) {
5413
+ if (!existingMsg.isStreaming && existingMsg.isIntermediate && !existingMsg.isPending) {
5230
5414
  msgIndex = -1;
5231
5415
  }
5232
5416
  }
@@ -6294,14 +6478,16 @@ function mapCoreEventToProcessorEvent(coreEvent, sessionId) {
6294
6478
  type: "text_delta",
6295
6479
  sessionId,
6296
6480
  delta: coreEvent.text,
6297
- turnId: coreEvent.turnId
6481
+ turnId: coreEvent.turnId,
6482
+ isIntermediate: true
6298
6483
  };
6299
6484
  case "reasoning":
6300
6485
  return {
6301
6486
  type: "text_complete",
6302
6487
  sessionId,
6303
6488
  text: coreEvent.text,
6304
- turnId: coreEvent.turnId
6489
+ turnId: coreEvent.turnId,
6490
+ isIntermediate: true
6305
6491
  };
6306
6492
  case "permission_response":
6307
6493
  return {
@@ -6341,7 +6527,8 @@ function mapTimelineEnvelopeToProcessorEvent(envelope) {
6341
6527
  sessionId,
6342
6528
  delta: item.text,
6343
6529
  turnId: item.turnId,
6344
- timestamp
6530
+ timestamp,
6531
+ ...item.type === "reasoning_delta" && { isIntermediate: true }
6345
6532
  };
6346
6533
  case "assistant_message":
6347
6534
  case "reasoning":
@@ -6351,7 +6538,8 @@ function mapTimelineEnvelopeToProcessorEvent(envelope) {
6351
6538
  text: item.text,
6352
6539
  turnId: item.turnId,
6353
6540
  timestamp,
6354
- messageId: item.messageId
6541
+ messageId: item.messageId,
6542
+ ...item.type === "reasoning" && { isIntermediate: true }
6355
6543
  };
6356
6544
  case "tool_call":
6357
6545
  return {
@@ -6518,6 +6706,10 @@ function normalizeTimelineToolName(name) {
6518
6706
  return name;
6519
6707
  }
6520
6708
  function optionalToolDisplayName(toolName, detail) {
6709
+ if (detail && typeof detail === "object") {
6710
+ const explicit = detail.displayName;
6711
+ if (typeof explicit === "string" && explicit) return { toolDisplayName: explicit };
6712
+ }
6521
6713
  if (toolName !== "commandExecution") return {};
6522
6714
  const displayName = commandDisplayName(detail);
6523
6715
  return displayName ? { toolDisplayName: displayName } : {};
@@ -6653,10 +6845,10 @@ function normalizeTokenUsage(usage) {
6653
6845
  }
6654
6846
  function useEventProcessor(options) {
6655
6847
  const { eventSource, sessionId, workspaceId, workspaceName, onEffect, onError, onClose } = options;
6656
- const [session, setSession] = useState10(null);
6848
+ const [session, setSession] = useState11(null);
6657
6849
  const sessionRef = useRef7(null);
6658
6850
  const streamingStates = useRef7(/* @__PURE__ */ new Map());
6659
- const [isConnected, setIsConnected] = useState10(false);
6851
+ const [isConnected, setIsConnected] = useState11(false);
6660
6852
  const processedCount = useRef7(0);
6661
6853
  const processAgentEvent = useCallback8((event) => {
6662
6854
  const processorEvent = mapCoreEventToProcessorEvent(event, sessionId);
@@ -6678,7 +6870,7 @@ function useEventProcessor(options) {
6678
6870
  effects: result.effects
6679
6871
  };
6680
6872
  }, [sessionId, workspaceId, workspaceName]);
6681
- useEffect6(() => {
6873
+ useEffect8(() => {
6682
6874
  eventSource.connect(
6683
6875
  (coreEvent) => {
6684
6876
  const result = processAgentEvent(coreEvent);
@@ -6837,7 +7029,7 @@ var InProcessEventSource = class {
6837
7029
 
6838
7030
  // ../local-chat/dist/index.js
6839
7031
  import { useState as useState22 } from "react";
6840
- import { useCallback as useCallback9, useEffect as useEffect7, useMemo as useMemo8, useRef as useRef8, useState as useState11 } from "react";
7032
+ import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef8, useState as useState12 } from "react";
6841
7033
 
6842
7034
  // ../timeline/dist/index.js
6843
7035
  function createTimelineCursor(cursor) {
@@ -6885,7 +7077,7 @@ function timelineKey(item) {
6885
7077
  }
6886
7078
 
6887
7079
  // ../local-chat/dist/index.js
6888
- import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
7080
+ import { jsx as jsx39, jsxs as jsxs21 } from "react/jsx-runtime";
6889
7081
  import { useCallback as useCallback22, useEffect as useEffect22, useMemo as useMemo22, useRef as useRef22, useState as useState32 } from "react";
6890
7082
  import { jsx as jsx210, jsxs as jsxs22 } from "react/jsx-runtime";
6891
7083
  function createAgentChatPanelModel(args) {
@@ -6974,8 +7166,8 @@ function createTimelineDetailItems(timeline) {
6974
7166
  }
6975
7167
  function useAgentChatSession(options) {
6976
7168
  const { runtime, workspaceId = "local-workspace", workspaceName = "Local Workspace" } = options;
6977
- const [auth, setAuth] = useState11(null);
6978
- const [error, setError] = useState11(null);
7169
+ const [auth, setAuth] = useState12(null);
7170
+ const [error, setError] = useState12(null);
6979
7171
  const processor = useEventProcessor({
6980
7172
  eventSource: runtime.events,
6981
7173
  sessionId: runtime.sessionId,
@@ -7022,13 +7214,13 @@ function useAgentChatSession(options) {
7022
7214
  }
7023
7215
  function useTimelineAgentChatSession(options) {
7024
7216
  const { runtime, workspaceId = "local-workspace", workspaceName = "Local Workspace" } = options;
7025
- const [timeline, setTimeline] = useState11([]);
7026
- const [capabilityReport, setCapabilityReport] = useState11(null);
7027
- const [error, setError] = useState11(null);
7028
- const [isReconnecting, setIsReconnecting] = useState11(false);
7029
- const [hasGap, setHasGap] = useState11(false);
7217
+ const [timeline, setTimeline] = useState12([]);
7218
+ const [capabilityReport, setCapabilityReport] = useState12(null);
7219
+ const [error, setError] = useState12(null);
7220
+ const [isReconnecting, setIsReconnecting] = useState12(false);
7221
+ const [hasGap, setHasGap] = useState12(false);
7030
7222
  const lastCursorRef = useRef8(null);
7031
- useEffect7(() => {
7223
+ useEffect9(() => {
7032
7224
  let catchupAbort = false;
7033
7225
  const onEvent = (envelope) => {
7034
7226
  lastCursorRef.current = { epoch: envelope.epoch, afterSeq: envelope.seq };
@@ -7334,8 +7526,8 @@ function AgentChatPanel({
7334
7526
  }
7335
7527
  }
7336
7528
  const storedSession = chat.session ? toStoredSession(chat.session, workspaceId) : createEmptyStoredSession(runtime.sessionId, workspaceId, workspaceName);
7337
- const footer = /* @__PURE__ */ jsxs19("form", { onSubmit: handleSubmit, className: "flex gap-2 p-3", children: [
7338
- /* @__PURE__ */ jsx35(
7529
+ const footer = /* @__PURE__ */ jsxs21("form", { onSubmit: handleSubmit, className: "flex gap-2 p-3", children: [
7530
+ /* @__PURE__ */ jsx39(
7339
7531
  "textarea",
7340
7532
  {
7341
7533
  value: draft,
@@ -7345,7 +7537,7 @@ function AgentChatPanel({
7345
7537
  className: "min-h-10 flex-1 resize-none rounded-md border px-3 py-2 text-sm"
7346
7538
  }
7347
7539
  ),
7348
- /* @__PURE__ */ jsx35(
7540
+ /* @__PURE__ */ jsx39(
7349
7541
  "button",
7350
7542
  {
7351
7543
  type: "submit",
@@ -7354,7 +7546,7 @@ function AgentChatPanel({
7354
7546
  children: "Send"
7355
7547
  }
7356
7548
  ),
7357
- chat.isRunning && /* @__PURE__ */ jsx35(
7549
+ chat.isRunning && /* @__PURE__ */ jsx39(
7358
7550
  "button",
7359
7551
  {
7360
7552
  type: "button",
@@ -7364,9 +7556,9 @@ function AgentChatPanel({
7364
7556
  }
7365
7557
  )
7366
7558
  ] });
7367
- return /* @__PURE__ */ jsxs19("div", { className, children: [
7368
- chat.error && /* @__PURE__ */ jsx35("div", { className: "border-b px-3 py-2 text-sm text-red-600", children: chat.error.message }),
7369
- /* @__PURE__ */ jsx35(
7559
+ return /* @__PURE__ */ jsxs21("div", { className, children: [
7560
+ chat.error && /* @__PURE__ */ jsx39("div", { className: "border-b px-3 py-2 text-sm text-red-600", children: chat.error.message }),
7561
+ /* @__PURE__ */ jsx39(
7370
7562
  SessionViewer,
7371
7563
  {
7372
7564
  session: storedSession,
@@ -7442,10 +7634,7 @@ function TimelineAgentChatPanel({
7442
7634
  const [selectedActivity, setSelectedActivity] = useState32(null);
7443
7635
  const [selectedDetail, setSelectedDetail] = useState32(null);
7444
7636
  const [permissionMode, setPermissionMode] = useState32("ask");
7445
- const [turnExpandOverride, setTurnExpandOverride] = useState32({});
7446
- const handleTurnExpandedChange = useCallback22((turnId, expanded) => {
7447
- setTurnExpandOverride((prev) => ({ ...prev, [turnId]: expanded }));
7448
- }, []);
7637
+ const [isPermMenuOpen, setIsPermMenuOpen] = useState32(false);
7449
7638
  const runtimeState = runtime.getState();
7450
7639
  const isWaitingPermission = runtimeState.status === "waiting_for_permission";
7451
7640
  const waitingRequestId = runtimeState.waitingPermissionRequestId;
@@ -7499,28 +7688,13 @@ function TimelineAgentChatPanel({
7499
7688
  return /* @__PURE__ */ jsx210("div", { className: "flex justify-end py-1", children: /* @__PURE__ */ jsx210(UserMessageBubble, { content: turn.message.content }) }, `user-${turn.message.id}`);
7500
7689
  }
7501
7690
  if (turn.type === "assistant") {
7502
- const isLast = index === chat.turns.length - 1;
7503
- const defaultExpanded = turn.isStreaming || isLast && chat.isRunning;
7504
- const isExpanded = turnExpandOverride[turn.turnId] ?? defaultExpanded;
7505
7691
  return /* @__PURE__ */ jsx210(
7506
- TurnCard,
7692
+ AssistantTurnCard,
7507
7693
  {
7508
7694
  sessionId: workspaceId,
7509
- turnId: turn.turnId,
7510
- activities: turn.activities,
7511
- response: turn.response,
7512
- intent: turn.intent,
7513
- isStreaming: turn.isStreaming,
7514
- isComplete: turn.isComplete,
7515
- isExpanded,
7516
- onExpandedChange: (expanded) => handleTurnExpandedChange(turn.turnId, expanded),
7517
- onOpenActivityDetails: setSelectedActivity,
7518
- hasEditOrWriteActivities: turn.activities.some(
7519
- (a) => a.toolName === "Edit" || a.toolName === "Write"
7520
- ),
7521
- todos: turn.todos,
7522
- isLastResponse: isLast,
7523
- displayMode: "detailed"
7695
+ turn,
7696
+ isLast: index === chat.turns.length - 1,
7697
+ onInspectActivity: setSelectedActivity
7524
7698
  },
7525
7699
  `assistant-${turn.turnId}`
7526
7700
  );
@@ -7610,24 +7784,19 @@ function TimelineAgentChatPanel({
7610
7784
  }
7611
7785
  )
7612
7786
  ] }),
7613
- /* @__PURE__ */ jsxs22("label", { className: "flex items-center gap-2 text-[12px] text-muted-foreground", children: [
7614
- /* @__PURE__ */ jsx210("span", { className: "shrink-0", children: "Tool permissions" }),
7615
- /* @__PURE__ */ jsxs22(
7616
- "select",
7617
- {
7618
- value: permissionMode,
7619
- onChange: (e) => setPermissionMode(e.currentTarget.value),
7620
- className: "rounded-[6px] border border-border bg-background px-2 py-1 text-[12px] text-foreground outline-none focus:ring-1 focus:ring-accent",
7621
- children: [
7622
- /* @__PURE__ */ jsx210("option", { value: "ask", children: "Ask before each tool" }),
7623
- /* @__PURE__ */ jsx210("option", { value: "allow-all", children: "Auto-run (no prompts)" })
7624
- ]
7625
- }
7626
- )
7627
- ] })
7787
+ /* @__PURE__ */ jsx210(
7788
+ PermissionModeMenu,
7789
+ {
7790
+ value: permissionMode,
7791
+ onChange: setPermissionMode,
7792
+ onClose: () => setIsPermMenuOpen(false),
7793
+ isOpen: isPermMenuOpen,
7794
+ onToggle: () => setIsPermMenuOpen((o) => !o)
7795
+ }
7796
+ )
7628
7797
  ] }) }),
7629
- selectedActivity && /* @__PURE__ */ jsx210(
7630
- ActivityDetailOverlay,
7798
+ /* @__PURE__ */ jsx210(
7799
+ ActivityDetailsPanel,
7631
7800
  {
7632
7801
  activity: selectedActivity,
7633
7802
  onClose: () => setSelectedActivity(null)
@@ -7635,74 +7804,6 @@ function TimelineAgentChatPanel({
7635
7804
  )
7636
7805
  ] });
7637
7806
  }
7638
- function formatActivityValue(value) {
7639
- if (value == null) return "";
7640
- if (typeof value === "string") return value;
7641
- try {
7642
- return JSON.stringify(value, null, 2);
7643
- } catch {
7644
- return String(value);
7645
- }
7646
- }
7647
- function ActivityDetailOverlay({
7648
- activity,
7649
- onClose
7650
- }) {
7651
- const title = activity.displayName || activity.toolName || activity.type;
7652
- const input = activity.toolInput && Object.keys(activity.toolInput).length > 0 ? formatActivityValue(activity.toolInput) : "";
7653
- const result = formatActivityValue(activity.content);
7654
- return /* @__PURE__ */ jsx210(
7655
- "div",
7656
- {
7657
- className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
7658
- onClick: onClose,
7659
- role: "presentation",
7660
- children: /* @__PURE__ */ jsxs22(
7661
- "div",
7662
- {
7663
- className: "flex max-h-[80vh] w-full max-w-[640px] flex-col overflow-hidden rounded-[10px] border border-border bg-background shadow-lg",
7664
- onClick: (e) => e.stopPropagation(),
7665
- role: "dialog",
7666
- "aria-modal": "true",
7667
- "aria-label": `${title} details`,
7668
- children: [
7669
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between gap-2 border-b border-border px-4 py-3", children: [
7670
- /* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
7671
- /* @__PURE__ */ jsx210("div", { className: "truncate text-[13px] font-medium text-foreground", children: title }),
7672
- /* @__PURE__ */ jsxs22("div", { className: "text-[11px] text-muted-foreground", children: [
7673
- activity.type,
7674
- " \xB7 ",
7675
- activity.status
7676
- ] })
7677
- ] }),
7678
- /* @__PURE__ */ jsx210(
7679
- "button",
7680
- {
7681
- type: "button",
7682
- onClick: onClose,
7683
- className: "shrink-0 rounded-[6px] px-2 py-1 text-[12px] text-muted-foreground transition hover:bg-foreground/[0.06] hover:text-foreground",
7684
- children: "Close"
7685
- }
7686
- )
7687
- ] }),
7688
- /* @__PURE__ */ jsxs22("div", { className: "flex-1 overflow-y-auto px-4 py-3 space-y-3", children: [
7689
- activity.error && /* @__PURE__ */ jsx210("div", { className: "rounded-[6px] bg-red-500/[0.08] px-3 py-2 text-[12px] text-red-600", children: activity.error }),
7690
- input && /* @__PURE__ */ jsxs22("div", { children: [
7691
- /* @__PURE__ */ jsx210("div", { className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground", children: "Request" }),
7692
- /* @__PURE__ */ jsx210("pre", { className: "overflow-x-auto rounded-[6px] bg-foreground/[0.04] px-3 py-2 text-[12px] text-foreground whitespace-pre-wrap break-words", children: input })
7693
- ] }),
7694
- result && /* @__PURE__ */ jsxs22("div", { children: [
7695
- /* @__PURE__ */ jsx210("div", { className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground", children: "Result" }),
7696
- /* @__PURE__ */ jsx210("pre", { className: "overflow-x-auto rounded-[6px] bg-foreground/[0.04] px-3 py-2 text-[12px] text-foreground whitespace-pre-wrap break-words", children: result })
7697
- ] }),
7698
- !input && !result && !activity.error && /* @__PURE__ */ jsx210("div", { className: "text-[12px] text-muted-foreground", children: "No additional detail for this step." })
7699
- ] })
7700
- ]
7701
- }
7702
- )
7703
- }
7704
- );
7705
- }
7706
7807
 
7707
7808
  // ../runtime-core/dist/index.js
7708
7809
  var RUNTIME_KINDS = ["native-sdk", "app-server", "compatible-sdk", "cli-fallback"];
@@ -8270,7 +8371,7 @@ var PushTimelineStream = class {
8270
8371
  };
8271
8372
 
8272
8373
  // src/use-agent-session.ts
8273
- import { useEffect as useEffect8, useMemo as useMemo9, useRef as useRef9 } from "react";
8374
+ import { useEffect as useEffect10, useMemo as useMemo9, useRef as useRef9 } from "react";
8274
8375
  function useAgentSession(options) {
8275
8376
  const onTokenExpiredRef = useRef9(options.onTokenExpired);
8276
8377
  onTokenExpiredRef.current = options.onTokenExpired;
@@ -8289,7 +8390,7 @@ function useAgentSession(options) {
8289
8390
  })
8290
8391
  });
8291
8392
  }, [options.server, options.sessionId]);
8292
- useEffect8(() => {
8393
+ useEffect10(() => {
8293
8394
  return () => {
8294
8395
  void runtime.disposeIfCreated();
8295
8396
  };
@@ -8373,9 +8474,12 @@ function createDeferredAgentRuntime(options) {
8373
8474
  };
8374
8475
  }
8375
8476
  export {
8477
+ ActivityDetailsPanel,
8478
+ ActivityInspector,
8376
8479
  AgentChatPanel,
8377
8480
  AnnotationIslandMenu,
8378
8481
  AnnotationOverlayLayer,
8482
+ AssistantTurnCard,
8379
8483
  ChatTranscript,
8380
8484
  CodeBlock,
8381
8485
  CollapsibleMarkdownProvider,
@@ -8386,6 +8490,7 @@ export {
8386
8490
  Markdown,
8387
8491
  MemoizedMarkdown,
8388
8492
  PendingIndicator,
8493
+ PermissionModeMenu,
8389
8494
  PermissionRequestCard,
8390
8495
  PlatformProvider,
8391
8496
  ResponseCard,