@agent-native/core 0.153.10 → 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/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/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/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/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/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/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- 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/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 +3 -3
|
@@ -125,6 +125,15 @@ export { loadResourcesForPrompt };
|
|
|
125
125
|
export { _agentChatPromptSectionsForTests };
|
|
126
126
|
export { buildPublicAgentA2ASkills };
|
|
127
127
|
export { assembleA2AFinalResponse };
|
|
128
|
+
export function buildLeanSystemPrompt(input) {
|
|
129
|
+
return (input.basePrompt +
|
|
130
|
+
(input.additionalFramework ?? "") +
|
|
131
|
+
(input.cacheSplit ?? "") +
|
|
132
|
+
input.resources +
|
|
133
|
+
(input.extra ?? "") +
|
|
134
|
+
(input.modelOverlay ?? "") +
|
|
135
|
+
(input.runtimeContext ?? ""));
|
|
136
|
+
}
|
|
128
137
|
export { runA2AAgentLoop };
|
|
129
138
|
export { runMCPAgentLoop };
|
|
130
139
|
export { createA2AEngineToolSurface };
|
|
@@ -2601,20 +2610,25 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2601
2610
|
// so everything after it can change without a cache write.
|
|
2602
2611
|
if (leanPrompt) {
|
|
2603
2612
|
const leanRunPolicyPrompt = buildLeanRunPolicyPrompt(codeEditingSurfaceRestriction, prodCodeExecPromptNote);
|
|
2613
|
+
const resources = await loadResourcesForPrompt(owner, true, options?.appId, undefined, { disabledFrameworkGroups });
|
|
2604
2614
|
await emitContextXraySystemSections(event, {
|
|
2605
2615
|
frameworkPrompt: leanBasePrompt.slice(0, Math.max(0, leanBasePrompt.length - leanActionsPrompt.length)),
|
|
2606
2616
|
actionsPrompt: leanActionsPrompt,
|
|
2607
2617
|
additionalFramework: leanRunPolicyPrompt,
|
|
2618
|
+
resources,
|
|
2608
2619
|
extra,
|
|
2609
2620
|
modelOverlay,
|
|
2610
2621
|
runtimeContext,
|
|
2611
2622
|
});
|
|
2612
|
-
return setSystemPromptOnContext(
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2623
|
+
return setSystemPromptOnContext(buildLeanSystemPrompt({
|
|
2624
|
+
basePrompt: leanBasePrompt,
|
|
2625
|
+
additionalFramework: leanRunPolicyPrompt,
|
|
2626
|
+
cacheSplit: SYSTEM_PROMPT_CACHE_SPLIT,
|
|
2627
|
+
resources,
|
|
2628
|
+
extra,
|
|
2629
|
+
modelOverlay,
|
|
2630
|
+
runtimeContext,
|
|
2631
|
+
}));
|
|
2618
2632
|
}
|
|
2619
2633
|
const resources = await loadResourcesForPrompt(owner, lazyContext, options?.appId, undefined, { disabledFrameworkGroups });
|
|
2620
2634
|
// In lazy context mode, skip embedding the full schema. When database
|
|
@@ -2840,14 +2854,22 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2840
2854
|
// cached prompt prefix as possible. See the prod handler above
|
|
2841
2855
|
// for the same pattern.
|
|
2842
2856
|
if (leanPrompt) {
|
|
2857
|
+
const resources = await loadResourcesForPrompt(owner, true, options?.appId, undefined, { disabledFrameworkGroups });
|
|
2843
2858
|
await emitContextXraySystemSections(event, {
|
|
2844
2859
|
frameworkPrompt: leanBasePrompt.slice(0, Math.max(0, leanBasePrompt.length - leanActionsPrompt.length)),
|
|
2845
2860
|
actionsPrompt: leanActionsPrompt,
|
|
2861
|
+
resources,
|
|
2846
2862
|
extra,
|
|
2847
2863
|
modelOverlay,
|
|
2848
2864
|
runtimeContext,
|
|
2849
2865
|
});
|
|
2850
|
-
return setSystemPromptOnContext(
|
|
2866
|
+
return setSystemPromptOnContext(buildLeanSystemPrompt({
|
|
2867
|
+
basePrompt: leanBasePrompt,
|
|
2868
|
+
resources,
|
|
2869
|
+
extra,
|
|
2870
|
+
modelOverlay,
|
|
2871
|
+
runtimeContext,
|
|
2872
|
+
}));
|
|
2851
2873
|
}
|
|
2852
2874
|
const resources = await loadResourcesForPrompt(owner, lazyContext, options?.appId, undefined, { disabledFrameworkGroups });
|
|
2853
2875
|
const schemaBlock = lazyContext || !databaseToolsEnabled
|
|
@@ -39,6 +39,8 @@ export interface BuilderDesignSystemProxyFieldsOptions {
|
|
|
39
39
|
description?: string;
|
|
40
40
|
surface: "design" | "slides";
|
|
41
41
|
sourceKind?: BuilderDesignSystemSourceKind;
|
|
42
|
+
githubSources?: BuilderDesignSystemGitHubSource[];
|
|
43
|
+
syncedAt?: string;
|
|
42
44
|
}
|
|
43
45
|
export type BuilderDesignSystemSourceKind = "figma" | "code" | "github" | "mixed";
|
|
44
46
|
export interface BuilderDesignSystemProxyFields {
|
|
@@ -55,6 +57,8 @@ export interface BuilderDesignSystemProxyReference {
|
|
|
55
57
|
builderProjectId?: string;
|
|
56
58
|
builderUrl?: string;
|
|
57
59
|
builderStatus?: string;
|
|
60
|
+
githubSources?: BuilderDesignSystemGitHubSource[];
|
|
61
|
+
syncedAt?: string;
|
|
58
62
|
}
|
|
59
63
|
export interface BuilderDesignSystemDocsOptions {
|
|
60
64
|
page?: number;
|
|
@@ -82,11 +86,20 @@ export interface BuilderDesignSystemIndexOptions {
|
|
|
82
86
|
projectName?: string;
|
|
83
87
|
description?: string;
|
|
84
88
|
githubRepoUrl?: string;
|
|
89
|
+
githubRepos?: BuilderDesignSystemGitHubSource[];
|
|
85
90
|
connectedProjectId?: string;
|
|
86
91
|
files?: BuilderDesignSystemIndexFile[];
|
|
87
92
|
selection?: Record<string, string[]>;
|
|
88
93
|
devToolsVersion?: string;
|
|
89
94
|
}
|
|
95
|
+
/** A durable, replayable GitHub source configuration for a Builder DSI kit. */
|
|
96
|
+
export interface BuilderDesignSystemGitHubSource {
|
|
97
|
+
repoUrl: string;
|
|
98
|
+
ref?: string;
|
|
99
|
+
include?: string[];
|
|
100
|
+
exclude?: string[];
|
|
101
|
+
instructions?: string;
|
|
102
|
+
}
|
|
90
103
|
export interface BuilderDesignSystemIndexResult {
|
|
91
104
|
ok: true;
|
|
92
105
|
source: "builder";
|
|
@@ -124,6 +137,25 @@ export interface BuilderDesignSystemDecodeJobStatus {
|
|
|
124
137
|
createdAt: number;
|
|
125
138
|
updatedAt: number;
|
|
126
139
|
}
|
|
140
|
+
export interface BuilderDesignSystemGitHubFile {
|
|
141
|
+
path: string;
|
|
142
|
+
content: string;
|
|
143
|
+
}
|
|
144
|
+
export interface BuilderDesignSystemGitHubFileCollection {
|
|
145
|
+
source: BuilderDesignSystemGitHubSource;
|
|
146
|
+
owner: string;
|
|
147
|
+
repo: string;
|
|
148
|
+
ref?: string;
|
|
149
|
+
files: BuilderDesignSystemGitHubFile[];
|
|
150
|
+
totalBytes: number;
|
|
151
|
+
truncated: boolean;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolve an explicitly scoped/ref'd GitHub source into bounded file uploads.
|
|
155
|
+
* Native Builder public-repo sources are preferred for unscoped public repos;
|
|
156
|
+
* this path exists so branch, folder, and private-repo imports are replayable.
|
|
157
|
+
*/
|
|
158
|
+
export declare function collectBuilderDesignSystemGitHubFiles(input: BuilderDesignSystemGitHubSource): Promise<BuilderDesignSystemGitHubFileCollection>;
|
|
127
159
|
export declare function fetchBuilderDesignSystemDecodeJobStatus(jobId: string): Promise<BuilderDesignSystemDecodeJobStatus>;
|
|
128
160
|
export declare function getBuilderDesignSystemsBaseUrl(): string;
|
|
129
161
|
export declare function mimeTypeForBuilderDesignSystemFilename(filename: string, explicit?: string): string;
|
|
@@ -131,7 +163,7 @@ export declare function buildBuilderDesignSystemIndexFiles({ codeFiles, designMd
|
|
|
131
163
|
export declare function builderDesignSystemUrl(designSystemId?: string | null): string;
|
|
132
164
|
export declare function builderProjectBranchUrl(projectId?: string | null, branchName?: string | null): string | undefined;
|
|
133
165
|
export declare function localBuilderDesignSystemId(builderDesignSystemId: string): string;
|
|
134
|
-
export declare function createBuilderDesignSystemProxyFields({ result, projectName, description, surface, sourceKind, }: BuilderDesignSystemProxyFieldsOptions): BuilderDesignSystemProxyFields;
|
|
166
|
+
export declare function createBuilderDesignSystemProxyFields({ result, projectName, description, surface, sourceKind, githubSources, syncedAt, }: BuilderDesignSystemProxyFieldsOptions): BuilderDesignSystemProxyFields;
|
|
135
167
|
export declare function parseBuilderDesignSystemProxyReference(data: unknown): BuilderDesignSystemProxyReference | null;
|
|
136
168
|
export declare function fetchBuilderDesignSystemDocs(designSystemId: string, options?: BuilderDesignSystemDocsOptions): Promise<BuilderDesignSystemDocument[]>;
|
|
137
169
|
export declare function hydrateBuilderDesignSystemReference(reference: BuilderDesignSystemProxyReference, options?: BuilderDesignSystemDocsOptions): Promise<BuilderDesignSystemHydratedReference>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
2
2
|
import { FeatureNotConfiguredError } from "./credential-provider.js";
|
|
3
|
-
import { getBuilderProxyOrigin, resolveBuilderCredentials, } from "./credential-provider.js";
|
|
3
|
+
import { getBuilderProxyOrigin, resolveSecret, resolveBuilderCredentials, } from "./credential-provider.js";
|
|
4
|
+
import { canonicalGitHubRepoUrl, fetchGitHubJsonResult, fetchGitHubRaw, parseGitHubRepoReference, } from "./design-token-utils.js";
|
|
4
5
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
5
6
|
// GCS resumable uploads require every chunk except the last to be a multiple
|
|
6
7
|
// of 256 KiB. 16 MiB is the recommended default and keeps very large `.fig`
|
|
@@ -10,6 +11,186 @@ const MAX_CHUNK_RETRIES = 5;
|
|
|
10
11
|
const DEFAULT_MAX_CODE_FILES = 50;
|
|
11
12
|
const DEFAULT_MAX_TOTAL_CODE_BYTES = 2 * 1024 * 1024;
|
|
12
13
|
const MAX_DOC_CONTENT_CHARS = 4_000;
|
|
14
|
+
const MAX_GITHUB_FILES = 50;
|
|
15
|
+
const MAX_GITHUB_TOTAL_BYTES = 2 * 1024 * 1024;
|
|
16
|
+
const MAX_GITHUB_FILE_BYTES = 512 * 1024;
|
|
17
|
+
const MAX_GITHUB_DIRECTORIES = 250;
|
|
18
|
+
const SKIPPED_GITHUB_DIRECTORIES = new Set([
|
|
19
|
+
".git",
|
|
20
|
+
".next",
|
|
21
|
+
".turbo",
|
|
22
|
+
".cache",
|
|
23
|
+
"build",
|
|
24
|
+
"coverage",
|
|
25
|
+
"dist",
|
|
26
|
+
"node_modules",
|
|
27
|
+
"vendor",
|
|
28
|
+
]);
|
|
29
|
+
function normalizeGitHubPath(value) {
|
|
30
|
+
const normalized = value.trim().replace(/^\/+|\/+$/g, "");
|
|
31
|
+
if (normalized.split("/").some((segment) => segment === "." || segment === "..")) {
|
|
32
|
+
throw new Error("GitHub file and folder scopes cannot contain . or .. segments.");
|
|
33
|
+
}
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
function pathMatchesScope(path, scope) {
|
|
37
|
+
const normalizedPath = normalizeGitHubPath(path);
|
|
38
|
+
const normalizedScope = normalizeGitHubPath(scope);
|
|
39
|
+
return (normalizedPath === normalizedScope ||
|
|
40
|
+
normalizedPath.startsWith(`${normalizedScope}/`));
|
|
41
|
+
}
|
|
42
|
+
function pathIsExcluded(path, excludes) {
|
|
43
|
+
return excludes.some((scope) => pathMatchesScope(path, scope));
|
|
44
|
+
}
|
|
45
|
+
function isIndexableGitHubFile(path) {
|
|
46
|
+
const name = path.split("/").pop()?.toLowerCase() ?? path.toLowerCase();
|
|
47
|
+
return (name === "package.json" ||
|
|
48
|
+
/\.(css|scss|sass|less|ts|tsx|js|jsx|json|html|svg|xml|md|markdown|mdx|txt)$/.test(name) ||
|
|
49
|
+
/(?:tailwind|postcss|theme|tokens|design)\.config\.[^/]+$/.test(name));
|
|
50
|
+
}
|
|
51
|
+
function isSkippedGitHubDirectory(path) {
|
|
52
|
+
const name = path.split("/").pop()?.toLowerCase() ?? "";
|
|
53
|
+
return SKIPPED_GITHUB_DIRECTORIES.has(name);
|
|
54
|
+
}
|
|
55
|
+
function githubSourceAccessError(owner, repo, status, hasToken, message) {
|
|
56
|
+
const suffix = message ? ` GitHub said: ${message}` : "";
|
|
57
|
+
if (!hasToken && (status === 401 || status === 403 || status === 404)) {
|
|
58
|
+
return new Error(`Could not access ${owner}/${repo}. Public repositories work without setup; private repositories require a fine-grained GitHub personal access token saved as GITHUB_TOKEN in Settings > Secrets with Repository permissions > Contents: Read-only.${suffix}`);
|
|
59
|
+
}
|
|
60
|
+
if (hasToken && (status === 401 || status === 403 || status === 404)) {
|
|
61
|
+
return new Error(`Could not access ${owner}/${repo} with the saved GITHUB_TOKEN. Check that the token is valid, the repository is selected, organization SSO/approval is complete, and Contents is Read-only.${suffix}`);
|
|
62
|
+
}
|
|
63
|
+
if (status === 429) {
|
|
64
|
+
return new Error(`GitHub rate-limited requests for ${owner}/${repo}. Save a GITHUB_TOKEN in Settings > Secrets or try again after the rate limit resets.${suffix}`);
|
|
65
|
+
}
|
|
66
|
+
return new Error(`Could not read ${owner}/${repo} from GitHub (status ${status || "unknown"}).${suffix}`);
|
|
67
|
+
}
|
|
68
|
+
function normalizedGitHubSource(source) {
|
|
69
|
+
const reference = parseGitHubRepoReference(source.repoUrl);
|
|
70
|
+
const ref = source.ref?.trim() || reference.ref;
|
|
71
|
+
const impliedPath = reference.subpath ? [reference.subpath] : [];
|
|
72
|
+
const include = [
|
|
73
|
+
...impliedPath,
|
|
74
|
+
...(source.include ?? []).map(normalizeGitHubPath).filter(Boolean),
|
|
75
|
+
];
|
|
76
|
+
const uniqueInclude = [...new Set(include)];
|
|
77
|
+
const exclude = [
|
|
78
|
+
...(source.exclude ?? []).map(normalizeGitHubPath).filter(Boolean),
|
|
79
|
+
];
|
|
80
|
+
const normalized = {
|
|
81
|
+
repoUrl: canonicalGitHubRepoUrl(source.repoUrl),
|
|
82
|
+
...(ref ? { ref } : {}),
|
|
83
|
+
...(uniqueInclude.length > 0 ? { include: uniqueInclude } : {}),
|
|
84
|
+
...(exclude.length > 0 ? { exclude: [...new Set(exclude)] } : {}),
|
|
85
|
+
...(source.instructions?.trim()
|
|
86
|
+
? { instructions: source.instructions.trim() }
|
|
87
|
+
: {}),
|
|
88
|
+
};
|
|
89
|
+
return { source: normalized, reference: { ...reference, ref } };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolve an explicitly scoped/ref'd GitHub source into bounded file uploads.
|
|
93
|
+
* Native Builder public-repo sources are preferred for unscoped public repos;
|
|
94
|
+
* this path exists so branch, folder, and private-repo imports are replayable.
|
|
95
|
+
*/
|
|
96
|
+
export async function collectBuilderDesignSystemGitHubFiles(input) {
|
|
97
|
+
const { source, reference } = normalizedGitHubSource(input);
|
|
98
|
+
const githubToken = await resolveSecret("GITHUB_TOKEN");
|
|
99
|
+
const include = source.include ?? [];
|
|
100
|
+
const explicitScope = include.length > 0 || Boolean(source.ref);
|
|
101
|
+
const queue = [...(include.length > 0 ? include : [""])];
|
|
102
|
+
const visited = new Set();
|
|
103
|
+
const files = [];
|
|
104
|
+
let totalBytes = 0;
|
|
105
|
+
let directoriesVisited = 0;
|
|
106
|
+
let truncated = false;
|
|
107
|
+
while (queue.length > 0) {
|
|
108
|
+
const path = normalizeGitHubPath(queue.shift() ?? "");
|
|
109
|
+
if (visited.has(path) || pathIsExcluded(path, source.exclude ?? [])) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
visited.add(path);
|
|
113
|
+
directoriesVisited++;
|
|
114
|
+
if (directoriesVisited > MAX_GITHUB_DIRECTORIES) {
|
|
115
|
+
truncated = true;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
const result = await fetchGitHubJsonResult(reference.owner, reference.repo, path, {
|
|
119
|
+
token: githubToken,
|
|
120
|
+
ref: reference.ref,
|
|
121
|
+
});
|
|
122
|
+
if (!result.ok) {
|
|
123
|
+
throw githubSourceAccessError(reference.owner, reference.repo, result.status, Boolean(githubToken), result.message);
|
|
124
|
+
}
|
|
125
|
+
const entries = Array.isArray(result.data)
|
|
126
|
+
? result.data
|
|
127
|
+
: result.data
|
|
128
|
+
? [result.data]
|
|
129
|
+
: [];
|
|
130
|
+
for (const entry of entries) {
|
|
131
|
+
const entryPath = normalizeGitHubPath(entry?.path ?? entry?.name ?? "");
|
|
132
|
+
if (!entryPath || pathIsExcluded(entryPath, source.exclude ?? [])) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (entry.type === "dir") {
|
|
136
|
+
if (isSkippedGitHubDirectory(entryPath))
|
|
137
|
+
continue;
|
|
138
|
+
queue.push(entryPath);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (entry.type !== "file")
|
|
142
|
+
continue;
|
|
143
|
+
if (include.length > 0 &&
|
|
144
|
+
!include.some((scope) => pathMatchesScope(entryPath, scope))) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (!explicitScope && !isIndexableGitHubFile(entryPath))
|
|
148
|
+
continue;
|
|
149
|
+
if (files.length >= MAX_GITHUB_FILES) {
|
|
150
|
+
truncated = true;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
if ((entry.size ?? 0) > MAX_GITHUB_FILE_BYTES)
|
|
154
|
+
continue;
|
|
155
|
+
const content = await fetchGitHubRaw(reference.owner, reference.repo, entryPath, { token: githubToken, ref: reference.ref });
|
|
156
|
+
if (content === null) {
|
|
157
|
+
throw new Error(`Could not read ${entryPath} from ${reference.owner}/${reference.repo}${source.ref ? ` at ref ${source.ref}` : ""}. Check the repository Contents permission and file size.`);
|
|
158
|
+
}
|
|
159
|
+
const bytes = new TextEncoder().encode(content).byteLength;
|
|
160
|
+
if (totalBytes + bytes > MAX_GITHUB_TOTAL_BYTES) {
|
|
161
|
+
truncated = true;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
files.push({ path: entryPath, content });
|
|
165
|
+
totalBytes += bytes;
|
|
166
|
+
}
|
|
167
|
+
if (truncated)
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (files.length === 0) {
|
|
171
|
+
throw new Error(`No readable design-system files were found in ${reference.owner}/${reference.repo}${source.ref ? ` at ref ${source.ref}` : ""}. Select a folder or file that contains code, styles, tokens, or design.md.`);
|
|
172
|
+
}
|
|
173
|
+
if (truncated) {
|
|
174
|
+
throw new Error(`The selected GitHub source ${reference.owner}/${reference.repo} is larger than the safe inline indexing limit. Select a narrower folder or file set and try again.`);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
source,
|
|
178
|
+
owner: reference.owner,
|
|
179
|
+
repo: reference.repo,
|
|
180
|
+
...(reference.ref ? { ref: reference.ref } : {}),
|
|
181
|
+
files,
|
|
182
|
+
totalBytes,
|
|
183
|
+
truncated,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async function isPublicGitHubSource(reference) {
|
|
187
|
+
const result = await fetchGitHubJsonResult(reference.owner, reference.repo, "", {
|
|
188
|
+
ref: reference.ref,
|
|
189
|
+
});
|
|
190
|
+
return result.ok
|
|
191
|
+
? { ok: true }
|
|
192
|
+
: { ok: false, status: result.status, message: result.message };
|
|
193
|
+
}
|
|
13
194
|
export async function fetchBuilderDesignSystemDecodeJobStatus(jobId) {
|
|
14
195
|
const credentials = await resolveBuilderDesignSystemCredentials();
|
|
15
196
|
const url = makeBuilderDesignSystemUrl("decode-jobs/" + encodeURIComponent(jobId), credentials);
|
|
@@ -287,14 +468,19 @@ export function localBuilderDesignSystemId(builderDesignSystemId) {
|
|
|
287
468
|
.slice(0, 96);
|
|
288
469
|
return `builder-${slug || "design-system"}`;
|
|
289
470
|
}
|
|
290
|
-
export function createBuilderDesignSystemProxyFields({ result, projectName, description, surface, sourceKind, }) {
|
|
471
|
+
export function createBuilderDesignSystemProxyFields({ result, projectName, description, surface, sourceKind, githubSources, syncedAt, }) {
|
|
291
472
|
const title = projectName?.trim() || "Builder indexed design system";
|
|
473
|
+
const normalizedGithubSources = githubSources?.map((source) => normalizedGitHubSource(source).source);
|
|
292
474
|
const fallbackDescription = description ?? `Builder indexed design system ${result.designSystemId}`;
|
|
293
475
|
const surfaceNoun = surface === "slides" ? "slides" : "designs";
|
|
294
476
|
const spacingKey = surface === "slides" ? "slidePadding" : "pagePadding";
|
|
295
477
|
const data = JSON.stringify({
|
|
296
478
|
source: "builder",
|
|
297
479
|
...(sourceKind ? { sourceKind } : {}),
|
|
480
|
+
...(normalizedGithubSources?.length
|
|
481
|
+
? { githubSources: normalizedGithubSources }
|
|
482
|
+
: {}),
|
|
483
|
+
...(syncedAt ? { syncedAt } : {}),
|
|
298
484
|
builderDesignSystemId: result.designSystemId,
|
|
299
485
|
builderJobId: result.jobId,
|
|
300
486
|
builderProjectId: result.projectId,
|
|
@@ -328,6 +514,9 @@ export function createBuilderDesignSystemProxyFields({ result, projectName, desc
|
|
|
328
514
|
projectName ? `Requested name: ${projectName}` : "",
|
|
329
515
|
description ? `Context: ${description}` : "",
|
|
330
516
|
"Builder Design System Intelligence is the source of truth for indexed tokens, components, assets, and usage guidance.",
|
|
517
|
+
normalizedGithubSources?.length
|
|
518
|
+
? "GitHub source scope is persisted so this design system can be synced without reconfiguring it."
|
|
519
|
+
: "",
|
|
331
520
|
]
|
|
332
521
|
.filter(Boolean)
|
|
333
522
|
.join("\n"),
|
|
@@ -340,6 +529,9 @@ export function createBuilderDesignSystemProxyFields({ result, projectName, desc
|
|
|
340
529
|
`Builder URL: ${result.builderUrl}`,
|
|
341
530
|
`When generating ${surfaceNoun}, treat Builder DSI as the source of truth for indexed tokens, components, assets, and usage guidance.`,
|
|
342
531
|
"Call get-design-system for this local id before generation and use the returned builder docs and token values when available.",
|
|
532
|
+
normalizedGithubSources?.length
|
|
533
|
+
? "Use sync-design-system-with-builder to refresh the persisted GitHub source scope before generating when the repository changed."
|
|
534
|
+
: "",
|
|
343
535
|
].join("\n");
|
|
344
536
|
return {
|
|
345
537
|
title,
|
|
@@ -375,6 +567,48 @@ export function parseBuilderDesignSystemProxyReference(data) {
|
|
|
375
567
|
sourceKind !== "mixed") {
|
|
376
568
|
return null;
|
|
377
569
|
}
|
|
570
|
+
let invalidGithubSource = false;
|
|
571
|
+
const githubSources = Array.isArray(value.githubSources)
|
|
572
|
+
? value.githubSources.flatMap((source) => {
|
|
573
|
+
if (!source || typeof source !== "object") {
|
|
574
|
+
invalidGithubSource = true;
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
const candidate = source;
|
|
578
|
+
if (typeof candidate.repoUrl !== "string") {
|
|
579
|
+
invalidGithubSource = true;
|
|
580
|
+
return [];
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
const normalized = normalizedGitHubSource({
|
|
584
|
+
repoUrl: candidate.repoUrl,
|
|
585
|
+
...(typeof candidate.ref === "string"
|
|
586
|
+
? { ref: candidate.ref }
|
|
587
|
+
: {}),
|
|
588
|
+
...(Array.isArray(candidate.include)
|
|
589
|
+
? {
|
|
590
|
+
include: candidate.include.filter((path) => typeof path === "string"),
|
|
591
|
+
}
|
|
592
|
+
: {}),
|
|
593
|
+
...(Array.isArray(candidate.exclude)
|
|
594
|
+
? {
|
|
595
|
+
exclude: candidate.exclude.filter((path) => typeof path === "string"),
|
|
596
|
+
}
|
|
597
|
+
: {}),
|
|
598
|
+
...(typeof candidate.instructions === "string"
|
|
599
|
+
? { instructions: candidate.instructions }
|
|
600
|
+
: {}),
|
|
601
|
+
});
|
|
602
|
+
return [normalized.source];
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
invalidGithubSource = true;
|
|
606
|
+
return [];
|
|
607
|
+
}
|
|
608
|
+
})
|
|
609
|
+
: undefined;
|
|
610
|
+
if (invalidGithubSource)
|
|
611
|
+
return null;
|
|
378
612
|
return {
|
|
379
613
|
source: "builder",
|
|
380
614
|
...(sourceKind ? { sourceKind } : {}),
|
|
@@ -385,6 +619,8 @@ export function parseBuilderDesignSystemProxyReference(data) {
|
|
|
385
619
|
: undefined,
|
|
386
620
|
builderUrl: typeof value.builderUrl === "string" ? value.builderUrl : undefined,
|
|
387
621
|
builderStatus: typeof value.builderStatus === "string" ? value.builderStatus : undefined,
|
|
622
|
+
...(githubSources?.length ? { githubSources } : {}),
|
|
623
|
+
...(typeof value.syncedAt === "string" ? { syncedAt: value.syncedAt } : {}),
|
|
388
624
|
};
|
|
389
625
|
}
|
|
390
626
|
function truncateDocContent(content) {
|
|
@@ -435,8 +671,9 @@ export async function fetchBuilderDesignSystemDocs(designSystemId, options = {})
|
|
|
435
671
|
});
|
|
436
672
|
await assertOk(response, "Builder design-system docs fetch failed");
|
|
437
673
|
const json = (await response.json());
|
|
438
|
-
if (!Array.isArray(json))
|
|
439
|
-
|
|
674
|
+
if (!Array.isArray(json)) {
|
|
675
|
+
throw new Error("Builder design-system docs fetch returned an invalid response.");
|
|
676
|
+
}
|
|
440
677
|
return json.map(normalizeBuilderDesignSystemDocument);
|
|
441
678
|
}
|
|
442
679
|
export async function hydrateBuilderDesignSystemReference(reference, options = { page: 0, pageSize: 40 }) {
|
|
@@ -555,10 +792,56 @@ export async function startBuilderDesignSystemIndex(options) {
|
|
|
555
792
|
}
|
|
556
793
|
if (files.length === 0 &&
|
|
557
794
|
!options.githubRepoUrl &&
|
|
795
|
+
!(options.githubRepos && options.githubRepos.length > 0) &&
|
|
558
796
|
!options.connectedProjectId) {
|
|
559
797
|
throw new Error("Provide at least one .fig/code/text file or a GitHub repository URL to index with Builder.");
|
|
560
798
|
}
|
|
561
799
|
const sources = [];
|
|
800
|
+
const fileInstructions = new Map();
|
|
801
|
+
function appendGitHubCollection(collection) {
|
|
802
|
+
for (const file of collection.files) {
|
|
803
|
+
const name = `github/${collection.owner}/${collection.repo}/${file.path}`;
|
|
804
|
+
files.push({
|
|
805
|
+
name,
|
|
806
|
+
data: new TextEncoder().encode(file.content),
|
|
807
|
+
mimeType: mimeTypeForBuilderDesignSystemFilename(file.path),
|
|
808
|
+
});
|
|
809
|
+
if (collection.source.instructions) {
|
|
810
|
+
fileInstructions.set(name, collection.source.instructions);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
const githubSources = options.githubRepos?.length
|
|
815
|
+
? options.githubRepos
|
|
816
|
+
: options.githubRepoUrl?.trim()
|
|
817
|
+
? [{ repoUrl: options.githubRepoUrl.trim() }]
|
|
818
|
+
: [];
|
|
819
|
+
for (const input of githubSources) {
|
|
820
|
+
const { source, reference } = normalizedGitHubSource(input);
|
|
821
|
+
const hasExplicitScope = Boolean(source.ref) ||
|
|
822
|
+
Boolean(source.include?.length) ||
|
|
823
|
+
Boolean(source.exclude?.length);
|
|
824
|
+
if (hasExplicitScope) {
|
|
825
|
+
const collection = await collectBuilderDesignSystemGitHubFiles(source);
|
|
826
|
+
appendGitHubCollection(collection);
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
const publicAccess = await isPublicGitHubSource(reference);
|
|
830
|
+
if (publicAccess.ok) {
|
|
831
|
+
sources.push({
|
|
832
|
+
kind: "public-repo",
|
|
833
|
+
repoUrl: source.repoUrl,
|
|
834
|
+
...(source.instructions ? { instructions: source.instructions } : {}),
|
|
835
|
+
});
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
if (await resolveSecret("GITHUB_TOKEN")) {
|
|
839
|
+
const collection = await collectBuilderDesignSystemGitHubFiles(source);
|
|
840
|
+
appendGitHubCollection(collection);
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
throw githubSourceAccessError(reference.owner, reference.repo, publicAccess.status, false, publicAccess.message);
|
|
844
|
+
}
|
|
562
845
|
if (files.length > 0) {
|
|
563
846
|
const slots = await startBuilderDesignSystemUpload(files.map((file) => ({
|
|
564
847
|
name: file.name,
|
|
@@ -568,23 +851,22 @@ export async function startBuilderDesignSystemIndex(options) {
|
|
|
568
851
|
for (let i = 0; i < slots.length; i++) {
|
|
569
852
|
await uploadToResumableUrl(slots[i], files[i]);
|
|
570
853
|
}
|
|
854
|
+
const fileSources = [];
|
|
571
855
|
for (let i = 0; i < slots.length; i++) {
|
|
572
856
|
const name = files[i].name;
|
|
573
857
|
const fileSelection = options.selection?.[name];
|
|
574
|
-
|
|
858
|
+
fileSources.push({
|
|
575
859
|
kind: "file",
|
|
576
860
|
uploadToken: slots[i].uploadToken,
|
|
861
|
+
...(fileInstructions.get(name)
|
|
862
|
+
? { instructions: fileInstructions.get(name) }
|
|
863
|
+
: {}),
|
|
577
864
|
...(fileSelection && fileSelection.length > 0
|
|
578
865
|
? { selection: { [name]: fileSelection } }
|
|
579
866
|
: {}),
|
|
580
867
|
});
|
|
581
868
|
}
|
|
582
|
-
|
|
583
|
-
if (options.githubRepoUrl?.trim()) {
|
|
584
|
-
sources.push({
|
|
585
|
-
kind: "public-repo",
|
|
586
|
-
repoUrl: options.githubRepoUrl.trim(),
|
|
587
|
-
});
|
|
869
|
+
sources.unshift(...fileSources);
|
|
588
870
|
}
|
|
589
871
|
if (options.connectedProjectId?.trim()) {
|
|
590
872
|
sources.push({
|
|
@@ -101,6 +101,14 @@ export interface UrlExtractionResult {
|
|
|
101
101
|
}
|
|
102
102
|
export interface GitHubFetchOptions {
|
|
103
103
|
token?: string | null;
|
|
104
|
+
/** Branch, tag, or commit to read from. */
|
|
105
|
+
ref?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface GitHubRepoReference {
|
|
108
|
+
owner: string;
|
|
109
|
+
repo: string;
|
|
110
|
+
ref?: string;
|
|
111
|
+
subpath?: string;
|
|
104
112
|
}
|
|
105
113
|
export interface GitHubJsonResult<T = unknown> {
|
|
106
114
|
ok: boolean;
|
|
@@ -117,11 +125,14 @@ export interface GitHubJsonResult<T = unknown> {
|
|
|
117
125
|
* clear early error for literal private hosts, ssrfSafeFetch is the backstop.
|
|
118
126
|
*/
|
|
119
127
|
export declare function validateUrl(url: string): void;
|
|
128
|
+
/** Parse a GitHub URL or "org/repo" shorthand, retaining an optional ref/path. */
|
|
129
|
+
export declare function parseGitHubRepoReference(raw: string): GitHubRepoReference;
|
|
120
130
|
/** Parse a GitHub URL or "org/repo" shorthand into owner + repo. */
|
|
121
131
|
export declare function parseOwnerRepo(raw: string): {
|
|
122
132
|
owner: string;
|
|
123
133
|
repo: string;
|
|
124
134
|
};
|
|
135
|
+
export declare function canonicalGitHubRepoUrl(raw: string): string;
|
|
125
136
|
/** Fetch a path from the GitHub Contents API as JSON with status details. */
|
|
126
137
|
export declare function fetchGitHubJsonResult<T = unknown>(owner: string, repo: string, path: string, options?: GitHubFetchOptions): Promise<GitHubJsonResult<T>>;
|
|
127
138
|
/** Fetch a path from the GitHub Contents API as JSON. Returns null on error. */
|