@agent-native/core-corpus 0.217.0 → 0.218.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 (56) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +2 -0
  3. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +38 -167
  4. package/corpus/templates/analytics/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  5. package/corpus/templates/assets/CHANGELOG.md +6 -0
  6. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +51 -117
  7. package/corpus/templates/assets/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  8. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +34 -101
  9. package/corpus/templates/brain/app/routes/sources.tsx +1 -1
  10. package/corpus/templates/brain/vitest.config.ts +7 -0
  11. package/corpus/templates/calendar/CHANGELOG.md +6 -0
  12. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +1 -1
  13. package/corpus/templates/calendar/changelog/2026-10-16-booking-links-show-localized-visibility-badges.md +6 -0
  14. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +62 -101
  15. package/corpus/templates/clips/CHANGELOG.md +7 -20
  16. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +20 -77
  17. package/corpus/templates/clips/app/components/player/share-dialog.tsx +63 -90
  18. package/corpus/templates/clips/app/components/sharing/share-test-support.tsx +180 -0
  19. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -584
  20. package/corpus/templates/clips/changelog/2026-10-16-share-dialogs-make-it-easier-to-see-who-has-access-and-manag.md +6 -0
  21. package/corpus/templates/clips/changelog/2026-10-21-share-panels-describe-general-access-in-a-sentence.md +6 -0
  22. package/corpus/templates/community/qr/package.json +1 -1
  23. package/corpus/templates/content/CHANGELOG.md +2 -0
  24. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +119 -30
  25. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +56 -13
  26. package/corpus/templates/content/app/components/editor/SuggestionText.tsx +18 -3
  27. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +89 -22
  28. package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +383 -34
  29. package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +31 -0
  30. package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +82 -4
  31. package/corpus/templates/content/app/global.css +31 -0
  32. package/corpus/templates/content/changelog/2026-10-16-accepting-a-suggestion-on-a-page-that-changed-since-it-was-s.md +6 -0
  33. package/corpus/templates/content/changelog/2026-10-20-suggested-edits-that-add-remove-split-or-merge-paragraphs-li.md +6 -0
  34. package/corpus/templates/content/shared/suggestion-diff.ts +23 -6
  35. package/corpus/templates/content/shared/suggestion-formatting.ts +44 -14
  36. package/corpus/templates/content/shared/suggestion-text.ts +20 -5
  37. package/corpus/templates/design/CHANGELOG.md +3 -0
  38. package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -1
  39. package/corpus/templates/design/app/pages/Index.tsx +18 -64
  40. package/corpus/templates/design/changelog/2026-10-16-design-pages-use-localized-visibility-badges-and-a-shared-ow.md +6 -0
  41. package/corpus/templates/dispatch/CHANGELOG.md +4 -0
  42. package/corpus/templates/dispatch/app/i18n-data.ts +75 -0
  43. package/corpus/templates/dispatch/changelog/2026-10-21-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  44. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +34 -100
  45. package/corpus/templates/forms/app/pages/FormsListPage.tsx +1 -1
  46. package/corpus/templates/plan/CHANGELOG.md +6 -0
  47. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +34 -109
  48. package/corpus/templates/plan/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  49. package/corpus/templates/slides/CHANGELOG.md +1 -0
  50. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
  51. package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +1 -1
  52. package/corpus/templates/slides/app/pages/Index.tsx +7 -2
  53. package/corpus/templates/slides/changelog/2026-10-16-deck-lists-use-the-shared-ownership-filter-and-visibility-ba.md +6 -0
  54. package/package.json +1 -1
  55. package/corpus/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
  56. package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +0 -83
@@ -312,6 +312,10 @@ const enUS = {
312
312
  },
313
313
  },
