@stigmer/react 3.7.0 → 3.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.
Files changed (219) hide show
  1. package/attachment/AttachmentChipList.d.ts.map +1 -1
  2. package/attachment/AttachmentChipList.js +30 -1
  3. package/attachment/AttachmentChipList.js.map +1 -1
  4. package/attachment/attachment-utils.d.ts +11 -0
  5. package/attachment/attachment-utils.d.ts.map +1 -1
  6. package/attachment/attachment-utils.js +23 -0
  7. package/attachment/attachment-utils.js.map +1 -1
  8. package/attachment/clipboard.d.ts +51 -0
  9. package/attachment/clipboard.d.ts.map +1 -0
  10. package/attachment/clipboard.js +89 -0
  11. package/attachment/clipboard.js.map +1 -0
  12. package/attachment/index.d.ts +6 -1
  13. package/attachment/index.d.ts.map +1 -1
  14. package/attachment/index.js +4 -1
  15. package/attachment/index.js.map +1 -1
  16. package/attachment/prepare-image.d.ts +43 -0
  17. package/attachment/prepare-image.d.ts.map +1 -0
  18. package/attachment/prepare-image.js +162 -0
  19. package/attachment/prepare-image.js.map +1 -0
  20. package/attachment/useAttachments.d.ts.map +1 -1
  21. package/attachment/useAttachments.js +23 -3
  22. package/attachment/useAttachments.js.map +1 -1
  23. package/attachment/vision-fit.d.ts +50 -0
  24. package/attachment/vision-fit.d.ts.map +1 -0
  25. package/attachment/vision-fit.js +76 -0
  26. package/attachment/vision-fit.js.map +1 -0
  27. package/channel/AgentChannelsPanel.d.ts.map +1 -1
  28. package/channel/AgentChannelsPanel.js +21 -2
  29. package/channel/AgentChannelsPanel.js.map +1 -1
  30. package/channel/ChannelConversationsDialog.d.ts +12 -4
  31. package/channel/ChannelConversationsDialog.d.ts.map +1 -1
  32. package/channel/ChannelConversationsDialog.js +18 -24
  33. package/channel/ChannelConversationsDialog.js.map +1 -1
  34. package/channel/providers.d.ts +23 -0
  35. package/channel/providers.d.ts.map +1 -1
  36. package/channel/providers.js +4 -0
  37. package/channel/providers.js.map +1 -1
  38. package/channel/useSaveAgentChannel.d.ts +5 -4
  39. package/channel/useSaveAgentChannel.d.ts.map +1 -1
  40. package/channel/useSaveAgentChannel.js +18 -4
  41. package/channel/useSaveAgentChannel.js.map +1 -1
  42. package/composer/ComposerToolbar.d.ts +1 -1
  43. package/composer/ComposerToolbar.d.ts.map +1 -1
  44. package/composer/SessionComposer.d.ts +4 -2
  45. package/composer/SessionComposer.d.ts.map +1 -1
  46. package/composer/SessionComposer.js +51 -5
  47. package/composer/SessionComposer.js.map +1 -1
  48. package/conversation/ConversationAttentionBanner.d.ts +22 -0
  49. package/conversation/ConversationAttentionBanner.d.ts.map +1 -0
  50. package/conversation/ConversationAttentionBanner.js +25 -0
  51. package/conversation/ConversationAttentionBanner.js.map +1 -0
  52. package/conversation/ConversationComposer.d.ts +41 -0
  53. package/conversation/ConversationComposer.d.ts.map +1 -0
  54. package/conversation/ConversationComposer.js +57 -0
  55. package/conversation/ConversationComposer.js.map +1 -0
  56. package/conversation/ConversationControlBanner.d.ts +52 -0
  57. package/conversation/ConversationControlBanner.d.ts.map +1 -0
  58. package/conversation/ConversationControlBanner.js +59 -0
  59. package/conversation/ConversationControlBanner.js.map +1 -0
  60. package/conversation/ConversationListPane.d.ts +68 -0
  61. package/conversation/ConversationListPane.d.ts.map +1 -0
  62. package/conversation/ConversationListPane.js +120 -0
  63. package/conversation/ConversationListPane.js.map +1 -0
  64. package/conversation/ConversationTimelineView.d.ts +46 -0
  65. package/conversation/ConversationTimelineView.d.ts.map +1 -0
  66. package/conversation/ConversationTimelineView.js +166 -0
  67. package/conversation/ConversationTimelineView.js.map +1 -0
  68. package/conversation/ConversationsWorkbench.d.ts +63 -0
  69. package/conversation/ConversationsWorkbench.d.ts.map +1 -0
  70. package/conversation/ConversationsWorkbench.js +165 -0
  71. package/conversation/ConversationsWorkbench.js.map +1 -0
  72. package/conversation/conversationPresentation.d.ts +137 -0
  73. package/conversation/conversationPresentation.d.ts.map +1 -0
  74. package/conversation/conversationPresentation.js +230 -0
  75. package/conversation/conversationPresentation.js.map +1 -0
  76. package/conversation/index.d.ts +26 -0
  77. package/conversation/index.d.ts.map +1 -0
  78. package/conversation/index.js +14 -0
  79. package/conversation/index.js.map +1 -0
  80. package/conversation/polling.d.ts +39 -0
  81. package/conversation/polling.d.ts.map +1 -0
  82. package/conversation/polling.js +39 -0
  83. package/conversation/polling.js.map +1 -0
  84. package/conversation/useConversation.d.ts +61 -0
  85. package/conversation/useConversation.d.ts.map +1 -0
  86. package/conversation/useConversation.js +153 -0
  87. package/conversation/useConversation.js.map +1 -0
  88. package/conversation/useConversationList.d.ts +98 -0
  89. package/conversation/useConversationList.d.ts.map +1 -0
  90. package/conversation/useConversationList.js +200 -0
  91. package/conversation/useConversationList.js.map +1 -0
  92. package/conversation/useConversationParticipation.d.ts +63 -0
  93. package/conversation/useConversationParticipation.d.ts.map +1 -0
  94. package/conversation/useConversationParticipation.js +84 -0
  95. package/conversation/useConversationParticipation.js.map +1 -0
  96. package/conversation/useConversationTimeline.d.ts +71 -0
  97. package/conversation/useConversationTimeline.d.ts.map +1 -0
  98. package/conversation/useConversationTimeline.js +152 -0
  99. package/conversation/useConversationTimeline.js.map +1 -0
  100. package/conversation/useConversationsWantsHumanCount.d.ts +42 -0
  101. package/conversation/useConversationsWantsHumanCount.d.ts.map +1 -0
  102. package/conversation/useConversationsWantsHumanCount.js +40 -0
  103. package/conversation/useConversationsWantsHumanCount.js.map +1 -0
  104. package/index.d.ts +6 -2
  105. package/index.d.ts.map +1 -1
  106. package/index.js +11 -2
  107. package/index.js.map +1 -1
  108. package/internal/tooltip.d.ts.map +1 -1
  109. package/internal/tooltip.js +7 -1
  110. package/internal/tooltip.js.map +1 -1
  111. package/internal/useAutoScroll.d.ts +25 -4
  112. package/internal/useAutoScroll.d.ts.map +1 -1
  113. package/internal/useAutoScroll.js +55 -15
  114. package/internal/useAutoScroll.js.map +1 -1
  115. package/internal/useFetch.d.ts.map +1 -1
  116. package/internal/useFetch.js +14 -4
  117. package/internal/useFetch.js.map +1 -1
  118. package/models/ModelSelector.d.ts +24 -5
  119. package/models/ModelSelector.d.ts.map +1 -1
  120. package/models/ModelSelector.js +31 -9
  121. package/models/ModelSelector.js.map +1 -1
  122. package/models/registry.d.ts +3 -2
  123. package/models/registry.d.ts.map +1 -1
  124. package/models/registry.js.map +1 -1
  125. package/models/service-tier.d.ts +1 -1
  126. package/models/service-tier.d.ts.map +1 -1
  127. package/models/service-tier.js +1 -1
  128. package/models/service-tier.js.map +1 -1
  129. package/package.json +4 -4
  130. package/schedule/ScheduleDetailView.js +1 -1
  131. package/schedule/ScheduleDetailView.js.map +1 -1
  132. package/schedule/ScheduleForm.d.ts.map +1 -1
  133. package/schedule/ScheduleForm.js +7 -6
  134. package/schedule/ScheduleForm.js.map +1 -1
  135. package/sharing/useSaveAgentShare.d.ts +10 -1
  136. package/sharing/useSaveAgentShare.d.ts.map +1 -1
  137. package/sharing/useSaveAgentShare.js +9 -0
  138. package/sharing/useSaveAgentShare.js.map +1 -1
  139. package/sidebar/WorkspaceSidebar.d.ts +12 -4
  140. package/sidebar/WorkspaceSidebar.d.ts.map +1 -1
  141. package/sidebar/WorkspaceSidebar.js +19 -7
  142. package/sidebar/WorkspaceSidebar.js.map +1 -1
  143. package/src/attachment/AttachmentChipList.tsx +45 -1
  144. package/src/attachment/__tests__/AttachmentChipList.test.tsx +103 -0
  145. package/src/attachment/__tests__/attachment-utils.test.ts +54 -0
  146. package/src/attachment/__tests__/clipboard.test.ts +110 -0
  147. package/src/attachment/__tests__/prepare-image.browser.test.ts +166 -0
  148. package/src/attachment/__tests__/prepare-image.test.ts +32 -0
  149. package/src/attachment/__tests__/vision-fit.test.ts +93 -0
  150. package/src/attachment/attachment-utils.ts +27 -0
  151. package/src/attachment/clipboard.ts +102 -0
  152. package/src/attachment/index.ts +13 -0
  153. package/src/attachment/prepare-image.ts +179 -0
  154. package/src/attachment/useAttachments.ts +26 -2
  155. package/src/attachment/vision-fit.ts +90 -0
  156. package/src/channel/AgentChannelsPanel.tsx +33 -2
  157. package/src/channel/ChannelConversationsDialog.tsx +22 -25
  158. package/src/channel/__tests__/AgentChannelsPanel.test.tsx +36 -5
  159. package/src/channel/__tests__/ChannelConversationsDialog.test.tsx +38 -1
  160. package/src/channel/__tests__/useSaveAgentChannel.test.tsx +26 -0
  161. package/src/channel/providers.ts +27 -0
  162. package/src/channel/useSaveAgentChannel.ts +18 -4
  163. package/src/composer/ComposerToolbar.tsx +1 -1
  164. package/src/composer/SessionComposer.tsx +75 -6
  165. package/src/composer/__tests__/SessionComposer-paste.test.tsx +263 -0
  166. package/src/composer/__tests__/SessionComposer-serviceTier.test.tsx +4 -3
  167. package/src/composer/__tests__/SessionComposer-uploadGate.test.tsx +239 -0
  168. package/src/conversation/ConversationAttentionBanner.tsx +77 -0
  169. package/src/conversation/ConversationComposer.tsx +156 -0
  170. package/src/conversation/ConversationControlBanner.tsx +193 -0
  171. package/src/conversation/ConversationListPane.tsx +459 -0
  172. package/src/conversation/ConversationTimelineView.tsx +435 -0
  173. package/src/conversation/ConversationsWorkbench.tsx +378 -0
  174. package/src/conversation/__tests__/ConversationAttentionBanner.test.tsx +82 -0
  175. package/src/conversation/__tests__/ConversationComposer.test.tsx +160 -0
  176. package/src/conversation/__tests__/ConversationControlBanner.test.tsx +190 -0
  177. package/src/conversation/__tests__/ConversationListPane.test.tsx +372 -0
  178. package/src/conversation/__tests__/ConversationTimelineView.layout.test.tsx +160 -0
  179. package/src/conversation/__tests__/ConversationTimelineView.test.tsx +405 -0
  180. package/src/conversation/__tests__/ConversationsWorkbench.test.tsx +860 -0
  181. package/src/conversation/__tests__/a11y/conversation-surfaces.a11y.test.tsx +235 -0
  182. package/src/conversation/__tests__/a11y/harness.tsx +100 -0
  183. package/src/conversation/__tests__/conversation-tooltips.layout.test.tsx +167 -0
  184. package/src/conversation/__tests__/conversationPollingComposition.test.tsx +138 -0
  185. package/src/conversation/__tests__/conversationPresentation.test.ts +289 -0
  186. package/src/conversation/__tests__/useConversation.test.tsx +243 -0
  187. package/src/conversation/__tests__/useConversationList.test.tsx +492 -0
  188. package/src/conversation/__tests__/useConversationParticipation.test.tsx +190 -0
  189. package/src/conversation/__tests__/useConversationTimeline.test.tsx +258 -0
  190. package/src/conversation/__tests__/useConversationsWantsHumanCount.test.tsx +102 -0
  191. package/src/conversation/conversationPresentation.ts +305 -0
  192. package/src/conversation/index.ts +80 -0
  193. package/src/conversation/polling.ts +41 -0
  194. package/src/conversation/useConversation.ts +221 -0
  195. package/src/conversation/useConversationList.ts +328 -0
  196. package/src/conversation/useConversationParticipation.ts +178 -0
  197. package/src/conversation/useConversationTimeline.ts +244 -0
  198. package/src/conversation/useConversationsWantsHumanCount.ts +86 -0
  199. package/src/index.ts +78 -1
  200. package/src/internal/__tests__/fake-timer-slices.ts +29 -0
  201. package/src/internal/__tests__/useAutoScroll.layout.test.tsx +143 -0
  202. package/src/internal/__tests__/useAutoScroll.test.tsx +62 -5
  203. package/src/internal/__tests__/useFetch-poll-under-render-pressure.test.tsx +79 -0
  204. package/src/internal/tooltip.tsx +6 -1
  205. package/src/internal/useAutoScroll.ts +66 -20
  206. package/src/internal/useFetch.ts +15 -4
  207. package/src/models/ModelSelector.tsx +81 -49
  208. package/src/models/__tests__/ModelSelector-serviceTier.test.tsx +105 -21
  209. package/src/models/registry.ts +3 -2
  210. package/src/models/service-tier.ts +1 -1
  211. package/src/schedule/ScheduleDetailView.tsx +1 -1
  212. package/src/schedule/ScheduleForm.tsx +7 -6
  213. package/src/schedule/__tests__/scheduleCreation.test.tsx +2 -2
  214. package/src/sharing/__tests__/useSaveAgentShare.test.tsx +55 -1
  215. package/src/sharing/__tests__/useShareToolReadiness.test.tsx +1 -0
  216. package/src/sharing/useSaveAgentShare.ts +19 -1
  217. package/src/sidebar/WorkspaceSidebar.tsx +62 -3
  218. package/src/sidebar/__tests__/WorkspaceSidebar.test.tsx +56 -1
  219. package/styles.css +1 -1
