@agent-native/core 0.101.6 → 0.101.10

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 (237) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +28 -0
  3. package/corpus/core/docs/content/deployment.mdx +9 -7
  4. package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +9 -7
  5. package/corpus/core/docs/content/locales/de-DE/deployment.mdx +9 -7
  6. package/corpus/core/docs/content/locales/es-ES/deployment.mdx +9 -7
  7. package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +9 -7
  8. package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +9 -7
  9. package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +9 -7
  10. package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +9 -7
  11. package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +9 -7
  12. package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +9 -7
  13. package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +9 -7
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/a2a/artifact-response.ts +255 -12
  16. package/corpus/core/src/agent/thread-data-builder.ts +84 -11
  17. package/corpus/core/src/client/review/ReviewCommentComposer.tsx +9 -1
  18. package/corpus/core/src/client/review/ReviewThreadPanel.tsx +17 -2
  19. package/corpus/core/src/client/settings/SettingsPanel.tsx +41 -21
  20. package/corpus/core/src/client/settings/useBuilderStatus.ts +28 -9
  21. package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +2 -7
  22. package/corpus/core/src/integrations/a2a-continuation-processor.ts +99 -7
  23. package/corpus/core/src/integrations/adapters/discord.ts +3 -1
  24. package/corpus/core/src/integrations/adapters/email.ts +4 -1
  25. package/corpus/core/src/integrations/adapters/google-docs.ts +4 -1
  26. package/corpus/core/src/integrations/adapters/microsoft-teams.ts +3 -1
  27. package/corpus/core/src/integrations/adapters/slack.ts +38 -9
  28. package/corpus/core/src/integrations/adapters/telegram.ts +32 -10
  29. package/corpus/core/src/integrations/adapters/whatsapp.ts +5 -1
  30. package/corpus/core/src/integrations/index.ts +1 -0
  31. package/corpus/core/src/integrations/types.ts +9 -2
  32. package/corpus/core/src/integrations/webhook-handler.ts +69 -45
  33. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +1 -0
  34. package/corpus/core/src/server/auth.ts +25 -1
  35. package/corpus/core/src/server/builder-browser.ts +353 -1
  36. package/corpus/core/src/server/core-routes-plugin.ts +601 -223
  37. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +80 -1
  38. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +28 -3
  39. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +5 -1
  40. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +30 -3
  41. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +196 -0
  42. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +115 -1
  43. package/corpus/templates/calendar/app/lib/out-of-office.ts +45 -0
  44. package/corpus/templates/calendar/changelog/2026-07-14-out-of-office-blocks-now-sit-behind-meetings-and-event-stack.md +6 -0
  45. package/corpus/templates/content/.agents/skills/content/SKILL.md +31 -0
  46. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +35 -21
  47. package/corpus/templates/content/AGENTS.md +32 -9
  48. package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +87 -0
  49. package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -25
  50. package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +1 -0
  51. package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +427 -18
  52. package/corpus/templates/content/actions/_builder-cms-write-client.ts +17 -73
  53. package/corpus/templates/content/actions/_builder-cms-write-settings.ts +27 -7
  54. package/corpus/templates/content/actions/_builder-source-execution-claim.ts +124 -0
  55. package/corpus/templates/content/actions/_builder-source-execution-preservation.ts +21 -0
  56. package/corpus/templates/content/actions/_builder-source-timings.ts +57 -0
  57. package/corpus/templates/content/actions/_database-source-utils.ts +1071 -170
  58. package/corpus/templates/content/actions/_database-utils.ts +104 -13
  59. package/corpus/templates/content/actions/_local-file-documents.ts +53 -1
  60. package/corpus/templates/content/actions/_preview-document-draft.ts +31 -0
  61. package/corpus/templates/content/actions/_property-utils.ts +7 -1
  62. package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +309 -0
  63. package/corpus/templates/content/actions/configure-document-property.ts +11 -0
  64. package/corpus/templates/content/actions/create-content-database.ts +11 -0
  65. package/corpus/templates/content/actions/create-document.ts +9 -0
  66. package/corpus/templates/content/actions/create-inline-content-database.ts +3 -0
  67. package/corpus/templates/content/actions/execute-builder-source-batch.ts +120 -49
  68. package/corpus/templates/content/actions/execute-builder-source-execution.ts +608 -264
  69. package/corpus/templates/content/actions/export-content-source.ts +1 -0
  70. package/corpus/templates/content/actions/get-content-database.ts +13 -1
  71. package/corpus/templates/content/actions/get-document.ts +12 -2
  72. package/corpus/templates/content/actions/get-preview-document-draft.ts +26 -0
  73. package/corpus/templates/content/actions/import-content-source.ts +6 -0
  74. package/corpus/templates/content/actions/list-documents.ts +3 -0
  75. package/corpus/templates/content/actions/materialize-builder-required-fields.ts +550 -0
  76. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +112 -65
  77. package/corpus/templates/content/actions/prepare-builder-source-review.ts +463 -170
  78. package/corpus/templates/content/actions/preview-builder-source-review.ts +99 -0
  79. package/corpus/templates/content/actions/pull-document.ts +2 -0
  80. package/corpus/templates/content/actions/search-documents.ts +5 -1
  81. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +2 -2
  82. package/corpus/templates/content/actions/update-document.ts +16 -1
  83. package/corpus/templates/content/actions/update-preview-document-draft.ts +153 -0
  84. package/corpus/templates/content/actions/view-screen.ts +15 -2
  85. package/corpus/templates/content/app/components/editor/DescriptionField.tsx +121 -0
  86. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +14 -0
  87. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +250 -49
  88. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +57 -5
  89. package/corpus/templates/content/app/components/editor/body-hydration.ts +27 -0
  90. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2414 -589
  91. package/corpus/templates/content/app/components/editor/database/settings.tsx +13 -10
  92. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +358 -75
  93. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +124 -29
  94. package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +2 -0
  95. package/corpus/templates/content/app/global.css +18 -1
  96. package/corpus/templates/content/app/hooks/use-content-database.ts +68 -0
  97. package/corpus/templates/content/app/hooks/use-documents.ts +53 -4
  98. package/corpus/templates/content/app/i18n/zh-TW.ts +30 -0
  99. package/corpus/templates/content/app/i18n-data.ts +339 -0
  100. package/corpus/templates/content/changelog/2026-07-10-builder-backed-preview-edits-are-preserved-when-article-bodi.md +6 -0
  101. package/corpus/templates/content/changelog/2026-07-10-builder-cms-sources-can-now-be-enabled-for-guarded-staged-or.md +6 -0
  102. package/corpus/templates/content/changelog/2026-07-13-builder-connection-setup-is-now-available-directly-from-conn.md +6 -0
  103. package/corpus/templates/content/changelog/2026-07-13-builder-reviews-now-hide-already-applied-writes-detect-nativ.md +6 -0
  104. package/corpus/templates/content/changelog/2026-07-13-required-builder-publishing-fields-can-now-be-added-directly.md +6 -0
  105. package/corpus/templates/content/changelog/2026-07-13-you-can-now-cancel-a-prepared-builder-update-safely-before-i.md +6 -0
  106. package/corpus/templates/content/changelog/2026-07-14-builder-account-connection-now-remains-available-when-branch.md +6 -0
  107. package/corpus/templates/content/changelog/2026-07-14-builder-backed-articles-now-preserve-fifth-and-sixth-level-h.md +6 -0
  108. package/corpus/templates/content/changelog/2026-07-14-builder-sources-now-review-and-publish-rich-article-updates-.md +6 -0
  109. package/corpus/templates/content/changelog/2026-07-14-builder-writes-now-stop-retries-when-reconciliation-is-needed.md +6 -0
  110. package/corpus/templates/content/changelog/2026-07-14-file-and-media-links-now-validate-before-saving.md +6 -0
  111. package/corpus/templates/content/changelog/2026-07-14-pages-and-databases-can-describe-themselves-with-guidance-fo.md +6 -0
  112. package/corpus/templates/content/changelog/2026-07-14-slack-follow-ups-now-retain-created-content-identity-and-per.md +6 -0
  113. package/corpus/templates/content/parity/matrix.md +27 -25
  114. package/corpus/templates/content/parity/matrix.ts +50 -2
  115. package/corpus/templates/content/server/db/schema.ts +51 -0
  116. package/corpus/templates/content/server/lib/document-context.ts +76 -0
  117. package/corpus/templates/content/server/lib/public-documents.ts +3 -0
  118. package/corpus/templates/content/server/plugins/auth.ts +1 -0
  119. package/corpus/templates/content/server/plugins/db.ts +59 -0
  120. package/corpus/templates/content/server/routes/api/document-agent-context.json.get.ts +5 -0
  121. package/corpus/templates/content/shared/api.ts +87 -1
  122. package/corpus/templates/content/shared/builder-mdx.ts +705 -15
  123. package/corpus/templates/content/shared/content-source.ts +7 -0
  124. package/corpus/templates/content/shared/nfm.ts +3 -3
  125. package/corpus/templates/content/shared/properties.ts +2 -0
  126. package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +52 -7
  127. package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +36 -4
  128. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
  129. package/corpus/templates/design/app/i18n/ar-SA.ts +1 -0
  130. package/corpus/templates/design/app/i18n/de-DE.ts +1 -0
  131. package/corpus/templates/design/app/i18n/en-US.ts +1 -0
  132. package/corpus/templates/design/app/i18n/es-ES.ts +1 -0
  133. package/corpus/templates/design/app/i18n/fr-FR.ts +1 -0
  134. package/corpus/templates/design/app/i18n/hi-IN.ts +1 -0
  135. package/corpus/templates/design/app/i18n/ja-JP.ts +1 -0
  136. package/corpus/templates/design/app/i18n/ko-KR.ts +1 -0
  137. package/corpus/templates/design/app/i18n/pt-BR.ts +1 -0
  138. package/corpus/templates/design/app/i18n/zh-CN.ts +1 -0
  139. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  140. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +8 -0
  141. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +11 -0
  142. package/corpus/templates/design/changelog/2026-07-14-reviewers-can-now-pin-comments-from-the-canvas-toolbar-targe.md +6 -0
  143. package/corpus/templates/design/changelog/2026-07-15-viewer-comment-controls-now-sit-inside-the-read-only-notice-.md +6 -0
  144. package/corpus/templates/design/shared/review-anchor.ts +48 -0
  145. package/corpus/templates/plan/server/plan-mdx.ts +53 -7
  146. package/dist/a2a/artifact-response.d.ts +15 -0
  147. package/dist/a2a/artifact-response.d.ts.map +1 -1
  148. package/dist/a2a/artifact-response.js +204 -5
  149. package/dist/a2a/artifact-response.js.map +1 -1
  150. package/dist/agent/thread-data-builder.d.ts +6 -0
  151. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  152. package/dist/agent/thread-data-builder.js +71 -8
  153. package/dist/agent/thread-data-builder.js.map +1 -1
  154. package/dist/client/review/ReviewCommentComposer.d.ts +2 -1
  155. package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
  156. package/dist/client/review/ReviewCommentComposer.js +3 -3
  157. package/dist/client/review/ReviewCommentComposer.js.map +1 -1
  158. package/dist/client/review/ReviewThreadPanel.d.ts +9 -1
  159. package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
  160. package/dist/client/review/ReviewThreadPanel.js +6 -4
  161. package/dist/client/review/ReviewThreadPanel.js.map +1 -1
  162. package/dist/client/settings/SettingsPanel.d.ts +3 -0
  163. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  164. package/dist/client/settings/SettingsPanel.js +11 -4
  165. package/dist/client/settings/SettingsPanel.js.map +1 -1
  166. package/dist/client/settings/useBuilderStatus.d.ts +8 -4
  167. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  168. package/dist/client/settings/useBuilderStatus.js +19 -6
  169. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  170. package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
  171. package/dist/client/setup-connections/BuilderConnectCard.js +2 -5
  172. package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
  173. package/dist/collab/awareness.d.ts +2 -2
  174. package/dist/collab/awareness.d.ts.map +1 -1
  175. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  176. package/dist/integrations/a2a-continuation-processor.js +72 -6
  177. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  178. package/dist/integrations/adapters/discord.d.ts.map +1 -1
  179. package/dist/integrations/adapters/discord.js +1 -0
  180. package/dist/integrations/adapters/discord.js.map +1 -1
  181. package/dist/integrations/adapters/email.d.ts.map +1 -1
  182. package/dist/integrations/adapters/email.js +2 -0
  183. package/dist/integrations/adapters/email.js.map +1 -1
  184. package/dist/integrations/adapters/google-docs.d.ts.map +1 -1
  185. package/dist/integrations/adapters/google-docs.js +2 -0
  186. package/dist/integrations/adapters/google-docs.js.map +1 -1
  187. package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -1
  188. package/dist/integrations/adapters/microsoft-teams.js +1 -0
  189. package/dist/integrations/adapters/microsoft-teams.js.map +1 -1
  190. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  191. package/dist/integrations/adapters/slack.js +21 -6
  192. package/dist/integrations/adapters/slack.js.map +1 -1
  193. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  194. package/dist/integrations/adapters/telegram.js +11 -2
  195. package/dist/integrations/adapters/telegram.js.map +1 -1
  196. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  197. package/dist/integrations/adapters/whatsapp.js +3 -0
  198. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  199. package/dist/integrations/index.d.ts +1 -1
  200. package/dist/integrations/index.d.ts.map +1 -1
  201. package/dist/integrations/index.js.map +1 -1
  202. package/dist/integrations/types.d.ts +8 -2
  203. package/dist/integrations/types.d.ts.map +1 -1
  204. package/dist/integrations/types.js.map +1 -1
  205. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  206. package/dist/integrations/webhook-handler.js +40 -43
  207. package/dist/integrations/webhook-handler.js.map +1 -1
  208. package/dist/observability/routes.d.ts +5 -5
  209. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  210. package/dist/secrets/routes.d.ts +9 -9
  211. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  212. package/dist/server/agent-chat/action-filters-a2a.js +1 -0
  213. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  214. package/dist/server/auth.d.ts +1 -0
  215. package/dist/server/auth.d.ts.map +1 -1
  216. package/dist/server/auth.js +19 -2
  217. package/dist/server/auth.js.map +1 -1
  218. package/dist/server/builder-browser.d.ts +78 -0
  219. package/dist/server/builder-browser.d.ts.map +1 -1
  220. package/dist/server/builder-browser.js +246 -1
  221. package/dist/server/builder-browser.js.map +1 -1
  222. package/dist/server/core-routes-plugin.d.ts +41 -0
  223. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  224. package/dist/server/core-routes-plugin.js +260 -14
  225. package/dist/server/core-routes-plugin.js.map +1 -1
  226. package/docs/content/deployment.mdx +9 -7
  227. package/docs/content/locales/ar-SA/deployment.mdx +9 -7
  228. package/docs/content/locales/de-DE/deployment.mdx +9 -7
  229. package/docs/content/locales/es-ES/deployment.mdx +9 -7
  230. package/docs/content/locales/fr-FR/deployment.mdx +9 -7
  231. package/docs/content/locales/hi-IN/deployment.mdx +9 -7
  232. package/docs/content/locales/ja-JP/deployment.mdx +9 -7
  233. package/docs/content/locales/ko-KR/deployment.mdx +9 -7
  234. package/docs/content/locales/pt-BR/deployment.mdx +9 -7
  235. package/docs/content/locales/zh-CN/deployment.mdx +9 -7
  236. package/docs/content/locales/zh-TW/deployment.mdx +9 -7
  237. package/package.json +2 -2
