@builder.io/ai-utils 0.76.4 → 0.79.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.76.4",
3
+ "version": "0.79.1",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
package/src/codegen.d.ts CHANGED
@@ -837,6 +837,8 @@ export declare const ProposedConfigSchema: z.ZodObject<{
837
837
  createdAt: z.ZodNumber;
838
838
  updatedAt: z.ZodNumber;
839
839
  ownerId: z.ZodString;
840
+ userInitiated: z.ZodBoolean;
841
+ autoApply: z.ZodBoolean;
840
842
  state: z.ZodEnum<{
841
843
  "code-change-required": "code-change-required";
842
844
  "empty-project": "empty-project";
@@ -1211,7 +1213,6 @@ export declare const SpawnBranchToolInputSchema: z.ZodObject<{
1211
1213
  }>>;
1212
1214
  attachment_urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
1213
1215
  git_base_branch: z.ZodOptional<z.ZodString>;
1214
- auto_archive_on_idle: z.ZodOptional<z.ZodBoolean>;
1215
1216
  }, z.core.$strip>;
1216
1217
  export type SpawnBranchToolInput = z.infer<typeof SpawnBranchToolInputSchema>;
1217
1218
  export declare const CreateProjectToolInputSchema: z.ZodObject<{
@@ -1923,7 +1924,6 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
1923
1924
  }>>;
1924
1925
  attachment_urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
1925
1926
  git_base_branch: z.ZodOptional<z.ZodString>;
1926
- auto_archive_on_idle: z.ZodOptional<z.ZodBoolean>;
1927
1927
  }, z.core.$strip>;
1928
1928
  CreateProject: z.ZodObject<{
1929
1929
  repo_url: z.ZodString;
@@ -2897,7 +2897,7 @@ export type CodeGenInputOptions = z.infer<typeof CodeGenInputOptionsSchema> & {
2897
2897
  */
2898
2898
  _mcpClientWrapperFactory?: (realClient: any) => any;
2899
2899
  };
2900
- export type CodeGenErrorCodes = "credits-limit-daily" | "credits-limit-monthly" | "credits-limit-user" | "credits-limit-other" | "cli-genetic-error" | "git-update-error" | "prompt-too-long" | "context-too-long" | "abrupt-end" | "unknown" | "failed-recover-state" | "completion-expired" | "ask-to-continue" | "bad-initial-url" | "bad-smart-export-payload" | "invalid-last-message" | "corrupted-session" | "privacy-mode-key-required" | "privacy-mode-key-invalid" | "cli-network-error" | "invalid-credentials" | "model-restricted-too-large" | "org-no-models-enabled" | "assertion" | "rate-limit" | "unknown-design-system";
2900
+ export type CodeGenErrorCodes = "credits-limit-daily" | "credits-limit-monthly" | "credits-limit-user" | "credits-limit-other" | "cli-genetic-error" | "git-update-error" | "prompt-too-long" | "context-too-long" | "abrupt-end" | "unknown" | "failed-recover-state" | "completion-expired" | "ask-to-continue" | "bad-initial-url" | "bad-smart-export-payload" | "invalid-last-message" | "corrupted-session" | "privacy-mode-key-required" | "privacy-mode-key-invalid" | "privacy-mode-key-mismatch" | "cli-network-error" | "invalid-credentials" | "model-restricted-too-large" | "org-no-models-enabled" | "assertion" | "rate-limit" | "unknown-design-system";
2901
2901
  export interface CodegenUsage {
2902
2902
  total: number;
2903
2903
  fast: number;
@@ -3700,6 +3700,25 @@ export interface GetSessionTurnsResult {
3700
3700
  sessionMode?: SessionMode;
3701
3701
  hasPlanToApply?: boolean;
3702
3702
  metadata?: Record<string, any>;
3703
+ /** SHA-256(JWK) of the key this session is encrypted with. Presence ⟹ private. */
3704
+ encryptKeyHash?: string;
3705
+ /** Org requires new sessions to be private; derived per-request, not stored. */
3706
+ privacyModeRequired?: boolean;
3707
+ }
3708
+ /**
3709
+ * Body for `POST /codegen/settings`. All context is optional; the server
3710
+ * resolves settings for the narrowest scope it can, falling back to org.
3711
+ */
3712
+ export declare const CodegenSettingsRequestSchema: z.ZodObject<{
3713
+ sessionId: z.ZodOptional<z.ZodString>;
3714
+ projectName: z.ZodOptional<z.ZodString>;
3715
+ branchName: z.ZodOptional<z.ZodString>;
3716
+ repoHash: z.ZodOptional<z.ZodString>;
3717
+ }, z.core.$strip>;
3718
+ export type CodegenSettingsRequest = z.infer<typeof CodegenSettingsRequestSchema>;
3719
+ /** Load-independent client settings. v1 carries only the privacy gate. */
3720
+ export interface CodegenSettingsResult {
3721
+ privacyModeRequired?: boolean;
3703
3722
  }
3704
3723
  export interface CodegenFeedback {
3705
3724
  id: string;
@@ -3788,6 +3807,7 @@ export interface GenerateCodeEventUser {
3788
3807
  id: string;
3789
3808
  previousId: string | undefined;
3790
3809
  displayPrompt: string | undefined;
3810
+ attachments?: Array<Attachment>;
3791
3811
  user: UserSource;
3792
3812
  compacting: boolean;
3793
3813
  sessionMode: SessionMode;
@@ -3974,6 +3994,12 @@ export interface WorkspaceFolder {
3974
3994
  name?: string;
3975
3995
  originalRepoUrl?: string;
3976
3996
  repoUrl?: string;
3997
+ /**
3998
+ * Read-only source to clone when bootstrapping the repo. When set, the CLI clones
3999
+ * this instead of `repoUrl`, then sets origin to `repoUrl` (the real push remote).
4000
+ * Optional, so older CLIs/configs that ignore it stay compatible.
4001
+ */
4002
+ templateRepoUrl?: string;
3977
4003
  repoName?: string;
3978
4004
  resetGit?: boolean;
3979
4005
  branchName?: string;
@@ -4001,6 +4027,8 @@ export interface GitRepoContext {
4001
4027
  repoUrl?: string;
4002
4028
  /** Clean repo URL without auth tokens, for stable storage and refs */
4003
4029
  originalRepoUrl?: string;
4030
+ /** Read-only source to clone when bootstrapping (distinct from the push remote). */
4031
+ templateRepoUrl?: string;
4004
4032
  /** Repo name (e.g., owner/repo) */
4005
4033
  repoName?: string;
4006
4034
  /**
@@ -4149,6 +4177,8 @@ export interface FusionConfig {
4149
4177
  */
4150
4178
  figmaDecodeJobId?: string;
4151
4179
  featureBranch?: string;
4180
+ /** When set, init checks out this exact git commit after cloning featureBranch. */
4181
+ checkoutCommit?: string;
4152
4182
  aiBranch?: string;
4153
4183
  /** Whether this is a fork PR - affects git operations (read-only, can't push) */
4154
4184
  isFork?: boolean;
@@ -4787,5 +4817,10 @@ export interface SessionData {
4787
4817
  numUserMessages: number;
4788
4818
  numNormalUserMessages: number;
4789
4819
  metadata?: Record<string, any>;
4820
+ /**
4821
+ * SHA-256(JWK) of the encryption key this session is encrypted with.
4822
+ * Presence makes the session private (sticky — no downgrade to plaintext).
4823
+ */
4824
+ encryptKeyHash?: string;
4790
4825
  }
4791
4826
  export {};
package/src/codegen.js CHANGED
@@ -1025,6 +1025,8 @@ export const ProposedConfigSchema = z
1025
1025
  createdAt: z.number(),
1026
1026
  updatedAt: z.number(),
1027
1027
  ownerId: z.string(),
1028
+ userInitiated: z.boolean(),
1029
+ autoApply: z.boolean(),
1028
1030
  state: ExitStateSchema.meta({
1029
1031
  description: "Configuration state from Exit tool",
1030
1032
  }),
@@ -1245,7 +1247,6 @@ export const SpawnBranchToolInputSchema = z
1245
1247
  model: z.enum(["auto", "opus", "sonnet", "haiku"]).optional(),
1246
1248
  attachment_urls: z.array(z.string()).optional(),
1247
1249
  git_base_branch: z.string().optional(),
1248
- auto_archive_on_idle: z.boolean().optional(),
1249
1250
  })
1250
1251
  .meta({ title: "SpawnBranchToolInput" });
1251
1252
  export const CreateProjectToolInputSchema = z
@@ -1976,6 +1977,18 @@ export const GenerateUserMessageSchema = z
1976
1977
  }),
1977
1978
  })