@@ -6,6 +6,7 @@ import {
6
6
  LayoutDashboard,
7
7
  Library,
8
8
  MessageSquare,
9
+ MessagesSquare,
9
10
  Workflow,
10
11
  type LucideIcon,
11
12
  } from "lucide-react";
@@ -29,7 +30,11 @@ import type { RenderSidebarLink } from "./types.js";
29
30
  // ---------------------------------------------------------------------------
30
31
 
31
32
  /** Primary navigation destinations in the workspace sidebar. */
32
- export type WorkspaceNavId = "new-session" | "dashboard" | "library";
33
+ export type WorkspaceNavId =
34
+ | "new-session"
35
+ | "dashboard"
36
+ | "conversations"
37
+ | "library";
33
38
 
34
39
  /**
35
40
  * Recent-activity data for the sidebar's Recents section — the return
@@ -66,6 +71,14 @@ export interface WorkspaceSidebarProps {
66
71
  * timestamp column, inside the row.
67
72
  */
68
73
  readonly renderEntryAccessory?: (entry: RecentActivityEntry) => ReactNode;
74
+ /**
75
+ * Count for the Conversations row's badge: how many conversations
76
+ * want a human right now (`useConversationsWantsHumanCount`). Data as
77
+ * props per the chrome contract — hosts fetch, deterministic hosts
78
+ * (tours) pass a fixture or omit. Hidden at `0`/omitted; the display
79
+ * caps at "99+" while the accessible name keeps the real number.
80
+ */
81
+ readonly conversationsBadgeCount?: number;
69
82
  /** Footer content — typically the host app's `UserMenu` wrapper. */
