siteplane 0.1.42 → 0.1.44

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.
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/bin/run-siteplane.ts
4
- import { randomUUID as randomUUID4 } from "crypto";
5
- import { access as access2, readFile as readFile8 } from "fs/promises";
6
- import { join as join7, resolve } from "path";
4
+ import { randomUUID as randomUUID7 } from "crypto";
5
+ import { access as access6, readFile as readFile13 } from "fs/promises";
6
+ import { join as join12, resolve as resolve4 } from "path";
7
7
 
8
8
  // ../cli/dist/analytics/manifest.js
9
9
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -892,7 +892,7 @@ function redactBookingManifest(value) {
892
892
  var BOOKING_CREATE_PAYLOAD_LIMIT_BYTES = 16 * 1024;
893
893
 
894
894
  // ../shared/dist/bridge-protocol.js
895
- import { z as z15 } from "zod";
895
+ import { z as z16 } from "zod";
896
896
 
897
897
  // ../shared/dist/field-id.js
898
898
  import { z as z9 } from "zod";
@@ -939,21 +939,70 @@ var imageValueSchema = z11.object({
939
939
  ]).optional()
940
940
  });
941
941
 
942
+ // ../shared/dist/setup-deployment.js
943
+ import { z as z12 } from "zod";
944
+ var version = z12.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u);
945
+ var hash = z12.string().regex(/^sha256:[0-9a-f]{64}$/u);
946
+ var setupDeploymentRecordSchema = z12.object({
947
+ version: z12.literal(1),
948
+ operationId: z12.string().uuid(),
949
+ provider: z12.literal("vercel"),
950
+ projectId: z12.string().regex(/^prj_[A-Za-z0-9]+$/u),
951
+ teamId: z12.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u),
952
+ origin: z12.string().url().refine((value) => {
953
+ const url = new URL(value);
954
+ return url.protocol === "https:" && url.origin === value && !url.username && !url.password;
955
+ }),
956
+ deploymentId: z12.string().regex(/^dpl_[A-Za-z0-9]+$/u).nullable(),
957
+ revision: z12.string().regex(/^[0-9a-f]{40}$/u),
958
+ fieldContractHash: hash,
959
+ packages: z12.object({ siteplane: version, runtimeNext: version }).strict(),
960
+ configurationFingerprint: hash,
961
+ adminSecretGeneration: z12.string().uuid(),
962
+ revalidationGeneration: z12.number().int().positive(),
963
+ startedAt: z12.string().datetime(),
964
+ environmentWrittenAt: z12.string().datetime().nullable(),
965
+ deployRequestedAt: z12.string().datetime().nullable(),
966
+ deadline: z12.string().datetime(),
967
+ phase: z12.enum([
968
+ "planned",
969
+ "environment_written",
970
+ "deploy_requested",
971
+ "deployed",
972
+ "verified",
973
+ "failed"
974
+ ]),
975
+ build: z12.object({
976
+ node: version,
977
+ packageManager: z12.enum(["npm", "pnpm"]),
978
+ packageManagerVersion: version,
979
+ lockfileHash: hash
980
+ }).strict().nullable()
981
+ }).strict();
982
+ var setupDeploymentInputSchema = z12.discriminatedUnion("action", [
983
+ z12.object({ action: z12.literal("read") }).strict(),
984
+ z12.object({
985
+ action: z12.literal("record"),
986
+ expectedOperationId: z12.string().uuid().nullable(),
987
+ record: setupDeploymentRecordSchema
988
+ }).strict()
989
+ ]);
990
+
942
991
  // ../shared/dist/site-setup.js
943
- import { z as z14 } from "zod";
992
+ import { z as z15 } from "zod";
944
993
 
945
994
  // ../shared/dist/site-field-contract.js
946
- import { z as z13 } from "zod";
995
+ import { z as z14 } from "zod";
947
996
 
948
997
  // ../shared/dist/fallback-hash.js
949
- import { z as z12 } from "zod";
998
+ import { z as z13 } from "zod";
950
999
  var SAFE_REPRESENTATION_REASONS = [
951
1000
  "asset_import_rewritten",
952
1001
  "relative_url_normalized",
953
1002
  "line_endings_normalized",
954
1003
  "image_value_serialized"
955
1004
  ];
