@agent-native/core 0.140.0 → 0.141.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 (128) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  3. package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +6 -0
  4. package/corpus/templates/analytics/server/lib/dashboard-report.ts +0 -2
  5. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +11 -6
  6. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +8 -18
  7. package/corpus/templates/analytics/server/plugins/db.ts +174 -0
  8. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +38 -38
  9. package/corpus/templates/calendar/changelog/2026-08-05-out-of-office-blocks-now-open-from-their-scheduled-time-rang.md +6 -0
  10. package/corpus/templates/calendar/server/lib/booking-emails.ts +70 -154
  11. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +28 -64
  12. package/corpus/templates/clips/actions/get-recording-player-data.ts +1 -0
  13. package/corpus/templates/clips/actions/invite-member.ts +16 -39
  14. package/corpus/templates/clips/app/components/player/comments-panel.tsx +2 -3
  15. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +10 -0
  16. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +2 -2
  17. package/corpus/templates/clips/app/components/player/video-player.tsx +20 -6
  18. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +33 -0
  19. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +5 -1
  20. package/corpus/templates/clips/app/routes/share.$shareId.tsx +27 -1
  21. package/corpus/templates/clips/changelog/2026-08-05-comment-and-video-reaction-pickers-now-include-eyes-and-mind.md +6 -0
  22. package/corpus/templates/clips/changelog/2026-08-05-fresh-recordings-now-open-with-the-complete-video.md +6 -0
  23. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +0 -24
  24. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
  25. package/corpus/templates/content/server/lib/comment-notifications.ts +26 -57
  26. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +1 -44
  27. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -265
  28. package/corpus/templates/design/actions/create-design-system.ts +10 -9
  29. package/corpus/templates/design/actions/get-design-system.ts +0 -53
  30. package/corpus/templates/design/actions/import-design-tokens.ts +71 -5
  31. package/corpus/templates/design/actions/index-design-tokens.ts +80 -61
  32. package/corpus/templates/design/actions/update-design-system.ts +10 -7
  33. package/corpus/templates/design/app/components/design/EditPanel.tsx +2 -45
  34. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +0 -12
  35. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +6 -10
  36. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +3 -19
  37. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +10 -36
  38. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +0 -15
  39. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +1 -19
  40. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +0 -6
  41. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +23 -53
  42. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +4 -142
  43. package/corpus/templates/design/app/components/design/types.ts +0 -6
  44. package/corpus/templates/design/app/i18n-data.ts +0 -20
  45. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
  46. package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -78
  47. package/corpus/templates/design/app/pages/design-editor/html-layer-positioning.ts +1 -6
  48. package/corpus/templates/design/e2e/helpers.ts +0 -17
  49. package/corpus/templates/design/shared/resolve-tweaks.ts +18 -10
  50. package/corpus/templates/forms/server/lib/response-email.ts +0 -2
  51. package/corpus/templates/plan/actions/request-plan-access.ts +12 -33
  52. package/corpus/templates/plan/server/lib/comment-notifications.ts +27 -53
  53. package/corpus/templates/slides/server/lib/comment-notifications.ts +21 -44
  54. package/dist/a2a/handlers.js +9 -10
  55. package/dist/brand-kit/index.d.ts +0 -1
  56. package/dist/brand-kit/index.js +0 -1
  57. package/dist/brand-kit/types.d.ts +0 -25
  58. package/dist/collab/awareness.d.ts +2 -2
  59. package/dist/collab/struct-routes.d.ts +1 -1
  60. package/dist/db/client.js +8 -8
  61. package/dist/db/migrations.js +39 -19
  62. package/dist/localization/default-messages.d.ts +0 -45
  63. package/dist/localization/default-messages.js +0 -45
  64. package/dist/notifications/routes.d.ts +6 -6
  65. package/dist/observability/routes.d.ts +3 -3
  66. package/dist/org/handlers.js +1 -8
  67. package/dist/progress/routes.d.ts +1 -1
  68. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  69. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  70. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  71. package/dist/resources/handlers.d.ts +1 -1
  72. package/dist/secrets/routes.d.ts +9 -9
  73. package/dist/server/action-discovery.js +0 -22
  74. package/dist/server/auth.js +3 -1
  75. package/dist/server/better-auth-instance.js +2 -17
  76. package/dist/server/email.d.ts +0 -9
  77. package/dist/server/email.js +3 -44
  78. package/dist/server/index.d.ts +0 -1
  79. package/dist/server/index.js +0 -1
  80. package/dist/server/transcribe-voice.d.ts +1 -1
  81. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +3 -2
  82. package/docs/content/authentication.mdx +25 -19
  83. package/package.json +1 -1
  84. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +3 -2
  85. package/corpus/templates/analytics/server/lib/emails.ts +0 -51
  86. package/corpus/templates/analytics/server/plugins/transactional-emails.ts +0 -5
  87. package/corpus/templates/calendar/server/lib/emails.ts +0 -167
  88. package/corpus/templates/calendar/server/plugins/transactional-emails.ts +0 -5
  89. package/corpus/templates/clips/server/lib/emails.ts +0 -256
  90. package/corpus/templates/clips/server/plugins/transactional-email-catalog.ts +0 -5
  91. package/corpus/templates/content/server/lib/emails.ts +0 -70
  92. package/corpus/templates/content/server/plugins/transactional-emails.ts +0 -5
  93. package/corpus/templates/design/app/components/design/edit-panel/design-system-swatches.ts +0 -215
  94. package/corpus/templates/design/changelog/2026-08-04-design-system-tokens-show-by-name-in-the-editor.md +0 -6
  95. package/corpus/templates/design/server/lib/design-system-tokens.ts +0 -35
  96. package/corpus/templates/design/shared/authored-color-styles.ts +0 -401
  97. package/corpus/templates/dispatch/app/routes/transactional-email.$appId.$id.tsx +0 -4
  98. package/corpus/templates/dispatch/app/routes/transactional-email.tsx +0 -4
  99. package/corpus/templates/forms/server/lib/emails.ts +0 -52
  100. package/corpus/templates/forms/server/plugins/transactional-emails.ts +0 -5
  101. package/corpus/templates/plan/server/lib/emails.ts +0 -67
  102. package/corpus/templates/plan/server/plugins/transactional-emails.ts +0 -5
  103. package/corpus/templates/slides/server/lib/emails.ts +0 -40
  104. package/corpus/templates/slides/server/plugins/transactional-emails.ts +0 -5
  105. package/dist/brand-kit/tokens.d.ts +0 -92
  106. package/dist/brand-kit/tokens.js +0 -280
  107. package/dist/email-catalog/actions/list-email-activity.d.ts +0 -6
  108. package/dist/email-catalog/actions/list-email-activity.js +0 -15
  109. package/dist/email-catalog/actions/list-email-engagement.d.ts +0 -6
  110. package/dist/email-catalog/actions/list-email-engagement.js +0 -15
  111. package/dist/email-catalog/actions/list-email-log.d.ts +0 -8
  112. package/dist/email-catalog/actions/list-email-log.js +0 -22
  113. package/dist/email-catalog/actions/list-transactional-emails.d.ts +0 -23
  114. package/dist/email-catalog/actions/list-transactional-emails.js +0 -61
  115. package/dist/email-catalog/actions/render-transactional-email-preview.d.ts +0 -10
  116. package/dist/email-catalog/actions/render-transactional-email-preview.js +0 -24
  117. package/dist/email-catalog/authorize.d.ts +0 -2
  118. package/dist/email-catalog/authorize.js +0 -10
  119. package/dist/email-catalog/log.d.ts +0 -57
  120. package/dist/email-catalog/log.js +0 -117
  121. package/dist/email-catalog/provider-metrics.d.ts +0 -34
  122. package/dist/email-catalog/provider-metrics.js +0 -165
  123. package/dist/email-catalog/registry.d.ts +0 -79
  124. package/dist/email-catalog/registry.js +0 -71
  125. package/dist/email-catalog/schema.d.ts +0 -212
  126. package/dist/email-catalog/schema.js +0 -49
  127. package/dist/email-catalog/system-emails.d.ts +0 -14
  128. package/dist/email-catalog/system-emails.js +0 -68