70
83
  readonly footer: ReactNode;
71
84
  /** Reflected as `aria-expanded` on the collapse toggle. @default true */
@@ -85,8 +98,8 @@ export interface WorkspaceSidebarProps {
85
98
 
86
99
  /**
87
100
  * The console's workspace-zone sidebar: org switcher, primary navigation
88
- * (New Session / Dashboard / Library), time-bucketed recent activity,
89
- * and a user footer.
101
+ * (New Session / Dashboard / Conversations / Library), time-bucketed
102
+ * recent activity, and a user footer.
90
103
  *
91
104
  * This is the same component the Stigmer web console and desktop app
92
105
  * render — hosts differ only in what they return from `renderLink`
@@ -117,6 +130,7 @@ export function WorkspaceSidebar({
117
130
  activeSessionId = null,
118
131
  activeExecutionId = null,
119
132
  renderEntryAccessory,
133
+ conversationsBadgeCount,
120
134
  footer,
121
135
  isOpen = true,
122
136
  onCollapse,
@@ -154,6 +168,22 @@ export function WorkspaceSidebar({
154
168
  active={activeNav === "dashboard"}
155
169
  renderLink={renderLink}
156
170
  />
171
+ {/* MessagesSquare, deliberately not MessageSquare — the singular
172
+ mark is the session glyph in Recents, and the two areas must
173
+ not read as one. */}
174
+ <PrimaryNavRow
175
+ id="conversations"
176
+ href="/conversations"
177
+ label="Conversations"
178
+ icon={MessagesSquare}
179
+ active={activeNav === "conversations"}
180
+ renderLink={renderLink}
181
+ accessory={
182
+ conversationsBadgeCount !== undefined && conversationsBadgeCount > 0 ? (
183
+ <WantsHumanBadge count={conversationsBadgeCount} />
184
+ ) : null
185
+ }
186
+ />
157
187
  <PrimaryNavRow