@@ -6,6 +6,7 @@ export interface ContentSourceDocument {
6
6
  parentId: string | null;
7
7
  title: string;
8
8
  content: string;
9
+ description?: string;
9
10
  icon: string | null;
10
11
  position: number;
11
12
  isFavorite: boolean;
@@ -31,6 +32,7 @@ export interface ParsedContentSourceFile {
31
32
  parentId?: string | null;
32
33
  title: string;
33
34
  content: string;
35
+ description?: string;
34
36
  icon?: string | null;
35
37
  position?: number;
36
38
  isFavorite?: boolean;
@@ -152,6 +154,7 @@ export function serializeContentSourceDocument(
152
154
  const frontmatter = [
153
155
  frontmatterLine("id", doc.id),
154
156
  frontmatterLine("title", doc.title || "Untitled"),
157
+ frontmatterLine("description", doc.description),
155
158
  frontmatterLine("parentId", doc.parentId),
156
159
  frontmatterLine("icon", doc.icon),
157
160
  frontmatterLine("position", doc.position),
@@ -196,6 +199,10 @@ export function parseContentSourceFile(
196
199
  parentId,
197
200
  title,
198
201
  content,
202
+ description:
203
+ typeof metadata.description === "string"
204
+ ? metadata.description
205
+ : undefined,
199
206
  icon: hasOwn(metadata, "icon")
200
207
  ? typeof metadata.icon === "string"
201
208
  ? metadata.icon
@@ -115,7 +115,7 @@ function unescapeInlineText(text: string): string {
115
115
  // paragraph instead of being reparsed as that block type. These are matched
116
116
  // against the raw (untrimmed) text because the corresponding block parsers
117
117
  // (heading/list/task) also match against the untrimmed dedented line.
118
- const LEADING_BLOCK_MARKER = /^(#{1,4} |[-*+] |\d+[.)] |\[[ xX]\] )/;
118
+ const LEADING_BLOCK_MARKER = /^(#{1,6} |[-*+] |\d+[.)] |\[[ xX]\] )/;
119
119
 
120
120
  // Divider lookalikes ("---", "***", "___", 3+ repeats) — matched separately
121
121
  // because the divider parser trims the line before testing
@@ -865,7 +865,7 @@ function serializeBlock(node: PMNode, indent: number): string[] {
865
865
  ];
866
866
  }
867
867
  case "heading": {
868
- const level = Math.min(4, Math.max(1, Number(node.attrs?.level) || 1));
868
+ const level = Math.min(6, Math.max(1, Number(node.attrs?.level) || 1));
869
869
  const inline = serializeInline(node.content);
870
870
  return [
871
871
  indentStr(ind) +
@@ -1480,7 +1480,7 @@ function parseSingleBlock(
1480
1480
  // Heading (possibly a toggle heading)
1481
1481
  const headingMatch = dedent.match(/^(#{1,6})\s+(.*)$/);
1482
1482
  if (headingMatch) {
1483
- const level = Math.min(4, headingMatch[1].length);
1483
+ const level = headingMatch[1].length;
1484
1484
  const { text, toggle, color } = splitBlockAttrs(headingMatch[2]);
1485
1485
  if (toggle) {
1486
1486
  const childRes = parseBlockSequence(lines, start + 1, indent + 1);
@@ -89,6 +89,8 @@ export interface DocumentPropertyOption {
89
89
  id: string;
90
90
  name: string;
91
91
  color: DocumentPropertyOptionColor;
92
+ /** Stable guidance for when this select/status value should be chosen. */
93
+ description?: string;
92
94
  }
93
95
 
94
96
  export interface DocumentPropertyOptions {
@@ -1,21 +1,66 @@
1
- import { IconInfoCircle } from "@tabler/icons-react";
1
+ import { useT } from "@agent-native/core/client";
2
+ import { IconInfoCircle, IconMessage } from "@tabler/icons-react";
3
+
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Tooltip,
7
+ TooltipContent,
8
+ TooltipTrigger,
9
+ } from "@/components/ui/tooltip";
10
+ import { cn } from "@/lib/utils";
2
11
 
3
12
  /**
4
13
  * Slim, non-blocking banner shown below the canvas when the current user only
5
14
  * has viewer access to the design (Figma-style "you can't edit this" notice).
6
- * Purely informational — editing affordances are already disabled elsewhere
7
- * via `canEditDesign`; this just tells the viewer why.
15
+ * Editing affordances are disabled elsewhere via `canEditDesign`; signed-in
16
+ * viewers get their one canvas action integrated into the same quiet notice.
8
17
  */
9
- export function ReadOnlyDesignBanner() {
18
+ export function ReadOnlyDesignBanner({
19
+ pinMode = false,
20
+ onCommentPin,
21
+ }: {
22
+ pinMode?: boolean;
23
+ onCommentPin?: () => void;
24
+ }) {
25
+ const t = useT();
26
+ const commentLabel = pinMode
27
+ ? t("designEditor.stopPinningComments")
28
+ : t("designEditor.pinComment");
29
+
10
30
  return (
11
- <div className="pointer-events-none absolute inset-x-0 bottom-0 z-30 flex items-center justify-center px-3 pb-2">
12
- <div className="flex items-center gap-2 rounded-full border border-blue-500/30 bg-blue-500/10 px-3 py-1.5 text-xs text-blue-600 shadow-sm backdrop-blur-sm dark:text-blue-400">
31
+ <div
32
+ data-read-only-design-banner
33
+ className="pointer-events-none absolute inset-x-0 bottom-0 z-[50] flex items-center justify-center px-3 pb-2"
34
+ >
35
+ <div className="flex max-w-full items-center gap-2 rounded-full border border-blue-500/30 bg-blue-500/10 py-1 pe-1 ps-3 text-xs text-blue-600 shadow-sm backdrop-blur-sm dark:text-blue-400">
13
36
  <IconInfoCircle className="size-3.5 shrink-0" />
14
- <span className="truncate">
37
+ <span className="min-w-0 truncate">
15
38
  {
16
39
  "You don't have access to edit this design" /* i18n-ignore Figma-style read-only notice */
17
40
  }
18
41
  </span>
42
+ {onCommentPin ? (
43
+ <Tooltip>
44
+ <TooltipTrigger asChild>
45
+ <Button
46
+ type="button"
47
+ variant="ghost"
48
+ size="icon"
49
+ className={cn(
50
+ "pointer-events-auto size-7 shrink-0 rounded-full text-blue-600 hover:bg-blue-500/15 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300",
51
+ pinMode &&
52
+ "bg-blue-500/20 text-blue-700 dark:bg-blue-400/20 dark:text-blue-300",
53
+ )}
54
+ aria-label={commentLabel}
55
+ aria-pressed={pinMode}
56
+ onClick={onCommentPin}
57
+ >
58
+ <IconMessage className="size-4" />
59
+ </Button>
60
+ </TooltipTrigger>
61
+ <TooltipContent side="top">{commentLabel}</TooltipContent>
62
+ </Tooltip>
63
+ ) : null}
19
64
  </div>
20
65
  </div>
21
66
  );
@@ -15,6 +15,9 @@ import { cn } from "@/lib/utils";
15
15
  export interface ReviewCommentsPanelProps {
16
16
  designId: string;
17
17
  activeFileId?: string | null;
18
+ commentAnchor?: unknown | null;
19
+ commentMetadata?: Record<string, unknown>;
20
+ commentContextLabel?: string;
18
21
  canComment: boolean;
19
22
  /** Caller-derived editor capability for resolving threads. */
20
23
  canResolve?: boolean;
@@ -30,9 +33,27 @@ export interface ReviewCommentsPanelProps {
30
33
  className?: string;
31
34
  }
32
35
 
36
+ type ReviewCommentsScope = "screen" | "all";
37
+
38
+ export function resolveReviewComposerTargetId({
39
+ scope,
40
+ activeFileId,
41
+ commentAnchor,
42
+ }: {
43
+ scope: ReviewCommentsScope;
44
+ activeFileId?: string | null;
45
+ commentAnchor?: unknown | null;
46
+ }): string | null | undefined {
47
+ if (commentAnchor != null) return activeFileId;
48
+ return scope === "screen" ? activeFileId : undefined;
49
+ }
50
+
33
51
  export function ReviewCommentsPanel({
34
52
  designId,
35
53
  activeFileId,
54
+ commentAnchor,
55
+ commentMetadata,
56
+ commentContextLabel,
36
57
  canComment,
37
58
  canResolve,
38
59
  canDeleteComment,
@@ -46,8 +67,13 @@ export function ReviewCommentsPanel({
46
67
  className,
47
68
  }: ReviewCommentsPanelProps) {
48
69
  const t = useT();
49
- const [scope, setScope] = useState<"screen" | "all">("screen");
70
+ const [scope, setScope] = useState<ReviewCommentsScope>("screen");
50
71
  const targetId = scope === "screen" ? activeFileId : undefined;
72
+ const composerTargetId = resolveReviewComposerTargetId({
73
+ scope,
74
+ activeFileId,
75
+ commentAnchor,
76
+ });
51
77
 
52
78
  return (
53
79
  <div
@@ -87,6 +113,10 @@ export function ReviewCommentsPanel({
87
113
  resourceType="design"
88
114
  resourceId={designId}
89
115
  targetId={targetId}
116
+ composerTargetId={composerTargetId}
117
+ composerAnchor={commentAnchor}
118
+ composerMetadata={commentMetadata}
119
+ composerContextLabel={commentContextLabel}
90
120
  title={t("review.panelTitle")}
91
121
  placeholder={t("review.placeholder")}
92
122
  emptyState={t("review.emptyState")}
@@ -104,13 +134,15 @@ export function ReviewCommentsPanel({
104
134
  variant="plain"
105
135
  showComposer={canComment && showComposer}
106
136
  canReply={canComment}
107
- canResolve={canResolve ?? canDispatchToAgent}
137
+ canResolve={canResolve ?? false}
108
138
  canDeleteComment={canDeleteComment}
109
- showComposerTargetPicker={canComment && showComposer}
139
+ showComposerTargetPicker={
140
+ canComment && showComposer && canDispatchToAgent
141
+ }
110
142
  composerCommentLabel={t("review.commentMode")}
111
143
  composerAgentLabel={t("review.sendToAgent")}
112
144
  onCommentCreated={(comment) => {
113
- if (comment.resolutionTarget === "agent") {
145
+ if (canDispatchToAgent && comment.resolutionTarget === "agent") {
114
146
  onDispatchCommentToAgent?.(comment);
115
147
  }
116
148
  }}
@@ -777,6 +777,7 @@ export function ReviewCanvasPins({
777
777
  postDraft({ ...draftPin, resolutionTarget });
778
778
  }}
779
779
  resolutionTarget={draftPin.resolutionTarget}
780
+ showAgentAction={Boolean(onDispatchCommentToAgent)}
780
781
  placement={getReviewPopoverPlacement(draftPinPosition.point)}
781
782
  submitting={createComment.isPending}
782
783
  />
@@ -843,6 +844,7 @@ function DraftComposer({
843
844
  onCancel,
844
845
  onSubmit,
845
846
  resolutionTarget,
847
+ showAgentAction,
846
848
  placement,
847
849
  submitting,
848
850
  }: {
@@ -851,6 +853,7 @@ function DraftComposer({
851
853
  onCancel: () => void;
852
854
  onSubmit: (target: "agent" | "human") => void;
853
855
  resolutionTarget: "agent" | "human";
856
+ showAgentAction: boolean;
854
857
  placement: ReviewPopoverPlacement;
855
858
  submitting: boolean;
856
859
  }) {
@@ -886,7 +889,7 @@ function DraftComposer({
886
889
  onChange={onChange}
887
890
  onSubmit={onSubmit}
888
891
  submittingTarget={submitting ? resolutionTarget : null}
889
- showAgentAction
892
+ showAgentAction={showAgentAction}
890
893
  placeholder={t("review.placeholder")}
891
894
  commentLabel={t("review.commentMode")}
892
895
  agentLabel={t("review.sendToAgent")}
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "سجّل الدخول للتعليق",
13
13
  panelTitle: "الملاحظات",
14
14
  placeholder: "اترك ملاحظاتك…",
15
+ commentingOn: "التعليق على {{name}}",
15
16
  emptyState: "لا توجد تعليقات مراجعة بعد.",
16
17
  clickToPin: "انقر في أي مكان لتثبيت ملاحظة",
17
18
  escToExit: "اضغط Esc للخروج",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "Zum Kommentieren anmelden",
13
13
  panelTitle: "Feedback",
14
14
  placeholder: "Feedback hinterlassen…",
15
+ commentingOn: "Kommentar zu {{name}}",
15
16
  emptyState: "Noch keine Prüfkommentare.",
16
17
  clickToPin: "Klicke an eine beliebige Stelle, um Feedback anzuheften",
17
18
  escToExit: "Esc zum Beenden",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "Sign in to comment",
13
13
  panelTitle: "Feedback",
14
14
  placeholder: "Leave feedback…",
15
+ commentingOn: "Commenting on {{name}}",
15
16
  emptyState: "No review comments yet.",
16
17
  clickToPin: "Click anywhere to pin feedback",
17
18
  escToExit: "Esc to exit",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "Inicia sesión para comentar",
13
13
  panelTitle: "Opiniones",
14
14
  placeholder: "Deja tus comentarios…",
15
+ commentingOn: "Comentando en {{name}}",
15
16
  emptyState: "Aún no hay comentarios de revisión.",
16
17
  clickToPin: "Haz clic en cualquier lugar para fijar un comentario",
17
18
  escToExit: "Pulsa Esc para salir",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "Connectez-vous pour commenter",
13
13
  panelTitle: "Retours",
14
14
  placeholder: "Laissez un commentaire…",
15
+ commentingOn: "Commentaire sur {{name}}",
15
16
  emptyState: "Aucun commentaire de révision pour le moment.",
16
17
  clickToPin: "Cliquez n’importe où pour épingler un commentaire",
17
18
  escToExit: "Appuyez sur Esc pour quitter",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "टिप्पणी करने के लिए साइन इन करें",
13
13
  panelTitle: "प्रतिक्रिया",
14
14
  placeholder: "अपनी प्रतिक्रिया दें…",
15
+ commentingOn: "{{name}} पर टिप्पणी",
15
16
  emptyState: "अभी तक कोई समीक्षा टिप्पणी नहीं है।",
16
17
  clickToPin: "प्रतिक्रिया पिन करने के लिए कहीं भी क्लिक करें",
17
18
  escToExit: "बाहर निकलने के लिए Esc दबाएँ",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "コメントするにはサインイン",
13
13
  panelTitle: "フィードバック",
14
14
  placeholder: "フィードバックを入力…",
15
+ commentingOn: "{{name}} にコメント",
15
16
  emptyState: "レビューコメントはまだありません。",
16
17
  clickToPin: "任意の場所をクリックしてフィードバックを固定",
17
18
  escToExit: "Esc で終了",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "댓글을 작성하려면 로그인",
13
13
  panelTitle: "피드백",
14
14
  placeholder: "피드백을 남겨 주세요…",
15
+ commentingOn: "{{name}}에 댓글 작성",
15
16
  emptyState: "아직 검토 댓글이 없습니다.",
16
17
  clickToPin: "아무 곳이나 클릭하여 피드백 고정",
17
18
  escToExit: "Esc를 눌러 종료",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "Entre para comentar",
13
13
  panelTitle: "Feedback",
14
14
  placeholder: "Deixe seu feedback…",
15
+ commentingOn: "Comentando em {{name}}",
15
16
  emptyState: "Ainda não há comentários de revisão.",
16
17
  clickToPin: "Clique em qualquer lugar para fixar o feedback",
17
18
  escToExit: "Pressione Esc para sair",
@@ -12,6 +12,7 @@ const messages = {
12
12
  signInToComment: "登录后评论",
13
13
  panelTitle: "反馈",
14
14
  placeholder: "留下反馈…",
15
+ commentingOn: "正在评论 {{name}}",
15
16
  emptyState: "暂无审阅评论。",
16
17
  clickToPin: "点击任意位置固定反馈",
17
18
  escToExit: "按 Esc 退出",
@@ -53,6 +53,7 @@ const messages = {
53
53
  signInToComment: "登入後評論",
54
54
  panelTitle: "意見回饋",
55
55
  placeholder: "留下意見…",
56
+ commentingOn: "正在評論 {{name}}",
56
57
  emptyState: "目前沒有審閱評論。",
57
58
  clickToPin: "點選任意位置以固定意見",
58
59
  escToExit: "按 Esc 退出",
@@ -483,6 +483,14 @@ export function shouldClearBridgeSelectionOnEmptyMarquee(args: {
483
483
  return args.resolvedCount === 0 && !args.additive;
484
484
  }
485
485
 
486
+ /** Clear element context only when a selected review thread changes screens. */
487
+ export function shouldClearSelectionForReviewThreadTarget(args: {
488
+ activeFileId?: string | null;
489
+ targetId?: string | null;
490
+ }): boolean {
491
+ return Boolean(args.targetId && args.targetId !== args.activeFileId);
492
+ }
493
+
486
494
  /**
487
495
  * PICK-RACE: MultiScreenCanvas's `onPick` prop is `(id: string) => void` — no
488
496
  * modifier/event info — even though a shift-click there already toggled a
@@ -102,6 +102,17 @@ export function shouldAutoEnableDrawOverlay(args: {
102
102
  );
103
103
  }
104
104
 
105
+ export type DesignBottomToolbarMode = "editor" | "commenter" | "hidden";
106
+
107
+ export function getDesignBottomToolbarMode(args: {
108
+ isSignedIn: boolean;
109
+ canEditDesign: boolean;
110
+ hasActiveFile: boolean;
111
+ }): DesignBottomToolbarMode {
112
+ if (!args.isSignedIn || !args.hasActiveFile) return "hidden";
113
+ return args.canEditDesign ? "editor" : "commenter";
114
+ }
115
+
105
116
  export function getSingleScreenCreationTool(args: {
106
117
  activeTool: DesignTool;
107
118
  viewMode: "single" | "overview";
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-14
4
+ ---
5
+
6
+ Reviewers can now pin comments from the canvas toolbar, target selected layers, and only see actions they can use.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-15
4
+ ---
5
+
6
+ Viewer comment controls now sit inside the read-only notice instead of floating over the canvas.
@@ -14,6 +14,54 @@ export interface ResolvedReviewAnchor {
14
14
  source: "node" | "point";
15
15
  }
16
16
 
17
+ export function createElementReviewAnchor(input: {
18
+ nodeId?: string | null;
19
+ rect?: { x: number; y: number; width: number; height: number } | null;
20
+ viewportWidth?: number | null;
21
+ viewportHeight?: number | null;
22
+ }): DesignReviewAnchor | null {
23
+ const nodeId = input.nodeId?.trim() ?? "";
24
+ const rect = input.rect;
25
+ const hasRect = Boolean(
26
+ rect &&
27
+ Number.isFinite(rect.x) &&
28
+ Number.isFinite(rect.y) &&
29
+ Number.isFinite(rect.width) &&
30
+ rect.width > 0 &&
31
+ Number.isFinite(rect.height) &&
32
+ rect.height > 0 &&
33
+ typeof input.viewportWidth === "number" &&
34
+ Number.isFinite(input.viewportWidth) &&
35
+ input.viewportWidth > 0 &&
36
+ typeof input.viewportHeight === "number" &&
37
+ Number.isFinite(input.viewportHeight) &&
38
+ input.viewportHeight > 0,
39
+ );
40
+ if (!nodeId && !hasRect) return null;
41
+
42
+ const point = hasRect
43
+ ? {
44
+ xPct:
45
+ finitePercentage(
46
+ (((rect?.x ?? 0) + (rect?.width ?? 0) / 2) /
47
+ (input.viewportWidth as number)) *
48
+ 100,
49
+ ) ?? 50,
50
+ yPct:
51
+ finitePercentage(
52
+ (((rect?.y ?? 0) + (rect?.height ?? 0) / 2) /
53
+ (input.viewportHeight as number)) *
54
+ 100,
55
+ ) ?? 50,
56
+ }
57
+ : { xPct: 50, yPct: 50 };
58
+
59
+ return {
60
+ ...(nodeId ? { nodeId } : {}),
61
+ point,
62
+ };
63
+ }
64
+
17
65
  function finitePercentage(value: unknown): number | null {
18
66
  if (typeof value !== "number" || !Number.isFinite(value)) return null;
19
67
  return Math.min(100, Math.max(0, value));
@@ -1015,6 +1015,50 @@ function parseMdx(source: string): MdxNode {
1015
1015
  return tree;
1016
1016
  }
1017
1017
 
1018
+ type MdxParseError = {
1019
+ column?: unknown;
1020
+ line?: unknown;
1021
+ position?: { start?: { column?: unknown; line?: unknown } };
1022
+ reason?: unknown;
1023
+ };
1024
+
1025
+ function parsePlanMdxFile(
1026
+ filename: "plan.mdx" | "canvas.mdx" | "prototype.mdx",
1027
+ source: string,
1028
+ lineOffset = 0,
1029
+ ): MdxNode {
1030
+ try {
1031
+ return parseMdx(source);
1032
+ } catch (error) {
1033
+ const mdxError = error as MdxParseError;
1034
+ const line = numericMdxPosition(
1035
+ mdxError.line ?? mdxError.position?.start?.line,
1036
+ );
1037
+ const column = numericMdxPosition(
1038
+ mdxError.column ?? mdxError.position?.start?.column,
1039
+ );
1040
+ const reason =
1041
+ typeof mdxError.reason === "string"
1042
+ ? mdxError.reason
1043
+ : error instanceof Error
1044
+ ? error.message
1045
+ : String(error);
1046
+ const location = line && column ? `:${line + lineOffset}:${column}` : "";
1047
+ throw new Error(`${filename}${location}: ${reason}`);
1048
+ }
1049
+ }
1050
+
1051
+ function numericMdxPosition(value: unknown): number | undefined {
1052
+ return typeof value === "number" && Number.isFinite(value)
1053
+ ? value
1054
+ : undefined;
1055
+ }
1056
+
1057
+ function lineCountBeforeContent(source: string, content: string): number {
1058
+ const prefix = source.slice(0, Math.max(0, source.length - content.length));
1059
+ return (prefix.match(/\r?\n/g) ?? []).length;
1060
+ }
1061
+
1018
1062
  function restoreStaticTemplateLiteralAttributes(tree: MdxNode, source: string) {
1019
1063
  const walk = (node: MdxNode | undefined) => {
1020
1064
  if (!node) return;
@@ -1718,7 +1762,11 @@ export async function parsePlanMdxFolder(
1718
1762
  ): Promise<PlanContent> {
1719
1763
  const files = planMdxFileSchema.parse(folder);
1720
1764
  const parsedMatter = parseSimpleFrontmatter(files["plan.mdx"]);
1721
- const planTree = parseMdx(parsedMatter.content);
1765
+ const planTree = parsePlanMdxFile(
1766
+ "plan.mdx",
1767
+ parsedMatter.content,
1768
+ lineCountBeforeContent(files["plan.mdx"], parsedMatter.content),
1769
+ );
1722
1770
  const state = parsePlanState(files[".plan-state.json"]);
1723
1771
  const blocks = parseBlocksFromNodes(planTree.children, "plan-block", {
1724
1772
  markdownBlockIds: state?.markdownBlockIds,
@@ -1726,10 +1774,10 @@ export async function parsePlanMdxFolder(
1726
1774
  });
1727
1775
 
1728
1776
  const canvas = files["canvas.mdx"]
1729
- ? parseCanvas(files["canvas.mdx"])
1777
+ ? parseCanvas(parsePlanMdxFile("canvas.mdx", files["canvas.mdx"]))
1730
1778
  : undefined;
1731
1779
  const prototype = files["prototype.mdx"]
1732
- ? parsePrototype(files["prototype.mdx"])
1780
+ ? parsePrototype(parsePlanMdxFile("prototype.mdx", files["prototype.mdx"]))
1733
1781
  : undefined;
1734
1782
  if (canvas && state?.canvas) canvas.viewport = state.canvas;
1735
1783
 
@@ -1757,8 +1805,7 @@ export async function parsePlanMdxFolder(
1757
1805
  return normalized;
1758
1806
  }
1759
1807
 
1760
- function parsePrototype(source: string): PlanPrototype | undefined {
1761
- const tree = parseMdx(source);
1808
+ function parsePrototype(tree: MdxNode): PlanPrototype | undefined {
1762
1809
  const node = (tree.children ?? []).find(
1763
1810
  (child) => elementName(child) === "Prototype",
1764
1811
  );
@@ -1822,8 +1869,7 @@ function parsePlanState(source: string | undefined) {
1822
1869
  }
1823
1870
  }
1824
1871
 
1825
- function parseCanvas(source: string): PlanContent["canvas"] {
1826
- const tree = parseMdx(source);
1872
+ function parseCanvas(tree: MdxNode): PlanContent["canvas"] {
1827
1873
  const board = (tree.children ?? []).find(
1828
1874
  (child) => elementName(child) === "DesignBoard",
1829
1875
  );
@@ -5,7 +5,22 @@ export interface A2AToolResultSummary {
5
5
  export interface A2AArtifactResponseOptions {
6
6
  baseUrl?: string;
7
7
  includeReferencedArtifacts?: boolean;
8
+ includePersistedArtifactMarker?: boolean;
8
9
  }
10
+ export interface A2AArtifactIdentity {
11
+ resourceType: "document" | "deck" | "dashboard" | "analysis" | "image" | "design" | "monitor" | "form";
12
+ id: string;
13
+ sourceAction: string;
14
+ titleAtAction?: string;
15
+ url?: string;
16
+ }
17
+ export declare function stripA2APersistedArtifactMarkers(text: string): string;
18
+ /**
19
+ * Extract a compact, verified identity ledger from successful artifact tools.
20
+ * The ledger deliberately excludes raw tool results so it is safe to retain in
21
+ * long-lived thread context and stable even when a resource is later renamed.
22
+ */
23
+ export declare function extractA2AArtifactIdentities(results: A2AToolResultSummary[]): A2AArtifactIdentity[];
9
24
  export declare function appendA2AArtifactLinks(responseText: string, toolResults: A2AToolResultSummary[], options?: A2AArtifactResponseOptions): string;
10
25
  export declare function buildA2ARecoverableArtifactMessage(toolResults: A2AToolResultSummary[], options?: A2AArtifactResponseOptions): string | null;
11
26
  //# sourceMappingURL=artifact-response.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-response.d.ts","sourceRoot":"","sources":["../../src/a2a/artifact-response.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AA6lCD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,CAsIR;AAED,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,GAAG,IAAI,CA8Bf"}
1
+ {"version":3,"file":"artifact-response.d.ts","sourceRoot":"","sources":["../../src/a2a/artifact-response.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EACR,UAAU,GACV,MAAM,GACN,WAAW,GACX,UAAU,GACV,OAAO,GACP,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAgGD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErE;AA8tBD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,EAAE,GAC9B,mBAAmB,EAAE,CAmGvB;AA2YD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,CA8IR;AAED,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,GAAG,IAAI,CA8Bf"}