@agent-native/core 0.153.9 → 0.154.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/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/DataSources.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +1 -1
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +4 -2
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -2
- 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/app/root.tsx +4 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -2
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +43 -8
- package/corpus/templates/clips/desktop/src/app.tsx +27 -13
- 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/app/i18n-data.ts +10 -10
- package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
- 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/DesignImportPanel.tsx +2 -1
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
- 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/plan/app/pages/PlansPage.tsx +5 -2
- 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/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/EditorSidebar.tsx +58 -33
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +28 -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/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/global.css +24 -0
- package/corpus/templates/slides/app/hooks/use-navigation-state.ts +5 -1
- 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/Index.tsx +25 -9
- package/corpus/templates/slides/netlify.toml +1 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
- 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/skills-content/help.d.ts +1 -1
- package/dist/cli/skills-content/help.js +2 -1
- package/dist/cli/skills.js +2 -1
- package/dist/cli/visualize-repo.js +1 -1
- package/dist/client/FeedbackButton.js +12 -12
- package/dist/client/NewWorkspaceAppFlow.js +4 -1
- package/dist/client/agent-chat-adapter.js +3 -4
- package/dist/client/agent-page/AgentTabsPage.d.ts +2 -2
- package/dist/client/agent-page/AgentTabsPage.js +12 -9
- 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/ExtensionsSidebarSection.js +2 -1
- 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/onboarding/FirstRunOnboarding.js +2 -1
- package/dist/client/org/TeamPage.js +14 -3
- package/dist/client/settings/SettingsPanel.js +26 -1
- 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/extensions/html-shell.js +5 -0
- package/dist/integrations/catalog.js +9 -8
- package/dist/observability/routes.d.ts +2 -2
- package/dist/secrets/routes.d.ts +6 -6
- 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 +31 -9
- 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/dist/server/onboarding-html.js +2 -1
- package/dist/shared/docs-url.d.ts +24 -0
- package/dist/shared/docs-url.js +39 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/templates/default/app/routes/_index.tsx +2 -1
- package/package.json +2 -2
- package/src/templates/default/app/routes/_index.tsx +2 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { appBasePath } from "@agent-native/core/client/api-path";
|
|
2
|
+
|
|
3
|
+
function imageProxyUrl(src: string): string {
|
|
4
|
+
return `${appBasePath()}/api/image-proxy?url=${encodeURIComponent(src)}`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function isRemoteHttpUrl(src: string): boolean {
|
|
8
|
+
try {
|
|
9
|
+
const url = new URL(src, window.location.href);
|
|
10
|
+
return (
|
|
11
|
+
(url.protocol === "http:" || url.protocol === "https:") &&
|
|
12
|
+
url.origin !== window.location.origin
|
|
13
|
+
);
|
|
14
|
+
} catch {
|
|
15
|
+
// coercion-ok: malformed image sources are treated as non-remote candidates.
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function imageDownloadFilename(src: string): string {
|
|
21
|
+
if (/^(?:data|blob):/i.test(src)) return "image";
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const pathname = new URL(src, window.location.href).pathname;
|
|
25
|
+
const filename = pathname.split("/").filter(Boolean).pop();
|
|
26
|
+
const decoded = filename ? decodeURIComponent(filename) : "";
|
|
27
|
+
const sanitized = decoded.replace(/[^a-z0-9._-]+/gi, "-");
|
|
28
|
+
if (sanitized) return sanitized;
|
|
29
|
+
} catch {
|
|
30
|
+
// coercion-ok: malformed image sources use the generic download filename.
|
|
31
|
+
// Use the generic name for malformed or non-URL image sources.
|
|
32
|
+
}
|
|
33
|
+
return "image";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function triggerBlobDownload(blob: Blob, filename: string): void {
|
|
37
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
38
|
+
const anchor = document.createElement("a");
|
|
39
|
+
anchor.href = objectUrl;
|
|
40
|
+
anchor.download = filename;
|
|
41
|
+
anchor.hidden = true;
|
|
42
|
+
document.body.append(anchor);
|
|
43
|
+
anchor.click();
|
|
44
|
+
anchor.remove();
|
|
45
|
+
URL.revokeObjectURL(objectUrl);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function openImageInNewTab(src: string, filename: string): void {
|
|
49
|
+
const anchor = document.createElement("a");
|
|
50
|
+
anchor.href = src;
|
|
51
|
+
anchor.download = filename;
|
|
52
|
+
anchor.target = "_blank";
|
|
53
|
+
anchor.rel = "noopener noreferrer";
|
|
54
|
+
anchor.hidden = true;
|
|
55
|
+
document.body.append(anchor);
|
|
56
|
+
anchor.click();
|
|
57
|
+
anchor.remove();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Download the selected image, proxying external sources when CORS blocks the browser. */
|
|
61
|
+
export async function downloadImage(src: string): Promise<void> {
|
|
62
|
+
const normalizedSrc = src.trim();
|
|
63
|
+
if (!normalizedSrc || typeof document === "undefined") return;
|
|
64
|
+
|
|
65
|
+
const candidates = [normalizedSrc];
|
|
66
|
+
if (isRemoteHttpUrl(normalizedSrc)) {
|
|
67
|
+
candidates.push(imageProxyUrl(normalizedSrc));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const filename = imageDownloadFilename(normalizedSrc);
|
|
71
|
+
for (const candidate of candidates) {
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(candidate, { credentials: "include" });
|
|
74
|
+
if (!response.ok) continue;
|
|
75
|
+
triggerBlobDownload(await response.blob(), filename);
|
|
76
|
+
return;
|
|
77
|
+
} catch {
|
|
78
|
+
// coercion-ok: a failed candidate is retried or falls back to opening the source.
|
|
79
|
+
// Try the authenticated image proxy before falling back to the source URL.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
openImageInNewTab(normalizedSrc, filename);
|
|
84
|
+
}
|
|
@@ -67,6 +67,12 @@ import { useWorkspaceDefaults } from "@/hooks/use-workspace-defaults";
|
|
|
67
67
|
import { createDeckAgentMessage } from "@/lib/agent-visible-message";
|
|
68
68
|
import { savePromptToComposerDraft } from "@/lib/composer-draft";
|
|
69
69
|
import { isSourceImprovementRequest } from "@/lib/create-deck-generation";
|
|
70
|
+
import {
|
|
71
|
+
readStoredDeckFilter,
|
|
72
|
+
resolveDeckFilter,
|
|
73
|
+
writeStoredDeckFilter,
|
|
74
|
+
type DeckFilter,
|
|
75
|
+
} from "@/lib/deck-filter";
|
|
70
76
|
import { sortDecksByRecency } from "@/lib/deck-sorting";
|
|
71
77
|
import {
|
|
72
78
|
IMPORT_ACTION_TIMEOUT_MS,
|
|
@@ -291,6 +297,7 @@ export default function Index() {
|
|
|
291
297
|
string | null
|
|
292
298
|
>(null);
|
|
293
299
|
const [deckSearch, setDeckSearch] = useState("");
|
|
300
|
+
const [storedDeckFilter, setStoredDeckFilter] = useState<DeckFilter>("mine");
|
|
294
301
|
// True while the picker still reflects an auto-applied default rather than
|
|
295
302
|
// an explicit user choice. `useWorkspaceDefaults()`/`useDesignSystems()`
|
|
296
303
|
// resolve asynchronously, so the initial value set on dialog open can be a
|
|
@@ -324,7 +331,8 @@ export default function Index() {
|
|
|
324
331
|
const initialDesignSystemId =
|
|
325
332
|
lastUsedDesignSystemId ?? workspaceDesignSystemId;
|
|
326
333
|
const initialReferenceDeckId = lastUsedReferenceDeckId;
|
|
327
|
-
const
|
|
334
|
+
const createdByParam = searchParams.get("createdBy");
|
|
335
|
+
const deckFilter = resolveDeckFilter(createdByParam, storedDeckFilter);
|
|
328
336
|
const normalizedDeckSearch = deckSearch.trim().toLowerCase();
|
|
329
337
|
const visibleDecks = useMemo(
|
|
330
338
|
() =>
|
|
@@ -356,6 +364,12 @@ export default function Index() {
|
|
|
356
364
|
if (result.readable) setRecentReferences(result.items);
|
|
357
365
|
}, []);
|
|
358
366
|
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
if (createdByParam !== null) return;
|
|
369
|
+
const savedFilter = readStoredDeckFilter();
|
|
370
|
+
if (savedFilter) setStoredDeckFilter(savedFilter);
|
|
371
|
+
}, [createdByParam]);
|
|
372
|
+
|
|
359
373
|
const initialPrompt = searchParams.get("initialPrompt")?.trim() ?? "";
|
|
360
374
|
const onboardingPreview = searchParams.get("onboarding") === "preview";
|
|
361
375
|
const firstRunOnboardingEnabled =
|
|
@@ -417,6 +431,8 @@ export default function Index() {
|
|
|
417
431
|
const setDeckFilter = useCallback(
|
|
418
432
|
(value: string) => {
|
|
419
433
|
const nextFilter = value === "mine" ? "mine" : "all";
|
|
434
|
+
setStoredDeckFilter(nextFilter);
|
|
435
|
+
writeStoredDeckFilter(nextFilter);
|
|
420
436
|
setSearchParams(
|
|
421
437
|
(prev) => {
|
|
422
438
|
const next = new URLSearchParams(prev);
|
|
@@ -1377,14 +1393,6 @@ export default function Index() {
|
|
|
1377
1393
|
className="w-fit rounded-lg border border-border bg-card p-0.5"
|
|
1378
1394
|
size="sm"
|
|
1379
1395
|
>
|
|
1380
|
-
<ToggleGroupItem
|
|
1381
|
-
value="all"
|
|
1382
|
-
aria-label={t("home.showAllDecks")}
|
|
1383
|
-
className="h-7 rounded-md px-3 text-xs data-[state=on]:bg-accent"
|
|
1384
|
-
>
|
|
1385
|
-
<IconStack2 className="me-1.5 h-3.5 w-3.5" />
|
|
1386
|
-
{t("home.all")}
|
|
1387
|
-
</ToggleGroupItem>
|
|
1388
1396
|
<ToggleGroupItem
|
|
1389
1397
|
value="mine"
|
|
1390
1398
|
aria-label={t("home.showMineDecks")}
|
|
@@ -1393,6 +1401,14 @@ export default function Index() {
|
|
|
1393
1401
|
<IconUserCircle className="me-1.5 h-3.5 w-3.5" />
|
|
1394
1402
|
{t("home.mine")}
|
|
1395
1403
|
</ToggleGroupItem>
|
|
1404
|
+
<ToggleGroupItem
|
|
1405
|
+
value="all"
|
|
1406
|
+
aria-label={t("home.showAllDecks")}
|
|
1407
|
+
className="h-7 rounded-md px-3 text-xs data-[state=on]:bg-accent"
|
|
1408
|
+
>
|
|
1409
|
+
<IconStack2 className="me-1.5 h-3.5 w-3.5" />
|
|
1410
|
+
{t("home.all")}
|
|
1411
|
+
</ToggleGroupItem>
|
|
1396
1412
|
</ToggleGroup>
|
|
1397
1413
|
<label className="flex h-8 w-full items-center gap-2 rounded-lg border border-border bg-card px-2.5 text-muted-foreground sm:w-60">
|
|
1398
1414
|
<IconSearch className="size-3.5 shrink-0" aria-hidden="true" />
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
createBuilderDesignSystemProxyFields,
|
|
3
3
|
localBuilderDesignSystemId,
|
|
4
4
|
type BuilderDesignSystemIndexResult,
|
|
5
|
+
type BuilderDesignSystemGitHubSource,
|
|
5
6
|
type BuilderDesignSystemSourceKind,
|
|
6
7
|
} from "@agent-native/core/server";
|
|
7
8
|
import { and, eq, isNull } from "drizzle-orm";
|
|
@@ -16,6 +17,8 @@ export async function upsertBuilderProxyDesignSystem({
|
|
|
16
17
|
projectName,
|
|
17
18
|
description,
|
|
18
19
|
sourceKind,
|
|
20
|
+
githubSources,
|
|
21
|
+
localDesignSystemId: requestedLocalDesignSystemId,
|
|
19
22
|
}: {
|
|
20
23
|
result: BuilderDesignSystemIndexResult;
|
|
21
24
|
ownerEmail: string;
|
|
@@ -23,6 +26,8 @@ export async function upsertBuilderProxyDesignSystem({
|
|
|
23
26
|
projectName?: string;
|
|
24
27
|
description?: string;
|
|
25
28
|
sourceKind?: BuilderDesignSystemSourceKind;
|
|
29
|
+
githubSources?: BuilderDesignSystemGitHubSource[];
|
|
30
|
+
localDesignSystemId?: string;
|
|
26
31
|
}) {
|
|
27
32
|
const db = getDb();
|
|
28
33
|
const now = new Date().toISOString();
|
|
@@ -35,6 +40,8 @@ export async function upsertBuilderProxyDesignSystem({
|
|
|
35
40
|
description,
|
|
36
41
|
surface: "slides",
|
|
37
42
|
sourceKind,
|
|
43
|
+
githubSources,
|
|
44
|
+
syncedAt: githubSources?.length ? now : undefined,
|
|
38
45
|
});
|
|
39
46
|
const [existing] = await db
|
|
40
47
|
.select({
|
|
@@ -43,7 +50,12 @@ export async function upsertBuilderProxyDesignSystem({
|
|
|
43
50
|
orgId: schema.designSystems.orgId,
|
|
44
51
|
})
|
|
45
52
|
.from(schema.designSystems)
|
|
46
|
-
.where(
|
|
53
|
+
.where(
|
|
54
|
+
eq(
|
|
55
|
+
schema.designSystems.id,
|
|
56
|
+
requestedLocalDesignSystemId ?? baseLocalDesignSystemId,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
47
59
|
.limit(1);
|
|
48
60
|
const existingBelongsToScope =
|
|
49
61
|
existing?.ownerEmail === ownerEmail &&
|
|
@@ -51,7 +63,7 @@ export async function upsertBuilderProxyDesignSystem({
|
|
|
51
63
|
const localDesignSystemId =
|
|
52
64
|
existing && !existingBelongsToScope
|
|
53
65
|
? `${baseLocalDesignSystemId}-${nanoid(8)}`
|
|
54
|
-
: baseLocalDesignSystemId;
|
|
66
|
+
: (requestedLocalDesignSystemId ?? baseLocalDesignSystemId);
|
|
55
67
|
if (existingBelongsToScope) {
|
|
56
68
|
await db
|
|
57
69
|
.update(schema.designSystems)
|
|
@@ -6499,7 +6499,7 @@ export function createProductionAgentHandler(options) {
|
|
|
6499
6499
|
const capturedAt = typeof sel.capturedAt === "number" ? sel.capturedAt : 0;
|
|
6500
6500
|
if (Date.now() - capturedAt > SELECTION_TTL_MS)
|
|
6501
6501
|
return "";
|
|
6502
|
-
return (`\n\nThe user has selected the following text and pressed Cmd
|
|
6502
|
+
return (`\n\nThe user has selected the following text and pressed Cmd I to focus the agent. ` +
|
|
6503
6503
|
`Treat this as the immediate context to act on:\n` +
|
|
6504
6504
|
`<selection>\n${capSelectionContext(sel.text)}\n</selection>`);
|
|
6505
6505
|
}
|
|
@@ -23,8 +23,16 @@ export interface BrandKitColors {
|
|
|
23
23
|
text: string;
|
|
24
24
|
textMuted: string;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Semantic category a {@link BrandKitToken} belongs to.
|
|
28
|
+
*
|
|
29
|
+
* `motion` covers durations, easings, and transitions — the DTCG `duration`,
|
|
30
|
+
* `cubicBezier`, and `transition` types. It exists because a design system's
|
|
31
|
+
* motion is part of its identity, and a category-less token is a dropped one:
|
|
32
|
+
* extractors discard what they cannot classify, so "no bucket" silently became
|
|
33
|
+
* "no motion in any imported system".
|
|
34
|
+
*/
|
|
35
|
+
export type BrandKitTokenType = "color" | "typography" | "spacing" | "radius" | "shadow" | "motion" | "other";
|
|
28
36
|
/**
|
|
29
37
|
* One token under the name its source design system uses. The seven
|
|
30
38
|
* {@link BrandKitColors} roles are a summary view, not a substitute: collapsing
|
package/dist/cli/code.js
CHANGED
|
@@ -946,7 +946,7 @@ async function attachCodeAgentRun(runs, args, output) {
|
|
|
946
946
|
const printed = new Set();
|
|
947
947
|
writeLine(output, "");
|
|
948
948
|
writeLine(output, `Attaching to Agent-Native Code run ${run.id}`);
|
|
949
|
-
writeLine(output, "Press Ctrl
|
|
949
|
+
writeLine(output, "Press Ctrl C to detach. The session keeps its transcript.");
|
|
950
950
|
writeLine(output, "");
|
|
951
951
|
const printNewEvents = () => {
|
|
952
952
|
const events = listCodeAgentTranscriptEvents(run.id);
|
package/dist/cli/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
import * as Sentry from "@sentry/node";
|
|
8
8
|
import { clearAgentNativeNitroPresetMarker, resolveAgentNativeNitroPreset, } from "../deploy/nitro-preset.js";
|
|
9
9
|
import { resolveDeployPostBuildInvocation } from "./deploy-build.js";
|
|
10
|
+
import { assertNativeDependencies, assertNodeRuntimeMarker, ensureNativeDependencies, writeNodeRuntimeMarker, } from "./native-dependencies.js";
|
|
10
11
|
import { cliSpawnOptions } from "./process.js";
|
|
11
12
|
import { shouldTrackCliRun } from "./telemetry-routing.js";
|
|
12
13
|
import { createCliTelemetry } from "./telemetry.js";
|
|
@@ -527,6 +528,13 @@ if (shouldTrackCliRun(command, args))
|
|
|
527
528
|
trackCli("cli.run");
|
|
528
529
|
switch (command) {
|
|
529
530
|
case "dev": {
|
|
531
|
+
try {
|
|
532
|
+
ensureNativeDependencies({ repair: true, label: "dev" });
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
536
|
+
process.exit(1);
|
|
537
|
+
}
|
|
530
538
|
if (isWorkspaceRoot()) {
|
|
531
539
|
import("./workspace-dev.js")
|
|
532
540
|
.then((m) => m.runWorkspaceDev({ args }))
|
|
@@ -586,6 +594,7 @@ switch (command) {
|
|
|
586
594
|
// child exits non-zero, runBuildStep calls process.exit itself; the
|
|
587
595
|
// continuation only runs on success.
|
|
588
596
|
(async () => {
|
|
597
|
+
ensureNativeDependencies({ repair: true, label: "build" });
|
|
589
598
|
// Doctor pre-step: scans app source for the security-critical guard
|
|
590
599
|
// invariants (see `agent-native doctor --help`). Findings fail by
|
|
591
600
|
// default; only an explicit `doctor.failOnBuild: false` opt-out keeps
|
|
@@ -640,6 +649,14 @@ switch (command) {
|
|
|
640
649
|
console.warn("[build] Deploy build script not found and no deploy preset is configured. Skipping post-build step.");
|
|
641
650
|
}
|
|
642
651
|
}
|
|
652
|
+
const serverDirectory = path.resolve(".output/server");
|
|
653
|
+
if (fs.existsSync(serverDirectory)) {
|
|
654
|
+
assertNativeDependencies({
|
|
655
|
+
fromDirectory: serverDirectory,
|
|
656
|
+
label: "build output",
|
|
657
|
+
});
|
|
658
|
+
writeNodeRuntimeMarker(serverDirectory);
|
|
659
|
+
}
|
|
643
660
|
console.log("\nBuild complete.");
|
|
644
661
|
})().catch((err) => {
|
|
645
662
|
// runBuildStep handles its own failures and exits, so reaching here
|
|
@@ -662,7 +679,19 @@ switch (command) {
|
|
|
662
679
|
console.error('No production build found. Run "agent-native build" first.');
|
|
663
680
|
process.exit(1);
|
|
664
681
|
}
|
|
665
|
-
|
|
682
|
+
const serverDirectory = path.dirname(serverEntry);
|
|
683
|
+
try {
|
|
684
|
+
assertNodeRuntimeMarker(serverDirectory);
|
|
685
|
+
assertNativeDependencies({
|
|
686
|
+
fromDirectory: serverDirectory,
|
|
687
|
+
label: "start output",
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
692
|
+
process.exit(1);
|
|
693
|
+
}
|
|
694
|
+
run(process.execPath, [serverEntry, ...args]);
|
|
666
695
|
break;
|
|
667
696
|
}
|
|
668
697
|
case "action": {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type NativeDependencyCheck = {
|
|
2
|
+
status: "absent";
|
|
3
|
+
packageName: string;
|
|
4
|
+
} | {
|
|
5
|
+
status: "healthy";
|
|
6
|
+
packageName: string;
|
|
7
|
+
packageDir: string;
|
|
8
|
+
} | {
|
|
9
|
+
status: "broken";
|
|
10
|
+
packageName: string;
|
|
11
|
+
packageDir: string;
|
|
12
|
+
error: unknown;
|
|
13
|
+
};
|
|
14
|
+
export interface NativeDependencyOptions {
|
|
15
|
+
fromDirectory?: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
repair?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function checkNativeDependencies(fromDirectory?: string): NativeDependencyCheck;
|
|
20
|
+
export declare function ensureNativeDependencies(options?: NativeDependencyOptions): NativeDependencyCheck;
|
|
21
|
+
export declare function assertNativeDependencies(options?: Omit<NativeDependencyOptions, "repair">): NativeDependencyCheck;
|
|
22
|
+
export declare function writeNodeRuntimeMarker(serverDirectory: string): string | null;
|
|
23
|
+
export declare function assertNodeRuntimeMarker(serverDirectory: string): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const BETTER_SQLITE3 = "better-sqlite3";
|
|
7
|
+
const REBUILD_LOCK = ".agent-native-better-sqlite3-rebuild.lock";
|
|
8
|
+
const RUNTIME_MARKER = ".agent-native-node-runtime.json";
|
|
9
|
+
const LOCK_INITIALIZATION_TIMEOUT_MS = 5_000;
|
|
10
|
+
const REBUILD_WAIT_MS = 250;
|
|
11
|
+
const REBUILD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
12
|
+
function corePackageDirectory() {
|
|
13
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
14
|
+
}
|
|
15
|
+
function packageRootFromManifest(packageName, manifestPath) {
|
|
16
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
17
|
+
return manifest.name === packageName ? path.dirname(manifestPath) : null;
|
|
18
|
+
}
|
|
19
|
+
function resolvePackageDirectory(packageName, fromDirectory) {
|
|
20
|
+
const requireFromDirectory = createRequire(path.join(path.resolve(fromDirectory), "package.json"));
|
|
21
|
+
try {
|
|
22
|
+
const manifestPath = requireFromDirectory.resolve(`${packageName}/package.json`);
|
|
23
|
+
return packageRootFromManifest(packageName, manifestPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
try {
|
|
27
|
+
const entryPath = requireFromDirectory.resolve(packageName);
|
|
28
|
+
let current = path.dirname(entryPath);
|
|
29
|
+
while (true) {
|
|
30
|
+
const manifestPath = path.join(current, "package.json");
|
|
31
|
+
if (fs.existsSync(manifestPath)) {
|
|
32
|
+
const packageDir = packageRootFromManifest(packageName, manifestPath);
|
|
33
|
+
if (packageDir)
|
|
34
|
+
return packageDir;
|
|
35
|
+
}
|
|
36
|
+
const parent = path.dirname(current);
|
|
37
|
+
if (parent === current)
|
|
38
|
+
return null;
|
|
39
|
+
current = parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function probeBetterSqlite3(packageDir) {
|
|
48
|
+
try {
|
|
49
|
+
const requireFromPackage = createRequire(path.join(packageDir, "package.json"));
|
|
50
|
+
const Database = requireFromPackage(BETTER_SQLITE3);
|
|
51
|
+
const database = new Database(":memory:");
|
|
52
|
+
database.prepare("select 1 as ok").get();
|
|
53
|
+
database.close();
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function checkNativeDependencies(fromDirectory = corePackageDirectory()) {
|
|
61
|
+
const packageDir = resolvePackageDirectory(BETTER_SQLITE3, fromDirectory);
|
|
62
|
+
if (!packageDir) {
|
|
63
|
+
return { status: "absent", packageName: BETTER_SQLITE3 };
|
|
64
|
+
}
|
|
65
|
+
const error = probeBetterSqlite3(packageDir);
|
|
66
|
+
return error === null
|
|
67
|
+
? { status: "healthy", packageName: BETTER_SQLITE3, packageDir }
|
|
68
|
+
: { status: "broken", packageName: BETTER_SQLITE3, packageDir, error };
|
|
69
|
+
}
|
|
70
|
+
function errorMessage(error) {
|
|
71
|
+
return error instanceof Error ? error.message : String(error);
|
|
72
|
+
}
|
|
73
|
+
function npmExecutable() {
|
|
74
|
+
const sibling = path.join(path.dirname(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
75
|
+
return fs.existsSync(sibling) ? sibling : "npm";
|
|
76
|
+
}
|
|
77
|
+
function sleepSync(milliseconds) {
|
|
78
|
+
const signal = new Int32Array(new SharedArrayBuffer(4));
|
|
79
|
+
Atomics.wait(signal, 0, 0, milliseconds);
|
|
80
|
+
}
|
|
81
|
+
function processIsRunning(pid) {
|
|
82
|
+
try {
|
|
83
|
+
process.kill(pid, 0);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return error instanceof Error && "code" in error && error.code !== "ESRCH";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function acquireRebuildLock(packageDir, label) {
|
|
91
|
+
const lockPath = path.join(packageDir, REBUILD_LOCK);
|
|
92
|
+
const startedWaiting = Date.now();
|
|
93
|
+
while (true) {
|
|
94
|
+
try {
|
|
95
|
+
const lockFd = fs.openSync(lockPath, "wx");
|
|
96
|
+
fs.writeSync(lockFd, JSON.stringify({
|
|
97
|
+
pid: process.pid,
|
|
98
|
+
startedAt: new Date().toISOString(),
|
|
99
|
+
}));
|
|
100
|
+
return () => {
|
|
101
|
+
try {
|
|
102
|
+
fs.closeSync(lockFd);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
try {
|
|
106
|
+
fs.unlinkSync(lockPath);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (!(error instanceof Error &&
|
|
110
|
+
"code" in error &&
|
|
111
|
+
error.code === "ENOENT")) {
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) {
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
let ownerPid = null;
|
|
123
|
+
let lockAge = 0;
|
|
124
|
+
try {
|
|
125
|
+
const lock = JSON.parse(fs.readFileSync(lockPath, "utf8"));
|
|
126
|
+
ownerPid = typeof lock.pid === "number" ? lock.pid : null;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// The owner may be between creating and writing the lock metadata.
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
lockAge = Date.now() - fs.statSync(lockPath).mtimeMs;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if ((ownerPid !== null && !processIsRunning(ownerPid)) ||
|
|
138
|
+
(ownerPid === null && lockAge > LOCK_INITIALIZATION_TIMEOUT_MS)) {
|
|
139
|
+
try {
|
|
140
|
+
fs.unlinkSync(lockPath);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
catch (unlinkError) {
|
|
144
|
+
if (!(unlinkError instanceof Error &&
|
|
145
|
+
"code" in unlinkError &&
|
|
146
|
+
unlinkError.code === "ENOENT")) {
|
|
147
|
+
throw unlinkError;
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (Date.now() - startedWaiting > REBUILD_TIMEOUT_MS) {
|
|
153
|
+
throw new Error(`[${label}] Timed out waiting for another process to finish rebuilding ${BETTER_SQLITE3}.`);
|
|
154
|
+
}
|
|
155
|
+
sleepSync(REBUILD_WAIT_MS);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function rebuildNativeDependency(packageDir) {
|
|
160
|
+
execFileSync(npmExecutable(), ["run", "build-release", "--prefix", packageDir], {
|
|
161
|
+
cwd: packageDir,
|
|
162
|
+
stdio: "inherit",
|
|
163
|
+
shell: process.platform === "win32",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function brokenDependencyMessage(check, label) {
|
|
167
|
+
return [
|
|
168
|
+
`[${label}] ${check.packageName} cannot load its native binding.`,
|
|
169
|
+
`Package: ${check.packageDir}`,
|
|
170
|
+
`Node: ${process.version} (ABI ${process.versions.modules}, ${process.platform}-${process.arch})`,
|
|
171
|
+
`Original error: ${errorMessage(check.error)}`,
|
|
172
|
+
"The installed native binary was built for a different Node runtime or is otherwise stale.",
|
|
173
|
+
].join("\n");
|
|
174
|
+
}
|
|
175
|
+
export function ensureNativeDependencies(options = {}) {
|
|
176
|
+
const label = options.label ?? "native preflight";
|
|
177
|
+
const check = checkNativeDependencies(options.fromDirectory);
|
|
178
|
+
if (check.status !== "broken")
|
|
179
|
+
return check;
|
|
180
|
+
if (!options.repair) {
|
|
181
|
+
throw new Error(brokenDependencyMessage(check, label));
|
|
182
|
+
}
|
|
183
|
+
console.warn(`${brokenDependencyMessage(check, label)}\n[${label}] Rebuilding it with the current Node runtime...`);
|
|
184
|
+
const releaseLock = acquireRebuildLock(check.packageDir, label);
|
|
185
|
+
try {
|
|
186
|
+
const current = checkNativeDependencies(options.fromDirectory);
|
|
187
|
+
if (current.status === "healthy")
|
|
188
|
+
return current;
|
|
189
|
+
if (current.status !== "broken") {
|
|
190
|
+
throw new Error(`[${label}] ${BETTER_SQLITE3} disappeared before its native rebuild.`);
|
|
191
|
+
}
|
|
192
|
+
rebuildNativeDependency(current.packageDir);
|
|
193
|
+
const repaired = checkNativeDependencies(options.fromDirectory);
|
|
194
|
+
if (repaired.status === "healthy") {
|
|
195
|
+
console.log(`[${label}] ${repaired.packageName} is ready for Node ABI ${process.versions.modules}.`);
|
|
196
|
+
return repaired;
|
|
197
|
+
}
|
|
198
|
+
if (repaired.status === "broken") {
|
|
199
|
+
throw new Error(brokenDependencyMessage(repaired, label));
|
|
200
|
+
}
|
|
201
|
+
throw new Error(`[${label}] ${BETTER_SQLITE3} disappeared after its native rebuild.`);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
releaseLock();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
export function assertNativeDependencies(options = {}) {
|
|
208
|
+
const check = checkNativeDependencies(options.fromDirectory);
|
|
209
|
+
if (check.status === "broken") {
|
|
210
|
+
throw new Error(brokenDependencyMessage(check, options.label ?? "runtime"));
|
|
211
|
+
}
|
|
212
|
+
return check;
|
|
213
|
+
}
|
|
214
|
+
export function writeNodeRuntimeMarker(serverDirectory) {
|
|
215
|
+
if (!fs.existsSync(serverDirectory))
|
|
216
|
+
return null;
|
|
217
|
+
const markerPath = path.join(serverDirectory, RUNTIME_MARKER);
|
|
218
|
+
const marker = {
|
|
219
|
+
nodeVersion: process.version,
|
|
220
|
+
nodeAbi: process.versions.modules,
|
|
221
|
+
platform: process.platform,
|
|
222
|
+
arch: process.arch,
|
|
223
|
+
};
|
|
224
|
+
fs.writeFileSync(markerPath, `${JSON.stringify(marker)}\n`);
|
|
225
|
+
return markerPath;
|
|
226
|
+
}
|
|
227
|
+
export function assertNodeRuntimeMarker(serverDirectory) {
|
|
228
|
+
const markerPath = path.join(serverDirectory, RUNTIME_MARKER);
|
|
229
|
+
if (!fs.existsSync(markerPath))
|
|
230
|
+
return;
|
|
231
|
+
let marker;
|
|
232
|
+
try {
|
|
233
|
+
marker = JSON.parse(fs.readFileSync(markerPath, "utf8"));
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
throw new Error(`[runtime] Could not read ${RUNTIME_MARKER}: ${errorMessage(error)}`);
|
|
237
|
+
}
|
|
238
|
+
const mismatches = [
|
|
239
|
+
marker.nodeAbi !== process.versions.modules
|
|
240
|
+
? `Node ABI ${marker.nodeAbi} (build) vs ${process.versions.modules} (runtime)`
|
|
241
|
+
: null,
|
|
242
|
+
marker.platform !== process.platform
|
|
243
|
+
? `platform ${marker.platform} (build) vs ${process.platform} (runtime)`
|
|
244
|
+
: null,
|
|
245
|
+
marker.arch !== process.arch
|
|
246
|
+
? `architecture ${marker.arch} (build) vs ${process.arch} (runtime)`
|
|
247
|
+
: null,
|
|
248
|
+
].filter((value) => value !== null);
|
|
249
|
+
if (mismatches.length > 0) {
|
|
250
|
+
throw new Error([
|
|
251
|
+
`[runtime] Production output was built for a different Node runtime: ${mismatches.join(", ")}.`,
|
|
252
|
+
`Build Node: ${marker.nodeVersion}; runtime Node: ${process.version}.`,
|
|
253
|
+
"Run the build and start commands with the same Node installation.",
|
|
254
|
+
].join("\n"));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function isDirectExecution() {
|
|
258
|
+
const entryPoint = process.argv[1];
|
|
259
|
+
return (entryPoint !== undefined &&
|
|
260
|
+
path.resolve(entryPoint) === path.resolve(fileURLToPath(import.meta.url)));
|
|
261
|
+
}
|
|
262
|
+
if (isDirectExecution() && process.argv.includes("--repair")) {
|
|
263
|
+
ensureNativeDependencies({ repair: true, label: "native repair" });
|
|
264
|
+
}
|
package/dist/cli/plan-local.js
CHANGED
|
@@ -2169,7 +2169,7 @@ async function runServe(args) {
|
|
|
2169
2169
|
bridgeUrl: bridge.result.bridgeUrl,
|
|
2170
2170
|
}),
|
|
2171
2171
|
"Keep this bridge command running while the Plan page is open; stopping it makes this URL unreachable.",
|
|
2172
|
-
"Press Ctrl
|
|
2172
|
+
"Press Ctrl C to stop.",
|
|
2173
2173
|
]
|
|
2174
2174
|
.filter(Boolean)
|
|
2175
2175
|
.join("\n") + "\n");
|