956
- var safeRepresentationReasonSchema = z12.enum(SAFE_REPRESENTATION_REASONS);
1005
+ var safeRepresentationReasonSchema = z13.enum(SAFE_REPRESENTATION_REASONS);
957
1006
  function canonicalizeFallbackValue(input) {
958
1007
  const fieldType = fieldTypeSchema.parse(input.fieldType);
959
1008
  if (input.safeRepresentationReason !== void 0) {
@@ -989,10 +1038,10 @@ function createCanonicalFallbackHash(input) {
989
1038
  const payload = stableJsonStringify(canonical);
990
1039
  return `sha256:${sha256Hex(payload)}`;
991
1040
  }
992
- var linkFallbackSchema = z12.object({
993
- href: z12.string().trim().min(1),
994
- label: z12.string().trim().min(1).optional(),
995
- target: z12.enum(["_self", "_blank"]).optional()
1041
+ var linkFallbackSchema = z13.object({
1042
+ href: z13.string().trim().min(1),
1043
+ label: z13.string().trim().min(1).optional(),
1044
+ target: z13.enum(["_self", "_blank"]).optional()
996
1045
  }).passthrough();
997
1046
  function normalizeLineEndings(value) {
998
1047
  return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -1170,67 +1219,67 @@ var SHA256_CONSTANTS = [
1170
1219
  // ../shared/dist/site-field-contract.js
1171
1220
  var fieldContractVersion = "1.0.0";
1172
1221
  var scannerContractVersion = "1.0.0";
1173
- var siteFieldStatusSchema = z13.enum(["hidden", "active"]);
1174
- var semanticVersionSchema = z13.string().regex(/^\d+\.\d+\.\d+$/u);
1175
- var siteFieldRouteKeySchema = z13.string().trim().refine((value) => value === "$global" || value.startsWith("/") && !value.includes("?") && !value.includes("#") && (value === "/" || !value.endsWith("/")), "Route keys must be canonical paths or $global.");
1176
- var repositoryRelativePosixPathSchema = z13.string().trim().min(1).refine((value) => !value.startsWith("/") && !value.includes("\\") && !/^[a-z]:/iu.test(value) && !value.split("/").includes(".."), "Source paths must be repository-relative POSIX paths.");
1177
- var sourceMappingSchema = z13.object({
1178
- kind: z13.literal("function"),
1222
+ var siteFieldStatusSchema = z14.enum(["hidden", "active"]);
1223
+ var semanticVersionSchema = z14.string().regex(/^\d+\.\d+\.\d+$/u);
1224
+ var siteFieldRouteKeySchema = z14.string().trim().refine((value) => value === "$global" || value.startsWith("/") && !value.includes("?") && !value.includes("#") && (value === "/" || !value.endsWith("/")), "Route keys must be canonical paths or $global.");
1225
+ var repositoryRelativePosixPathSchema = z14.string().trim().min(1).refine((value) => !value.startsWith("/") && !value.includes("\\") && !/^[a-z]:/iu.test(value) && !value.split("/").includes(".."), "Source paths must be repository-relative POSIX paths.");
1226
+ var sourceMappingSchema = z14.object({
1227
+ kind: z14.literal("function"),
1179
1228
  filePath: repositoryRelativePosixPathSchema,
1180
- exportName: z13.string().trim().min(1).optional(),
1181
- sourcePath: z13.string().trim().min(1).optional(),
1229
+ exportName: z14.string().trim().min(1).optional(),
1230
+ sourcePath: z14.string().trim().min(1).optional(),
1182
1231
  editTarget: fieldIdSchema.optional()
1183
1232
  }).strict();
1184
- var domMappingSchema = z13.object({
1185
- attribute: z13.literal("data-siteplane-field-id"),
1186
- previewStrategy: z13.enum(["dom", "event"])
1233
+ var domMappingSchema = z14.object({
1234
+ attribute: z14.literal("data-siteplane-field-id"),
1235
+ previewStrategy: z14.enum(["dom", "event"])
1187
1236
  }).strict();
1188
- var fieldBaseSchema = z13.object({
1237
+ var fieldBaseSchema = z14.object({
1189
1238
  fieldId: fieldIdSchema,
1190
1239
  routeKey: siteFieldRouteKeySchema,
1191
1240
  source: sourceMappingSchema,
1192
1241
  dom: domMappingSchema.optional()
1193
1242
  }).strict();
1194
- var linkFallbackSchema2 = z13.object({
1195
- href: z13.string().trim().min(1),
1196
- label: z13.string().trim().min(1).optional(),
1197
- target: z13.enum(["_self", "_blank"]).optional()
1243
+ var linkFallbackSchema2 = z14.object({
1244
+ href: z14.string().trim().min(1),
1245
+ label: z14.string().trim().min(1).optional(),
1246
+ target: z14.enum(["_self", "_blank"]).optional()
1198
1247
  }).strict();
1199
- var imageFallbackSchema = z13.object({
1200
- src: z13.string().trim().min(1),
1201
- alt: z13.string().trim().max(300),
1202
- width: z13.number().int().positive().optional(),
1203
- height: z13.number().int().positive().optional(),
1204
- crop: z13.object({
1205
- x: z13.number().min(0).max(100),
1206
- y: z13.number().min(0).max(100),
1207
- zoom: z13.number().min(1).max(4),
1208
- aspectRatio: z13.number().positive().max(10)
1248
+ var imageFallbackSchema = z14.object({
1249
+ src: z14.string().trim().min(1),
1250
+ alt: z14.string().trim().max(300),
1251
+ width: z14.number().int().positive().optional(),
1252
+ height: z14.number().int().positive().optional(),
1253
+ crop: z14.object({
1254
+ x: z14.number().min(0).max(100),
1255
+ y: z14.number().min(0).max(100),
1256
+ zoom: z14.number().min(1).max(4),
1257
+ aspectRatio: z14.number().positive().max(10)
1209
1258
  }).strict().optional()
1210
1259
  }).strict();
1211
- var siteFieldContractFieldSchema = z13.discriminatedUnion("fieldType", [
1260
+ var siteFieldContractFieldSchema = z14.discriminatedUnion("fieldType", [
1212
1261
  fieldBaseSchema.extend({
1213
- fieldType: z13.literal("text"),
1214
- fallback: z13.string()
1262
+ fieldType: z14.literal("text"),
1263
+ fallback: z14.string()
1215
1264
  }),
1216
1265
  fieldBaseSchema.extend({
1217
- fieldType: z13.literal("longText"),
1218
- fallback: z13.string()
1266
+ fieldType: z14.literal("longText"),
1267
+ fallback: z14.string()
1219
1268
  }),
1220
1269
  fieldBaseSchema.extend({
1221
- fieldType: z13.literal("link"),
1270
+ fieldType: z14.literal("link"),
1222
1271
  fallback: linkFallbackSchema2
1223
1272
  }),
1224
1273
  fieldBaseSchema.extend({
1225
- fieldType: z13.literal("image"),
1274
+ fieldType: z14.literal("image"),
1226
1275
  fallback: imageFallbackSchema
1227
1276
  })
1228
1277
  ]);
1229
- var siteFieldContractV1Schema = z13.object({
1230
- version: z13.literal(1),
1278
+ var siteFieldContractV1Schema = z14.object({
1279
+ version: z14.literal(1),
1231
1280
  fieldContractVersion: semanticVersionSchema,
1232
1281
  scannerContractVersion: semanticVersionSchema,
1233
- fields: z13.array(siteFieldContractFieldSchema)
1282
+ fields: z14.array(siteFieldContractFieldSchema)
1234
1283
  }).strict().superRefine((contract, context) => {
1235
1284
  const seen = /* @__PURE__ */ new Set();
1236
1285
  for (const [index, field] of contract.fields.entries()) {
@@ -1290,20 +1339,20 @@ var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH = 2e3;
1290
1339
  var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES = 8e3;
1291
1340
  var CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES = 32 * 1024;
1292
1341
  var CONTINUE_SITE_SETUP_HTTP_BODY_MAX_BYTES = 64 * 1024;
1293
- var siteSetupRunStatusSchema = z14.enum(SITE_SETUP_RUN_STATUSES);
1294
- var siteSetupRunModeSchema = z14.enum(SITE_SETUP_RUN_MODES);
1295
- var siteSetupErrorCodeSchema = z14.enum(SITE_SETUP_ERROR_CODES);
1296
- var editorFieldSchema = z14.object({
1342
+ var siteSetupRunStatusSchema = z15.enum(SITE_SETUP_RUN_STATUSES);
1343
+ var siteSetupRunModeSchema = z15.enum(SITE_SETUP_RUN_MODES);
1344
+ var siteSetupErrorCodeSchema = z15.enum(SITE_SETUP_ERROR_CODES);
1345
+ var editorFieldSchema = z15.object({
1297
1346
  fieldId: fieldIdSchema,
1298
- label: z14.string().trim().min(1),
1299
- subsection: z14.string().trim().min(1).optional(),
1300
- description: z14.string().trim().min(1).optional(),
1301
- required: z14.boolean().optional(),
1302
- maxLength: z14.number().int().positive().optional()
1347
+ label: z15.string().trim().min(1),
1348
+ subsection: z15.string().trim().min(1).optional(),
1349
+ description: z15.string().trim().min(1).optional(),
1350
+ required: z15.boolean().optional(),
1351
+ maxLength: z15.number().int().positive().optional()
1303
1352
  }).strict();
1304
- var editorSectionSchema = z14.object({
1305
- label: z14.string().trim().min(1),
1306
- fields: z14.array(editorFieldSchema).min(1)
1353
+ var editorSectionSchema = z15.object({
1354
+ label: z15.string().trim().min(1),
1355
+ fields: z15.array(editorFieldSchema).min(1)
1307
1356
  }).strict().superRefine((section, context) => {
1308
1357
  const closedSubsections = /* @__PURE__ */ new Set();
1309
1358
  let currentSubsection;
@@ -1322,10 +1371,10 @@ var editorSectionSchema = z14.object({
1322
1371
  }
1323
1372
  }
1324
1373
  });
1325
- var editorRouteSchema = z14.object({
1374
+ var editorRouteSchema = z15.object({
1326
1375
  routeKey: siteFieldRouteKeySchema,
1327
- label: z14.string().trim().min(1),
1328
- sections: z14.array(editorSectionSchema).min(1)
1376
+ label: z15.string().trim().min(1),
1377
+ sections: z15.array(editorSectionSchema).min(1)
1329
1378
  }).strict().superRefine((route, context) => {
1330
1379
  const sections = /* @__PURE__ */ new Set();
1331
1380
  for (const [index, section] of route.sections.entries()) {
@@ -1339,9 +1388,9 @@ var editorRouteSchema = z14.object({
1339
1388
  sections.add(section.label);
1340
1389
  }
1341
1390
  });
1342
- var editorDefinitionV1Schema = z14.object({
1343
- version: z14.literal(1),
1344
- routes: z14.array(editorRouteSchema).min(1)
1391
+ var editorDefinitionV1Schema = z15.object({
1392
+ version: z15.literal(1),
1393
+ routes: z15.array(editorRouteSchema).min(1)
1345
1394
  }).strict().superRefine((definition, context) => {
1346
1395
  const routes = /* @__PURE__ */ new Set();
1347
1396
  const fields = /* @__PURE__ */ new Set();
@@ -1379,7 +1428,7 @@ var editorDefinitionV1Schema = z14.object({
1379
1428
  var forbiddenControlOrBidi = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
1380
1429
  var forbiddenOwnerNoteControlOrBidi = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
1381
1430
  var unsafeLocator = /<\/?[a-z][^>]*>|\b(?:javascript|data:text\/html)\s*:|\bon[a-z]+\s*=/iu;
1382
- var renderedPathSchema = z14.string().trim().transform((value) => value !== "/" ? value.replace(/\/+$/u, "") : value).superRefine((value, context) => {
1431
+ var renderedPathSchema = z15.string().trim().transform((value) => value !== "/" ? value.replace(/\/+$/u, "") : value).superRefine((value, context) => {
1383
1432
  if (!value.startsWith("/") || value === "$global" || value.includes("?") || value.includes("#")) {
1384
1433
  context.addIssue({
1385
1434
  code: "custom",
@@ -1389,7 +1438,7 @@ var renderedPathSchema = z14.string().trim().transform((value) => value !== "/"
1389
1438
  addSafeByteIssues(value, CONTINUE_SITE_SETUP_RENDERED_PATH_MAX_BYTES, "renderedPath", context);
1390
1439
  });
1391
1440
  function normalizedSafeTextSchema(maxBytes, label) {
1392
- return z14.string().transform((value) => value.trim().replace(new RegExp("\\p{White_Space}+", "gu"), " ")).pipe(z14.string().min(1)).superRefine((value, context) => {
1441
+ return z15.string().transform((value) => value.trim().replace(new RegExp("\\p{White_Space}+", "gu"), " ")).pipe(z15.string().min(1)).superRefine((value, context) => {
1393
1442
  addSafeByteIssues(value, maxBytes, label, context);
1394
1443
  if (label === "locatorHint" && unsafeLocator.test(value)) {
1395
1444
  context.addIssue({
@@ -1406,12 +1455,12 @@ var correctionItemBase = {
1406
1455
  requestedLabel: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_LABEL_MAX_BYTES, "requestedLabel").optional(),
1407
1456
  requestedSection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SECTION_MAX_BYTES, "requestedSection").optional(),
1408
1457
  requestedSubsection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SUBSECTION_MAX_BYTES, "requestedSubsection").optional(),
1409
- requestedSortOrder: z14.number().int().nonnegative().optional()
1458
+ requestedSortOrder: z15.number().int().nonnegative().optional()
1410
1459
  };
1411
- var setupCorrectionItemSchema = z14.discriminatedUnion("kind", [
1412
- z14.object({ kind: z14.literal("text"), ...correctionItemBase }).strict(),
1413
- z14.object({ kind: z14.literal("link"), ...correctionItemBase }).strict(),
1414
- z14.object({ kind: z14.literal("image"), ...correctionItemBase }).strict()
1460
+ var setupCorrectionItemSchema = z15.discriminatedUnion("kind", [
1461
+ z15.object({ kind: z15.literal("text"), ...correctionItemBase }).strict(),
1462
+ z15.object({ kind: z15.literal("link"), ...correctionItemBase }).strict(),
1463
+ z15.object({ kind: z15.literal("image"), ...correctionItemBase }).strict()
1415
1464
  ]).superRefine((item, context) => {
1416
1465
  if (item.requestedSubsection && !item.requestedSection) {
1417
1466
  context.addIssue({
@@ -1421,7 +1470,7 @@ var setupCorrectionItemSchema = z14.discriminatedUnion("kind", [
1421
1470
  });
1422
1471
  }
1423
1472
  });
1424
- var setupCorrectionItemsSchema = z14.array(setupCorrectionItemSchema).max(CONTINUE_SITE_SETUP_MAX_ITEMS).superRefine((items, context) => {
1473
+ var setupCorrectionItemsSchema = z15.array(setupCorrectionItemSchema).max(CONTINUE_SITE_SETUP_MAX_ITEMS).superRefine((items, context) => {
1425
1474
  const bytes = utf8Bytes(stableJsonStringify(items));
1426
1475
  if (bytes > CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES) {
1427
1476
  context.addIssue({
@@ -1430,7 +1479,7 @@ var setupCorrectionItemsSchema = z14.array(setupCorrectionItemSchema).max(CONTIN
1430
1479
  });
1431
1480
  }
1432
1481
  });
1433
- var siteSetupOwnerEditabilityNoteSchema = z14.string().max(SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH).superRefine((value, context) => {
1482
+ var siteSetupOwnerEditabilityNoteSchema = z15.string().max(SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH).superRefine((value, context) => {
1434
1483
  if (utf8Bytes(value) > SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES) {
1435
1484
  context.addIssue({
1436
1485
  code: "custom",
@@ -1455,7 +1504,7 @@ var SITE_SETUP_MODULE_SCOPES = {
1455
1504
  "analytics:public_key_read"
1456
1505
  ]
1457
1506
  };
1458
- var siteSetupModulesSchema = z14.array(z14.enum(["editing", "analytics"])).min(1).max(2).refine((modules) => modules[0] === "editing" && (modules.length === 1 || modules[1] === "analytics"), "Choose Editing with optional Analytics.");
1507
+ var siteSetupModulesSchema = z15.array(z15.enum(["editing", "analytics"])).min(1).max(2).refine((modules) => modules[0] === "editing" && (modules.length === 1 || modules[1] === "analytics"), "Choose Editing with optional Analytics.");
1459
1508
  function siteSetupScopes(modules) {
1460
1509
  return modules.flatMap((module) => [...SITE_SETUP_MODULE_SCOPES[module]]);
1461
1510
  }
@@ -1463,15 +1512,15 @@ function hasExactSiteSetupScopes(scopes, modules) {
1463
1512
  const matches = (expected) => scopes.length === expected.length && expected.every((scope) => scopes.includes(scope));
1464
1513
  return modules ? matches(siteSetupScopes(modules)) : matches(siteSetupScopes(["editing"])) || matches(siteSetupScopes(["editing", "analytics"]));
1465
1514
  }
1466
- var siteSetupActivityInputSchema = z14.object({
1467
- phase: z14.enum([
1515
+ var siteSetupActivityInputSchema = z15.object({
1516
+ phase: z15.enum([
1468
1517
  "inspecting",
1469
1518
  "integrating",
1470
1519
  "deploying",
1471
1520
  "verifying",
1472
1521
  "repairing"
1473
1522
  ]),
1474
- textId: z14.enum([
1523
+ textId: z15.enum([
1475
1524
  "inspecting",
1476
1525
  "integrating",
1477
1526
  "deploying",
@@ -1480,8 +1529,8 @@ var siteSetupActivityInputSchema = z14.object({
1480
1529
  ])
1481
1530
  }).strict().refine((value) => value.phase === value.textId, "Activity text must describe its phase.");
1482
1531
  var nextActionFields = {
1483
- actor: z14.enum(["agent", "user", "siteplane"]),
1484
- boundary: z14.enum([
1532
+ actor: z15.enum(["agent", "user", "siteplane"]),
1533
+ boundary: z15.enum([
1485
1534
  "source",
1486
1535
  "environment",
1487
1536
  "deployment",
@@ -1489,33 +1538,33 @@ var nextActionFields = {
1489
1538
  "authorization",
1490
1539
  "review"
1491
1540
  ]),
1492
- precondition: z14.string().min(1).max(1e3),
1493
- instruction: z14.string().min(1).max(2e3),
1494
- expectedEvidence: z14.string().min(1).max(1e3)
1541
+ precondition: z15.string().min(1).max(1e3),
1542
+ instruction: z15.string().min(1).max(2e3),
1543
+ expectedEvidence: z15.string().min(1).max(1e3)
1495
1544
  };
1496
- var siteSetupNextActionSchema = z14.discriminatedUnion("kind", [
1497
- z14.object({
1545
+ var siteSetupNextActionSchema = z15.discriminatedUnion("kind", [
1546
+ z15.object({
1498
1547
  ...nextActionFields,
1499
- kind: z14.literal("run_command"),
1500
- command: z14.string().min(1).max(500)
1548
+ kind: z15.literal("run_command"),
1549
+ command: z15.string().min(1).max(500)
1501
1550
  }).strict(),
1502
- z14.object({ ...nextActionFields, kind: z14.literal("agent_edit") }).strict(),
1503
- z14.object({ ...nextActionFields, kind: z14.literal("needs_user_action") }).strict(),
1504
- z14.object({ ...nextActionFields, kind: z14.literal("wait") }).strict(),
1505
- z14.object({ ...nextActionFields, kind: z14.literal("done") }).strict()
1551
+ z15.object({ ...nextActionFields, kind: z15.literal("agent_edit") }).strict(),
1552
+ z15.object({ ...nextActionFields, kind: z15.literal("needs_user_action") }).strict(),
1553
+ z15.object({ ...nextActionFields, kind: z15.literal("wait") }).strict(),
1554
+ z15.object({ ...nextActionFields, kind: z15.literal("done") }).strict()
1506
1555
  ]);
1507
- var siteSetupTaskRunSchema = z14.object({
1508
- runId: z14.string().uuid(),
1556
+ var siteSetupTaskRunSchema = z15.object({
1557
+ runId: z15.string().uuid(),
1509
1558
  mode: siteSetupRunModeSchema,
1510
1559
  status: siteSetupRunStatusSchema,
1511
- fieldContractHash: z14.string().nullable(),
1512
- deploymentOrigin: z14.string().url().nullable(),
1513
- deploymentRevision: z14.string().nullable(),
1514
- publicRuntimeKeyId: z14.string().uuid().nullable(),
1515
- reviewVersion: z14.string().nullable()
1560
+ fieldContractHash: z15.string().nullable(),
1561
+ deploymentOrigin: z15.string().url().nullable(),
1562
+ deploymentRevision: z15.string().nullable(),
1563
+ publicRuntimeKeyId: z15.string().uuid().nullable(),
1564
+ reviewVersion: z15.string().nullable()
1516
1565
  }).strict();
1517
- var siteSetupTaskProgressSchema = z14.object({
1518
- progressStage: z14.enum([
1566
+ var siteSetupTaskProgressSchema = z15.object({
1567
+ progressStage: z15.enum([
1519
1568
  "waiting_for_connection",
1520
1569
  "agent_connected",
1521
1570
  "project_context_loaded",
@@ -1525,66 +1574,73 @@ var siteSetupTaskProgressSchema = z14.object({
1525
1574
  "action_required",
1526
1575
  "completed"
1527
1576
  ]),
1528
- lastVerifiedAt: z14.string().datetime().nullable(),
1529
- lastActivityAt: z14.string().datetime(),
1530
- activitySource: z14.enum(["user", "server", "agent"]),
1577
+ lastVerifiedAt: z15.string().datetime().nullable(),
1578
+ lastActivityAt: z15.string().datetime(),
1579
+ activitySource: z15.enum(["user", "server", "agent"]),
1531
1580
  activityPhase: siteSetupActivityInputSchema.shape.phase.nullable(),
1532
1581
  activityTextId: siteSetupActivityInputSchema.shape.textId.nullable()
1533
1582
  }).strict();
1534
- var siteSetupTaskSchema = z14.object({
1535
- contractVersion: z14.literal("siteplane.setup-task.v2"),
1536
- workflow: z14.enum(["initial_setup", "structure_update"]),
1537
- goal: z14.string().min(1),
1583
+ var siteSetupTaskSchema = z15.object({
1584
+ contractVersion: z15.literal("siteplane.setup-task.v2"),
1585
+ workflow: z15.enum(["initial_setup", "structure_update"]),
1586
+ goal: z15.string().min(1),
1538
1587
  modules: siteSetupModulesSchema,
1539
- authorizationVersion: z14.number().int().positive(),
1540
- authorizedScopes: z14.array(z14.string()).min(2),
1541
- site: z14.object({
1542
- siteId: z14.string().uuid(),
1543
- portalPath: z14.string(),
1544
- adminOrigin: z14.string().url()
1588
+ authorizationVersion: z15.number().int().positive(),
1589
+ authorizedScopes: z15.array(z15.string()).min(2),
1590
+ site: z15.object({
1591
+ siteId: z15.string().uuid(),
1592
+ portalPath: z15.string(),
1593
+ adminOrigin: z15.string().url()
1545
1594
  }).strict().nullable(),
1546
1595
  run: siteSetupTaskRunSchema.nullable(),
1547
1596
  progress: siteSetupTaskProgressSchema.nullable(),
1548
- assignment: z14.literal("owned"),
1549
- deadline: z14.string().datetime().nullable(),
1550
- userInstructions: z14.object({
1597
+ deployment: setupDeploymentRecordSchema.nullable(),
1598
+ revalidationGeneration: z15.number().int().positive(),
1599
+ assignment: z15.literal("owned"),
1600
+ deadline: z15.string().datetime().nullable(),
1601
+ userInstructions: z15.object({
1551
1602
  text: siteSetupOwnerEditabilityNoteSchema,
1552
- source: z14.literal("user"),
1553
- trust: z14.literal("untrusted")
1603
+ source: z15.literal("user"),
1604
+ trust: z15.literal("untrusted")
1554
1605
  }).strict(),
1555
1606
  corrections: setupCorrectionItemsSchema,
1556
- environmentBindings: z14.array(z14.object({
1557
- name: z14.string().regex(/^[A-Z][A-Z0-9_]+$/u),
1558
- source: z14.string().min(1),
1559
- sensitivity: z14.enum(["public", "secret"]),
1560
- usage: z14.enum(["build", "server", "build_and_server"]),
1561
- evidence: z14.string().min(1)
1607
+ contentSelectionSummary: z15.object({
1608
+ text: siteSetupOwnerEditabilityNoteSchema,
1609
+ source: z15.literal("agent"),
1610
+ trust: z15.literal("untrusted")
1611
+ }).strict().nullable(),
1612
+ environmentBindings: z15.array(z15.object({
1613
+ name: z15.string().regex(/^[A-Z][A-Z0-9_]+$/u),
1614
+ source: z15.string().min(1),
1615
+ sensitivity: z15.enum(["public", "secret"]),
1616
+ usage: z15.enum(["build", "server", "build_and_server"]),
1617
+ evidence: z15.string().min(1)
1562
1618
  }).strict()),
1563
1619
  nextAction: siteSetupNextActionSchema,
1564
- error: z14.object({
1565
- code: z14.string().regex(/^[a-z0-9_.]+$/u).max(160),
1620
+ error: z15.object({
1621
+ code: z15.string().regex(/^[a-z0-9_.]+$/u).max(160),
1566
1622
  boundary: nextActionFields.boundary,
1567
1623
  responsibleActor: nextActionFields.actor,
1568
- retryable: z14.boolean(),
1569
- retryAfter: z14.number().int().nonnegative().nullable(),
1570
- requestId: z14.string().regex(/^[A-Za-z0-9_-]+$/u).max(128)
1624
+ retryable: z15.boolean(),
1625
+ retryAfter: z15.number().int().nonnegative().nullable(),
1626
+ requestId: z15.string().regex(/^[A-Za-z0-9_-]+$/u).max(128)
1571
1627
  }).strict().nullable(),
1572
- packages: z14.object({
1573
- siteplane: z14.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
1574
- runtimeNext: z14.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
1628
+ packages: z15.object({
1629
+ siteplane: z15.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
1630
+ runtimeNext: z15.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
1575
1631
  }).strict(),
1576
- communication: z14.object({
1577
- beforeSourceChanges: z14.string().min(1),
1578
- updates: z14.array(z14.string().min(1)).min(1),
1579
- blocker: z14.string().min(1)
1632
+ communication: z15.object({
1633
+ beforeSourceChanges: z15.string().min(1),
1634
+ updates: z15.array(z15.string().min(1)).min(1),
1635
+ blocker: z15.string().min(1)
1580
1636
  }).strict(),
1581
- discovery: z14.object({
1582
- inspectPublicRoutes: z14.boolean(),
1583
- contentKinds: z14.array(z14.enum(["text", "longText", "link", "image"])).min(1),
1584
- rules: z14.array(z14.string().min(1)).min(1)
1637
+ discovery: z15.object({
1638
+ inspectPublicRoutes: z15.boolean(),
1639
+ contentKinds: z15.array(z15.enum(["text", "longText", "link", "image"])).min(1),
1640
+ rules: z15.array(z15.string().min(1)).min(1)
1585
1641
  }).strict(),
1586
- steps: z14.array(z14.object({
1587
- id: z14.enum([
1642
+ steps: z15.array(z15.object({
1643
+ id: z15.enum([
1588
1644
  "inspect_repository",
1589
1645
  "install_packages",
1590
1646
  "instrument_fields",
@@ -1592,34 +1648,35 @@ var siteSetupTaskSchema = z14.object({
1592
1648
  "deploy_production",
1593
1649
  "verify_deployment"
1594
1650
  ]),
1595
- instruction: z14.string().min(1)
1651
+ instruction: z15.string().min(1)
1596
1652
  }).strict()).length(6),
1597
- completion: z14.object({
1598
- verifiedStatus: z14.literal("ready_for_review"),
1599
- instruction: z14.string().min(1)
1653
+ completion: z15.object({
1654
+ verifiedStatus: z15.literal("ready_for_review"),
1655
+ instruction: z15.string().min(1)
1600
1656
  }).strict()
1601
1657
  }).strict().refine((task) => hasExactSiteSetupScopes(task.authorizedScopes, task.modules), "Task scopes must exactly match its modules.");
1602
- var canonicalHashSchema = z14.string().regex(/^sha256:[0-9a-f]{64}$/iu);
1658
+ var canonicalHashSchema = z15.string().regex(/^sha256:[0-9a-f]{64}$/iu);
1603
1659
  var deploymentRevisionSchema = normalizedSafeTextSchema(256, "deploymentRevision");
1604
- var continueSiteSetupInputSchema = z14.object({
1605
- siteId: z14.string().uuid(),
1606
- runId: z14.string().uuid(),
1660
+ var continueSiteSetupInputSchema = z15.object({
1661
+ siteId: z15.string().uuid(),
1662
+ runId: z15.string().uuid(),
1607
1663
  expectedFieldContractHash: canonicalHashSchema,
1608
1664
  expectedDeploymentRevision: deploymentRevisionSchema,
1609
1665
  correctionItems: setupCorrectionItemsSchema,
1610
1666
  ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema.optional()
1611
1667
  }).strict();
1612
- var saveSiteSetupOwnerNoteInputSchema = z14.object({
1613
- siteId: z14.string().uuid(),
1614
- runId: z14.string().uuid(),
1668
+ var saveSiteSetupOwnerNoteInputSchema = z15.object({
1669
+ siteId: z15.string().uuid(),
1670
+ runId: z15.string().uuid(),
1615
1671
  expectedFieldContractHash: canonicalHashSchema,
1616
1672
  expectedDeploymentRevision: deploymentRevisionSchema,
1617
1673
  ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema
1618
1674
  }).strict();
1619
- var siteSetupContextInputSchema = z14.object({}).strict();
1620
- var siteSetupApplyInputSchema = z14.object({
1675
+ var siteSetupContextInputSchema = z15.object({}).strict();
1676
+ var siteSetupApplyInputSchema = z15.object({
1621
1677
  fieldContract: siteFieldContractV1Schema,
1622
- editorDefinition: editorDefinitionV1Schema
1678
+ editorDefinition: editorDefinitionV1Schema,
1679
+ contentSelectionSummary: siteSetupOwnerEditabilityNoteSchema.refine((text) => text.trim().length > 0, "Describe the selected content, important exclusions and any open gaps.")
1623
1680
  }).strict().superRefine((input, context) => {
1624
1681
  const contractRoutesByFieldId = new Map(input.fieldContract.fields.map((field) => [
1625
1682
  field.fieldId,
@@ -1683,37 +1740,37 @@ var siteSetupApplyInputSchema = z14.object({
1683
1740
  }
1684
1741
  }
1685
1742
  });
1686
- var siteSetupVerifyInputSchema = z14.object({
1687
- deploymentUrl: z14.string().url().refine((value) => value.startsWith("https://")),
1743
+ var siteSetupVerifyInputSchema = z15.object({
1744
+ deploymentUrl: z15.string().url().refine((value) => value.startsWith("https://")),
1688
1745
  deploymentRevision: deploymentRevisionSchema,
1689
- wait: z14.boolean().optional()
1746
+ wait: z15.boolean().optional()
1690
1747
  }).strict();
1691
- var siteSetupEvidenceInputSchema = z14.object({
1692
- siteId: z14.string().uuid(),
1693
- runId: z14.string().uuid(),
1748
+ var siteSetupEvidenceInputSchema = z15.object({
1749
+ siteId: z15.string().uuid(),
1750
+ runId: z15.string().uuid(),
1694
1751
  expectedFieldContractHash: canonicalHashSchema,
1695
- expectedDeploymentOrigin: z14.string().url().refine((value) => value.startsWith("https://")),
1752
+ expectedDeploymentOrigin: z15.string().url().refine((value) => value.startsWith("https://")),
1696
1753
  expectedDeploymentRevision: deploymentRevisionSchema,
1697
- publicRuntimeKeyId: z14.string().uuid(),
1754
+ publicRuntimeKeyId: z15.string().uuid(),
1698
1755
  bridgeSessionId: normalizedSafeTextSchema(256, "bridgeSessionId"),
1699
- observations: z14.array(z14.object({
1756
+ observations: z15.array(z15.object({
1700
1757
  fieldId: fieldIdSchema,
1701
1758
  routeKey: siteFieldRouteKeySchema,
1702
1759
  renderedPath: renderedPathSchema,
1703
- targetResolved: z14.boolean(),
1704
- previewAck: z14.boolean()
1760
+ targetResolved: z15.boolean(),
1761
+ previewAck: z15.boolean()
1705
1762
  }).strict().refine((value) => !value.previewAck || value.targetResolved, "Preview ACK requires a resolved target.")).min(1).max(200)
1706
1763
  }).strict();
1707
- var completeSiteSetupInputSchema = z14.object({
1708
- siteId: z14.string().uuid(),
1709
- runId: z14.string().uuid(),
1764
+ var completeSiteSetupInputSchema = z15.object({
1765
+ siteId: z15.string().uuid(),
1766
+ runId: z15.string().uuid(),
1710
1767
  expectedFieldContractHash: canonicalHashSchema,
1711
1768
  expectedDeploymentRevision: deploymentRevisionSchema,
1712
1769
  expectedReadyFingerprint: canonicalHashSchema
1713
1770
  }).strict();
1714
- var refreshSiteSetupDeploymentInputSchema = z14.object({
1715
- siteId: z14.string().uuid(),
1716
- deploymentUrl: z14.string().url().refine((value) => value.startsWith("https://")),
1771
+ var refreshSiteSetupDeploymentInputSchema = z15.object({
1772
+ siteId: z15.string().uuid(),
1773
+ deploymentUrl: z15.string().url().refine((value) => value.startsWith("https://")),
1717
1774
  deploymentRevision: deploymentRevisionSchema
1718
1775
  }).strict();
1719
1776
  function addSafeByteIssues(value, maxBytes, label, context) {
@@ -1736,34 +1793,34 @@ function utf8Bytes(value) {
1736
1793
 
1737
1794
  // ../shared/dist/bridge-protocol.js
1738
1795
  var BRIDGE_PROTOCOL_VERSION = 2;
1739
- var bridgeRectSchema = z15.object({
1740
- x: z15.number(),
1741
- y: z15.number(),
1742
- width: z15.number().nonnegative(),
1743
- height: z15.number().nonnegative()
1796
+ var bridgeRectSchema = z16.object({
1797
+ x: z16.number(),
1798
+ y: z16.number(),
1799
+ width: z16.number().nonnegative(),
1800
+ height: z16.number().nonnegative()
1744
1801
  });
1745
- var previewTextValueSchema = z15.object({
1746
- fieldType: z15.enum(["text", "longText"]),
1747
- value: z15.string()
1802
+ var previewTextValueSchema = z16.object({
1803
+ fieldType: z16.enum(["text", "longText"]),
1804
+ value: z16.string()
1748
1805
  });
1749
- var previewLinkValueSchema = z15.object({
1750
- fieldType: z15.literal("link"),
1751
- value: z15.object({
1752
- href: z15.string().trim().min(1),
1753
- label: z15.string().trim().min(1).optional()
1806
+ var previewLinkValueSchema = z16.object({
1807
+ fieldType: z16.literal("link"),
1808
+ value: z16.object({
1809
+ href: z16.string().trim().min(1),
1810
+ label: z16.string().trim().min(1).optional()
1754
1811
  })
1755
1812
  });
1756
- var previewImageValueSchema = z15.object({
1757
- fieldType: z15.literal("image"),
1813
+ var previewImageValueSchema = z16.object({
1814
+ fieldType: z16.literal("image"),
1758
1815
  value: imageValueSchema
1759
1816
  });
1760
- var bridgePreviewValueSchema = z15.discriminatedUnion("fieldType", [
1817
+ var bridgePreviewValueSchema = z16.discriminatedUnion("fieldType", [
1761
1818
  previewTextValueSchema,
1762
1819
  previewLinkValueSchema,
1763
1820
  previewImageValueSchema
1764
1821
  ]);
1765
- var fieldSelectionModeSchema = z15.enum(["replace", "range", "toggle"]);
1766
- var fieldBridgeMissingContentActionSchema = z15.enum([
1822
+ var fieldSelectionModeSchema = z16.enum(["replace", "range", "toggle"]);
1823
+ var fieldBridgeMissingContentActionSchema = z16.enum([
1767
1824
  "add",
1768
1825
  "select",
1769
1826
  "remove"
@@ -1782,77 +1839,77 @@ var FIELD_BRIDGE_MESSAGE_TYPES = [
1782
1839
  "siteplane:field-bridge:preview-scrolled",
1783
1840
  "siteplane:field-bridge:error"
1784
1841
  ];
1785
- var canonicalFieldContractHashSchema = z15.string().regex(/^sha256:[0-9a-f]{64}$/u);
1786
- var bridgeSectionSchema = z15.string().trim().min(1).max(256);
1787
- var realRenderedPathSchema = z15.string().trim().refine((value) => value.startsWith("/") && value !== "$global" && !value.includes("?") && !value.includes("#"), "A field bridge rendered path must be a real canonical path.");
1788
- var fieldBridgeIdentitySchema = z15.object({
1789
- publicRuntimeKeyId: z15.string().uuid(),
1842
+ var canonicalFieldContractHashSchema = z16.string().regex(/^sha256:[0-9a-f]{64}$/u);
1843
+ var bridgeSectionSchema = z16.string().trim().min(1).max(256);
1844
+ var realRenderedPathSchema = z16.string().trim().refine((value) => value.startsWith("/") && value !== "$global" && !value.includes("?") && !value.includes("#"), "A field bridge rendered path must be a real canonical path.");
1845
+ var fieldBridgeIdentitySchema = z16.object({
1846
+ publicRuntimeKeyId: z16.string().uuid(),
1790
1847
  fieldContractHash: canonicalFieldContractHashSchema,
1791
- deploymentRevision: z15.string().trim().min(1).max(256)
1848
+ deploymentRevision: z16.string().trim().min(1).max(256)
1792
1849
  }).strict();
1793
- var fieldBridgeBaseSchema = z15.object({
1794
- version: z15.literal(BRIDGE_PROTOCOL_VERSION),
1795
- type: z15.enum(FIELD_BRIDGE_MESSAGE_TYPES),
1796
- siteId: z15.string().uuid(),
1797
- sessionId: z15.string().trim().min(1),
1798
- publicRuntimeKeyId: z15.string().uuid(),
1850
+ var fieldBridgeBaseSchema = z16.object({
1851
+ version: z16.literal(BRIDGE_PROTOCOL_VERSION),
1852
+ type: z16.enum(FIELD_BRIDGE_MESSAGE_TYPES),
1853
+ siteId: z16.string().uuid(),
1854
+ sessionId: z16.string().trim().min(1),
1855
+ publicRuntimeKeyId: z16.string().uuid(),
1799
1856
  fieldContractHash: canonicalFieldContractHashSchema,
1800
- deploymentRevision: z15.string().trim().min(1).max(256),
1801
- requestId: z15.string().trim().min(1),
1802
- sentAt: z15.string().datetime()
1857
+ deploymentRevision: z16.string().trim().min(1).max(256),
1858
+ requestId: z16.string().trim().min(1),
1859
+ sentAt: z16.string().datetime()
1803
1860
  }).strict();
1804
- var fieldBridgeFieldSchema = z15.object({
1861
+ var fieldBridgeFieldSchema = z16.object({
1805
1862
  fieldId: fieldIdSchema,
1806
1863
  fieldType: fieldTypeSchema,
1807
1864
  routeKey: siteFieldRouteKeySchema,
1808
1865
  renderedPath: realRenderedPathSchema,
1809
- sourcePath: z15.string().trim().min(1).optional(),
1866
+ sourcePath: z16.string().trim().min(1).optional(),
1810
1867
  editTarget: fieldIdSchema,
1811
1868
  rect: bridgeRectSchema,
1812
- targetResolved: z15.literal(true),
1869
+ targetResolved: z16.literal(true),
1813
1870
  currentValue: bridgePreviewValueSchema.optional()
1814
1871
  }).strict();
1815
1872
  var fieldBridgeInitMessageSchema = fieldBridgeBaseSchema.extend({
1816
- type: z15.literal("siteplane:field-bridge:init"),
1817
- payload: z15.object({
1818
- adminOrigin: z15.string().url(),
1819
- customerOrigin: z15.string().url(),
1873
+ type: z16.literal("siteplane:field-bridge:init"),
1874
+ payload: z16.object({
1875
+ adminOrigin: z16.string().url(),
1876
+ customerOrigin: z16.string().url(),
1820
1877
  renderedPath: realRenderedPathSchema
1821
1878
  }).strict()
1822
1879
  });
1823
1880
  var fieldBridgeReadyMessageSchema = fieldBridgeBaseSchema.extend({
1824
- type: z15.literal("siteplane:field-bridge:ready"),
1825
- payload: z15.object({
1881
+ type: z16.literal("siteplane:field-bridge:ready"),
1882
+ payload: z16.object({
1826
1883
  renderedPath: realRenderedPathSchema,
1827
- fieldCount: z15.number().int().nonnegative(),
1828
- capabilities: z15.tuple([
1829
- z15.literal("field_selection"),
1830
- z15.literal("preview_values"),
1831
- z15.literal("field_evidence"),
1832
- z15.literal("visual_field_control")
1884
+ fieldCount: z16.number().int().nonnegative(),
1885
+ capabilities: z16.tuple([
1886
+ z16.literal("field_selection"),
1887
+ z16.literal("preview_values"),
1888
+ z16.literal("field_evidence"),
1889
+ z16.literal("visual_field_control")
1833
1890
  ])
1834
1891
  }).strict()
1835
1892
  });
1836
1893
  var fieldBridgeFieldsMessageSchema = fieldBridgeBaseSchema.extend({
1837
- type: z15.literal("siteplane:field-bridge:fields"),
1838
- payload: z15.object({
1894
+ type: z16.literal("siteplane:field-bridge:fields"),
1895
+ payload: z16.object({
1839
1896
  renderedPath: realRenderedPathSchema,
1840
- fields: z15.array(fieldBridgeFieldSchema)
1897
+ fields: z16.array(fieldBridgeFieldSchema)
1841
1898
  }).strict()
1842
1899
  });
1843
1900
  var fieldBridgeSelectFieldMessageSchema = fieldBridgeBaseSchema.extend({
1844
- type: z15.literal("siteplane:field-bridge:select-field"),
1845
- payload: z15.object({
1901
+ type: z16.literal("siteplane:field-bridge:select-field"),
1902
+ payload: z16.object({
1846
1903
  fieldId: fieldIdSchema,
1847
1904
  selectionMode: fieldSelectionModeSchema
1848
1905
  }).strict()
1849
1906
  });
1850
1907
  var fieldBridgeSetSelectedFieldMessageSchema = fieldBridgeBaseSchema.extend({
1851
- type: z15.literal("siteplane:field-bridge:set-selected-field"),
1852
- payload: z15.object({
1853
- fieldIds: z15.array(fieldIdSchema).max(200),
1908
+ type: z16.literal("siteplane:field-bridge:set-selected-field"),
1909
+ payload: z16.object({
1910
+ fieldIds: z16.array(fieldIdSchema).max(200),
1854
1911
  primaryFieldId: fieldIdSchema.nullable(),
1855
- scrollIntoView: z15.boolean().optional()
1912
+ scrollIntoView: z16.boolean().optional()
1856
1913
  }).strict().superRefine((value, context) => {
1857
1914
  if (value.fieldIds.length > 0 && value.primaryFieldId === null) {
1858
1915
  context.addIssue({
@@ -1871,58 +1928,58 @@ var fieldBridgeSetSelectedFieldMessageSchema = fieldBridgeBaseSchema.extend({
1871
1928
  })
1872
1929
  });
1873
1930
  var fieldBridgeApplyPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
1874
- type: z15.literal("siteplane:field-bridge:apply-preview-values"),
1875
- payload: z15.object({ values: z15.record(fieldIdSchema, bridgePreviewValueSchema) }).strict()
1931
+ type: z16.literal("siteplane:field-bridge:apply-preview-values"),
1932
+ payload: z16.object({ values: z16.record(fieldIdSchema, bridgePreviewValueSchema) }).strict()
1876
1933
  });
1877
1934
  var fieldBridgeTestPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
1878
- type: z15.literal("siteplane:field-bridge:test-preview-values"),
1879
- payload: z15.object({ fieldIds: z15.array(fieldIdSchema).min(1).max(200) }).strict()
1935
+ type: z16.literal("siteplane:field-bridge:test-preview-values"),
1936
+ payload: z16.object({ fieldIds: z16.array(fieldIdSchema).min(1).max(200) }).strict()
1880
1937
  });
1881
1938
  var fieldBridgePreviewAckMessageSchema = fieldBridgeBaseSchema.extend({
1882
- type: z15.literal("siteplane:field-bridge:preview-ack"),
1883
- payload: z15.object({
1884
- ackRequestId: z15.string().trim().min(1),
1885
- kind: z15.enum(["apply", "test"]),
1939
+ type: z16.literal("siteplane:field-bridge:preview-ack"),
1940
+ payload: z16.object({
1941
+ ackRequestId: z16.string().trim().min(1),
1942
+ kind: z16.enum(["apply", "test"]),
1886
1943
  renderedPath: realRenderedPathSchema,
1887
- fieldIds: z15.array(fieldIdSchema).max(200)
1944
+ fieldIds: z16.array(fieldIdSchema).max(200)
1888
1945
  }).strict()
1889
1946
  });
1890
1947
  var fieldBridgeSetVisualControlStateMessageSchema = fieldBridgeBaseSchema.extend({
1891
- type: z15.literal("siteplane:field-bridge:set-visual-control-state"),
1892
- payload: z15.object({
1893
- enabled: z15.boolean(),
1894
- fieldProximityEnabled: z15.boolean(),
1895
- pendingKeys: z15.array(z15.string().trim().min(1).max(2048)).max(50),
1896
- activeFieldIds: z15.array(fieldIdSchema),
1897
- fieldSections: z15.record(fieldIdSchema, bridgeSectionSchema),
1898
- selectedPending: z15.array(z15.object({
1899
- key: z15.string().trim().min(1).max(2048),
1900
- locatorHint: z15.string().trim().min(1).max(2048)
1948
+ type: z16.literal("siteplane:field-bridge:set-visual-control-state"),
1949
+ payload: z16.object({
1950
+ enabled: z16.boolean(),
1951
+ fieldProximityEnabled: z16.boolean(),
1952
+ pendingKeys: z16.array(z16.string().trim().min(1).max(2048)).max(50),
1953
+ activeFieldIds: z16.array(fieldIdSchema),
1954
+ fieldSections: z16.record(fieldIdSchema, bridgeSectionSchema),
1955
+ selectedPending: z16.array(z16.object({
1956
+ key: z16.string().trim().min(1).max(2048),
1957
+ locatorHint: z16.string().trim().min(1).max(2048)
1901
1958
  }).strict()).max(50),
1902
- scrollPendingIntoView: z15.boolean().optional()
1959
+ scrollPendingIntoView: z16.boolean().optional()
1903
1960
  }).strict()
1904
1961
  });
1905
1962
  var fieldBridgeMissingContentMessageSchema = fieldBridgeBaseSchema.extend({
1906
- type: z15.literal("siteplane:field-bridge:missing-content"),
1907
- payload: z15.object({
1963
+ type: z16.literal("siteplane:field-bridge:missing-content"),
1964
+ payload: z16.object({
1908
1965
  action: fieldBridgeMissingContentActionSchema,
1909
1966
  item: setupCorrectionItemSchema,
1910
1967
  suggestedSection: bridgeSectionSchema.optional()
1911
1968
  }).strict()
1912
1969
  });
1913
1970
  var fieldBridgePreviewScrolledMessageSchema = fieldBridgeBaseSchema.extend({
1914
- type: z15.literal("siteplane:field-bridge:preview-scrolled"),
1915
- payload: z15.object({ renderedPath: realRenderedPathSchema }).strict()
1971
+ type: z16.literal("siteplane:field-bridge:preview-scrolled"),
1972
+ payload: z16.object({ renderedPath: realRenderedPathSchema }).strict()
1916
1973
  });
1917
1974
  var fieldBridgeErrorMessageSchema = fieldBridgeBaseSchema.extend({
1918
- type: z15.literal("siteplane:field-bridge:error"),
1919
- payload: z15.object({
1920
- code: z15.string().trim().min(1),
1921
- message: z15.string().trim().min(1),
1922
- recoverable: z15.boolean().default(false)
1975
+ type: z16.literal("siteplane:field-bridge:error"),
1976
+ payload: z16.object({
1977
+ code: z16.string().trim().min(1),
1978
+ message: z16.string().trim().min(1),
1979
+ recoverable: z16.boolean().default(false)
1923
1980
  }).strict()
1924
1981
  });
1925
- var fieldBridgeMessageSchema = z15.discriminatedUnion("type", [
1982
+ var fieldBridgeMessageSchema = z16.discriminatedUnion("type", [
1926
1983
  fieldBridgeInitMessageSchema,
1927
1984
  fieldBridgeReadyMessageSchema,
1928
1985
  fieldBridgeFieldsMessageSchema,
@@ -1938,51 +1995,51 @@ var fieldBridgeMessageSchema = z15.discriminatedUnion("type", [
1938
1995
  ]);
1939
1996
 
1940
1997
  // ../shared/dist/commands.js
1941
- import { z as z17 } from "zod";
1998
+ import { z as z18 } from "zod";
1942
1999
 
1943
2000
  // ../shared/dist/errors.js
1944
- import { z as z16 } from "zod";
2001
+ import { z as z17 } from "zod";
1945
2002
  var UI_ERROR_CATEGORIES = [
1946
2003
  "site_member",
1947
2004
  "workspace_member",
1948
2005
  "internal"
1949
2006
  ];
1950
- var uiErrorCategorySchema = z16.enum(UI_ERROR_CATEGORIES);
1951
- var commandErrorPayloadSchema = z16.object({
1952
- code: z16.string().min(1),
1953
- message: z16.string().min(1),
2007
+ var uiErrorCategorySchema = z17.enum(UI_ERROR_CATEGORIES);
2008
+ var commandErrorPayloadSchema = z17.object({
2009
+ code: z17.string().min(1),
2010
+ message: z17.string().min(1),
1954
2011
  category: uiErrorCategorySchema,
1955
- details: z16.record(z16.string(), z16.unknown()).optional()
2012
+ details: z17.record(z17.string(), z17.unknown()).optional()
1956
2013
  });
1957
2014
 
1958
2015
  // ../shared/dist/commands.js
1959
- var commandSuccessSchema = z17.object({
1960
- ok: z17.literal(true),
1961
- data: z17.unknown()
2016
+ var commandSuccessSchema = z18.object({
2017
+ ok: z18.literal(true),
2018
+ data: z18.unknown()
1962
2019
  });
1963
- var commandErrorSchema = z17.object({
1964
- ok: z17.literal(false),
2020
+ var commandErrorSchema = z18.object({
2021
+ ok: z18.literal(false),
1965
2022
  error: commandErrorPayloadSchema
1966
2023
  });
1967
- var commandResultSchema = z17.discriminatedUnion("ok", [
2024
+ var commandResultSchema = z18.discriminatedUnion("ok", [
1968
2025
  commandSuccessSchema,
1969
2026
  commandErrorSchema
1970
2027
  ]);
1971
2028
 
1972
2029
  // ../shared/dist/editor-settings.js
1973
- import { z as z18 } from "zod";
1974
- var editorColorSchemeSchema = z18.enum([
2030
+ import { z as z19 } from "zod";
2031
+ var editorColorSchemeSchema = z19.enum([
1975
2032
  "paper",
1976
2033
  "slate",
1977
2034
  "siteplane",
1978
2035
  "bloom"
1979
2036
  ]);
1980
2037
  var editorColorSchemes = editorColorSchemeSchema.options;
1981
- var editorColorModeSchema = z18.enum(["light", "dark"]);
2038
+ var editorColorModeSchema = z19.enum(["light", "dark"]);
1982
2039
  var editorColorModes = editorColorModeSchema.options;
1983
2040
 
1984
2041
  // ../shared/dist/site-slug.js
1985
- import { z as z19 } from "zod";
2042
+ import { z as z20 } from "zod";
1986
2043
  var SITE_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1987
2044
  var RESERVED_SITE_SLUGS = /* @__PURE__ */ new Set([
1988
2045
  "account",
@@ -1999,31 +2056,31 @@ var RESERVED_SITE_SLUGS = /* @__PURE__ */ new Set([
1999
2056
  "support",
2000
2057
  "workspace"
2001
2058
  ]);
2002
- var siteSlugSchema = z19.string().regex(SITE_SLUG_PATTERN, "Invalid site slug").refine((value) => !RESERVED_SITE_SLUGS.has(value), "Reserved site slug");
2059
+ var siteSlugSchema = z20.string().regex(SITE_SLUG_PATTERN, "Invalid site slug").refine((value) => !RESERVED_SITE_SLUGS.has(value), "Reserved site slug");
2003
2060
 
2004
2061
  // ../shared/dist/entitlements.js
2005
- import { z as z20 } from "zod";
2006
- var entitlementSnapshotSchema = z20.object({
2007
- planKey: z20.string().trim().min(1),
2008
- sitesLimit: z20.number().int().positive(),
2009
- siteMembersPerSiteLimit: z20.number().int().positive(),
2010
- customAdminDomainsEnabled: z20.boolean(),
2011
- agentMcpEnabled: z20.boolean(),
2012
- emailNotificationsEnabled: z20.boolean(),
2013
- analyticsEnabled: z20.boolean(),
2014
- analyticsSitesLimit: z20.number().int().min(0),
2015
- analyticsPortalPerformanceEnabled: z20.boolean(),
2016
- analyticsMonthlyReportsEnabled: z20.boolean(),
2017
- analyticsAiSummaryEnabled: z20.boolean(),
2018
- analyticsRawEventRetentionDays: z20.number().int().min(1).max(ANALYTICS_RETENTION_DEFAULTS.maxRawEventRetentionDaysWithoutAdr),
2019
- analyticsMonthlyEventLimit: z20.number().int().min(0),
2020
- bookingEnabled: z20.boolean().default(false),
2021
- bookingSitesLimit: z20.number().int().min(0).default(0),
2022
- bookingPortalManagementEnabled: z20.boolean().default(false),
2023
- bookingResourcesPerSiteLimit: z20.number().int().min(0).default(0),
2024
- bookingServicesPerSiteLimit: z20.number().int().min(0).default(0),
2025
- bookingMonthlyBookingsLimit: z20.number().int().min(0).default(0),
2026
- bookingRemindersEnabled: z20.boolean().default(false)
2062
+ import { z as z21 } from "zod";
2063
+ var entitlementSnapshotSchema = z21.object({
2064
+ planKey: z21.string().trim().min(1),
2065
+ sitesLimit: z21.number().int().positive(),
2066
+ siteMembersPerSiteLimit: z21.number().int().positive(),
2067
+ customAdminDomainsEnabled: z21.boolean(),
2068
+ agentMcpEnabled: z21.boolean(),
2069
+ emailNotificationsEnabled: z21.boolean(),
2070
+ analyticsEnabled: z21.boolean(),
2071
+ analyticsSitesLimit: z21.number().int().min(0),
2072
+ analyticsPortalPerformanceEnabled: z21.boolean(),
2073
+ analyticsMonthlyReportsEnabled: z21.boolean(),
2074
+ analyticsAiSummaryEnabled: z21.boolean(),
2075
+ analyticsRawEventRetentionDays: z21.number().int().min(1).max(ANALYTICS_RETENTION_DEFAULTS.maxRawEventRetentionDaysWithoutAdr),
2076
+ analyticsMonthlyEventLimit: z21.number().int().min(0),
2077
+ bookingEnabled: z21.boolean().default(false),
2078
+ bookingSitesLimit: z21.number().int().min(0).default(0),
2079
+ bookingPortalManagementEnabled: z21.boolean().default(false),
2080
+ bookingResourcesPerSiteLimit: z21.number().int().min(0).default(0),
2081
+ bookingServicesPerSiteLimit: z21.number().int().min(0).default(0),
2082
+ bookingMonthlyBookingsLimit: z21.number().int().min(0).default(0),
2083
+ bookingRemindersEnabled: z21.boolean().default(false)
2027
2084
  });
2028
2085
  var EARLY_ACCESS_PLAN = {
2029
2086
  planKey: "early_access_2026",
@@ -2049,7 +2106,7 @@ var EARLY_ACCESS_PLAN = {
2049
2106
  };
2050
2107
 
2051
2108
  // ../shared/dist/readiness.js
2052
- import { z as z21 } from "zod";
2109
+ import { z as z22 } from "zod";
2053
2110
  var READINESS_CHECK_KEYS = [
2054
2111
  "agent_instructions_installed",
2055
2112
  "runtime_package_connected",
@@ -2064,19 +2121,19 @@ var READINESS_STATUSES = [
2064
2121
  "failing",
2065
2122
  "warning"
2066
2123
  ];
2067
- var readinessCheckKeySchema = z21.enum(READINESS_CHECK_KEYS);
2068
- var readinessStatusSchema = z21.enum(READINESS_STATUSES);
2124
+ var readinessCheckKeySchema = z22.enum(READINESS_CHECK_KEYS);
2125
+ var readinessStatusSchema = z22.enum(READINESS_STATUSES);
2069
2126
 
2070
2127
  // ../shared/dist/site.js
2071
- import { z as z22 } from "zod";
2128
+ import { z as z23 } from "zod";
2072
2129
  var SITE_STATUSES = [
2073
2130
  "setup",
2074
2131
  "active",
2075
2132
  "disabled",
2076
2133
  "archived"
2077
2134
  ];
2078
- var siteStatusSchema = z22.enum(SITE_STATUSES);
2079
- var websiteUrlSchema = z22.string().trim().url().refine((value) => value.startsWith("https://") || value.startsWith("http://"), "Website URL must use http or https");
2135
+ var siteStatusSchema = z23.enum(SITE_STATUSES);
2136
+ var websiteUrlSchema = z23.string().trim().url().refine((value) => value.startsWith("https://") || value.startsWith("http://"), "Website URL must use http or https");
2080
2137
 
2081
2138
  // ../cli/dist/analytics/manifest.js
2082
2139
  async function readAnalyticsManifestFile(manifestPath) {
@@ -2403,17 +2460,17 @@ function readJsxAttributes(attributes) {
2403
2460
  if (!ts.isJsxAttribute(attribute)) {
2404
2461
  continue;
2405
2462
  }
2406
- const name = attribute.name.getText();
2463
+ const name2 = attribute.name.getText();
2407
2464
  if (!attribute.initializer) {
2408
- values.set(name, true);
2465
+ values.set(name2, true);
2409
2466
  continue;
2410
2467
  }
2411
2468
  if (ts.isStringLiteral(attribute.initializer)) {
2412
- values.set(name, attribute.initializer.text);
2469
+ values.set(name2, attribute.initializer.text);
2413
2470
  continue;
2414
2471
  }
2415
2472
  if (ts.isJsxExpression(attribute.initializer)) {
2416
- values.set(name, staticExpressionValue(attribute.initializer.expression));
2473
+ values.set(name2, staticExpressionValue(attribute.initializer.expression));
2417
2474
  }
2418
2475
  }
2419
2476
  return values;
@@ -2881,16 +2938,16 @@ async function analyticsReadinessCommand(input) {
2881
2938
  }
2882
2939
 
2883
2940
  // ../cli/dist/commands/analytics/public-key.js
2884
- import { z as z23 } from "zod";
2885
- var responseSchema = z23.object({
2886
- ok: z23.literal(true),
2887
- data: z23.object({
2888
- rawPublicKey: z23.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}_[A-Za-z0-9_-]{43}$/)
2941
+ import { z as z24 } from "zod";
2942
+ var responseSchema = z24.object({
2943
+ ok: z24.literal(true),
2944
+ data: z24.object({
2945
+ rawPublicKey: z24.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}_[A-Za-z0-9_-]{43}$/)
2889
2946
  })
2890
2947
  });
2891
- var errorResponseSchema = z23.object({
2892
- error: z23.object({
2893
- code: z23.string().regex(/^[a-z][a-z0-9_.-]+$/u)
2948
+ var errorResponseSchema = z24.object({
2949
+ error: z24.object({
2950
+ code: z24.string().regex(/^[a-z][a-z0-9_.-]+$/u)
2894
2951
  })
2895
2952
  });
2896
2953
  async function analyticsPublicKeyCommand(input) {
@@ -3110,14 +3167,22 @@ async function bookingTestCommand(input) {
3110
3167
  import { access, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
3111
3168
  import { randomUUID as randomUUID2 } from "crypto";
3112
3169
  import { join as join3 } from "path";
3113
- import { z as z24 } from "zod";
3114
- var siteplaneProjectConfigSchema = z24.object({
3115
- version: z24.literal(1),
3116
- apiBaseUrl: z24.string().url(),
3117
- siteId: z24.string().uuid(),
3118
- publicSiteKeyId: z24.string().uuid(),
3119
- publicSiteKey: z24.string().trim().min(1),
3120
- fieldContractHash: z24.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
3170
+ import { z as z25 } from "zod";
3171
+ var siteplaneProjectConfigSchema = z25.object({
3172
+ version: z25.literal(2),
3173
+ apiBaseUrl: z25.string().url(),
3174
+ siteId: z25.string().uuid(),
3175
+ publicSiteKeyId: z25.string().uuid(),
3176
+ publicSiteKey: z25.string().trim().min(1),
3177
+ runId: z25.string().uuid(),
3178
+ appDirectory: z25.string().min(1),
3179
+ taskContractVersion: z25.literal("siteplane.setup-task.v2"),
3180
+ adminProtocolVersion: z25.literal(2),
3181
+ packages: z25.object({
3182
+ siteplane: z25.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
3183
+ runtimeNext: z25.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
3184
+ }).strict(),
3185
+ fieldContractHash: z25.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
3121
3186
  }).strict();
3122
3187
  async function readProjectPackageJson(projectDir) {
3123
3188
  return JSON.parse(await readFile5(join3(projectDir, "package.json"), "utf8"));
@@ -3174,16 +3239,21 @@ async function writeJsonAtomically(path, value, mode) {
3174
3239
  // ../cli/dist/config/credentials.js
3175
3240
  import { execFile } from "child_process";
3176
3241
  import { randomUUID as randomUUID3 } from "crypto";
3177
- import { chmod as chmod2, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
3242
+ import { chmod as chmod2, lstat, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
3178
3243
  import { dirname as dirname5, join as join4, relative } from "path";
3179
3244
  import { promisify } from "util";
3180
- import { z as z25 } from "zod";
3181
- var siteplaneCredentialsSchema = z25.object({
3182
- accessToken: z25.string().trim().min(1),
3183
- siteRevalidationSecret: z25.string().trim().min(1)
3245
+ import { z as z26 } from "zod";
3246
+ var siteplaneCredentialsSchema = z26.object({
3247
+ accessToken: z26.string().trim().min(1),
3248
+ siteRevalidationSecret: z26.string().trim().min(1),
3249
+ adminSession: z26.object({
3250
+ secret: z26.string().regex(/^[A-Za-z0-9_-]{43}$/u),
3251
+ generation: z26.string().uuid()
3252
+ }).strict().optional()
3184
3253
  }).strict();
3185
3254
  async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
3186
3255
  const path = join4(projectDir, ".siteplane/credentials.json");
3256
+ await assertCredentialFilesystemSafe(projectDir);
3187
3257
  const isTrackedFile = options.isTrackedFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "ls-files"));
3188
3258
  const isIgnoredFile = options.isIgnoredFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "check-ignore"));
3189
3259
  if (await isTrackedFile(path)) {
@@ -3194,6 +3264,27 @@ async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
3194
3264
  }
3195
3265
  return path;
3196
3266
  }
3267
+ async function assertCredentialFilesystemSafe(projectDir) {
3268
+ for (const [path, directory, mode] of [
3269
+ [projectDir, true, null],
3270
+ [join4(projectDir, ".siteplane"), true, 448],
3271
+ [join4(projectDir, ".siteplane/credentials.json"), false, 384]
3272
+ ]) {
3273
+ const stat = await lstat(path).catch((error) => {
3274
+ if (error.code === "ENOENT")
3275
+ return null;
3276
+ throw error;
3277
+ });
3278
+ if (!stat)
3279
+ continue;
3280
+ if (stat.isSymbolicLink() || (directory ? !stat.isDirectory() : !stat.isFile())) {
3281
+ throw new Error("Siteplane credential paths must not contain symlinks or unexpected file types.");
3282
+ }
3283
+ if (mode !== null && (stat.mode & 511) !== mode) {
3284
+ throw new Error(`Siteplane credential ${directory ? "directory" : "file"} permissions must be ${mode.toString(8)} before setup.`);
3285
+ }
3286
+ }
3287
+ }
3197
3288
  async function writeLocalCredentials(projectDir, credentials, options = {}) {
3198
3289
  const path = await assertLocalCredentialsPathSafe(projectDir, options);
3199
3290
  const parsed = siteplaneCredentialsSchema.parse(credentials);
@@ -3202,6 +3293,7 @@ async function writeLocalCredentials(projectDir, credentials, options = {}) {
3202
3293
  return path;
3203
3294
  }
3204
3295
  async function readLocalCredentials(projectDir) {
3296
+ await assertCredentialFilesystemSafe(projectDir);
3205
3297
  return siteplaneCredentialsSchema.parse(JSON.parse(await readFile6(join4(projectDir, ".siteplane/credentials.json"), "utf8")));
3206
3298
  }
3207
3299
  async function writeCredentialsAtomically(path, credentials) {
@@ -3237,8 +3329,467 @@ async function gitPathMatches(projectDir, path, command) {
3237
3329
  }
3238
3330
 
3239
3331
  // ../cli/dist/commands/init.js
3332
+ import { access as access3 } from "fs/promises";
3333
+ import { join as join7, relative as relative3 } from "path";
3334
+ import { z as z29 } from "zod";
3335
+
3336
+ // ../cli/dist/commands/setup-preflight.js
3337
+ import { createHash as createHash2 } from "crypto";
3338
+ import semver from "semver";
3339
+ import { minimatch } from "minimatch";
3340
+ import { parse as parseYaml } from "yaml";
3341
+
3342
+ // ../cli/dist/config/installed-package.js
3343
+ import { createRequire } from "module";
3344
+ import { readFile as readFile7 } from "fs/promises";
3240
3345
  import { join as join5 } from "path";
3241
- import { z as z26 } from "zod";
3346
+ import { z as z27 } from "zod";
3347
+ var packageSchema = z27.object({
3348
+ name: z27.string().optional(),
3349
+ version: z27.string(),
3350
+ peerDependencies: z27.record(z27.string(), z27.string()).optional()
3351
+ });
3352
+ async function readInstalledPackage(projectDir, name2) {
3353
+ const require2 = createRequire(join5(projectDir, "package.json"));
3354
+ for (const directory of require2.resolve.paths(name2) ?? []) {
3355
+ try {
3356
+ return packageSchema.parse(JSON.parse(await readFile7(join5(directory, name2, "package.json"), "utf8")));
3357
+ } catch (error) {
3358
+ if (error.code !== "ENOENT")
3359
+ throw error;
3360
+ }
3361
+ }
3362
+ throw new Error(`Install ${name2} with the canonical package manager before setup.`);
3363
+ }
3364
+ async function assertExactSetupPackages(projectDir, packages) {
3365
+ const manifest = z27.object({
3366
+ dependencies: z27.record(z27.string(), z27.string()).optional(),
3367
+ devDependencies: z27.record(z27.string(), z27.string()).optional()
3368
+ }).parse(JSON.parse(await readFile7(join5(projectDir, "package.json"), "utf8")));
3369
+ for (const [name2, version2] of [
3370
+ ["siteplane", packages.siteplane],
3371
+ ["@siteplane/runtime-next", packages.runtimeNext]
3372
+ ]) {
3373
+ const declared = manifest.dependencies?.[name2] ?? manifest.devDependencies?.[name2];
3374
+ const installed = await readInstalledPackage(projectDir, name2);
3375
+ if (declared !== version2 || installed.version !== version2)
3376
+ throw new Error("The installed Siteplane packages must match the current task's exact pins.");
3377
+ }
3378
+ }
3379
+
3380
+ // ../cli/dist/commands/setup-preflight.js
3381
+ import { access as access2, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
3382
+ import { dirname as dirname6, join as join6, relative as relative2, resolve, sep } from "path";
3383
+ import { z as z28 } from "zod";
3384
+
3385
+ // ../cli/dist/commands/setup-process.js
3386
+ import { spawn } from "child_process";
3387
+ var SetupFailure = class extends Error {
3388
+ code;
3389
+ constructor(code, message) {
3390
+ super(message);
3391
+ this.code = code;
3392
+ }
3393
+ };
3394
+ async function setupProcess(binary, args, options) {
3395
+ return new Promise((resolve5, reject) => {
3396
+ const child = spawn(binary, args, {
3397
+ cwd: options.cwd,
3398
+ env: process.env,
3399
+ stdio: ["pipe", "pipe", "pipe"]
3400
+ });
3401
+ const chunks = [];
3402
+ const errors = [];
3403
+ let errorBytes = 0;
3404
+ let bytes = 0;
3405
+ let exceeded = false;
3406
+ const timer = setTimeout(() => {
3407
+ exceeded = true;
3408
+ child.kill("SIGKILL");
3409
+ }, options.timeoutMs ?? 12e4);
3410
+ const capture = (chunk) => {
3411
+ bytes += chunk.length;
3412
+ if (bytes > 4 * 1024 * 1024) {
3413
+ exceeded = true;
3414
+ child.kill("SIGKILL");
3415
+ } else
3416
+ chunks.push(chunk);
3417
+ };
3418
+ child.stdout.on("data", capture);
3419
+ child.stderr.on("data", (chunk) => {
3420
+ errorBytes += chunk.length;
3421
+ if (errorBytes <= 4 * 1024 * 1024)
3422
+ errors.push(chunk);
3423
+ else {
3424
+ exceeded = true;
3425
+ child.kill("SIGKILL");
3426
+ }
3427
+ });
3428
+ child.on("error", () => {
3429
+ clearTimeout(timer);
3430
+ reject(new SetupFailure("local_tool_unavailable", `${binary} could not be started. Check the local installation and access.`));
3431
+ });
3432
+ child.on("close", (code) => {
3433
+ clearTimeout(timer);
3434
+ if (exceeded)
3435
+ reject(new SetupFailure("provider_timeout", "The operation exceeded its time or response limit; inspect the existing operation before retrying."));
3436
+ else if (code !== 0) {
3437
+ const diagnostic = Buffer.concat([...chunks, ...errors]).toString("utf8");
3438
+ if (/\b(?:401|403|unauthorized|forbidden|not authenticated|not authorized|login required|E401|E403)\b/iu.test(diagnostic))
3439
+ reject(new SetupFailure("provider_access_denied", `${binary} denied access. Restore the existing local login and project/package permissions before retrying.`));
3440
+ else if (/\b(?:ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|ECONNREFUSED|429|502|503|504)\b/iu.test(diagnostic))
3441
+ reject(new SetupFailure("provider_transport_failed", `${binary} could not reach its provider. Inspect the existing operation before retrying.`));
3442
+ else
3443
+ reject(new SetupFailure("local_command_failed", `${binary} failed. Check its local login, permissions and project configuration.`));
3444
+ } else
3445
+ resolve5(Buffer.concat(options.includeStderr ? [...chunks, ...errors] : chunks).toString("utf8"));
3446
+ });
3447
+ child.stdin.on("error", () => {
3448
+ });
3449
+ child.stdin.end(options.input);
3450
+ });
3451
+ }
3452
+ async function setupVercelApi(cwd, endpoint, body, method, options) {
3453
+ const args = ["api", endpoint, "--raw"];
3454
+ if (body !== void 0)
3455
+ args.push("--method", method ?? "POST", "--input", "-");
3456
+ else if (method)
3457
+ args.push("--method", method);
3458
+ let output = "";
3459
+ for (let attempt = 0; attempt < 3; attempt++) {
3460
+ const remaining = (options?.deadline ?? Date.now() + 3e4) - Date.now();
3461
+ if (remaining <= 0)
3462
+ throw new SetupFailure("provider_deadline_exceeded", "The provider deadline expired; inspect the recorded operation before continuing.");
3463
+ try {
3464
+ output = await setupProcess("vercel", args, {
3465
+ cwd,
3466
+ timeoutMs: Math.min(3e4, remaining),
3467
+ ...body === void 0 ? {} : { input: JSON.stringify(body) }
3468
+ });
3469
+ break;
3470
+ } catch (error) {
3471
+ if (!(error instanceof SetupFailure) || error.code !== "provider_transport_failed" || attempt === 2)
3472
+ throw error;
3473
+ await new Promise((resolve5) => setTimeout(resolve5, Math.min(1e3 * 2 ** attempt, Math.max(0, (options?.deadline ?? Date.now() + 2e3) - Date.now()))));
3474
+ }
3475
+ }
3476
+ try {
3477
+ return JSON.parse(output);
3478
+ } catch {
3479
+ throw new SetupFailure("invalid_provider_response", "Vercel did not return valid JSON for the bound project.");
3480
+ }
3481
+ }
3482
+
3483
+ // ../cli/dist/commands/setup-preflight.js
3484
+ var manifestSchema = z28.object({
3485
+ packageManager: z28.string().optional(),
3486
+ engines: z28.object({ node: z28.string().optional() }).optional(),
3487
+ dependencies: z28.record(z28.string(), z28.string()).optional(),
3488
+ devDependencies: z28.record(z28.string(), z28.string()).optional(),
3489
+ scripts: z28.record(z28.string(), z28.string()).optional(),
3490
+ workspaces: z28.unknown().optional()
3491
+ });
3492
+ var vercelProjectSchema = z28.object({
3493
+ id: z28.string(),
3494
+ accountId: z28.string(),
3495
+ name: z28.string(),
3496
+ nodeVersion: z28.string().nullable().optional(),
3497
+ rootDirectory: z28.string().nullable().optional(),
3498
+ framework: z28.string().nullable().optional(),
3499
+ installCommand: z28.string().nullable().optional(),
3500
+ buildCommand: z28.string().nullable().optional(),
3501
+ link: z28.object({
3502
+ type: z28.string(),
3503
+ repo: z28.string().optional(),
3504
+ repoId: z28.union([z28.string(), z28.number()]).optional(),
3505
+ org: z28.string().optional(),
3506
+ productionBranch: z28.string().optional()
3507
+ }).nullable().optional()
3508
+ });
3509
+ var exists = async (path) => access2(path).then(() => true, () => false);
3510
+ var fail = (code, message) => {
3511
+ throw new SetupFailure(code, message);
3512
+ };
3513
+ var stable = (version2, major) => new RegExp(`^${major}\\.\\d+\\.\\d+$`, "u").test(version2);
3514
+ async function inspectSetupLocalProject(projectDir) {
3515
+ const projectDirectory = await realpath(resolve(projectDir));
3516
+ const manifest = manifestSchema.parse(JSON.parse(await readFile8(join6(projectDirectory, "package.json"), "utf8")));
3517
+ const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join6(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
3518
+ if (apps.length !== 1)
3519
+ fail("ambiguous_app_directory", "Select one Next.js App Router application with exactly one app/ or src/app/ directory.");
3520
+ const repositoryRoot = (await setupProcess("git", ["rev-parse", "--show-toplevel"], {
3521
+ cwd: projectDirectory
3522
+ })).trim();
3523
+ const tracked = await setupProcess("git", ["ls-files", "--stage", "-z"], {
3524
+ cwd: repositoryRoot
3525
+ });
3526
+ for (const entry of tracked.split("\0").filter(Boolean)) {
3527
+ if (entry.startsWith("160000 "))
3528
+ fail("git_submodule_conflict", "The repository contains Git submodules. Resolve the explicit deployment source boundary before setup; the CLI will not copy external repositories.");
3529
+ if (!entry.startsWith("120000 "))
3530
+ continue;
3531
+ const path = join6(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
3532
+ const target = resolve(dirname6(path), await readlink(path));
3533
+ const bound = relative2(repositoryRoot, target);
3534
+ if (bound.startsWith("..") || bound.startsWith(sep))
3535
+ fail("external_symlink_conflict", "A tracked symbolic link points outside this repository. Resolve that source boundary before setup; local external files cannot enter a deployment.");
3536
+ }
3537
+ let lockfileRoot = projectDirectory;
3538
+ const lockNames = [
3539
+ "package-lock.json",
3540
+ "npm-shrinkwrap.json",
3541
+ "pnpm-lock.yaml",
3542
+ "yarn.lock",
3543
+ "bun.lock",
3544
+ "bun.lockb"
3545
+ ];
3546
+ let locks = [];
3547
+ for (; ; ) {
3548
+ locks = (await Promise.all(lockNames.map(async (name3) => await exists(join6(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
3549
+ if (locks.length || lockfileRoot === repositoryRoot || dirname6(lockfileRoot) === lockfileRoot)
3550
+ break;
3551
+ lockfileRoot = dirname6(lockfileRoot);
3552
+ }
3553
+ if (locks.length > 1)
3554
+ fail("conflicting_lockfiles", "Resolve conflicting package-manager lockfiles before setup; Siteplane does not replace them.");
3555
+ if (!locks.length)
3556
+ fail("lockfile_missing", "Install the existing application with its chosen package manager to create one canonical lockfile.");
3557
+ const lockName = locks[0];
3558
+ if (!["package-lock.json", "pnpm-lock.yaml"].includes(lockName))
3559
+ fail("unsupported_package_manager", "This setup supports npm 10 or pnpm 9/10 with their canonical lockfile.");
3560
+ const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join6(lockfileRoot, "package.json"), "utf8")));
3561
+ if (lockfileRoot !== projectDirectory) {
3562
+ const workspaceFile = join6(lockfileRoot, "pnpm-workspace.yaml");
3563
+ const workspace = lockName === "pnpm-lock.yaml" && await exists(workspaceFile) ? z28.object({ packages: z28.array(z28.string()) }).parse(parseYaml(await readFile8(workspaceFile, "utf8"))).packages : z28.union([
3564
+ z28.array(z28.string()),
3565
+ z28.object({ packages: z28.array(z28.string()) }).transform((value) => value.packages)
3566
+ ]).parse(rootManifest.workspaces);
3567
+ const selected = relative2(lockfileRoot, projectDirectory).split(sep).join("/");
3568
+ if (!workspace.some((pattern) => !pattern.startsWith("!") && minimatch(selected, pattern)) || workspace.some((pattern) => pattern.startsWith("!") && minimatch(selected, pattern.slice(1))))
3569
+ fail("unbound_workspace_app", "The selected application is excluded from the canonical lockfile's workspace packages. Select its actual application root.");
3570
+ }
3571
+ for (let ancestor = dirname6(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname6(ancestor)) {
3572
+ const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join6(ancestor, name3))));
3573
+ if (ancestorLocks.some(Boolean))
3574
+ fail("ambiguous_lockfile_root", "Both the selected package and its repository ancestors contain lockfiles. Select one canonical workspace resolution before setup.");
3575
+ if (ancestor === repositoryRoot)
3576
+ break;
3577
+ }
3578
+ const lockText = await readFile8(join6(lockfileRoot, lockName), "utf8");
3579
+ const npmLock = lockName === "package-lock.json" ? z28.object({
3580
+ lockfileVersion: z28.number(),
3581
+ packages: z28.record(z28.string(), z28.object({
3582
+ version: z28.string().optional(),
3583
+ peerDependencies: z28.record(z28.string(), z28.string()).optional()
3584
+ })).optional()
3585
+ }).parse(JSON.parse(lockText)) : null;
3586
+ async function version2(name3) {
3587
+ try {
3588
+ return (await readInstalledPackage(projectDirectory, name3)).version;
3589
+ } catch {
3590
+ const resolved = npmLock?.packages?.[`node_modules/${name3}`]?.version;
3591
+ if (resolved)
3592
+ return resolved;
3593
+ return fail("dependencies_not_installed", `Install the existing ${name3} dependency using the canonical lockfile before setup.`);
3594
+ }
3595
+ }
3596
+ const [nextVersion, reactVersion, reactDomVersion] = await Promise.all([
3597
+ version2("next"),
3598
+ version2("react"),
3599
+ version2("react-dom")
3600
+ ]);
3601
+ if (!stable(nextVersion, 16))
3602
+ fail("unsupported_next_version", "Setup supports stable Next.js 16 App Router projects. Framework migration requires a separate owner decision.");
3603
+ if (!stable(reactVersion, 19) || reactDomVersion !== reactVersion)
3604
+ fail("react_version_conflict", "Use the same stable React 19/react-dom version compatible with the installed Next.js peers.");
3605
+ if (!stable(process.versions.node, 22))
3606
+ fail("unsupported_node_version", "Run setup under Node.js 22; this does not change your framework or package-manager versions.");
3607
+ const nextMetadata = await readInstalledPackage(projectDirectory, "next").catch(() => npmLock?.packages?.["node_modules/next"] ?? null);
3608
+ const peers = nextMetadata?.peerDependencies;
3609
+ if (!peers?.react || !peers["react-dom"])
3610
+ fail("next_peer_metadata_missing", "Install the locked Next.js dependency before setup so its actual React peer requirements can be checked.");
3611
+ if (!semver.satisfies(reactVersion, peers.react) || !semver.satisfies(reactDomVersion, peers["react-dom"]))
3612
+ fail("react_peer_conflict", "The installed React pair does not satisfy the installed Next.js peer requirements. Choose a compatible pair explicitly.");
3613
+ if (manifest.engines?.node && !semver.satisfies(process.versions.node, manifest.engines.node))
3614
+ fail("node_engine_conflict", "The selected application's Node engine declaration excludes the active supported Node.js 22 runtime.");
3615
+ const name2 = lockName === "package-lock.json" ? "npm" : "pnpm";
3616
+ const declared = rootManifest.packageManager ?? manifest.packageManager ?? null;
3617
+ if (rootManifest.packageManager && manifest.packageManager && rootManifest.packageManager !== manifest.packageManager)
3618
+ fail("package_manager_conflict", "Application and workspace packageManager declarations disagree.");
3619
+ if (declared && !new RegExp(`^${name2}@\\d+\\.\\d+\\.\\d+$`, "u").test(declared))
3620
+ fail("package_manager_conflict", "Declare an exact supported npm/pnpm packageManager version matching the canonical lockfile.");
3621
+ const localVersion = (await setupProcess(declared ? "npx" : name2, declared ? ["--yes", declared, "--version"] : ["--version"], { cwd: lockfileRoot })).trim();
3622
+ if (!(name2 === "npm" ? stable(localVersion, 10) : stable(localVersion, 9) || stable(localVersion, 10)))
3623
+ fail("unsupported_package_manager_version", "Use npm 10 or pnpm 9/10; other versions are outside the initial setup support range.");
3624
+ if (declared && declared !== `${name2}@${localVersion}`)
3625
+ fail("package_manager_conflict", "The actual local package-manager version differs from the project's exact packageManager declaration. Select the declared tool without rewriting the lockfile.");
3626
+ const format = npmLock ? String(npmLock.lockfileVersion) : /^lockfileVersion:\s*['"]?([\d.]+)/mu.exec(lockText)?.[1];
3627
+ if (name2 === "npm" && format !== "3" || name2 === "pnpm" && format !== "9.0" && format !== "9")
3628
+ fail("lockfile_format_conflict", "The canonical lockfile format does not match npm 10 or pnpm 9/10.");
3629
+ const sourceConflicts = [];
3630
+ for (const file of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
3631
+ if (!await exists(join6(projectDirectory, file)))
3632
+ continue;
3633
+ const source = await readFile8(join6(projectDirectory, file), "utf8");
3634
+ if (/output\s*:\s*['"]export['"]/u.test(source))
3635
+ sourceConflicts.push("static_export");
3636
+ if (/\bbasePath\s*:/u.test(source))
3637
+ sourceConflicts.push("base_path");
3638
+ }
3639
+ if (sourceConflicts.length)
3640
+ fail("unsupported_server_configuration", "Resolve static export/basePath configuration explicitly; Siteplane requires its server-side admin and revalidation handlers.");
3641
+ for (const name3 of [
3642
+ "middleware.ts",
3643
+ "middleware.js",
3644
+ "proxy.ts",
3645
+ "proxy.js",
3646
+ "src/middleware.ts",
3647
+ "src/middleware.js",
3648
+ "src/proxy.ts",
3649
+ "src/proxy.js"
3650
+ ]) {
3651
+ if (await exists(join6(projectDirectory, name3)))
3652
+ sourceConflicts.push(`inspect_routing:${name3}`);
3653
+ }
3654
+ async function inspectSource(directory) {
3655
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
3656
+ if (entry.isSymbolicLink() || ["node_modules", ".git", ".next", ".siteplane", ".vercel"].includes(entry.name))
3657
+ continue;
3658
+ const path = join6(directory, entry.name);
3659
+ if (entry.isDirectory()) {
3660
+ await inspectSource(path);
3661
+ continue;
3662
+ }
3663
+ if (!/\.[cm]?[jt]sx?$/u.test(entry.name))
3664
+ continue;
3665
+ const source = await readFile8(path, "utf8");
3666
+ if (/from\s*["']next\/image["']/u.test(source))
3667
+ sourceConflicts.push(`inspect_image_policy:${relative2(projectDirectory, path)}`);
3668
+ if (/\b(?:Cookiebot|OneTrust|cookieyes|consentManager|cookieConsent)\b/iu.test(source))
3669
+ sourceConflicts.push(`inspect_existing_consent:${relative2(projectDirectory, path)}`);
3670
+ if (/from\s*["']next\/image["']/u.test(source) && semver.lt(nextVersion, "16.3.3"))
3671
+ fail("next_security_advisory", `Next.js ${nextVersion} uses image optimization affected by the August 2026 AVIF advisory. Review https://nextjs.org/blog/august-2026-security-release and explicitly update the affected dependency before setup; no framework upgrade was performed.`);
3672
+ if (/["']use server["']/u.test(source) && semver.lt(nextVersion, "16.2.11"))
3673
+ fail("next_security_advisory", `Next.js ${nextVersion} contains Server Actions affected by the July 2026 advisory. Review https://nextjs.org/blog/july-2026-security-release and explicitly update the affected dependency before setup.`);
3674
+ }
3675
+ }
3676
+ await inspectSource(join6(projectDirectory, apps[0]));
3677
+ const gitRead = async (args) => setupProcess("git", args, { cwd: projectDirectory }).then((value) => value.trim(), () => null);
3678
+ return {
3679
+ projectDirectory,
3680
+ repositoryRoot,
3681
+ lockfileRoot,
3682
+ appDirectory: apps[0],
3683
+ nextVersion,
3684
+ reactVersion,
3685
+ nodeVersion: process.versions.node,
3686
+ packageManager: { name: name2, version: localVersion, declared },
3687
+ lockfile: {
3688
+ path: relative2(repositoryRoot, join6(lockfileRoot, lockName)),
3689
+ format,
3690
+ sha256: createHash2("sha256").update(lockText).digest("hex")
3691
+ },
3692
+ git: {
3693
+ branch: await gitRead(["branch", "--show-current"]),
3694
+ revision: await gitRead(["rev-parse", "HEAD"]),
3695
+ remote: safeGitRemote(await gitRead(["remote", "get-url", "origin"])),
3696
+ changes: (await gitRead(["status", "--porcelain=v1", "--untracked-files=all"]))?.split("\n").filter(Boolean) ?? []
3697
+ },
3698
+ sourceConflicts
3699
+ };
3700
+ }
3701
+ async function setupPreflightCommand(input) {
3702
+ let local;
3703
+ try {
3704
+ local = await inspectSetupLocalProject(input.projectDir);
3705
+ await assertLocalCredentialsPathSafe(input.projectDir);
3706
+ let linkDirectory = local.projectDirectory;
3707
+ while (!await exists(join6(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname6(linkDirectory) !== linkDirectory)
3708
+ linkDirectory = dirname6(linkDirectory);
3709
+ if (!await exists(join6(linkDirectory, ".vercel/project.json")))
3710
+ fail("vercel_project_not_linked", "Link this application to its intended Vercel project before setup; Siteplane will not guess a target.");
3711
+ const linked = z28.object({
3712
+ projectId: z28.string().regex(/^prj_[A-Za-z0-9]+$/u),
3713
+ orgId: z28.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u)
3714
+ }).parse(JSON.parse(await readFile8(join6(linkDirectory, ".vercel/project.json"), "utf8")));
3715
+ const project = vercelProjectSchema.parse(await setupVercelApi(linkDirectory, `/v9/projects/${linked.projectId}?teamId=${linked.orgId}`));
3716
+ if (project.id !== linked.projectId || project.accountId !== linked.orgId)
3717
+ fail("vercel_identity_conflict", "The provider project does not match the locally linked project and team.");
3718
+ const expectedRoot = relative2(local.repositoryRoot, local.projectDirectory).split(sep).join("/");
3719
+ if ((project.rootDirectory ?? "") !== expectedRoot)
3720
+ fail("vercel_root_conflict", "Vercel Root Directory and the selected local app must identify the same application.");
3721
+ if (project.nodeVersion !== "22.x" || project.framework !== "nextjs")
3722
+ fail("vercel_framework_conflict", "The bound Vercel project must use Next.js with Node.js 22 before setup.");
3723
+ if (project.link && project.link.productionBranch !== local.git.branch)
3724
+ fail("vercel_production_branch_conflict", "The local branch differs from the bound Vercel Production branch.");
3725
+ if (project.link?.repo && project.link.org && !local.git.remote?.replace(/\.git$/u, "").endsWith(`${project.link.org}/${project.link.repo}`))
3726
+ fail("vercel_git_conflict", "The local origin repository differs from the Vercel Git connection.");
3727
+ const env = z28.object({
3728
+ envs: z28.array(z28.object({
3729
+ key: z28.string(),
3730
+ value: z28.string().optional(),
3731
+ target: z28.array(z28.string()).optional()
3732
+ }))
3733
+ }).parse(await setupVercelApi(linkDirectory, `/v10/projects/${linked.projectId}/env?teamId=${linked.orgId}`));
3734
+ const corepack = env.envs.some((item) => item.key === "ENABLE_EXPERIMENTAL_COREPACK" && item.value === "1" && item.target?.includes("production"));
3735
+ const install = project.installCommand ?? null;
3736
+ const selected = corepack ? "corepack" : install ? "install_override" : "automatic";
3737
+ if (local.packageManager.declared && selected === "automatic")
3738
+ fail("vercel_package_manager_pin_unconfirmed", "This project declares an exact packageManager but Vercel automatic selection does not bind that version. Enable its supported Corepack selection or set an exact install AND build override in the existing project, then rerun preflight. No package, lockfile or provider setting was changed.");
3739
+ if (install && /\b(?:yarn|bun)\b/u.test(install))
3740
+ fail("vercel_package_manager_conflict", "The Vercel install override selects an unsupported package manager.");
3741
+ const overridePin = install ? /\b(npm|pnpm)@(\d+\.\d+\.\d+)\b/u.exec(install) : null;
3742
+ if (overridePin && overridePin[1] !== local.packageManager.name)
3743
+ fail("vercel_package_manager_conflict", "The provider override selects a different package manager than the canonical lockfile.");
3744
+ const overrideFamily = install ? /(?:^|[;&|]\s*)(npm|pnpm)\s+(?:ci|install)\b/u.exec(install)?.[1] : null;
3745
+ if (overrideFamily && overrideFamily !== local.packageManager.name)
3746
+ fail("vercel_package_manager_conflict", "The provider install command conflicts with the canonical lockfile.");
3747
+ if (overridePin && local.packageManager.declared && `${overridePin[1]}@${overridePin[2]}` !== local.packageManager.declared)
3748
+ fail("vercel_package_manager_conflict", "The Vercel install override conflicts with the exact packageManager declaration.");
3749
+ return {
3750
+ status: "ready",
3751
+ local,
3752
+ provider: {
3753
+ projectId: project.id,
3754
+ teamId: project.accountId,
3755
+ name: project.name,
3756
+ rootDirectory: expectedRoot,
3757
+ nodeVersion: project.nodeVersion,
3758
+ git: project.link,
3759
+ installCommand: install,
3760
+ buildCommand: project.buildCommand ?? null,
3761
+ packageManagerSelection: selected,
3762
+ declaredPackageManager: local.packageManager.declared,
3763
+ observedPackageManager: null
3764
+ }
3765
+ };
3766
+ } catch (error) {
3767
+ return {
3768
+ status: "action_required",
3769
+ code: error instanceof SetupFailure ? error.code : "invalid_local_project",
3770
+ message: error instanceof SetupFailure ? error.message : "The selected project or provider response could not be validated. Check the application manifest and local project access.",
3771
+ ...local ? { local } : {}
3772
+ };
3773
+ }
3774
+ }
3775
+ function safeGitRemote(value) {
3776
+ if (!value)
3777
+ return null;
3778
+ if (!value.includes("://"))
3779
+ return value;
3780
+ try {
3781
+ const url = new URL(value);
3782
+ url.username = "";
3783
+ url.password = "";
3784
+ url.search = "";
3785
+ url.hash = "";
3786
+ return url.toString().replace(/\/$/u, "");
3787
+ } catch {
3788
+ return null;
3789
+ }
3790
+ }
3791
+
3792
+ // ../cli/dist/commands/init.js
3242
3793
  async function initCommand(input) {
3243
3794
  if (!input.setupToken.trim()) {
3244
3795
  throw new Error("A Siteplane setup token is required.");
@@ -3246,47 +3797,64 @@ async function initCommand(input) {
3246
3797
  if (!await detectNextProject(input.projectDir)) {
3247
3798
  throw new Error("Siteplane init currently supports Next.js projects.");
3248
3799
  }
3800
+ await assertLocalCredentialsPathSafe(input.projectDir, {
3801
+ ...input.isIgnoredFile ? { isIgnoredFile: input.isIgnoredFile } : {},
3802
+ ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
3803
+ });
3804
+ const preflight = await (input.preflight ?? setupPreflightCommand)({
3805
+ projectDir: input.projectDir
3806
+ });
3807
+ if (preflight.status !== "ready")
3808
+ throw new Error(`${preflight.code}: ${preflight.message}`);
3249
3809
  const bootstrap = await bootstrapProjectConnection(input);
3250
- const paths = bootstrap.credentialPurpose === "site_setup" ? await persistSiteSetupBootstrap(input, bootstrap) : await persistFeatureBootstrap(input, bootstrap);
3810
+ const paths = bootstrap.credentialPurpose === "site_setup" ? await persistSiteSetupBootstrap(input, bootstrap, relative3(preflight.local.lockfileRoot, preflight.local.projectDirectory) || ".") : await persistFeatureBootstrap(input, bootstrap);
3251
3811
  await acknowledgeBootstrapResponse(input);
3252
3812
  return {
3253
3813
  ...paths,
3254
3814
  nextSteps: [
3255
3815
  "Run npx siteplane setup context and read the returned task.",
3256
3816
  "Before source changes, briefly tell the user what Siteplane requested and what you will do.",
3257
- "Follow the returned steps through setup verify and stop only at ready_for_review or action_required."
3817
+ "Follow the returned steps through setup prepare and setup deploy --wait, which performs setup verify; stop only at ready_for_review or action_required."
3258
3818
  ]
3259
3819
  };
3260
3820
  }
3261
- var siteSetupBootstrapDataSchema = z26.object({
3262
- credentialPurpose: z26.literal("site_setup"),
3263
- apiBaseUrl: z26.string().url(),
3264
- siteId: z26.string().uuid(),
3265
- publicSiteKeyId: z26.string().uuid(),
3266
- publicSiteKey: z26.string().trim().min(1),
3267
- accessToken: z26.string().trim().min(1),
3268
- siteRevalidationSecret: z26.string().regex(/^[A-Za-z0-9_-]{43}$/u)
3821
+ var siteSetupBootstrapDataSchema = z29.object({
3822
+ credentialPurpose: z29.literal("site_setup"),
3823
+ apiBaseUrl: z29.string().url(),
3824
+ siteId: z29.string().uuid(),
3825
+ publicSiteKeyId: z29.string().uuid(),
3826
+ publicSiteKey: z29.string().trim().min(1),
3827
+ accessToken: z29.string().trim().min(1),
3828
+ siteRevalidationSecret: z29.string().regex(/^[A-Za-z0-9_-]{43}$/u),
3829
+ runId: z29.string().uuid(),
3830
+ packages: z29.object({
3831
+ siteplane: z29.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
3832
+ runtimeNext: z29.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
3833
+ }).strict()
3269
3834
  }).strict();
3270
- var featureBootstrapDataSchema = z26.object({
3271
- credentialPurpose: z26.enum(["analytics", "booking"]),
3272
- apiBaseUrl: z26.string().url(),
3273
- siteId: z26.string().uuid(),
3274
- accessToken: z26.string().trim().min(1)
3835
+ var featureBootstrapDataSchema = z29.object({
3836
+ credentialPurpose: z29.enum(["analytics", "booking"]),
3837
+ apiBaseUrl: z29.string().url(),
3838
+ siteId: z29.string().uuid(),
3839
+ accessToken: z29.string().trim().min(1)
3275
3840
  }).strict();
3276
- var bootstrapResponseSchema = z26.object({
3277
- ok: z26.literal(true),
3278
- data: z26.discriminatedUnion("credentialPurpose", [
3841
+ var bootstrapResponseSchema = z29.object({
3842
+ ok: z29.literal(true),
3843
+ data: z29.discriminatedUnion("credentialPurpose", [
3279
3844
  siteSetupBootstrapDataSchema,
3280
3845
  featureBootstrapDataSchema
3281
3846
  ])
3282
3847
  }).strict();
3283
3848
  async function bootstrapProjectConnection(input) {
3284
3849
  const fetcher = input.fetcher ?? fetch;
3850
+ const existing = await access3(join7(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3285
3851
  const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
3286
3852
  method: "POST",
3853
+ signal: AbortSignal.timeout(2e4),
3287
3854
  headers: createBootstrapHeaders(input),
3288
3855
  body: JSON.stringify({
3289
3856
  action: "bootstrap",
3857
+ ...existing ? { expectedSiteId: existing.siteId, expectedRunId: existing.runId } : {},
3290
3858
  agentClient: input.agentClient ?? "codex"
3291
3859
  })
3292
3860
  });
@@ -3301,6 +3869,7 @@ async function acknowledgeBootstrapResponse(input) {
3301
3869
  const fetcher = input.fetcher ?? fetch;
3302
3870
  const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
3303
3871
  method: "POST",
3872
+ signal: AbortSignal.timeout(2e4),
3304
3873
  headers: createBootstrapHeaders(input),
3305
3874
  body: JSON.stringify({ action: "acknowledge" })
3306
3875
  });
@@ -3308,8 +3877,13 @@ async function acknowledgeBootstrapResponse(input) {
3308
3877
  throw new Error("Siteplane setup acknowledgement failed.");
3309
3878
  }
3310
3879
  }
3311
- async function persistSiteSetupBootstrap(input, bootstrap) {
3880
+ async function persistSiteSetupBootstrap(input, bootstrap, appDirectory) {
3881
+ const previous = await access3(join7(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3882
+ if (previous && (previous.siteId !== bootstrap.siteId || previous.runId !== bootstrap.runId || previous.publicSiteKeyId !== bootstrap.publicSiteKeyId || previous.publicSiteKey !== bootstrap.publicSiteKey))
3883
+ throw new Error("The grant does not match this local Siteplane run. Preserve this directory and choose the correct owner connection.");
3884
+ const previousCredentials = previous ? await access3(join7(input.projectDir, ".siteplane/credentials.json")).then(() => readLocalCredentials(input.projectDir), () => null) : null;
3312
3885
  const credentialsPath = await writeLocalCredentials(input.projectDir, {
3886
+ ...previousCredentials?.adminSession ? { adminSession: previousCredentials.adminSession } : {},
3313
3887
  accessToken: bootstrap.accessToken,
3314
3888
  siteRevalidationSecret: bootstrap.siteRevalidationSecret
3315
3889
  }, {
@@ -3317,7 +3891,13 @@ async function persistSiteSetupBootstrap(input, bootstrap) {
3317
3891
  ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
3318
3892
  });
3319
3893
  const configPath = await writeProjectConfig(input.projectDir, {
3320
- version: 1,
3894
+ ...previous ?? {},
3895
+ version: 2,
3896
+ appDirectory,
3897
+ runId: bootstrap.runId,
3898
+ packages: bootstrap.packages,
3899
+ taskContractVersion: "siteplane.setup-task.v2",
3900
+ adminProtocolVersion: 2,
3321
3901
  apiBaseUrl: bootstrap.apiBaseUrl,
3322
3902
  siteId: bootstrap.siteId,
3323
3903
  publicSiteKeyId: bootstrap.publicSiteKeyId,
@@ -3327,7 +3907,7 @@ async function persistSiteSetupBootstrap(input, bootstrap) {
3327
3907
  readLocalCredentials(input.projectDir),
3328
3908
  readProjectConfig(input.projectDir)
3329
3909
  ]);
3330
- if (credentials.accessToken !== bootstrap.accessToken || credentials.siteRevalidationSecret !== bootstrap.siteRevalidationSecret || config.apiBaseUrl !== bootstrap.apiBaseUrl || config.siteId !== bootstrap.siteId || config.publicSiteKeyId !== bootstrap.publicSiteKeyId || config.publicSiteKey !== bootstrap.publicSiteKey) {
3910
+ if (credentials.accessToken !== bootstrap.accessToken || credentials.siteRevalidationSecret !== bootstrap.siteRevalidationSecret || config.runId !== bootstrap.runId || config.packages.siteplane !== bootstrap.packages.siteplane || config.packages.runtimeNext !== bootstrap.packages.runtimeNext || config.apiBaseUrl !== bootstrap.apiBaseUrl || config.siteId !== bootstrap.siteId || config.publicSiteKeyId !== bootstrap.publicSiteKeyId || config.publicSiteKey !== bootstrap.publicSiteKey) {
3331
3911
  throw new Error("Siteplane setup files could not be verified.");
3332
3912
  }
3333
3913
  return { configPath, credentialsPath };
@@ -3341,8 +3921,8 @@ async function persistFeatureBootstrap(input, bootstrap) {
3341
3921
  throw new Error("The setup token belongs to a different Siteplane site.");
3342
3922
  }
3343
3923
  const credentialsPath = await writeLocalCredentials(input.projectDir, {
3344
- accessToken: bootstrap.accessToken,
3345
- siteRevalidationSecret: existingCredentials.siteRevalidationSecret
3924
+ ...existingCredentials,
3925
+ accessToken: bootstrap.accessToken
3346
3926
  }, {
3347
3927
  ...input.isIgnoredFile ? { isIgnoredFile: input.isIgnoredFile } : {},
3348
3928
  ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
@@ -3352,7 +3932,7 @@ async function persistFeatureBootstrap(input, bootstrap) {
3352
3932
  throw new Error("Siteplane credentials could not be verified.");
3353
3933
  }
3354
3934
  return {
3355
- configPath: join5(input.projectDir, "siteplane.config.json"),
3935
+ configPath: join7(input.projectDir, "siteplane.config.json"),
3356
3936
  credentialsPath
3357
3937
  };
3358
3938
  }
@@ -3374,8 +3954,8 @@ function readErrorMessage(payload) {
3374
3954
  }
3375
3955
 
3376
3956
  // ../cli/dist/commands/scan.js
3377
- import { readdir } from "fs/promises";
3378
- import { extname, join as join6 } from "path";
3957
+ import { readdir as readdir2 } from "fs/promises";
3958
+ import { extname, join as join8 } from "path";
3379
3959
  var defaultScanRoots = ["app", "src", "pages", "components", "lib"];
3380
3960
  var excludedDirectories = /* @__PURE__ */ new Set([
3381
3961
  ".git",
@@ -3393,14 +3973,14 @@ async function resolveScanFilePaths(filePaths, options = {}) {
3393
3973
  return filePaths;
3394
3974
  }
3395
3975
  const projectDir = options.projectDir ?? process.cwd();
3396
- const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join6(projectDir, root))));
3976
+ const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join8(projectDir, root))));
3397
3977
  return [...new Set(discovered.flat())].sort();
3398
3978
  }
3399
3979
  async function collectSourceFiles(directory) {
3400
- const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
3980
+ const entries = await readdir2(directory, { withFileTypes: true }).catch(() => []);
3401
3981
  const files = [];
3402
3982
  for (const entry of entries) {
3403
- const entryPath = join6(directory, entry.name);
3983
+ const entryPath = join8(directory, entry.name);
3404
3984
  if (entry.isDirectory()) {
3405
3985
  if (!excludedDirectories.has(entry.name)) {
3406
3986
  files.push(...await collectSourceFiles(entryPath));
@@ -3416,17 +3996,17 @@ async function collectSourceFiles(directory) {
3416
3996
 
3417
3997
  // ../cli/dist/commands/site-setup.js
3418
3998
  import { execFile as execFile2 } from "child_process";
3419
- import { readFile as readFile7 } from "fs/promises";
3999
+ import { readFile as readFile9 } from "fs/promises";
3420
4000
  import { promisify as promisify2 } from "util";
3421
- import { z as z27 } from "zod";
4001
+ import { z as z30 } from "zod";
3422
4002
 
3423
4003
  // ../cli/dist/scan/next-source-scan.js
3424
4004
  import ts2 from "typescript";
3425
- import { isAbsolute, relative as relative2 } from "path";
4005
+ import { isAbsolute, relative as relative4 } from "path";
3426
4006
  var eventPreviewHandlerMissingMessage = "Event preview fields must consume preview values with useSiteplanePreviewText from @siteplane/runtime-next/client or a siteplane:preview-value-applied listener.";
3427
4007
  var valueCallUnusedMessage = "Siteplane value calls must feed rendered content. Assign or await the returned value and render that value instead of ignoring the call.";
3428
4008
  var legacyEditableComponentPrefix = "Editable";
3429
- var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((name) => `${legacyEditableComponentPrefix}${name}`));
4009
+ var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((name2) => `${legacyEditableComponentPrefix}${name2}`));
3430
4010
  var functionTypeByName = {
3431
4011
  text: "text",
3432
4012
  longText: "longText",
@@ -3964,17 +4544,17 @@ function readObjectLiteral(expression) {
3964
4544
  if (!ts2.isPropertyAssignment(property)) {
3965
4545
  continue;
3966
4546
  }
3967
- const name = getPropertyName(property.name);
3968
- if (!name) {
4547
+ const name2 = getPropertyName(property.name);
4548
+ if (!name2) {
3969
4549
  continue;
3970
4550
  }
3971
- value[name] = staticExpressionValue2(property.initializer);
4551
+ value[name2] = staticExpressionValue2(property.initializer);
3972
4552
  }
3973
4553
  return value;
3974
4554
  }
3975
- function getPropertyName(name) {
3976
- if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) {
3977
- return name.text;
4555
+ function getPropertyName(name2) {
4556
+ if (ts2.isIdentifier(name2) || ts2.isStringLiteral(name2)) {
4557
+ return name2.text;
3978
4558
  }
3979
4559
  return null;
3980
4560
  }
@@ -4000,9 +4580,9 @@ function collectEventPreviewComponentPropUsages(node, eventPreviewAttrVariables,
4000
4580
  });
4001
4581
  }
4002
4582
  }
4003
- function getJsxAttributeName(name) {
4004
- if (ts2.isIdentifier(name)) {
4005
- return name.text;
4583
+ function getJsxAttributeName(name2) {
4584
+ if (ts2.isIdentifier(name2)) {
4585
+ return name2.text;
4006
4586
  }
4007
4587
  return void 0;
4008
4588
  }
@@ -4027,8 +4607,8 @@ function getFunctionComponentName(node) {
4027
4607
  }
4028
4608
  return void 0;
4029
4609
  }
4030
- function isComponentName(name) {
4031
- return /^[A-Z]/.test(name);
4610
+ function isComponentName(name2) {
4611
+ return /^[A-Z]/.test(name2);
4032
4612
  }
4033
4613
  function getAssignedVariableName(node) {
4034
4614
  let current = node;
@@ -4076,7 +4656,7 @@ function inferRouteHint(filePath) {
4076
4656
  return route ? `/${route}` : "/";
4077
4657
  }
4078
4658
  function toRepositoryRelativePosixPath(filePath, projectRoot) {
4079
- const path = isAbsolute(filePath) ? relative2(projectRoot, filePath) : filePath;
4659
+ const path = isAbsolute(filePath) ? relative4(projectRoot, filePath) : filePath;
4080
4660
  return path.replaceAll("\\", "/");
4081
4661
  }
4082
4662
  function isPositionalFieldReference(value) {
@@ -4085,30 +4665,30 @@ function isPositionalFieldReference(value) {
4085
4665
 
4086
4666
  // ../cli/dist/commands/site-setup.js
4087
4667
  var execFileAsync2 = promisify2(execFile2);
4088
- var safeErrorSchema = z27.object({
4089
- code: z27.string().trim().min(1),
4090
- message: z27.string().trim().min(1)
4668
+ var safeErrorSchema = z30.object({
4669
+ code: z30.string().trim().min(1),
4670
+ message: z30.string().trim().min(1)
4091
4671
  }).passthrough();
4092
- var errorResponseSchema2 = z27.object({ ok: z27.literal(false), error: safeErrorSchema }).passthrough();
4093
- var contextDataSchema = z27.object({ task: siteSetupTaskSchema }).strict();
4094
- var contextResponseSchema = z27.object({ ok: z27.literal(true), data: contextDataSchema }).strict();
4095
- var applyDataSchema = z27.object({
4096
- status: z27.enum(["applied", "ready_for_review"]),
4097
- runId: z27.string().uuid().optional(),
4098
- contractVersionId: z27.string().uuid().optional(),
4099
- fieldContractHash: z27.string().regex(/^sha256:[0-9a-f]{64}$/u),
4100
- editorDefinitionHash: z27.string().regex(/^sha256:[0-9a-f]{64}$/u).optional(),
4101
- fieldCount: z27.number().int().nonnegative().optional(),
4102
- routeCount: z27.number().int().nonnegative().optional()
4672
+ var errorResponseSchema2 = z30.object({ ok: z30.literal(false), error: safeErrorSchema }).passthrough();
4673
+ var contextDataSchema = z30.object({ task: siteSetupTaskSchema }).strict();
4674
+ var contextResponseSchema = z30.object({ ok: z30.literal(true), data: contextDataSchema }).strict();
4675
+ var applyDataSchema = z30.object({
4676
+ status: z30.enum(["applied", "ready_for_review"]),
4677
+ runId: z30.string().uuid().optional(),
4678
+ contractVersionId: z30.string().uuid().optional(),
4679
+ fieldContractHash: z30.string().regex(/^sha256:[0-9a-f]{64}$/u),
4680
+ editorDefinitionHash: z30.string().regex(/^sha256:[0-9a-f]{64}$/u).optional(),
4681
+ fieldCount: z30.number().int().nonnegative().optional(),
4682
+ routeCount: z30.number().int().nonnegative().optional()
4103
4683
  }).strict();
4104
- var applyResponseSchema = z27.object({ ok: z27.literal(true), data: applyDataSchema }).strict();
4105
- var verifyDataSchema = z27.object({
4106
- status: z27.literal("ready_for_review"),
4107
- runId: z27.string().uuid().optional(),
4108
- deploymentOrigin: z27.string().url().optional(),
4109
- deploymentRevision: z27.string().optional()
4684
+ var applyResponseSchema = z30.object({ ok: z30.literal(true), data: applyDataSchema }).strict();
4685
+ var verifyDataSchema = z30.object({
4686
+ status: z30.literal("ready_for_review"),
4687
+ runId: z30.string().uuid().optional(),
4688
+ deploymentOrigin: z30.string().url().optional(),
4689
+ deploymentRevision: z30.string().optional()
4110
4690
  }).strict();
4111
- var verifyResponseSchema = z27.object({ ok: z27.literal(true), data: verifyDataSchema }).strict();
4691
+ var verifyResponseSchema = z30.object({ ok: z30.literal(true), data: verifyDataSchema }).strict();
4112
4692
  async function siteSetupContextCommand(input) {
4113
4693
  const response = await postSiteSetup(input, "context", {});
4114
4694
  const parsed = contextResponseSchema.safeParse(response.payload);
@@ -4118,9 +4698,19 @@ async function siteSetupContextCommand(input) {
4118
4698
  return actionRequired(response.payload, "Siteplane setup context is unavailable.");
4119
4699
  }
4120
4700
  async function siteSetupApplyCommand(input) {
4701
+ const config = await readProjectConfig(input.projectDir);
4702
+ try {
4703
+ await assertExactSetupPackages(input.projectDir, config.packages);
4704
+ } catch {
4705
+ return {
4706
+ status: "action_required",
4707
+ code: "siteplane_package_pin_conflict",
4708
+ message: "Run setup prepare to install the exact Siteplane packages from the current task before applying fields."
4709
+ };
4710
+ }
4121
4711
  const editorDefinition = editorDefinitionV1Schema.parse(input.editorDefinition);
4122
4712
  const resolveSourceFiles = input.resolveSourceFiles ?? resolveScanFilePaths;
4123
- const readSourceFile = input.readSourceFile ?? ((path) => readFile7(path, "utf8"));
4713
+ const readSourceFile = input.readSourceFile ?? ((path) => readFile9(path, "utf8"));
4124
4714
  const scanSourceFiles = input.scanSourceFiles ?? scanNextSourceFilesToSiteFieldContract;
4125
4715
  const paths = await resolveSourceFiles([], { projectDir: input.projectDir });
4126
4716
  const files = await Promise.all(paths.map(async (filePath) => ({
@@ -4137,7 +4727,8 @@ async function siteSetupApplyCommand(input) {
4137
4727
  }
4138
4728
  const payload = siteSetupApplyInputSchema.parse({
4139
4729
  fieldContract: scan.contract,
4140
- editorDefinition
4730
+ editorDefinition,
4731
+ contentSelectionSummary: input.contentSelectionSummary
4141
4732
  });
4142
4733
  const response = await postSiteSetup(input, "apply", payload);
4143
4734
  const parsed = applyResponseSchema.safeParse(response.payload);
@@ -4152,7 +4743,6 @@ async function siteSetupApplyCommand(input) {
4152
4743
  message: "The applied field contract hash does not match the final local source scan."
4153
4744
  };
4154
4745
  }
4155
- const config = await readProjectConfig(input.projectDir);
4156
4746
  await writeProjectConfig(input.projectDir, {
4157
4747
  ...config,
4158
4748
  fieldContractHash: parsed.data.data.fieldContractHash
@@ -4161,7 +4751,7 @@ async function siteSetupApplyCommand(input) {
4161
4751
  }
4162
4752
  async function siteSetupVerifyCommand(input) {
4163
4753
  const resolveSourceFiles = input.resolveSourceFiles ?? resolveScanFilePaths;
4164
- const readSourceFile = input.readSourceFile ?? ((path) => readFile7(path, "utf8"));
4754
+ const readSourceFile = input.readSourceFile ?? ((path) => readFile9(path, "utf8"));
4165
4755
  const paths = await resolveSourceFiles([], { projectDir: input.projectDir });
4166
4756
  const sources = await Promise.all(paths.map(readSourceFile));
4167
4757
  if (!sources.some(hasMountedFieldRuntimeBridge)) {
@@ -4191,19 +4781,33 @@ async function postSiteSetup(input, operation, body) {
4191
4781
  readProjectConfig(input.projectDir),
4192
4782
  readLocalCredentials(input.projectDir)
4193
4783
  ]);
4194
- const response = await (input.fetcher ?? fetch)(`${config.apiBaseUrl.replace(/\/$/u, "")}/api/cli/setup/${operation}`, {
4195
- method: "POST",
4196
- headers: {
4197
- authorization: `Bearer ${credentials.accessToken}`,
4198
- "content-type": "application/json",
4199
- ...input.vercelAutomationBypassSecret?.trim() ? {
4200
- "x-vercel-protection-bypass": input.vercelAutomationBypassSecret.trim()
4201
- } : {}
4202
- },
4203
- body: JSON.stringify(body)
4204
- });
4205
- const payload = await response.json().catch(() => null);
4206
- return { ok: response.ok, payload };
4784
+ try {
4785
+ const response = await (input.fetcher ?? fetch)(`${config.apiBaseUrl.replace(/\/$/u, "")}/api/cli/setup/${operation}`, {
4786
+ method: "POST",
4787
+ signal: AbortSignal.timeout(Math.max(1, Math.min(2e4, (input.deadline ?? Date.now() + 2e4) - Date.now()))),
4788
+ headers: {
4789
+ authorization: `Bearer ${credentials.accessToken}`,
4790
+ "content-type": "application/json",
4791
+ ...input.vercelAutomationBypassSecret?.trim() ? {
4792
+ "x-vercel-protection-bypass": input.vercelAutomationBypassSecret.trim()
4793
+ } : {}
4794
+ },
4795
+ body: JSON.stringify(body)
4796
+ });
4797
+ const payload = await response.json().catch(() => null);
4798
+ return { ok: response.ok, payload };
4799
+ } catch {
4800
+ return {
4801
+ ok: false,
4802
+ payload: {
4803
+ ok: false,
4804
+ error: {
4805
+ code: "site_setup.transport_failed",
4806
+ message: "The setup request was not acknowledged. Reload the existing task before retrying; no credential values are included."
4807
+ }
4808
+ }
4809
+ };
4810
+ }
4207
4811
  }
4208
4812
  function actionRequired(payload, fallbackMessage) {
4209
4813
  const parsed = errorResponseSchema2.safeParse(payload);
@@ -4240,15 +4844,870 @@ async function siteSetupActivityCommand(input) {
4240
4844
  message: "Choose inspecting, integrating, deploying, verifying or repairing."
4241
4845
  };
4242
4846
  const response = await postSiteSetup(input, "activity", activity.data);
4243
- const parsed = z27.object({
4244
- ok: z27.literal(true),
4245
- data: z27.object({ status: z27.enum(["recorded", "rate_limited"]) }).strict()
4847
+ const parsed = z30.object({
4848
+ ok: z30.literal(true),
4849
+ data: z30.object({ status: z30.enum(["recorded", "rate_limited"]) }).strict()
4246
4850
  }).strict().safeParse(response.payload);
4247
4851
  return response.ok && parsed.success ? parsed.data.data : actionRequired(response.payload, "Setup activity could not be recorded.");
4248
4852
  }
4249
4853
 
4854
+ // ../cli/dist/commands/setup-prepare.js
4855
+ import { access as access4, lstat as lstat2, mkdir as mkdir6, open as open3, readFile as readFile10, rename as rename3, rm as rm3 } from "fs/promises";
4856
+ import { randomUUID as randomUUID4 } from "crypto";
4857
+ import { dirname as dirname7, join as join9, relative as relative5, sep as sep2 } from "path";
4858
+ import ts3 from "typescript";
4859
+ var exists2 = async (path) => access4(path).then(() => true, () => false);
4860
+ var importPath = (from, target) => {
4861
+ const path = relative5(dirname7(from), target).split(sep2).join("/");
4862
+ return path.startsWith(".") ? path : `./${path}`;
4863
+ };
4864
+ async function setupPrepareCommand(input) {
4865
+ try {
4866
+ const preflight = await setupPreflightCommand(input);
4867
+ if (preflight.status !== "ready")
4868
+ return preflight;
4869
+ const config = await readProjectConfig(input.projectDir);
4870
+ const context = await siteSetupContextCommand(input);
4871
+ if (context.status !== "ok")
4872
+ return context;
4873
+ const task = context.task;
4874
+ if (task.site?.siteId !== config.siteId || task.run?.runId !== config.runId || task.packages.siteplane !== config.packages.siteplane || task.packages.runtimeNext !== config.packages.runtimeNext) {
4875
+ throw new SetupFailure("setup_contract_conflict", "The local configuration does not match this server task and its exact package versions.");
4876
+ }
4877
+ if (task.run.status === "completed" || task.run.status === "ready_for_review")
4878
+ return {
4879
+ status: "unchanged",
4880
+ message: "The verified setup is available for owner review; no preparation writes are needed."
4881
+ };
4882
+ const directory = preflight.local.projectDirectory;
4883
+ const app = join9(directory, preflight.local.appDirectory);
4884
+ const layouts = (await Promise.all(["layout.tsx", "layout.jsx", "layout.js"].map(async (name2) => await exists2(join9(app, name2)) ? join9(app, name2) : null))).filter((path) => path !== null);
4885
+ if (layouts.length !== 1)
4886
+ throw new SetupFailure("layout_integration_conflict", "Select one root layout and mount the Siteplane preview bridge there; preserve existing providers and rendering.");
4887
+ const layoutPath = layouts[0];
4888
+ const typed = layoutPath.endsWith(".tsx");
4889
+ const routeExtension = typed ? "ts" : "js";
4890
+ const bridgePath = join9(app, "_siteplane", `bridge.${typed ? "tsx" : "jsx"}`);
4891
+ const portal = task.site.portalPath;
4892
+ if (!/^\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(portal))
4893
+ throw new SetupFailure("portal_route_conflict", "The selected portal path is not a supported single route segment.");
4894
+ const adminRoot = join9(app, portal.slice(1));
4895
+ for (const name2 of [
4896
+ "page.tsx",
4897
+ "page.jsx",
4898
+ "page.js",
4899
+ "route.ts",
4900
+ "route.js"
4901
+ ]) {
4902
+ if (await exists2(join9(adminRoot, name2)))
4903
+ throw new SetupFailure("portal_route_conflict", "The selected admin path already belongs to the website. Choose an unused editor path in Siteplane.");
4904
+ }
4905
+ const configPath = join9(directory, "siteplane.config.json");
4906
+ const adminPath = join9(adminRoot, "[[...siteplane]]", `route.${routeExtension}`);
4907
+ const revalidationPath = join9(app, "api/siteplane/revalidate", `route.${routeExtension}`);
4908
+ const commonOptions = `siteId: config.siteId,
4909
+ publicRuntimeKeyId: config.publicSiteKeyId,
4910
+ fieldContractHash: process.env.SITEPLANE_BUILD_FIELD_CONTRACT_HASH${typed ? "!" : ""},
4911
+ deploymentRevision: process.env.SITEPLANE_BUILD_REVISION${typed ? "!" : ""},`;
4912
+ const admin = `import { createSiteplaneAdminRouteHandler } from "@siteplane/runtime-next/server";
4913
+ import config from ${JSON.stringify(importPath(adminPath, configPath))};
4914
+ export const runtime = "nodejs";
4915
+ function handle(request${typed ? ": Request" : ""}) {
4916
+ return createSiteplaneAdminRouteHandler({
4917
+ ${commonOptions}
4918
+ setupRunId: config.runId, portalPath: ${JSON.stringify(portal)},
4919
+ deploymentOrigin: process.env.SITEPLANE_SITE_ORIGIN${typed ? "!" : ""},
4920
+ publicSiteKey: config.publicSiteKey, apiBaseUrl: config.apiBaseUrl,
4921
+ revalidationSecret: process.env.SITEPLANE_REVALIDATION_SECRET${typed ? "!" : ""},
4922
+ sessionSecret: process.env.SITEPLANE_ADMIN_SESSION_SECRET${typed ? "!" : ""},
4923
+ })(request);
4924
+ }
4925
+ export { handle as GET, handle as POST };
4926
+ `;
4927
+ const revalidation = `import { revalidatePath, revalidateTag } from "next/cache";
4928
+ import { createSiteplaneRevalidationHandler } from "@siteplane/runtime-next/server";
4929
+ import config from ${JSON.stringify(importPath(revalidationPath, configPath))};
4930
+ export const runtime = "nodejs";
4931
+ export async function POST(request${typed ? ": Request" : ""}) {
4932
+ return createSiteplaneRevalidationHandler({
4933
+ ${commonOptions}
4934
+ audienceOrigin: process.env.SITEPLANE_SITE_ORIGIN${typed ? "!" : ""},
4935
+ secret: process.env.SITEPLANE_REVALIDATION_SECRET,
4936
+ revalidate: async (_payload, context) => {
4937
+ revalidateTag(context.cacheTag, { expire: 0 });
4938
+ revalidatePath("/", "layout");
4939
+ },
4940
+ })(request);
4941
+ }
4942
+ `;
4943
+ const bridge = `"use client";
4944
+ import { useEffect, useState } from "react";
4945
+ import { FieldRuntimeBridge } from "@siteplane/runtime-next/client";
4946
+ import config from ${JSON.stringify(importPath(bridgePath, configPath))};
4947
+ export default function SiteplaneBridge() {
4948
+ const [sessionId, setSessionId] = useState${typed ? "<string | null>" : ""}(null);
4949
+ useEffect(() => {
4950
+ const query = new URL(window.location.href).searchParams;
4951
+ const session = query.get("siteplaneSessionId");
4952
+ if (query.get("siteplanePreview") === "1" && query.get("siteplaneAdminOrigin") === new URL(config.apiBaseUrl).origin && session && /^[A-Za-z0-9_-]{1,128}$/.test(session)) setSessionId(session);
4953
+ }, []);
4954
+ return sessionId ? <FieldRuntimeBridge siteId={config.siteId} adminOrigin={new URL(config.apiBaseUrl).origin} sessionId={sessionId} /> : null;
4955
+ }
4956
+ `;
4957
+ const files = /* @__PURE__ */ new Map([
4958
+ [adminPath, admin],
4959
+ [revalidationPath, revalidation],
4960
+ [bridgePath, bridge]
4961
+ ]);
4962
+ const layoutSource = await readFile10(layoutPath, "utf8");
4963
+ if (!/import\s+SiteplaneBridge\s+from\s+["']\.\/_siteplane\/bridge["']/u.test(layoutSource)) {
4964
+ const ast = ts3.createSourceFile(layoutPath, layoutSource, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
4965
+ const closingBodies = [];
4966
+ const visit = (node) => {
4967
+ if (ts3.isJsxClosingElement(node) && node.tagName.getText(ast) === "body")
4968
+ closingBodies.push(node.getStart(ast));
4969
+ ts3.forEachChild(node, visit);
4970
+ };
4971
+ visit(ast);
4972
+ if (closingBodies.length !== 1)
4973
+ throw new SetupFailure("layout_integration_conflict", "Mount SiteplaneBridge inside the existing root body. The layout shape requires a deliberate agent edit.");
4974
+ const point = closingBodies[0];
4975
+ files.set(layoutPath, `import SiteplaneBridge from "./_siteplane/bridge";
4976
+ ${layoutSource.slice(0, point)}<SiteplaneBridge />${layoutSource.slice(point)}`);
4977
+ }
4978
+ const configs = (await Promise.all(["next.config.ts", "next.config.mjs", "next.config.js"].map(async (name2) => await exists2(join9(directory, name2)) ? join9(directory, name2) : null))).filter((path) => path !== null);
4979
+ if (configs.length > 1)
4980
+ throw new SetupFailure("next_config_conflict", "Choose one existing Next.js configuration before setup.");
4981
+ const nextPath = configs[0] ?? join9(directory, "next.config.mjs");
4982
+ const nextSource = configs.length ? await readFile10(nextPath, "utf8") : "export default {};\n";
4983
+ if (!/\bwithSiteplane\s*\(/u.test(nextSource)) {
4984
+ const ast = ts3.createSourceFile(nextPath, nextSource, ts3.ScriptTarget.Latest, true);
4985
+ const exported = ast.statements.filter(ts3.isExportAssignment);
4986
+ if (exported.length !== 1 || exported[0].isExportEquals)
4987
+ throw new SetupFailure("next_config_conflict", "Wrap the existing default Next.js configuration with withSiteplane from siteplane/next, preserving its existing options.");
4988
+ const expression = exported[0].expression;
4989
+ files.set(nextPath, `import { withSiteplane } from "siteplane/next";
4990
+ ${nextSource.slice(0, expression.getStart(ast))}withSiteplane(${expression.getText(ast)})${nextSource.slice(expression.end)}`);
4991
+ }
4992
+ files.set(join9(directory, ".siteplane/setup-guide-v2.md"), `# Siteplane setup task v2
4993
+
4994
+ ${task.goal}
4995
+
4996
+ ## Technical rules
4997
+
4998
+ ${task.discovery.rules.map((rule) => `- ${rule}`).join("\n")}
4999
+
5000
+ Run setup context for the current user instructions and authorized modules. Keep the user instructions distinct from your selection summary. Use setup deploy --wait for environment transfer and deployment; never read or print credential values.
5001
+ `);
5002
+ for (const [path, content] of files) {
5003
+ if (path === layoutPath || path === nextPath)
5004
+ continue;
5005
+ if (await exists2(path) && await readFile10(path, "utf8") !== content)
5006
+ throw new SetupFailure("owned_file_conflict", `Preserve the existing ${relative5(directory, path)} and reconcile its integration with the current Siteplane guide before retrying.`);
5007
+ }
5008
+ for (const path of files.keys())
5009
+ await assertSourcePath(directory, path);
5010
+ const before = /* @__PURE__ */ new Map();
5011
+ for (const path of files.keys())
5012
+ before.set(path, await readFile10(path, "utf8").catch((error) => {
5013
+ if (error.code === "ENOENT")
5014
+ return null;
5015
+ throw error;
5016
+ }));
5017
+ const packageManifest = JSON.parse(await readFile10(join9(directory, "package.json"), "utf8"));
5018
+ const pm = preflight.local.packageManager;
5019
+ const command = (args) => setupProcess("npx", ["--yes", `${pm.name}@${pm.version}`, ...args], {
5020
+ cwd: directory,
5021
+ timeoutMs: 3e5
5022
+ });
5023
+ if (packageManifest.devDependencies?.siteplane !== task.packages.siteplane)
5024
+ await command(pm.name === "npm" ? [
5025
+ "install",
5026
+ "--save-dev",
5027
+ "--save-exact",
5028
+ `siteplane@${task.packages.siteplane}`
5029
+ ] : [
5030
+ "add",
5031
+ "--save-dev",
5032
+ "--save-exact",
5033
+ `siteplane@${task.packages.siteplane}`
5034
+ ]);
5035
+ if (packageManifest.dependencies?.["@siteplane/runtime-next"] !== task.packages.runtimeNext)
5036
+ await command(pm.name === "npm" ? [
5037
+ "install",
5038
+ "--save-exact",
5039
+ `@siteplane/runtime-next@${task.packages.runtimeNext}`
5040
+ ] : [
5041
+ "add",
5042
+ "--save-exact",
5043
+ `@siteplane/runtime-next@${task.packages.runtimeNext}`
5044
+ ]);
5045
+ try {
5046
+ await assertExactSetupPackages(directory, task.packages);
5047
+ } catch {
5048
+ throw new SetupFailure("siteplane_package_pin_conflict", "The actual installed Siteplane packages do not match the task's exact versions. Resolve package access and the canonical lockfile before preparation.");
5049
+ }
5050
+ const written = [];
5051
+ for (const [path, content] of files) {
5052
+ await assertSourcePath(directory, path);
5053
+ const current = await readFile10(path, "utf8").catch((error) => {
5054
+ if (error.code === "ENOENT")
5055
+ return null;
5056
+ throw error;
5057
+ });
5058
+ if (current !== before.get(path))
5059
+ throw new SetupFailure("source_changed_during_prepare", "The source changed while dependencies were installing. Preserve the concurrent edit and reconcile it before retrying preparation.");
5060
+ if (current === content)
5061
+ continue;
5062
+ await mkdir6(dirname7(path), {
5063
+ recursive: true,
5064
+ mode: path.includes(`${sep2}.siteplane${sep2}`) ? 448 : 493
5065
+ });
5066
+ const temporary = `${path}.${randomUUID4()}.tmp`;
5067
+ const handle = await open3(temporary, "wx", path.includes(`${sep2}.siteplane${sep2}`) ? 384 : 420);
5068
+ try {
5069
+ await handle.writeFile(content, "utf8");
5070
+ await handle.sync();
5071
+ await handle.close();
5072
+ await assertSourcePath(directory, path);
5073
+ const latest = await readFile10(path, "utf8").catch((error) => {
5074
+ if (error.code === "ENOENT")
5075
+ return null;
5076
+ throw error;
5077
+ });
5078
+ if (latest !== current)
5079
+ throw new SetupFailure("source_changed_during_prepare", "The source changed before the prepared write. The existing edit was preserved.");
5080
+ await rename3(temporary, path);
5081
+ } finally {
5082
+ await handle.close().catch(() => void 0);
5083
+ await rm3(temporary, { force: true });
5084
+ }
5085
+ written.push(relative5(directory, path));
5086
+ }
5087
+ return {
5088
+ status: "prepared",
5089
+ preexistingChanges: preflight.local.git.changes,
5090
+ files: written,
5091
+ packages: task.packages,
5092
+ nextAction: "Describe your content selection, instrument those values, then run setup apply with the editor definition and --selection-summary-file. Commit only the intended source before setup deploy --wait."
5093
+ };
5094
+ } catch (error) {
5095
+ return {
5096
+ status: "action_required",
5097
+ code: error instanceof SetupFailure ? error.code : "setup_preparation_failed",
5098
+ message: error instanceof SetupFailure ? error.message : "Setup preparation could not complete. Check the selected project, package access and current task; no credential values are included in this diagnostic."
5099
+ };
5100
+ }
5101
+ }
5102
+ async function assertSourcePath(root, target) {
5103
+ let current = root;
5104
+ for (const part of relative5(root, target).split(sep2)) {
5105
+ if (part === "..")
5106
+ throw new SetupFailure("unsafe_source_path", "The prepared file is outside the selected application.");
5107
+ current = join9(current, part);
5108
+ const stat = await lstat2(current).catch((error) => {
5109
+ if (error.code === "ENOENT")
5110
+ return null;
5111
+ throw error;
5112
+ });
5113
+ if (stat?.isSymbolicLink())
5114
+ throw new SetupFailure("unsafe_source_path", "Preparation cannot write through a symbolic link.");
5115
+ }
5116
+ }
5117
+
5118
+ // ../cli/dist/commands/setup-lock.js
5119
+ import { randomUUID as randomUUID5 } from "crypto";
5120
+ import { lstat as lstat3, mkdir as mkdir7, open as open4, readFile as readFile11, rm as rm4, rmdir } from "fs/promises";
5121
+ import { resolve as resolve2 } from "path";
5122
+ import { z as z31 } from "zod";
5123
+ var ownerSchema = z31.object({ pid: z31.number().int().positive(), nonce: z31.string().uuid() }).strict();
5124
+ async function withSetupLock(projectDir, work) {
5125
+ const gitPath = (await setupProcess("git", ["rev-parse", "--git-path", "siteplane-setup.lock"], { cwd: projectDir })).trim();
5126
+ const path = resolve2(projectDir, gitPath);
5127
+ const owner = { pid: process.pid, nonce: randomUUID5() };
5128
+ for (let attempt = 0; ; attempt++) {
5129
+ try {
5130
+ const handle = await open4(path, "wx", 384);
5131
+ try {
5132
+ await handle.writeFile(JSON.stringify(owner));
5133
+ await handle.sync();
5134
+ } finally {
5135
+ await handle.close();
5136
+ }
5137
+ break;
5138
+ } catch (error) {
5139
+ if (error.code !== "EEXIST")
5140
+ throw error;
5141
+ if (attempt || (await lstat3(path)).isSymbolicLink())
5142
+ throw locked();
5143
+ const recovery = `${path}.recovery`;
5144
+ try {
5145
+ await mkdir7(recovery, { mode: 448 });
5146
+ } catch {
5147
+ throw locked();
5148
+ }
5149
+ try {
5150
+ const source = await readFile11(path, "utf8");
5151
+ const existing = ownerSchema.safeParse(JSON.parse(source));
5152
+ if (!existing.success)
5153
+ throw locked();
5154
+ try {
5155
+ process.kill(existing.data.pid, 0);
5156
+ throw locked();
5157
+ } catch (failure) {
5158
+ if (failure.code !== "ESRCH")
5159
+ throw locked();
5160
+ }
5161
+ if (await readFile11(path, "utf8") !== source)
5162
+ throw locked();
5163
+ await rm4(path);
5164
+ } finally {
5165
+ await rmdir(recovery);
5166
+ }
5167
+ }
5168
+ }
5169
+ try {
5170
+ return await work();
5171
+ } finally {
5172
+ const current = await readFile11(path, "utf8").catch(() => "");
5173
+ if (current === JSON.stringify(owner))
5174
+ await rm4(path);
5175
+ }
5176
+ }
5177
+ function locked() {
5178
+ return new SetupFailure("setup_process_active", "Another setup process owns this repository. Wait for it to finish; a live lock is never replaced.");
5179
+ }
5180
+
5181
+ // ../cli/dist/config/build-provenance.js
5182
+ import { createHash as createHash3 } from "crypto";
5183
+ import { execFile as execFile3 } from "child_process";
5184
+ import { lstat as lstat4, readFile as readFile12, writeFile as writeFile5, mkdir as mkdir8 } from "fs/promises";
5185
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join10, relative as relative6, resolve as resolve3, sep as sep3 } from "path";
5186
+ import { isDeepStrictEqual, promisify as promisify3 } from "util";
5187
+ import { z as z32 } from "zod";
5188
+ var execute = promisify3(execFile3);
5189
+ var name = ".siteplane/build-source.json";
5190
+ var oid = z32.string().regex(/^[0-9a-f]{40}$/u);
5191
+ var entrySchema = z32.object({
5192
+ path: z32.string().min(1).max(4096),
5193
+ mode: z32.enum(["100644", "100755", "120000"]),
5194
+ oid
5195
+ }).strict();
5196
+ var schema = z32.object({
5197
+ version: z32.literal(2),
5198
+ revision: oid,
5199
+ commit: z32.string().min(1).max(1048576),
5200
+ entries: z32.array(entrySchema).min(1).max(1e5),
5201
+ providerConfigurations: z32.array(z32.object({
5202
+ path: z32.string().max(4096).regex(/(?:^|\/)vercel\.json$/u),
5203
+ source: z32.string().max(1048576)
5204
+ }).strict()).max(1e3)
5205
+ }).strict();
5206
+ async function writeBuildProvenance(checkout, revision) {
5207
+ const commit = (await execute("git", ["cat-file", "commit", revision], {
5208
+ cwd: checkout,
5209
+ maxBuffer: 1048576
5210
+ })).stdout;
5211
+ const tree = (await execute("git", ["ls-tree", "-rz", "--full-tree", revision], {
5212
+ cwd: checkout,
5213
+ maxBuffer: 16777216
5214
+ })).stdout;
5215
+ const entries = tree.split("\0").filter(Boolean).map((line) => {
5216
+ const match = /^(100644|100755|120000) blob ([0-9a-f]{40})\t([\s\S]+)$/u.exec(line);
5217
+ if (!match)
5218
+ throw new Error("Git submodules or unsupported tracked objects need an explicit deployment configuration.");
5219
+ return { path: match[3], mode: match[1], oid: match[2] };
5220
+ });
5221
+ for (const entry of entries) {
5222
+ if (entry.mode !== "120000")
5223
+ continue;
5224
+ const { readlink: readlink2 } = await import("fs/promises");
5225
+ const path = join10(checkout, entry.path);
5226
+ const target2 = resolve3(dirname8(path), await readlink2(path));
5227
+ const bound = relative6(checkout, target2);
5228
+ if (bound.startsWith("..") || isAbsolute2(bound))
5229
+ throw new Error("A tracked symbolic link escapes the committed upload; resolve that source boundary before deployment.");
5230
+ }
5231
+ const providerConfigurations = await Promise.all(entries.filter((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path)).map(async (entry) => ({
5232
+ path: entry.path,
5233
+ source: await readFile12(join10(checkout, entry.path), "utf8")
5234
+ })));
5235
+ const record = schema.parse({
5236
+ version: 2,
5237
+ revision,
5238
+ commit,
5239
+ entries,
5240
+ providerConfigurations
5241
+ });
5242
+ const target = join10(checkout, name);
5243
+ await mkdir8(dirname8(target), { recursive: true, mode: 448 });
5244
+ await writeFile5(target, JSON.stringify(record), { flag: "wx", mode: 384 });
5245
+ }
5246
+
5247
+ // ../cli/dist/commands/setup-deploy.js
5248
+ import { createHash as createHash4, randomBytes, randomUUID as randomUUID6 } from "crypto";
5249
+ import { access as access5, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
5250
+ import { tmpdir } from "os";
5251
+ import { join as join11 } from "path";
5252
+ import { z as z33 } from "zod";
5253
+ var envSchema = z33.object({
5254
+ id: z33.string(),
5255
+ key: z33.string(),
5256
+ target: z33.array(z33.string()),
5257
+ type: z33.string(),
5258
+ comment: z33.string().optional(),
5259
+ updatedAt: z33.number().optional()
5260
+ });
5261
+ var deploymentSchema = z33.object({
5262
+ id: z33.string(),
5263
+ projectId: z33.string(),
5264
+ ownerId: z33.string().optional(),
5265
+ target: z33.string().nullable(),
5266
+ readyState: z33.string(),
5267
+ createdAt: z33.number(),
5268
+ url: z33.string(),
5269
+ meta: z33.record(z33.string(), z33.unknown()).optional(),
5270
+ gitSource: z33.object({ sha: z33.string().optional() }).nullable().optional()
5271
+ });
5272
+ var buildProofSchema = z33.object({
5273
+ node: z33.string(),
5274
+ packageManager: z33.enum(["npm", "pnpm"]),
5275
+ packageManagerVersion: z33.string(),
5276
+ lockfileHash: z33.string(),
5277
+ revision: z33.string(),
5278
+ fieldContractHash: z33.string(),
5279
+ siteplane: z33.string(),
5280
+ runtimeNext: z33.string(),
5281
+ next: z33.string(),
5282
+ react: z33.string()
5283
+ }).strict();
5284
+ var digest = (value) => `sha256:${createHash4("sha256").update(stableJsonStringify(value)).digest("hex")}`;
5285
+ function fail2(code, message) {
5286
+ throw new SetupFailure(code, message);
5287
+ }
5288
+ var defaults = {
5289
+ preflight: setupPreflightCommand,
5290
+ context: siteSetupContextCommand,
5291
+ api: setupVercelApi,
5292
+ process: setupProcess,
5293
+ verify: siteSetupVerifyCommand,
5294
+ post: postSiteSetup,
5295
+ writeBuildProvenance,
5296
+ now: Date.now,
5297
+ pause: (milliseconds) => new Promise((resolve5) => setTimeout(resolve5, milliseconds))
5298
+ };
5299
+ async function setupDeployCommand(input, deps = defaults) {
5300
+ let record = null;
5301
+ try {
5302
+ if (!await access5(join11(input.projectDir, "siteplane.config.json")).then(() => true, () => false) || !await access5(join11(input.projectDir, ".siteplane/credentials.json")).then(() => true, () => false))
5303
+ fail2("local_connection_missing", "Open this site's setup and choose Replace local connection, then initialize this folder with its new one-time grant.");
5304
+ await assertLocalCredentialsPathSafe(input.projectDir);
5305
+ const config = await readProjectConfig(input.projectDir);
5306
+ let credentials = await readLocalCredentials(input.projectDir);
5307
+ const context = await deps.context(input);
5308
+ if (context.status !== "ok")
5309
+ return context;
5310
+ const task = context.task;
5311
+ if (task.run?.runId !== config.runId || task.site?.siteId !== config.siteId || task.packages.siteplane !== config.packages.siteplane || task.packages.runtimeNext !== config.packages.runtimeNext || task.run.fieldContractHash !== config.fieldContractHash)
5312
+ fail2("setup_contract_conflict", "Local configuration and the current applied setup task must match before deployment.");
5313
+ if (!config.fieldContractHash)
5314
+ fail2("setup_apply_required", "Instrument the agreed content and run setup apply before deployment.");
5315
+ record = task.deployment;
5316
+ const preflight = await deps.preflight(input);
5317
+ if (preflight.status !== "ready")
5318
+ return {
5319
+ ...preflight,
5320
+ ...record ? { deploymentId: record.deploymentId, deadline: record.deadline } : {}
5321
+ };
5322
+ const { local, provider } = preflight;
5323
+ if (local.git.changes.length || !local.git.revision || !local.git.branch)
5324
+ fail2("uncommitted_source", "Commit only the intended setup source on a named branch before deployment. Siteplane does not stage, reset or publish unrelated local work.");
5325
+ const revision = local.git.revision;
5326
+ if (!/^[0-9a-f]{40}$/u.test(revision))
5327
+ fail2("invalid_git_revision", "A full committed Git revision is required.");
5328
+ try {
5329
+ await assertExactSetupPackages(local.projectDirectory, config.packages);
5330
+ } catch {
5331
+ fail2("siteplane_package_pin_conflict", "Install the exact Siteplane package versions from the current task and commit their canonical lockfile.");
5332
+ }
5333
+ let operationDeadline = record && !["verified", "failed"].includes(record.phase) ? Date.parse(record.deadline) : deps.now() + 9e5;
5334
+ const remaining = () => {
5335
+ const milliseconds = operationDeadline - deps.now();
5336
+ if (milliseconds <= 0)
5337
+ fail2("provider_deadline_exceeded", "The 15-minute provider deadline expired. Inspect the recorded operation; setup will not start a second deployment on resume.");
5338
+ return milliseconds;
5339
+ };
5340
+ const processCommand = async (binary, args, options) => {
5341
+ const output = await deps.process(binary, args, {
5342
+ ...options,
5343
+ timeoutMs: Math.min(options.timeoutMs ?? 12e4, remaining())
5344
+ });
5345
+ remaining();
5346
+ return output;
5347
+ };
5348
+ const scope = `teamId=${provider.teamId}`;
5349
+ const api = async (endpoint, body, method) => {
5350
+ remaining();
5351
+ const result = await deps.api(local.projectDirectory, endpoint, body, method, { deadline: operationDeadline });
5352
+ remaining();
5353
+ return result;
5354
+ };
5355
+ const domains = z33.object({
5356
+ domains: z33.array(z33.object({
5357
+ name: z33.string(),
5358
+ verified: z33.boolean(),
5359
+ redirect: z33.string().nullable().optional(),
5360
+ gitBranch: z33.string().nullable().optional()
5361
+ }))
5362
+ }).parse(await api(`/v9/projects/${provider.projectId}/domains?${scope}`)).domains.filter((domain) => domain.verified && !domain.redirect && !domain.gitBranch);
5363
+ const origin = record?.origin ?? (domains.length === 1 ? `https://${domains[0].name}` : null);
5364
+ if (!origin || !domains.some((domain) => `https://${domain.name}` === origin))
5365
+ fail2("production_origin_ambiguous", "The linked project needs one verified canonical Production domain, or the existing setup domain must still belong to it.");
5366
+ if (record && (record.projectId !== provider.projectId || record.teamId !== provider.teamId))
5367
+ fail2("deployment_target_conflict", "This setup already belongs to a different provider project/team. Restore its original local link.");
5368
+ const listEnv = async () => z33.object({ envs: z33.array(envSchema) }).parse(await api(`/v10/projects/${provider.projectId}/env?${scope}`)).envs;
5369
+ let env = await listEnv();
5370
+ const owned = (key) => {
5371
+ const matches2 = env.filter((item) => item.key === key && item.target.includes("production"));
5372
+ if (matches2.length > 1 || matches2.some((item) => item.target.length !== 1))
5373
+ fail2("environment_scope_conflict", `Separate ${key} into an unambiguous Production-only binding before setup; other scopes are preserved.`);
5374
+ return matches2[0];
5375
+ };
5376
+ const admin = owned("SITEPLANE_ADMIN_SESSION_SECRET");
5377
+ if (record && !admin && !credentials.adminSession)
5378
+ fail2("admin_secret_recovery_required", "The previously configured admin-session secret is missing. Restore it through an explicit owner-directed configuration recovery; connection replacement never rotates it.");
5379
+ if (!credentials.adminSession && !record && admin)
5380
+ fail2("admin_secret_binding_unknown", "An existing admin-session secret has no matching setup generation. Resolve its ownership before configuration; Siteplane will not overwrite it.");
5381
+ if (!credentials.adminSession && !record && !admin) {
5382
+ credentials = {
5383
+ ...credentials,
5384
+ adminSession: {
5385
+ secret: randomBytes(32).toString("base64url"),
5386
+ generation: randomUUID6()
5387
+ }
5388
+ };
5389
+ await writeLocalCredentials(input.projectDir, credentials);
5390
+ const persisted = await readLocalCredentials(input.projectDir);
5391
+ if (persisted.adminSession?.secret !== credentials.adminSession.secret)
5392
+ fail2("credential_write_failed", "The generated admin credential could not be read back securely.");
5393
+ }
5394
+ const generation = record?.adminSecretGeneration ?? credentials.adminSession.generation;
5395
+ if (credentials.adminSession && credentials.adminSession.generation !== generation)
5396
+ fail2("admin_secret_generation_conflict", "The local admin credential belongs to another configuration generation. Preserve the provider secret and resolve the local binding.");
5397
+ if (admin && admin.comment !== `Siteplane admin generation ${generation}`)
5398
+ fail2("admin_secret_generation_conflict", "The provider admin secret does not match the recorded setup generation. No secret was replaced.");
5399
+ const publicBindings = {
5400
+ SITEPLANE_SITE_KEY: config.publicSiteKey,
5401
+ RUNTIME_API_BASE_URL: config.apiBaseUrl,
5402
+ SITEPLANE_SITE_ORIGIN: origin,
5403
+ SITEPLANE_SETUP_RUN_ID: config.runId,
5404
+ SITEPLANE_PORTAL_PATH: task.site.portalPath,
5405
+ SITEPLANE_BUILD_FIELD_CONTRACT_HASH: config.fieldContractHash,
5406
+ SITEPLANE_BUILD_REVISION: revision
5407
+ };
5408
+ const fingerprint = digest({
5409
+ publicBindings,
5410
+ siteId: config.siteId,
5411
+ publicKeyId: config.publicSiteKeyId,
5412
+ apiBaseUrl: config.apiBaseUrl,
5413
+ packages: config.packages,
5414
+ bindings: [
5415
+ ...Object.keys(publicBindings),
5416
+ "SITEPLANE_REVALIDATION_SECRET",
5417
+ "SITEPLANE_ADMIN_SESSION_SECRET"
5418
+ ].sort(),
5419
+ adminSecretGeneration: generation,
5420
+ revalidationGeneration: task.revalidationGeneration,
5421
+ projectId: provider.projectId,
5422
+ teamId: provider.teamId,
5423
+ rootDirectory: provider.rootDirectory,
5424
+ nodeVersion: provider.nodeVersion,
5425
+ installCommand: provider.installCommand,
5426
+ buildCommand: provider.buildCommand,
5427
+ packageManagerSelection: provider.packageManagerSelection,
5428
+ declaredPackageManager: provider.declaredPackageManager,
5429
+ lockfileHash: local.lockfile.sha256
5430
+ });
5431
+ const save = async (next) => {
5432
+ const result = await deps.post({ ...input, deadline: operationDeadline }, "deployment", {
5433
+ action: "record",
5434
+ expectedOperationId: record?.operationId ?? null,
5435
+ record: next
5436
+ });
5437
+ const parsed = z33.object({
5438
+ ok: z33.literal(true),
5439
+ data: z33.object({ record: setupDeploymentRecordSchema }).strict()
5440
+ }).strict().safeParse(result.payload);
5441
+ if (!result.ok || !parsed.success || stableJsonStringify(parsed.data.data.record) !== stableJsonStringify(next))
5442
+ fail2("deployment_record_unconfirmed", "The setup deployment record was not acknowledged. Reload context before continuing; no deployment is blindly repeated.");
5443
+ record = parsed.data.data.record;
5444
+ if (next.phase === "planned")
5445
+ operationDeadline = Date.parse(next.deadline);
5446
+ };
5447
+ const fresh = () => ({
5448
+ version: 1,
5449
+ operationId: randomUUID6(),
5450
+ provider: "vercel",
5451
+ projectId: provider.projectId,
5452
+ teamId: provider.teamId,
5453
+ origin,
5454
+ deploymentId: null,
5455
+ revision,
5456
+ fieldContractHash: config.fieldContractHash,
5457
+ packages: config.packages,
5458
+ configurationFingerprint: fingerprint,
5459
+ adminSecretGeneration: generation,
5460
+ revalidationGeneration: task.revalidationGeneration,
5461
+ startedAt: new Date(deps.now()).toISOString(),
5462
+ environmentWrittenAt: null,
5463
+ deployRequestedAt: null,
5464
+ deadline: new Date(deps.now() + 9e5).toISOString(),
5465
+ phase: "planned",
5466
+ build: null
5467
+ });
5468
+ if (!record || record.configurationFingerprint !== fingerprint) {
5469
+ if (record && !["verified", "deployed", "failed"].includes(record.phase))
5470
+ fail2("previous_deployment_unresolved", "Resolve the previous provider operation before changing the source or configuration.");
5471
+ await save(fresh());
5472
+ }
5473
+ const progress = () => input.onProgress?.({
5474
+ phase: record.phase,
5475
+ deadline: record.deadline,
5476
+ deploymentId: record.deploymentId
5477
+ });
5478
+ progress();
5479
+ const values = {
5480
+ ...publicBindings,
5481
+ SITEPLANE_REVALIDATION_SECRET: credentials.siteRevalidationSecret,
5482
+ ...credentials.adminSession ? { SITEPLANE_ADMIN_SESSION_SECRET: credentials.adminSession.secret } : {}
5483
+ };
5484
+ const pending = [];
5485
+ for (const [key, value] of Object.entries(values)) {
5486
+ const item = owned(key);
5487
+ if (key === "SITEPLANE_ADMIN_SESSION_SECRET" && item && record.phase === "verified")
5488
+ continue;
5489
+ const current = item ? z33.object({ key: z33.literal(key), value: z33.string() }).parse(await api(`/v1/projects/${provider.projectId}/env/${encodeURIComponent(item.id)}?${scope}`)).value : null;
5490
+ if (current !== value)
5491
+ pending.push({
5492
+ key,
5493
+ value,
5494
+ type: key.endsWith("SECRET") ? "encrypted" : "plain",
5495
+ target: ["production"],
5496
+ comment: key === "SITEPLANE_ADMIN_SESSION_SECRET" ? `Siteplane admin generation ${generation}` : "Managed by Siteplane setup"
5497
+ });
5498
+ }
5499
+ if (pending.length && record.phase !== "planned") {
5500
+ if (!["verified", "deployed", "failed"].includes(record.phase))
5501
+ fail2("environment_changed_during_deploy", "The environment changed during an unresolved deployment. Inspect that operation before retrying.");
5502
+ await save(fresh());
5503
+ }
5504
+ if (record.phase === "planned") {
5505
+ if (deps.now() >= Date.parse(record.deadline))
5506
+ fail2("provider_deadline_exceeded", "The setup provider deadline expired before configuration. Inspect its existing record before a new attempt.");
5507
+ for (const binding of pending)
5508
+ await api(`/v10/projects/${provider.projectId}/env?${scope}&upsert=true`, binding);
5509
+ env = await listEnv();
5510
+ for (const [key, value] of Object.entries(values)) {
5511
+ const item = owned(key);
5512
+ if (!item)
5513
+ fail2("environment_write_unconfirmed", "A Siteplane Production binding was not persisted; retry the same configuration.");
5514
+ const observed = z33.object({ key: z33.literal(key), value: z33.string() }).parse(await api(`/v1/projects/${provider.projectId}/env/${encodeURIComponent(item.id)}?${scope}`));
5515
+ if (observed.value !== value)
5516
+ fail2("environment_write_unconfirmed", "The provider readback does not match the authorized Siteplane value; no deployment was started.");
5517
+ }
5518
+ await save({
5519
+ ...record,
5520
+ phase: "environment_written",
5521
+ environmentWrittenAt: new Date(deps.now()).toISOString()
5522
+ });
5523
+ }
5524
+ const detail = async (id) => deploymentSchema.parse(await api(`/v13/deployments/${encodeURIComponent(id)}?${scope}&withGitRepoInfo=true`));
5525
+ const matches = (deployment2) => deployment2.projectId === provider.projectId && deployment2.target === "production" && (!deployment2.ownerId || deployment2.ownerId === provider.teamId) && deployment2.createdAt >= Date.parse(record.environmentWrittenAt) && (deployment2.meta?.siteplaneOperationId === record.operationId || provider.git && (deployment2.gitSource?.sha ?? deployment2.meta?.githubCommitSha ?? deployment2.meta?.gitlabCommitSha ?? deployment2.meta?.bitbucketCommitSha ?? deployment2.meta?.gitCommitSha) === revision);
5526
+ const discover = async () => {
5527
+ const result = z33.object({ deployments: z33.array(z33.object({ uid: z33.string() })) }).parse(await api(`/v6/deployments?${scope}&projectId=${provider.projectId}&target=production&since=${Date.parse(record.environmentWrittenAt)}&limit=100`));
5528
+ const candidates = [];
5529
+ for (const item of result.deployments) {
5530
+ const found = await detail(item.uid);
5531
+ if (matches(found))
5532
+ candidates.push(found);
5533
+ }
5534
+ if (candidates.length > 1)
5535
+ fail2("deployment_ambiguous", "Multiple matching provider deployments exist. Select the existing intended operation before continuing; no additional build was started.");
5536
+ return candidates[0] ?? null;
5537
+ };
5538
+ let deployment = record.deploymentId ? await detail(record.deploymentId) : await discover();
5539
+ if (deployment && !matches(deployment))
5540
+ fail2("deployment_binding_conflict", "The stored deployment does not match this project, commit and environment generation.");
5541
+ if (!deployment && record.phase === "environment_written") {
5542
+ const status = await processCommand("git", ["status", "--porcelain=v1", "--untracked-files=all"], { cwd: local.repositoryRoot });
5543
+ const head = (await processCommand("git", ["rev-parse", "HEAD"], {
5544
+ cwd: local.repositoryRoot
5545
+ })).trim();
5546
+ if (status.trim() || head !== revision)
5547
+ fail2("source_changed_before_deploy", "The source changed after preflight. Commit only the intended source and rerun setup deploy.");
5548
+ await save({
5549
+ ...record,
5550
+ phase: "deploy_requested",
5551
+ deployRequestedAt: new Date(deps.now()).toISOString()
5552
+ });
5553
+ try {
5554
+ if (provider.git) {
5555
+ const remote = (await processCommand("git", ["ls-remote", "origin", `refs/heads/${local.git.branch}`], { cwd: local.repositoryRoot })).trim().split(/\s/u)[0];
5556
+ if (remote !== revision)
5557
+ await processCommand("git", ["push", "origin", `HEAD:refs/heads/${local.git.branch}`], { cwd: local.repositoryRoot });
5558
+ else {
5559
+ const gitSource = {
5560
+ type: provider.git.type,
5561
+ ref: revision,
5562
+ ...provider.git.repoId ? { repoId: provider.git.repoId } : {}
5563
+ };
5564
+ const body = JSON.stringify({
5565
+ name: provider.name,
5566
+ project: provider.projectId,
5567
+ target: "production",
5568
+ gitSource,
5569
+ meta: { siteplaneOperationId: record.operationId }
5570
+ });
5571
+ await processCommand("vercel", [
5572
+ "api",
5573
+ `/v13/deployments?${scope}`,
5574
+ "--method",
5575
+ "POST",
5576
+ "--input",
5577
+ "-",
5578
+ "--raw"
5579
+ ], { cwd: local.projectDirectory, input: body, timeoutMs: 3e4 });
5580
+ }
5581
+ } else {
5582
+ const upload = await mkdtemp(join11(tmpdir(), "siteplane-setup-upload-"));
5583
+ try {
5584
+ await processCommand("git", [
5585
+ "clone",
5586
+ "--no-hardlinks",
5587
+ "--no-checkout",
5588
+ "--",
5589
+ local.repositoryRoot,
5590
+ upload
5591
+ ], { cwd: local.repositoryRoot });
5592
+ await processCommand("git", ["checkout", "--detach", revision], {
5593
+ cwd: upload
5594
+ });
5595
+ await deps.writeBuildProvenance(upload, revision);
5596
+ await mkdir9(join11(upload, ".vercel"), {
5597
+ recursive: true,
5598
+ mode: 448
5599
+ });
5600
+ await writeFile6(join11(upload, ".vercel/project.json"), JSON.stringify({
5601
+ projectId: provider.projectId,
5602
+ orgId: provider.teamId
5603
+ }), { mode: 384 });
5604
+ await processCommand("vercel", [
5605
+ "deploy",
5606
+ "--yes",
5607
+ "--prod",
5608
+ "--no-wait",
5609
+ "--scope",
5610
+ provider.teamId,
5611
+ "--meta",
5612
+ `siteplaneOperationId=${record.operationId}`
5613
+ ], { cwd: upload, timeoutMs: 12e4 });
5614
+ } finally {
5615
+ await rm5(upload, { recursive: true, force: true });
5616
+ }
5617
+ }
5618
+ } catch (error) {
5619
+ if (error instanceof SetupFailure && error.code === "provider_access_denied") {
5620
+ await save({
5621
+ ...record,
5622
+ phase: "environment_written",
5623
+ deployRequestedAt: null
5624
+ });
5625
+ throw error;
5626
+ }
5627
+ if (!(error instanceof SetupFailure) || !["provider_timeout", "provider_transport_failed"].includes(error.code))
5628
+ throw error;
5629
+ }
5630
+ }
5631
+ let poll = 0;
5632
+ while (!deployment || !["READY", "ERROR", "CANCELED"].includes(deployment.readyState)) {
5633
+ progress();
5634
+ const remaining2 = Date.parse(record.deadline) - deps.now();
5635
+ if (remaining2 <= 0)
5636
+ fail2("provider_deadline_exceeded", "The 15-minute provider deadline expired. Inspect the recorded operation; setup will not start a second deployment on resume.");
5637
+ await deps.pause(Math.min(remaining2, Math.min(15e3, 2e3 * 2 ** Math.min(poll++, 3)) + Math.floor(Math.random() * 500)));
5638
+ deployment = deployment ? await detail(deployment.id) : await discover();
5639
+ if (deployment && !matches(deployment))
5640
+ fail2("deployment_binding_conflict", "The provider operation no longer matches this setup deployment.");
5641
+ }
5642
+ if (deployment.readyState !== "READY") {
5643
+ await save({ ...record, phase: "failed", deploymentId: deployment.id });
5644
+ fail2("provider_build_failed", "The existing provider build failed or was canceled. Fix its diagnosed package/build configuration before requesting another deployment.");
5645
+ }
5646
+ if (record.phase !== "verified")
5647
+ await save({
5648
+ ...record,
5649
+ phase: "deployed",
5650
+ deploymentId: deployment.id
5651
+ });
5652
+ const logs = await processCommand("vercel", ["inspect", deployment.url, "--logs", "--scope", provider.teamId], { cwd: local.projectDirectory, includeStderr: true });
5653
+ const markers = [
5654
+ ...logs.matchAll(/SITEPLANE_BUILD_PROOF=(\{[^\n]+\})/gu)
5655
+ ].map((match) => buildProofSchema.parse(JSON.parse(match[1])));
5656
+ const proof = markers.find((item) => item.revision === revision && item.fieldContractHash === config.fieldContractHash);
5657
+ if (!proof || !/^22\.\d+\.\d+$/u.test(proof.node) || proof.siteplane !== config.packages.siteplane || proof.runtimeNext !== config.packages.runtimeNext || proof.lockfileHash !== `sha256:${local.lockfile.sha256}` || proof.next !== local.nextVersion || proof.react !== local.reactVersion || !(proof.packageManager === "npm" ? /^10\./u : /^(9|10)\./u).test(proof.packageManagerVersion) || local.packageManager.declared && `${proof.packageManager}@${proof.packageManagerVersion}` !== local.packageManager.declared)
5658
+ fail2("provider_build_identity_missing", "The actual provider build did not prove the expected Node, package manager, lockfile, package pins and applied source. Inspect its install/build configuration.");
5659
+ const canonical = await detail(new URL(origin).hostname);
5660
+ if (canonical.id !== deployment.id)
5661
+ fail2("production_alias_not_ready", "The canonical Production domain does not yet point to the verified deployment. Inspect the existing promotion; do not create another build.");
5662
+ const verified = await deps.verify({ ...input, deploymentUrl: origin });
5663
+ if (verified.status !== "ready_for_review")
5664
+ return {
5665
+ ...verified,
5666
+ deadline: record.deadline,
5667
+ deploymentId: deployment.id
5668
+ };
5669
+ await save({
5670
+ ...record,
5671
+ phase: "verified",
5672
+ deploymentId: deployment.id,
5673
+ build: {
5674
+ node: proof.node,
5675
+ packageManager: proof.packageManager,
5676
+ packageManagerVersion: proof.packageManagerVersion,
5677
+ lockfileHash: proof.lockfileHash
5678
+ }
5679
+ });
5680
+ return {
5681
+ status: "ready_for_review",
5682
+ deploymentId: deployment.id,
5683
+ origin,
5684
+ configurationFingerprint: fingerprint,
5685
+ deadline: record.deadline,
5686
+ build: record.build
5687
+ };
5688
+ } catch (error) {
5689
+ return {
5690
+ status: "action_required",
5691
+ code: error instanceof SetupFailure ? error.code : "setup_deployment_failed",
5692
+ message: error instanceof SetupFailure ? error.message : "The setup deployment could not be validated. Inspect the local connection and bound provider operation; credential values are never included.",
5693
+ ...record ? { deploymentId: record.deploymentId, deadline: record.deadline } : {}
5694
+ };
5695
+ }
5696
+ }
5697
+
4250
5698
  // src/bin/run-siteplane.ts
4251
5699
  async function runSiteplaneCli(args, dependencies = createDefaultDependencies()) {
5700
+ const writes = args[0] === "init" || args[0] === "setup" && ["apply", "prepare", "deploy"].includes(args[1] ?? "");
5701
+ const missingDeploy = args[0] === "setup" && args[1] === "deploy" && !await access6(join12(dependencies.cwd(), "siteplane.config.json")).then(
5702
+ () => true,
5703
+ () => false
5704
+ );
5705
+ return writes && !missingDeploy ? dependencies.withSetupLock(
5706
+ dependencies.cwd(),
5707
+ () => runSiteplaneCliUnlocked(args, dependencies)
5708
+ ) : runSiteplaneCliUnlocked(args, dependencies);
5709
+ }
5710
+ async function runSiteplaneCliUnlocked(args, dependencies = createDefaultDependencies()) {
4252
5711
  const [command, ...commandArgs] = args;
4253
5712
  if (command === "init") {
4254
5713
  const setupToken = readOption(commandArgs, "--setup-token");
@@ -4321,7 +5780,7 @@ async function runAnalyticsCommand(args, dependencies) {
4321
5780
  siteId: projectConfig.siteId,
4322
5781
  ...readOptionalVercelAutomationBypassSecret(dependencies.env)
4323
5782
  };
4324
- const manifestPath = join7(projectDir, "siteplane.analytics.json");
5783
+ const manifestPath = join12(projectDir, "siteplane.analytics.json");
4325
5784
  if (subcommand === "init") {
4326
5785
  const rawPublicKey = await dependencies.commands.analyticsPublicKeyCommand({
4327
5786
  config
@@ -4353,18 +5812,18 @@ async function runAnalyticsCommand(args, dependencies) {
4353
5812
  projectDir
4354
5813
  }
4355
5814
  );
4356
- const artifactFilePaths = [join7(projectDir, ".siteplane/analytics.md")];
5815
+ const artifactFilePaths = [join12(projectDir, ".siteplane/analytics.md")];
4357
5816
  const cspFilePaths = await existingPaths([
4358
- join7(projectDir, "next.config.js"),
4359
- join7(projectDir, "next.config.mjs"),
4360
- join7(projectDir, "next.config.ts"),
4361
- join7(projectDir, "middleware.ts"),
4362
- join7(projectDir, "src/middleware.ts")
5817
+ join12(projectDir, "next.config.js"),
5818
+ join12(projectDir, "next.config.mjs"),
5819
+ join12(projectDir, "next.config.ts"),
5820
+ join12(projectDir, "middleware.ts"),
5821
+ join12(projectDir, "src/middleware.ts")
4363
5822
  ]);
4364
5823
  const check = await dependencies.commands.analyticsCheckCommand({
4365
5824
  manifestPath,
4366
5825
  sourceFilePaths,
4367
- packageJsonPath: join7(projectDir, "package.json"),
5826
+ packageJsonPath: join12(projectDir, "package.json"),
4368
5827
  cspFilePaths,
4369
5828
  artifactFilePaths
4370
5829
  });
@@ -4432,6 +5891,28 @@ async function runSetupCommand(args, dependencies) {
4432
5891
  const connectionOptions = readOptionalVercelAutomationBypassSecret(
4433
5892
  dependencies.env
4434
5893
  );
5894
+ if (area === "deploy") {
5895
+ const result = await dependencies.commands.setupDeployCommand({
5896
+ projectDir,
5897
+ onProgress: (progress) => dependencies.stderr(JSON.stringify({ status: "waiting", ...progress }))
5898
+ });
5899
+ dependencies.stdout(JSON.stringify(result, null, 2));
5900
+ return { exitCode: result.status === "ready_for_review" ? 0 : 1 };
5901
+ }
5902
+ if (area === "preflight") {
5903
+ const result = await dependencies.commands.setupPreflightCommand({
5904
+ projectDir
5905
+ });
5906
+ dependencies.stdout(JSON.stringify(result, null, 2));
5907
+ return { exitCode: result.status === "ready" ? 0 : 1 };
5908
+ }
5909
+ if (area === "prepare") {
5910
+ const result = await dependencies.commands.setupPrepareCommand({
5911
+ projectDir
5912
+ });
5913
+ dependencies.stdout(JSON.stringify(result, null, 2));
5914
+ return { exitCode: result.status === "action_required" ? 1 : 0 };
5915
+ }
4435
5916
  if (area === "context") {
4436
5917
  const result = await dependencies.commands.siteSetupContextCommand({
4437
5918
  projectDir,
@@ -4456,6 +5937,12 @@ async function runSetupCommand(args, dependencies) {
4456
5937
  const result = await dependencies.commands.siteSetupApplyCommand({
4457
5938
  projectDir,
4458
5939
  editorDefinition,
5940
+ contentSelectionSummary: await dependencies.readTextFile(
5941
+ resolve4(
5942
+ projectDir,
5943
+ readRequiredOption(areaArgs, "--selection-summary-file")
5944
+ )
5945
+ ),
4459
5946
  ...connectionOptions
4460
5947
  });
4461
5948
  dependencies.stdout(JSON.stringify(result, null, 2));
@@ -4471,13 +5958,15 @@ async function runSetupCommand(args, dependencies) {
4471
5958
  dependencies.stdout(JSON.stringify(result, null, 2));
4472
5959
  return { exitCode: result.status === "ready_for_review" ? 0 : 1 };
4473
5960
  }
4474
- dependencies.stdout("Usage: siteplane setup <context|activity|apply|verify>");
5961
+ dependencies.stdout(
5962
+ "Usage: siteplane setup <preflight|prepare|context|activity|apply|deploy|verify>"
5963
+ );
4475
5964
  return { exitCode: 1 };
4476
5965
  }
4477
5966
  async function runBookingCommand(args, dependencies) {
4478
5967
  const [subcommand, ...subcommandArgs] = args;
4479
5968
  const projectDir = dependencies.cwd();
4480
- const manifestPath = join7(projectDir, "siteplane.booking.json");
5969
+ const manifestPath = join12(projectDir, "siteplane.booking.json");
4481
5970
  if (subcommand === "init") {
4482
5971
  const siteId = readRequiredOption(subcommandArgs, "--site-id");
4483
5972
  const siteKeyPrefix = readRequiredOption(
@@ -4556,7 +6045,7 @@ async function runBookingCommand(args, dependencies) {
4556
6045
  resourceId: readOption(subcommandArgs, "--resource-id") ?? null,
4557
6046
  startUtc: readRequiredOption(subcommandArgs, "--start-utc"),
4558
6047
  customer,
4559
- clientToken: readOption(subcommandArgs, "--client-token") ?? randomUUID4(),
6048
+ clientToken: readOption(subcommandArgs, "--client-token") ?? randomUUID7(),
4560
6049
  paymentChoice: "onsite"
4561
6050
  }
4562
6051
  });
@@ -4592,12 +6081,14 @@ function createDefaultDependencies() {
4592
6081
  env: process.env,
4593
6082
  stdout: (line) => console.log(line),
4594
6083
  stderr: (line) => console.error(line),
6084
+ readTextFile: (path) => readFile13(path, "utf8"),
6085
+ withSetupLock,
4595
6086
  readJsonFile: async (path) => JSON.parse(
4596
- await readFile8(resolve(process.cwd(), path), "utf8")
6087
+ await readFile13(resolve4(process.cwd(), path), "utf8")
4597
6088
  ),
4598
6089
  readPackageVersion: async () => {
4599
6090
  const packageJson = JSON.parse(
4600
- await readFile8(new URL("../../package.json", import.meta.url), "utf8")
6091
+ await readFile13(new URL("../../package.json", import.meta.url), "utf8")
4601
6092
  );
4602
6093
  return packageJson.version;
4603
6094
  },
@@ -4606,6 +6097,9 @@ function createDefaultDependencies() {
4606
6097
  siteSetupContextCommand,
4607
6098
  siteSetupActivityCommand,
4608
6099
  siteSetupVerifyCommand,
6100
+ setupPreflightCommand,
6101
+ setupPrepareCommand,
6102
+ setupDeployCommand,
4609
6103
  initCommand,
4610
6104
  bookingInitCommand,
4611
6105
  bookingCheckCommand,
@@ -4666,7 +6160,7 @@ async function existingPaths(paths) {
4666
6160
  const existing = [];
4667
6161
  for (const path of paths) {
4668
6162
  try {
4669
- await access2(path);
6163
+ await access6(path);
4670
6164
  existing.push(path);
4671
6165
  } catch {
4672
6166
  }