1978
1979
  .meta({ title: "GenerateUserMessage" });
1980
+ /**
1981
+ * Body for `POST /codegen/settings`. All context is optional; the server
1982
+ * resolves settings for the narrowest scope it can, falling back to org.
1983
+ */
1984
+ export const CodegenSettingsRequestSchema = z
1985
+ .object({
1986
+ sessionId: z.string().optional(),
1987
+ projectName: z.string().optional(),
1988
+ branchName: z.string().optional(),
1989
+ repoHash: z.string().optional(),
1990
+ })
1991
+ .meta({ title: "CodegenSettingsRequest" });
1979
1992
  /**
1980
1993
  * Request for generating a commit message via LLM
1981
1994
  */
@@ -53,7 +53,7 @@ export interface GenerateDesignSystemErrorResponse {
53
53
  }
54
54
  export declare const GENERATE_DESIGN_SYSTEM_MAX_FILE_BYTES: number;
55
55
  export declare const GENERATE_DESIGN_SYSTEM_MAX_ATTACHMENTS = 50;
56
- export declare const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 1;
56
+ export declare const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 0;
57
57
  export declare const generateDesignSystemBodySchema: z.ZodObject<{
58
58
  projectName: z.ZodOptional<z.ZodString>;
59
59
  devToolsVersion: z.ZodOptional<z.ZodString>;
@@ -7,7 +7,7 @@ import { z } from "zod";
7
7
  export const GITHUB_REPO_URL_REGEX = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\.git)?\/?$/;
8
8
  export const GENERATE_DESIGN_SYSTEM_MAX_FILE_BYTES = 2 * 1024 * 1024 * 1024;
9
9
  export const GENERATE_DESIGN_SYSTEM_MAX_ATTACHMENTS = 50;