@@ -1,256 +0,0 @@
1
- /**
2
- * Catalog entries for the transactional emails Clips sends.
3
- *
4
- * Registered from `server/plugins/transactional-emails.ts` so Dispatch can list
5
- * and preview them without the app having sent anything yet.
6
- *
7
- * Every entry except the organization invite renders through
8
- * `renderClipsTransactionalEmail`, so a preview shows the real template rather
9
- * than a copy of it.
10
- */
11
-
12
- import { defineTransactionalEmail } from "@agent-native/core/email-catalog";
13
-
14
- import { renderClipsInviteEmail } from "../../actions/invite-member.js";
15
- import {
16
- CLIPS_ACTIVITY_COMMENT_EMAIL_ID,
17
- CLIPS_ACTIVITY_REACTION_EMAIL_ID,
18
- CLIPS_FIRST_AGENT_VIEW_EMAIL_ID,
19
- CLIPS_FIRST_IMPORT_EMAIL_ID,
20
- CLIPS_FIRST_VIEW_EMAIL_ID,
21
- CLIPS_MONTHLY_RECAP_EMAIL_ID,
22
- CLIPS_TWO_CLIPS_EMAIL_ID,
23
- CLIPS_UNVIEWED_REMINDER_EMAIL_ID,
24
- renderClipsTransactionalEmail,
25
- type ClipsTransactionalEmailInput,
26
- type ClipsTransactionalEmailRenderOptions,
27
- } from "./transactional-email-templates.js";
28
-
29
- /** Obviously-fake sample data — these render in a preview pane, never send. */
30
- const PREVIEW_OPTIONS: ClipsTransactionalEmailRenderOptions = {
31
- appUrl: "https://example.com",
32
- };
33
- const SAMPLE_RECORDING_ID = "rec_sample";
34
- const SAMPLE_TITLE = "Onboarding walkthrough";
35
- const SAMPLE_TO = "sam.rivera@example.com";
36
-
37
- function preview(input: ClipsTransactionalEmailInput) {
38
- return renderClipsTransactionalEmail(input, PREVIEW_OPTIONS);
39
- }
40
-
41
- export const CLIPS_ORGANIZATION_INVITE_EMAIL_ID = "clips.organization-invite";
42
-
43
- /**
44
- * How the shared Clips sender resolves From and Reply-To for every kind it
45
- * renders, so each entry can say so without restating the mechanism.
46
- */
47
- const CLIPS_SENDER =
48
- 'From is the configured EMAIL_FROM with the display name "Agent-Native Clips"; on first-party agent-native.com deployments it becomes clips@agent-native.com. Reply-to is hello@agent-native.com.';
49
-
50
- let registered = false;
51
-
52
- export function registerClipsEmails(): void {
53
- if (registered) return;
54
- registered = true;
55
-
56
- defineTransactionalEmail({
57
- id: CLIPS_FIRST_VIEW_EMAIL_ID,
58
- name: "First view on a Clip",
59
- trigger:
60
- "The background transactional-email sweep finds the first counted view of a Clip by someone other than its owner, recorded after transactional email was switched on. One per Clip.",
61
- recipientLabel: "Clip owner",
62
- recipient:
63
- "The Clip's owner. Suppressed recipient addresses are skipped, and the send is dropped if the owner is no longer the recording's owner at send time.",
64
- senderLabel: "Agent-Native Clips",
65
- sender: CLIPS_SENDER,
66
- preview: () =>
67
- preview({
68
- kind: "first-view",
69
- to: SAMPLE_TO,
70
- recordingId: SAMPLE_RECORDING_ID,
71
- title: SAMPLE_TITLE,
72
- viewerEmail: "alex.chen@example.com",
73
- }),
74
- });
75
-
76
- defineTransactionalEmail({
77
- id: CLIPS_UNVIEWED_REMINDER_EMAIL_ID,
78
- name: "Unviewed Clip reminder",
79
- trigger:
80
- "A direct share is 48 hours old and the recipient still has no counted view of that Clip. Re-checked at send time, so a view in the meantime cancels it.",
81
- recipientLabel: "Shared-with address",
82
- recipient:
83
- "The address the Clip was directly shared with. Requires the share to still exist.",
84
- senderLabel: "Sharer via Clips",
85
- sender:
86
- 'Same as the other Clips emails, except the display name becomes "<sharer> (via Agent-Native Clips)" and reply-to is the sharer\'s own address when it is a valid address, falling back to hello@agent-native.com.',
87
- preview: () =>
88
- preview({
89
- kind: "unviewed-reminder",
90
- to: SAMPLE_TO,
91
- recordingId: SAMPLE_RECORDING_ID,
92
- title: SAMPLE_TITLE,
93
- senderEmail: "dana.hill@example.com",
94
- senderName: "Dana Hill",
95
- }),
96
- });
97
-
98
- defineTransactionalEmail({
99
- id: CLIPS_FIRST_AGENT_VIEW_EMAIL_ID,
100
- name: "First agent read of a Clip",
101
- trigger:
102
- "An AI agent reads one of an owner's Clips for the first time since transactional email was switched on. One per owner, not per Clip.",
103
- recipientLabel: "Clip owner",
104
- recipient:
105
- "The owner of the Clip the agent read. Re-checked at send time against the owner's actual first agent view.",
106
- senderLabel: "Agent-Native Clips",
107
- sender: CLIPS_SENDER,
108
- preview: () =>
109
- preview({
110
- kind: "first-agent-view",
111
- to: SAMPLE_TO,
112
- recordingId: SAMPLE_RECORDING_ID,
113
- title: SAMPLE_TITLE,
114
- agentName: "Claude Code",
115
- }),
116
- });
117
-
118
- defineTransactionalEmail({
119
- id: CLIPS_FIRST_IMPORT_EMAIL_ID,
120
- name: "First imported video is ready",
121
- trigger:
122
- "An owner's first imported (rather than recorded) video finishes processing and becomes ready. One per owner.",
123
- recipientLabel: "Clip owner",
124
- recipient:
125
- "The owner of the imported recording, re-checked at send time so a later import does not resend.",
126
- senderLabel: "Agent-Native Clips",
127
- sender: CLIPS_SENDER,
128
- preview: () =>
129
- preview({
130
- kind: "first-import",
131
- to: SAMPLE_TO,
132
- recordingId: SAMPLE_RECORDING_ID,
133
- title: "Quarterly demo recording",
134
- }),
135
- });
136
-
137
- defineTransactionalEmail({
138
- id: CLIPS_MONTHLY_RECAP_EMAIL_ID,
139
- name: "Monthly Clips recap",
140
- trigger:
141
- "Once per owner per calendar month, from 14:00 UTC on the 1st, for owners whose Clips had any human views or agent reads in the closed month. Metrics and the top Clip are recomputed at send time.",
142
- recipientLabel: "Clip owner",
143
- recipient:
144
- "The Clip owner whose audience the recap reports. Suppressed addresses are skipped.",
145
- senderLabel: "Agent-Native Clips",
146
- sender: CLIPS_SENDER,
147
- preview: () =>
148
- preview({
149
- kind: "monthly-recap",
150
- to: SAMPLE_TO,
151
- month: "2025-02",
152
- humanViews: 42,
153
- agentSessions: 7,
154
- topClip: {
155
- recordingId: SAMPLE_RECORDING_ID,
156
- title: SAMPLE_TITLE,
157
- thumbnailUrl: "https://example.com/thumbnails/sample.png",
158
- durationMs: 214_000,
159
- recordedAt: "2025-02-11T16:00:00.000Z",
160
- humanViews: 18,
161
- agentSessions: 4,
162
- },
163
- copy: {
164
- heroLine: "Your clips were watched 42 times. 7 agents read them.",
165
- completionNote: "68% average completion · most stopped at 2:31",
166
- agentBreakdown: "4 from Claude Code · 3 unidentified",
167
- },
168
- }),
169
- });
170
-
171
- defineTransactionalEmail({
172
- id: CLIPS_TWO_CLIPS_EMAIL_ID,
173
- name: "Two Clips received",
174
- trigger:
175
- "A one-time nudge once someone who owns no Clips of their own has had two distinct Clips directly shared with them. The summary line is AI-generated before the job is released to send.",
176
- recipientLabel: "Shared-with address",
177
- recipient:
178
- "The shared-with address. Dropped at send time if they now own a Clip or no longer hold both shares.",
179
- senderLabel: "Agent-Native Clips",
180
- sender: CLIPS_SENDER,
181
- preview: () =>
182
- preview({
183
- kind: "two-clips",
184
- to: SAMPLE_TO,
185
- generatedSummary:
186
- "Two teammates walked you through the new onboarding flow.",
187
- }),
188
- });
189
-
190
- defineTransactionalEmail({
191
- id: CLIPS_ACTIVITY_COMMENT_EMAIL_ID,
192
- name: "Clip comment",
193
- trigger:
194
- "Someone comments or replies on a Clip. Subject and copy differ slightly for a reply; both send under this id.",
195
- recipientLabel: "Owner and thread authors",
196
- recipient:
197
- "The recording owner, plus every prior author in the thread when the comment is a reply. The list is re-checked against the recording's live ACL and filtered by each user's `emailNotifications` preference; the comment's own author never receives it.",
198
- senderLabel: "Agent-Native Clips",
199
- sender: CLIPS_SENDER,
200
- preview: () =>
201
- preview({
202
- kind: "activity-comment",
203
- to: SAMPLE_TO,
204
- recordingId: SAMPLE_RECORDING_ID,
205
- title: SAMPLE_TITLE,
206
- authorEmail: "alex.chen@example.com",
207
- authorName: "Alex Chen",
208
- content: "The step at 1:20 is the part new hires always miss.",
209
- videoTimestampMs: 80_000,
210
- isReply: false,
211
- }),
212
- });
213
-
214
- defineTransactionalEmail({
215
- id: CLIPS_ACTIVITY_REACTION_EMAIL_ID,
216
- name: "Clip reaction",
217
- trigger: "A viewer reacts with an emoji on a Clip.",
218
- recipientLabel: "Clip owner",
219
- recipient:
220
- "The recording owner plus any extra recipients the caller passes, re-checked against the recording's live ACL and filtered by each user's `emailNotifications` preference. The reacting viewer never receives it.",
221
- senderLabel: "Agent-Native Clips",
222
- sender: CLIPS_SENDER,
223
- preview: () =>
224
- preview({
225
- kind: "activity-reaction",
226
- to: SAMPLE_TO,
227
- recordingId: SAMPLE_RECORDING_ID,
228
- title: SAMPLE_TITLE,
229
- emoji: "🎉",
230
- authorEmail: "alex.chen@example.com",
231
- authorName: "Alex Chen",
232
- videoTimestampMs: 45_000,
233
- }),
234
- });
235
-
236
- defineTransactionalEmail({
237
- id: CLIPS_ORGANIZATION_INVITE_EMAIL_ID,
238
- name: "Organization invitation",
239
- trigger:
240
- "An organization admin runs `invite-member`. Any earlier pending invite for the same address is cancelled first, so a re-invite sends a fresh email with a new token.",
241
- recipientLabel: "Invited address",
242
- recipient:
243
- "The address passed to the action, exactly as typed. One email per invite.",
244
- senderLabel: "Default sender",
245
- sender:
246
- "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`, so unlike the other Clips emails it does not send as Agent-Native Clips.",
247
- preview: () =>
248
- renderClipsInviteEmail({
249
- appName: "Clips",
250
- orgName: "Northwind Design",
251
- inviter: "dana.hill@example.com",
252
- role: "member",
253
- inviteUrl: "https://example.com/invite/sample-token",
254
- }),
255
- });
256
- }
@@ -1,5 +0,0 @@
1
- import { registerClipsEmails } from "../lib/emails.js";
2
-
3
- export default function registerTransactionalEmailCatalog(): void {
4
- registerClipsEmails();
5
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Catalog entries for the transactional emails Documents sends.
3
- *
4
- * Registered from `server/plugins/transactional-emails.ts` so Dispatch can list
5
- * and preview them without the app having sent anything yet.
6
- */
7
-
8
- import { defineTransactionalEmail } from "@agent-native/core/email-catalog";
9
-
10
- import { renderDocumentCommentEmail } from "./comment-notifications.js";
11
-
12
- /** Obviously-fake sample data — these render in a preview pane, never send. */
13
- const SAMPLE_TITLE = "Q3 launch brief";
14
- const SAMPLE_URL = "https://example.com/page/doc_sample";
15
- const SAMPLE_COMMENT =
16
- "Can we tighten the second paragraph? It repeats the intro.";
17
-
18
- export const CONTENT_DOCUMENT_COMMENT_EMAIL_ID = "content.document-comment";
19
- export const CONTENT_DOCUMENT_MENTION_EMAIL_ID = "content.document-mention";
20
-
21
- let registered = false;
22
-
23
- export function registerContentEmails(): void {
24
- if (registered) return;
25
- registered = true;
26
-
27
- defineTransactionalEmail({
28
- id: CONTENT_DOCUMENT_COMMENT_EMAIL_ID,
29
- name: "Document comment",
30
- trigger:
31
- "Someone posts a comment or a thread reply on a document. Sent to recipients who were not mentioned in it; the copy and subject differ slightly for a reply.",
32
- recipientLabel: "Owner and thread authors",
33
- recipient:
34
- "The document owner, plus every prior author in the thread when the new comment is a reply. The list is re-checked against the document's live ACL and filtered by each user's `emailNotifications` preference; the comment's own author never receives it.",
35
- senderLabel: "Default sender",
36
- sender:
37
- "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`.",
38
- preview: () =>
39
- renderDocumentCommentEmail({
40
- actor: "Sam Rivera",
41
- title: SAMPLE_TITLE,
42
- url: SAMPLE_URL,
43
- content: SAMPLE_COMMENT,
44
- isReply: false,
45
- wasMentioned: false,
46
- }),
47
- });
48
-
49
- defineTransactionalEmail({
50
- id: CONTENT_DOCUMENT_MENTION_EMAIL_ID,
51
- name: "Document mention",
52
- trigger:
53
- "A comment or reply mentions someone by email. Sent instead of the plain comment notification to each mentioned recipient.",
54
- recipientLabel: "Mentioned users",
55
- recipient:
56
- "The mentioned addresses supplied by the caller, re-checked against the document's live ACL and filtered by each user's `emailNotifications` preference.",
57
- senderLabel: "Default sender",
58
- sender:
59
- "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`.",
60
- preview: () =>
61
- renderDocumentCommentEmail({
62
- actor: "Sam Rivera",
63
- title: SAMPLE_TITLE,
64
- url: SAMPLE_URL,
65
- content: SAMPLE_COMMENT,
66
- isReply: false,
67
- wasMentioned: true,
68
- }),
69
- });
70
- }
@@ -1,5 +0,0 @@
1
- import { registerContentEmails } from "../lib/emails.js";
2
-
3
- export default function registerTransactionalEmails(): void {
4
- registerContentEmails();
5
- }
@@ -1,215 +0,0 @@
1
- import { parseCssColorExtended, rgbaToHex } from "@shared/color-utils";
2
-
3
- /** One colour token from the design's linked Brand Kit, as the kit names it. */
4
- export interface DesignSystemColorSwatch {
5
- name: string;
6
- cssVar: string;
7
- value: string;
8
- group?: string;
9
- source?: string;
10
- }
11
-
12
- interface IndexedToken {
13
- name: string;
14
- cssVar: string;
15
- value: string;
16
- type: string;
17
- group?: string;
18
- source?: string;
19
- origin?: string;
20
- }
21
-
22
- /** Extended: the classifier stores `oklch()`/`color()` tokens as colours. */
23
- function normalizeHex(value: string): string | null {
24
- const parsed = parseCssColorExtended(value.trim());
25
- return parsed ? rgbaToHex(parsed).toUpperCase() : null;
26
- }
27
-
28
- /** Guards a cyclic alias chain (`--a: var(--b); --b: var(--a)`). */
29
- const MAX_ALIAS_DEPTH = 8;
30
-
31
- /**
32
- * A token's value as a paintable literal, following aliases through the kit's
33
- * own vocabulary. A kit legitimately defines one token as another, and dropping
34
- * those loses a selectable token; painting them raw gives an empty swatch.
35
- */
36
- function paintableTokenValue(
37
- value: string,
38
- byCssVar: ReadonlyMap<string, string>,
39
- depth = 0,
40
- ): string | null {
41
- if (normalizeHex(value)) return value;
42
- if (depth >= MAX_ALIAS_DEPTH) return null;
43
- const reference = parseTokenReference(value);
44
- if (!reference) return null;
45
-
46
- const aliased = byCssVar.get(reference.cssVar);
47
- if (aliased !== undefined) {
48
- const resolved = paintableTokenValue(aliased, byCssVar, depth + 1);
49
- if (resolved) return resolved;
50
- }
51
- return reference.fallback
52
- ? paintableTokenValue(reference.fallback, byCssVar, depth + 1)
53
- : null;
54
- }
55
-
56
- /**
57
- * The linked kit's swatchable colour tokens from an `index-design-tokens`
58
- * result, which mixes the design's own `:root` colours into the same list.
59
- * Values that resolve to no colour at all are dropped, since they would paint
60
- * an empty swatch.
61
- */
62
- export function toDesignSystemColorSwatches(
63
- tokens: readonly IndexedToken[] | undefined,
64
- limit = 48,
65
- ): DesignSystemColorSwatch[] {
66
- if (!tokens) return [];
67
- // Every token, not just kit ones: a kit alias may point at a design `:root`
68
- // variable, and that still resolves to a real colour.
69
- const byCssVar = new Map(tokens.map((token) => [token.cssVar, token.value]));
70
- const seen = new Set<string>();
71
- const out: DesignSystemColorSwatch[] = [];
72
-
73
- for (const token of tokens) {
74
- if (token.type !== "color") continue;
75
- if (token.origin !== "brand-kit") continue;
76
- const value = paintableTokenValue(token.value, byCssVar);
77
- if (!value) continue;
78
- if (seen.has(token.cssVar)) continue;
79
- seen.add(token.cssVar);
80
- out.push({
81
- name: token.name,
82
- cssVar: token.cssVar,
83
- value,
84
- ...(token.group ? { group: token.group } : {}),
85
- ...(token.source ? { source: token.source } : {}),
86
- });
87
- if (out.length >= limit) break;
88
- }
89
-
90
- return out;
91
- }
92
-
93
- /**
94
- * What to call a token in the picker: its CSS variable, minus the leading `--`.
95
- *
96
- * The indexed `name` is title-cased for tokens the kit never named ("Color
97
- * Primary"), which reads as a different vocabulary than the kit's own
98
- * `cds-background-brand` sitting next to it. The variable is what the design
99
- * references, so it is the name worth showing.
100
- */
101
- export function swatchLabel(swatch: DesignSystemColorSwatch): string {
102
- return swatch.cssVar.replace(/^--/, "");
103
- }
104
-
105
- const TOKEN_REFERENCE_HEAD = /^var\(\s*(--[-_a-zA-Z0-9]+)\s*(,?)/;
106
-
107
- export interface TokenReference {
108
- cssVar: string;
109
- /** Literal after the comma. Absent for a bare `var(--x)`. */
110
- fallback: string | null;
111
- }
112
-
113
- /**
114
- * A fallback is itself a CSS value, so it can nest parentheses. Scanning to the
115
- * balanced close rather than matching `[^()]+` is what keeps a function-valued
116
- * token from reading as "not a token" and being dropped by the commit guard.
117
- */
118
- export function parseTokenReference(value: string): TokenReference | null {
119
- const trimmed = value.trim();
120
- const head = TOKEN_REFERENCE_HEAD.exec(trimmed);
121
- if (!head) return null;
122
-
123
- let depth = 1;
124
- let index = head[0].length;
125
- for (; index < trimmed.length && depth > 0; index += 1) {
126
- const char = trimmed[index];
127
- if (char === "(") depth += 1;
128
- else if (char === ")") depth -= 1;
129
- }
130
- // Anything after the matching `)` means this is not a lone reference.
131
- if (depth !== 0 || index !== trimmed.length) return null;
132
-
133
- const fallback = trimmed.slice(head[0].length, index - 1).trim();
134
- if (fallback && !head[2]) return null;
135
- return { cssVar: head[1], fallback: fallback || null };
136
- }
137
-
138
- /**
139
- * The declaration to persist for a picked token.
140
- *
141
- * The fallback is not optional padding: outside the editor — an export, a
142
- * published page, a design whose kit link was removed — nothing defines the
143
- * custom property, and a bare `var(--x)` renders transparent.
144
- */
145
- export function tokenReferenceValue(swatch: DesignSystemColorSwatch): string {
146
- return `var(${swatch.cssVar}, ${swatch.value})`;
147
- }
148
-
149
- const HIDDEN_TOKEN_MIX =
150
- /^color-mix\(\s*in\s+srgb\s*,\s*(var\(.+\))\s+0%\s*,\s*transparent\s*\)$/i;
151
-
152
- /**
153
- * What to write when hiding a colour. Zeroing alpha needs literal channels,
154
- * which a `var()` reference has none of — so a token is hidden as a 0% mix that
155
- * keeps the reference inside the persisted CSS. React state would not survive
156
- * the deselect/reselect that unmounts the inspector.
157
- */
158
- export function hiddenColorWrite(
159
- color: string,
160
- zeroAlpha: (literal: string) => string | null,
161
- ): string {
162
- const reference = parseTokenReference(color);
163
- if (reference) return `color-mix(in srgb, ${color} 0%, transparent)`;
164
- return zeroAlpha(color) ?? "transparent";
165
- }
166
-
167
- /** The reference a hidden token colour carries, or null if it is not one. */
168
- export function hiddenTokenReference(value: string): string | null {
169
- return HIDDEN_TOKEN_MIX.exec(value.trim())?.[1] ?? null;
170
- }
171
-
172
- /**
173
- * Name the token a value came from, or null when that cannot be known. A
174
- * `var()` reference names itself; a bare colour is matched by value, and a tie
175
- * returns null — Carbon points four tokens at one blue.
176
- */
177
- export function resolveTokenNameForColor(
178
- value: string,
179
- swatches: readonly DesignSystemColorSwatch[],
180
- ): string | null {
181
- const reference = parseTokenReference(value);
182
- if (reference) return reference.cssVar.replace(/^--/, "");
183
-
184
- const target = normalizeHex(value);
185
- if (!target) return null;
186
-
187
- let match: string | null = null;
188
- for (const swatch of swatches) {
189
- if (normalizeHex(swatch.value) !== target) continue;
190
- if (match) return null;
191
- match = swatchLabel(swatch);
192
- }
193
- return match;
194
- }
195
-
196
- /** Group swatches under their kit collection path, preserving token order. */
197
- export function groupColorSwatches(
198
- swatches: readonly DesignSystemColorSwatch[],
199
- ): { label: string | null; swatches: DesignSystemColorSwatch[] }[] {
200
- const groups = new Map<
201
- string,
202
- { label: string | null; swatches: DesignSystemColorSwatch[] }
203
- >();
204
- for (const swatch of swatches) {
205
- const label = swatch.group?.trim() || null;
206
- const key = label ?? "";
207
- const existing = groups.get(key);
208
- if (existing) {
209
- existing.swatches.push(swatch);
210
- continue;
211
- }
212
- groups.set(key, { label, swatches: [swatch] });
213
- }
214
- return [...groups.values()];
215
- }
@@ -1,6 +0,0 @@
1
- ---
2
- type: added
3
- date: 2026-08-04
4
- ---
5
-
6
- Design system tokens now show by name across the Brand Kit page and the fill, stroke, effects, page background and selection colour rows, so a colour reads as `cds-link-primary` instead of `0F62FE`.
@@ -1,35 +0,0 @@
1
- import {
2
- describeBrandKitTokenRejections,
3
- normalizeBrandKitTokens,
4
- } from "@agent-native/core/brand-kit/tokens";
5
-
6
- /**
7
- * Reject a write whose named tokens cannot be stored verbatim. Keeping the
8
- * storable subset would read downstream as a genuinely smaller design system.
9
- */
10
- export function assertStorableDesignSystemTokens(dataJson: string): void {
11
- let parsed: unknown;
12
- try {
13
- parsed = JSON.parse(dataJson);
14
- } catch {
15
- throw new Error("data must be a valid JSON object string");
16
- }
17
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
18
- throw new Error("data must be a valid JSON object string");
19
- }
20
-
21
- const tokens = (parsed as Record<string, unknown>).tokens;
22
- if (tokens === undefined) return;
23
-
24
- const { rejected } = normalizeBrandKitTokens(tokens);
25
- if (rejected.length > 0) {
26
- throw new Error(
27
- `data.tokens contains ${rejected.length} entr${
28
- rejected.length === 1 ? "y" : "ies"
29
- } that cannot be stored: ${describeBrandKitTokenRejections(rejected)}. ` +
30
- "Each token needs a name, a CSS custom property (-- followed by " +
31
- "letters, digits, hyphens or underscores), and a value with no " +
32
- '";", "{", "}", "<", ">", or CSS comment.',
33
- );
34
- }
35
- }