@agent-native/core-corpus 0.217.0 → 0.219.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 (81) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +5 -3
  3. package/corpus/templates/analytics/CHANGELOG.md +2 -0
  4. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +38 -167
  5. package/corpus/templates/analytics/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  6. package/corpus/templates/assets/CHANGELOG.md +6 -0
  7. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +51 -117
  8. package/corpus/templates/assets/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  9. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +34 -101
  10. package/corpus/templates/brain/app/routes/sources.tsx +1 -1
  11. package/corpus/templates/brain/vitest.config.ts +7 -0
  12. package/corpus/templates/calendar/CHANGELOG.md +6 -0
  13. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +1 -1
  14. package/corpus/templates/calendar/changelog/2026-10-16-booking-links-show-localized-visibility-badges.md +6 -0
  15. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +62 -101
  16. package/corpus/templates/clips/CHANGELOG.md +7 -20
  17. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +20 -77
  18. package/corpus/templates/clips/app/components/player/share-dialog.tsx +63 -90
  19. package/corpus/templates/clips/app/components/sharing/share-test-support.tsx +180 -0
  20. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -584
  21. package/corpus/templates/clips/changelog/2026-10-16-share-dialogs-make-it-easier-to-see-who-has-access-and-manag.md +6 -0
  22. package/corpus/templates/clips/changelog/2026-10-21-share-panels-describe-general-access-in-a-sentence.md +6 -0
  23. package/corpus/templates/community/qr/package.json +1 -1
  24. package/corpus/templates/content/CHANGELOG.md +7 -0
  25. package/corpus/templates/content/app/components/editor/CommentStack.tsx +301 -0
  26. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +770 -179
  27. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +75 -27
  28. package/corpus/templates/content/app/components/editor/SuggestionText.tsx +18 -3
  29. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +89 -22
  30. package/corpus/templates/content/app/components/editor/block-field-comment-threads.ts +15 -0
  31. package/corpus/templates/content/app/components/editor/block-field-comments.tsx +5 -9
  32. package/corpus/templates/content/app/components/editor/comment-stacks.ts +143 -0
  33. package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +383 -34
  34. package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +31 -0
  35. package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +82 -4
  36. package/corpus/templates/content/app/global.css +31 -0
  37. package/corpus/templates/content/app/i18n-data.ts +8 -0
  38. package/corpus/templates/content/changelog/2026-10-16-accepting-a-suggestion-on-a-page-that-changed-since-it-was-s.md +6 -0
  39. package/corpus/templates/content/changelog/2026-10-20-suggested-edits-that-add-remove-split-or-merge-paragraphs-li.md +6 -0
  40. package/corpus/templates/content/changelog/2026-10-22-blocks-with-several-comment-threads-fold-into-one-stack-in-t.md +6 -0
  41. package/corpus/templates/content/changelog/2026-10-22-opening-a-page-no-longer-saves-an-edit-again-after-another-o.md +6 -0
  42. package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +8 -1
  43. package/corpus/templates/content/shared/suggestion-diff.ts +23 -6
  44. package/corpus/templates/content/shared/suggestion-formatting.ts +44 -14
  45. package/corpus/templates/content/shared/suggestion-text.ts +20 -5
  46. package/corpus/templates/design/.generated/bridge/interact-links.generated.ts +8 -8
  47. package/corpus/templates/design/CHANGELOG.md +8 -0
  48. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +18 -1
  49. package/corpus/templates/design/app/components/design/bridge/interact-links.bridge.ts +8 -8
  50. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +15 -13
  51. package/corpus/templates/design/app/i18n/en-US.ts +1 -1
  52. package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -1
  53. package/corpus/templates/design/app/pages/Index.tsx +18 -64
  54. package/corpus/templates/design/app/pages/design-editor/domains/use-editor-modes.ts +15 -6
  55. package/corpus/templates/design/app/pages/design-editor/domains/use-editor-screen-rendering.tsx +29 -5
  56. package/corpus/templates/design/app/pages/design-editor/prototype-navigation-transition.ts +423 -0
  57. package/corpus/templates/design/app/pages/design-editor/view/single-screen-canvas.tsx +35 -9
  58. package/corpus/templates/design/changelog/2026-10-16-design-pages-use-localized-visibility-badges-and-a-shared-ow.md +6 -0
  59. package/corpus/templates/design/changelog/2026-10-20-the-design-full-app-toggle-on-the-home-page-no-longer-hides-.md +6 -0
  60. package/corpus/templates/design/changelog/2026-10-22-prototype-links-can-play-code-authored-screen-transitions.md +6 -0
  61. package/corpus/templates/design/shared/motion-authored-css-import.ts +938 -7
  62. package/corpus/templates/design/shared/motion-html-source.ts +1689 -135
  63. package/corpus/templates/design/shared/motion-prototype-transition.ts +329 -0
  64. package/corpus/templates/design/shared/motion-react-source.ts +2154 -126
  65. package/corpus/templates/design/shared/motion-text-runtime-v1.fixture.txt +221 -0
  66. package/corpus/templates/dispatch/CHANGELOG.md +4 -0
  67. package/corpus/templates/dispatch/app/i18n-data.ts +75 -0
  68. package/corpus/templates/dispatch/changelog/2026-10-21-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  69. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +34 -100
  70. package/corpus/templates/forms/app/pages/FormsListPage.tsx +1 -1
  71. package/corpus/templates/plan/CHANGELOG.md +6 -0
  72. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +34 -109
  73. package/corpus/templates/plan/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
  74. package/corpus/templates/slides/CHANGELOG.md +1 -0
  75. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
  76. package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +1 -1
  77. package/corpus/templates/slides/app/pages/Index.tsx +7 -2
  78. package/corpus/templates/slides/changelog/2026-10-16-deck-lists-use-the-shared-ownership-filter-and-visibility-ba.md +6 -0
  79. package/package.json +1 -1
  80. package/corpus/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
  81. package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +0 -83