10
- export const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 1;
10
+ export const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 0;
11
11
  export const generateDesignSystemBodySchema = z.object({
12
12
  projectName: z.string().trim().min(1).max(200).optional(),
13
13
  devToolsVersion: z.string().trim().min(1).max(64).optional(),
package/src/events.d.ts CHANGED
@@ -1219,6 +1219,18 @@ export declare const ClientDevtoolsToolResultV1: {
1219
1219
  eventName: "client.devtools.tool.result";
1220
1220
  version: "1";
1221
1221
  };
1222
+ export type ClientDevtoolsBuildMigratedV1 = FusionEventVariant<"client.devtools.build.migrated", {
1223
+ deployId: string;
1224
+ projectId: string;
1225
+ migrationApplied?: boolean;
1226
+ }, {
1227
+ projectId: string;
1228
+ deployId: string;
1229
+ }, 1>;
1230
+ export declare const ClientDevtoolsBuildMigratedV1: {
1231
+ eventName: "client.devtools.build.migrated";
1232
+ version: "1";
1233
+ };
1222
1234
  export type ClientDevtoolsBuildCompletedV1 = FusionEventVariant<"client.devtools.build.completed", {
1223
1235
  deployId: string;
1224
1236
  projectId: string;
@@ -1233,6 +1245,16 @@ export declare const ClientDevtoolsBuildCompletedV1: {
1233
1245
  export type ClientDevtoolsBuildUploadedV1 = FusionEventVariant<"client.devtools.build.uploaded", {
1234
1246
  deployId: string;
1235
1247
  projectId: string;
1248
+ /** Git commit SHA the deploy pod built (git rev-parse HEAD). */
1249
+ gitCommit?: string;
1250
+ /**
1251
+ * Production env from the repo's `builder.config.json` (`hosting.environment.prod`).
1252
+ * The file only exists on the deploy pod, so the pod transports it here for the
1253
+ * service to merge with the Firestore prod env. These are committed plaintext
1254
+ * values with no secret concept; Firestore prod env (which can be secret) is read
1255
+ * directly in the handler and is not sent through the event.
1256
+ */
1257
+ prodEnvFromBuilderConfig?: Record<string, string>;
1236
1258
  }, {
1237
1259
  projectId: string;
1238
1260
  deployId: string;
@@ -1264,7 +1286,7 @@ export declare const McpPrototypePulledV1: {
1264
1286
  eventName: "mcp.prototype.pulled";
1265
1287
  version: "1";
1266
1288
  };
1267
- export type FusionEvent = ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | ClientDevtoolsToolCallRequestV1 | ClientDevtoolsToolCallV1 | ClientDevtoolsToolResultV1 | ClientDevtoolsBuildCompletedV1 | ClientDevtoolsBuildUploadedV1 | ClientDevtoolsBuildFailedV1 | FusionProjectCreatedV1 | SetupAgentCompletedV1 | GitPrMergedV1 | GitPrCreatedV1 | GitPrClosedV1 | ForceSetupAgentV1 | ClawMessageSentV1 | CodegenCompletionV1 | CodegenUserPromptV1 | GitWebhooksRegisterV1 | FusionProjectSettingsUpdatedV1 | VideoRecordingCompletedV1 | TimelineRecordingReadyV1 | FusionBranchCreatedV1 | FusionContainerStartedV1 | FusionContainerFailedV1 | FusionBranchFailedV1 | BotMentionGitHubExternalPrV1 | BotMentionGitHubInternalPrV1 | BotMentionGitLabPrV1 | BotMentionBitbucketPrV1 | BotMentionAzurePrV1 | ReviewSubmittedV1 | PrReviewRequestedV1 | FigmaDecodeJobV1 | ProjectSnapshotRefreshV1 | ProjectSnapshotCapturedV1 | ProjectSnapshotCreatedV1 | ProjectSnapshotFailedV1 | ProjectSnapshotReadyCheckV1 | ProjectSnapshotPodWatchV1 | McpPrototypePulledV1;
1289
+ export type FusionEvent = ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | ClientDevtoolsToolCallRequestV1 | ClientDevtoolsToolCallV1 | ClientDevtoolsToolResultV1 | ClientDevtoolsBuildMigratedV1 | ClientDevtoolsBuildCompletedV1 | ClientDevtoolsBuildUploadedV1 | ClientDevtoolsBuildFailedV1 | FusionProjectCreatedV1 | SetupAgentCompletedV1 | GitPrMergedV1 | GitPrCreatedV1 | GitPrClosedV1 | ForceSetupAgentV1 | ClawMessageSentV1 | CodegenCompletionV1 | CodegenUserPromptV1 | GitWebhooksRegisterV1 | FusionProjectSettingsUpdatedV1 | VideoRecordingCompletedV1 | TimelineRecordingReadyV1 | FusionBranchCreatedV1 | FusionContainerStartedV1 | FusionContainerFailedV1 | FusionBranchFailedV1 | BotMentionGitHubExternalPrV1 | BotMentionGitHubInternalPrV1 | BotMentionGitLabPrV1 | BotMentionBitbucketPrV1 | BotMentionAzurePrV1 | ReviewSubmittedV1 | PrReviewRequestedV1 | FigmaDecodeJobV1 | ProjectSnapshotRefreshV1 | ProjectSnapshotCapturedV1 | ProjectSnapshotCreatedV1 | ProjectSnapshotFailedV1 | ProjectSnapshotReadyCheckV1 | ProjectSnapshotPodWatchV1 | McpPrototypePulledV1;
1268
1290
  export interface ModelPermissionRequiredEvent {
1269
1291
  type: "assistant.model.permission.required";
1270
1292
  data: {
package/src/events.js CHANGED
@@ -142,6 +142,10 @@ export const ClientDevtoolsToolResultV1 = {
142
142
  eventName: "client.devtools.tool.result",
143
143
  version: "1",
144
144
  };
145
+ export const ClientDevtoolsBuildMigratedV1 = {
146
+ eventName: "client.devtools.build.migrated",
147
+ version: "1",
148
+ };
145
149
  export const ClientDevtoolsBuildCompletedV1 = {
146
150
  eventName: "client.devtools.build.completed",
147
151
  version: "1",
@@ -71,6 +71,8 @@ interface OrganizationSettings {
71
71
  enableOrgInsights?: boolean;
72
72
  enableBuilderHosting?: boolean;
73
73
  enableFusionHosting?: boolean;
74
+ netlifyAXPartnerAccountId?: string;
75
+ netlifyAXPartnerAccountSlug?: string;
74
76
  allowLegacyPlanSubscriptions?: boolean;
75
77
  enforceMaxUsers?: boolean;
76
78
  ssoRestrictedMode?: boolean;
package/src/projects.d.ts CHANGED
@@ -229,6 +229,7 @@ export type GitConfigs = Record<string, GitConfig>;
229
229
  export declare const EXAMPLE_REPOS: string[];
230
230
  export declare const STARTER_REPO = "BuilderIO/fusion-starter";
231
231
  export declare const DSI_PREVIEW_REPO = "BuilderIO/dsi-starter";
232
+ export declare const AGENT_NATIVE_STARTER_REPO = "BuilderIO/builder-agent-native-starter";
232
233
  export declare const EXAMPLE_OR_STARTER_REPOS: string[];
233
234
  export declare const EXAMPLE_OR_STARTER_REPOS_URLS: string[];
234
235
  export interface GitBackupUploadUrlResult {
@@ -394,9 +395,13 @@ export interface PartialBranchData {
394
395
  lastCommitHash?: GitSnapshot | null;
395
396
  lastCommitDate?: number | null;
396
397
  commitMode?: CommitMode;
398
+ /** @internal When false, merging this branch's PR does not archive it. Seeded from project.settings at creation. */
399
+ autoCloseBranchOnMerge?: boolean;
397
400
  useHomeDir?: boolean;
398
401
  agentType?: AgentType;
399
402
  checkoutBranch?: string | null;
403
+ /** When set, the deploy pod checks out this exact git commit after cloning checkoutBranch. */
404
+ checkoutCommit?: string | null;
400
405
  prNumber?: number;
401
406
  /** Whether this branch is for a fork PR - affects git operations (read-only, can't push) */
402
407
  isFork?: boolean | null;
@@ -548,12 +553,16 @@ export interface BranchSharedData {
548
553
  /** Public kube hostnames for this branch (no scheme), when more than one domain is available. */
549
554
  kubeHostnames?: string[] | null;
550
555
  checkoutBranch?: string | null;
556
+ /** When set, the deploy pod checks out this exact git commit after cloning checkoutBranch. */
557
+ checkoutCommit?: string | null;
551
558
  /** Whether this branch is for a fork PR - affects git operations (read-only, can't push) */
552
559
  isFork?: boolean | null;
553
560
  vscodeTunnelUrl?: string | null;
554
561
  vscodeTunnelName?: string | null;
555
562
  vscodeTunnelExpiresAt?: string | null;
556
563
  commitMode?: CommitMode;
564
+ /** @internal When false, merging this branch's PR does not archive it. Seeded from project.settings at creation. */
565
+ autoCloseBranchOnMerge?: boolean;
557
566
  /** Timestamp when an AI agent started activity on this branch, null when inactive (in milliseconds since epoch) */
558
567
  lastAgentActivityAt?: number | null;
559
568
  /** Timestamp of last activity on this branch - includes both agent and user activity (in milliseconds since epoch) */
@@ -754,6 +763,10 @@ export interface Project {
754
763
  customAgents?: CustomAgentDefinition[];
755
764
  /** How the AI commits changes: direct commits, draft PRs, or ready-for-review PRs. Default: "draft-prs". */
756
765
  commitMode?: CommitMode;
766
+ /** @internal Default for new branches' autoCloseBranchOnMerge. When false, merging a PR does not archive the branch. Read only at branch-creation time. Default: true. */
767
+ autoCloseBranchOnMerge?: boolean;
768
+ /** Whether merging the PR from the editor is enabled. */
769
+ enableMergePR?: boolean;
757
770
  /** Default visibility for new branches: shared (team-visible) or private. Default: "private". */
758
771
  defaultBranchType?: "shared" | "private";
759
772
  /** Custom container image path (e.g. ghcr.io/org/image:tag). Overrides nodeVersion when set. */
@@ -883,6 +896,8 @@ export interface Project {
883
896
  isFromUserTemplate?: boolean;
884
897
  /** ID of the template used to create this project, if any. */
885
898
  templateId?: string | null;
899
+ /** @internal Read-only source repo cloned to bootstrap the project. Immutable. Absent for non-template projects. Distinct from `repoUrl`, which is always the real push remote. */
900
+ templateRepoUrl?: string;
886
901
  /** Local filesystem path for desktop-app projects. */
887
902
  localPath?: string | null;
888
903
  /** The state of the project. Use `isProjectDeleted()` helper for backwards-compatible checks. */
@@ -995,6 +1010,29 @@ export declare const isBranchArchived: (branch: Branch) => boolean;
995
1010
  * Check if a project is deleted, supporting both `state` and legacy `deleted` fields.
996
1011
  */
997
1012
  export declare const isProjectDeleted: (project: Project) => boolean;
1013
+ /**
1014
+ * Canonical "is this project connected to a real remote" predicate. The single
1015
+ * source of truth for "connected", replacing scattered repoFullName-truthiness checks.
1016
+ */
1017
+ export declare const hasConnectedRepo: (project: Pick<Project, "repoUrl">) => boolean;
1018
+ /**
1019
+ * Derived state: a template-derived project that has a clone source but no real
1020
+ * remote yet. Eager creation (v0) keeps this false; it becomes meaningful under
1021
+ * future lazy repo creation.
1022
+ */
1023
+ export declare const isAwaitingRepoCreation: (project: Pick<Project, "templateRepoUrl" | "repoUrl">) => boolean;
1024
+ /**
1025
+ * Derived state: the clone source is a separate template repo, so origin must be
1026
+ * re-pointed to the real remote after cloning. Once the internal-host repo is
1027
+ * seeded the template URL is wiped, so this flips to false and clones target the
1028
+ * real remote directly.
1029
+ */
1030
+ export declare const clonesFromTemplate: (project: Pick<Project, "templateRepoUrl" | "repoUrl">) => boolean;
1031
+ /**
1032
+ * Fail-fast accessor for crash-tier call sites: returns the real remote or throws
1033
+ * a clear error instead of letting `new URL(undefined)` blow up downstream.
1034
+ */
1035
+ export declare const getRepoUrlOrThrow: (project: Pick<Project, "repoUrl">) => string;
998
1036
  export interface ProjectWithBranches extends Project {
999
1037
  branches: Record<string, Branch>;
1000
1038
  }
@@ -1030,7 +1068,43 @@ export interface CreateProjectOptions {
1030
1068
  useInternalHost?: boolean;
1031
1069
  /** Store branches in the standalone `branches` collection vs embedded in the project doc. */
1032
1070
  useBranchesCollection?: boolean;
1071
+ /** @internal Read-only source repo cloned to bootstrap the project. Carried through to Firestore. */
1072
+ templateRepoUrl?: string;
1073
+ /** @internal First-class hosting config copied from the template. Carried through to Firestore. */
1074
+ hosting?: ProjectHosting;
1075
+ /** @internal When true, provision the internalHost repo eagerly at creation. Hardcoded true for v0. */
1076
+ eagerRepoCreate?: boolean;
1033
1077
  }
1078
+ /**
1079
+ * Source-agnostic description of where a new project comes from. A project can be
1080
+ * created from a plain repo URL (connected) or from a template id; template is just
1081
+ * one source kind. Consumed by the shared `createProjectFromSource` create path.
1082
+ */
1083
+ export declare const ProjectSourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1084
+ kind: z.ZodLiteral<"repo">;
1085
+ repoUrl: z.ZodString;
1086
+ }, z.core.$strip>, z.ZodObject<{
1087
+ kind: z.ZodLiteral<"template">;
1088
+ templateId: z.ZodString;
1089
+ }, z.core.$strip>], "kind">;
1090
+ export type ProjectSource = z.infer<typeof ProjectSourceSchema>;
1091
+ /**
1092
+ * Request body for `POST /projects/create`. Identity/credentials come from the
1093
+ * authenticated request context, never the body.
1094
+ */
1095
+ export declare const CreateProjectRequestSchema: z.ZodObject<{
1096
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
1097
+ kind: z.ZodLiteral<"repo">;
1098
+ repoUrl: z.ZodString;
1099
+ }, z.core.$strip>, z.ZodObject<{
1100
+ kind: z.ZodLiteral<"template">;
1101
+ templateId: z.ZodString;
1102
+ }, z.core.$strip>], "kind">;
1103
+ name: z.ZodString;
1104
+ initialMessage: z.ZodOptional<z.ZodString>;
1105
+ designSystems: z.ZodOptional<z.ZodArray<z.ZodString>>;
1106
+ }, z.core.$strip>;
1107
+ export type CreateProjectRequest = z.infer<typeof CreateProjectRequestSchema>;
1034
1108
  export interface BuilderMyContext {
1035
1109
  success: boolean;
1036
1110
  projectId: string;
@@ -1063,6 +1137,8 @@ export interface CreateBranchOptions {
1063
1137
  hidden?: boolean;
1064
1138
  featureFlags?: Record<string, boolean>;
1065
1139
  checkoutBranch?: string | null;
1140
+ /** When set, the deploy pod checks out this exact git commit after cloning checkoutBranch. */
1141
+ checkoutCommit?: string | null;
1066
1142
  canHandleTools?: (keyof CodeGenToolMap)[];
1067
1143
  skipPromptAnalysis?: boolean;
1068
1144
  useKube?: boolean;
@@ -1328,6 +1404,7 @@ export interface ShouldDeletePodResponse {
1328
1404
  /**
1329
1405
  * Deploy lifecycle status:
1330
1406
  * - queued - inital state although we don't currently queue deploys per se
1407
+ * - migrating — deploy pod is preparing production database state before the build
1331
1408
  * - building — deploy pod is running `npm run build`
1332
1409
  * - uploading — build succeeded; artifacts being uploaded to GCS (transient,
1333
1410
  * between `client.devtools.build.completed` and `client.devtools.build.uploaded`)
@@ -1344,12 +1421,13 @@ export declare const DeployStatusSchema: z.ZodEnum<{
1344
1421
  deploying: "deploying";
1345
1422
  failed: "failed";
1346
1423
  live: "live";
1424
+ migrating: "migrating";
1347
1425
  queued: "queued";
1348
1426
  uploading: "uploading";
1349
1427
  }>;
1350
1428
  export type DeployStatus = z.infer<typeof DeployStatusSchema>;
1351
1429
  /** Deploy statuses that are terminal — never transitioned out of. */
1352
- export declare const TERMINAL_DEPLOY_STATUSES: Set<"building" | "canceled" | "deploying" | "failed" | "live" | "queued" | "uploading">;
1430
+ export declare const TERMINAL_DEPLOY_STATUSES: Set<"building" | "canceled" | "deploying" | "failed" | "live" | "migrating" | "queued" | "uploading">;
1353
1431
  export declare const HostingPublishStatusSchema: z.ZodEnum<{
1354
1432
  published: "published";
1355
1433
  publishing: "publishing";
@@ -1405,14 +1483,21 @@ export declare const ProjectHostingSchema: z.ZodObject<{
1405
1483
  deploying: "deploying";
1406
1484
  failed: "failed";
1407
1485
  live: "live";
1486
+ migrating: "migrating";
1408
1487
  queued: "queued";
1409
1488
  uploading: "uploading";
1410
1489
  }>>;
1490
+ publishedCommit: z.ZodOptional<z.ZodString>;
1411
1491
  customDomain: z.ZodOptional<z.ZodString>;
1412
1492
  customDomainVerified: z.ZodOptional<z.ZodBoolean>;
1413
1493
  autoDeploy: z.ZodOptional<z.ZodBoolean>;
1414
1494
  }, z.core.$strip>;
1415
1495
  export type ProjectHosting = z.infer<typeof ProjectHostingSchema>;
1496
+ /**
1497
+ * Canonical "is this project hostable" predicate. Keys off the explicit
1498
+ * `hosting.enabled` flag rather than inferring from build-config presence.
1499
+ */
1500
+ export declare const isProjectHostable: (hosting: Pick<ProjectHosting, "enabled"> | undefined | null) => boolean;
1416
1501
  /**
1417
1502
  * A single deploy record, stored at `deploys/{deployId}`. The Deploy.id is the document key.
1418
1503
  */
@@ -1421,6 +1506,8 @@ export declare const DeploySchema: z.ZodObject<{
1421
1506
  projectId: z.ZodString;
1422
1507
  ownerId: z.ZodString;
1423
1508
  checkoutBranch: z.ZodOptional<z.ZodString>;
1509
+ checkoutCommit: z.ZodOptional<z.ZodString>;
1510
+ builtCommit: z.ZodOptional<z.ZodString>;
1424
1511
  deployBranchId: z.ZodOptional<z.ZodString>;
1425
1512
  deployBranchName: z.ZodOptional<z.ZodString>;
1426
1513
  devBranchId: z.ZodOptional<z.ZodString>;
@@ -1430,11 +1517,13 @@ export declare const DeploySchema: z.ZodObject<{
1430
1517
  deploying: "deploying";
1431
1518
  failed: "failed";
1432
1519
  live: "live";
1520
+ migrating: "migrating";
1433
1521
  queued: "queued";
1434
1522
  uploading: "uploading";
1435
1523
  }>;
1436
1524
  netlifyDeployId: z.ZodOptional<z.ZodString>;
1437
1525
  url: z.ZodOptional<z.ZodString>;
1526
+ migrationApplied: z.ZodOptional<z.ZodBoolean>;
1438
1527
  error: z.ZodOptional<z.ZodString>;
1439
1528
  createdAt: z.ZodNumber;
1440
1529
  completedAt: z.ZodOptional<z.ZodNumber>;
@@ -1490,12 +1579,16 @@ export type HostingLock = z.infer<typeof HostingLockSchema>;
1490
1579
  */
1491
1580
  export declare const DeployListItemSchema: z.ZodObject<{
1492
1581
  id: z.ZodString;
1582
+ checkoutBranch: z.ZodOptional<z.ZodString>;
1583
+ checkoutCommit: z.ZodOptional<z.ZodString>;
1584
+ builtCommit: z.ZodOptional<z.ZodString>;
1493
1585
  status: z.ZodEnum<{
1494
1586
  building: "building";
1495
1587
  canceled: "canceled";
1496
1588
  deploying: "deploying";
1497
1589
  failed: "failed";
1498
1590
  live: "live";
1591
+ migrating: "migrating";
1499
1592
  queued: "queued";
1500
1593
  uploading: "uploading";
1501
1594
  }>;
@@ -1561,6 +1654,7 @@ export type ReserveSlugResponse = z.infer<typeof ReserveSlugResponseSchema>;
1561
1654
  export declare const DeployRequestSchema: z.ZodObject<{
1562
1655
  projectId: z.ZodString;
1563
1656
  checkoutBranch: z.ZodOptional<z.ZodString>;
1657
+ checkoutCommit: z.ZodOptional<z.ZodString>;
1564
1658
  }, z.core.$strip>;
1565
1659
  export type DeployRequest = z.infer<typeof DeployRequestSchema>;
1566
1660
  export declare const DeployResponseSchema: z.ZodObject<{
@@ -1571,6 +1665,7 @@ export declare const DeployResponseSchema: z.ZodObject<{
1571
1665
  deploying: "deploying";
1572
1666
  failed: "failed";
1573
1667
  live: "live";
1668
+ migrating: "migrating";
1574
1669
  queued: "queued";
1575
1670
  uploading: "uploading";
1576
1671
  }>;
@@ -1592,12 +1687,16 @@ export type GetDeploysRequest = z.infer<typeof GetDeploysRequestSchema>;
1592
1687
  export declare const GetDeploysResponseSchema: z.ZodObject<{
1593
1688
  deploys: z.ZodArray<z.ZodObject<{
1594
1689
  id: z.ZodString;
1690
+ checkoutBranch: z.ZodOptional<z.ZodString>;
1691
+ checkoutCommit: z.ZodOptional<z.ZodString>;
1692
+ builtCommit: z.ZodOptional<z.ZodString>;
1595
1693
  status: z.ZodEnum<{
1596
1694
  building: "building";
1597
1695
  canceled: "canceled";
1598
1696
  deploying: "deploying";
1599
1697
  failed: "failed";
1600
1698
  live: "live";
1699
+ migrating: "migrating";
1601
1700
  queued: "queued";
1602
1701
  uploading: "uploading";
1603
1702
  }>;
package/src/projects.js CHANGED
@@ -36,10 +36,12 @@ export const EXAMPLE_REPOS = [
36
36
  ];
37
37
  export const STARTER_REPO = "BuilderIO/fusion-starter";
38
38
  export const DSI_PREVIEW_REPO = "BuilderIO/dsi-starter";
39
+ export const AGENT_NATIVE_STARTER_REPO = "BuilderIO/builder-agent-native-starter";
39
40
  export const EXAMPLE_OR_STARTER_REPOS = [
40
41
  ...EXAMPLE_REPOS,
41
42
  STARTER_REPO,
42
43
  DSI_PREVIEW_REPO,
44
+ AGENT_NATIVE_STARTER_REPO,
43
45
  ];
44
46
  export const EXAMPLE_OR_STARTER_REPOS_URLS = EXAMPLE_OR_STARTER_REPOS.map((repo) => `https://github.com/${repo}`);
45
47
  export const checkIsNewBranch = (branch) => {
@@ -86,6 +88,61 @@ export const isBranchArchived = (branch) => {
86
88
  export const isProjectDeleted = (project) => {
87
89
  return getProjectState(project) === "deleted";
88
90
  };
91
+ /**
92
+ * Canonical "is this project connected to a real remote" predicate. The single
93
+ * source of truth for "connected", replacing scattered repoFullName-truthiness checks.
94
+ */
95
+ export const hasConnectedRepo = (project) => {
96
+ return !!project.repoUrl;
97
+ };
98
+ /**
99
+ * Derived state: a template-derived project that has a clone source but no real
100
+ * remote yet. Eager creation (v0) keeps this false; it becomes meaningful under
101
+ * future lazy repo creation.
102
+ */
103
+ export const isAwaitingRepoCreation = (project) => {
104
+ return !!project.templateRepoUrl && !project.repoUrl;
105
+ };
106
+ /**
107
+ * Derived state: the clone source is a separate template repo, so origin must be
108
+ * re-pointed to the real remote after cloning. Once the internal-host repo is
109
+ * seeded the template URL is wiped, so this flips to false and clones target the
110
+ * real remote directly.
111
+ */
112
+ export const clonesFromTemplate = (project) => {
113
+ return (!!project.templateRepoUrl && project.templateRepoUrl !== project.repoUrl);
114
+ };
115
+ /**
116
+ * Fail-fast accessor for crash-tier call sites: returns the real remote or throws
117
+ * a clear error instead of letting `new URL(undefined)` blow up downstream.
118
+ */
119
+ export const getRepoUrlOrThrow = (project) => {
120
+ if (!project.repoUrl) {
121
+ throw new Error("Project repo has not been created yet");
122
+ }
123
+ return project.repoUrl;
124
+ };
125
+ /**
126
+ * Source-agnostic description of where a new project comes from. A project can be
127
+ * created from a plain repo URL (connected) or from a template id; template is just
128
+ * one source kind. Consumed by the shared `createProjectFromSource` create path.
129
+ */
130
+ export const ProjectSourceSchema = z.discriminatedUnion("kind", [
131
+ z.object({ kind: z.literal("repo"), repoUrl: z.string().url() }),
132
+ z.object({ kind: z.literal("template"), templateId: z.string() }),
133
+ ]);
134
+ /**
135
+ * Request body for `POST /projects/create`. Identity/credentials come from the
136
+ * authenticated request context, never the body.
137
+ */
138
+ export const CreateProjectRequestSchema = z.object({
139
+ source: ProjectSourceSchema,
140
+ name: z.string(),
141
+ /** Optional first message to start the agent with after creation. Template source only (current constraint). */
142
+ initialMessage: z.string().optional(),
143
+ /** Design system ids to seed into project settings at creation. */
144
+ designSystems: z.array(z.string()).optional(),
145
+ });
89
146
  export const MEMORY_PICKED_FIELDS = [
90
147
  "id",
91
148
  "updatedAt",
@@ -181,6 +238,7 @@ export function parseExitPlanMode(chunk) {
181
238
  /**
182
239
  * Deploy lifecycle status:
183
240
  * - queued - inital state although we don't currently queue deploys per se
241
+ * - migrating — deploy pod is preparing production database state before the build
184
242
  * - building — deploy pod is running `npm run build`
185
243
  * - uploading — build succeeded; artifacts being uploaded to GCS (transient,
186
244
  * between `client.devtools.build.completed` and `client.devtools.build.uploaded`)
@@ -194,6 +252,7 @@ export function parseExitPlanMode(chunk) {
194
252
  export const DeployStatusSchema = z.enum([
195
253
  "queued",
196
254
  "building",
255
+ "migrating",
197
256
  "uploading",
198
257
  "deploying",
199
258
  "live",
@@ -261,6 +320,8 @@ export const ProjectHostingSchema = z.object({
261
320
  lastDeployId: z.string().optional(),
262
321
  lastDeployAt: z.number().optional(),
263
322
  lastDeployStatus: DeployStatusSchema.optional(),
323
+ /** Git commit currently live at the project's hosting URL (set on go-live). */
324
+ publishedCommit: z.string().optional(),
264
325
  customDomain: z.string().optional(),
265
326
  customDomainVerified: z.boolean().optional(),
266
327
  autoDeploy: z
@@ -268,6 +329,13 @@ export const ProjectHostingSchema = z.object({
268
329
  .optional()
269
330
  .meta({ description: "auto-deploy on push/merge" }),
270
331
  });
332
+ /**
333
+ * Canonical "is this project hostable" predicate. Keys off the explicit
334
+ * `hosting.enabled` flag rather than inferring from build-config presence.
335
+ */
336
+ export const isProjectHostable = (hosting) => {
337
+ return (hosting === null || hosting === void 0 ? void 0 : hosting.enabled) === true;
338
+ };
271
339
  /**
272
340
  * A single deploy record, stored at `deploys/{deployId}`. The Deploy.id is the document key.
273
341
  */
@@ -283,6 +351,20 @@ export const DeploySchema = z.object({
283
351
  "for row 2 in v2). This is the value passed as `checkoutBranch` when the " +
284
352
  "deploy pod was created.",
285
353
  }),
354
+ checkoutCommit: z
355
+ .string()
356
+ .optional()
357
+ .meta({
358
+ description: "Exact git commit hash deployed. When set, the deploy pod pinned to this " +
359
+ "commit instead of the branch tip.",
360
+ }),
361
+ builtCommit: z
362
+ .string()
363
+ .optional()
364
+ .meta({
365
+ description: "Actual git commit hash built by the deploy pod (from git rev-parse HEAD " +
366
+ "after checkout). Set when build.uploaded fires.",
367
+ }),
286
368
  deployBranchId: z.string().optional().meta({
287
369
  description: 'Fusion branch id of the ephemeral hidden deploy branch (`type: "deploy"`) that ran the build.',
288
370
  }),
@@ -295,6 +377,9 @@ export const DeploySchema = z.object({
295
377
  status: DeployStatusSchema,
296
378
  netlifyDeployId: z.string().optional(),
297
379
  url: z.string().optional(),
380
+ migrationApplied: z.boolean().optional().meta({
381
+ description: "Whether Drizzle migrations were applied during this deploy. Absent when no migration ran.",
382
+ }),
298
383
  error: z.string().optional().meta({
299
384
  description: "Single human-readable line on failure; raw build logs not surfaced in v0",
300
385
  }),
@@ -361,6 +446,9 @@ export const DeployListItemSchema = DeploySchema.pick({
361
446
  createdAt: true,
362
447
  completedAt: true,
363
448
  error: true,
449
+ checkoutBranch: true,
450
+ checkoutCommit: true,
451
+ builtCommit: true,
364
452
  }).meta({ title: "DeployListItem" });
365
453
  /**
366
454
  * Shape of the `manifest.json` the deploy pod uploads to GCS alongside
@@ -486,9 +574,13 @@ export const ReserveSlugRequestSchema = z.object({
486
574
  export const ReserveSlugResponseSchema = z.object({
487
575
  slug: z.string(),
488
576
  });
577
+ const gitCommitHashSchema = z
578
+ .string()
579
+ .regex(/^[0-9a-f]{7,40}$/i, "Must be a valid git commit hash (7–40 hex chars)");
489
580
  export const DeployRequestSchema = z.object({
490
581
  projectId: z.string(),
491
582
  checkoutBranch: z.string().optional(),
583
+ checkoutCommit: gitCommitHashSchema.optional(),
492
584
  });
493
585
  export const DeployResponseSchema = z.object({
494
586
  deployId: z.string(),