@agent-native/core 0.153.10 → 0.154.1
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/AGENTS.md +20 -30
- package/corpus/templates/analytics/actions/search-dashboard-references.ts +58 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/analytics/app/lib/utils.ts +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +1 -1
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +366 -3
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +3 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -2
- package/corpus/templates/calendar/app/components/calendar/EventDialog.tsx +1 -1
- package/corpus/templates/calendar/app/lib/utils.ts +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +32 -5
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +15 -15
- package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
- package/corpus/templates/clips/app/lib/utils.ts +5 -6
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +43 -8
- package/corpus/templates/clips/desktop/src/app.tsx +26 -12
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +23 -9
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +261 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +21 -3
- package/corpus/templates/clips/shared/mic-audio-cleanup.ts +350 -0
- package/corpus/templates/content/actions/resolve-content-landing.ts +162 -32
- package/corpus/templates/content/app/i18n-data.ts +10 -10
- package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
- package/corpus/templates/content/shared/content-landing.ts +5 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +79 -7
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +14 -2
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +2 -2
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +35 -11
- package/corpus/templates/design/actions/get-design-system.ts +103 -3
- package/corpus/templates/design/actions/import-design-tokens.ts +37 -8
- package/corpus/templates/design/actions/import-github.ts +32 -138
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +49 -16
- package/corpus/templates/design/actions/present-design-variants.ts +93 -4
- package/corpus/templates/design/actions/run-design-audit.ts +229 -0
- package/corpus/templates/design/actions/sync-design-system-with-builder.ts +64 -0
- package/corpus/templates/design/app/components/design/code-workbench/commands.ts +2 -2
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +17 -4
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +5 -1
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +5 -1
- package/corpus/templates/design/app/hooks/use-question-flow.ts +81 -5
- package/corpus/templates/design/app/i18n/en-US.ts +1 -1
- package/corpus/templates/design/app/i18n-data.ts +32 -1
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +10 -10
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +83 -11
- package/corpus/templates/design/app/pages/DesignSystems.tsx +14 -0
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +22 -0
- package/corpus/templates/design/changelog/2026-08-13-a-screen-that-would-render-behind-an-invisible-alpine-overla.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-attach-a-ui-screenshot-and-the-design-is-reproduced-not-rein.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-linking-a-design-system-means-you-never-get-generic-directio.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-reports-when-a-screen-ignores-its-linke.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-system-preview-now-shows-how-many-named-tokens-we.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-your-design-system-prompt-and-reference-screenshots-now-reac.md +6 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +18 -2
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +171 -0
- package/corpus/templates/mail/app/lib/utils.ts +1 -1
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +10 -6
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +41 -3
- package/corpus/templates/slides/actions/patch-deck.ts +12 -3
- package/corpus/templates/slides/actions/sync-design-system-with-builder.ts +64 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +193 -20
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +73 -1
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +64 -34
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +34 -41
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +119 -91
- package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +16 -0
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +15 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +158 -31
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +30 -14
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +2 -2
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -1
- package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +14 -0
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +24 -0
- package/corpus/templates/slides/app/context/DeckContext.tsx +19 -31
- package/corpus/templates/slides/app/global.css +24 -0
- package/corpus/templates/slides/app/hooks/use-navigation-state.ts +20 -17
- package/corpus/templates/slides/app/i18n/en-US.ts +19 -10
- package/corpus/templates/slides/app/lib/deck-filter.ts +47 -0
- package/corpus/templates/slides/app/lib/export-google-slides-client.ts +15 -4
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +637 -1
- package/corpus/templates/slides/app/lib/image-download.ts +84 -0
- package/corpus/templates/slides/app/lib/utils.ts +1 -1
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +9 -0
- package/corpus/templates/slides/app/pages/Index.tsx +25 -9
- package/corpus/templates/slides/changelog/2026-08-13-clicking-a-slide-thumbnail-now-focuses-it-so-the-slide-shortc.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-13-duplicating-or-restoring-a-slide-now-keeps-its-transition-ani.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-13-opening-presentation-mode-from-the-agent-now-starts-on-the-re.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-13-slide-transitions-can-be-set-from-a-visible-control-in-the-sl.md +6 -0
- package/corpus/templates/slides/netlify.toml +1 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
- package/dist/a2a/audience.d.ts +2 -0
- package/dist/a2a/audience.js +23 -0
- package/dist/a2a/client.d.ts +4 -0
- package/dist/a2a/client.js +32 -14
- package/dist/a2a/server.d.ts +9 -4
- package/dist/a2a/server.js +52 -25
- package/dist/a2a/types.d.ts +4 -4
- package/dist/agent/production-agent.js +1 -1
- package/dist/brand-kit/types.d.ts +10 -2
- package/dist/cli/code.js +1 -1
- package/dist/cli/index.js +30 -1
- package/dist/cli/native-dependencies.d.ts +24 -0
- package/dist/cli/native-dependencies.js +264 -0
- package/dist/cli/plan-local.js +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +2 -2
- package/dist/cli/visualize-repo.js +1 -1
- package/dist/client/FeedbackButton.js +12 -12
- package/dist/client/agent-chat-adapter.js +3 -4
- package/dist/client/assistant-ui-recovery.d.ts +1 -1
- package/dist/client/assistant-ui-recovery.js +4 -0
- package/dist/client/chat/message-components.d.ts +11 -3
- package/dist/client/chat/message-components.js +31 -5
- package/dist/client/chat/tool-call-display.d.ts +2 -1
- package/dist/client/chat/tool-call-display.js +33 -15
- package/dist/client/db-admin/SqlEditor.js +1 -1
- package/dist/client/dev-overlay/DevOverlay.js +2 -2
- package/dist/client/extensions/portable-extension.js +4 -0
- package/dist/client/guided-questions.d.ts +8 -0
- package/dist/client/guided-questions.js +12 -3
- package/dist/client/sharing/ShareButton.js +16 -24
- package/dist/client/sse-event-processor.js +35 -15
- package/dist/client/tool-display.d.ts +9 -0
- package/dist/client/tool-display.js +39 -0
- package/dist/client/vite-dev-recovery-script.js +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/html-shell.js +5 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +2 -2
- package/dist/server/agent-capabilities.js +0 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -13
- package/dist/server/agent-chat/action-filters-a2a.js +59 -23
- package/dist/server/agent-chat/prompt-resources.js +17 -16
- package/dist/server/agent-chat-plugin.d.ts +9 -0
- package/dist/server/agent-chat-plugin.js +29 -7
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +33 -1
- package/dist/server/builder-design-systems.js +293 -11
- package/dist/server/design-token-utils.d.ts +11 -0
- package/dist/server/design-token-utils.js +68 -16
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +2 -2
|
@@ -489,6 +489,203 @@ export function checkTokenDrift(
|
|
|
489
489
|
return findings;
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
// ---------------------------------------------------------------------------
|
|
493
|
+
// Design-system adherence check
|
|
494
|
+
// ---------------------------------------------------------------------------
|
|
495
|
+
//
|
|
496
|
+
// checkTokenDrift above only proves the screens agree with EACH OTHER. A design
|
|
497
|
+
// can be perfectly self-consistent and still ignore the brand it is linked to,
|
|
498
|
+
// which is the most-reported failure of generation: the user links their system,
|
|
499
|
+
// the agent writes its own palette, and nothing anywhere notices. This compares
|
|
500
|
+
// the saved HTML against the linked kit's own values so the drift is reportable
|
|
501
|
+
// instead of invisible.
|
|
502
|
+
|
|
503
|
+
/** The subset of a Brand Kit this check can verify against rendered HTML. */
|
|
504
|
+
export interface DesignSystemExpectation {
|
|
505
|
+
title: string;
|
|
506
|
+
fonts: string[];
|
|
507
|
+
/** Lowercase six-digit hex values, normalized from the kit's own notation. */
|
|
508
|
+
colors: string[];
|
|
509
|
+
/** Custom-property names the kit names, e.g. `--color-primary`. */
|
|
510
|
+
cssVars: string[];
|
|
511
|
+
/**
|
|
512
|
+
* The kit's stored `data` could not be parsed. Adherence is then UNKNOWN,
|
|
513
|
+
* which is not the same as satisfied — a silent empty expectation would
|
|
514
|
+
* report a corrupt design system as a clean audit.
|
|
515
|
+
*/
|
|
516
|
+
unreadable?: boolean;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function normalizeHex(value: unknown): string | null {
|
|
520
|
+
if (typeof value !== "string") return null;
|
|
521
|
+
const match = value.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
|
522
|
+
if (!match) return null;
|
|
523
|
+
const hex = match[1].toLowerCase();
|
|
524
|
+
// Expand shorthand so 3- and 6-digit forms compare in one space.
|
|
525
|
+
return hex.length === 3
|
|
526
|
+
? `#${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`
|
|
527
|
+
: `#${hex}`;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function expandShortHexes(html: string): string {
|
|
531
|
+
return html.replace(
|
|
532
|
+
/#([0-9a-f])([0-9a-f])([0-9a-f])\b/gi,
|
|
533
|
+
(_m, r: string, g: string, b: string) =>
|
|
534
|
+
`#${r}${r}${g}${g}${b}${b}`.toLowerCase(),
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Build the checkable expectation from a kit's stored `data` JSON. Returns null
|
|
540
|
+
* when the kit carries nothing verifiable — "we cannot check" must not render
|
|
541
|
+
* as "the design complies".
|
|
542
|
+
*/
|
|
543
|
+
export function designSystemExpectation(
|
|
544
|
+
title: string,
|
|
545
|
+
data: string | null | undefined,
|
|
546
|
+
): DesignSystemExpectation | null {
|
|
547
|
+
const unreadable: DesignSystemExpectation = {
|
|
548
|
+
title,
|
|
549
|
+
fonts: [],
|
|
550
|
+
colors: [],
|
|
551
|
+
cssVars: [],
|
|
552
|
+
unreadable: true,
|
|
553
|
+
};
|
|
554
|
+
let parsed: Record<string, unknown> | null = null;
|
|
555
|
+
try {
|
|
556
|
+
parsed = data ? (JSON.parse(data) as Record<string, unknown>) : null;
|
|
557
|
+
} catch {
|
|
558
|
+
return unreadable;
|
|
559
|
+
}
|
|
560
|
+
if (!parsed) return null;
|
|
561
|
+
|
|
562
|
+
const typography = (parsed.typography ?? {}) as Record<string, unknown>;
|
|
563
|
+
const fonts = [typography.headingFont, typography.bodyFont]
|
|
564
|
+
.filter((font): font is string => typeof font === "string" && !!font.trim())
|
|
565
|
+
.map((font) => font.trim());
|
|
566
|
+
|
|
567
|
+
const colorRoles = (parsed.colors ?? {}) as Record<string, unknown>;
|
|
568
|
+
const colors = Object.values(colorRoles)
|
|
569
|
+
.map(normalizeHex)
|
|
570
|
+
.filter((hex): hex is string => hex !== null);
|
|
571
|
+
|
|
572
|
+
const cssVars = Array.isArray(parsed.tokens)
|
|
573
|
+
? parsed.tokens
|
|
574
|
+
.map((token) =>
|
|
575
|
+
token && typeof token === "object"
|
|
576
|
+
? (token as { cssVar?: unknown }).cssVar
|
|
577
|
+
: null,
|
|
578
|
+
)
|
|
579
|
+
.filter(
|
|
580
|
+
(cssVar): cssVar is string =>
|
|
581
|
+
typeof cssVar === "string" && cssVar.startsWith("--"),
|
|
582
|
+
)
|
|
583
|
+
: [];
|
|
584
|
+
|
|
585
|
+
if (fonts.length === 0 && colors.length === 0 && cssVars.length === 0) {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
title,
|
|
590
|
+
fonts: Array.from(new Set(fonts)),
|
|
591
|
+
colors: Array.from(new Set(colors)),
|
|
592
|
+
cssVars: Array.from(new Set(cssVars)),
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Flag a screen that uses none of its linked design system's fonts, or none of
|
|
598
|
+
* its colors. Deliberately a "none of them" test rather than a per-value one:
|
|
599
|
+
* a design legitimately uses a subset of a kit, but a design using zero of it
|
|
600
|
+
* is not following it at all. Pure so it can be unit tested without a DB.
|
|
601
|
+
*/
|
|
602
|
+
export function checkDesignSystemAdherence(
|
|
603
|
+
html: string,
|
|
604
|
+
expectation: DesignSystemExpectation | null,
|
|
605
|
+
filename: string,
|
|
606
|
+
): A11yFinding[] {
|
|
607
|
+
if (!expectation) return [];
|
|
608
|
+
if (expectation.unreadable) {
|
|
609
|
+
return [
|
|
610
|
+
{
|
|
611
|
+
id: `design-system-drift:${filename}:unreadable`,
|
|
612
|
+
severity: "warning",
|
|
613
|
+
category: "design-system-drift",
|
|
614
|
+
message: `"${expectation.title}" could not be read, so adherence was not checked.`,
|
|
615
|
+
detail:
|
|
616
|
+
"The linked design system's stored token data is not valid JSON. " +
|
|
617
|
+
"Adherence is unknown, not satisfied — re-import or re-index the " +
|
|
618
|
+
"system before treating this screen as on-brand.",
|
|
619
|
+
selector: ":root",
|
|
620
|
+
fixAvailable: false,
|
|
621
|
+
},
|
|
622
|
+
];
|
|
623
|
+
}
|
|
624
|
+
const findings: A11yFinding[] = [];
|
|
625
|
+
const haystack = expandShortHexes(html.toLowerCase());
|
|
626
|
+
|
|
627
|
+
if (expectation.fonts.length > 0) {
|
|
628
|
+
const used = expectation.fonts.filter((font) =>
|
|
629
|
+
haystack.includes(font.toLowerCase()),
|
|
630
|
+
);
|
|
631
|
+
if (used.length === 0) {
|
|
632
|
+
findings.push({
|
|
633
|
+
id: `design-system-drift:${filename}:fonts`,
|
|
634
|
+
severity: "warning",
|
|
635
|
+
category: "design-system-drift",
|
|
636
|
+
message: `${filename} uses none of "${expectation.title}"'s fonts.`,
|
|
637
|
+
detail:
|
|
638
|
+
`The linked design system specifies ${expectation.fonts.join(", ")}, ` +
|
|
639
|
+
`but ${filename} references none of them. Load and apply the system's ` +
|
|
640
|
+
"typography, or tell the user you are deviating and why.",
|
|
641
|
+
selector: ":root",
|
|
642
|
+
fixAvailable: false,
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (expectation.colors.length > 0) {
|
|
648
|
+
const used = expectation.colors.filter((hex) => haystack.includes(hex));
|
|
649
|
+
if (used.length === 0) {
|
|
650
|
+
findings.push({
|
|
651
|
+
id: `design-system-drift:${filename}:colors`,
|
|
652
|
+
severity: "warning",
|
|
653
|
+
category: "design-system-drift",
|
|
654
|
+
message: `${filename} uses none of "${expectation.title}"'s colors.`,
|
|
655
|
+
detail:
|
|
656
|
+
`The linked design system defines ${expectation.colors.slice(0, 6).join(", ")}` +
|
|
657
|
+
`${expectation.colors.length > 6 ? ", …" : ""}, but ${filename} uses none of ` +
|
|
658
|
+
"them. Put the system's values in the `:root` token block instead of an " +
|
|
659
|
+
"invented palette.",
|
|
660
|
+
selector: ":root",
|
|
661
|
+
fixAvailable: false,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (expectation.cssVars.length > 0) {
|
|
667
|
+
const used = expectation.cssVars.filter((cssVar) =>
|
|
668
|
+
haystack.includes(cssVar.toLowerCase()),
|
|
669
|
+
);
|
|
670
|
+
if (used.length === 0) {
|
|
671
|
+
findings.push({
|
|
672
|
+
id: `design-system-drift:${filename}:css-vars`,
|
|
673
|
+
severity: "info",
|
|
674
|
+
category: "design-system-drift",
|
|
675
|
+
message: `${filename} uses none of "${expectation.title}"'s token names.`,
|
|
676
|
+
detail:
|
|
677
|
+
`The system names ${expectation.cssVars.length} custom properties (e.g. ` +
|
|
678
|
+
`${expectation.cssVars.slice(0, 4).join(", ")}). Reusing those exact names ` +
|
|
679
|
+
"keeps the prototype swappable with the real codebase.",
|
|
680
|
+
selector: ":root",
|
|
681
|
+
fixAvailable: false,
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
return findings;
|
|
687
|
+
}
|
|
688
|
+
|
|
492
689
|
// ---------------------------------------------------------------------------
|
|
493
690
|
// Live-content helper (matches the pattern in other actions)
|
|
494
691
|
// ---------------------------------------------------------------------------
|
|
@@ -519,6 +716,11 @@ export default defineAction({
|
|
|
519
716
|
"form labels, focus-visibility gaps, reduced-motion coverage, and — for " +
|
|
520
717
|
"multi-screen designs — token drift (the audited screen's :root custom " +
|
|
521
718
|
"properties diverging from index.html's). " +
|
|
719
|
+
"When the design is linked to a design system, also reports " +
|
|
720
|
+
"design-system drift: the screen using none of the linked system's fonts, " +
|
|
721
|
+
"colors, or token names. Treat that finding as a generation bug to fix, " +
|
|
722
|
+
"not a style opinion — reload the system with `get-design-system` and " +
|
|
723
|
+
"apply its values rather than explaining the deviation. " +
|
|
522
724
|
"Returns A11yFinding[] that can be shown in the Review panel or persisted " +
|
|
523
725
|
"via create-design-review-snapshot. No writes are performed.",
|
|
524
726
|
schema: z.object({
|
|
@@ -612,6 +814,32 @@ export default defineAction({
|
|
|
612
814
|
finding.id.includes(`token-drift:${file.filename}:`),
|
|
613
815
|
);
|
|
614
816
|
|
|
817
|
+
// Adherence to the LINKED system, which token drift cannot see.
|
|
818
|
+
const [linkedSystem] = await db
|
|
819
|
+
.select({
|
|
820
|
+
title: schema.designSystems.title,
|
|
821
|
+
data: schema.designSystems.data,
|
|
822
|
+
})
|
|
823
|
+
.from(schema.designs)
|
|
824
|
+
.innerJoin(
|
|
825
|
+
schema.designSystems,
|
|
826
|
+
eq(schema.designs.designSystemId, schema.designSystems.id),
|
|
827
|
+
)
|
|
828
|
+
.where(
|
|
829
|
+
and(
|
|
830
|
+
eq(schema.designs.id, designId),
|
|
831
|
+
accessFilter(schema.designSystems, schema.designSystemShares),
|
|
832
|
+
),
|
|
833
|
+
)
|
|
834
|
+
.limit(1);
|
|
835
|
+
const designSystemFindings = linkedSystem
|
|
836
|
+
? checkDesignSystemAdherence(
|
|
837
|
+
html,
|
|
838
|
+
designSystemExpectation(linkedSystem.title, linkedSystem.data),
|
|
839
|
+
file.filename,
|
|
840
|
+
)
|
|
841
|
+
: [];
|
|
842
|
+
|
|
615
843
|
// Run all audit checks over the static HTML.
|
|
616
844
|
const findings: A11yFinding[] = [
|
|
617
845
|
...checkMissingAlt(html),
|
|
@@ -621,6 +849,7 @@ export default defineAction({
|
|
|
621
849
|
...checkFocusVisibility(html),
|
|
622
850
|
...checkContrastHint(html),
|
|
623
851
|
...tokenDriftFindings,
|
|
852
|
+
...designSystemFindings,
|
|
624
853
|
];
|
|
625
854
|
|
|
626
855
|
// Summarise by severity for the agent context.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
parseBuilderDesignSystemProxyReference,
|
|
4
|
+
startBuilderDesignSystemIndex,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
7
|
+
import { assertAccess, resolveAccess } from "@agent-native/core/sharing";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
import "../server/db/index.js";
|
|
11
|
+
import { upsertBuilderProxyDesignSystem } from "../server/lib/builder-design-system-proxy.js";
|
|
12
|
+
|
|
13
|
+
export default defineAction({
|
|
14
|
+
description:
|
|
15
|
+
"Re-index a Builder-backed GitHub design system using its persisted repository, ref, and file/folder scope. Requires editor access.",
|
|
16
|
+
schema: z.object({
|
|
17
|
+
id: z.string().min(1).describe("Local design system id"),
|
|
18
|
+
}),
|
|
19
|
+
run: async ({ id }) => {
|
|
20
|
+
await assertAccess("design-system", id, "editor");
|
|
21
|
+
const access = await resolveAccess("design-system", id);
|
|
22
|
+
if (!access) throw new Error("Design system not found");
|
|
23
|
+
|
|
24
|
+
const reference = parseBuilderDesignSystemProxyReference(
|
|
25
|
+
access.resource.data,
|
|
26
|
+
);
|
|
27
|
+
if (!reference?.githubSources?.length) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"This design system has no persisted GitHub source scope to sync.",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (reference.sourceKind === "mixed") {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"This design system combines GitHub with non-replayable sources. Re-import all sources before syncing it.",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = await startBuilderDesignSystemIndex({
|
|
39
|
+
projectName: access.resource.title,
|
|
40
|
+
description: access.resource.description ?? undefined,
|
|
41
|
+
githubRepos: reference.githubSources,
|
|
42
|
+
});
|
|
43
|
+
const ownerEmail = getRequestUserEmail();
|
|
44
|
+
if (!ownerEmail) throw new Error("no authenticated user");
|
|
45
|
+
|
|
46
|
+
const proxy = await upsertBuilderProxyDesignSystem({
|
|
47
|
+
result,
|
|
48
|
+
ownerEmail: access.resource.ownerEmail,
|
|
49
|
+
orgId: access.resource.orgId,
|
|
50
|
+
projectName: access.resource.title,
|
|
51
|
+
description: access.resource.description ?? undefined,
|
|
52
|
+
sourceKind: reference.sourceKind,
|
|
53
|
+
githubSources: reference.githubSources,
|
|
54
|
+
localDesignSystemId: id,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...result,
|
|
59
|
+
...proxy,
|
|
60
|
+
synced: true,
|
|
61
|
+
githubSourceCount: reference.githubSources.length,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
@@ -169,7 +169,7 @@ const MAC_KEY_LABELS: Record<string, string> = {
|
|
|
169
169
|
escape: "⎋",
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
-
/** Human-readable keybinding, e.g. "⇧⌘P" on macOS or "Ctrl
|
|
172
|
+
/** Human-readable keybinding, e.g. "⇧⌘P" on macOS or "Ctrl Shift P". */
|
|
173
173
|
export function formatKeybinding(binding: string): string {
|
|
174
174
|
const parsed = parseKeybinding(binding);
|
|
175
175
|
const keyLabel =
|
|
@@ -191,7 +191,7 @@ export function formatKeybinding(binding: string): string {
|
|
|
191
191
|
if (parsed.alt) parts.push("Alt");
|
|
192
192
|
if (parsed.shift) parts.push("Shift");
|
|
193
193
|
parts.push(keyLabel.length === 1 ? keyLabel.toUpperCase() : keyLabel);
|
|
194
|
-
return parts.join("
|
|
194
|
+
return parts.join(" ");
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
/**
|
|
@@ -270,9 +270,11 @@ const DEFAULT_LABELS: DesignColorPickerLabels = {
|
|
|
270
270
|
diamond: "Diamond", // i18n-ignore fallback component label
|
|
271
271
|
};
|
|
272
272
|
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
const
|
|
273
|
+
// Keep transparency tiles light on both light and dark editor surfaces.
|
|
274
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
275
|
+
const CHECKER_A = "#e5e5e5";
|
|
276
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
277
|
+
const CHECKER_B = "#f5f5f5";
|
|
276
278
|
const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
|
|
277
279
|
|
|
278
280
|
// ─── Paint-type icon SVGs (Tabler style, distinct per type) ────────────────────
|
|
@@ -1676,6 +1678,7 @@ export function DesignColorPicker({
|
|
|
1676
1678
|
max={100}
|
|
1677
1679
|
disabled={disabled}
|
|
1678
1680
|
backgroundImage={alphaTrackBackground(fieldColor)}
|
|
1681
|
+
backgroundColor={CHECKER_B}
|
|
1679
1682
|
backgroundSize="8px 8px, 8px 8px, 8px 8px, 8px 8px, 100% 100%"
|
|
1680
1683
|
backgroundPosition="0 0, 0 4px, 4px -4px, -4px 0, 0 0"
|
|
1681
1684
|
onChange={(next) => {
|
|
@@ -2062,6 +2065,7 @@ function ColorTrack({
|
|
|
2062
2065
|
max,
|
|
2063
2066
|
disabled,
|
|
2064
2067
|
backgroundImage,
|
|
2068
|
+
backgroundColor,
|
|
2065
2069
|
backgroundSize,
|
|
2066
2070
|
backgroundPosition,
|
|
2067
2071
|
onChange,
|
|
@@ -2073,6 +2077,7 @@ function ColorTrack({
|
|
|
2073
2077
|
max: number;
|
|
2074
2078
|
disabled: boolean;
|
|
2075
2079
|
backgroundImage: string;
|
|
2080
|
+
backgroundColor?: string;
|
|
2076
2081
|
backgroundSize?: string;
|
|
2077
2082
|
backgroundPosition?: string;
|
|
2078
2083
|
onChange: (value: number) => void;
|
|
@@ -2160,7 +2165,12 @@ function ColorTrack({
|
|
|
2160
2165
|
"active:cursor-grabbing",
|
|
2161
2166
|
disabled && "cursor-not-allowed opacity-60",
|
|
2162
2167
|
)}
|
|
2163
|
-
style={{
|
|
2168
|
+
style={{
|
|
2169
|
+
backgroundImage,
|
|
2170
|
+
backgroundColor,
|
|
2171
|
+
backgroundSize,
|
|
2172
|
+
backgroundPosition,
|
|
2173
|
+
}}
|
|
2164
2174
|
>
|
|
2165
2175
|
{/* Thumb overhangs the track slightly, matching the design editor */}
|
|
2166
2176
|
<span
|
|
@@ -2552,6 +2562,7 @@ function triggerSwatchStyle(
|
|
|
2552
2562
|
if (!lower || lower === "transparent") {
|
|
2553
2563
|
return {
|
|
2554
2564
|
backgroundImage: CHECKERBOARD_IMAGE,
|
|
2565
|
+
backgroundColor: CHECKER_B,
|
|
2555
2566
|
backgroundSize: "8px 8px",
|
|
2556
2567
|
};
|
|
2557
2568
|
}
|
|
@@ -2577,6 +2588,7 @@ function swatchStyle(value: string): {
|
|
|
2577
2588
|
if (parsed && parsed.a < 1) {
|
|
2578
2589
|
return {
|
|
2579
2590
|
backgroundImage: `${CHECKERBOARD_IMAGE}, linear-gradient(${rgbaToCss(parsed)}, ${rgbaToCss(parsed)})`,
|
|
2591
|
+
backgroundColor: CHECKER_B,
|
|
2580
2592
|
backgroundSize: "8px 8px, 8px 8px, 8px 8px, 8px 8px, 100% 100%",
|
|
2581
2593
|
backgroundPosition: "0 0, 0 4px, 4px -4px, -4px 0, 0 0",
|
|
2582
2594
|
};
|
|
@@ -2590,6 +2602,7 @@ function swatchStyle(value: string): {
|
|
|
2590
2602
|
// that would otherwise render as a blank swatch.
|
|
2591
2603
|
return {
|
|
2592
2604
|
backgroundImage: CHECKERBOARD_IMAGE,
|
|
2605
|
+
backgroundColor: CHECKER_B,
|
|
2593
2606
|
backgroundSize: "8px 8px",
|
|
2594
2607
|
};
|
|
2595
2608
|
}
|
|
@@ -75,7 +75,10 @@ export interface GradientEditSessionTarget {
|
|
|
75
75
|
|
|
76
76
|
// ─── Checkerboard (matches DesignColorPicker) ───────────────────────────────────
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
79
|
+
const CHECKER_A = "#e5e5e5";
|
|
80
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
81
|
+
const CHECKER_B = "#f5f5f5";
|
|
79
82
|
const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
|
|
80
83
|
const CHECKER_SIZE = "8px 8px, 8px 8px, 8px 8px, 8px 8px";
|
|
81
84
|
const CHECKER_POS = "0 0, 0 4px, 4px -4px, -4px 0";
|
|
@@ -635,6 +638,7 @@ export function GradientEditor({
|
|
|
635
638
|
style={{
|
|
636
639
|
height: BAR_HEIGHT,
|
|
637
640
|
backgroundImage: CHECKERBOARD_IMAGE,
|
|
641
|
+
backgroundColor: CHECKER_B,
|
|
638
642
|
backgroundSize: CHECKER_SIZE,
|
|
639
643
|
backgroundPosition: CHECKER_POS,
|
|
640
644
|
}}
|
|
@@ -71,7 +71,10 @@ function readFileAsDataUrl(file: File): Promise<string> {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
75
|
+
const CHECKER_A = "#e5e5e5";
|
|
76
|
+
// guard:allow-raw-color — fixed light checkerboard tile keeps transparency visible.
|
|
77
|
+
const CHECKER_B = "#f5f5f5";
|
|
75
78
|
const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
|
|
76
79
|
const FIT_MARKER_RE =
|
|
77
80
|
/\/\*\s*agent-native-image-fit:(fill|fit|crop|tile)\s*\*\//i;
|
|
@@ -345,6 +348,7 @@ export function ImageFillControls({
|
|
|
345
348
|
backgroundImage: value.url
|
|
346
349
|
? `url("${escapeForQuotedUrl(value.url.trim())}")`
|
|
347
350
|
: CHECKERBOARD_IMAGE,
|
|
351
|
+
backgroundColor: value.url ? undefined : CHECKER_B,
|
|
348
352
|
backgroundSize: value.url
|
|
349
353
|
? value.fit === "fit"
|
|
350
354
|
? "contain"
|
|
@@ -7,6 +7,7 @@ import { type PromptComposerSubmitOptions } from "@agent-native/core/client/comp
|
|
|
7
7
|
import { useCallback } from "react";
|
|
8
8
|
|
|
9
9
|
import { sendToDesignAgentChat } from "@/lib/agent-chat";
|
|
10
|
+
import { loadDesignSystemGenerationContext } from "@/pages/design-editor/generation-prompt-directives";
|
|
10
11
|
|
|
11
12
|
export interface QuestionFlowModelSelection {
|
|
12
13
|
model?: string;
|
|
@@ -14,6 +15,23 @@ export interface QuestionFlowModelSelection {
|
|
|
14
15
|
effort?: PromptComposerSubmitOptions["effort"];
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* What the user actually supplied at kickoff. The intake turn is forced to emit
|
|
20
|
+
* only a questionnaire and then stop, so THIS continuation is the turn that
|
|
21
|
+
* writes HTML — and a fresh thread inherits nothing. Re-sending the brief here
|
|
22
|
+
* is the only thing that puts the user's own prompt, reference screenshots, and
|
|
23
|
+
* design system in front of the model at the moment it generates.
|
|
24
|
+
*/
|
|
25
|
+
export interface QuestionFlowGenerationBrief {
|
|
26
|
+
/** The user's original words, replayed verbatim — never a paraphrase. */
|
|
27
|
+
prompt?: string;
|
|
28
|
+
designSystemId?: string | null;
|
|
29
|
+
/** Data URLs; re-attached so the reference screenshot survives the hop. */
|
|
30
|
+
images?: string[];
|
|
31
|
+
/** Extracted text from uploaded files (specs, outlines, token dumps). */
|
|
32
|
+
uploadedFileContext?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
interface UseQuestionFlowOptions {
|
|
18
36
|
enabled?: boolean;
|
|
19
37
|
continuationTabId?: string | null;
|
|
@@ -25,12 +43,49 @@ interface UseQuestionFlowOptions {
|
|
|
25
43
|
* filled after render, so a snapshot taken here would be the pre-kickoff one.
|
|
26
44
|
*/
|
|
27
45
|
getModelSelection?: () => QuestionFlowModelSelection | null | undefined;
|
|
46
|
+
/** Read at send time, for the same reason as `getModelSelection`. */
|
|
47
|
+
getGenerationBrief?: () => QuestionFlowGenerationBrief | null | undefined;
|
|
28
48
|
}
|
|
29
49
|
|
|
30
50
|
function designQuestionsStateKey(designId: string | undefined): string {
|
|
31
51
|
return designId ? `show-questions:${designId}` : "show-questions";
|
|
32
52
|
}
|
|
33
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Render the kickoff brief as prompt context for the continuation turn.
|
|
56
|
+
* Exported and pure so the carry-through is testable without a DOM — this is
|
|
57
|
+
* the whole fix for "the agent ignored my design system / screenshot / brief".
|
|
58
|
+
*/
|
|
59
|
+
export function buildGenerationBriefContext(
|
|
60
|
+
brief: QuestionFlowGenerationBrief | null | undefined,
|
|
61
|
+
designSystemContext: string,
|
|
62
|
+
): string {
|
|
63
|
+
return [
|
|
64
|
+
brief?.prompt?.trim()
|
|
65
|
+
? [
|
|
66
|
+
"## The user's original request (verbatim)",
|
|
67
|
+
"This is the spec for what to build. The answers below refine it;",
|
|
68
|
+
"they do not replace it. Do not restate it as a looser paraphrase.",
|
|
69
|
+
"",
|
|
70
|
+
brief.prompt.trim(),
|
|
71
|
+
].join("\n")
|
|
72
|
+
: "",
|
|
73
|
+
brief?.images?.length
|
|
74
|
+
? [
|
|
75
|
+
`## ${brief.images.length} reference image(s) re-attached to this message`,
|
|
76
|
+
"Treat an attached UI screenshot as a layout specification to",
|
|
77
|
+
"reproduce — its structure, hierarchy, density, and component",
|
|
78
|
+
"grammar — not as loose inspiration. Match it unless an answer",
|
|
79
|
+
"below explicitly overrides a part of it.",
|
|
80
|
+
].join("\n")
|
|
81
|
+
: "",
|
|
82
|
+
brief?.uploadedFileContext?.trim() ?? "",
|
|
83
|
+
designSystemContext,
|
|
84
|
+
]
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.join("\n\n");
|
|
87
|
+
}
|
|
88
|
+
|
|
34
89
|
const RESPONSIVE_GENERATION_REQUIREMENTS =
|
|
35
90
|
'Responsive behavior is mandatory for every web design. Read the form-factor answer above: for Desktop or Both/responsive, call generate-design with `primaryViewport: "desktop"` and a 1440x1024 canvas frame; use `primaryViewport: "mobile"` only for an explicitly mobile-primary choice. Use mobile-first responsive CSS, then take desktop and mobile screenshots and fix any overflow before reporting the design complete.';
|
|
36
91
|
|
|
@@ -47,6 +102,7 @@ export function useQuestionFlow(
|
|
|
47
102
|
continuationTabId,
|
|
48
103
|
onContinue,
|
|
49
104
|
getModelSelection,
|
|
105
|
+
getGenerationBrief,
|
|
50
106
|
}: UseQuestionFlowOptions = {},
|
|
51
107
|
) {
|
|
52
108
|
const stateKey = designQuestionsStateKey(designId);
|
|
@@ -79,9 +135,21 @@ export function useQuestionFlow(
|
|
|
79
135
|
});
|
|
80
136
|
|
|
81
137
|
const sendContinuation = useCallback(
|
|
82
|
-
(message: string, context?: string) => {
|
|
138
|
+
async (message: string, context?: string) => {
|
|
83
139
|
const selection = getModelSelection?.() ?? {};
|
|
84
140
|
const { model, engine, effort } = selection;
|
|
141
|
+
const brief = getGenerationBrief?.() ?? null;
|
|
142
|
+
// Re-hydrated rather than snapshotted at kickoff: the user can link or
|
|
143
|
+
// change the design system while the questionnaire is open. This never
|
|
144
|
+
// throws — a load failure returns instruction text telling the agent to
|
|
145
|
+
// stop rather than improvise a generic style.
|
|
146
|
+
const designSystemContext = brief?.designSystemId
|
|
147
|
+
? await loadDesignSystemGenerationContext(brief.designSystemId)
|
|
148
|
+
: "";
|
|
149
|
+
const briefContext = buildGenerationBriefContext(
|
|
150
|
+
brief,
|
|
151
|
+
designSystemContext,
|
|
152
|
+
);
|
|
85
153
|
// Always request `newTab` (mirroring useAgentGenerating.submit's
|
|
86
154
|
// default). Without it, when there is no continuationTabId yet the
|
|
87
155
|
// message goes to whatever tab is currently active, but the id we
|
|
@@ -96,9 +164,10 @@ export function useQuestionFlow(
|
|
|
96
164
|
// real destination thread.
|
|
97
165
|
const tabId = sendToDesignAgentChat({
|
|
98
166
|
message,
|
|
99
|
-
context,
|
|
167
|
+
context: [briefContext, context].filter(Boolean).join("\n\n"),
|
|
100
168
|
submit: true,
|
|
101
169
|
newTab: true,
|
|
170
|
+
...(brief?.images?.length ? { images: brief.images } : {}),
|
|
102
171
|
...(continuationTabId ? { tabId: continuationTabId } : {}),
|
|
103
172
|
...(model ? { model } : {}),
|
|
104
173
|
...(engine ? { engine } : {}),
|
|
@@ -107,7 +176,14 @@ export function useQuestionFlow(
|
|
|
107
176
|
onContinue?.(tabId);
|
|
108
177
|
flow.clear();
|
|
109
178
|
},
|
|
110
|
-
[
|
|
179
|
+
[
|
|
180
|
+
continuationTabId,
|
|
181
|
+
designId,
|
|
182
|
+
flow,
|
|
183
|
+
getGenerationBrief,
|
|
184
|
+
getModelSelection,
|
|
185
|
+
onContinue,
|
|
186
|
+
],
|
|
111
187
|
);
|
|
112
188
|
|
|
113
189
|
const handleSubmit = useCallback(
|
|
@@ -129,13 +205,13 @@ export function useQuestionFlow(
|
|
|
129
205
|
.filter(Boolean)
|
|
130
206
|
.join("\n");
|
|
131
207
|
|
|
132
|
-
sendContinuation("Here are my answers — go ahead.", context);
|
|
208
|
+
void sendContinuation("Here are my answers — go ahead.", context);
|
|
133
209
|
},
|
|
134
210
|
[designId, sendContinuation],
|
|
135
211
|
);
|
|
136
212
|
|
|
137
213
|
const handleSkip = useCallback(() => {
|
|
138
|
-
sendContinuation(
|
|
214
|
+
void sendContinuation(
|
|
139
215
|
"Skip the questions — decide for me.",
|
|
140
216
|
designId
|
|
141
217
|
? `The user skipped the pre-generation questions for design ${designId}. Proceed with reasonable defaults. ${RESPONSIVE_GENERATION_REQUIREMENTS} Generate one polished first direction unless the original prompt explicitly requested options.`
|
|
@@ -25,7 +25,7 @@ const messages = {
|
|
|
25
25
|
commentMode: "Comment",
|
|
26
26
|
sendToAgent: "Send to agent",
|
|
27
27
|
sendingToAgent: "Sending to agent…",
|
|
28
|
-
enterToPost: "Enter to post · Shift
|
|
28
|
+
enterToPost: "Enter to post · Shift Enter for a new line",
|
|
29
29
|
post: "Post",
|
|
30
30
|
posting: "Posting…",
|
|
31
31
|
postFailed: "Could not post this comment",
|