314
314
  dispatch: {
315
+ sidebar: {
316
+ showLocalChats: "Show local chats",
317
+ showAllChats: "Show all chats",
318
+ },
315
319
  nav: {
316
320
  admin: "Admin",
317
321
  automations: "Automations",
@@ -324,6 +328,9 @@ const enUS = {
324
328
  agent: "Agent",
325
329
  },
326
330
  pages: {
331
+ chatFirstCopySessionId: "Copy session ID",
332
+ chatFirstSessionIdCopied: "Session ID copied",
333
+ chatFirstWatchSession: "Watch",
327
334
  adminDescription: "Workspace controls and operations",
328
335
  simpleAgentsDescription:
329
336
  "Create reusable agents in minutes, or import a setup you already made in Claude or another agent tool.",
@@ -595,6 +602,7 @@ type PartialMessages = {
595
602
  } & Record<string, unknown>
596
603
  : K extends "dispatch"
597
604
  ? {
605
+ sidebar?: Partial<Messages["dispatch"]["sidebar"]>;
598
606
  nav?: Partial<Messages["dispatch"]["nav"]> & Record<string, unknown>;
599
607
  pages?: Partial<Messages["dispatch"]["pages"]> &
600
608
  Record<string, unknown>;
@@ -1251,6 +1259,10 @@ function mergeMessages(
1251
1259
  dispatch: {
1252
1260
  ...enUS.dispatch,
1253
1261
  ...overrides.dispatch,
1262
+ sidebar: {
1263
+ ...enUS.dispatch.sidebar,
1264
+ ...overrides.dispatch?.sidebar,
1265
+ },
1254
1266
  nav: {
1255
1267
  ...enUS.dispatch.nav,
1256
1268
  ...(overrides.dispatch as { nav?: Record<string, string> } | undefined)
@@ -1537,6 +1549,10 @@ export const messagesByLocale = {
1537
1549
  },
1538
1550
 
1539
1551
  dispatch: {
1552
+ sidebar: {
1553
+ showLocalChats: "显示本地聊天",
1554
+ showAllChats: "显示所有聊天",
1555
+ },
1540
1556
  nav: {
1541
1557
  admin: "管理",
1542
1558
  automations: "自动化",
@@ -1549,6 +1565,9 @@ export const messagesByLocale = {
1549
1565
  agent: "代理",
1550
1566
  },
1551
1567
  pages: {
1568
+ chatFirstCopySessionId: "复制会话 ID",
1569
+ chatFirstSessionIdCopied: "会话 ID 已复制",
1570
+ chatFirstWatchSession: "观看",
1552
1571
  ...chatFirstPageTranslations["zh-CN"],
1553
1572
  adminDescription: "工作区控制与运营",
1554
1573
  connectApps: "连接应用",
@@ -1989,6 +2008,10 @@ export const messagesByLocale = {
1989
2008
  },
1990
2009
 
1991
2010
  dispatch: {
2011
+ sidebar: {
2012
+ showLocalChats: "Mostrar chats locales",
2013
+ showAllChats: "Mostrar todos los chats",
2014
+ },
1992
2015
  nav: {
1993
2016
  admin: "Administración",
1994
2017
  automations: "Automatizaciones",
@@ -2001,6 +2024,9 @@ export const messagesByLocale = {
2001
2024
  agent: "Agente",
2002
2025
  },
2003
2026
  pages: {
2027
+ chatFirstCopySessionId: "Copiar ID de sesión",
2028
+ chatFirstSessionIdCopied: "ID de sesión copiado",
2029
+ chatFirstWatchSession: "Observar",
2004
2030
  ...chatFirstPageTranslations["es-ES"],
2005
2031
  adminDescription: "Controles y operaciones del espacio de trabajo",
2006
2032
  connectApps: "Conectar apps",
@@ -2455,6 +2481,10 @@ export const messagesByLocale = {
2455
2481
  },
2456
2482
 
2457
2483
  dispatch: {
2484
+ sidebar: {
2485
+ showLocalChats: "Afficher les conversations locales",
2486
+ showAllChats: "Afficher toutes les conversations",
2487
+ },
2458
2488
  nav: {
2459
2489
  admin: "Administration",
2460
2490
  automations: "Automatisations",
@@ -2467,6 +2497,9 @@ export const messagesByLocale = {
2467
2497
  agent: "Agent",
2468
2498
  },
2469
2499
  pages: {
2500
+ chatFirstCopySessionId: "Copier l’identifiant de session",
2501
+ chatFirstSessionIdCopied: "Identifiant de session copié",
2502
+ chatFirstWatchSession: "Observer",
2470
2503
  ...chatFirstPageTranslations["fr-FR"],
2471
2504
  adminDescription: "Contrôles et opérations de l’espace de travail",
2472
2505
  connectApps: "Connecter des apps",
@@ -2912,6 +2945,10 @@ export const messagesByLocale = {
2912
2945
  },
2913
2946
 
2914
2947
  dispatch: {
2948
+ sidebar: {
2949
+ showLocalChats: "Lokale Chats anzeigen",
2950
+ showAllChats: "Alle Chats anzeigen",
2951
+ },
2915
2952
  nav: {
2916
2953
  admin: "Administration",
2917
2954
  automations: "Automatisierungen",
@@ -2924,6 +2961,9 @@ export const messagesByLocale = {
2924
2961
  agent: "Agent",
2925
2962
  },
2926
2963
  pages: {
2964
+ chatFirstCopySessionId: "Sitzungs-ID kopieren",
2965
+ chatFirstSessionIdCopied: "Sitzungs-ID kopiert",
2966
+ chatFirstWatchSession: "Beobachten",
2927
2967
  ...chatFirstPageTranslations["de-DE"],
2928
2968
  adminDescription: "Arbeitsbereichssteuerung und -betrieb",
2929
2969
  connectApps: "Apps verbinden",
@@ -3363,6 +3403,10 @@ export const messagesByLocale = {
3363
3403
  },
3364
3404
 
3365
3405
  dispatch: {
3406
+ sidebar: {
3407
+ showLocalChats: "ローカルのチャットを表示",
3408
+ showAllChats: "すべてのチャットを表示",
3409
+ },
3366
3410
  nav: {
3367
3411
  admin: "管理",
3368
3412
  automations: "自動化",
@@ -3375,6 +3419,9 @@ export const messagesByLocale = {
3375
3419
  agent: "エージェント",
3376
3420
  },
3377
3421
  pages: {
3422
+ chatFirstCopySessionId: "セッション ID をコピー",
3423
+ chatFirstSessionIdCopied: "セッション ID をコピーしました",
3424
+ chatFirstWatchSession: "ウォッチ",
3378
3425
  ...chatFirstPageTranslations["ja-JP"],
3379
3426
  adminDescription: "ワークスペースの管理と運用",
3380
3427
  connectApps: "アプリを接続",
@@ -3808,6 +3855,10 @@ export const messagesByLocale = {
3808
3855
  },
3809
3856
 
3810
3857
  dispatch: {
3858
+ sidebar: {
3859
+ showLocalChats: "로컬 채팅 표시",
3860
+ showAllChats: "모든 채팅 표시",
3861
+ },
3811
3862
  nav: {
3812
3863
  admin: "관리",
3813
3864
  automations: "자동화",
@@ -3820,6 +3871,9 @@ export const messagesByLocale = {
3820
3871
  agent: "에이전트",
3821
3872
  },
3822
3873
  pages: {
3874
+ chatFirstCopySessionId: "세션 ID 복사",
3875
+ chatFirstSessionIdCopied: "세션 ID가 복사되었습니다",
3876
+ chatFirstWatchSession: "지켜보기",
3823
3877
  ...chatFirstPageTranslations["ko-KR"],
3824
3878
  adminDescription: "워크스페이스 제어 및 운영",
3825
3879
  connectApps: "앱 연결",
@@ -4261,6 +4315,10 @@ export const messagesByLocale = {
4261
4315
  },
4262
4316
 
4263
4317
  dispatch: {
4318
+ sidebar: {
4319
+ showLocalChats: "Mostrar conversas locais",
4320
+ showAllChats: "Mostrar todas as conversas",
4321
+ },
4264
4322
  nav: {
4265
4323
  admin: "Administração",
4266
4324
  automations: "Automações",
@@ -4273,6 +4331,9 @@ export const messagesByLocale = {
4273
4331
  agent: "Agente",
4274
4332
  },
4275
4333
  pages: {
4334
+ chatFirstCopySessionId: "Copiar ID da sessão",
4335
+ chatFirstSessionIdCopied: "ID da sessão copiado",
4336
+ chatFirstWatchSession: "Observar",
4276
4337
  ...chatFirstPageTranslations["pt-BR"],
4277
4338
  adminDescription: "Controles e operações do espaço de trabalho",
4278
4339
  connectApps: "Conectar apps",
@@ -4707,6 +4768,10 @@ export const messagesByLocale = {
4707
4768
  },
4708
4769
 
4709
4770
  dispatch: {
4771
+ sidebar: {
4772
+ showLocalChats: "स्थानीय चैट दिखाएँ",
4773
+ showAllChats: "सभी चैट दिखाएँ",
4774
+ },
4710
4775
  nav: {
4711
4776
  admin: "व्यवस्थापक",
4712
4777
  automations: "ऑटोमेशन",
@@ -4719,6 +4784,9 @@ export const messagesByLocale = {
4719
4784
  agent: "एजेंट",
4720
4785
  },
4721
4786
  pages: {
4787
+ chatFirstCopySessionId: "सत्र ID कॉपी करें",
4788
+ chatFirstSessionIdCopied: "सत्र ID कॉपी किया गया",
4789
+ chatFirstWatchSession: "देखें",
4722
4790
  ...chatFirstPageTranslations["hi-IN"],
4723
4791
  adminDescription: "वर्कस्पेस नियंत्रण और संचालन",
4724
4792
  connectApps: "ऐप कनेक्ट करें",
@@ -5181,6 +5249,10 @@ export const messagesByLocale = {
5181
5249
  },
5182
5250
 
5183
5251
  dispatch: {
5252
+ sidebar: {
5253
+ showLocalChats: "إظهار المحادثات المحلية",
5254
+ showAllChats: "إظهار جميع المحادثات",
5255
+ },
5184
5256
  nav: {
5185
5257
  admin: "الإدارة",
5186
5258
  automations: "الأتمتة",
@@ -5193,6 +5265,9 @@ export const messagesByLocale = {
5193
5265
  agent: "الوكيل",
5194
5266
  },
5195
5267
  pages: {
5268
+ chatFirstCopySessionId: "نسخ معرّف الجلسة",
5269
+ chatFirstSessionIdCopied: "تم نسخ معرّف الجلسة",
5270
+ chatFirstWatchSession: "مشاهدة",
5196
5271
  ...chatFirstPageTranslations["ar-SA"],
5197
5272
  adminDescription: "عناصر التحكم في مساحة العمل وعملياتها",
5198
5273
  connectApps: "توصيل التطبيقات",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-10-21
4
+ ---
5
+
6
+ Owned and shared chats appear in separate history sections, with each shared chat's owner shown as an avatar and a Copy link action on every chat.
@@ -1,9 +1,14 @@
1
1
  import {
2
2
  navigateWithAgentChatViewTransition,
3
3
  useChatThreads,
4
- type ChatThreadSummary,
5
4
  } from "@agent-native/core/client/agent-chat";
5
+ import { appPath } from "@agent-native/core/client/api-path";
6
6
  import { useT } from "@agent-native/core/client/i18n";
7
+ import {
8
+ OwnershipChatHistoryRail,
9
+ useOwnershipChatHistory,
10
+ ownDraftRows,
11
+ } from "@agent-native/toolkit/app/chat/ownership-history";
7
12
  import { FeedbackButton } from "@agent-native/toolkit/app/feedback";
8
13
  import { OrgSwitcher } from "@agent-native/toolkit/app/org";
9
14
  import { openCommandMenu } from "@agent-native/toolkit/app/shared";
@@ -11,17 +16,12 @@ import {
11
16
  AppSidebar,
12
17
  AppSidebarNavItem,
13
18
  } from "@agent-native/toolkit/app/shared";
14
- import {
15
- ChatHistoryRail,
16
- type ChatHistoryItem,
17
- } from "@agent-native/toolkit/chat-history";
18
19
  import {
19
20
  IconGitPullRequest,
20
21
  IconHierarchy2,
21
22
  IconMessageCircle,
22
23
  IconSearch,
23
24
  } from "@tabler/icons-react";
24
- import { useEffect, useMemo } from "react";
25
25
  import { useLocation, useNavigate } from "react-router";
26
26
  import { toast } from "sonner";
27
27
 
@@ -42,40 +42,6 @@ interface SidebarProps {
42
42
  onCollapsedChange?: (collapsed: boolean) => void;
43
43
  }
44
44
 
45
- function formatThreadAge(updatedAt: number) {
46
- const diffMs = Math.max(0, Date.now() - updatedAt);
47
- const minutes = Math.floor(diffMs / 60_000);
48
- if (minutes < 1) return "now";
49
- if (minutes < 60) return `${minutes}m`;
50
- const hours = Math.floor(minutes / 60);
51
- if (hours < 24) return `${hours}h`;
52
- const days = Math.floor(hours / 24);
53
- if (days < 7) return `${days}d`;
54
- return new Date(updatedAt).toLocaleDateString([], {
55
- month: "short",
56
- day: "numeric",
57
- });
58
- }
59
-
60
- function threadTitle(thread: ChatThreadSummary) {
61
- return thread.title || thread.preview || "Untitled chat";
62
- }
63
-
64
- function threadUpdatedAt(thread: ChatThreadSummary) {
65
- return Number.isFinite(thread.updatedAt)
66
- ? thread.updatedAt
67
- : Number.isFinite(thread.createdAt)
68
- ? thread.createdAt
69
- : 0;
70
- }
71
-
72
- function compareThreads(a: ChatThreadSummary, b: ChatThreadSummary) {
73
- const aPinned = a.pinnedAt ?? 0;
74
- const bPinned = b.pinnedAt ?? 0;
75
- if (aPinned || bPinned) return bPinned - aPinned;
76
- return threadUpdatedAt(b) - threadUpdatedAt(a);
77
- }
78
-
79
45
  function persistedActiveThreadId() {
80
46
  try {
81
47
  return localStorage.getItem(CHAT_ACTIVE_THREAD_KEY);
@@ -120,56 +86,37 @@ function ChatThreadsSection({ open }: { open: boolean }) {
120
86
  pinThread,
121
87
  archiveThread,
122
88
  renameThread,
123
- refreshThreads,
89
+ isNewThread,
124
90
  } = useChatThreads(undefined, CHAT_STORAGE_KEY, undefined, {
91
+ ownership: "mine",
125
92
  autoCreate: false,
126
93
  restoreActiveThread: false,
127
94
  });
128
95
 
129
- const visibleThreads = useMemo(
130
- () =>
131
- threads
132
- .filter((thread) => thread.messageCount > 0 && !thread.archivedAt)
133
- .sort(compareThreads)
134
- .slice(0, 15),
135
- [threads],
136
- );
137
96
  const displayedActiveThreadId =
138
97
  threadIdFromPath(location.pathname) ??
139
98
  (location.pathname === "/chat" ? null : activeThreadId);
140
- const chatItems = useMemo<ChatHistoryItem[]>(
141
- () =>
142
- visibleThreads.map((thread) => ({
143
- id: thread.id,
144
- title: threadTitle(thread),
145
- titleText: threadTitle(thread),
146
- timestamp:
147
- thread.id === displayedActiveThreadId
148
- ? undefined
149
- : formatThreadAge(threadUpdatedAt(thread)),
150
- pinned: Boolean(thread.pinnedAt),
151
- })),
152
- [displayedActiveThreadId, visibleThreads],
153
- );
154
-
155
- useEffect(() => {
156
- const refresh = () => refreshThreads();
157
- const handleRunning = (event: Event) => {
158
- const detail = (event as CustomEvent).detail as
159
- | { isRunning?: unknown }
160
- | undefined;
161
- if (typeof detail?.isRunning === "boolean") refreshThreads();
162
- };
163
-
164
- window.addEventListener("agent-chat:threads-updated", refresh);
165
- window.addEventListener("agentNative.chatRunning", handleRunning);
166
- window.addEventListener("focus", refresh);
167
- return () => {
168
- window.removeEventListener("agent-chat:threads-updated", refresh);
169
- window.removeEventListener("agentNative.chatRunning", handleRunning);
170
- window.removeEventListener("focus", refresh);
171
- };
172
- }, [refreshThreads]);
99
+ const history = useOwnershipChatHistory({
100
+ getThreadUrl: (threadId) => appPath(chatThreadPath(threadId)),
101
+ activeId: displayedActiveThreadId,
102
+ localMineRows: ownDraftRows({ threads, isNewThread }),
103
+ mutations: {
104
+ pin: pinThread,
105
+ rename: renameThread,
106
+ archive: archiveThread,
107
+ },
108
+ onMutationFailed: (kind) => {
109
+ toast.error(
110
+ t(
111
+ kind === "archive"
112
+ ? "chat.archiveFailed"
113
+ : kind === "rename"
114
+ ? "chat.renameFailed"
115
+ : "agentChat.common.saveFailed",
116
+ ),
117
+ );
118
+ },
119
+ });
173
120
 
174
121
  function openThread(threadId: string, options?: { isNew?: boolean }) {
175
122
  switchThread(threadId);
@@ -195,20 +142,12 @@ function ChatThreadsSection({ open }: { open: boolean }) {
195
142
  async function handleArchiveThread(threadId: string) {
196
143
  const wasActive =
197
144
  threadId === activeThreadId || threadId === persistedActiveThreadId();
198
- const archived = await archiveThread(threadId);
199
- if (!archived) {
200
- toast.error(t("chat.archiveFailed"));
201
- return;
202
- }
145
+ const archived = await history.listProps.onDelete!(threadId);
146
+ if (!archived) return false;
203
147
  if (wasActive) {
204
148
  await handleNewChat();
205
149
  }
206
- }
207
-
208
- function handleRenameThread(threadId: string, title: string) {
209
- void renameThread(threadId, title).then((renamed) => {
210
- if (!renamed) toast.error(t("chat.renameFailed"));
211
- });
150
+ return true;
212
151
  }
213
152
 
214
153
  return (
@@ -218,8 +157,8 @@ function ChatThreadsSection({ open }: { open: boolean }) {
218
157
  aria-hidden={!open}
219
158
  >
220
159
  <div className="ms-4">
221
- <ChatHistoryRail
222
- items={chatItems}
160
+ <OwnershipChatHistoryRail
161
+ {...history}
223
162
  activeId={displayedActiveThreadId}
224
163
  onSelect={(threadId) => openThread(threadId)}
225
164
  onNewChat={() => void handleNewChat()}
@@ -229,11 +168,6 @@ function ChatThreadsSection({ open }: { open: boolean }) {
229
168
  showLess: t("chat.chats"),
230
169
  }}
231
170
  renameMaxLength={160}
232
- onTogglePin={(threadId) => {
233
- const thread = visibleThreads.find((item) => item.id === threadId);
234
- if (thread) void pinThread(threadId, !thread.pinnedAt);
235
- }}
236
- onRename={handleRenameThread}
237
171
  onDelete={(threadId) => void handleArchiveThread(threadId)}
238
172
  labels={{
239
173
  options: (item) =>
@@ -5,7 +5,7 @@ import {
5
5
  useSetHeaderActions,
6
6
  useSetPageTitle,
7
7
  } from "@agent-native/toolkit/app-shell";
8
- import { VisibilityBadge } from "@agent-native/toolkit/sharing";
8
+ import { VisibilityBadge } from "@agent-native/toolkit/app/sharing/VisibilityBadge";
9
9
  import {
10
10
  IconPlus,
11
11
  IconLoader2,
@@ -13,6 +13,12 @@ time from the command menu (Cmd+K → "What's new").
13
13
 
14
14
  - Apps no longer keep server functions and databases warm by default; set `AGENT_NATIVE_ENABLE_KEEP_WARM=1` to opt in.
15
15
 
16
+ ## 2026-10-16
17
+
18
+ ### Added
19
+
20
+ - Owned and shared chats appear in separate history sections, with each shared chat's owner shown as an avatar and a Copy link action on every chat.
21
+
16
22
  ## 2026-10-13
17
23
 
18
24
  ### Fixed
@@ -2,7 +2,6 @@ import {
2
2
  navigateWithAgentChatViewTransition,
3
3
  sendToAgentChat,
4
4
  useChatThreads,
5
- type ChatThreadSummary,
6
5
  } from "@agent-native/core/client/agent-chat";
7
6
  import { useCodeMode } from "@agent-native/core/client/agent-chat";
8
7
  import { appPath } from "@agent-native/core/client/api-path";
@@ -10,6 +9,11 @@ import { useSession } from "@agent-native/core/client/hooks";
10
9
  import { useT } from "@agent-native/core/client/i18n";
11
10
  import { buildSignInReturnHref } from "@agent-native/core/client/sign-in-return";
12
11
  import { useSendToAgentChat } from "@agent-native/toolkit/app/chat/composer";
12
+ import {
13
+ OwnershipChatHistoryRail,
14
+ useOwnershipChatHistory,
15
+ ownDraftRows,
16
+ } from "@agent-native/toolkit/app/chat/ownership-history";
13
17
  import { DevDatabaseLink } from "@agent-native/toolkit/app/db-admin";
14
18
  import { FeedbackButton } from "@agent-native/toolkit/app/feedback";
15
19
  import { OrgSwitcher } from "@agent-native/toolkit/app/org";
@@ -21,10 +25,6 @@ import {
21
25
  } from "@agent-native/toolkit/app/shared";
22
26
  import { LazyChunkErrorBoundary } from "@agent-native/toolkit/app/shared";
23
27
  import { LazyChunkRetryFallback } from "@agent-native/toolkit/app/shared";
24
- import {
25
- ChatHistoryRail,
26
- type ChatHistoryItem,
27
- } from "@agent-native/toolkit/chat-history";
28
28
  import { planPathForKind } from "@shared/plan-routes";
29
29
  import {
30
30
  IconClipboardCheck,
@@ -34,14 +34,7 @@ import {
34
34
  IconRefresh,
35
35
  IconNews,
36
36
  } from "@tabler/icons-react";
37
- import {
38
- lazy,
39
- Suspense,
40
- useEffect,
41
- useMemo,
42
- useState,
43
- type MouseEvent,
44
- } from "react";
37
+ import { lazy, Suspense, useMemo, useState, type MouseEvent } from "react";
45
38
  import { Link, useLocation, useNavigate } from "react-router";
46
39
  import { toast } from "sonner";
47
40
 
@@ -121,40 +114,6 @@ function formatPlanAge(value: string) {
121
114
  });
122
115
  }
123
116
 
124
- function formatThreadAge(updatedAt: number) {
125
- const diffMs = Math.max(0, Date.now() - updatedAt);
126
- const minutes = Math.floor(diffMs / 60_000);
127
- if (minutes < 1) return "now";
128
- if (minutes < 60) return `${minutes}m`;
129
- const hours = Math.floor(minutes / 60);
130
- if (hours < 24) return `${hours}h`;
131
- const days = Math.floor(hours / 24);
132
- if (days < 7) return `${days}d`;
133
- return new Date(updatedAt).toLocaleDateString([], {
134
- month: "short",
135
- day: "numeric",
136
- });
137
- }
138
-
139
- function threadTitle(thread: ChatThreadSummary) {
140
- return thread.title || thread.preview || "Untitled chat";
141
- }
142
-
143
- function threadUpdatedAt(thread: ChatThreadSummary) {
144
- return Number.isFinite(thread.updatedAt)
145
- ? thread.updatedAt
146
- : Number.isFinite(thread.createdAt)
147
- ? thread.createdAt
148
- : 0;
149
- }
150
-
151
- function compareThreads(a: ChatThreadSummary, b: ChatThreadSummary) {
152
- const aPinned = a.pinnedAt ?? 0;
153
- const bPinned = b.pinnedAt ?? 0;
154
- if (aPinned || bPinned) return bPinned - aPinned;
155
- return threadUpdatedAt(b) - threadUpdatedAt(a);
156
- }
157
-
158
117
  function persistedActiveThreadId() {
159
118
  try {
160
119
  return localStorage.getItem(
@@ -182,53 +141,34 @@ function PlanChatsSection({
182
141
  pinThread,
183
142
  archiveThread,
184
143
  renameThread,
185
- refreshThreads,
144
+ isNewThread,
186
145
  } = useChatThreads(undefined, PLAN_CHAT_STORAGE_KEY, undefined, {
146
+ ownership: "mine",
187
147
  autoCreate: false,
188
148
  restoreActiveThread: false,
189
149
  });
190
150
 
191
- const visibleThreads = useMemo(
192
- () =>
193
- threads
194
- .filter((thread) => thread.messageCount > 0 && !thread.archivedAt)
195
- .sort(compareThreads)
196
- .slice(0, 15),
197
- [threads],
198
- );
199
- const chatItems = useMemo<ChatHistoryItem[]>(
200
- () =>
201
- visibleThreads.map((thread) => ({
202
- id: thread.id,
203
- title: threadTitle(thread),
204
- titleText: threadTitle(thread),
205
- timestamp:
206
- thread.id === activeThreadId
207
- ? undefined
208
- : formatThreadAge(threadUpdatedAt(thread)),
209
- pinned: Boolean(thread.pinnedAt),
210
- })),
211
- [activeThreadId, visibleThreads],
212
- );
213
-
214
- useEffect(() => {
215
- const refresh = () => refreshThreads();
216
- const handleRunning = (event: Event) => {
217
- const detail = (event as CustomEvent).detail as
218
- | { isRunning?: unknown }
219
- | undefined;
220
- if (typeof detail?.isRunning === "boolean") refreshThreads();
221
- };
222
-
223
- window.addEventListener("agent-chat:threads-updated", refresh);
224
- window.addEventListener("agentNative.chatRunning", handleRunning);
225
- window.addEventListener("focus", refresh);
226
- return () => {
227
- window.removeEventListener("agent-chat:threads-updated", refresh);
228
- window.removeEventListener("agentNative.chatRunning", handleRunning);
229
- window.removeEventListener("focus", refresh);
230
- };
231
- }, [refreshThreads]);
151
+ const history = useOwnershipChatHistory({
152
+ getThreadUrl: (threadId) => appPath(planChatThreadPath(threadId)),
153
+ activeId: activeThreadId,
154
+ localMineRows: ownDraftRows({ threads, isNewThread }),
155
+ mutations: {
156
+ pin: pinThread,
157
+ rename: renameThread,
158
+ archive: archiveThread,
159
+ },
160
+ onMutationFailed: (kind) => {
161
+ toast.error(
162
+ t(
163
+ kind === "archive"
164
+ ? "raw.sidebar.archiveChatFailed"
165
+ : kind === "rename"
166
+ ? "raw.sidebar.renameChatFailed"
167
+ : "agentChat.common.saveFailed",
168
+ ),
169
+ );
170
+ },
171
+ });
232
172
 
233
173
  if (collapsed) return null;
234
174
 
@@ -252,20 +192,12 @@ function PlanChatsSection({
252
192
  async function handleArchiveThread(threadId: string) {
253
193
  const wasActive =
254
194
  threadId === activeThreadId || threadId === persistedActiveThreadId();
255
- const archived = await archiveThread(threadId);
256
- if (!archived) {
257
- toast.error(t("raw.sidebar.archiveChatFailed"));
258
- return;
259
- }
195
+ const archived = await history.listProps.onDelete!(threadId);
196
+ if (!archived) return false;
260
197
  if (wasActive) {
261
198
  await handleNewChat();
262
199
  }
263
- }
264
-
265
- function handleRenameThread(threadId: string, title: string) {
266
- void renameThread(threadId, title).then((renamed) => {
267
- if (!renamed) toast.error(t("raw.sidebar.renameChatFailed"));
268
- });
200
+ return true;
269
201
  }
270
202
 
271
203
  return (
@@ -275,22 +207,15 @@ function PlanChatsSection({
275
207
  aria-hidden={!open}
276
208
  >
277
209
  <div className="ms-4">
278
- <ChatHistoryRail
279
- items={chatItems}
210
+ <OwnershipChatHistoryRail
211
+ {...history}
280
212
  activeId={activeThreadId}
281
213
  onSelect={(threadId) => openThread(threadId)}
282
214
  onNewChat={() => void handleNewChat()}
283
215
  railLabels={{
284
216
  newChat: t("sidebar.newChat"),
285
- showMore: t("sidebar.chats"),
286
- showLess: t("sidebar.chats"),
287
217
  }}
288
218
  renameMaxLength={160}
289
- onTogglePin={(threadId) => {
290
- const thread = visibleThreads.find((item) => item.id === threadId);
291
- if (thread) void pinThread(threadId, !thread.pinnedAt);
292
- }}
293
- onRename={handleRenameThread}
294
219
  onDelete={(threadId) => void handleArchiveThread(threadId)}
295
220
  labels={{
296
221
  options: (item) => `${t("sidebar.chats")}: ${item.titleText ?? ""}`,
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-10-16
4
+ ---
5
+
6
+ Owned and shared chats appear in separate history sections, with each shared chat's owner shown as an avatar and a Copy link action on every chat.
@@ -47,6 +47,7 @@ time from the command menu (Cmd+K → "What's new").
47
47
 
48
48
  ### Improved
49
49
 
50
+ - Deck lists use the shared ownership filter, and visibility badges use localized labels.
50
51
  - Contextual toolbar: the second row now changes with what is selected (text, shape, image, video, multi-select), and every state ends with an Edit with Agent button with quick picks.
51
52
  - The top bar shows a deck's privacy next to its name, Share has People and Agents tabs, and Present opens a menu to start in this tab, full screen, or Presenter View.
52
53