@builder.io/ai-utils 0.107.0 → 0.109.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/package.json +1 -1
- package/src/codegen.d.ts +99 -8
- package/src/codegen.js +65 -1
- package/src/projects.d.ts +120 -3
- package/src/projects.js +118 -0
- package/src/projects.spec.d.ts +1 -0
- package/src/projects.spec.js +40 -0
- package/src/projects.test.js +87 -1
package/package.json
CHANGED
package/src/codegen.d.ts
CHANGED
|
@@ -140,6 +140,7 @@ export declare const GlobSearchToolInputSchema: z.ZodObject<{
|
|
|
140
140
|
export type GlobSearchToolInput = z.infer<typeof GlobSearchToolInputSchema>;
|
|
141
141
|
export declare const GrepSearchToolInputSchema: z.ZodObject<{
|
|
142
142
|
query: z.ZodString;
|
|
143
|
+
node_modules_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
143
144
|
include_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
144
145
|
exclude_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
145
146
|
case_sensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
@@ -510,6 +511,56 @@ export declare const RecordFrameToolInputSchema: z.ZodObject<{
|
|
|
510
511
|
pr_highlight: z.ZodOptional<z.ZodBoolean>;
|
|
511
512
|
}, z.core.$strip>;
|
|
512
513
|
export type RecordFrameToolInput = z.infer<typeof RecordFrameToolInputSchema>;
|
|
514
|
+
export declare const StartRecordingToolInputSchema: z.ZodObject<{
|
|
515
|
+
label: z.ZodString;
|
|
516
|
+
}, z.core.$strip>;
|
|
517
|
+
export type StartRecordingToolInput = z.infer<typeof StartRecordingToolInputSchema>;
|
|
518
|
+
export declare const StopRecordingToolInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
519
|
+
export type StopRecordingToolInput = z.infer<typeof StopRecordingToolInputSchema>;
|
|
520
|
+
export declare const PublishEvidenceToolInputSchema: z.ZodObject<{
|
|
521
|
+
issues: z.ZodArray<z.ZodObject<{
|
|
522
|
+
title: z.ZodString;
|
|
523
|
+
verdict: z.ZodEnum<{
|
|
524
|
+
fixed: "fixed";
|
|
525
|
+
"needs-input": "needs-input";
|
|
526
|
+
"no-ui-change": "no-ui-change";
|
|
527
|
+
"not-reproduced": "not-reproduced";
|
|
528
|
+
}>;
|
|
529
|
+
summary: z.ZodString;
|
|
530
|
+
screenshots: z.ZodArray<z.ZodObject<{
|
|
531
|
+
path: z.ZodString;
|
|
532
|
+
caption: z.ZodString;
|
|
533
|
+
}, z.core.$strip>>;
|
|
534
|
+
recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
535
|
+
recording_id: z.ZodString;
|
|
536
|
+
}, z.core.$strip>>>;
|
|
537
|
+
}, z.core.$strip>>;
|
|
538
|
+
}, z.core.$strip>;
|
|
539
|
+
export type PublishEvidenceToolInput = z.infer<typeof PublishEvidenceToolInputSchema>;
|
|
540
|
+
export declare const MAX_EVIDENCE_UPLOAD_BYTES: number;
|
|
541
|
+
export declare const EvidenceUploadUrlOptionsSchema: z.ZodObject<{
|
|
542
|
+
contentType: z.ZodEnum<{
|
|
543
|
+
"image/webp": "image/webp";
|
|
544
|
+
"video/mp4": "video/mp4";
|
|
545
|
+
}>;
|
|
546
|
+
size: z.ZodNumber;
|
|
547
|
+
}, z.core.$strip>;
|
|
548
|
+
export type EvidenceUploadUrlOptions = z.infer<typeof EvidenceUploadUrlOptionsSchema>;
|
|
549
|
+
/** What publishing evidence did to the branch's open pull request. */
|
|
550
|
+
export type OpenPRRefresh = {
|
|
551
|
+
status: "no-open-pr";
|
|
552
|
+
} | {
|
|
553
|
+
status: "updated";
|
|
554
|
+
prNumber: number;
|
|
555
|
+
} | {
|
|
556
|
+
status: "failed";
|
|
557
|
+
reason: string;
|
|
558
|
+
};
|
|
559
|
+
export interface EvidenceUploadUrlResult {
|
|
560
|
+
upload_url: string;
|
|
561
|
+
public_url: string;
|
|
562
|
+
required_headers: Record<string, string>;
|
|
563
|
+
}
|
|
513
564
|
export declare const ReportTestOutcomeToolInputSchema: z.ZodObject<{
|
|
514
565
|
outcome: z.ZodEnum<{
|
|
515
566
|
couldnt_verify: "couldnt_verify";
|
|
@@ -568,12 +619,29 @@ export interface TimelineFrameMetadata {
|
|
|
568
619
|
fileName?: string;
|
|
569
620
|
image_url?: string;
|
|
570
621
|
prHighlight?: boolean;
|
|
622
|
+
/** Index into `TimelineRecording.phases` for a frame that belongs to a recording tab. */
|
|
623
|
+
phaseIndex?: number;
|
|
571
624
|
description?: string;
|
|
572
625
|
cursorX?: number | null;
|
|
573
626
|
cursorY?: number | null;
|
|
574
627
|
viewportWidth?: number;
|
|
575
628
|
viewportHeight?: number;
|
|
576
629
|
}
|
|
630
|
+
/** One agent's slice of a merged browser-testing run. */
|
|
631
|
+
export interface TimelineAgentPhase {
|
|
632
|
+
label: string;
|
|
633
|
+
sessionId: string;
|
|
634
|
+
startEventId: number;
|
|
635
|
+
endEventId: number;
|
|
636
|
+
testCaseIds?: string[];
|
|
637
|
+
replayId?: string;
|
|
638
|
+
}
|
|
639
|
+
/** One screen recording published as evidence; the timeline shows a tab for each. */
|
|
640
|
+
export interface TimelineVideoPhase {
|
|
641
|
+
label: string;
|
|
642
|
+
videoUrl: string;
|
|
643
|
+
testCaseIds: string[];
|
|
644
|
+
}
|
|
577
645
|
export interface TimelineRecording {
|
|
578
646
|
version: 1;
|
|
579
647
|
sessionId: string;
|
|
@@ -590,14 +658,7 @@ export interface TimelineRecording {
|
|
|
590
658
|
description: string;
|
|
591
659
|
debugInfo?: string;
|
|
592
660
|
}>;
|
|
593
|
-
phases?: Array<
|
|
594
|
-
label: string;
|
|
595
|
-
sessionId: string;
|
|
596
|
-
startEventId: number;
|
|
597
|
-
endEventId: number;
|
|
598
|
-
testCaseIds?: string[];
|
|
599
|
-
replayId?: string;
|
|
600
|
-
}>;
|
|
661
|
+
phases?: Array<TimelineAgentPhase | TimelineVideoPhase>;
|
|
601
662
|
}
|
|
602
663
|
export interface TimelineSubmissionMetadata {
|
|
603
664
|
prNumber?: number;
|
|
@@ -1515,6 +1576,7 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1515
1576
|
}, z.core.$strip>;
|
|
1516
1577
|
Grep: z.ZodObject<{
|
|
1517
1578
|
query: z.ZodString;
|
|
1579
|
+
node_modules_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1518
1580
|
include_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1519
1581
|
exclude_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1520
1582
|
case_sensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
@@ -1629,6 +1691,29 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1629
1691
|
description: z.ZodOptional<z.ZodString>;
|
|
1630
1692
|
pr_highlight: z.ZodOptional<z.ZodBoolean>;
|
|
1631
1693
|
}, z.core.$strip>;
|
|
1694
|
+
StartRecording: z.ZodObject<{
|
|
1695
|
+
label: z.ZodString;
|
|
1696
|
+
}, z.core.$strip>;
|
|
1697
|
+
StopRecording: z.ZodObject<{}, z.core.$strip>;
|
|
1698
|
+
PublishEvidence: z.ZodObject<{
|
|
1699
|
+
issues: z.ZodArray<z.ZodObject<{
|
|
1700
|
+
title: z.ZodString;
|
|
1701
|
+
verdict: z.ZodEnum<{
|
|
1702
|
+
fixed: "fixed";
|
|
1703
|
+
"needs-input": "needs-input";
|
|
1704
|
+
"no-ui-change": "no-ui-change";
|
|
1705
|
+
"not-reproduced": "not-reproduced";
|
|
1706
|
+
}>;
|
|
1707
|
+
summary: z.ZodString;
|
|
1708
|
+
screenshots: z.ZodArray<z.ZodObject<{
|
|
1709
|
+
path: z.ZodString;
|
|
1710
|
+
caption: z.ZodString;
|
|
1711
|
+
}, z.core.$strip>>;
|
|
1712
|
+
recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1713
|
+
recording_id: z.ZodString;
|
|
1714
|
+
}, z.core.$strip>>>;
|
|
1715
|
+
}, z.core.$strip>>;
|
|
1716
|
+
}, z.core.$strip>;
|
|
1632
1717
|
SubmitPRReview: z.ZodObject<{
|
|
1633
1718
|
summary: z.ZodString;
|
|
1634
1719
|
comments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1999,6 +2084,7 @@ export declare const CodeGenToolsSchema: z.ZodEnum<{
|
|
|
1999
2084
|
PowerShell: "PowerShell";
|
|
2000
2085
|
ProposeConfig: "ProposeConfig";
|
|
2001
2086
|
ProposeEnvVariable: "ProposeEnvVariable";
|
|
2087
|
+
PublishEvidence: "PublishEvidence";
|
|
2002
2088
|
PullPrototype: "PullPrototype";
|
|
2003
2089
|
Read: "Read";
|
|
2004
2090
|
ReadBranch: "ReadBranch";
|
|
@@ -2018,6 +2104,8 @@ export declare const CodeGenToolsSchema: z.ZodEnum<{
|
|
|
2018
2104
|
SetFileOverride: "SetFileOverride";
|
|
2019
2105
|
Skill: "Skill";
|
|
2020
2106
|
SpawnBranch: "SpawnBranch";
|
|
2107
|
+
StartRecording: "StartRecording";
|
|
2108
|
+
StopRecording: "StopRecording";
|
|
2021
2109
|
SubmitPRReview: "SubmitPRReview";
|
|
2022
2110
|
TaskCreate: "TaskCreate";
|
|
2023
2111
|
TaskList: "TaskList";
|
|
@@ -2891,6 +2979,7 @@ export declare const CodeGenInputOptionsSchema: z.ZodObject<{
|
|
|
2891
2979
|
PowerShell: "PowerShell";
|
|
2892
2980
|
ProposeConfig: "ProposeConfig";
|
|
2893
2981
|
ProposeEnvVariable: "ProposeEnvVariable";
|
|
2982
|
+
PublishEvidence: "PublishEvidence";
|
|
2894
2983
|
PullPrototype: "PullPrototype";
|
|
2895
2984
|
Read: "Read";
|
|
2896
2985
|
ReadBranch: "ReadBranch";
|
|
@@ -2910,6 +2999,8 @@ export declare const CodeGenInputOptionsSchema: z.ZodObject<{
|
|
|
2910
2999
|
SetFileOverride: "SetFileOverride";
|
|
2911
3000
|
Skill: "Skill";
|
|
2912
3001
|
SpawnBranch: "SpawnBranch";
|
|
3002
|
+
StartRecording: "StartRecording";
|
|
3003
|
+
StopRecording: "StopRecording";
|
|
2913
3004
|
SubmitPRReview: "SubmitPRReview";
|
|
2914
3005
|
TaskCreate: "TaskCreate";
|
|
2915
3006
|
TaskList: "TaskList";
|
package/src/codegen.js
CHANGED
|
@@ -143,7 +143,9 @@ export function readToolImageMediaType(filePath) {
|
|
|
143
143
|
}
|
|
144
144
|
export const GlobSearchToolInputSchema = z
|
|
145
145
|
.object({
|
|
146
|
-
pattern: z.string().meta({
|
|
146
|
+
pattern: z.string().meta({
|
|
147
|
+
description: "The pattern to search for. node_modules and dist folders are skipped unless the pattern starts with a path inside node_modules (e.g. 'node_modules/@tabler/icons-react/**/*.d.ts').",
|
|
148
|
+
}),
|
|
147
149
|
})
|
|
148
150
|
.meta({ title: "GlobSearchToolInput" });
|
|
149
151
|
export const GrepSearchToolInputSchema = z
|
|
@@ -151,6 +153,9 @@ export const GrepSearchToolInputSchema = z
|
|
|
151
153
|
query: z.string().meta({
|
|
152
154
|
description: 'A string literal or a JavaScript-flavored regex to search for in all project files. Only escape special characters such as {} and () in string literals to avoid confusion with regex patterns (e.g. "import \\{ foo \\}"). Avoid over-escaping as that will cause errors. Do NOT use inline regex flags like (?i) or (?s) — they are not supported. The search is case-insensitive by default; use the case_sensitive parameter to control this.',
|
|
153
155
|
}),
|
|
156
|
+
node_modules_path: z.string().nullish().meta({
|
|
157
|
+
description: "Searches an installed package instead of the project. node_modules and dist folders are skipped by default; set this to a directory or file inside node_modules (e.g. 'node_modules/@tabler/icons-react') to search that package, including its dist folder and .d.ts files.",
|
|
158
|
+
}),
|
|
154
159
|
include_glob: z.string().nullish().meta({
|
|
155
160
|
description: "An optional single glob pattern to include only specific files (e.g. '**/*.(ts|tsx)' for all TypeScript files)",
|
|
156
161
|
}),
|
|
@@ -746,6 +751,62 @@ export const RecordFrameToolInputSchema = z
|
|
|
746
751
|
}),
|
|
747
752
|
})
|
|
748
753
|
.meta({ title: "RecordFrameToolInput" });
|
|
754
|
+
export const StartRecordingToolInputSchema = z
|
|
755
|
+
.object({
|
|
756
|
+
label: z.string().meta({
|
|
757
|
+
description: "Timeline tab label for this recording, e.g. 'Production before', 'Figma', 'Local after'.",
|
|
758
|
+
}),
|
|
759
|
+
})
|
|
760
|
+
.meta({ title: "StartRecordingToolInput" });
|
|
761
|
+
export const StopRecordingToolInputSchema = z
|
|
762
|
+
.object({})
|
|
763
|
+
.meta({ title: "StopRecordingToolInput" });
|
|
764
|
+
export const PublishEvidenceToolInputSchema = z
|
|
765
|
+
.object({
|
|
766
|
+
issues: z
|
|
767
|
+
.array(z.object({
|
|
768
|
+
title: z.string().meta({
|
|
769
|
+
description: "The issue as the user would name it.",
|
|
770
|
+
}),
|
|
771
|
+
verdict: z
|
|
772
|
+
.enum(["fixed", "not-reproduced", "needs-input", "no-ui-change"])
|
|
773
|
+
.meta({
|
|
774
|
+
description: "Only 'fixed' issues reach the PR's Verified section; the others stay on the timeline. 'no-ui-change' is for a change with nothing to show in a browser.",
|
|
775
|
+
}),
|
|
776
|
+
summary: z.string().meta({
|
|
777
|
+
description: "One or two sentences: what changed, or why it was not fixed.",
|
|
778
|
+
}),
|
|
779
|
+
screenshots: z
|
|
780
|
+
.array(z.object({
|
|
781
|
+
path: z.string().meta({
|
|
782
|
+
description: "A .png, .jpg or .webp file in the workspace or under ~/.builder.",
|
|
783
|
+
}),
|
|
784
|
+
caption: z.string(),
|
|
785
|
+
}))
|
|
786
|
+
.meta({
|
|
787
|
+
description: "Stills that support the fix; the PR shows them under the recording.",
|
|
788
|
+
}),
|
|
789
|
+
recordings: z
|
|
790
|
+
.array(z.object({
|
|
791
|
+
recording_id: z.string().meta({
|
|
792
|
+
description: "The recording_id StopRecording returned.",
|
|
793
|
+
}),
|
|
794
|
+
}))
|
|
795
|
+
.optional()
|
|
796
|
+
.meta({
|
|
797
|
+
description: "Required for a 'fixed' issue: its verification, recorded on your current code. Older recordings stay on the timeline as comparisons. One timeline tab each.",
|
|
798
|
+
}),
|
|
799
|
+
}))
|
|
800
|
+
.min(1),
|
|
801
|
+
})
|
|
802
|
+
.meta({ title: "PublishEvidenceToolInput" });
|
|
803
|
+
export const MAX_EVIDENCE_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
804
|
+
export const EvidenceUploadUrlOptionsSchema = z
|
|
805
|
+
.object({
|
|
806
|
+
contentType: z.enum(["video/mp4", "image/webp"]),
|
|
807
|
+
size: z.number().int().positive().max(MAX_EVIDENCE_UPLOAD_BYTES),
|
|
808
|
+
})
|
|
809
|
+
.meta({ title: "EvidenceUploadUrlOptions" });
|
|
749
810
|
export const ReportTestOutcomeToolInputSchema = z
|
|
750
811
|
.object({
|
|
751
812
|
outcome: TestOutcomeSchema.meta({
|
|
@@ -1638,6 +1699,9 @@ export const CodeGenToolMapSchema = z.object({
|
|
|
1638
1699
|
ExitPlanMode: ExitPlanModeToolInputSchema,
|
|
1639
1700
|
ReadMcpResource: ReadMcpResourceToolInputSchema,
|
|
1640
1701
|
RecordFrame: RecordFrameToolInputSchema,
|
|
1702
|
+
StartRecording: StartRecordingToolInputSchema,
|
|
1703
|
+
StopRecording: StopRecordingToolInputSchema,
|
|
1704
|
+
PublishEvidence: PublishEvidenceToolInputSchema,
|
|
1641
1705
|
SubmitPRReview: SubmitPRReviewToolInputSchema,
|
|
1642
1706
|
AddComment: AddCommentToolInputSchema,
|
|
1643
1707
|
ProposeConfig: ProposeConfigToolInputSchema,
|
package/src/projects.d.ts
CHANGED
|
@@ -472,7 +472,13 @@ export declare const ProjectSkillSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
472
472
|
url: z.ZodString;
|
|
473
473
|
}, z.core.$strip>]>;
|
|
474
474
|
export type ProjectSkill = z.infer<typeof ProjectSkillSchema>;
|
|
475
|
-
export
|
|
475
|
+
export declare const FusionExecutionEnvironmentSchema: z.ZodEnum<{
|
|
476
|
+
cloud: "cloud";
|
|
477
|
+
"cloud-v2": "cloud-v2";
|
|
478
|
+
"container-less": "container-less";
|
|
479
|
+
containerized: "containerized";
|
|
480
|
+
}>;
|
|
481
|
+
export type FusionExecutionEnvironment = z.infer<typeof FusionExecutionEnvironmentSchema>;
|
|
476
482
|
export type AgentType = "setup-project" | "project-configuration" | "org-agent" | "code-review-orchestrator" | "design-system-indexer" | "repo-indexer" | "builder-publish-integration";
|
|
477
483
|
export interface PartialBranchData {
|
|
478
484
|
name?: string;
|
|
@@ -725,6 +731,19 @@ export interface NewBranch extends BranchSharedData, RequiredBranchSharedData {
|
|
|
725
731
|
*/
|
|
726
732
|
export type Branch = NewBranch | LegacyBranch;
|
|
727
733
|
export declare const checkIsNewBranch: (branch: Branch) => branch is NewBranch;
|
|
734
|
+
/** Identifies a single branch by its project and branch name. */
|
|
735
|
+
export declare const BranchIdentifierSchema: z.ZodObject<{
|
|
736
|
+
projectId: z.ZodString;
|
|
737
|
+
branchName: z.ZodString;
|
|
738
|
+
}, z.core.$strip>;
|
|
739
|
+
export type BranchIdentifier = z.infer<typeof BranchIdentifierSchema>;
|
|
740
|
+
/** Query params for `DELETE /projects/branches`. */
|
|
741
|
+
export declare const DeleteBranchOptionsSchema: z.ZodObject<{
|
|
742
|
+
projectId: z.ZodString;
|
|
743
|
+
branchName: z.ZodString;
|
|
744
|
+
hard: z.ZodDefault<z.ZodCodec<z.ZodString, z.ZodBoolean>>;
|
|
745
|
+
}, z.core.$strip>;
|
|
746
|
+
export type DeleteBranchOptions = z.input<typeof DeleteBranchOptionsSchema>;
|
|
728
747
|
/**
|
|
729
748
|
* Request options for `GET /projects/branches/list`. Owner/org scope comes from
|
|
730
749
|
* the authenticated request context; `ownerId` here is a superuser-only override.
|
|
@@ -829,6 +848,11 @@ export declare const ShapeOptionSchema: z.ZodObject<{
|
|
|
829
848
|
designSystemName: z.ZodString;
|
|
830
849
|
}, z.core.$strip>], "kind">>>;
|
|
831
850
|
}, z.core.$strip>>;
|
|
851
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
852
|
+
delegate: "delegate";
|
|
853
|
+
"figma-link": "figma-link";
|
|
854
|
+
upload: "upload";
|
|
855
|
+
}>>;
|
|
832
856
|
}, z.core.$strip>;
|
|
833
857
|
export type ShapeOption = z.infer<typeof ShapeOptionSchema>;
|
|
834
858
|
export declare const ShapeQuestionSchema: z.ZodObject<{
|
|
@@ -853,14 +877,32 @@ export declare const ShapeQuestionSchema: z.ZodObject<{
|
|
|
853
877
|
designSystemName: z.ZodString;
|
|
854
878
|
}, z.core.$strip>], "kind">>>;
|
|
855
879
|
}, z.core.$strip>>;
|
|
880
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
881
|
+
delegate: "delegate";
|
|
882
|
+
"figma-link": "figma-link";
|
|
883
|
+
upload: "upload";
|
|
884
|
+
}>>;
|
|
856
885
|
}, z.core.$strip>>;
|
|
857
886
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
858
887
|
}, z.core.$strip>;
|
|
859
888
|
export type ShapeQuestion = z.infer<typeof ShapeQuestionSchema>;
|
|
889
|
+
/**
|
|
890
|
+
* The link in canonical form, or undefined when it is not an https link to a
|
|
891
|
+
* file on figma.com. Deliberately strict: the result is written into the
|
|
892
|
+
* user's repo and handed to the agent as a requirement.
|
|
893
|
+
*/
|
|
894
|
+
export declare function parseFigmaFileUrl(value: string): string | undefined;
|
|
895
|
+
/**
|
|
896
|
+
* The first Figma file link in `text`, canonicalized by `parseFigmaFileUrl`.
|
|
897
|
+
* Bare and `http:` mentions count as https; trailing punctuation is dropped.
|
|
898
|
+
*/
|
|
899
|
+
export declare function findFigmaFileUrl(text: string): string | undefined;
|
|
900
|
+
export declare function mentionsFigmaFileUrl(text: string): boolean;
|
|
860
901
|
export declare const ShapeAnswerSchema: z.ZodObject<{
|
|
861
902
|
questionId: z.ZodString;
|
|
862
903
|
optionId: z.ZodOptional<z.ZodString>;
|
|
863
904
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
905
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
864
906
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
865
907
|
skipped: z.ZodBoolean;
|
|
866
908
|
delegated: z.ZodBoolean;
|
|
@@ -878,6 +920,7 @@ export declare const ShapeAnswerInputSchema: z.ZodObject<{
|
|
|
878
920
|
questionId: z.ZodString;
|
|
879
921
|
optionId: z.ZodOptional<z.ZodString>;
|
|
880
922
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
923
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
881
924
|
}, z.core.$strip>;
|
|
882
925
|
export type ShapeAnswerInput = z.infer<typeof ShapeAnswerInputSchema>;
|
|
883
926
|
export declare const GetShapeQuestionnaireOptionsSchema: z.ZodObject<{
|
|
@@ -893,6 +936,7 @@ export declare const SubmitShapeAnswersOptionsSchema: z.ZodObject<{
|
|
|
893
936
|
questionId: z.ZodString;
|
|
894
937
|
optionId: z.ZodOptional<z.ZodString>;
|
|
895
938
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
939
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
896
940
|
}, z.core.$strip>>;
|
|
897
941
|
}, z.core.$strip>;
|
|
898
942
|
export type SubmitShapeAnswersOptions = z.infer<typeof SubmitShapeAnswersOptionsSchema>;
|
|
@@ -968,6 +1012,11 @@ export declare const ShapeSessionSchema: z.ZodObject<{
|
|
|
968
1012
|
designSystemName: z.ZodString;
|
|
969
1013
|
}, z.core.$strip>], "kind">>>;
|
|
970
1014
|
}, z.core.$strip>>;
|
|
1015
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
1016
|
+
delegate: "delegate";
|
|
1017
|
+
"figma-link": "figma-link";
|
|
1018
|
+
upload: "upload";
|
|
1019
|
+
}>>;
|
|
971
1020
|
}, z.core.$strip>>;
|
|
972
1021
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
973
1022
|
}, z.core.$strip>>;
|
|
@@ -976,6 +1025,7 @@ export declare const ShapeSessionSchema: z.ZodObject<{
|
|
|
976
1025
|
questionId: z.ZodString;
|
|
977
1026
|
optionId: z.ZodOptional<z.ZodString>;
|
|
978
1027
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
1028
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
979
1029
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
980
1030
|
skipped: z.ZodBoolean;
|
|
981
1031
|
delegated: z.ZodBoolean;
|
|
@@ -1041,6 +1091,11 @@ export declare const ShapeSessionDocSchema: z.ZodObject<{
|
|
|
1041
1091
|
designSystemName: z.ZodString;
|
|
1042
1092
|
}, z.core.$strip>], "kind">>>;
|
|
1043
1093
|
}, z.core.$strip>>;
|
|
1094
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
1095
|
+
delegate: "delegate";
|
|
1096
|
+
"figma-link": "figma-link";
|
|
1097
|
+
upload: "upload";
|
|
1098
|
+
}>>;
|
|
1044
1099
|
}, z.core.$strip>>;
|
|
1045
1100
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
1046
1101
|
}, z.core.$strip>>;
|
|
@@ -1049,6 +1104,7 @@ export declare const ShapeSessionDocSchema: z.ZodObject<{
|
|
|
1049
1104
|
questionId: z.ZodString;
|
|
1050
1105
|
optionId: z.ZodOptional<z.ZodString>;
|
|
1051
1106
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
1107
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
1052
1108
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
1053
1109
|
skipped: z.ZodBoolean;
|
|
1054
1110
|
delegated: z.ZodBoolean;
|
|
@@ -1868,7 +1924,14 @@ export interface Project {
|
|
|
1868
1924
|
projectType?: "app" | "repo-indexing";
|
|
1869
1925
|
/** Custom domains associated with this project. */
|
|
1870
1926
|
domains?: string[];
|
|
1871
|
-
/**
|
|
1927
|
+
/**
|
|
1928
|
+
* Which members of the owning space can access the project. `"public"` (shown
|
|
1929
|
+
* as "Team" in the UI, and the behavior when absent) admits every space
|
|
1930
|
+
* member, subject to any project limits on their org role; `"private"` admits
|
|
1931
|
+
* only the roles and users in {@link Project.projectAccess}. Org admins and
|
|
1932
|
+
* the project's creator always have access. Grants nothing outside the
|
|
1933
|
+
* space — see {@link Project.isPublic}.
|
|
1934
|
+
*/
|
|
1872
1935
|
accessMode?: "public" | "private";
|
|
1873
1936
|
/** Fine-grained access control configuration for the project. */
|
|
1874
1937
|
projectAccess?: ProjectAccessControl;
|
|
@@ -1878,7 +1941,12 @@ export interface Project {
|
|
|
1878
1941
|
screenshot: string | null;
|
|
1879
1942
|
/** When true, this project is a built-in example shown to new users. */
|
|
1880
1943
|
isExample?: boolean;
|
|
1881
|
-
/**
|
|
1944
|
+
/**
|
|
1945
|
+
* When true, signed-in users outside the owning space can view and clone the
|
|
1946
|
+
* project. Only example projects and connected fusion-starter projects can be
|
|
1947
|
+
* made public. Independent of {@link Project.accessMode}, which governs members
|
|
1948
|
+
* of the owning space.
|
|
1949
|
+
*/
|
|
1882
1950
|
isPublic?: boolean;
|
|
1883
1951
|
/** Volume snapshot metadata for restoring container state. */
|
|
1884
1952
|
snapshotVolume?: {
|
|
@@ -2202,6 +2270,11 @@ export declare const ProjectSourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2202
2270
|
templateId: z.ZodString;
|
|
2203
2271
|
}, z.core.$strip>], "kind">;
|
|
2204
2272
|
export type ProjectSource = z.infer<typeof ProjectSourceSchema>;
|
|
2273
|
+
/** Query string of `GET /projects`. Only `limit` is validated here so far. */
|
|
2274
|
+
export declare const GetProjectsQuerySchema: z.ZodObject<{
|
|
2275
|
+
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
2276
|
+
}, z.core.$strip>;
|
|
2277
|
+
export type GetProjectsQuery = z.infer<typeof GetProjectsQuerySchema>;
|
|
2205
2278
|
/**
|
|
2206
2279
|
* Request body for `POST /projects/create`. Identity/credentials come from the
|
|
2207
2280
|
* authenticated request context, never the body.
|
|
@@ -3169,6 +3242,12 @@ export declare const DeployFailureReportSchema: z.ZodObject<{
|
|
|
3169
3242
|
excerpt: z.ZodOptional<z.ZodString>;
|
|
3170
3243
|
}, z.core.$strip>;
|
|
3171
3244
|
export type DeployFailureReport = z.infer<typeof DeployFailureReportSchema>;
|
|
3245
|
+
export declare const DeployFixNotRequestedReasonSchema: z.ZodEnum<{
|
|
3246
|
+
error: "error";
|
|
3247
|
+
"no-branch": "no-branch";
|
|
3248
|
+
"send-failed": "send-failed";
|
|
3249
|
+
}>;
|
|
3250
|
+
export type DeployFixNotRequestedReason = z.infer<typeof DeployFixNotRequestedReasonSchema>;
|
|
3172
3251
|
export declare const DeployFailureSchema: z.ZodObject<{
|
|
3173
3252
|
stage: z.ZodOptional<z.ZodEnum<{
|
|
3174
3253
|
build: "build";
|
|
@@ -3188,6 +3267,11 @@ export declare const DeployFailureSchema: z.ZodObject<{
|
|
|
3188
3267
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
3189
3268
|
signal: z.ZodOptional<z.ZodString>;
|
|
3190
3269
|
fixRequested: z.ZodOptional<z.ZodBoolean>;
|
|
3270
|
+
fixNotRequestedReason: z.ZodOptional<z.ZodEnum<{
|
|
3271
|
+
error: "error";
|
|
3272
|
+
"no-branch": "no-branch";
|
|
3273
|
+
"send-failed": "send-failed";
|
|
3274
|
+
}>>;
|
|
3191
3275
|
}, z.core.$strip>;
|
|
3192
3276
|
export type DeployFailure = z.infer<typeof DeployFailureSchema>;
|
|
3193
3277
|
export declare const DeploySchema: z.ZodObject<{
|
|
@@ -3239,6 +3323,11 @@ export declare const DeploySchema: z.ZodObject<{
|
|
|
3239
3323
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
3240
3324
|
signal: z.ZodOptional<z.ZodString>;
|
|
3241
3325
|
fixRequested: z.ZodOptional<z.ZodBoolean>;
|
|
3326
|
+
fixNotRequestedReason: z.ZodOptional<z.ZodEnum<{
|
|
3327
|
+
error: "error";
|
|
3328
|
+
"no-branch": "no-branch";
|
|
3329
|
+
"send-failed": "send-failed";
|
|
3330
|
+
}>>;
|
|
3242
3331
|
}, z.core.$strip>>;
|
|
3243
3332
|
createdAt: z.ZodNumber;
|
|
3244
3333
|
completedAt: z.ZodOptional<z.ZodNumber>;
|
|
@@ -3365,6 +3454,11 @@ export declare const DeployListItemSchema: z.ZodObject<{
|
|
|
3365
3454
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
3366
3455
|
signal: z.ZodOptional<z.ZodString>;
|
|
3367
3456
|
fixRequested: z.ZodOptional<z.ZodBoolean>;
|
|
3457
|
+
fixNotRequestedReason: z.ZodOptional<z.ZodEnum<{
|
|
3458
|
+
error: "error";
|
|
3459
|
+
"no-branch": "no-branch";
|
|
3460
|
+
"send-failed": "send-failed";
|
|
3461
|
+
}>>;
|
|
3368
3462
|
}, z.core.$strip>>;
|
|
3369
3463
|
createdAt: z.ZodNumber;
|
|
3370
3464
|
completedAt: z.ZodOptional<z.ZodNumber>;
|
|
@@ -3625,6 +3719,11 @@ export declare const GetDeploysResponseSchema: z.ZodObject<{
|
|
|
3625
3719
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
3626
3720
|
signal: z.ZodOptional<z.ZodString>;
|
|
3627
3721
|
fixRequested: z.ZodOptional<z.ZodBoolean>;
|
|
3722
|
+
fixNotRequestedReason: z.ZodOptional<z.ZodEnum<{
|
|
3723
|
+
error: "error";
|
|
3724
|
+
"no-branch": "no-branch";
|
|
3725
|
+
"send-failed": "send-failed";
|
|
3726
|
+
}>>;
|
|
3628
3727
|
}, z.core.$strip>>;
|
|
3629
3728
|
createdAt: z.ZodNumber;
|
|
3630
3729
|
completedAt: z.ZodOptional<z.ZodNumber>;
|
|
@@ -3936,6 +4035,24 @@ export declare const EnsureMainBranchExistsOptionsSchema: z.ZodObject<{
|
|
|
3936
4035
|
branchName: z.ZodString;
|
|
3937
4036
|
}, z.core.$strip>;
|
|
3938
4037
|
export type EnsureMainBranchExistsOptions = z.infer<typeof EnsureMainBranchExistsOptionsSchema>;
|
|
4038
|
+
/** Request body for `POST /projects/ensure-fusion-config`. */
|
|
4039
|
+
export declare const EnsureFusionConfigParamsSchema: z.ZodObject<{
|
|
4040
|
+
projectId: z.ZodString;
|
|
4041
|
+
branchName: z.ZodString;
|
|
4042
|
+
includeBackupMetadata: z.ZodOptional<z.ZodBoolean>;
|
|
4043
|
+
volumeMountPath: z.ZodOptional<z.ZodString>;
|
|
4044
|
+
isLocal: z.ZodOptional<z.ZodBoolean>;
|
|
4045
|
+
nativeApp: z.ZodOptional<z.ZodBoolean>;
|
|
4046
|
+
miseLocationPath: z.ZodOptional<z.ZodString>;
|
|
4047
|
+
_useNI: z.ZodOptional<z.ZodBoolean>;
|
|
4048
|
+
fusionEnvironment: z.ZodOptional<z.ZodEnum<{
|
|
4049
|
+
cloud: "cloud";
|
|
4050
|
+
"cloud-v2": "cloud-v2";
|
|
4051
|
+
"container-less": "container-less";
|
|
4052
|
+
containerized: "containerized";
|
|
4053
|
+
}>>;
|
|
4054
|
+
}, z.core.$strip>;
|
|
4055
|
+
export type EnsureFusionConfigParams = z.infer<typeof EnsureFusionConfigParamsSchema>;
|
|
3939
4056
|
/**
|
|
3940
4057
|
* `settings.environmentVariables` is stored with **plaintext** secret values;
|
|
3941
4058
|
* secrets are masked before this shape leaves ai-services, same as
|
package/src/projects.js
CHANGED
|
@@ -200,9 +200,27 @@ export const ProjectSkillSchema = z
|
|
|
200
200
|
ProjectSkillUrlSchema,
|
|
201
201
|
])
|
|
202
202
|
.meta({ title: "ProjectSkill" });
|
|
203
|
+
export const FusionExecutionEnvironmentSchema = z.enum([
|
|
204
|
+
"containerized",
|
|
205
|
+
"container-less",
|
|
206
|
+
"cloud",
|
|
207
|
+
"cloud-v2",
|
|
208
|
+
]);
|
|
203
209
|
export const checkIsNewBranch = (branch) => {
|
|
204
210
|
return "projectId" in branch;
|
|
205
211
|
};
|
|
212
|
+
/** Identifies a single branch by its project and branch name. */
|
|
213
|
+
export const BranchIdentifierSchema = z.object({
|
|
214
|
+
projectId: z.string().min(1),
|
|
215
|
+
branchName: z.string().min(1),
|
|
216
|
+
});
|
|
217
|
+
/** Query params for `DELETE /projects/branches`. */
|
|
218
|
+
export const DeleteBranchOptionsSchema = z.object({
|
|
219
|
+
...BranchIdentifierSchema.shape,
|
|
220
|
+
hard: z.stringbool().default(false).meta({
|
|
221
|
+
description: 'Permanently delete the branch instead of soft-deleting it ("true" / "false").',
|
|
222
|
+
}),
|
|
223
|
+
});
|
|
206
224
|
/**
|
|
207
225
|
* Request options for `GET /projects/branches/list`. Owner/org scope comes from
|
|
208
226
|
* the authenticated request context; `ownerId` here is a superuser-only override.
|
|
@@ -310,6 +328,11 @@ export const ShapeOptionSchema = z.object({
|
|
|
310
328
|
id: z.string(),
|
|
311
329
|
label: z.string(),
|
|
312
330
|
effect: ShapeOptionEffectSchema.optional(),
|
|
331
|
+
/**
|
|
332
|
+
* How the client renders an option that is not a plain choice. Absent means
|
|
333
|
+
* a choice when `effect` is set, delegation otherwise.
|
|
334
|
+
*/
|
|
335
|
+
kind: z.enum(["upload", "delegate", "figma-link"]).optional(),
|
|
313
336
|
});
|
|
314
337
|
export const ShapeQuestionSchema = z.object({
|
|
315
338
|
id: z.string(),
|
|
@@ -318,10 +341,57 @@ export const ShapeQuestionSchema = z.object({
|
|
|
318
341
|
options: z.array(ShapeOptionSchema),
|
|
319
342
|
guessOptionId: z.string().optional(),
|
|
320
343
|
});
|
|
344
|
+
/** Figma paths that name a file, which is what the Builder Design tools read. */
|
|
345
|
+
const FIGMA_FILE_PATH = /^\/(?:design|file|proto|board|slides|make)\/[A-Za-z0-9]+/;
|
|
346
|
+
/**
|
|
347
|
+
* The link in canonical form, or undefined when it is not an https link to a
|
|
348
|
+
* file on figma.com. Deliberately strict: the result is written into the
|
|
349
|
+
* user's repo and handed to the agent as a requirement.
|
|
350
|
+
*/
|
|
351
|
+
export function parseFigmaFileUrl(value) {
|
|
352
|
+
let url;
|
|
353
|
+
try {
|
|
354
|
+
url = new URL(value.trim());
|
|
355
|
+
}
|
|
356
|
+
catch (_a) {
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
const isFigmaHost = url.hostname === "figma.com" || url.hostname === "www.figma.com";
|
|
360
|
+
if (url.protocol !== "https:" ||
|
|
361
|
+
!isFigmaHost ||
|
|
362
|
+
url.port ||
|
|
363
|
+
url.username ||
|
|
364
|
+
url.password ||
|
|
365
|
+
!FIGMA_FILE_PATH.test(url.pathname)) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
return url.href;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Lenient on purpose: users paste bare links, so any mention counts. Not one
|
|
372
|
+
* inside another URL's path or after an `@`, which would name a different host.
|
|
373
|
+
*/
|
|
374
|
+
const FIGMA_FILE_MENTION = /(?:^|[^a-z0-9.\/@-])(?:https?:\/\/)?((?:www\.)?figma\.com\/(?:design|file|proto|board|slides|make)\/[a-z0-9]+[^\s<>()[\]{}"'`]*)/i;
|
|
375
|
+
/**
|
|
376
|
+
* The first Figma file link in `text`, canonicalized by `parseFigmaFileUrl`.
|
|
377
|
+
* Bare and `http:` mentions count as https; trailing punctuation is dropped.
|
|
378
|
+
*/
|
|
379
|
+
export function findFigmaFileUrl(text) {
|
|
380
|
+
var _a;
|
|
381
|
+
const mention = (_a = FIGMA_FILE_MENTION.exec(text)) === null || _a === void 0 ? void 0 : _a[1];
|
|
382
|
+
if (!mention)
|
|
383
|
+
return undefined;
|
|
384
|
+
return parseFigmaFileUrl(`https://${mention.replace(/[.,;:!?]+$/, "")}`);
|
|
385
|
+
}
|
|
386
|
+
export function mentionsFigmaFileUrl(text) {
|
|
387
|
+
return findFigmaFileUrl(text) !== undefined;
|
|
388
|
+
}
|
|
321
389
|
export const ShapeAnswerSchema = z.object({
|
|
322
390
|
questionId: z.string(),
|
|
323
391
|
optionId: z.string().optional(),
|
|
324
392
|
designSystemId: z.string().optional(),
|
|
393
|
+
/** Set only for the Figma link option, canonicalized by `parseFigmaFileUrl`. */
|
|
394
|
+
figmaUrl: z.string().optional(),
|
|
325
395
|
/**
|
|
326
396
|
* Server-resolved from `designSystemId` against the caller's accessible
|
|
327
397
|
* design systems. `settings.designSystems` is matched by name downstream, so
|
|
@@ -338,6 +408,7 @@ const ShapeAnswerInputBaseSchema = ShapeAnswerSchema.pick({
|
|
|
338
408
|
questionId: true,
|
|
339
409
|
optionId: true,
|
|
340
410
|
designSystemId: true,
|
|
411
|
+
figmaUrl: true,
|
|
341
412
|
skipped: true,
|
|
342
413
|
delegated: true,
|
|
343
414
|
});
|
|
@@ -354,6 +425,14 @@ export const ShapeAnswerInputSchema = z.object({
|
|
|
354
425
|
.trim()
|
|
355
426
|
.min(1)
|
|
356
427
|
.optional(),
|
|
428
|
+
figmaUrl: ShapeAnswerInputBaseSchema.shape.figmaUrl
|
|
429
|
+
.unwrap()
|
|
430
|
+
.trim()
|
|
431
|
+
.max(2048)
|
|
432
|
+
.refine((value) => parseFigmaFileUrl(value) !== undefined, {
|
|
433
|
+
message: "Must be a link to a Figma file",
|
|
434
|
+
})
|
|
435
|
+
.optional(),
|
|
357
436
|
});
|
|
358
437
|
export const GetShapeQuestionnaireOptionsSchema = z.object({
|
|
359
438
|
projectId: z.string().trim().min(1),
|
|
@@ -1023,6 +1102,11 @@ export const ProjectSourceSchema = z.discriminatedUnion("kind", [
|
|
|
1023
1102
|
z.object({ kind: z.literal("repo"), repoUrl: z.string().url() }),
|
|
1024
1103
|
z.object({ kind: z.literal("template"), templateId: z.string() }),
|
|
1025
1104
|
]);
|
|
1105
|
+
/** Query string of `GET /projects`. Only `limit` is validated here so far. */
|
|
1106
|
+
export const GetProjectsQuerySchema = z.object({
|
|
1107
|
+
/** At most this many projects, counted after access, hidden and DSI filtering. */
|
|
1108
|
+
limit: z.coerce.number().int().min(1).max(1000).optional(),
|
|
1109
|
+
});
|
|
1026
1110
|
/**
|
|
1027
1111
|
* Request body for `POST /projects/create`. Identity/credentials come from the
|
|
1028
1112
|
* authenticated request context, never the body.
|
|
@@ -1416,6 +1500,11 @@ export const DeployFailureReportSchema = z.object({
|
|
|
1416
1500
|
description: "Head-and-tail excerpt of the failing output, cut on line boundaries. Event only, never persisted.",
|
|
1417
1501
|
}),
|
|
1418
1502
|
});
|
|
1503
|
+
export const DeployFixNotRequestedReasonSchema = z.enum([
|
|
1504
|
+
"no-branch",
|
|
1505
|
+
"send-failed",
|
|
1506
|
+
"error",
|
|
1507
|
+
]);
|
|
1419
1508
|
export const DeployFailureSchema = z.object({
|
|
1420
1509
|
stage: DeployFailureStageSchema.optional(),
|
|
1421
1510
|
owner: DeployFailureOwnerSchema,
|
|
@@ -1430,6 +1519,9 @@ export const DeployFailureSchema = z.object({
|
|
|
1430
1519
|
fixRequested: z.boolean().optional().meta({
|
|
1431
1520
|
description: "Whether a Fusion agent fix was dispatched for this failure.",
|
|
1432
1521
|
}),
|
|
1522
|
+
fixNotRequestedReason: DeployFixNotRequestedReasonSchema.optional().meta({
|
|
1523
|
+
description: "Why a fix this failure qualified for was not dispatched. Absent when the failure never qualified.",
|
|
1524
|
+
}),
|
|
1433
1525
|
});
|
|
1434
1526
|
export const DeploySchema = z.object({
|
|
1435
1527
|
id: z.string(),
|
|
@@ -2214,6 +2306,32 @@ export const EnsureMainBranchExistsOptionsSchema = z.object({
|
|
|
2214
2306
|
description: "Branch whose head ref seeds the main branch when it doesn't exist yet. No-op for non-internalHost projects.",
|
|
2215
2307
|
}),
|
|
2216
2308
|
});
|
|
2309
|
+
/** Request body for `POST /projects/ensure-fusion-config`. */
|
|
2310
|
+
export const EnsureFusionConfigParamsSchema = z.object({
|
|
2311
|
+
projectId: z.string().min(1),
|
|
2312
|
+
branchName: z.string().min(1),
|
|
2313
|
+
includeBackupMetadata: z.boolean().optional().meta({
|
|
2314
|
+
description: "Whether to include backup metadata in the fusion config. This involves checking backup data and generating download URLs. Defaults to false.",
|
|
2315
|
+
}),
|
|
2316
|
+
volumeMountPath: z.string().optional().meta({
|
|
2317
|
+
description: 'Volume mount path for the container. Defaults to "/app" if not specified.',
|
|
2318
|
+
}),
|
|
2319
|
+
isLocal: z.boolean().optional().meta({
|
|
2320
|
+
description: "Flag for local execution mode. When true, adjusts paths for local execution (e.g., ./workspace instead of /app/workspace).",
|
|
2321
|
+
}),
|
|
2322
|
+
nativeApp: z.boolean().optional().meta({
|
|
2323
|
+
description: "Flag for native app projects. When true, adds nativeApp: true to fusion config.",
|
|
2324
|
+
}),
|
|
2325
|
+
miseLocationPath: z.string().optional().meta({
|
|
2326
|
+
description: "Path to mise installation. Provided by client from desktop app system info.",
|
|
2327
|
+
}),
|
|
2328
|
+
_useNI: z.boolean().optional().meta({
|
|
2329
|
+
description: "Flag to use NI for package management. When true, uses NI for package management. Defaults to true.",
|
|
2330
|
+
}),
|
|
2331
|
+
fusionEnvironment: FusionExecutionEnvironmentSchema.optional().meta({
|
|
2332
|
+
description: "Fusion environment type override. When not provided, the environment is resolved from branch/project settings.",
|
|
2333
|
+
}),
|
|
2334
|
+
});
|
|
2217
2335
|
/**
|
|
2218
2336
|
* `settings.environmentVariables` is stored with **plaintext** secret values;
|
|
2219
2337
|
* secrets are masked before this shape leaves ai-services, same as
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { DeleteBranchOptionsSchema, EnsureFusionConfigParamsSchema, } from "./projects.js";
|
|
3
|
+
describe("DeleteBranchOptionsSchema", () => {
|
|
4
|
+
const ids = { projectId: "p1", branchName: "main" };
|
|
5
|
+
it("defaults hard to false", () => {
|
|
6
|
+
expect(DeleteBranchOptionsSchema.parse(ids)).toEqual({
|
|
7
|
+
...ids,
|
|
8
|
+
hard: false,
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
it("parses hard from its query-string form", () => {
|
|
12
|
+
expect(DeleteBranchOptionsSchema.parse({ ...ids, hard: "true" }).hard).toBe(true);
|
|
13
|
+
expect(DeleteBranchOptionsSchema.parse({ ...ids, hard: "false" }).hard).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
it("rejects a hard value that isn't a boolean string", () => {
|
|
16
|
+
expect(DeleteBranchOptionsSchema.safeParse({ ...ids, hard: "maybe" }).success).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it("requires a non-empty projectId and branchName", () => {
|
|
19
|
+
expect(DeleteBranchOptionsSchema.safeParse({}).success).toBe(false);
|
|
20
|
+
expect(DeleteBranchOptionsSchema.safeParse({ projectId: "", branchName: "main" })
|
|
21
|
+
.success).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("EnsureFusionConfigParamsSchema", () => {
|
|
25
|
+
const ids = { projectId: "p1", branchName: "main" };
|
|
26
|
+
it("accepts just the identifiers", () => {
|
|
27
|
+
expect(EnsureFusionConfigParamsSchema.parse(ids)).toEqual(ids);
|
|
28
|
+
});
|
|
29
|
+
it("requires a non-empty projectId and branchName", () => {
|
|
30
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({ ...ids, projectId: "" })
|
|
31
|
+
.success).toBe(false);
|
|
32
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({ projectId: "p1" }).success).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it("rejects an unknown fusionEnvironment", () => {
|
|
35
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({
|
|
36
|
+
...ids,
|
|
37
|
+
fusionEnvironment: "mainframe",
|
|
38
|
+
}).success).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
package/src/projects.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { AGENT_NATIVE_STARTER_REPO, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, getProjectState, GetShapeQuestionnaireOptionsSchema, InitialPromptSchema, isProjectDeleted, matchesAgentNativeStarter, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
|
|
2
|
+
import { AGENT_NATIVE_STARTER_REPO, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, getProjectState, GetShapeQuestionnaireOptionsSchema, InitialPromptSchema, isProjectDeleted, matchesAgentNativeStarter, findFigmaFileUrl, mentionsFigmaFileUrl, parseFigmaFileUrl, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
|
|
3
3
|
describe("project hosting schemas", () => {
|
|
4
4
|
it("accepts the canonical published branch route", () => {
|
|
5
5
|
expect(ProjectHostingSchema.parse({ publishedBranchId: "branch-live" })).toEqual({ publishedBranchId: "branch-live" });
|
|
@@ -112,6 +112,92 @@ describe("guided onboarding project settings", () => {
|
|
|
112
112
|
answers: [],
|
|
113
113
|
})).toThrow();
|
|
114
114
|
});
|
|
115
|
+
it("accepts a Figma file link on an answer and rejects anything else", () => {
|
|
116
|
+
var _a, _b;
|
|
117
|
+
const submit = (figmaUrl) => SubmitShapeAnswersOptionsSchema.safeParse({
|
|
118
|
+
projectId: "project-1",
|
|
119
|
+
questionnaireId: "questionnaire-1",
|
|
120
|
+
answers: [
|
|
121
|
+
{
|
|
122
|
+
questionId: "visual-style",
|
|
123
|
+
optionId: "figma-link",
|
|
124
|
+
figmaUrl,
|
|
125
|
+
skipped: false,
|
|
126
|
+
delegated: false,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
expect((_b = (_a = submit(" https://www.figma.com/design/AbC123/App ").data) === null || _a === void 0 ? void 0 : _a.answers[0]) === null || _b === void 0 ? void 0 : _b.figmaUrl).toBe("https://www.figma.com/design/AbC123/App");
|
|
131
|
+
expect(submit("https://example.com/design/AbC123").success).toBe(false);
|
|
132
|
+
expect(submit("").success).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("parseFigmaFileUrl", () => {
|
|
136
|
+
it.each([
|
|
137
|
+
"https://www.figma.com/design/AbC123/My-App?node-id=1-2",
|
|
138
|
+
"https://figma.com/file/AbC123/Old-Style",
|
|
139
|
+
" https://www.figma.com/proto/AbC123/Flow ",
|
|
140
|
+
])("accepts %s", (value) => {
|
|
141
|
+
expect(parseFigmaFileUrl(value)).toBe(new URL(value.trim()).href);
|
|
142
|
+
});
|
|
143
|
+
it.each([
|
|
144
|
+
"",
|
|
145
|
+
"not a url",
|
|
146
|
+
"http://www.figma.com/design/AbC123/My-App",
|
|
147
|
+
"https://evil.com/figma.com/design/AbC123",
|
|
148
|
+
"https://www.figma.com.evil.com/design/AbC123",
|
|
149
|
+
"https://www.figma.com/community/file/123",
|
|
150
|
+
"https://www.figma.com/design/",
|
|
151
|
+
"https://user:pass@www.figma.com/design/AbC123",
|
|
152
|
+
"https://www.figma.com:8443/design/AbC123",
|
|
153
|
+
"javascript:alert(1)",
|
|
154
|
+
])("rejects %j", (value) => {
|
|
155
|
+
expect(parseFigmaFileUrl(value)).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("mentionsFigmaFileUrl", () => {
|
|
159
|
+
it.each([
|
|
160
|
+
"Build this https://www.figma.com/design/AbC123/My-App please",
|
|
161
|
+
"from figma.com/file/AbC123",
|
|
162
|
+
"(https://figma.com/proto/AbC123)",
|
|
163
|
+
])("finds a link in %j", (text) => {
|
|
164
|
+
expect(mentionsFigmaFileUrl(text)).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
it.each([
|
|
167
|
+
"Make it look like our Figma mockups",
|
|
168
|
+
"https://notfigma.com/design/AbC123",
|
|
169
|
+
"https://www.figma.com/community",
|
|
170
|
+
"https://evil.com/figma.com/design/AbC123",
|
|
171
|
+
"https://evil.com/?next=//figma.com/design/AbC123",
|
|
172
|
+
"user@figma.com/design/AbC123",
|
|
173
|
+
])("finds nothing in %j", (text) => {
|
|
174
|
+
expect(mentionsFigmaFileUrl(text)).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe("findFigmaFileUrl", () => {
|
|
178
|
+
it.each([
|
|
179
|
+
[
|
|
180
|
+
"Build this https://www.figma.com/design/AbC123/App?node-id=1-2.",
|
|
181
|
+
"https://www.figma.com/design/AbC123/App?node-id=1-2",
|
|
182
|
+
],
|
|
183
|
+
[
|
|
184
|
+
"from figma.com/file/AbC123/Old, thanks",
|
|
185
|
+
"https://figma.com/file/AbC123/Old",
|
|
186
|
+
],
|
|
187
|
+
[
|
|
188
|
+
"(http://www.figma.com/proto/AbC123/Flow)",
|
|
189
|
+
"https://www.figma.com/proto/AbC123/Flow",
|
|
190
|
+
],
|
|
191
|
+
[
|
|
192
|
+
"first https://www.figma.com/design/One/A then https://www.figma.com/design/Two/B",
|
|
193
|
+
"https://www.figma.com/design/One/A",
|
|
194
|
+
],
|
|
195
|
+
])("reads the link out of %j", (text, expected) => {
|
|
196
|
+
expect(findFigmaFileUrl(text)).toBe(expected);
|
|
197
|
+
});
|
|
198
|
+
it("finds nothing without a file link", () => {
|
|
199
|
+
expect(findFigmaFileUrl("Make it like our Figma mockups")).toBeUndefined();
|
|
200
|
+
});
|
|
115
201
|
});
|
|
116
202
|
describe("matchesAgentNativeStarter", () => {
|
|
117
203
|
it("matches when repoName is the starter", () => {
|