158
188
  id="library"
159
189
  href="/library"
@@ -204,6 +234,7 @@ function PrimaryNavRow({
204
234
  icon: Icon,
205
235
  active,
206
236
  renderLink,
237
+ accessory = null,
207
238
  }: {
208
239
  readonly id: WorkspaceNavId;
209
240
  readonly href: string;
@@ -211,6 +242,8 @@ function PrimaryNavRow({
211
242
  readonly icon: LucideIcon;
212
243
  readonly active: boolean;
213
244
  readonly renderLink: RenderSidebarLink;
245
+ /** Trailing row content (e.g. the Conversations count pill). */
246
+ readonly accessory?: ReactNode;
214
247
  }) {
215
248
  return (
216
249
  <div className="flex-none px-3 py-1">
@@ -224,6 +257,7 @@ function PrimaryNavRow({
224
257
  <>
225
258
  <Icon className="size-4 shrink-0" />
226
259
  {label}
260
+ {accessory}
227
261
  </>
228
262
  ),
229
263
  })}
@@ -231,6 +265,31 @@ function PrimaryNavRow({
231
265
  );
232
266
  }
233
267
 
268
+ /**
269
+ * The Conversations row's count pill: how many conversations want a
270
+ * human right now (DD-011 D-f — `needs_attention` OR awaiting-reply
271
+ * while human-held). The visible number caps at "99+"; the accessible
272
+ * name states the meaning with the real number, because a bare "104"
273
+ * read aloud after "Conversations" says nothing.
274
+ */
275
+ function WantsHumanBadge({ count }: { readonly count: number }) {
276
+ return (
277
+ <span className="ml-auto flex shrink-0 items-center">
278
+ <span
279
+ aria-hidden="true"
280
+ className="bg-sidebar-primary text-sidebar-primary-foreground rounded-full px-1.5 py-0.5 text-[10px] leading-none font-semibold tabular-nums"
281
+ >
282
+ {count > 99 ? "99+" : count}
283
+ </span>
284
+ <span className="sr-only">
285
+ {count === 1
286
+ ? "1 conversation needs a human"
287
+ : `${count} conversations need a human`}
288
+ </span>
289
+ </span>
290
+ );
291
+ }
292
+
234
293
  function ActivityGroupList({
235
294
  groups,
236
295
  activeSessionId,
@@ -109,14 +109,69 @@ function baseProps() {
109
109
  };
110
110
  }
111
111
 
112
+ describe("WorkspaceSidebar — Conversations badge (channel-conversations DD-011 D-f)", () => {
113
+ const conversationsRow = (container: HTMLElement) =>
114
+ container.querySelector<HTMLAnchorElement>('[data-row-id="conversations"]')!;
115
+
116
+ it("shows the wants-human count on the Conversations row with a meaning-stating accessible name", () => {
117
+ const { container } = renderSidebar(
118
+ <WorkspaceSidebar {...baseProps()} conversationsBadgeCount={3} />,
119
+ );
120
+
121
+ const row = conversationsRow(container);
122
+ expect(within(row).getByText("3")).toBeDefined();
123
+ expect(within(row).getByText("3 conversations need a human")).toBeDefined();
124
+ });
125
+
126
+ it("speaks the singular for one conversation", () => {
127
+ const { container } = renderSidebar(
128
+ <WorkspaceSidebar {...baseProps()} conversationsBadgeCount={1} />,
129
+ );
130
+
131
+ expect(
132
+ within(conversationsRow(container)).getByText("1 conversation needs a human"),
133
+ ).toBeDefined();
134
+ });
135
+
136
+ it("hides the badge at zero and when the host passes no count", () => {
137
+ const { container } = renderSidebar(
138
+ <WorkspaceSidebar {...baseProps()} conversationsBadgeCount={0} />,
139
+ );
140
+ expect(
141
+ within(conversationsRow(container)).queryByText(/need(s)? a human/),
142
+ ).toBeNull();
143
+
144
+ cleanup();
145
+
146
+ const { container: without } = renderSidebar(
147
+ <WorkspaceSidebar {...baseProps()} />,
148
+ );
149
+ expect(
150
+ within(conversationsRow(without)).queryByText(/need(s)? a human/),
151
+ ).toBeNull();
152
+ });
153
+
154
+ it("caps the visible number at 99+ while the accessible name keeps the real count", () => {
155
+ const { container } = renderSidebar(
156
+ <WorkspaceSidebar {...baseProps()} conversationsBadgeCount={104} />,
157
+ );
158
+
159
+ const row = conversationsRow(container);
160
+ expect(within(row).getByText("99+")).toBeDefined();
161
+ expect(within(row).queryByText("104")).toBeNull();
162
+ expect(within(row).getByText("104 conversations need a human")).toBeDefined();
163
+ });
164
+ });
165
+
112
166
  describe("WorkspaceSidebar — primary navigation", () => {
113
- it("renders the three primary rows through renderLink with stable ids and hrefs", () => {
167
+ it("renders the four primary rows through renderLink with stable ids and hrefs", () => {
114
168
  const { container } = renderSidebar(<WorkspaceSidebar {...baseProps()} />);
115
169
 
116
170
  const row = (id: string) =>
117
171
  container.querySelector<HTMLAnchorElement>(`[data-row-id="${id}"]`);
118
172
  expect(row("new-session")?.getAttribute("href")).toBe("/");
119
173
  expect(row("dashboard")?.getAttribute("href")).toBe("/dashboard");
174
+ expect(row("conversations")?.getAttribute("href")).toBe("/conversations");
120
175
  expect(row("library")?.getAttribute("href")).toBe("/library");
121
176
  });
122
177