@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +0 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +11 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +8 -18
- package/corpus/templates/analytics/server/plugins/db.ts +174 -0
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +38 -38
- package/corpus/templates/calendar/changelog/2026-08-05-out-of-office-blocks-now-open-from-their-scheduled-time-rang.md +6 -0
- package/corpus/templates/calendar/server/lib/booking-emails.ts +70 -154
- package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +28 -64
- package/corpus/templates/clips/actions/get-recording-player-data.ts +1 -0
- package/corpus/templates/clips/actions/invite-member.ts +16 -39
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +2 -3
- package/corpus/templates/clips/app/components/player/reaction-emojis.ts +10 -0
- package/corpus/templates/clips/app/components/player/reactions-tray.tsx +2 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +20 -6
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +33 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +5 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +27 -1
- package/corpus/templates/clips/changelog/2026-08-05-comment-and-video-reaction-pickers-now-include-eyes-and-mind.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-05-fresh-recordings-now-open-with-the-complete-video.md +6 -0
- package/corpus/templates/clips/server/lib/transactional-email-templates.ts +0 -24
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
- package/corpus/templates/content/server/lib/comment-notifications.ts +26 -57
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +1 -44
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -265
- package/corpus/templates/design/actions/create-design-system.ts +10 -9
- package/corpus/templates/design/actions/get-design-system.ts +0 -53
- package/corpus/templates/design/actions/import-design-tokens.ts +71 -5
- package/corpus/templates/design/actions/index-design-tokens.ts +80 -61
- package/corpus/templates/design/actions/update-design-system.ts +10 -7
- package/corpus/templates/design/app/components/design/EditPanel.tsx +2 -45
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +0 -12
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +6 -10
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +3 -19
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +10 -36
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +0 -15
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +1 -19
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +0 -6
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +23 -53
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +4 -142
- package/corpus/templates/design/app/components/design/types.ts +0 -6
- package/corpus/templates/design/app/i18n-data.ts +0 -20
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -78
- package/corpus/templates/design/app/pages/design-editor/html-layer-positioning.ts +1 -6
- package/corpus/templates/design/e2e/helpers.ts +0 -17
- package/corpus/templates/design/shared/resolve-tweaks.ts +18 -10
- package/corpus/templates/forms/server/lib/response-email.ts +0 -2
- package/corpus/templates/plan/actions/request-plan-access.ts +12 -33
- package/corpus/templates/plan/server/lib/comment-notifications.ts +27 -53
- package/corpus/templates/slides/server/lib/comment-notifications.ts +21 -44
- package/dist/a2a/handlers.js +9 -10
- package/dist/brand-kit/index.d.ts +0 -1
- package/dist/brand-kit/index.js +0 -1
- package/dist/brand-kit/types.d.ts +0 -25
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.js +8 -8
- package/dist/db/migrations.js +39 -19
- package/dist/localization/default-messages.d.ts +0 -45
- package/dist/localization/default-messages.js +0 -45
- package/dist/notifications/routes.d.ts +6 -6
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/handlers.js +1 -8
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-discovery.js +0 -22
- package/dist/server/auth.js +3 -1
- package/dist/server/better-auth-instance.js +2 -17
- package/dist/server/email.d.ts +0 -9
- package/dist/server/email.js +3 -44
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.js +0 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +3 -2
- package/docs/content/authentication.mdx +25 -19
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +3 -2
- package/corpus/templates/analytics/server/lib/emails.ts +0 -51
- package/corpus/templates/analytics/server/plugins/transactional-emails.ts +0 -5
- package/corpus/templates/calendar/server/lib/emails.ts +0 -167
- package/corpus/templates/calendar/server/plugins/transactional-emails.ts +0 -5
- package/corpus/templates/clips/server/lib/emails.ts +0 -256
- package/corpus/templates/clips/server/plugins/transactional-email-catalog.ts +0 -5
- package/corpus/templates/content/server/lib/emails.ts +0 -70
- package/corpus/templates/content/server/plugins/transactional-emails.ts +0 -5
- package/corpus/templates/design/app/components/design/edit-panel/design-system-swatches.ts +0 -215
- package/corpus/templates/design/changelog/2026-08-04-design-system-tokens-show-by-name-in-the-editor.md +0 -6
- package/corpus/templates/design/server/lib/design-system-tokens.ts +0 -35
- package/corpus/templates/design/shared/authored-color-styles.ts +0 -401
- package/corpus/templates/dispatch/app/routes/transactional-email.$appId.$id.tsx +0 -4
- package/corpus/templates/dispatch/app/routes/transactional-email.tsx +0 -4
- package/corpus/templates/forms/server/lib/emails.ts +0 -52
- package/corpus/templates/forms/server/plugins/transactional-emails.ts +0 -5
- package/corpus/templates/plan/server/lib/emails.ts +0 -67
- package/corpus/templates/plan/server/plugins/transactional-emails.ts +0 -5
- package/corpus/templates/slides/server/lib/emails.ts +0 -40
- package/corpus/templates/slides/server/plugins/transactional-emails.ts +0 -5
- package/dist/brand-kit/tokens.d.ts +0 -92
- package/dist/brand-kit/tokens.js +0 -280
- package/dist/email-catalog/actions/list-email-activity.d.ts +0 -6
- package/dist/email-catalog/actions/list-email-activity.js +0 -15
- package/dist/email-catalog/actions/list-email-engagement.d.ts +0 -6
- package/dist/email-catalog/actions/list-email-engagement.js +0 -15
- package/dist/email-catalog/actions/list-email-log.d.ts +0 -8
- package/dist/email-catalog/actions/list-email-log.js +0 -22
- package/dist/email-catalog/actions/list-transactional-emails.d.ts +0 -23
- package/dist/email-catalog/actions/list-transactional-emails.js +0 -61
- package/dist/email-catalog/actions/render-transactional-email-preview.d.ts +0 -10
- package/dist/email-catalog/actions/render-transactional-email-preview.js +0 -24
- package/dist/email-catalog/authorize.d.ts +0 -2
- package/dist/email-catalog/authorize.js +0 -10
- package/dist/email-catalog/log.d.ts +0 -57
- package/dist/email-catalog/log.js +0 -117
- package/dist/email-catalog/provider-metrics.d.ts +0 -34
- package/dist/email-catalog/provider-metrics.js +0 -165
- package/dist/email-catalog/registry.d.ts +0 -79
- package/dist/email-catalog/registry.js +0 -71
- package/dist/email-catalog/schema.d.ts +0 -212
- package/dist/email-catalog/schema.js +0 -49
- package/dist/email-catalog/system-emails.d.ts +0 -14
- package/dist/email-catalog/system-emails.js +0 -68
|
@@ -293,6 +293,8 @@ const CLIPS_AGENT_DOCS_URL =
|
|
|
293
293
|
"https://www.agent-native.com/docs/template-clips#agent-readable-clips";
|
|
294
294
|
const UPLOAD_STUCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
295
295
|
const PROCESSING_STUCK_TIMEOUT_MS = 12 * 60 * 1000;
|
|
296
|
+
const READY_MEDIA_SETTLE_POLL_MS = 20 * 1000;
|
|
297
|
+
const READY_MEDIA_SETTLE_POLL_INTERVAL_MS = 1000;
|
|
296
298
|
|
|
297
299
|
type ViewerPlatform = "mac" | "windows" | "linux";
|
|
298
300
|
|
|
@@ -404,6 +406,7 @@ export default function ShareRoute() {
|
|
|
404
406
|
}, [recordingId, attribution.ref, attribution.via]);
|
|
405
407
|
|
|
406
408
|
const playerRef = useRef<VideoPlayerHandle | null>(null);
|
|
409
|
+
const readyMediaPollRef = useRef<{ key: string; until: number } | null>(null);
|
|
407
410
|
const [password, setPassword] = useState<string | null>(() => {
|
|
408
411
|
if (typeof window === "undefined" || !shareId) return null;
|
|
409
412
|
try {
|
|
@@ -463,7 +466,26 @@ export default function ShareRoute() {
|
|
|
463
466
|
// page auto-upgrades from "Processing" to the real player the moment
|
|
464
467
|
// the server flips status to 'ready' and writes videoUrl. Mirrors
|
|
465
468
|
// r.$recordingId.tsx's playerDataQ.refetchInterval.
|
|
466
|
-
if (rec.status !== "ready" || !rec.videoUrl)
|
|
469
|
+
if (rec.status !== "ready" || !rec.videoUrl) {
|
|
470
|
+
readyMediaPollRef.current = null;
|
|
471
|
+
return 2000;
|
|
472
|
+
}
|
|
473
|
+
const mediaKey = [
|
|
474
|
+
rec.id,
|
|
475
|
+
rec.durationMs ?? "",
|
|
476
|
+
rec.videoSizeBytes ?? "",
|
|
477
|
+
rec.videoFormat ?? "",
|
|
478
|
+
].join(":");
|
|
479
|
+
const now = Date.now();
|
|
480
|
+
if (readyMediaPollRef.current?.key !== mediaKey) {
|
|
481
|
+
readyMediaPollRef.current = {
|
|
482
|
+
key: mediaKey,
|
|
483
|
+
until: now + READY_MEDIA_SETTLE_POLL_MS,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
if (now < readyMediaPollRef.current.until) {
|
|
487
|
+
return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
|
|
488
|
+
}
|
|
467
489
|
// Also keep polling while a transcript is pending so "Transcribing…"
|
|
468
490
|
// auto-flips to the ready transcript (or to the failure card). The
|
|
469
491
|
// public payload has no transcript.cleanup field (that's authenticated
|
|
@@ -985,6 +1007,10 @@ export default function ShareRoute() {
|
|
|
985
1007
|
onVideoElementChange={setTrackedVideoEl}
|
|
986
1008
|
recordingId={recording.id}
|
|
987
1009
|
videoUrl={recording.videoUrl}
|
|
1010
|
+
mediaVersion={[
|
|
1011
|
+
recording.videoSizeBytes ?? "",
|
|
1012
|
+
recording.updatedAt ?? "",
|
|
1013
|
+
].join(":")}
|
|
988
1014
|
videoFormat={recording.videoFormat}
|
|
989
1015
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
990
1016
|
durationMs={recording.durationMs}
|
|
@@ -86,29 +86,6 @@ export type ClipsTransactionalEmailInput =
|
|
|
86
86
|
videoTimestampMs?: number | null;
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
export const CLIPS_FIRST_VIEW_EMAIL_ID = "clips.first-view";
|
|
90
|
-
export const CLIPS_UNVIEWED_REMINDER_EMAIL_ID = "clips.unviewed-reminder";
|
|
91
|
-
export const CLIPS_FIRST_AGENT_VIEW_EMAIL_ID = "clips.first-agent-view";
|
|
92
|
-
export const CLIPS_FIRST_IMPORT_EMAIL_ID = "clips.first-import";
|
|
93
|
-
export const CLIPS_MONTHLY_RECAP_EMAIL_ID = "clips.monthly-recap";
|
|
94
|
-
export const CLIPS_TWO_CLIPS_EMAIL_ID = "clips.two-clips";
|
|
95
|
-
export const CLIPS_ACTIVITY_COMMENT_EMAIL_ID = "clips.activity-comment";
|
|
96
|
-
export const CLIPS_ACTIVITY_REACTION_EMAIL_ID = "clips.activity-reaction";
|
|
97
|
-
|
|
98
|
-
export const CLIPS_EMAIL_ID_BY_KIND: Record<
|
|
99
|
-
ClipsTransactionalEmailInput["kind"],
|
|
100
|
-
string
|
|
101
|
-
> = {
|
|
102
|
-
"first-view": CLIPS_FIRST_VIEW_EMAIL_ID,
|
|
103
|
-
"unviewed-reminder": CLIPS_UNVIEWED_REMINDER_EMAIL_ID,
|
|
104
|
-
"first-agent-view": CLIPS_FIRST_AGENT_VIEW_EMAIL_ID,
|
|
105
|
-
"first-import": CLIPS_FIRST_IMPORT_EMAIL_ID,
|
|
106
|
-
"monthly-recap": CLIPS_MONTHLY_RECAP_EMAIL_ID,
|
|
107
|
-
"two-clips": CLIPS_TWO_CLIPS_EMAIL_ID,
|
|
108
|
-
"activity-comment": CLIPS_ACTIVITY_COMMENT_EMAIL_ID,
|
|
109
|
-
"activity-reaction": CLIPS_ACTIVITY_REACTION_EMAIL_ID,
|
|
110
|
-
};
|
|
111
|
-
|
|
112
89
|
export interface RecapTopClipInput {
|
|
113
90
|
recordingId: string;
|
|
114
91
|
title?: string | null;
|
|
@@ -636,7 +613,6 @@ export async function sendClipsTransactionalEmail(
|
|
|
636
613
|
? (validReplyTo(input.senderEmail) ?? FRIENDLY_REPLY_TO)
|
|
637
614
|
: FRIENDLY_REPLY_TO,
|
|
638
615
|
timeoutMs: EMAIL_SEND_TIMEOUT_MS,
|
|
639
|
-
templateId: CLIPS_EMAIL_ID_BY_KIND[input.kind],
|
|
640
616
|
});
|
|
641
617
|
}
|
|
642
618
|
|
|
@@ -453,6 +453,7 @@ export default defineEventHandler(async (event) => {
|
|
|
453
453
|
editsJson: rec.editsJson,
|
|
454
454
|
videoUrl: playbackVideoUrl,
|
|
455
455
|
videoFormat: rec.videoFormat,
|
|
456
|
+
videoSizeBytes: rec.videoSizeBytes ?? null,
|
|
456
457
|
width: rec.width,
|
|
457
458
|
height: rec.height,
|
|
458
459
|
hasAudio: Boolean(rec.hasAudio),
|
|
@@ -21,10 +21,6 @@ import { and, eq } from "drizzle-orm";
|
|
|
21
21
|
|
|
22
22
|
import { CONTENT_USER_PREFS_KEY } from "../../shared/content-user-prefs.js";
|
|
23
23
|
import { getDb, schema } from "../db/index.js";
|
|
24
|
-
import {
|
|
25
|
-
CONTENT_DOCUMENT_COMMENT_EMAIL_ID,
|
|
26
|
-
CONTENT_DOCUMENT_MENTION_EMAIL_ID,
|
|
27
|
-
} from "./emails.js";
|
|
28
24
|
|
|
29
25
|
export type DocumentCommentNotificationResult = ActivityNotificationResult;
|
|
30
26
|
|
|
@@ -74,48 +70,6 @@ export interface DocumentCommentNotificationInput {
|
|
|
74
70
|
isReply: boolean;
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
export function renderDocumentCommentEmail({
|
|
78
|
-
actor,
|
|
79
|
-
title,
|
|
80
|
-
url,
|
|
81
|
-
content,
|
|
82
|
-
isReply,
|
|
83
|
-
wasMentioned,
|
|
84
|
-
}: {
|
|
85
|
-
actor: string;
|
|
86
|
-
title: string;
|
|
87
|
-
url: string;
|
|
88
|
-
content: string;
|
|
89
|
-
isReply: boolean;
|
|
90
|
-
wasMentioned: boolean;
|
|
91
|
-
}) {
|
|
92
|
-
const lead = wasMentioned
|
|
93
|
-
? `${emailStrong(actor)} mentioned you in a comment on ${emailStrong(title)}.`
|
|
94
|
-
: isReply
|
|
95
|
-
? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(title)}.`
|
|
96
|
-
: `${emailStrong(actor)} commented on ${emailStrong(title)}.`;
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
subject: wasMentioned
|
|
100
|
-
? `${actor} mentioned you on "${title}"`
|
|
101
|
-
: isReply
|
|
102
|
-
? `${actor} replied to a comment on "${title}"`
|
|
103
|
-
: `${actor} commented on "${title}"`,
|
|
104
|
-
...renderEmail({
|
|
105
|
-
preheader: `${actor} commented on ${title}.`,
|
|
106
|
-
heading: wasMentioned
|
|
107
|
-
? "You were mentioned"
|
|
108
|
-
: isReply
|
|
109
|
-
? "New reply on your document"
|
|
110
|
-
: "New comment",
|
|
111
|
-
paragraphs: [lead, `"${excerpt(content)}"`],
|
|
112
|
-
cta: { label: "Open document", url },
|
|
113
|
-
footer:
|
|
114
|
-
"You received this because you own, were mentioned in, or participated in this thread. Turn these off in Documents settings.",
|
|
115
|
-
}),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
73
|
export async function notifyDocumentComment(
|
|
120
74
|
input: DocumentCommentNotificationInput,
|
|
121
75
|
): Promise<DocumentCommentNotificationResult> {
|
|
@@ -158,19 +112,34 @@ async function deliverDocumentCommentEmails(
|
|
|
158
112
|
logLabel: LOG_LABEL,
|
|
159
113
|
send: async (to) => {
|
|
160
114
|
const wasMentioned = mentioned.has(to);
|
|
115
|
+
const lead = wasMentioned
|
|
116
|
+
? `${emailStrong(actor)} mentioned you in a comment on ${emailStrong(title)}.`
|
|
117
|
+
: input.isReply
|
|
118
|
+
? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(title)}.`
|
|
119
|
+
: `${emailStrong(actor)} commented on ${emailStrong(title)}.`;
|
|
120
|
+
|
|
121
|
+
const { html, text } = renderEmail({
|
|
122
|
+
preheader: `${actor} commented on ${title}.`,
|
|
123
|
+
heading: wasMentioned
|
|
124
|
+
? "You were mentioned"
|
|
125
|
+
: input.isReply
|
|
126
|
+
? "New reply on your document"
|
|
127
|
+
: "New comment",
|
|
128
|
+
paragraphs: [lead, `"${excerpt(input.content)}"`],
|
|
129
|
+
cta: { label: "Open document", url },
|
|
130
|
+
footer:
|
|
131
|
+
"You received this because you own, were mentioned in, or participated in this thread. Turn these off in Documents settings.",
|
|
132
|
+
});
|
|
133
|
+
|
|
161
134
|
await sendEmail({
|
|
162
|
-
...renderDocumentCommentEmail({
|
|
163
|
-
actor,
|
|
164
|
-
title,
|
|
165
|
-
url,
|
|
166
|
-
content: input.content,
|
|
167
|
-
isReply: input.isReply,
|
|
168
|
-
wasMentioned,
|
|
169
|
-
}),
|
|
170
135
|
to,
|
|
171
|
-
|
|
172
|
-
?
|
|
173
|
-
:
|
|
136
|
+
subject: wasMentioned
|
|
137
|
+
? `${actor} mentioned you on "${title}"`
|
|
138
|
+
: input.isReply
|
|
139
|
+
? `${actor} replied to a comment on "${title}"`
|
|
140
|
+
: `${actor} commented on "${title}"`,
|
|
141
|
+
html,
|
|
142
|
+
text,
|
|
174
143
|
});
|
|
175
144
|
},
|
|
176
145
|
});
|
|
@@ -73,14 +73,6 @@ interface DesignSystemData {
|
|
|
73
73
|
name: string;
|
|
74
74
|
variant: "light" | "dark" | "auto";
|
|
75
75
|
}[];
|
|
76
|
-
tokens?: {
|
|
77
|
-
name: string; // The source system's own name, e.g. "interactive-01"
|
|
78
|
-
cssVar: string; // e.g. "--cds-interactive-01"
|
|
79
|
-
value: string; // e.g. "#0F62FE" or "0.5rem"
|
|
80
|
-
type: "color" | "typography" | "spacing" | "radius" | "shadow" | "other";
|
|
81
|
-
group?: string; // Collection path, e.g. "Colors/Interactive"
|
|
82
|
-
source?: string; // e.g. "Carbon v11" or "globals.css"
|
|
83
|
-
}[];
|
|
84
76
|
imageStyle?: {
|
|
85
77
|
referenceUrls: string[];
|
|
86
78
|
styleDescription: string; // e.g., "Clean, minimal product photography"
|
|
@@ -90,29 +82,6 @@ interface DesignSystemData {
|
|
|
90
82
|
}
|
|
91
83
|
```
|
|
92
84
|
|
|
93
|
-
### The seven color roles are a summary, not the vocabulary
|
|
94
|
-
|
|
95
|
-
`colors` exists so a generated page can be themed from any brand. It is **not**
|
|
96
|
-
where a real design system goes. Carbon has `interactive-01`, Material has
|
|
97
|
-
`md-sys-color-primary-container`; mapping those onto `secondary` throws away the
|
|
98
|
-
only name the design team uses, and the Brand Kit page then shows the wrong
|
|
99
|
-
label for a token the user recognises.
|
|
100
|
-
|
|
101
|
-
So when a source names its tokens, populate **both**: `colors` for generation,
|
|
102
|
-
and `tokens` for the real vocabulary. `tokens` is capped at 500 entries, every
|
|
103
|
-
`cssVar` must be a valid custom property, and values may not contain `;`, `{`,
|
|
104
|
-
`}`, `<`, `>`, or CSS comments — `create-design-system` and
|
|
105
|
-
`update-design-system` reject the whole write and name the offending entries
|
|
106
|
-
rather than storing a partial vocabulary that would read as a smaller system.
|
|
107
|
-
|
|
108
|
-
`update-design-system` replaces the entire `data` object, so carry the existing
|
|
109
|
-
`tokens` array through any edit or those names are lost.
|
|
110
|
-
|
|
111
|
-
A kit with no stored `tokens` falls back to whatever names its `customCSS`
|
|
112
|
-
declares, which is why the production templates already display real Carbon,
|
|
113
|
-
Material, and Primer token names. Prefer real stored `tokens` when a source
|
|
114
|
-
gives them to you.
|
|
115
|
-
|
|
116
85
|
`imageStyle.styleDescription` is not just metadata — fold it into every
|
|
117
86
|
`generate-asset` prompt for a design linked to this system, alongside the
|
|
118
87
|
subject/composition/lighting direction described in the design-generation
|
|
@@ -487,11 +456,7 @@ When the user provides multiple sources, call all applicable import actions in p
|
|
|
487
456
|
3. **Cross-reference with website** — validates colors/fonts are actually deployed
|
|
488
457
|
4. **Documents supplement** — presentations may reveal brand colors not in code
|
|
489
458
|
5. **Images inform mood** — color temperature, density, visual style
|
|
490
|
-
6. **Aggregate into DesignSystemData** — merge all extracted tokens, resolve
|
|
491
|
-
conflicts, and carry every extracted name into `tokens`. The import actions
|
|
492
|
-
return `cssCustomProperties` keyed by the source's real variable names; those
|
|
493
|
-
keys are the vocabulary, so do not reduce them to the seven `colors` roles and
|
|
494
|
-
drop the rest.
|
|
459
|
+
6. **Aggregate into DesignSystemData** — merge all extracted tokens, resolve conflicts
|
|
495
460
|
7. **Call `create-design-system`** with the combined result
|
|
496
461
|
8. **Link to design** via `update-design --designSystemId`
|
|
497
462
|
|
|
@@ -544,14 +509,6 @@ When generating a design that has a linked design system, replace all default CS
|
|
|
544
509
|
}
|
|
545
510
|
```
|
|
546
511
|
|
|
547
|
-
### Reference named tokens, do not inline their values
|
|
548
|
-
|
|
549
|
-
`get-design-system` injects the kit's colour tokens and this requirement into
|
|
550
|
-
the generation context, so follow it there: write `var(--cds-link-primary,
|
|
551
|
-
#0f62fe)` rather than the colour. The fallback is required — exports and
|
|
552
|
-
kit-less designs define no custom properties, and a bare `var()` renders
|
|
553
|
-
transparent.
|
|
554
|
-
|
|
555
512
|
Also update the Google Fonts `<link>` tag to include the design system's fonts:
|
|
556
513
|
|
|
557
514
|
```html
|
|
@@ -388,263 +388,6 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
388
388
|
};
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
// shared/authored-color-styles.ts
|
|
392
|
-
var AUTHORED_COLOR_PROPERTIES = [
|
|
393
|
-
"color",
|
|
394
|
-
"backgroundColor",
|
|
395
|
-
"borderColor",
|
|
396
|
-
"outlineColor",
|
|
397
|
-
// Not colours themselves, but the only place a shadow's colour keeps its name.
|
|
398
|
-
"boxShadow",
|
|
399
|
-
"textShadow"
|
|
400
|
-
];
|
|
401
|
-
var SHORTHAND_FALLBACK = {
|
|
402
|
-
backgroundColor: "background",
|
|
403
|
-
borderColor: "border",
|
|
404
|
-
outlineColor: "outline"
|
|
405
|
-
};
|
|
406
|
-
var INHERITED_PROPERTIES = ["color"];
|
|
407
|
-
var RESET_KEYWORDS = /* @__PURE__ */ new Set([
|
|
408
|
-
"initial",
|
|
409
|
-
"inherit",
|
|
410
|
-
"unset",
|
|
411
|
-
"revert",
|
|
412
|
-
"revert-layer"
|
|
413
|
-
]);
|
|
414
|
-
function isAuthoredColor(value) {
|
|
415
|
-
return typeof value === "string" && value !== "" && !RESET_KEYWORDS.has(value.trim().toLowerCase());
|
|
416
|
-
}
|
|
417
|
-
var LINE_STYLE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
418
|
-
"none",
|
|
419
|
-
"hidden",
|
|
420
|
-
"solid",
|
|
421
|
-
"dashed",
|
|
422
|
-
"dotted",
|
|
423
|
-
"double",
|
|
424
|
-
"groove",
|
|
425
|
-
"ridge",
|
|
426
|
-
"inset",
|
|
427
|
-
"outset"
|
|
428
|
-
]);
|
|
429
|
-
var LINE_WIDTH = /^(thin|medium|thick|-?\\d*\\.?\\d+[a-z%]*)$/i;
|
|
430
|
-
function splitTopLevel(value) {
|
|
431
|
-
const parts = [];
|
|
432
|
-
let depth = 0;
|
|
433
|
-
let current = "";
|
|
434
|
-
for (const char of value) {
|
|
435
|
-
if (char === "(") depth += 1;
|
|
436
|
-
else if (char === ")") depth -= 1;
|
|
437
|
-
if (depth === 0 && /\\s/.test(char)) {
|
|
438
|
-
if (current) parts.push(current);
|
|
439
|
-
current = "";
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
current += char;
|
|
443
|
-
}
|
|
444
|
-
if (current) parts.push(current);
|
|
445
|
-
return parts;
|
|
446
|
-
}
|
|
447
|
-
function lineShorthandColor(value) {
|
|
448
|
-
const rest = splitTopLevel(value).filter((part) => {
|
|
449
|
-
const lower = part.toLowerCase();
|
|
450
|
-
return !LINE_STYLE_KEYWORDS.has(lower) && !LINE_WIDTH.test(part);
|
|
451
|
-
});
|
|
452
|
-
return rest.length === 1 ? rest[0] : null;
|
|
453
|
-
}
|
|
454
|
-
function shorthandColorValue(shorthand, value) {
|
|
455
|
-
const trimmed = value.trim();
|
|
456
|
-
if (!trimmed) return null;
|
|
457
|
-
if (/url\\(|gradient\\(/i.test(trimmed)) return null;
|
|
458
|
-
if (/^var\\(.*\\)$/.test(trimmed)) return trimmed;
|
|
459
|
-
if (shorthand === "border" || shorthand === "outline") {
|
|
460
|
-
return lineShorthandColor(trimmed);
|
|
461
|
-
}
|
|
462
|
-
return /\\s/.test(trimmed) ? null : trimmed;
|
|
463
|
-
}
|
|
464
|
-
function selectorSpecificity(selector) {
|
|
465
|
-
const cleaned = selector.replace(/\\\\./g, "").replace(/\\[[^\\]]*\\]/g, " :attr ").replace(/\\(([^()]*)\\)/g, " ");
|
|
466
|
-
const count = (pattern) => (cleaned.match(pattern) ?? []).length;
|
|
467
|
-
const ids = count(/#[\\w-]+/g);
|
|
468
|
-
const classes = count(/\\.[\\w-]+/g) + count(/:(?!:)[\\w-]+/g);
|
|
469
|
-
const types = count(/(?:^|[\\s>+~])[a-zA-Z][\\w-]*/g) + count(/::[\\w-]+/g);
|
|
470
|
-
return ids * 1e4 + classes * 100 + types;
|
|
471
|
-
}
|
|
472
|
-
function matchedSpecificity(element, selectorText) {
|
|
473
|
-
let best = -1;
|
|
474
|
-
for (const selector of selectorText.split(",")) {
|
|
475
|
-
const trimmed = selector.trim();
|
|
476
|
-
if (!trimmed) continue;
|
|
477
|
-
try {
|
|
478
|
-
if (!element.matches(trimmed)) continue;
|
|
479
|
-
} catch {
|
|
480
|
-
continue;
|
|
481
|
-
}
|
|
482
|
-
best = Math.max(best, selectorSpecificity(trimmed));
|
|
483
|
-
}
|
|
484
|
-
return best;
|
|
485
|
-
}
|
|
486
|
-
var INLINE_SPECIFICITY = Number.MAX_SAFE_INTEGER;
|
|
487
|
-
function beats(next, current) {
|
|
488
|
-
if (!current) return true;
|
|
489
|
-
if (next.important !== current.important) return next.important;
|
|
490
|
-
if (next.specificity !== current.specificity) {
|
|
491
|
-
return next.specificity > current.specificity;
|
|
492
|
-
}
|
|
493
|
-
return next.order >= current.order;
|
|
494
|
-
}
|
|
495
|
-
function readRules(element, rules, out, counter) {
|
|
496
|
-
if (!rules) return;
|
|
497
|
-
for (let index = 0; index < rules.length; index += 1) {
|
|
498
|
-
const rule = rules[index];
|
|
499
|
-
if (!rule) continue;
|
|
500
|
-
const declaresOwnStyles = Boolean(rule.selectorText && rule.style);
|
|
501
|
-
if (!declaresOwnStyles) {
|
|
502
|
-
if (!rule.cssRules) continue;
|
|
503
|
-
if (rule.conditionText === void 0) {
|
|
504
|
-
readRules(element, rule.cssRules, out, counter);
|
|
505
|
-
continue;
|
|
506
|
-
}
|
|
507
|
-
let applies = false;
|
|
508
|
-
try {
|
|
509
|
-
applies = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(rule.conditionText).matches : false;
|
|
510
|
-
} catch {
|
|
511
|
-
applies = false;
|
|
512
|
-
}
|
|
513
|
-
if (applies) readRules(element, rule.cssRules, out, counter);
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
if (rule.cssRules?.length) {
|
|
517
|
-
readRules(element, rule.cssRules, out, counter);
|
|
518
|
-
}
|
|
519
|
-
if (!rule.selectorText || !rule.style) continue;
|
|
520
|
-
const specificity = matchedSpecificity(element, rule.selectorText);
|
|
521
|
-
if (specificity < 0) continue;
|
|
522
|
-
const order = counter.order++;
|
|
523
|
-
const style = rule.style;
|
|
524
|
-
const priority = (name) => style.getPropertyPriority?.(name) === "important";
|
|
525
|
-
const offer = (property, value, cssName) => {
|
|
526
|
-
const candidate = {
|
|
527
|
-
value,
|
|
528
|
-
important: priority(cssName),
|
|
529
|
-
specificity,
|
|
530
|
-
order
|
|
531
|
-
};
|
|
532
|
-
if (beats(candidate, out[property])) out[property] = candidate;
|
|
533
|
-
};
|
|
534
|
-
for (const property of AUTHORED_COLOR_PROPERTIES) {
|
|
535
|
-
const declared = style[property];
|
|
536
|
-
if (isAuthoredColor(declared)) {
|
|
537
|
-
offer(property, declared, cssPropertyName(property));
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
const shorthand = SHORTHAND_FALLBACK[property];
|
|
541
|
-
if (!shorthand) continue;
|
|
542
|
-
const shorthandValue = style[shorthand];
|
|
543
|
-
if (typeof shorthandValue !== "string") continue;
|
|
544
|
-
const colorOnly = shorthandColorValue(shorthand, shorthandValue);
|
|
545
|
-
if (colorOnly) offer(property, colorOnly, shorthand);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
function cssPropertyName(property) {
|
|
550
|
-
return property.replace(/[A-Z]/g, (c) => \`-\${c.toLowerCase()}\`);
|
|
551
|
-
}
|
|
552
|
-
function authoredMatchesPainted(element, property, authored) {
|
|
553
|
-
const view = element.ownerDocument?.defaultView;
|
|
554
|
-
if (!view || typeof view.getComputedStyle !== "function") return true;
|
|
555
|
-
let painted = "";
|
|
556
|
-
try {
|
|
557
|
-
painted = view.getComputedStyle(element)[property] ?? "";
|
|
558
|
-
} catch {
|
|
559
|
-
return true;
|
|
560
|
-
}
|
|
561
|
-
if (!painted) return true;
|
|
562
|
-
const probe = element.ownerDocument.createElement("span");
|
|
563
|
-
const name = cssPropertyName(property);
|
|
564
|
-
probe.style.setProperty("display", "none");
|
|
565
|
-
probe.style.setProperty(name, authored);
|
|
566
|
-
if (!probe.style.getPropertyValue(name)) return false;
|
|
567
|
-
element.appendChild(probe);
|
|
568
|
-
let resolved = "";
|
|
569
|
-
try {
|
|
570
|
-
resolved = view.getComputedStyle(probe)[property] ?? "";
|
|
571
|
-
} catch {
|
|
572
|
-
resolved = "";
|
|
573
|
-
}
|
|
574
|
-
probe.remove();
|
|
575
|
-
return resolved === "" || resolved === painted;
|
|
576
|
-
}
|
|
577
|
-
function collectForElement(element) {
|
|
578
|
-
const ranked = {};
|
|
579
|
-
const counter = { order: 0 };
|
|
580
|
-
try {
|
|
581
|
-
const doc = element.ownerDocument;
|
|
582
|
-
const sheets = [
|
|
583
|
-
...Array.from(doc?.styleSheets ?? []),
|
|
584
|
-
...Array.from(
|
|
585
|
-
doc?.adoptedStyleSheets ?? []
|
|
586
|
-
)
|
|
587
|
-
];
|
|
588
|
-
for (const sheet of sheets) {
|
|
589
|
-
let rules;
|
|
590
|
-
try {
|
|
591
|
-
rules = sheet.cssRules;
|
|
592
|
-
} catch {
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
readRules(element, rules, ranked, counter);
|
|
596
|
-
}
|
|
597
|
-
} catch (error) {
|
|
598
|
-
console.warn(
|
|
599
|
-
"[design] could not read stylesheets for authored colours; token names will fall back to resolved values",
|
|
600
|
-
error
|
|
601
|
-
);
|
|
602
|
-
}
|
|
603
|
-
const inline = element.style;
|
|
604
|
-
if (inline) {
|
|
605
|
-
const order = counter.order++;
|
|
606
|
-
for (const property of AUTHORED_COLOR_PROPERTIES) {
|
|
607
|
-
const value = inline[property];
|
|
608
|
-
if (!isAuthoredColor(value)) continue;
|
|
609
|
-
const candidate = {
|
|
610
|
-
value,
|
|
611
|
-
important: inline.getPropertyPriority?.(cssPropertyName(property)) === "important",
|
|
612
|
-
specificity: INLINE_SPECIFICITY,
|
|
613
|
-
order
|
|
614
|
-
};
|
|
615
|
-
if (beats(candidate, ranked[property])) ranked[property] = candidate;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
const out = {};
|
|
619
|
-
for (const [property, candidate] of Object.entries(ranked)) {
|
|
620
|
-
out[property] = candidate.value;
|
|
621
|
-
}
|
|
622
|
-
return out;
|
|
623
|
-
}
|
|
624
|
-
function collectAuthoredColorStyles(element) {
|
|
625
|
-
const out = collectForElement(element);
|
|
626
|
-
for (const property of Object.keys(out)) {
|
|
627
|
-
if (!authoredMatchesPainted(element, property, out[property])) {
|
|
628
|
-
delete out[property];
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
for (const property of INHERITED_PROPERTIES) {
|
|
632
|
-
if (out[property]) continue;
|
|
633
|
-
let ancestor = element.parentElement;
|
|
634
|
-
while (ancestor) {
|
|
635
|
-
const inherited = collectForElement(ancestor)[property];
|
|
636
|
-
if (inherited) {
|
|
637
|
-
if (authoredMatchesPainted(element, property, inherited)) {
|
|
638
|
-
out[property] = inherited;
|
|
639
|
-
}
|
|
640
|
-
break;
|
|
641
|
-
}
|
|
642
|
-
ancestor = ancestor.parentElement;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
return out;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
391
|
// app/components/design/bridge/editor-chrome.bridge.ts
|
|
649
392
|
(function() {
|
|
650
393
|
if (window.__anEditorChromeBridge) return;
|
|
@@ -1890,13 +1633,7 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
1890
1633
|
"width",
|
|
1891
1634
|
"height",
|
|
1892
1635
|
"transform",
|
|
1893
|
-
"whiteSpace"
|
|
1894
|
-
"color",
|
|
1895
|
-
"backgroundColor",
|
|
1896
|
-
"borderColor",
|
|
1897
|
-
"outlineColor",
|
|
1898
|
-
"boxShadow",
|
|
1899
|
-
"textShadow"
|
|
1636
|
+
"whiteSpace"
|
|
1900
1637
|
];
|
|
1901
1638
|
function collectInlineStyles(el) {
|
|
1902
1639
|
var styles = {};
|
|
@@ -2100,7 +1837,6 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
2100
1837
|
whiteSpace: cs.whiteSpace
|
|
2101
1838
|
},
|
|
2102
1839
|
inlineStyles: collectInlineStyles(el),
|
|
2103
|
-
authoredColorStyles: collectAuthoredColorStyles(el),
|
|
2104
1840
|
primitiveKind: el.getAttribute("data-an-primitive") || void 0,
|
|
2105
1841
|
portableStyleSnapshot: collectPortableStyleSnapshot(el),
|
|
2106
1842
|
boundingRect: {
|
|
@@ -8,7 +8,6 @@ import { nanoid } from "nanoid";
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { getDb, schema } from "../server/db/index.js";
|
|
11
|
-
import { assertStorableDesignSystemTokens } from "../server/lib/design-system-tokens.js";
|
|
12
11
|
import {
|
|
13
12
|
DESIGN_SYSTEM_TEMPLATE_IDS,
|
|
14
13
|
getProductionDesignSystemTemplate,
|
|
@@ -40,13 +39,7 @@ export const createDesignSystemSchema = z
|
|
|
40
39
|
.min(1, "data is required")
|
|
41
40
|
.optional()
|
|
42
41
|
.describe(
|
|
43
|
-
"JSON string of DesignSystemData (required without templateId; templates supply their verified token snapshot)
|
|
44
|
-
"Include a `tokens` array whenever the source names its tokens: " +
|
|
45
|
-
// guard:allow-raw-color — an agent-facing payload example, not a styled value
|
|
46
|
-
'[{ "name": "interactive-01", "cssVar": "--cds-interactive-01", "value": "#0F62FE", ' +
|
|
47
|
-
'"type": "color", "group": "Colors/Interactive", "source": "Carbon v11" }]. ' +
|
|
48
|
-
"The seven `colors` roles are a summary for generation, not a place to squash a " +
|
|
49
|
-
"real system's vocabulary into — send both.",
|
|
42
|
+
"JSON string of DesignSystemData (required without templateId; templates supply their verified token snapshot)",
|
|
50
43
|
),
|
|
51
44
|
assets: z
|
|
52
45
|
.string()
|
|
@@ -118,7 +111,15 @@ export default defineAction({
|
|
|
118
111
|
throw new Error("title and data are required");
|
|
119
112
|
}
|
|
120
113
|
|
|
121
|
-
|
|
114
|
+
// Validate that data is valid JSON and not an empty primitive.
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(resolvedData);
|
|
117
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
118
|
+
throw new Error();
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
throw new Error("data must be a valid JSON object string");
|
|
122
|
+
}
|
|
122
123
|
if (assets) {
|
|
123
124
|
try {
|
|
124
125
|
JSON.parse(assets);
|