@@ -0,0 +1,221 @@
1
+ (function (source) {
2
+ var animations = source.animations;
3
+ var playbackMode = source.playbackMode;
4
+ if (typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
5
+ if (!document || typeof document.querySelectorAll !== "function") throw new Error("Motion text runtime requires a document.");
6
+ var previewBridge = typeof window !== "undefined" && window.__designMotionPreviewBridge === true;
7
+ var previewAnimations = [];
8
+ var allTargets = Array.prototype.slice.call(document.querySelectorAll("[data-agent-native-node-id]"));
9
+ var paragraphTags = { blockquote: true, h1: true, h2: true, h3: true, h4: true, h5: true, h6: true, li: true, p: true };
10
+ function textTokens(value, kind) {
11
+ var Segmenter = typeof Intl !== "undefined" ? Intl.Segmenter : null;
12
+ if (kind === "character") {
13
+ var characters = Segmenter ? Array.from(new Segmenter(undefined, { granularity: "grapheme" }).segment(value), function (part) { return part.segment; }) : Array.from(value);
14
+ return characters.map(function (part) { return { value: part, animated: !/^\s+$/u.test(part) }; });
15
+ }
16
+ var chunks;
17
+ if (Segmenter) {
18
+ chunks = Array.from(new Segmenter(undefined, { granularity: "word" }).segment(value), function (part) { return { value: part.segment, word: !!part.isWordLike }; });
19
+ } else {
20
+ chunks = (value.match(/\s+|[^\s]+/gu) || []).map(function (part) { return { value: part, word: !/^\s+$/u.test(part) }; });
21
+ }
22
+ var tokens = [];
23
+ for (var index = 0; index < chunks.length; index += 1) {
24
+ var chunk = chunks[index];
25
+ if (/^\s+$/u.test(chunk.value)) {
26
+ tokens.push({ value: chunk.value, animated: false });
27
+ } else if (chunk.word) {
28
+ tokens.push({ value: chunk.value, animated: true });
29
+ } else if (tokens.length && tokens[tokens.length - 1].animated) {
30
+ tokens[tokens.length - 1].value += chunk.value;
31
+ } else {
32
+ var nextWord = chunks.slice(index + 1).findIndex(function (candidate) { return candidate.word; });
33
+ if (nextWord >= 0) {
34
+ var punctuation = chunk.value;
35
+ while (index + 1 < chunks.length && !chunks[index + 1].word && !/^\s+$/u.test(chunks[index + 1].value)) punctuation += chunks[++index].value;
36
+ tokens.push({ value: punctuation, animated: true });
37
+ } else {
38
+ tokens.push({ value: chunk.value, animated: false });
39
+ }
40
+ }
41
+ }
42
+ return tokens;
43
+ }
44
+ function descendantTextNodes(target) {
45
+ var nodes = [];
46
+ function visit(node) {
47
+ if (node.nodeName === "#text") { nodes.push(node); return; }
48
+ Array.prototype.slice.call(node.childNodes || []).forEach(visit);
49
+ }
50
+ visit(target);
51
+ return nodes;
52
+ }
53
+ function nodeText(node) {
54
+ return typeof node.nodeValue === "string" ? node.nodeValue : (node.value || "");
55
+ }
56
+ function splitTextTarget(target, kind) {
57
+ var leaves = descendantTextNodes(target);
58
+ var value = leaves.map(nodeText).join("");
59
+ var tokens = textTokens(value, kind === "line" ? "word" : kind);
60
+ var units = [];
61
+ var sourceOffset = 0;
62
+ tokens.forEach(function (token) {
63
+ var start = sourceOffset;
64
+ var end = start + token.value.length;
65
+ sourceOffset = end;
66
+ if (token.animated) units.push({ start: start, end: end, index: units.length, fragments: [] });
67
+ });
68
+ if (units.length === 0) throw new Error("Motion text target has no animatable text units.");
69
+ if (units.length > 512) throw new Error("Motion text target exceeds the 512-unit runtime limit.");
70
+
71
+ var leafOffset = 0;
72
+ leaves.forEach(function (leaf) {
73
+ var text = nodeText(leaf);
74
+ var leafStart = leafOffset;
75
+ var leafEnd = leafStart + text.length;
76
+ leafOffset = leafEnd;
77
+ if (!text.length) return;
78
+
79
+ var fragment = document.createDocumentFragment();
80
+ var cursor = 0;
81
+ tokens.forEach(function (token) {
82
+ var tokenStart = cursor;
83
+ var tokenEnd = tokenStart + token.value.length;
84
+ cursor = tokenEnd;
85
+ var start = Math.max(leafStart, tokenStart);
86
+ var end = Math.min(leafEnd, tokenEnd);
87
+ if (start >= end) return;
88
+ var part = text.slice(start - leafStart, end - leafStart);
89
+ if (!token.animated) {
90
+ fragment.appendChild(document.createTextNode(part));
91
+ return;
92
+ }
93
+ var unitIndex = units.findIndex(function (unit) { return unit.start === tokenStart; });
94
+ var unit = units[unitIndex];
95
+ var span = document.createElement("span");
96
+ span.setAttribute("data-agent-native-motion-text-unit", String(unit.index));
97
+ span.style.display = "inline-block";
98
+ span.appendChild(document.createTextNode(part));
99
+ fragment.appendChild(span);
100
+ unit.fragments.push(span);
101
+ });
102
+ if (leaf.parentNode) leaf.parentNode.replaceChild(fragment, leaf);
103
+ });
104
+ return units;
105
+ }
106
+ function paragraphUnits(target) {
107
+ var tag = String(target.tagName || "").toLowerCase();
108
+ if (paragraphTags[tag]) return [target];
109
+ var children = Array.prototype.slice.call(target.children || []);
110
+ if (children.length && children.every(function (child) { return paragraphTags[String(child.tagName || "").toLowerCase()]; })) return children;
111
+ if (children.length) throw new Error("Paragraph Text animation found unsupported nested elements.");
112
+ return [target];
113
+ }
114
+ function lineGroups(units) {
115
+ var tops = [];
116
+ return units.map(function (unit, index) {
117
+ var top = unit.getBoundingClientRect().top;
118
+ var found = tops.findIndex(function (existing) { return Math.abs(existing - top) < 0.5; });
119
+ if (found < 0) { tops.push(top); found = tops.length - 1; }
120
+ return { unit: unit, index: found };
121
+ });
122
+ }
123
+ function springSample(bounce, settle, x) {
124
+ if (x <= 0) return 0;
125
+ var u = x / settle;
126
+ if (u >= 1) return 1;
127
+ var zeta = Math.min(1, Math.max(0.02, 1 - bounce));
128
+ var omega = Math.log(1 / 0.001) / zeta;
129
+ if (zeta >= 1) return 1 - Math.exp(-omega * u) * (1 + omega * u);
130
+ var omegaD = omega * Math.sqrt(1 - zeta * zeta);
131
+ var decay = Math.exp(-zeta * omega * u);
132
+ return 1 - decay * (Math.cos(omegaD * u) + ((zeta * omega) / omegaD) * Math.sin(omegaD * u));
133
+ }
134
+ function springToLinear(bounce, settle) {
135
+ var sampleCount = 16 + Math.round(bounce * 34);
136
+ var stops = [];
137
+ for (var index = 0; index <= sampleCount; index += 1) {
138
+ var value = index === sampleCount ? 1 : springSample(bounce, settle, index / sampleCount);
139
+ stops.push((Math.round(value * 10000) / 10000).toString());
140
+ }
141
+ return "linear(" + stops.join(", ") + ")";
142
+ }
143
+ function motionEaseForWebAnimations(ease, element) {
144
+ var resolved = ease;
145
+ var reference = /^var\(--an-motion-ease-([a-z0-9][a-z0-9-]{0,63})\)$/.exec(String(ease));
146
+ if (reference) {
147
+ var property = "--an-motion-ease-" + reference[1];
148
+ resolved = window.getComputedStyle(element).getPropertyValue(property).trim();
149
+ if (!resolved || /^var\(/i.test(resolved)) throw new Error("Motion easing variable " + property + " is not defined or does not resolve to a concrete easing.");
150
+ }
151
+ var normalized = String(resolved).trim();
152
+ if (normalized.toLowerCase() === "spring") return springToLinear(0.25, 1);
153
+ var spring = /^spring\(\s*([+-]?(?:\d+\.?\d*|\.\d+))\s*(?:,\s*([+-]?(?:\d+\.?\d*|\.\d+))\s*)?\)$/i.exec(normalized);
154
+ if (/^spring/i.test(normalized) && !spring) throw new Error("Motion text easing is not supported: " + normalized);
155
+ if (spring) return springToLinear(Number(spring[1]), Number(spring[2] || 1));
156
+ return resolved;
157
+ }
158
+ var targetGroups = [];
159
+ animations.forEach(function (animation) {
160
+ var group = targetGroups.find(function (candidate) { return candidate.targetNodeId === animation.targetNodeId; });
161
+ if (!group) { group = { targetNodeId: animation.targetNodeId, animations: [] }; targetGroups.push(group); }
162
+ group.animations.push(animation);
163
+ });
164
+ targetGroups.forEach(function (targetGroup) {
165
+ var animation = targetGroup.animations[0];
166
+ var matches = allTargets.filter(function (candidate) { return candidate.getAttribute("data-agent-native-node-id") === targetGroup.targetNodeId; });
167
+ if (matches.length !== 1) throw new Error("Motion text target " + targetGroup.targetNodeId + " resolved to " + matches.length + " elements.");
168
+ var target = matches[0];
169
+ var entries;
170
+ if (animation.unit === "paragraph") {
171
+ entries = paragraphUnits(target).map(function (unit, index) { return { unit: unit, index: index }; });
172
+ } else {
173
+ var units = splitTextTarget(target, animation.unit);
174
+ var fragments = units.reduce(function (all, unit) { return all.concat(unit.fragments); }, []);
175
+ entries = animation.unit === "line"
176
+ ? lineGroups(fragments)
177
+ : fragments.map(function (unit) { return { unit: unit, index: Number(unit.getAttribute("data-agent-native-motion-text-unit")) }; });
178
+ }
179
+ var groupCount = entries.reduce(function (count, entry) { return Math.max(count, entry.index + 1); }, 0);
180
+ if ((groupCount - 1) * animation.staggerMs > 120000) throw new Error("Motion text stagger exceeds the 120000ms runtime limit.");
181
+ targetGroup.animations.forEach(function (track) {
182
+ entries.forEach(function (entry) {
183
+ if (typeof entry.unit.animate !== "function") throw new Error("Motion text requires the Web Animations API.");
184
+ var delayIndex = track.direction === "reverse" ? groupCount - 1 - entry.index : entry.index;
185
+ var keyframes = track.keyframes.map(function (keyframe) {
186
+ var frame = { offset: keyframe.t, easing: motionEaseForWebAnimations(keyframe.ease || "ease", entry.unit) };
187
+ frame[track.property] = keyframe.value;
188
+ return frame;
189
+ });
190
+ var delay = track.delayMs + delayIndex * track.staggerMs;
191
+ var options = { duration: track.durationMs, delay: delay, fill: "both" };
192
+ if (!previewBridge && playbackMode !== "once") {
193
+ options.iterations = Infinity;
194
+ if (playbackMode === "ping-pong") options.direction = "alternate";
195
+ }
196
+ var runningAnimation = entry.unit.animate(keyframes, options);
197
+ if (previewBridge) {
198
+ runningAnimation.pause();
199
+ runningAnimation.currentTime = 0;
200
+ previewAnimations.push({ animation: runningAnimation, delay: delay, duration: track.durationMs });
201
+ }
202
+ });
203
+ });
204
+ });
205
+ if (previewBridge && typeof window.addEventListener === "function") {
206
+ window.addEventListener("message", function (event) {
207
+ if (event.source !== window.parent || !event.data || typeof event.data.type !== "string") return;
208
+ if (event.data.type === "motion-preview") {
209
+ var t = Number(event.data.t);
210
+ var timelineDuration = Number(event.data.durationMs);
211
+ if (!Number.isFinite(t) || !Number.isFinite(timelineDuration) || timelineDuration <= 0) return;
212
+ var timelineTime = Math.max(0, Math.min(1, t)) * timelineDuration;
213
+ previewAnimations.forEach(function (entry) {
214
+ entry.animation.currentTime = Math.max(0, Math.min(entry.duration, timelineTime - entry.delay));
215
+ });
216
+ } else if (event.data.type === "motion-preview-clear") {
217
+ previewAnimations.forEach(function (entry) { entry.animation.currentTime = 0; });
218
+ }
219
+ });
220
+ }
221
+ })(__MOTION_TEXT_SOURCE__);
@@ -5,6 +5,10 @@ time from the command menu (Cmd+K → "What's new").
5
5
 
6
6
  ## 2026-10-21
7
7
 
8
+ ### Added
9
+
10
+ - 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.
11
+
8
12
  ### Improved
9
13
 
10
14
  - Customer AI credit questions route to account health instead of workspace spend metrics.
@@ -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,