@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
@@ -1641,8 +1641,6 @@ const enUS = {
1641
1641
  description:
1642
1642
  "A snapshot of the colors, type, spacing, and assets currently stored.",
1643
1643
  colors: "Colors",
1644
- namedTokens: "Design system tokens",
1645
- colorRoles: "Color roles",
1646
1644
  noColors: "No color tokens saved.",
1647
1645
  typography: "Typography",
1648
1646
  details: "Details",
@@ -2109,8 +2107,6 @@ const designLocaleOverrides = {
2109
2107
  title: "代币预览",
2110
2108
  description: "当前存储的颜色、类型、间距和资源的快照。",
2111
2109
  colors: "颜色",
2112
- namedTokens: "设计系统令牌",
2113
- colorRoles: "颜色角色",
2114
2110
  noColors: "没有保存颜色标记。",
2115
2111
  typography: "版式",
2116
2112
  details: "细节",
@@ -2537,8 +2533,6 @@ const designLocaleOverrides = {
2537
2533
  description:
2538
2534
  "Una instantánea de los colores, tipos, espacios y recursos almacenados actualmente.",
2539
2535
  colors: "Bandera",
2540
- namedTokens: "Tokens del sistema de diseño",
2541
- colorRoles: "Roles de color",
2542
2536
  noColors: "No se guardaron fichas de color.",
2543
2537
  typography: "Tipografía",
2544
2538
  details: "Detalles",
@@ -2970,8 +2964,6 @@ const designLocaleOverrides = {
2970
2964
  description:
2971
2965
  "Un instantané des couleurs, du type, de l'espacement et des ressources actuellement stockés.",
2972
2966
  colors: "Couleurs",
2973
- namedTokens: "Jetons du système de design",
2974
- colorRoles: "Rôles de couleur",
2975
2967
  noColors: "Aucun jeton de couleur enregistré.",
2976
2968
  typography: "Typographie",
2977
2969
  details: "Détails",
@@ -3404,8 +3396,6 @@ const designLocaleOverrides = {
3404
3396
  description:
3405
3397
  "Eine Momentaufnahme der Farben, des Typs, der Abstände und der aktuell gespeicherten Elemente.",
3406
3398
  colors: "Farben",
3407
- namedTokens: "Design-System-Tokens",
3408
- colorRoles: "Farbrollen",
3409
3399
  noColors: "Keine Farbtokens gespeichert.",
3410
3400
  typography: "Typografie",
3411
3401
  details: "Details",
@@ -3833,8 +3823,6 @@ const designLocaleOverrides = {
3833
3823
  description:
3834
3824
  "現在保存されている色、タイプ、間隔、アセットのスナップショット。",
3835
3825
  colors: "色",
3836
- namedTokens: "デザインシステムのトークン",
3837
- colorRoles: "カラーロール",
3838
3826
  noColors: "カラートークンは保存されません。",
3839
3827
  typography: "タイポグラフィ",
3840
3828
  details: "詳細",
@@ -4255,8 +4243,6 @@ const designLocaleOverrides = {
4255
4243
  title: "토큰 미리보기",
4256
4244
  description: "현재 저장된 색상, 유형, 간격 및 자산의 스냅샷입니다.",
4257
4245
  colors: "그림 물감",
4258
- namedTokens: "디자인 시스템 토큰",
4259
- colorRoles: "색상 역할",
4260
4246
  noColors: "저장된 색상 토큰이 없습니다.",
4261
4247
  typography: "타이포그래피",
4262
4248
  details: "세부",
@@ -4684,8 +4670,6 @@ const designLocaleOverrides = {
4684
4670
  description:
4685
4671
  "Um instantâneo das cores, tipo, espaçamento e ativos armazenados atualmente.",
4686
4672
  colors: "Cores",
4687
- namedTokens: "Tokens do sistema de design",
4688
- colorRoles: "Funções de cor",
4689
4673
  noColors: "Nenhum token de cor salvo.",
4690
4674
  typography: "Tipografia",
4691
4675
  details: "Detalhes",
@@ -5104,8 +5088,6 @@ const designLocaleOverrides = {
5104
5088
  description:
5105
5089
  "वर्तमान में संग्रहीत रंग, प्रकार, रिक्ति और संपत्तियों का एक स्नैपशॉट।",
5106
5090
  colors: "रंग",
5107
- namedTokens: "डिज़ाइन सिस्टम टोकन",
5108
- colorRoles: "रंग भूमिकाएँ",
5109
5091
  noColors: "कोई रंग टोकन सहेजा नहीं गया.",
5110
5092
  typography: "टाइपोग्राफी",
5111
5093
  details: "विवरण",
@@ -5523,8 +5505,6 @@ const designLocaleOverrides = {
5523
5505
  title: "معاينة الرمز المميز",
5524
5506
  description: "لقطة للألوان والنوع والتباعد والأصول المخزنة حاليًا.",
5525
5507
  colors: "الألوان",
5526
- namedTokens: "رموز نظام التصميم",
5527
- colorRoles: "أدوار الألوان",
5528
5508
  noColors: "لم يتم حفظ أي رموز ملونة.",
5529
5509
  typography: "الطباعة",
5530
5510
  details: "تفاصيل",
@@ -433,7 +433,7 @@ export default function DesignSystemSetup() {
433
433
 
434
434
  const parts: string[] = [];
435
435
  parts.push(
436
- "Set up a design system from the following sources. Use Builder Design System Intelligence (DSI) as the source of truth for reusable Figma/code/design.md indexing. Analyze each source, extract design tokens (colors, fonts, spacing, borders), and create a cohesive design system. Keep each token under the name its source gives it: put the full named vocabulary in `data.tokens` (name, cssVar, value, type, group, source) as well as filling the seven `colors` roles, so tokens like `interactive-01` are not collapsed into `secondary`.",
436
+ "Set up a design system from the following sources. Use Builder Design System Intelligence (DSI) as the source of truth for reusable Figma/code/design.md indexing. Analyze each source, extract design tokens (colors, fonts, spacing, borders), and create a cohesive design system.",
437
437
  );
438
438
 
439
439
  if (companyInfo.trim()) {
@@ -1,9 +1,3 @@
1
- import {
2
- groupBrandKitTokens,
3
- isColorTokenValue,
4
- resolveBrandKitTokens,
5
- type BrandKitTokenGroup,
6
- } from "@agent-native/core/brand-kit/tokens";
7
1
  import {
8
2
  useActionQuery,
9
3
  useActionMutation,
@@ -115,8 +109,6 @@ interface DesignSystemData {
115
109
  borders?: Record<string, unknown>;
116
110
  logos?: Array<{ url?: string; name?: string; variant?: string }>;
117
111
  defaults?: Record<string, unknown>;
118
- tokens?: unknown;
119
- customCSS?: unknown;
120
112
  notes?: unknown;
121
113
  }
122
114
 
@@ -947,7 +939,6 @@ function TokenPreview({
947
939
  const colors = getColorTokens(data, t);
948
940
  const typeTokens = getTypographyTokens(data, t);
949
941
  const detailTokens = getDetailTokens(data, assets, t);
950
- const namedGroups = groupBrandKitTokens(resolveBrandKitTokens(data));
951
942
 
952
943
  return (
953
944
  <section className="space-y-6 border-t border-border pt-6">
@@ -960,15 +951,9 @@ function TokenPreview({
960
951
  </p>
961
952
  </div>
962
953
 
963
- {namedGroups.length > 0 ? (
964
- <NamedTokenGroups groups={namedGroups} />
965
- ) : null}
966
-
967
954
  <div className="space-y-3">
968
955
  <h4 className="text-xs font-medium uppercase text-muted-foreground">
969
- {namedGroups.length > 0
970
- ? t("designSystems.tokenPreview.colorRoles")
971
- : t("designSystems.tokenPreview.colors")}
956
+ {t("designSystems.tokenPreview.colors")}
972
957
  </h4>
973
958
  {colors.length > 0 ? (
974
959
  <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
@@ -1017,68 +1002,6 @@ function TokenPreview({
1017
1002
  );
1018
1003
  }
1019
1004
 
1020
- function NamedTokenGroups({ groups }: { groups: BrandKitTokenGroup[] }) {
1021
- const t = useT();
1022
- const total = groups.reduce((sum, group) => sum + group.tokens.length, 0);
1023
-
1024
- return (
1025
- <div className="space-y-4">
1026
- <div className="flex items-baseline justify-between gap-3">
1027
- <h4 className="text-xs font-medium uppercase text-muted-foreground">
1028
- {t("designSystems.tokenPreview.namedTokens")}
1029
- </h4>
1030
- <span className="!text-[11px] text-muted-foreground">
1031
- {t("designSystems.tokenPreview.savedCount", { count: total })}
1032
- </span>
1033
- </div>
1034
-
1035
- {groups.map((group) => (
1036
- <div key={`${group.type}:${group.label}`} className="space-y-2">
1037
- <div className="flex items-center gap-2">
1038
- <span className="text-xs font-medium text-foreground">
1039
- {group.label}
1040
- </span>
1041
- <span className="!text-[11px] text-muted-foreground">
1042
- {group.tokens.length}
1043
- </span>
1044
- </div>
1045
- <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
1046
- {group.tokens.map((token) => (
1047
- <div
1048
- key={token.cssVar}
1049
- className="flex min-w-0 items-center gap-3 rounded-lg border border-border bg-muted/30 p-2"
1050
- >
1051
- {isColorTokenValue(token.value) ? (
1052
- <div
1053
- className="h-9 w-9 shrink-0 rounded-md border border-border"
1054
- style={{ backgroundColor: token.value }}
1055
- />
1056
- ) : null}
1057
- <div className="min-w-0 flex-1">
1058
- <div className="truncate text-xs font-medium text-foreground">
1059
- {token.name}
1060
- </div>
1061
- <div className="truncate font-mono !text-[11px] text-muted-foreground">
1062
- {token.cssVar}
1063
- </div>
1064
- <div className="truncate font-mono !text-[11px] text-muted-foreground">
1065
- {token.value}
1066
- </div>
1067
- </div>
1068
- {token.source ? (
1069
- <span className="shrink-0 rounded border border-border px-1.5 py-0.5 !text-[10px] text-muted-foreground">
1070
- {token.source}
1071
- </span>
1072
- ) : null}
1073
- </div>
1074
- ))}
1075
- </div>
1076
- </div>
1077
- ))}
1078
- </div>
1079
- );
1080
- }
1081
-
1082
1005
  function PreviewList({
1083
1006
  title,
1084
1007
  items,
@@ -1,4 +1,3 @@
1
- import { collectAuthoredColorStyles } from "@shared/authored-color-styles";
2
1
  import { normalizePoisonedBoardNestedCoords } from "@shared/board-file";
3
2
  import type { CodeLayerNode } from "@shared/code-layer";
4
3
 
@@ -212,12 +211,8 @@ export function getBodyInlineStyles(content: string): Record<string, string> {
212
211
  const doc = new DOMParser().parseFromString(content, "text/html");
213
212
  const body = doc.body;
214
213
  if (!body) return {};
215
- // A generated screen sets its page background in a `body { … }` rule, and a
216
- // `background:` shorthand holding var() leaves the longhand empty, so the
217
- // inline style alone reports an unstyled page.
218
- const authored = collectAuthoredColorStyles(body);
219
214
  return {
220
- backgroundColor: body.style.backgroundColor || authored.backgroundColor,
215
+ backgroundColor: body.style.backgroundColor,
221
216
  backgroundImage: body.style.backgroundImage,
222
217
  backgroundPosition: body.style.backgroundPosition,
223
218
  backgroundRepeat: body.style.backgroundRepeat,
@@ -66,23 +66,6 @@ async function postAction(
66
66
  return res.json();
67
67
  }
68
68
 
69
- /** Create a Brand Kit from a production template and return its title. */
70
- export async function createDesignSystemFromTemplate(
71
- page: Page,
72
- templateId: string,
73
- ): Promise<string> {
74
- const created = await postAction(page, "create-design-system", {
75
- templateId,
76
- });
77
- const title: string | undefined = created?.title ?? created?.data?.title;
78
- if (!title) {
79
- throw new Error(
80
- `create-design-system did not return a title: ${JSON.stringify(created)}`,
81
- );
82
- }
83
- return title;
84
- }
85
-
86
69
  export async function createFixtureDesign(
87
70
  page: Page,
88
71
  title = SEED_TITLE,
@@ -11,21 +11,13 @@
11
11
  * - the snapshot / coding-handoff actions inject so an external agent
12
12
  * continues from the *tuned* design, not the original generated tokens.
13
13
  *
14
- * Keep it pure so the UI and the server actions produce byte-identical
15
- * output. The CSS-safety predicates are re-exported from core so a Brand Kit
16
- * token and a tweak value can never be validated by two drifting copies.
14
+ * Keep it pure and dependency-free so the UI and the server actions produce
15
+ * byte-identical output.
17
16
  */
18
17
 
19
- import {
20
- isSafeCssTokenValue,
21
- isSafeCssVarName,
22
- } from "@agent-native/core/brand-kit/tokens";
23
-
24
18
  import type { TweakDefinition } from "./api.js";
25
19
  import { sourceContentHash } from "./source-workspace.js";
26
20
 
27
- export { isSafeCssTokenValue, isSafeCssVarName };
28
-
29
21
  export type TweakSelections = Record<string, string | number | boolean>;
30
22
 
31
23
  /**
@@ -57,6 +49,22 @@ export function tweakSelectionsHash(
57
49
  * emitted directly, which lets token edits persist vars that were not part of
58
50
  * the generated tweak definition list.
59
51
  */
52
+ const CSS_CUSTOM_PROPERTY_NAME = /^--[-_a-zA-Z0-9]+$/;
53
+
54
+ export function isSafeCssVarName(value: string): boolean {
55
+ return CSS_CUSTOM_PROPERTY_NAME.test(value);
56
+ }
57
+
58
+ export function isSafeCssTokenValue(value: string): boolean {
59
+ return (
60
+ value.length > 0 &&
61
+ value.length <= 300 &&
62
+ !/[;{}<>]/.test(value) &&
63
+ !/\/\*/.test(value) &&
64
+ !/[\u0000-\u001f\u007f]/.test(value)
65
+ );
66
+ }
67
+
60
68
  export function resolveTweaksToCssVars(
61
69
  tweaks: TweakDefinition[],
62
70
  selections: TweakSelections,
@@ -1,7 +1,6 @@
1
1
  import { emailStrong, renderEmail, sendEmail } from "@agent-native/core/server";
2
2
 
3
3
  import type { FormField } from "../../shared/types.js";
4
- import { FORMS_NEW_RESPONSE_EMAIL_ID } from "./emails.js";
5
4
 
6
5
  export interface NewResponseEmailArgs {
7
6
  to: string;
@@ -62,6 +61,5 @@ export async function sendNewResponseEmail(
62
61
  await sendEmail({
63
62
  to: args.to,
64
63
  ...renderNewResponseEmail(args),
65
- templateId: FORMS_NEW_RESPONSE_EMAIL_ID,
66
64
  });
67
65
  }
@@ -22,8 +22,6 @@ import {
22
22
  } from "../server/lib/local-identity.js";
23
23
  import { newId, nowIso, planPath, writeEvent } from "../server/plans.js";
24
24
 
25
- export const PLAN_ACCESS_REQUEST_EMAIL_ID = "plan.access-request";
26
-
27
25
  function httpError(message: string, statusCode: number): Error {
28
26
  return Object.assign(new Error(message), { statusCode });
29
27
  }
@@ -51,28 +49,6 @@ function absolutePlanUrl(planId: string, kind: "plan" | "recap"): string {
51
49
  }
52
50
  }
53
51
 
54
- export function renderPlanAccessRequestEmail(input: {
55
- requesterName: string;
56
- requesterEmail: string;
57
- planTitle: string;
58
- url: string;
59
- }) {
60
- const subject = `${input.requesterName} requested access to "${input.planTitle}"`;
61
- return {
62
- subject,
63
- ...renderEmail({
64
- preheader: subject,
65
- heading: "Access request",
66
- paragraphs: [
67
- `${emailStrong(input.requesterName)} (${emailStrong(input.requesterEmail)}) requested access to ${emailStrong(input.planTitle)}.`,
68
- "Open the plan and use Share to grant access if this request should be approved.",
69
- ],
70
- cta: { label: "Open plan", url: input.url },
71
- footer: "You received this because you own this Agent-Native Plan.",
72
- }),
73
- };
74
- }
75
-
76
52
  async function notifyOwner(input: {
77
53
  planId: string;
78
54
  planKind: "plan" | "recap";
@@ -86,16 +62,19 @@ async function notifyOwner(input: {
86
62
  return false;
87
63
  }
88
64
 
89
- await sendEmail({
90
- ...renderPlanAccessRequestEmail({
91
- requesterName: input.requesterName,
92
- requesterEmail: input.requesterEmail,
93
- planTitle: input.planTitle,
94
- url: absolutePlanUrl(input.planId, input.planKind),
95
- }),
96
- to: input.ownerEmail,
97
- templateId: PLAN_ACCESS_REQUEST_EMAIL_ID,
65
+ const url = absolutePlanUrl(input.planId, input.planKind);
66
+ const subject = `${input.requesterName} requested access to "${input.planTitle}"`;
67
+ const { html, text } = renderEmail({
68
+ preheader: subject,
69
+ heading: "Access request",
70
+ paragraphs: [
71
+ `${emailStrong(input.requesterName)} (${emailStrong(input.requesterEmail)}) requested access to ${emailStrong(input.planTitle)}.`,
72
+ "Open the plan and use Share to grant access if this request should be approved.",
73
+ ],
74
+ cta: { label: "Open plan", url },
75
+ footer: "You received this because you own this Agent-Native Plan.",
98
76
  });
77
+ await sendEmail({ to: input.ownerEmail, subject, html, text });
99
78
  return true;
100
79
  }
101
80
 
@@ -14,8 +14,6 @@ import {
14
14
  import type { PlanBundle, PlanComment } from "../../shared/types.js";
15
15
  import { getDb, schema } from "../db/index.js";
16
16
 
17
- export const PLAN_COMMENT_EMAIL_ID = "plan.plan-comment";
18
-
19
17
  type CommentNotificationInput = {
20
18
  bundle: PlanBundle;
21
19
  insertedCommentIds: string[];
@@ -207,64 +205,40 @@ export function planCommentNotificationRecipients(input: {
207
205
  return Array.from(recipients.values());
208
206
  }
209
207
 
210
- export function renderPlanCommentEmail(input: {
211
- actor: string;
212
- app: string;
213
- planTitle: string;
214
- planUrl: string;
215
- message: string;
216
- isReply: boolean;
217
- reason: NotificationRecipient["reason"];
218
- }) {
219
- const actionText =
220
- input.reason === "mention"
221
- ? "mentioned you in a comment on"
222
- : input.reason === "plan-owner"
223
- ? "left a comment on your plan"
224
- : "replied in a comment thread you participated in";
225
- return {
226
- subject: input.isReply
227
- ? `${input.actor} replied to a comment on "${input.planTitle}"`
228
- : `${input.actor} commented on "${input.planTitle}"`,
229
- ...renderEmail({
230
- preheader: `${input.actor} ${actionText} on ${input.app}.`,
231
- heading: input.isReply
232
- ? "New reply on your plan"
233
- : "New comment on your plan",
234
- paragraphs: [
235
- `${emailStrong(input.actor)} ${actionText} ${emailStrong(input.planTitle)}.`,
236
- `Comment: "${commentExcerpt(input.message)}"`,
237
- ],
238
- cta: { label: "Open plan", url: input.planUrl },
239
- footer:
240
- input.reason === "plan-owner"
241
- ? "You received this because you own this plan."
242
- : input.reason === "mention"
243
- ? "You received this because you were mentioned in this comment."
244
- : "You received this because you participated in this comment thread.",
245
- }),
246
- };
247
- }
248
-
249
208
  async function sendPlanCommentNotification(input: {
250
209
  recipient: NotificationRecipient;
251
210
  comment: PlanComment;
252
211
  planTitle: string;
253
212
  planId: string;
254
213
  }) {
255
- await sendEmail({
256
- ...renderPlanCommentEmail({
257
- actor: actorName(input.comment),
258
- app: appName(),
259
- planTitle: input.planTitle,
260
- planUrl: planUrl(input.planId),
261
- message: input.comment.message,
262
- isReply: Boolean(input.comment.parentCommentId),
263
- reason: input.recipient.reason,
264
- }),
265
- to: input.recipient.email,
266
- templateId: PLAN_COMMENT_EMAIL_ID,
214
+ const actor = actorName(input.comment);
215
+ const app = appName();
216
+ const isReply = Boolean(input.comment.parentCommentId);
217
+ const subject = isReply
218
+ ? `${actor} replied to a comment on "${input.planTitle}"`
219
+ : `${actor} commented on "${input.planTitle}"`;
220
+ const actionText =
221
+ input.recipient.reason === "mention"
222
+ ? "mentioned you in a comment on"
223
+ : input.recipient.reason === "plan-owner"
224
+ ? "left a comment on your plan"
225
+ : "replied in a comment thread you participated in";
226
+ const { html, text } = renderEmail({
227
+ preheader: `${actor} ${actionText} on ${app}.`,
228
+ heading: isReply ? "New reply on your plan" : "New comment on your plan",
229
+ paragraphs: [
230
+ `${emailStrong(actor)} ${actionText} ${emailStrong(input.planTitle)}.`,
231
+ `Comment: "${commentExcerpt(input.comment.message)}"`,
232
+ ],
233
+ cta: { label: "Open plan", url: planUrl(input.planId) },
234
+ footer:
235
+ input.recipient.reason === "plan-owner"
236
+ ? "You received this because you own this plan."
237
+ : input.recipient.reason === "mention"
238
+ ? "You received this because you were mentioned in this comment."
239
+ : "You received this because you participated in this comment thread.",
267
240
  });
241
+ await sendEmail({ to: input.recipient.email, subject, html, text });
268
242
  }
269
243
 
270
244
  export async function notifyPlanCommentRecipients({
@@ -21,7 +21,6 @@ import { and, eq } from "drizzle-orm";
21
21
  import { getDeckUrl } from "../../actions/_app-url.js";
22
22
  import { SLIDES_USER_PREFS_KEY } from "../../shared/slides-user-prefs.js";
23
23
  import { getDb, schema } from "../db/index.js";
24
- import { SLIDES_DECK_COMMENT_EMAIL_ID } from "./emails.js";
25
24
 
26
25
  /**
27
26
  * `deck-missing` stays distinct from `no-recipients`: one means the deck could
@@ -100,41 +99,6 @@ async function threadParticipants(
100
99
  return rows.map((row) => row.authorEmail);
101
100
  }
102
101
 
103
- export function renderDeckCommentEmail({
104
- actor,
105
- title,
106
- url,
107
- content,
108
- isReply,
109
- }: {
110
- actor: string;
111
- title: string;
112
- url: string;
113
- content: string;
114
- isReply: boolean;
115
- }) {
116
- return {
117
- subject: isReply
118
- ? `${actor} replied to a comment on "${title}"`
119
- : `${actor} commented on "${title}"`,
120
- ...renderEmail({
121
- preheader: isReply
122
- ? `${actor} replied to a comment on ${title}.`
123
- : `${actor} commented on ${title}.`,
124
- heading: isReply ? "New reply on your deck" : "New comment",
125
- paragraphs: [
126
- isReply
127
- ? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(title)}.`
128
- : `${emailStrong(actor)} commented on ${emailStrong(title)}.`,
129
- `"${excerpt(content)}"`,
130
- ],
131
- cta: { label: "Open deck", url },
132
- footer:
133
- "You received this because you own or participated in this thread. Turn these off in Slides settings.",
134
- }),
135
- };
136
- }
137
-
138
102
  export async function notifyDeckComment(input: {
139
103
  deckId: string;
140
104
  slideId: string;
@@ -189,16 +153,29 @@ async function deliverDeckCommentEmails(input: {
189
153
  preferenceKey: SLIDES_USER_PREFS_KEY,
190
154
  logLabel: LOG_LABEL,
191
155
  send: async (to) => {
156
+ const { html, text } = renderEmail({
157
+ preheader: input.isReply
158
+ ? `${actor} replied to a comment on ${deck.title}.`
159
+ : `${actor} commented on ${deck.title}.`,
160
+ heading: input.isReply ? "New reply on your deck" : "New comment",
161
+ paragraphs: [
162
+ input.isReply
163
+ ? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(deck.title)}.`
164
+ : `${emailStrong(actor)} commented on ${emailStrong(deck.title)}.`,
165
+ `"${excerpt(input.content)}"`,
166
+ ],
167
+ cta: { label: "Open deck", url },
168
+ footer:
169
+ "You received this because you own or participated in this thread. Turn these off in Slides settings.",
170
+ });
171
+
192
172
  await sendEmail({
193
- ...renderDeckCommentEmail({
194
- actor,
195
- title: deck.title,
196
- url,
197
- content: input.content,
198
- isReply: input.isReply,
199
- }),
200
173
  to,
201
- templateId: SLIDES_DECK_COMMENT_EMAIL_ID,
174
+ subject: input.isReply
175
+ ? `${actor} replied to a comment on "${deck.title}"`
176
+ : `${actor} commented on "${deck.title}"`,
177
+ html,
178
+ text,
202
179
  });
203
180
  },
204
181
  });
@@ -583,17 +583,16 @@ async function handleSend(params, config, event) {
583
583
  if (!asyncMode)
584
584
  idempotencyKey = undefined;
585
585
  if (asyncMode) {
586
- // Refuse async mode entirely when no auth is configured in production.
587
- // The async dispatch path self-fires the `_process-task` route, which
588
- // accepts unsigned dispatches when A2A_SECRET is unset — that combined
589
- // with the lack of caller identity here would let any unauthenticated
590
- // attacker queue and trigger handler runs. In production, require some
591
- // form of auth so the verifiedEmail is bound to the task.
592
- const hasA2ASecret = hasConfiguredA2ASecret();
593
- const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);
594
- if (isA2AProductionRuntime() && !hasA2ASecret && !hasApiKey) {
586
+ // Refuse async mode entirely without the shared secret in production.
587
+ // The async dispatch path self-fires the `_process-task` route, which is
588
+ // authenticated with an internal HMAC signed by A2A_SECRET. A legacy
589
+ // apiKeyEnv can authenticate the JSON-RPC request, but it cannot
590
+ // authenticate that internal handoff. Accepting it here would create a
591
+ // working task that can never start and leaves the caller polling until
592
+ // its timeout.
593
+ if (isA2AProductionRuntime() && !hasConfiguredA2ASecret()) {
595
594
  return {
596
- ...jsonRpcError(0, -32001, "A2A async mode is not available — A2A_SECRET or apiKeyEnv must be configured."),
595
+ ...jsonRpcError(0, -32001, "A2A async mode requires A2A_SECRET for internal processor dispatch; apiKeyEnv only supports synchronous A2A."),
597
596
  _id: 0,
598
597
  };
599
598
  }
@@ -16,7 +16,6 @@
16
16
  */
17
17
  export * from "./types.js";
18
18
  export * from "./brand-signals.js";
19
- export * from "./tokens.js";
20
19
  export { extractDesignTokensFromUrl, validateUrl, parseOwnerRepo, fetchGitHubJson, fetchGitHubJsonResult, fetchGitHubRaw, parseTailwindConfig, parseCss, detectStylingFramework, createCodeAnalysisState, analyzeCodeFile, analyzeCssFile, analyzeTailwindConfig, analyzeJsonTheme, analyzePackageJson, analyzeThemeSourceFile, addFont, extractCssVars, extractCodeColors, extractCodeFonts, extractDocumentColors, extractDocumentFonts, classifyFile, suggestionsForType, unique, MAX_FILES, MAX_FILE_SIZE, FETCH_TIMEOUT, ROOT_PATTERNS, SECONDARY_PATHS, CODE_MAX_FILES, CODE_MAX_TOTAL_BYTES, } from "../server/design-token-utils.js";
21
20
  export type { ContentType, ParsedCss, ParsedTailwindConfig, CodeAnalysisState, UrlExtractionResult, GitHubFetchOptions, GitHubJsonResult, } from "../server/design-token-utils.js";
22
21
  //# sourceMappingURL=index.d.ts.map
@@ -16,7 +16,6 @@
16
16
  */
17
17
  export * from "./types.js";
18
18
  export * from "./brand-signals.js";
19
- export * from "./tokens.js";
20
19
  // Import-source parsing + token extraction (Tailwind/CSS/GitHub/URL/document/
21
20
  // code analysis). These already power the import-* actions across templates.
22
21
  export {
@@ -23,25 +23,6 @@ export interface BrandKitColors {
23
23
  text: string;
24
24
  textMuted: string;
25
25
  }
26
- /** Semantic category a {@link BrandKitToken} belongs to. */
27
- export type BrandKitTokenType = "color" | "typography" | "spacing" | "radius" | "shadow" | "other";
28
- /**
29
- * One token under the name its source design system uses. The seven
30
- * {@link BrandKitColors} roles are a summary view, not a substitute: collapsing
31
- * `interactive-01` into `secondary` discards the only name the design team has.
32
- */
33
- export interface BrandKitToken {
34
- name: string;
35
- /** e.g. `--cds-interactive-01`. */
36
- cssVar: string;
37
- /** Resolved value, e.g. a hex color or `0.5rem`. */
38
- value: string;
39
- type: BrandKitTokenType;
40
- /** Collection path as the source organises it, e.g. `Colors/Interactive`. */
41
- group?: string;
42
- /** e.g. `Carbon v11` or `globals.css`. */
43
- source?: string;
44
- }
45
26
  /** Brand typography system. */
46
27
  export interface BrandKitTypography {
47
28
  headingFont: string;
@@ -95,12 +76,6 @@ export interface BrandKitData {
95
76
  spacing: BrandKitSpacing;
96
77
  borders: BrandKitBorders;
97
78
  logos: BrandKitLogo[];
98
- /**
99
- * The source system's full named vocabulary. Optional because kits predating
100
- * it store only the role summary — absent means "never extracted", not "the
101
- * system has none".
102
- */
103
- tokens?: BrandKitToken[];
104
79
  imageStyle?: BrandKitImageStyle;
105
80
  customCSS?: string;
106
81
  notes?: string;