@siteoshq/cli 1.13.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +21 -22
  2. package/dist/cli.js +789 -2471
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +18 -20
package/dist/cli.js CHANGED
@@ -17,7 +17,7 @@ __export(cookie_verification_exports, {
17
17
  verificationTarget: () => verificationTarget,
18
18
  verifyCookieWebsite: () => verifyCookieWebsite
19
19
  });
20
- import { z as z15 } from "zod";
20
+ import { z as z12 } from "zod";
21
21
  function verificationTarget(websiteUrl, candidate) {
22
22
  const website = new URL(websiteUrl);
23
23
  const target = new URL(candidate ?? websiteUrl, website);
@@ -362,80 +362,80 @@ var Names, Service, Envelope, State, VerificationInstallation;
362
362
  var init_cookie_verification = __esm({
363
363
  "src/services/cookie-verification.ts"() {
364
364
  "use strict";
365
- Names = z15.object({
366
- exact: z15.array(z15.string()),
367
- prefixes: z15.array(z15.string())
368
- });
369
- Service = z15.object({
370
- key: z15.string(),
371
- purposeKey: z15.string(),
372
- lifecycle: z15.object({
373
- scriptOrigins: z15.array(z15.string()),
374
- iframeOrigins: z15.array(z15.string()),
375
- pixelOrigins: z15.array(z15.string()),
365
+ Names = z12.object({
366
+ exact: z12.array(z12.string()),
367
+ prefixes: z12.array(z12.string())
368
+ });
369
+ Service = z12.object({
370
+ key: z12.string(),
371
+ purposeKey: z12.string(),
372
+ lifecycle: z12.object({
373
+ scriptOrigins: z12.array(z12.string()),
374
+ iframeOrigins: z12.array(z12.string()),
375
+ pixelOrigins: z12.array(z12.string()),
376
376
  firstPartyCookies: Names,
377
377
  localStorage: Names
378
378
  }).optional()
379
379
  });
380
- Envelope = z15.object({
381
- publicKey: z15.string(),
382
- revision: z15.number(),
383
- ruleKey: z15.string(),
384
- profileKey: z15.string(),
385
- trustedSignals: z15.object({
386
- region: z15.object({
387
- countryCode: z15.string().nullable(),
388
- subdivisionCode: z15.string().nullable()
380
+ Envelope = z12.object({
381
+ publicKey: z12.string(),
382
+ revision: z12.number(),
383
+ ruleKey: z12.string(),
384
+ profileKey: z12.string(),
385
+ trustedSignals: z12.object({
386
+ region: z12.object({
387
+ countryCode: z12.string().nullable(),
388
+ subdivisionCode: z12.string().nullable()
389
389
  }).optional()
390
390
  }).optional(),
391
- config: z15.object({
392
- services: z15.array(Service),
393
- categories: z15.array(z15.object({ key: z15.string(), required: z15.boolean() })),
394
- integrations: z15.object({ googleConsentMode: z15.string() })
391
+ config: z12.object({
392
+ services: z12.array(Service),
393
+ categories: z12.array(z12.object({ key: z12.string(), required: z12.boolean() })),
394
+ integrations: z12.object({ googleConsentMode: z12.string() })
395
395
  })
396
396
  });
397
- State = z15.object({
398
- runtimeVersion: z15.string(),
399
- preview: z15.boolean(),
400
- resolved: z15.object({
401
- publicKey: z15.string(),
402
- revision: z15.number(),
403
- ruleKey: z15.string(),
404
- profileKey: z15.string()
397
+ State = z12.object({
398
+ runtimeVersion: z12.string(),
399
+ preview: z12.boolean(),
400
+ resolved: z12.object({
401
+ publicKey: z12.string(),
402
+ revision: z12.number(),
403
+ ruleKey: z12.string(),
404
+ profileKey: z12.string()
405
405
  }).nullable(),
406
- consent: z15.object({
407
- categories: z15.array(z15.string()),
408
- decision: z15.string(),
409
- globalPrivacyControl: z15.boolean(),
410
- privacyChoices: z15.object({
411
- saleOrShareOptOut: z15.boolean(),
412
- targetedAdvertisingOptOut: z15.boolean()
406
+ consent: z12.object({
407
+ categories: z12.array(z12.string()),
408
+ decision: z12.string(),
409
+ globalPrivacyControl: z12.boolean(),
410
+ privacyChoices: z12.object({
411
+ saleOrShareOptOut: z12.boolean(),
412
+ targetedAdvertisingOptOut: z12.boolean()
413
413
  })
414
414
  }),
415
- services: z15.array(
416
- z15.object({
417
- key: z15.string(),
418
- allowed: z15.boolean(),
419
- footprintPresent: z15.boolean()
415
+ services: z12.array(
416
+ z12.object({
417
+ key: z12.string(),
418
+ allowed: z12.boolean(),
419
+ footprintPresent: z12.boolean()
420
420
  })
421
421
  )
422
422
  });
423
- VerificationInstallation = z15.object({
424
- publicKey: z15.string(),
425
- currentPublishedRevision: z15.number().int().positive(),
426
- delivery: z15.object({
427
- runtimeUrl: z15.string().url(),
428
- configUrl: z15.string().url(),
429
- analyticsUrl: z15.string().url().nullable(),
430
- receiptsUrl: z15.string().url(),
431
- handshakeUrl: z15.string().url()
423
+ VerificationInstallation = z12.object({
424
+ publicKey: z12.string(),
425
+ currentPublishedRevision: z12.number().int().positive(),
426
+ delivery: z12.object({
427
+ runtimeUrl: z12.string().url(),
428
+ configUrl: z12.string().url(),
429
+ analyticsUrl: z12.string().url().nullable(),
430
+ receiptsUrl: z12.string().url(),
431
+ handshakeUrl: z12.string().url()
432
432
  })
433
433
  });
434
434
  }
435
435
  });
436
436
 
437
437
  // src/health-check.ts
438
- import path10 from "path";
438
+ import path8 from "path";
439
439
 
440
440
  // src/projects/project-context.ts
441
441
  import path6 from "path";
@@ -1033,13 +1033,6 @@ import { realpath } from "fs/promises";
1033
1033
  import path4 from "path";
1034
1034
  import { z as z3 } from "zod";
1035
1035
 
1036
- // src/core/ports/project-binding-store.ts
1037
- var PRODUCT_SERVICES = ["pulse", "forms", "search"];
1038
- var PROJECT_BINDING_SERVICES = [
1039
- "project",
1040
- ...PRODUCT_SERVICES
1041
- ];
1042
-
1043
1036
  // src/core/adapters/node-json-document-store.ts
1044
1037
  import { createHash, randomUUID as randomUUID2 } from "crypto";
1045
1038
  import {
@@ -1206,7 +1199,7 @@ function isNodeErrorCode2(error, code) {
1206
1199
 
1207
1200
  // src/core/adapters/node-project-binding-store.ts
1208
1201
  var projectBindingSchema = z3.object({
1209
- service: z3.enum(PROJECT_BINDING_SERVICES),
1202
+ service: z3.literal("project"),
1210
1203
  apiOrigin: z3.string().url().refine((value) => new URL(value).origin === value),
1211
1204
  repositoryRoot: z3.string().refine(path4.isAbsolute),
1212
1205
  organizationId: z3.string().trim().min(1).max(255),
@@ -1331,13 +1324,13 @@ function normalizeApiOrigin(value) {
1331
1324
  } catch {
1332
1325
  throw new ProjectBindingStoreError(
1333
1326
  "PROJECT_BINDINGS_INVALID",
1334
- "The product Project binding is invalid."
1327
+ "The Project binding is invalid."
1335
1328
  );
1336
1329
  }
1337
1330
  if (url.protocol !== "http:" && url.protocol !== "https:") {
1338
1331
  throw new ProjectBindingStoreError(
1339
1332
  "PROJECT_BINDINGS_INVALID",
1340
- "The product Project binding is invalid."
1333
+ "The Project binding is invalid."
1341
1334
  );
1342
1335
  }
1343
1336
  return url.origin;
@@ -1350,26 +1343,26 @@ function mapStoreError(error) {
1350
1343
  if (error instanceof z3.ZodError) {
1351
1344
  return new ProjectBindingStoreError(
1352
1345
  "PROJECT_BINDINGS_INVALID",
1353
- "Product Project bindings are invalid."
1346
+ "Project bindings are invalid."
1354
1347
  );
1355
1348
  }
1356
1349
  if (error instanceof JsonDocumentStoreError) {
1357
1350
  if (error.code === "JSON_DOCUMENT_CONFLICT") {
1358
1351
  return new ProjectBindingStoreError(
1359
1352
  "PROJECT_BINDINGS_CONFLICT",
1360
- "Product Project bindings changed before they could be saved."
1353
+ "Project bindings changed before they could be saved."
1361
1354
  );
1362
1355
  }
1363
1356
  if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
1364
1357
  return new ProjectBindingStoreError(
1365
1358
  "PROJECT_BINDINGS_INVALID",
1366
- "Product Project bindings are invalid."
1359
+ "Project bindings are invalid."
1367
1360
  );
1368
1361
  }
1369
1362
  }
1370
1363
  return new ProjectBindingStoreError(
1371
1364
  "PROJECT_BINDINGS_UNAVAILABLE",
1372
- "Product Project bindings could not be accessed."
1365
+ "Project bindings could not be accessed."
1373
1366
  );
1374
1367
  }
1375
1368
 
@@ -1439,6 +1432,12 @@ function isNodeErrorCode3(error, code) {
1439
1432
  return error instanceof Error && "code" in error && error.code === code;
1440
1433
  }
1441
1434
 
1435
+ // src/environment-slug.ts
1436
+ var environmentSlugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1437
+ function isValidEnvironmentSlug(value) {
1438
+ return value.length >= 2 && value.length <= 30 && environmentSlugPattern.test(value);
1439
+ }
1440
+
1442
1441
  // src/projects/project-api.ts
1443
1442
  import { z as z4 } from "zod";
1444
1443
  var PROJECT_SERVICES = [
@@ -1502,7 +1501,7 @@ var OverviewSchema = z4.object({
1502
1501
  });
1503
1502
  function createProjectApi(input) {
1504
1503
  const origin = resolveSiteOSAuthBaseUrl(input.env);
1505
- async function request(path33, schema, body, method) {
1504
+ async function request(path29, schema, body, method) {
1506
1505
  const scope = body === void 0 ? "projects:workspace:read" : "projects:workspace:write";
1507
1506
  const grant = await input.grants.acquire({
1508
1507
  audience: "siteos-projects",
@@ -1516,7 +1515,7 @@ function createProjectApi(input) {
1516
1515
  message: "SiteOS API access is unavailable."
1517
1516
  });
1518
1517
  const response = await input.fetchImpl(
1519
- `${origin}/api/projects/v1/projects${path33}`,
1518
+ `${origin}/api/projects/v1/projects${path29}`,
1520
1519
  {
1521
1520
  method: method ?? (body === void 0 ? "GET" : "POST"),
1522
1521
  headers: {
@@ -1660,7 +1659,7 @@ function invalidResponse() {
1660
1659
  // src/projects/project-context.ts
1661
1660
  function commonProjectRuntime(options) {
1662
1661
  const store = options.projectBindingStore ?? new NodeProjectBindingStore(
1663
- path6.join(resolveSiteOSConfigHome(options), "project-bindings.json")
1662
+ path6.join(resolveSiteOSConfigHome(options), "projects.json")
1664
1663
  );
1665
1664
  const grants = options.serviceGrantProvider ?? createSiteOSServiceGrantProvider(options);
1666
1665
  return { store, grants, api: createProjectApi({ ...options, grants }) };
@@ -1681,7 +1680,12 @@ async function readCommonProject(options, environmentSlug) {
1681
1680
  const local = await readLocalCommonProject(options);
1682
1681
  if (!local) return null;
1683
1682
  const { api, binding } = local;
1684
- const selectedSlug = environmentSlug ?? binding.environmentSlug ?? "production";
1683
+ const selectedSlug = environmentSlug ?? binding.environmentSlug;
1684
+ if (!selectedSlug)
1685
+ throw new SiteOSAuthApiError({
1686
+ code: "PROJECT_ENVIRONMENT_REQUIRED",
1687
+ message: "Select an environment with `siteos project environment use <slug>`."
1688
+ });
1685
1689
  const overview = await api.get(binding.project.id, selectedSlug);
1686
1690
  if (overview.project.organizationId !== binding.organizationId)
1687
1691
  throw new SiteOSAuthApiError({
@@ -1732,11 +1736,6 @@ async function commonEnvironmentArguments(options, service, args2) {
1732
1736
  throw cause;
1733
1737
  });
1734
1738
  if (!local) return args2;
1735
- if (args2[0] === "environment" && args2[1] !== "list")
1736
- throw new Error(
1737
- "Manage shared environments with `siteos project environment` or Project settings."
1738
- );
1739
- if (["project", "environment", "submit"].includes(args2[0] ?? "")) return args2;
1740
1739
  const normalized = args2.flatMap(
1741
1740
  (arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice("--environment=".length)] : [arg]
1742
1741
  );
@@ -1745,6 +1744,8 @@ async function commonEnvironmentArguments(options, service, args2) {
1745
1744
  const index = normalized.indexOf("--environment");
1746
1745
  const slug2 = index >= 0 ? normalized[index + 1] : void 0;
1747
1746
  if (index >= 0 && (!slug2 || slug2.startsWith("--"))) return args2;
1747
+ if (slug2 && !isValidEnvironmentSlug(slug2))
1748
+ throw new Error("--environment must be a valid environment slug.");
1748
1749
  const context = await commonServiceContext(options, service, slug2);
1749
1750
  const binding = context?.environmentBinding;
1750
1751
  if (!context || !binding?.slug)
@@ -1757,113 +1758,11 @@ async function commonEnvironmentArguments(options, service, args2) {
1757
1758
  return result;
1758
1759
  }
1759
1760
 
1760
- // src/forms/project-reference.ts
1761
- import path7 from "path";
1762
- import { z as z5 } from "zod";
1763
- var FORMS_PROJECT_REFERENCE_RELATIVE_PATH = path7.join(
1764
- ".siteos",
1765
- "forms",
1766
- "project.json"
1767
- );
1768
- var formsProjectReferenceSchema = z5.object({
1769
- version: z5.literal(1),
1770
- service: z5.literal("forms"),
1771
- project: z5.object({
1772
- name: z5.string().trim().min(1).max(255),
1773
- slug: z5.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
1774
- }).strict()
1775
- }).strict();
1776
- var codec = {
1777
- decode(input) {
1778
- return { migrated: false, value: formsProjectReferenceSchema.parse(input) };
1779
- },
1780
- encode(value) {
1781
- return formsProjectReferenceSchema.parse(value);
1782
- }
1783
- };
1784
- var FormsProjectReferenceError = class extends Error {
1785
- code;
1786
- constructor(code, message) {
1787
- super(message);
1788
- this.name = "FormsProjectReferenceError";
1789
- this.code = code;
1790
- }
1791
- };
1792
- async function inspectFormsProjectReference(startDir, documents = new NodeJsonDocumentStore()) {
1793
- try {
1794
- const rootDir = await findRepositoryRoot(startDir);
1795
- const snapshot = await documents.read({
1796
- codec,
1797
- filePath: path7.join(rootDir, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
1798
- security: "tracked"
1799
- });
1800
- if (snapshot.status === "missing") return { rootDir, status: "missing" };
1801
- return {
1802
- checksum: snapshot.checksum,
1803
- reference: snapshot.value,
1804
- rootDir,
1805
- status: "loaded"
1806
- };
1807
- } catch (error) {
1808
- throw mapReferenceError(error);
1809
- }
1810
- }
1811
- async function writeFormsProjectReference(options) {
1812
- const reference = formsProjectReferenceSchema.parse({
1813
- version: 1,
1814
- service: "forms",
1815
- project: options.project
1816
- });
1817
- try {
1818
- await (options.documents ?? new NodeJsonDocumentStore()).write({
1819
- codec,
1820
- expectedChecksum: options.expectedChecksum,
1821
- filePath: path7.join(
1822
- await findRepositoryRoot(options.rootDir),
1823
- FORMS_PROJECT_REFERENCE_RELATIVE_PATH
1824
- ),
1825
- security: "tracked",
1826
- value: reference
1827
- });
1828
- return reference;
1829
- } catch (error) {
1830
- throw mapReferenceError(error);
1831
- }
1832
- }
1833
- function mapReferenceError(error) {
1834
- if (error instanceof FormsProjectReferenceError) return error;
1835
- if (error instanceof RepositoryRootError) throw error;
1836
- if (error instanceof JsonDocumentStoreError) {
1837
- if (error.code === "JSON_DOCUMENT_CONFLICT") {
1838
- return new FormsProjectReferenceError(
1839
- "FORMS_PROJECT_REFERENCE_CONFLICT",
1840
- "The Forms Project reference changed before it could be saved."
1841
- );
1842
- }
1843
- if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
1844
- return new FormsProjectReferenceError(
1845
- "FORMS_PROJECT_REFERENCE_INVALID",
1846
- "The Forms Project reference is invalid."
1847
- );
1848
- }
1849
- }
1850
- if (error instanceof z5.ZodError) {
1851
- return new FormsProjectReferenceError(
1852
- "FORMS_PROJECT_REFERENCE_INVALID",
1853
- "The Forms Project reference is invalid."
1854
- );
1855
- }
1856
- return new FormsProjectReferenceError(
1857
- "FORMS_PROJECT_REFERENCE_UNAVAILABLE",
1858
- "The Forms Project reference could not be accessed."
1859
- );
1860
- }
1861
-
1862
1761
  // src/pulse/config.ts
1863
1762
  import { createHash as createHash3, randomBytes } from "crypto";
1864
1763
  import { readFile as readFile3, rename as rename3, unlink, writeFile as writeFile3 } from "fs/promises";
1865
- import path8 from "path";
1866
- import { z as z6 } from "zod";
1764
+ import path7 from "path";
1765
+ import { z as z5 } from "zod";
1867
1766
 
1868
1767
  // src/pulse/errors.ts
1869
1768
  var CliError = class extends Error {
@@ -1882,44 +1781,43 @@ var CliError = class extends Error {
1882
1781
  // src/pulse/config.ts
1883
1782
  var CONFIG_FILE = "siteos.config.json";
1884
1783
  function isSafeRelativePath(value) {
1885
- if (!value || path8.isAbsolute(value) || value.startsWith("!")) return false;
1784
+ if (!value || path7.isAbsolute(value) || value.startsWith("!")) return false;
1886
1785
  return !value.split(/[\\/]/).includes("..");
1887
1786
  }
1888
- var safeRelativePath = z6.string().trim().min(1).refine(
1787
+ var safeRelativePath = z5.string().trim().min(1).refine(
1889
1788
  isSafeRelativePath,
1890
1789
  "Use a relative path without '..' or negated glob patterns."
1891
1790
  );
1892
- var slug = z6.string().trim().min(1).max(80).regex(
1791
+ var slug = z5.string().trim().min(1).max(80).regex(
1893
1792
  /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
1894
1793
  "Use lowercase letters, numbers, and hyphens."
1895
1794
  );
1896
- var displayName = z6.string().trim().min(1).max(120);
1897
- var httpUrl = z6.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
1795
+ var displayName = z5.string().trim().min(1).max(120);
1796
+ var httpUrl = z5.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
1898
1797
  message: "Use an HTTP or HTTPS URL."
1899
1798
  });
1900
- var legacySchedule = z6.object({
1901
- enabled: z6.boolean().default(true),
1902
- cadenceSeconds: z6.number().int().min(60).max(2592e3).default(300)
1799
+ var legacySchedule = z5.object({
1800
+ enabled: z5.boolean().default(true),
1801
+ cadenceSeconds: z5.number().int().min(60).max(2592e3).default(300)
1903
1802
  }).default({ enabled: true, cadenceSeconds: 300 });
1904
- var ChecksConfigV1Schema = z6.object({
1905
- version: z6.literal(1),
1803
+ var ChecksConfigV1Schema = z5.object({
1804
+ version: z5.literal(1),
1906
1805
  project: slug,
1907
1806
  suite: slug.default("smoke"),
1908
1807
  testsDir: safeRelativePath.default("tests/checks"),
1909
1808
  playwrightConfig: safeRelativePath.optional(),
1910
- include: z6.array(safeRelativePath).min(1).max(100),
1809
+ include: z5.array(safeRelativePath).min(1).max(100),
1911
1810
  baseUrl: httpUrl.optional(),
1912
- schedule: legacySchedule,
1913
- apiUrl: httpUrl.optional()
1811
+ schedule: legacySchedule
1914
1812
  });
1915
- var ScheduledConfigSchema = z6.object({
1916
- mode: z6.literal("scheduled"),
1917
- cadenceSeconds: z6.number().int().min(60).max(2592e3).default(300)
1813
+ var ScheduledConfigSchema = z5.object({
1814
+ mode: z5.literal("scheduled"),
1815
+ cadenceSeconds: z5.number().int().min(60).max(2592e3).default(300)
1918
1816
  });
1919
- var ManualConfigSchema = z6.object({ mode: z6.literal("manual") });
1920
- var CheckConfigSchema = z6.object({
1921
- environmentVariables: z6.array(
1922
- z6.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/).refine(
1817
+ var ManualConfigSchema = z5.object({ mode: z5.literal("manual") });
1818
+ var CheckConfigSchema = z5.object({
1819
+ environmentVariables: z5.array(
1820
+ z5.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/).refine(
1923
1821
  (name) => !/^(?:SITEOS_|PLAYWRIGHT_|DOCKER_|NODE_|NPM_|PNPM_|LD_|DYLD_)/.test(
1924
1822
  name
1925
1823
  ) && ![
@@ -1940,29 +1838,28 @@ var CheckConfigSchema = z6.object({
1940
1838
  ).optional(),
1941
1839
  slug,
1942
1840
  name: displayName,
1943
- include: z6.array(safeRelativePath).min(1).max(100),
1944
- active: z6.boolean().default(true),
1945
- schedule: z6.discriminatedUnion("mode", [ScheduledConfigSchema, ManualConfigSchema]).default({ mode: "scheduled", cadenceSeconds: 300 })
1841
+ include: z5.array(safeRelativePath).min(1).max(100),
1842
+ active: z5.boolean().default(true),
1843
+ schedule: z5.discriminatedUnion("mode", [ScheduledConfigSchema, ManualConfigSchema]).default({ mode: "scheduled", cadenceSeconds: 300 })
1946
1844
  });
1947
- var ChecksConfigV2Schema = z6.object({
1948
- version: z6.literal(2),
1949
- project: z6.object({
1845
+ var ChecksConfigV2Schema = z5.object({
1846
+ version: z5.literal(2),
1847
+ project: z5.object({
1950
1848
  slug,
1951
1849
  name: displayName,
1952
1850
  baseUrl: httpUrl.optional(),
1953
- monitoringEnabled: z6.boolean().default(true)
1851
+ monitoringEnabled: z5.boolean().default(true)
1954
1852
  }),
1955
1853
  testsDir: safeRelativePath.default("tests/siteos"),
1956
1854
  playwrightConfig: safeRelativePath.optional(),
1957
- bundle: z6.object({ include: z6.array(safeRelativePath).max(500).default([]) }).strict().optional(),
1958
- checks: z6.array(CheckConfigSchema).min(1).max(100),
1959
- apiUrl: httpUrl.optional()
1855
+ bundle: z5.object({ include: z5.array(safeRelativePath).max(500).default([]) }).strict().optional(),
1856
+ checks: z5.array(CheckConfigSchema).min(1).max(100)
1960
1857
  }).superRefine((config, context) => {
1961
1858
  const slugs = /* @__PURE__ */ new Set();
1962
1859
  for (const [index, check] of config.checks.entries()) {
1963
1860
  if (slugs.has(check.slug)) {
1964
1861
  context.addIssue({
1965
- code: z6.ZodIssueCode.custom,
1862
+ code: z5.ZodIssueCode.custom,
1966
1863
  path: ["checks", index, "slug"],
1967
1864
  message: `Duplicate Check slug: ${check.slug}`
1968
1865
  });
@@ -1970,7 +1867,7 @@ var ChecksConfigV2Schema = z6.object({
1970
1867
  slugs.add(check.slug);
1971
1868
  }
1972
1869
  });
1973
- var ChecksConfigSchema = z6.union([
1870
+ var ChecksConfigSchema = z5.union([
1974
1871
  ChecksConfigV1Schema,
1975
1872
  ChecksConfigV2Schema
1976
1873
  ]);
@@ -2003,8 +1900,7 @@ function normalizeChecksConfig(config) {
2003
1900
  cadenceSeconds: config.schedule.cadenceSeconds
2004
1901
  } : { mode: "manual" }
2005
1902
  }
2006
- ],
2007
- apiUrl: config.apiUrl
1903
+ ]
2008
1904
  });
2009
1905
  }
2010
1906
  async function fileExists(filePath) {
@@ -2017,7 +1913,7 @@ async function fileExists(filePath) {
2017
1913
  }
2018
1914
  }
2019
1915
  async function findChecksConfigFile(projectRoot) {
2020
- return await fileExists(path8.join(projectRoot, CONFIG_FILE)) ? CONFIG_FILE : null;
1916
+ return await fileExists(path7.join(projectRoot, CONFIG_FILE)) ? CONFIG_FILE : null;
2021
1917
  }
2022
1918
  async function loadChecksConfigFile(projectRoot) {
2023
1919
  return (await loadChecksConfigSnapshot(projectRoot)).fileConfig;
@@ -2033,7 +1929,7 @@ async function loadChecksConfigSnapshot(projectRoot) {
2033
1929
  }
2034
1930
  );
2035
1931
  }
2036
- const configPath = path8.join(projectRoot, configFile);
1932
+ const configPath = path7.join(projectRoot, configFile);
2037
1933
  let source;
2038
1934
  try {
2039
1935
  source = await readFile3(configPath, "utf8");
@@ -2081,8 +1977,8 @@ async function loadChecksConfig(projectRoot) {
2081
1977
  }
2082
1978
  async function saveChecksConfig(projectRoot, config, options = {}) {
2083
1979
  const configFile = await findChecksConfigFile(projectRoot) ?? CONFIG_FILE;
2084
- const configPath = path8.join(projectRoot, configFile);
2085
- const temporaryPath = path8.join(
1980
+ const configPath = path7.join(projectRoot, configFile);
1981
+ const temporaryPath = path7.join(
2086
1982
  projectRoot,
2087
1983
  `.${configFile}.${process.pid}.${randomBytes(6).toString("hex")}`
2088
1984
  );
@@ -2119,19 +2015,6 @@ async function saveChecksConfig(projectRoot, config, options = {}) {
2119
2015
  throw error;
2120
2016
  }
2121
2017
  }
2122
- async function reconcileProjectSlug(projectRoot, projectSlug2, options = {}) {
2123
- const snapshot = await loadChecksConfigSnapshot(projectRoot);
2124
- const config = ChecksConfigV2Schema.parse({
2125
- ...snapshot.config,
2126
- project: { ...snapshot.config.project, slug: projectSlug2 }
2127
- });
2128
- if (config.project.slug !== snapshot.config.project.slug || snapshot.migrationRequired) {
2129
- await saveChecksConfig(projectRoot, config, {
2130
- expectedChecksum: options.expectedChecksum ?? snapshot.checksum
2131
- });
2132
- }
2133
- return loadChecksConfigSnapshot(projectRoot);
2134
- }
2135
2018
  function projectSlug(value) {
2136
2019
  const normalized = value.trim().toLowerCase().replace(/^@[^/]+\//, "").replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 80);
2137
2020
  return normalized || "siteos-pulse-project";
@@ -2143,111 +2026,6 @@ function projectDisplayName(value) {
2143
2026
  return name.slice(0, 120) || "SiteOS Pulse Project";
2144
2027
  }
2145
2028
 
2146
- // src/search/project-reference.ts
2147
- import path9 from "path";
2148
- import { z as z7 } from "zod";
2149
- var SEARCH_PROJECT_REFERENCE_RELATIVE_PATH = path9.join(
2150
- ".siteos",
2151
- "search",
2152
- "project.json"
2153
- );
2154
- var searchProjectReferenceSchema = z7.object({
2155
- version: z7.literal(1),
2156
- service: z7.literal("search"),
2157
- project: z7.object({
2158
- name: z7.string().trim().min(1).max(255),
2159
- slug: z7.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
2160
- }).strict()
2161
- }).strict();
2162
- var codec2 = {
2163
- decode(input) {
2164
- return {
2165
- migrated: false,
2166
- value: searchProjectReferenceSchema.parse(input)
2167
- };
2168
- },
2169
- encode(value) {
2170
- return searchProjectReferenceSchema.parse(value);
2171
- }
2172
- };
2173
- var SearchProjectReferenceError = class extends Error {
2174
- code;
2175
- constructor(code, message) {
2176
- super(message);
2177
- this.name = "SearchProjectReferenceError";
2178
- this.code = code;
2179
- }
2180
- };
2181
- async function inspectSearchProjectReference(startDir, documents = new NodeJsonDocumentStore()) {
2182
- try {
2183
- const rootDir = await findRepositoryRoot(startDir);
2184
- const snapshot = await documents.read({
2185
- codec: codec2,
2186
- filePath: path9.join(rootDir, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
2187
- security: "tracked"
2188
- });
2189
- if (snapshot.status === "missing") return { rootDir, status: "missing" };
2190
- return {
2191
- checksum: snapshot.checksum,
2192
- reference: snapshot.value,
2193
- rootDir,
2194
- status: "loaded"
2195
- };
2196
- } catch (error) {
2197
- throw mapReferenceError2(error);
2198
- }
2199
- }
2200
- async function writeSearchProjectReference(options) {
2201
- const reference = searchProjectReferenceSchema.parse({
2202
- version: 1,
2203
- service: "search",
2204
- project: options.project
2205
- });
2206
- try {
2207
- await (options.documents ?? new NodeJsonDocumentStore()).write({
2208
- codec: codec2,
2209
- expectedChecksum: options.expectedChecksum,
2210
- filePath: path9.join(
2211
- await findRepositoryRoot(options.rootDir),
2212
- SEARCH_PROJECT_REFERENCE_RELATIVE_PATH
2213
- ),
2214
- security: "tracked",
2215
- value: reference
2216
- });
2217
- return reference;
2218
- } catch (error) {
2219
- throw mapReferenceError2(error);
2220
- }
2221
- }
2222
- function mapReferenceError2(error) {
2223
- if (error instanceof SearchProjectReferenceError) return error;
2224
- if (error instanceof RepositoryRootError) throw error;
2225
- if (error instanceof JsonDocumentStoreError) {
2226
- if (error.code === "JSON_DOCUMENT_CONFLICT") {
2227
- return new SearchProjectReferenceError(
2228
- "SEARCH_PROJECT_REFERENCE_CONFLICT",
2229
- "The Search Project reference changed before it could be saved."
2230
- );
2231
- }
2232
- if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
2233
- return new SearchProjectReferenceError(
2234
- "SEARCH_PROJECT_REFERENCE_INVALID",
2235
- "The Search Project reference is invalid."
2236
- );
2237
- }
2238
- }
2239
- if (error instanceof z7.ZodError) {
2240
- return new SearchProjectReferenceError(
2241
- "SEARCH_PROJECT_REFERENCE_INVALID",
2242
- "The Search Project reference is invalid."
2243
- );
2244
- }
2245
- return new SearchProjectReferenceError(
2246
- "SEARCH_PROJECT_REFERENCE_UNAVAILABLE",
2247
- "The Search Project reference could not be accessed."
2248
- );
2249
- }
2250
-
2251
2029
  // src/health-check.ts
2252
2030
  async function createHealthCheckResult(options = {}) {
2253
2031
  const packageMetadata = options.packageMetadata ?? {
@@ -2260,7 +2038,7 @@ async function createHealthCheckResult(options = {}) {
2260
2038
  homeDir: options.homeDir
2261
2039
  });
2262
2040
  const repositoryRoot = await optionalRepositoryRoot(cwd);
2263
- const productProjects = repositoryRoot ? await inspectProductProjects(repositoryRoot) : missingProductProjects(cwd);
2041
+ const pulse = repositoryRoot ? await inspectPulse(repositoryRoot) : { path: path8.join(cwd, CONFIG_FILE), status: "missing" };
2264
2042
  let project = { status: "missing" };
2265
2043
  if (repositoryRoot) {
2266
2044
  try {
@@ -2278,13 +2056,11 @@ async function createHealthCheckResult(options = {}) {
2278
2056
  project = { status: "invalid" };
2279
2057
  }
2280
2058
  }
2281
- const configured = project.status === "selected" || Object.values(productProjects).some(
2282
- (project2) => project2.status === "configured"
2283
- );
2059
+ const configured = project.status === "selected";
2284
2060
  return {
2285
2061
  checks: {
2286
2062
  configHome: { path: configHome, status: "ok" },
2287
- productProjects,
2063
+ pulse,
2288
2064
  project,
2289
2065
  repository: repositoryRoot ? { rootDir: repositoryRoot, status: "ok" } : { status: "missing" }
2290
2066
  },
@@ -2307,41 +2083,8 @@ async function optionalRepositoryRoot(cwd) {
2307
2083
  throw error;
2308
2084
  }
2309
2085
  }
2310
- async function inspectProductProjects(repositoryRoot) {
2311
- const [forms, pulse, search] = await Promise.all([
2312
- inspectReference(
2313
- "forms",
2314
- path10.join(repositoryRoot, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
2315
- () => inspectFormsProjectReference(repositoryRoot)
2316
- ),
2317
- inspectPulse(repositoryRoot),
2318
- inspectReference(
2319
- "search",
2320
- path10.join(repositoryRoot, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
2321
- () => inspectSearchProjectReference(repositoryRoot)
2322
- )
2323
- ]);
2324
- return { forms, pulse, search };
2325
- }
2326
- async function inspectReference(service, referencePath, inspect) {
2327
- try {
2328
- const state = await inspect();
2329
- return state.status === "loaded" ? {
2330
- path: referencePath,
2331
- slug: state.reference.project.slug,
2332
- status: "configured",
2333
- version: state.reference.version
2334
- } : { path: referencePath, status: "missing" };
2335
- } catch (error) {
2336
- return {
2337
- error: error instanceof Error && "code" in error ? String(error.code) : `${service.toUpperCase()}_PROJECT_REFERENCE_INVALID`,
2338
- path: referencePath,
2339
- status: "invalid"
2340
- };
2341
- }
2342
- }
2343
2086
  async function inspectPulse(repositoryRoot) {
2344
- const configPath = path10.join(repositoryRoot, CONFIG_FILE);
2087
+ const configPath = path8.join(repositoryRoot, CONFIG_FILE);
2345
2088
  try {
2346
2089
  const snapshot = await loadChecksConfigSnapshot(repositoryRoot);
2347
2090
  return {
@@ -2361,27 +2104,13 @@ async function inspectPulse(repositoryRoot) {
2361
2104
  };
2362
2105
  }
2363
2106
  }
2364
- function missingProductProjects(cwd) {
2365
- const root = path10.resolve(cwd);
2366
- return {
2367
- forms: {
2368
- path: path10.join(root, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
2369
- status: "missing"
2370
- },
2371
- pulse: { path: path10.join(root, CONFIG_FILE), status: "missing" },
2372
- search: {
2373
- path: path10.join(root, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
2374
- status: "missing"
2375
- }
2376
- };
2377
- }
2378
2107
 
2379
2108
  // src/auth-command.ts
2380
2109
  import { createHash as createHash4, randomBytes as randomBytes2 } from "crypto";
2381
2110
  import os3 from "os";
2382
- import { z as z8 } from "zod";
2111
+ import { z as z6 } from "zod";
2383
2112
  var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
2384
- var organizationDisplayNameSchema = z8.string().transform((value) => value.trim()).refine((value) => {
2113
+ var organizationDisplayNameSchema = z6.string().transform((value) => value.trim()).refine((value) => {
2385
2114
  const visibleLength = Array.from(value).length;
2386
2115
  return visibleLength >= 2 && visibleLength <= 80;
2387
2116
  });
@@ -2412,7 +2141,7 @@ async function runAuthCommand(options) {
2412
2141
  if (subcommand === "start") {
2413
2142
  const parsed = parseValueCommand(args2, "--email");
2414
2143
  if (!parsed.ok) return usageError(parsed.error, parsed.json);
2415
- const email = z8.string().trim().email().safeParse(parsed.value);
2144
+ const email = z6.string().trim().email().safeParse(parsed.value);
2416
2145
  if (!email.success) return usageError("--email is invalid.", parsed.json);
2417
2146
  return runStart({
2418
2147
  ...options,
@@ -2425,7 +2154,7 @@ async function runAuthCommand(options) {
2425
2154
  if (subcommand === "complete") {
2426
2155
  const parsed = parseValueCommand(args2, "--token");
2427
2156
  if (!parsed.ok) return usageError(parsed.error, parsed.json);
2428
- const token = z8.string().trim().regex(/^[A-Za-z0-9_-]{16}$/).safeParse(parsed.value);
2157
+ const token = z6.string().trim().regex(/^[A-Za-z0-9_-]{16}$/).safeParse(parsed.value);
2429
2158
  if (!token.success) return usageError("--token is invalid.", parsed.json);
2430
2159
  return runComplete({
2431
2160
  ...options,
@@ -2960,137 +2689,124 @@ function isCliExitCode(value) {
2960
2689
 
2961
2690
  // src/forms-command.ts
2962
2691
  import { readFile as readFile5 } from "fs/promises";
2963
- import path12 from "path";
2964
- import { z as z10 } from "zod";
2692
+ import path10 from "path";
2965
2693
  import { Ajv } from "ajv";
2966
2694
  import addFormats from "ajv-formats";
2695
+ import { z as z8 } from "zod";
2967
2696
 
2968
2697
  // src/siteos-forms-api.ts
2969
- import { z as z9 } from "zod";
2970
- var DEFAULT_SITEOS_FORMS_BASE_URL = "https://app.siteos.sh";
2971
- var SITEOS_FORMS_BASE_URL_ENV = "SITEOS_FORMS_PUBLIC_URL";
2972
- var opaqueIdentifierSchema = z9.string().trim().min(1).max(255);
2973
- var formsProjectSchema = z9.object({
2974
- createdAt: z9.string().datetime({ offset: true }),
2975
- id: opaqueIdentifierSchema,
2976
- name: z9.string().trim().min(1).max(255),
2977
- organizationId: opaqueIdentifierSchema,
2978
- slug: z9.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
2979
- updatedAt: z9.string().datetime({ offset: true })
2980
- }).strict();
2981
- var formsProjectListSchema = z9.object({ projects: z9.array(formsProjectSchema) }).strict();
2982
- var formsProjectResponseSchema = z9.object({ project: formsProjectSchema }).strict();
2983
- var formsEnvironmentSchema = z9.object({
2984
- createdAt: z9.string().datetime({ offset: true }),
2698
+ import { z as z7 } from "zod";
2699
+ var opaqueIdentifierSchema = z7.string().trim().min(1).max(255);
2700
+ var formsEnvironmentSchema = z7.object({
2701
+ createdAt: z7.string().datetime({ offset: true }),
2985
2702
  id: opaqueIdentifierSchema,
2986
- name: z9.string().trim().min(1).max(255),
2703
+ name: z7.string().trim().min(1).max(255),
2987
2704
  projectId: opaqueIdentifierSchema,
2988
- slug: z9.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
2989
- updatedAt: z9.string().datetime({ offset: true })
2705
+ slug: z7.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
2706
+ updatedAt: z7.string().datetime({ offset: true })
2990
2707
  }).strict();
2991
- var formsEnvironmentListSchema = z9.object({ environments: z9.array(formsEnvironmentSchema) }).strict();
2992
- var formsEnvironmentResponseSchema = z9.object({ environment: formsEnvironmentSchema }).strict();
2993
- var formDefinitionSyncResponseSchema = z9.object({
2708
+ var formsEnvironmentListSchema = z7.object({ environments: z7.array(formsEnvironmentSchema) }).strict();
2709
+ var formDefinitionSyncResponseSchema = z7.object({
2994
2710
  activeVersionId: opaqueIdentifierSchema,
2995
- createdForm: z9.boolean(),
2996
- createdVersion: z9.boolean(),
2711
+ createdForm: z7.boolean(),
2712
+ createdVersion: z7.boolean(),
2997
2713
  formId: opaqueIdentifierSchema,
2998
2714
  formKey: opaqueIdentifierSchema,
2999
- success: z9.literal(true),
3000
- version: z9.number().int().positive()
2715
+ success: z7.literal(true),
2716
+ version: z7.number().int().positive()
3001
2717
  }).strict();
3002
- var definitionSchema = z9.object({
2718
+ var definitionSchema = z7.object({
3003
2719
  id: opaqueIdentifierSchema,
3004
2720
  environmentId: opaqueIdentifierSchema,
3005
2721
  formKey: opaqueIdentifierSchema,
3006
- name: z9.string(),
3007
- sourcePagePath: z9.string().nullable(),
3008
- activeVersion: z9.number().int().positive(),
2722
+ name: z7.string(),
2723
+ sourcePagePath: z7.string().nullable(),
2724
+ activeVersion: z7.number().int().positive(),
3009
2725
  activeVersionId: opaqueIdentifierSchema,
3010
- status: z9.enum(["active", "inactive"]),
3011
- submissionCount: z9.number().int().nonnegative(),
3012
- lastSubmittedAt: z9.string().datetime({ offset: true }).nullable(),
3013
- createdAt: z9.string().datetime({ offset: true }),
3014
- updatedAt: z9.string().datetime({ offset: true })
2726
+ status: z7.enum(["active", "inactive"]),
2727
+ submissionCount: z7.number().int().nonnegative(),
2728
+ lastSubmittedAt: z7.string().datetime({ offset: true }).nullable(),
2729
+ createdAt: z7.string().datetime({ offset: true }),
2730
+ updatedAt: z7.string().datetime({ offset: true })
3015
2731
  });
3016
- var definitionListSchema = z9.object({
3017
- definitions: z9.array(definitionSchema)
2732
+ var definitionListSchema = z7.object({
2733
+ definitions: z7.array(definitionSchema)
3018
2734
  });
3019
- var definitionContextSchema = z9.object({
2735
+ var definitionContextSchema = z7.object({
3020
2736
  definition: definitionSchema,
3021
- revision: z9.number().int().positive(),
3022
- canManage: z9.boolean(),
3023
- project: z9.object({ id: opaqueIdentifierSchema, name: z9.string() }),
3024
- environment: z9.object({
2737
+ revision: z7.number().int().positive(),
2738
+ canManage: z7.boolean(),
2739
+ project: z7.object({ id: opaqueIdentifierSchema, name: z7.string() }),
2740
+ environment: z7.object({
3025
2741
  id: opaqueIdentifierSchema,
3026
- name: z9.string(),
3027
- slug: z9.string()
2742
+ name: z7.string(),
2743
+ slug: z7.string()
3028
2744
  })
3029
2745
  });
3030
- var definitionChangeResponseSchema = z9.object({
3031
- deleted: z9.boolean(),
2746
+ var definitionChangeResponseSchema = z7.object({
2747
+ deleted: z7.boolean(),
3032
2748
  formId: opaqueIdentifierSchema
3033
2749
  });
3034
- var formSubmissionResponseSchema = z9.object({
2750
+ var formSubmissionResponseSchema = z7.object({
3035
2751
  formId: opaqueIdentifierSchema,
3036
- receivedAt: z9.string().datetime({ offset: true }),
2752
+ receivedAt: z7.string().datetime({ offset: true }),
3037
2753
  submissionId: opaqueIdentifierSchema,
3038
- success: z9.literal(true)
2754
+ success: z7.literal(true)
3039
2755
  }).strict();
3040
- var formsSubmissionStatusSchema = z9.enum([
2756
+ var formsSubmissionStatusSchema = z7.enum([
3041
2757
  "new",
3042
2758
  "read",
3043
2759
  "archived",
3044
2760
  "spam"
3045
2761
  ]);
3046
- var submissionSummarySchema = z9.object({
2762
+ var submissionSummarySchema = z7.object({
3047
2763
  id: opaqueIdentifierSchema,
3048
2764
  formId: opaqueIdentifierSchema,
3049
- normalized: z9.record(
3050
- z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
2765
+ normalized: z7.record(
2766
+ z7.union([z7.string(), z7.number(), z7.boolean(), z7.null()])
3051
2767
  ),
3052
2768
  status: formsSubmissionStatusSchema,
3053
- submittedAt: z9.string().datetime({ offset: true })
2769
+ submittedAt: z7.string().datetime({ offset: true })
3054
2770
  });
3055
2771
  var submissionDetailSchema = submissionSummarySchema.extend({
3056
- payload: z9.record(z9.unknown()),
3057
- fields: z9.array(
3058
- z9.object({
3059
- key: z9.string(),
3060
- label: z9.string().optional(),
3061
- kind: z9.string().optional(),
3062
- displayRole: z9.enum(["primary", "secondary"]).optional(),
3063
- multiple: z9.boolean().optional(),
3064
- options: z9.array(z9.object({ value: z9.string(), label: z9.string() })).optional()
2772
+ payload: z7.record(z7.unknown()),
2773
+ fields: z7.array(
2774
+ z7.object({
2775
+ key: z7.string(),
2776
+ label: z7.string().optional(),
2777
+ kind: z7.string().optional(),
2778
+ displayRole: z7.enum(["primary", "secondary"]).optional(),
2779
+ multiple: z7.boolean().optional(),
2780
+ options: z7.array(z7.object({ value: z7.string(), label: z7.string() })).optional()
3065
2781
  })
3066
2782
  ),
3067
- version: z9.number().int().positive(),
2783
+ version: z7.number().int().positive(),
3068
2784
  versionId: opaqueIdentifierSchema
3069
2785
  });
3070
- var submissionPageSchema = z9.object({
3071
- submissions: z9.array(submissionSummarySchema),
3072
- total: z9.number().int().nonnegative(),
3073
- nextCursor: z9.string().nullable()
2786
+ var submissionPageSchema = z7.object({
2787
+ submissions: z7.array(submissionSummarySchema),
2788
+ total: z7.number().int().nonnegative(),
2789
+ nextCursor: z7.string().nullable()
3074
2790
  });
3075
- var submissionDetailResponseSchema = z9.object({
2791
+ var submissionDetailResponseSchema = z7.object({
3076
2792
  submission: submissionDetailSchema
3077
2793
  });
3078
- var formsCredentialMetadataSchema = z9.object({
3079
- createdAt: z9.string().datetime({ offset: true }),
3080
- id: z9.string().trim().min(1).max(255),
3081
- lastUsedAt: z9.string().datetime({ offset: true }).nullable(),
3082
- name: z9.string().trim().min(1).max(255),
3083
- projectEnvironmentId: z9.string().trim().min(1).max(255),
3084
- revokedAt: z9.string().datetime({ offset: true }).nullable(),
3085
- status: z9.enum(["active", "revoked"])
2794
+ var formsCredentialMetadataSchema = z7.object({
2795
+ createdAt: z7.string().datetime({ offset: true }),
2796
+ id: z7.string().trim().min(1).max(255),
2797
+ lastUsedAt: z7.string().datetime({ offset: true }).nullable(),
2798
+ name: z7.string().trim().min(1).max(255),
2799
+ projectEnvironmentId: z7.string().trim().min(1).max(255),
2800
+ revokedAt: z7.string().datetime({ offset: true }).nullable(),
2801
+ status: z7.enum(["active", "revoked"])
3086
2802
  }).strict();
3087
- var formsCredentialListSchema = z9.object({
3088
- tokens: z9.array(formsCredentialMetadataSchema)
2803
+ var formsCredentialListSchema = z7.object({
2804
+ tokens: z7.array(formsCredentialMetadataSchema)
3089
2805
  }).strict();
3090
2806
  var formsCredentialExchangeSchema = formsCredentialMetadataSchema.extend({
3091
- token: z9.string().regex(/^pfs_[A-Za-z0-9_-]{22}$/)
2807
+ token: z7.string().regex(/^pfs_[A-Za-z0-9_-]{22}$/)
3092
2808
  });
3093
- var formsErrorCodeSchema = z9.enum([
2809
+ var formsErrorCodeSchema = z7.enum([
3094
2810
  "AUTHENTICATION_REQUIRED",
3095
2811
  "FORBIDDEN",
3096
2812
  "CONFLICT",
@@ -3138,10 +2854,10 @@ var safeFormsErrorMessages = {
3138
2854
  SERVICE_UNAVAILABLE: "The Forms service is unavailable.",
3139
2855
  INTERNAL_ERROR: "The Forms request could not be completed."
3140
2856
  };
3141
- var apiErrorResponseSchema = z9.object({
3142
- error: z9.object({
2857
+ var apiErrorResponseSchema = z7.object({
2858
+ error: z7.object({
3143
2859
  code: formsErrorCodeSchema,
3144
- message: z9.string().trim().min(1).max(240)
2860
+ message: z7.string().trim().min(1).max(240)
3145
2861
  }).strict()
3146
2862
  }).strict();
3147
2863
  var SiteOSFormsApiError = class extends Error {
@@ -3154,20 +2870,15 @@ var SiteOSFormsApiError = class extends Error {
3154
2870
  this.status = options.status;
3155
2871
  }
3156
2872
  };
3157
- function resolveSiteOSFormsBaseUrl(env = process.env) {
3158
- return normalizeFormsOrigin(
3159
- env[SITEOS_FORMS_BASE_URL_ENV]?.trim() || DEFAULT_SITEOS_FORMS_BASE_URL
3160
- );
3161
- }
3162
- var deploymentResponseSchema = z9.object({
2873
+ var deploymentResponseSchema = z7.object({
3163
2874
  environmentId: opaqueIdentifierSchema,
3164
- forms: z9.array(
3165
- z9.object({
2875
+ forms: z7.array(
2876
+ z7.object({
3166
2877
  formKey: opaqueIdentifierSchema,
3167
2878
  formId: opaqueIdentifierSchema,
3168
- contractVersion: z9.string().regex(/^sha256:[a-f0-9]{64}$/),
2879
+ contractVersion: z7.string().regex(/^sha256:[a-f0-9]{64}$/),
3169
2880
  versionId: opaqueIdentifierSchema,
3170
- version: z9.number().int().positive()
2881
+ version: z7.number().int().positive()
3171
2882
  })
3172
2883
  )
3173
2884
  });
@@ -3236,24 +2947,6 @@ function createSiteOSFormsApiClient(options) {
3236
2947
  body: { status: input.status, expectedStatus: input.expectedStatus },
3237
2948
  responseSchema: submissionDetailResponseSchema
3238
2949
  }),
3239
- createProject: (input) => requestJson2({
3240
- apiBaseUrl,
3241
- body: { name: input.name, slug: input.slug },
3242
- fetchImpl: options.fetchImpl,
3243
- headers: managementHeaders(input),
3244
- method: "POST",
3245
- path: "/api/v1/forms/projects",
3246
- responseSchema: formsProjectResponseSchema
3247
- }),
3248
- createEnvironment: (input) => requestJson2({
3249
- apiBaseUrl,
3250
- body: { name: input.name, slug: input.slug },
3251
- fetchImpl: options.fetchImpl,
3252
- headers: managementHeaders(input),
3253
- method: "POST",
3254
- path: environmentCollectionPath(input),
3255
- responseSchema: formsEnvironmentResponseSchema
3256
- }),
3257
2950
  issueCredential: (input) => requestJson2({
3258
2951
  apiBaseUrl,
3259
2952
  body: input.name ? { name: input.name } : {},
@@ -3262,7 +2955,7 @@ function createSiteOSFormsApiClient(options) {
3262
2955
  method: "POST",
3263
2956
  path: keyCollection(input),
3264
2957
  responseSchema: options.deploymentKeys ? formsCredentialExchangeSchema.extend({
3265
- token: z9.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
2958
+ token: z7.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
3266
2959
  }) : formsCredentialExchangeSchema
3267
2960
  }),
3268
2961
  listEnvironments: (input) => requestJson2({
@@ -3273,14 +2966,6 @@ function createSiteOSFormsApiClient(options) {
3273
2966
  path: environmentCollectionPath(input),
3274
2967
  responseSchema: formsEnvironmentListSchema
3275
2968
  }),
3276
- listProjects: (input) => requestJson2({
3277
- apiBaseUrl,
3278
- fetchImpl: options.fetchImpl,
3279
- headers: managementHeaders(input),
3280
- method: "GET",
3281
- path: "/api/v1/forms/projects",
3282
- responseSchema: formsProjectListSchema
3283
- }),
3284
2969
  listCredentials: (input) => requestJson2({
3285
2970
  apiBaseUrl,
3286
2971
  fetchImpl: options.fetchImpl,
@@ -3305,7 +2990,7 @@ function createSiteOSFormsApiClient(options) {
3305
2990
  method: "POST",
3306
2991
  path: credentialRotatePath(input),
3307
2992
  responseSchema: options.deploymentKeys ? formsCredentialExchangeSchema.extend({
3308
- token: z9.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
2993
+ token: z7.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
3309
2994
  }) : formsCredentialExchangeSchema
3310
2995
  }),
3311
2996
  submitForm: (input) => requestJson2({
@@ -3433,7 +3118,7 @@ import {
3433
3118
  rm as rm3,
3434
3119
  writeFile as writeFile4
3435
3120
  } from "fs/promises";
3436
- import path11 from "path";
3121
+ import path9 from "path";
3437
3122
  var SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV = "SITEOS_FORMS_SUBMISSION_CREDENTIAL";
3438
3123
  var SITEOS_FORMS_DEPLOYMENT_KEY_ENV = "SITEOS_FORMS_DEPLOYMENT_KEY";
3439
3124
  var SiteOSFormsCredentialStorageError = class extends Error {
@@ -3449,8 +3134,8 @@ var SiteOSFormsCredentialStorageError = class extends Error {
3449
3134
  async function prepareSiteOSFormsCredentialInstallation(options) {
3450
3135
  const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
3451
3136
  const credentialPattern = options.deployment ? /^pfd_[A-Za-z0-9_-]{43}$/ : /^pfs_[A-Za-z0-9_-]{22}$/;
3452
- const projectRoot = path11.resolve(options.projectRoot);
3453
- const dotenvPath = path11.join(projectRoot, ".env");
3137
+ const projectRoot = path9.resolve(options.projectRoot);
3138
+ const dotenvPath = path9.join(projectRoot, ".env");
3454
3139
  try {
3455
3140
  await assertSafeProjectRoot(projectRoot);
3456
3141
  if (!await isDotenvIgnored(projectRoot)) {
@@ -3524,7 +3209,7 @@ async function readSafeDotenv(dotenvPath) {
3524
3209
  return content;
3525
3210
  }
3526
3211
  async function writeCredentialAtomically(options) {
3527
- const temporaryPath = path11.join(
3212
+ const temporaryPath = path9.join(
3528
3213
  options.projectRoot,
3529
3214
  `.siteos-forms-credential.${process.pid}.${randomUUID3()}.tmp`
3530
3215
  );
@@ -3577,12 +3262,6 @@ function isNodeErrorCode4(error, code) {
3577
3262
  return error instanceof Error && "code" in error && error.code === code;
3578
3263
  }
3579
3264
 
3580
- // src/environment-slug.ts
3581
- var environmentSlugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3582
- function isValidEnvironmentSlug(value) {
3583
- return value.length >= 2 && value.length <= 30 && environmentSlugPattern.test(value);
3584
- }
3585
-
3586
3265
  // src/forms-command.ts
3587
3266
  var HELP_FLAGS2 = /* @__PURE__ */ new Set(["--help", "-h"]);
3588
3267
  var JSON_FLAG = "--json";
@@ -3591,28 +3270,26 @@ var MANIFEST_FLAG = "--manifest";
3591
3270
  var ENVIRONMENT_FLAG = "--environment";
3592
3271
  var INSTALL_FLAG = "--install";
3593
3272
  var NAME_FLAG = "--name";
3594
- var SLUG_FLAG = "--slug";
3595
3273
  var CREDENTIAL_FLAG = "--credential";
3596
- var REPLACE_FLAG = "--replace";
3597
- var normalizedFieldOptionSchema = z10.object({
3598
- label: z10.string().trim().min(1).max(255),
3599
- value: z10.string().trim().min(1).max(255)
3274
+ var normalizedFieldOptionSchema = z8.object({
3275
+ label: z8.string().trim().min(1).max(255),
3276
+ value: z8.string().trim().min(1).max(255)
3600
3277
  });
3601
- var normalizedFieldSchema = z10.object({
3602
- key: z10.string().trim().min(1).max(255),
3603
- kind: z10.string().trim().min(1).max(64).optional(),
3604
- label: z10.string().trim().min(1).max(255).optional(),
3605
- displayRole: z10.enum(["primary", "secondary"]).optional(),
3606
- multiple: z10.boolean().optional(),
3607
- options: z10.array(normalizedFieldOptionSchema).max(500).optional()
3278
+ var normalizedFieldSchema = z8.object({
3279
+ key: z8.string().trim().min(1).max(255),
3280
+ kind: z8.string().trim().min(1).max(64).optional(),
3281
+ label: z8.string().trim().min(1).max(255).optional(),
3282
+ displayRole: z8.enum(["primary", "secondary"]).optional(),
3283
+ multiple: z8.boolean().optional(),
3284
+ options: z8.array(normalizedFieldOptionSchema).max(500).optional()
3608
3285
  }).strict();
3609
- var definitionSyncInputSchema = z10.object({
3610
- formKey: z10.string().trim().min(1).max(255),
3611
- name: z10.string().trim().min(1).max(255),
3612
- normalizedFieldsJson: z10.array(normalizedFieldSchema).min(1).max(500),
3613
- schemaJson: z10.record(z10.unknown()),
3614
- sourceExportId: z10.string().trim().min(1).max(255).optional(),
3615
- sourcePagePath: z10.string().trim().min(1).max(2048).optional()
3286
+ var definitionSyncInputSchema = z8.object({
3287
+ formKey: z8.string().trim().min(1).max(255),
3288
+ name: z8.string().trim().min(1).max(255),
3289
+ normalizedFieldsJson: z8.array(normalizedFieldSchema).min(1).max(500),
3290
+ schemaJson: z8.record(z8.unknown()),
3291
+ sourceExportId: z8.string().trim().min(1).max(255).optional(),
3292
+ sourcePagePath: z8.string().trim().min(1).max(2048).optional()
3616
3293
  }).strict().superRefine((definition, context) => {
3617
3294
  const ajv = new Ajv({
3618
3295
  allErrors: true,
@@ -3624,7 +3301,7 @@ var definitionSyncInputSchema = z10.object({
3624
3301
  ajv.compile(definition.schemaJson);
3625
3302
  } catch {
3626
3303
  context.addIssue({
3627
- code: z10.ZodIssueCode.custom,
3304
+ code: z8.ZodIssueCode.custom,
3628
3305
  message: "schemaJson must be an executable JSON Schema supported by SiteOS Forms.",
3629
3306
  path: ["schemaJson"]
3630
3307
  });
@@ -3633,7 +3310,7 @@ var definitionSyncInputSchema = z10.object({
3633
3310
  const duplicateKeys = fields.map((field) => field.key).filter((key, index, keys) => keys.indexOf(key) !== index);
3634
3311
  for (const key of new Set(duplicateKeys)) {
3635
3312
  context.addIssue({
3636
- code: z10.ZodIssueCode.custom,
3313
+ code: z8.ZodIssueCode.custom,
3637
3314
  message: `Field key "${key}" is registered more than once.`,
3638
3315
  path: ["normalizedFieldsJson"]
3639
3316
  });
@@ -3643,7 +3320,7 @@ var definitionSyncInputSchema = z10.object({
3643
3320
  );
3644
3321
  if (primaryFields.length !== 1) {
3645
3322
  context.addIssue({
3646
- code: z10.ZodIssueCode.custom,
3323
+ code: z8.ZodIssueCode.custom,
3647
3324
  message: "Exactly one managed field must use the primary display role.",
3648
3325
  path: ["normalizedFieldsJson"]
3649
3326
  });
@@ -3651,7 +3328,7 @@ var definitionSyncInputSchema = z10.object({
3651
3328
  const schemaProperties = definition.schemaJson.properties;
3652
3329
  if (!isRecord(schemaProperties)) {
3653
3330
  context.addIssue({
3654
- code: z10.ZodIssueCode.custom,
3331
+ code: z8.ZodIssueCode.custom,
3655
3332
  message: "schemaJson.properties must define the managed form fields.",
3656
3333
  path: ["schemaJson", "properties"]
3657
3334
  });
@@ -3661,7 +3338,7 @@ var definitionSyncInputSchema = z10.object({
3661
3338
  for (const key of Object.keys(schemaProperties)) {
3662
3339
  if (!metadataKeys.has(key)) {
3663
3340
  context.addIssue({
3664
- code: z10.ZodIssueCode.custom,
3341
+ code: z8.ZodIssueCode.custom,
3665
3342
  message: `Schema field "${key}" is missing managed field metadata.`,
3666
3343
  path: ["normalizedFieldsJson"]
3667
3344
  });
@@ -3670,7 +3347,7 @@ var definitionSyncInputSchema = z10.object({
3670
3347
  for (const [index, field] of fields.entries()) {
3671
3348
  if (!Object.prototype.hasOwnProperty.call(schemaProperties, field.key)) {
3672
3349
  context.addIssue({
3673
- code: z10.ZodIssueCode.custom,
3350
+ code: z8.ZodIssueCode.custom,
3674
3351
  message: `Managed field "${field.key}" is missing from schemaJson.properties.`,
3675
3352
  path: ["normalizedFieldsJson", index, "key"]
3676
3353
  });
@@ -3680,33 +3357,27 @@ var definitionSyncInputSchema = z10.object({
3680
3357
  const requiredFields = definition.schemaJson.required;
3681
3358
  if (primaryField && (!Array.isArray(requiredFields) || !requiredFields.includes(primaryField.key))) {
3682
3359
  context.addIssue({
3683
- code: z10.ZodIssueCode.custom,
3360
+ code: z8.ZodIssueCode.custom,
3684
3361
  message: `Primary display field "${primaryField.key}" must be required by schemaJson.`,
3685
3362
  path: ["schemaJson", "required"]
3686
3363
  });
3687
3364
  }
3688
3365
  });
3689
- var definitionManifestSchema = z10.object({
3690
- version: z10.literal(1),
3691
- forms: z10.array(z10.string().trim().min(1)).min(1)
3366
+ var definitionManifestSchema = z8.object({
3367
+ version: z8.literal(1),
3368
+ forms: z8.array(z8.string().trim().min(1)).min(1)
3692
3369
  });
3693
- var submitInputSchema = z10.object({
3694
- formKey: z10.string().trim().min(1),
3695
- idempotencyKey: z10.string().trim().min(1),
3696
- ipAddress: z10.string().trim().min(1).optional(),
3697
- payload: z10.record(z10.unknown()),
3698
- sourceUrl: z10.string().trim().min(1).optional(),
3699
- userAgent: z10.string().trim().min(1).optional()
3370
+ var submitInputSchema = z8.object({
3371
+ formKey: z8.string().trim().min(1),
3372
+ idempotencyKey: z8.string().trim().min(1),
3373
+ ipAddress: z8.string().trim().min(1).optional(),
3374
+ payload: z8.record(z8.unknown()),
3375
+ sourceUrl: z8.string().trim().min(1).optional(),
3376
+ userAgent: z8.string().trim().min(1).optional()
3700
3377
  }).passthrough();
3701
- var environmentNameSchema = z10.string().transform((value) => value.trim()).refine((value) => value.length >= 1 && value.length <= 255);
3702
- var projectSlugSchema = z10.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
3378
+ var environmentNameSchema = z8.string().transform((value) => value.trim()).refine((value) => value.length >= 1 && value.length <= 255);
3379
+ var projectSlugSchema = z8.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
3703
3380
  var FORMS_HELP = `Usage:
3704
- siteos forms project list [--json]
3705
- siteos forms project create --slug <slug> --name <name> [--json]
3706
- siteos forms project use <slug> [--replace] [--json]
3707
- siteos forms project status [--json]
3708
- siteos forms environment list [--json]
3709
- siteos forms environment create --slug <slug> --name <name> [--json]
3710
3381
  siteos forms definition sync --environment <slug> --input <path> [--json]
3711
3382
  siteos forms definition sync --environment <slug> --manifest <path> [--json]
3712
3383
  siteos forms definition list --environment <slug> [--status <active|inactive|all>] [--json]
@@ -3720,7 +3391,6 @@ var FORMS_HELP = `Usage:
3720
3391
  siteos forms credential issue --environment <slug> --install [--name <name>] [--json]
3721
3392
  siteos forms credential rotate --environment <slug> --install [--name <name>] [--json]
3722
3393
  siteos forms credential revoke --environment <slug> --credential <credential-id> [--json]
3723
- siteos forms credentials issue --environment <slug> [--name <name>] [--json]
3724
3394
  siteos forms submissions list --environment <slug> --form <form-id> [--query <text>] [--status <status>] [--from <ISO>] [--to <ISO>] [--limit <1-100>] [--cursor <cursor>] [--json]
3725
3395
  siteos forms submissions read --environment <slug> --form <form-id> --submission <id> [--json]
3726
3396
  siteos forms submissions status --environment <slug> --form <form-id> --submission <id> --status <new|read|archived|spam> --expected-status <status> [--json]
@@ -3739,12 +3409,26 @@ async function runFormsCommand(options) {
3739
3409
  stdout: FORMS_HELP
3740
3410
  };
3741
3411
  }
3412
+ const environmentFlags = args2.flatMap(
3413
+ (arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice(14)] : [arg]
3414
+ );
3415
+ const environmentIndex = environmentFlags.indexOf("--environment");
3416
+ options = {
3417
+ ...options,
3418
+ selectedEnvironment: environmentIndex >= 0 ? environmentFlags[environmentIndex + 1] : void 0
3419
+ };
3420
+ if (["project", "environment"].includes(args2[0] ?? ""))
3421
+ return usageError2(
3422
+ "Use `siteos project` to manage Projects and environments."
3423
+ );
3742
3424
  if (args2[0] === "deploy")
3743
3425
  return runDeployment({ ...options, args: args2.slice(1) });
3744
- if (args2[0] !== "submit" && args2[0] !== "project") {
3426
+ if (args2[0] !== "submit") {
3745
3427
  try {
3746
3428
  args2 = await commonEnvironmentArguments(options, "forms", args2);
3747
3429
  } catch (error) {
3430
+ if (error instanceof SiteOSAuthApiError)
3431
+ return formatAuthError(error).error;
3748
3432
  return {
3749
3433
  exitCode: 1,
3750
3434
  stderr: error instanceof Error ? error.message : "Environment could not be selected."
@@ -3759,18 +3443,6 @@ async function runFormsCommand(options) {
3759
3443
  args: args2.slice(1)
3760
3444
  });
3761
3445
  }
3762
- if (args2[0] === "environment") {
3763
- return runEnvironmentCommand({
3764
- ...options,
3765
- args: args2.slice(1)
3766
- });
3767
- }
3768
- if (args2[0] === "project") {
3769
- return runProjectCommand({
3770
- ...options,
3771
- args: args2.slice(1)
3772
- });
3773
- }
3774
3446
  if (args2[0] === "submit") {
3775
3447
  return runSubmit({
3776
3448
  ...options,
@@ -3790,17 +3462,6 @@ async function runFormsCommand(options) {
3790
3462
  args: args2.slice(1)
3791
3463
  });
3792
3464
  }
3793
- if (args2[0] === "credentials" && args2[1] === "issue") {
3794
- const compatibilityArgs = args2.slice(2);
3795
- return runCredentialCommand({
3796
- ...options,
3797
- args: [
3798
- "issue",
3799
- ...compatibilityArgs,
3800
- ...compatibilityArgs.includes(INSTALL_FLAG) ? [] : [INSTALL_FLAG]
3801
- ]
3802
- });
3803
- }
3804
3465
  return usageError2("Unknown SiteOS forms command.");
3805
3466
  }
3806
3467
  async function runSubmissionsCommand(options) {
@@ -3850,7 +3511,7 @@ async function runSubmissionsCommand(options) {
3850
3511
  if ((value("query")?.length ?? 0) > 200 || (value("cursor")?.length ?? 0) > 2048)
3851
3512
  return usageError2("The query or cursor is too long.");
3852
3513
  for (const key of ["from", "to"])
3853
- if (value(key) && !z10.string().datetime({ offset: true }).safeParse(value(key)).success)
3514
+ if (value(key) && !z8.string().datetime({ offset: true }).safeParse(value(key)).success)
3854
3515
  return usageError2(
3855
3516
  `--${key} must be an ISO timestamp including a timezone.`
3856
3517
  );
@@ -3872,7 +3533,7 @@ async function runSubmissionsCommand(options) {
3872
3533
  );
3873
3534
  if (!environment)
3874
3535
  return usageError2(
3875
- "The selected Forms Environment does not exist. Run forms environment list."
3536
+ "The selected Forms Environment does not exist. Run siteos project environment list."
3876
3537
  );
3877
3538
  const input = {
3878
3539
  grant: context.grant,
@@ -3893,277 +3554,56 @@ async function runSubmissionsCommand(options) {
3893
3554
  return formatApiError(error);
3894
3555
  }
3895
3556
  }
3896
- async function runProjectCommand(options) {
3557
+ async function runCredentialCommand(options) {
3897
3558
  const action = options.args[0];
3898
- if (!action || !["create", "list", "status", "use"].includes(action)) {
3899
- return usageError2("Unknown SiteOS forms project command.");
3559
+ if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
3560
+ return usageError2("Unknown SiteOS forms credential command.");
3900
3561
  }
3901
- const parsed = parseProjectFlags(action, options.args.slice(1));
3902
- if (!parsed.ok) return parsed.error;
3903
- if (!options.fetchImpl) {
3904
- return formatApiError(
3905
- new SiteOSFormsApiError({
3906
- code: "FORMS_UNAVAILABLE",
3907
- message: "SiteOS Forms access is unavailable in this runtime."
3908
- })
3562
+ if (options.deployment && action === "rotate")
3563
+ return usageError2(
3564
+ "Issue a new deployment key, update the release secret, then revoke the old key."
3909
3565
  );
3910
- }
3566
+ const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
3567
+ const parsed = parseCredentialFlags(action, options.args.slice(1));
3568
+ if (!parsed.ok) return parsed.error;
3569
+ const context = await loadCredentialManagementContext({
3570
+ ...options,
3571
+ install: parsed.install
3572
+ });
3573
+ if (!context.ok) return context.error;
3911
3574
  try {
3912
- const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
3913
- const grant = await serviceGrantProvider(options).acquire({
3914
- audience: "siteos-forms",
3915
- scopes: ["forms:workspace:write"]
3916
- });
3917
- requireGrant(grant, "forms:workspace:write");
3918
- const client = createSiteOSFormsApiClient({
3919
- apiBaseUrl,
3920
- fetchImpl: options.fetchImpl
3921
- });
3922
3575
  if (action === "list") {
3923
- const response = await client.listProjects({ grant: grant.accessToken });
3924
- requireProjectOrganization(response.projects, grant.grant.organizationId);
3576
+ const response = await context.client.listCredentials({
3577
+ environmentSlug: parsed.environmentSlug,
3578
+ grant: context.grant,
3579
+ projectId: context.project.id
3580
+ });
3581
+ const output2 = {
3582
+ credentials: response.tokens,
3583
+ environment: parsed.environmentSlug
3584
+ };
3925
3585
  return {
3926
3586
  exitCode: 0,
3927
- stdout: parsed.json ? stringifySafeJson(response) : formatProjectListOutput(response.projects)
3587
+ stdout: parsed.json ? stringifySafeJson(output2) : formatCredentialListOutput(output2)
3928
3588
  };
3929
3589
  }
3930
- if (action === "create") {
3931
- const response = await client.createProject({
3932
- grant: grant.accessToken,
3933
- name: parsed.name,
3934
- slug: parsed.slug
3590
+ if (action === "revoke") {
3591
+ const credential2 = await context.client.revokeCredential({
3592
+ credentialId: parsed.credentialId,
3593
+ environmentSlug: parsed.environmentSlug,
3594
+ grant: context.grant,
3595
+ projectId: context.project.id
3935
3596
  });
3936
- requireProjectOrganization(
3937
- [response.project],
3938
- grant.grant.organizationId
3939
- );
3597
+ const output2 = {
3598
+ credential: credential2,
3599
+ environment: parsed.environmentSlug,
3600
+ revoked: true
3601
+ };
3940
3602
  return {
3941
3603
  exitCode: 0,
3942
- stdout: parsed.json ? stringifySafeJson(response) : [
3943
- "SiteOS Forms Project created.",
3944
- `Project: ${response.project.slug}`,
3945
- `Name: ${response.project.name}`,
3946
- "Run `siteos forms project use " + response.project.slug + "` to select it for this repository."
3947
- ].join("\n")
3948
- };
3949
- }
3950
- const reference = await inspectFormsProjectReference(
3951
- options.cwd ?? process.cwd()
3952
- );
3953
- const store = projectBindingStore(options);
3954
- const locator = {
3955
- apiOrigin: apiBaseUrl,
3956
- repositoryRoot: reference.rootDir,
3957
- service: "forms"
3958
- };
3959
- if (action === "use") {
3960
- const response = await client.listProjects({ grant: grant.accessToken });
3961
- requireProjectOrganization(response.projects, grant.grant.organizationId);
3962
- const matches = response.projects.filter(
3963
- (project3) => project3.slug === parsed.slug
3964
- );
3965
- if (matches.length !== 1) {
3966
- throw new SiteOSFormsApiError({
3967
- code: matches.length === 0 ? "PROJECT_NOT_FOUND" : "INVALID_RESPONSE",
3968
- message: matches.length === 0 ? "The Forms Project was not found." : "SiteOS Forms returned an invalid response.",
3969
- status: matches.length === 0 ? 404 : void 0
3970
- });
3971
- }
3972
- const project2 = matches[0];
3973
- if (reference.status === "loaded" && reference.reference.project.slug !== project2.slug && !parsed.replace) {
3974
- throw new FormsProjectReferenceError(
3975
- "FORMS_PROJECT_REFERENCE_CONFLICT",
3976
- "A different Forms Project is already selected. Use --replace to replace it."
3977
- );
3978
- }
3979
- const previousBinding = await store.read(locator);
3980
- await store.write({
3981
- ...locator,
3982
- organizationId: grant.grant.organizationId,
3983
- project: { id: project2.id, slug: project2.slug }
3984
- });
3985
- try {
3986
- await writeFormsProjectReference({
3987
- expectedChecksum: reference.status === "loaded" ? reference.checksum : null,
3988
- project: { name: project2.name, slug: project2.slug },
3989
- rootDir: reference.rootDir
3990
- });
3991
- } catch (error) {
3992
- if (previousBinding) await store.write(previousBinding);
3993
- else await store.remove(locator);
3994
- throw error;
3995
- }
3996
- const output2 = {
3997
- apiOrigin: apiBaseUrl,
3998
- organizationId: grant.grant.organizationId,
3999
- project: project2,
4000
- referencePath: path12.join(
4001
- reference.rootDir,
4002
- ".siteos",
4003
- "forms",
4004
- "project.json"
4005
- )
4006
- };
4007
- return {
4008
- exitCode: 0,
4009
- stdout: parsed.json ? stringifySafeJson(output2) : [
4010
- "SiteOS Forms Project selected.",
4011
- `Project: ${project2.slug}`,
4012
- `Reference: ${output2.referencePath}`
4013
- ].join("\n")
4014
- };
4015
- }
4016
- if (reference.status === "missing") {
4017
- throw new FormsProjectReferenceError(
4018
- "FORMS_PROJECT_REFERENCE_REQUIRED",
4019
- "Select a Forms Project for this repository first."
4020
- );
4021
- }
4022
- const binding = await store.read(locator);
4023
- if (!binding) {
4024
- throw new FormsProjectReferenceError(
4025
- "FORMS_PROJECT_REFERENCE_REQUIRED",
4026
- "Select a Forms Project for this repository first."
4027
- );
4028
- }
4029
- if (binding.organizationId !== grant.grant.organizationId || binding.project.slug !== reference.reference.project.slug) {
4030
- throw new FormsProjectReferenceError(
4031
- "FORMS_PROJECT_REFERENCE_INVALID",
4032
- "The Forms Project reference and private binding do not match."
4033
- );
4034
- }
4035
- const projects = await client.listProjects({ grant: grant.accessToken });
4036
- requireProjectOrganization(projects.projects, grant.grant.organizationId);
4037
- const project = projects.projects.find(
4038
- (candidate) => candidate.id === binding.project.id
4039
- );
4040
- if (!project || project.slug !== binding.project.slug) {
4041
- throw new SiteOSFormsApiError({
4042
- code: "PROJECT_NOT_FOUND",
4043
- message: "The Forms Project was not found.",
4044
- status: 404
4045
- });
4046
- }
4047
- const output = {
4048
- apiOrigin: apiBaseUrl,
4049
- connected: true,
4050
- organizationId: binding.organizationId,
4051
- project,
4052
- repositoryRoot: reference.rootDir
4053
- };
4054
- return {
4055
- exitCode: 0,
4056
- stdout: parsed.json ? stringifySafeJson(output) : [
4057
- "SiteOS Forms Project connection is valid.",
4058
- `Project: ${project.slug}`,
4059
- `Organization: ${binding.organizationId}`,
4060
- `API: ${apiBaseUrl}`
4061
- ].join("\n")
4062
- };
4063
- } catch (error) {
4064
- return formatProjectError(error);
4065
- }
4066
- }
4067
- async function runEnvironmentCommand(options) {
4068
- const action = options.args[0];
4069
- if (!action || !["create", "list"].includes(action)) {
4070
- return usageError2("Unknown SiteOS forms environment command.");
4071
- }
4072
- const parsed = parseEnvironmentFlags(action, options.args.slice(1));
4073
- if (!parsed.ok) return parsed.error;
4074
- const context = await loadFormsManagementContext(
4075
- options,
4076
- "forms:workspace:write"
4077
- );
4078
- if (!context.ok) return context.error;
4079
- try {
4080
- if (action === "list") {
4081
- const response2 = await context.client.listEnvironments({
4082
- grant: context.grant,
4083
- projectId: context.project.id
4084
- });
4085
- requireEnvironmentProjectConvergence(
4086
- response2.environments,
4087
- context.project.id
4088
- );
4089
- return {
4090
- exitCode: 0,
4091
- stdout: parsed.json ? stringifySafeJson(response2) : formatEnvironmentListOutput(response2.environments)
4092
- };
4093
- }
4094
- const response = await context.client.createEnvironment({
4095
- grant: context.grant,
4096
- name: parsed.name,
4097
- projectId: context.project.id,
4098
- slug: parsed.slug
4099
- });
4100
- requireEnvironmentProjectConvergence(
4101
- [response.environment],
4102
- context.project.id
4103
- );
4104
- return {
4105
- exitCode: 0,
4106
- stdout: parsed.json ? stringifySafeJson(response) : [
4107
- "SiteOS Forms Environment created.",
4108
- `Environment: ${response.environment.slug}`,
4109
- `Name: ${response.environment.name}`,
4110
- `Project: ${response.environment.projectId}`
4111
- ].join("\n")
4112
- };
4113
- } catch (error) {
4114
- return formatApiError(error);
4115
- }
4116
- }
4117
- async function runCredentialCommand(options) {
4118
- const action = options.args[0];
4119
- if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
4120
- return usageError2("Unknown SiteOS forms credential command.");
4121
- }
4122
- if (options.deployment && action === "rotate")
4123
- return usageError2(
4124
- "Issue a new deployment key, update the release secret, then revoke the old key."
4125
- );
4126
- const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
4127
- const parsed = parseCredentialFlags(action, options.args.slice(1));
4128
- if (!parsed.ok) return parsed.error;
4129
- const context = await loadCredentialManagementContext({
4130
- ...options,
4131
- install: parsed.install
4132
- });
4133
- if (!context.ok) return context.error;
4134
- try {
4135
- if (action === "list") {
4136
- const response = await context.client.listCredentials({
4137
- environmentSlug: parsed.environmentSlug,
4138
- grant: context.grant,
4139
- projectId: context.project.id
4140
- });
4141
- const output2 = {
4142
- credentials: response.tokens,
4143
- environment: parsed.environmentSlug
4144
- };
4145
- return {
4146
- exitCode: 0,
4147
- stdout: parsed.json ? stringifySafeJson(output2) : formatCredentialListOutput(output2)
4148
- };
4149
- }
4150
- if (action === "revoke") {
4151
- const credential2 = await context.client.revokeCredential({
4152
- credentialId: parsed.credentialId,
4153
- environmentSlug: parsed.environmentSlug,
4154
- grant: context.grant,
4155
- projectId: context.project.id
4156
- });
4157
- const output2 = {
4158
- credential: credential2,
4159
- environment: parsed.environmentSlug,
4160
- revoked: true
4161
- };
4162
- return {
4163
- exitCode: 0,
4164
- stdout: parsed.json ? stringifySafeJson(output2) : `SiteOS Forms credential revoked.
4165
- Credential: ${credential2.id}
4166
- Environment: ${parsed.environmentSlug}`
3604
+ stdout: parsed.json ? stringifySafeJson(output2) : `SiteOS Forms credential revoked.
3605
+ Credential: ${credential2.id}
3606
+ Environment: ${parsed.environmentSlug}`
4167
3607
  };
4168
3608
  }
4169
3609
  const previousCredentials = action === "rotate" ? (await context.client.listCredentials({
@@ -4215,7 +3655,12 @@ Environment: ${parsed.environmentSlug}`
4215
3655
  async function loadCredentialManagementContext(options) {
4216
3656
  try {
4217
3657
  const local = await readLocalCommonProject(options);
4218
- const rootDir = local?.rootDir ?? (await requireFormsProjectReference(options.cwd ?? process.cwd())).rootDir;
3658
+ if (!local)
3659
+ throw new SiteOSAuthApiError({
3660
+ code: "PROJECT_REQUIRED",
3661
+ message: "Select a Project with `siteos project use <id-or-slug>`."
3662
+ });
3663
+ const rootDir = local.rootDir;
4219
3664
  const installation = options.install ? await (options.prepareCredentialInstallation ?? prepareSiteOSFormsCredentialInstallation)({
4220
3665
  projectRoot: rootDir,
4221
3666
  ...options.deployment ? { deployment: true } : {}
@@ -4242,31 +3687,41 @@ async function loadCredentialManagementContext(options) {
4242
3687
  }
4243
3688
  async function loadFormsManagementContext(options, scope) {
4244
3689
  try {
4245
- const common = await commonServiceContext(options, "forms");
4246
- if (common) {
3690
+ const common = await commonServiceContext(
3691
+ options,
3692
+ "forms",
3693
+ options.selectedEnvironment
3694
+ );
3695
+ if (!common)
3696
+ throw new SiteOSAuthApiError({
3697
+ code: "PROJECT_REQUIRED",
3698
+ message: "Select a Project with `siteos project use <id-or-slug>`."
3699
+ });
3700
+ {
4247
3701
  if (!options.fetchImpl)
4248
3702
  throw new SiteOSAuthApiError({
4249
3703
  code: "AUTH_UNAVAILABLE",
4250
3704
  message: "SiteOS API access is unavailable."
4251
3705
  });
4252
- const grant2 = await serviceGrantProvider(options).acquire({
3706
+ const grant = await serviceGrantProvider(options).acquire({
4253
3707
  audience: "siteos-forms",
4254
3708
  scopes: [scope]
4255
3709
  });
4256
- requireGrant(grant2, scope);
4257
- if (grant2.grant.organizationId !== common.overview.project.organizationId)
3710
+ requireGrant(grant, scope);
3711
+ if (grant.grant.organizationId !== common.overview.project.organizationId)
4258
3712
  throw new SiteOSAuthApiError({
4259
3713
  code: "PROJECT_ORGANIZATION_MISMATCH",
4260
3714
  message: "The Project and service grant belong to different organizations."
4261
3715
  });
4262
3716
  return {
4263
3717
  commonProjectId: common.overview.project.id,
3718
+ environmentSlug: common.environment.slug,
4264
3719
  apiBaseUrl: common.api.origin,
4265
3720
  client: createSiteOSFormsApiClient({
4266
3721
  apiBaseUrl: common.api.origin,
4267
3722
  fetchImpl: options.fetchImpl
4268
3723
  }),
4269
- grant: grant2.accessToken,
3724
+ grant: grant.accessToken,
4270
3725
  ok: true,
4271
3726
  organization: { id: common.overview.project.organizationId },
4272
3727
  project: {
@@ -4277,73 +3732,10 @@ async function loadFormsManagementContext(options, scope) {
4277
3732
  rootDir: common.rootDir
4278
3733
  };
4279
3734
  }
4280
- const reference = await requireFormsProjectReference(
4281
- options.cwd ?? process.cwd()
4282
- );
4283
- if (!options.fetchImpl) {
4284
- throw new SiteOSFormsApiError({
4285
- code: "FORMS_UNAVAILABLE",
4286
- message: "SiteOS Forms access is unavailable in this runtime."
4287
- });
4288
- }
4289
- const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
4290
- const binding = await projectBindingStore(options).read({
4291
- apiOrigin: apiBaseUrl,
4292
- repositoryRoot: reference.rootDir,
4293
- service: "forms"
4294
- });
4295
- if (!binding) {
4296
- throw new FormsProjectReferenceError(
4297
- "FORMS_PROJECT_REFERENCE_REQUIRED",
4298
- "Select a Forms Project for this repository first."
4299
- );
4300
- }
4301
- const grant = await serviceGrantProvider(options).acquire({
4302
- audience: "siteos-forms",
4303
- scopes: [scope]
4304
- });
4305
- if (grant.grant.audience !== "siteos-forms" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
4306
- throw new SiteOSAuthApiError({
4307
- code: "AUTH_INVALID_RESPONSE",
4308
- message: "The SiteOS Auth service returned an invalid response."
4309
- });
4310
- }
4311
- if (grant.grant.organizationId !== binding.organizationId || binding.project.slug !== reference.reference.project.slug) {
4312
- throw new SiteOSAuthApiError({
4313
- code: "AUTH_INVALID_RESPONSE",
4314
- message: "The selected Forms Project does not match this Auth Organization."
4315
- });
4316
- }
4317
- return {
4318
- apiBaseUrl,
4319
- client: createSiteOSFormsApiClient({
4320
- apiBaseUrl,
4321
- fetchImpl: options.fetchImpl
4322
- }),
4323
- grant: grant.accessToken,
4324
- ok: true,
4325
- organization: { id: binding.organizationId },
4326
- project: {
4327
- id: binding.project.id,
4328
- name: reference.reference.project.name,
4329
- slug: binding.project.slug
4330
- },
4331
- rootDir: reference.rootDir
4332
- };
4333
3735
  } catch (error) {
4334
3736
  return { error: formatManagementContextError(error), ok: false };
4335
3737
  }
4336
3738
  }
4337
- async function requireFormsProjectReference(cwd) {
4338
- const reference = await inspectFormsProjectReference(cwd);
4339
- if (reference.status === "missing") {
4340
- throw new FormsProjectReferenceError(
4341
- "FORMS_PROJECT_REFERENCE_REQUIRED",
4342
- "Select a Forms Project for this repository first."
4343
- );
4344
- }
4345
- return reference;
4346
- }
4347
3739
  async function runDefinitionCommand(options) {
4348
3740
  if (["list", "read", "archive", "restore", "delete"].includes(
4349
3741
  options.args[0] ?? ""
@@ -4421,7 +3813,7 @@ async function runDefinitionLifecycle(options) {
4421
3813
  );
4422
3814
  if (!environment)
4423
3815
  return usageError2(
4424
- "The selected Forms Environment does not exist. Run forms environment list."
3816
+ "The selected Forms Environment does not exist. Run siteos project environment list."
4425
3817
  );
4426
3818
  const input = {
4427
3819
  grant: context.grant,
@@ -4647,41 +4039,20 @@ async function loadSubmissionFormsContext(options) {
4647
4039
  }
4648
4040
  try {
4649
4041
  const common = await readLocalCommonProject(options);
4650
- if (common)
4042
+ if (common && common.binding.environmentSlug)
4651
4043
  return {
4652
4044
  apiBaseUrl: common.api.origin,
4653
4045
  commonProjectId: common.binding.project.id,
4046
+ environmentSlug: common.binding.environmentSlug,
4654
4047
  ok: true,
4655
4048
  organization: { id: common.binding.organizationId },
4656
4049
  project: { slug: common.binding.project.slug },
4657
4050
  credential
4658
4051
  };
4659
- const reference = await requireFormsProjectReference(
4660
- options.cwd ?? process.cwd()
4661
- );
4662
- const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
4663
- const binding = await projectBindingStore(options).read({
4664
- apiOrigin: apiBaseUrl,
4665
- repositoryRoot: reference.rootDir,
4666
- service: "forms"
4052
+ throw new SiteOSAuthApiError({
4053
+ code: "PROJECT_REQUIRED",
4054
+ message: "Select a Project with `siteos project use <id-or-slug>`."
4667
4055
  });
4668
- if (!binding || binding.project.slug !== reference.reference.project.slug) {
4669
- throw new FormsProjectReferenceError(
4670
- binding ? "FORMS_PROJECT_REFERENCE_INVALID" : "FORMS_PROJECT_REFERENCE_REQUIRED",
4671
- binding ? "The Forms Project reference and private binding do not match." : "Select a Forms Project for this repository first."
4672
- );
4673
- }
4674
- return {
4675
- apiBaseUrl,
4676
- ok: true,
4677
- organization: { id: binding.organizationId },
4678
- project: {
4679
- id: binding.project.id,
4680
- name: reference.reference.project.name,
4681
- slug: binding.project.slug
4682
- },
4683
- credential
4684
- };
4685
4056
  } catch (error) {
4686
4057
  return { error: formatManagementContextError(error), ok: false };
4687
4058
  }
@@ -4709,76 +4080,6 @@ function formatAuthError(error) {
4709
4080
  ok: false
4710
4081
  };
4711
4082
  }
4712
- function parseProjectFlags(action, args2) {
4713
- const creates = action === "create";
4714
- const uses = action === "use";
4715
- const parsed = parseFlags(args2, {
4716
- allowed: /* @__PURE__ */ new Set([
4717
- JSON_FLAG,
4718
- ...creates ? [NAME_FLAG, SLUG_FLAG] : [],
4719
- ...uses ? [REPLACE_FLAG] : []
4720
- ]),
4721
- boolean: /* @__PURE__ */ new Set([JSON_FLAG, REPLACE_FLAG]),
4722
- rejectDuplicates: true
4723
- });
4724
- if (!parsed.ok) return { error: usageError2(parsed.error), ok: false };
4725
- if (uses) {
4726
- if (parsed.positionals.length !== 1) {
4727
- return {
4728
- error: usageError2("Project use requires exactly one Project slug."),
4729
- ok: false
4730
- };
4731
- }
4732
- const slug3 = projectSlugSchema.safeParse(parsed.positionals[0]);
4733
- if (!slug3.success) {
4734
- return { error: usageError2("Project slug is invalid."), ok: false };
4735
- }
4736
- return {
4737
- json: parsed.flags.has(JSON_FLAG),
4738
- ok: true,
4739
- replace: parsed.flags.has(REPLACE_FLAG),
4740
- slug: slug3.data
4741
- };
4742
- }
4743
- if (parsed.positionals.length > 0) {
4744
- return {
4745
- error: usageError2(`Unexpected argument: ${parsed.positionals[0]}`),
4746
- ok: false
4747
- };
4748
- }
4749
- if (!creates) {
4750
- return {
4751
- json: parsed.flags.has(JSON_FLAG),
4752
- ok: true,
4753
- replace: false
4754
- };
4755
- }
4756
- const slug2 = projectSlugSchema.safeParse(
4757
- readStringFlag(parsed.flags, SLUG_FLAG)
4758
- );
4759
- const name = environmentNameSchema.safeParse(
4760
- readStringFlag(parsed.flags, NAME_FLAG)
4761
- );
4762
- if (!slug2.success) {
4763
- return {
4764
- error: usageError2("--slug is required and must be valid."),
4765
- ok: false
4766
- };
4767
- }
4768
- if (!name.success) {
4769
- return {
4770
- error: usageError2("--name is required and must be valid."),
4771
- ok: false
4772
- };
4773
- }
4774
- return {
4775
- json: parsed.flags.has(JSON_FLAG),
4776
- name: name.data,
4777
- ok: true,
4778
- replace: false,
4779
- slug: slug2.data
4780
- };
4781
- }
4782
4083
  function parseCredentialFlags(action, args2) {
4783
4084
  const installs = action === "issue" || action === "rotate";
4784
4085
  const revokes = action === "revoke";
@@ -4847,48 +4148,6 @@ function parseCredentialFlags(action, args2) {
4847
4148
  ok: true
4848
4149
  };
4849
4150
  }
4850
- function parseEnvironmentFlags(action, args2) {
4851
- const creates = action === "create";
4852
- const parsed = parseFlags(args2, {
4853
- allowed: /* @__PURE__ */ new Set([JSON_FLAG, ...creates ? [NAME_FLAG, SLUG_FLAG] : []]),
4854
- boolean: /* @__PURE__ */ new Set([JSON_FLAG]),
4855
- rejectDuplicates: true
4856
- });
4857
- if (!parsed.ok) return { error: usageError2(parsed.error), ok: false };
4858
- if (parsed.positionals.length > 0) {
4859
- return {
4860
- error: usageError2(`Unexpected argument: ${parsed.positionals[0]}`),
4861
- ok: false
4862
- };
4863
- }
4864
- if (!creates) {
4865
- return { json: parsed.flags.has(JSON_FLAG), ok: true };
4866
- }
4867
- const slug2 = readStringFlag(parsed.flags, SLUG_FLAG);
4868
- if (!slug2) {
4869
- return { error: usageError2("--slug is required."), ok: false };
4870
- }
4871
- if (!isValidEnvironmentSlug(slug2)) {
4872
- return {
4873
- error: usageError2("--slug must be a valid environment slug."),
4874
- ok: false
4875
- };
4876
- }
4877
- const name = readStringFlag(parsed.flags, NAME_FLAG);
4878
- if (!name) {
4879
- return { error: usageError2("--name is required."), ok: false };
4880
- }
4881
- const parsedName = environmentNameSchema.safeParse(name);
4882
- if (!parsedName.success) {
4883
- return { error: usageError2("--name is invalid."), ok: false };
4884
- }
4885
- return {
4886
- json: parsed.flags.has(JSON_FLAG),
4887
- name: parsedName.data,
4888
- ok: true,
4889
- slug: slug2
4890
- };
4891
- }
4892
4151
  function parseDefinitionSourceFlags(args2, options) {
4893
4152
  const parsed = parseFlags(args2, {
4894
4153
  allowed: /* @__PURE__ */ new Set([
@@ -4959,7 +4218,7 @@ async function loadFormDefinitions(options) {
4959
4218
  ok: true
4960
4219
  };
4961
4220
  }
4962
- const manifestPath = path12.resolve(
4221
+ const manifestPath = path10.resolve(
4963
4222
  options.cwd ?? process.cwd(),
4964
4223
  options.source.path
4965
4224
  );
@@ -4969,10 +4228,10 @@ async function loadFormDefinitions(options) {
4969
4228
  schema: definitionManifestSchema
4970
4229
  });
4971
4230
  if (!manifest.ok) return manifest;
4972
- const manifestDirectory = path12.dirname(manifestPath);
4231
+ const manifestDirectory = path10.dirname(manifestPath);
4973
4232
  const definitions = [];
4974
4233
  for (const definitionPath of manifest.value.forms) {
4975
- if (path12.isAbsolute(definitionPath)) {
4234
+ if (path10.isAbsolute(definitionPath)) {
4976
4235
  return {
4977
4236
  error: usageError2(
4978
4237
  `Manifest definition paths must be relative: ${definitionPath}`
@@ -4980,9 +4239,9 @@ async function loadFormDefinitions(options) {
4980
4239
  ok: false
4981
4240
  };
4982
4241
  }
4983
- const resolvedPath = path12.resolve(manifestDirectory, definitionPath);
4984
- const relativePath = path12.relative(manifestDirectory, resolvedPath);
4985
- if (relativePath.startsWith(`..${path12.sep}`) || relativePath === "..") {
4242
+ const resolvedPath = path10.resolve(manifestDirectory, definitionPath);
4243
+ const relativePath = path10.relative(manifestDirectory, resolvedPath);
4244
+ if (relativePath.startsWith(`..${path10.sep}`) || relativePath === "..") {
4986
4245
  return {
4987
4246
  error: usageError2(
4988
4247
  `Manifest definition paths must stay inside the manifest directory: ${definitionPath}`
@@ -5045,7 +4304,7 @@ function parseInputFlags(args2, options) {
5045
4304
  };
5046
4305
  }
5047
4306
  async function readInputFile(options) {
5048
- const resolvedInputPath = path12.resolve(
4307
+ const resolvedInputPath = path10.resolve(
5049
4308
  options.cwd ?? process.cwd(),
5050
4309
  options.inputPath
5051
4310
  );
@@ -5187,7 +4446,7 @@ function formatCredentialError(error) {
5187
4446
  stderr: error.message
5188
4447
  };
5189
4448
  }
5190
- if (error instanceof FormsProjectReferenceError || error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
4449
+ if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
5191
4450
  return {
5192
4451
  exitCode: 1,
5193
4452
  stderr: [
@@ -5216,7 +4475,7 @@ function formatManagementContextError(error) {
5216
4475
  if (error instanceof SiteOSAuthApiError) {
5217
4476
  return formatAuthError(error).error;
5218
4477
  }
5219
- if (error instanceof FormsProjectReferenceError || error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
4478
+ if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
5220
4479
  return {
5221
4480
  exitCode: 1,
5222
4481
  stderr: [
@@ -5228,24 +4487,12 @@ function formatManagementContextError(error) {
5228
4487
  }
5229
4488
  return formatApiError(error);
5230
4489
  }
5231
- function formatProjectError(error) {
5232
- if (error instanceof SiteOSAuthApiError) return formatAuthError(error).error;
5233
- return formatManagementContextError(error);
5234
- }
5235
4490
  function serviceGrantProvider(options) {
5236
4491
  return options.serviceGrantProvider ?? createSiteOSServiceGrantProvider({
5237
4492
  env: options.env,
5238
4493
  fetchImpl: options.fetchImpl
5239
4494
  });
5240
4495
  }
5241
- function projectBindingStore(options) {
5242
- return options.projectBindingStore ?? new NodeProjectBindingStore(
5243
- path12.join(
5244
- resolveSiteOSConfigHome({ env: options.env }),
5245
- "project-bindings.json"
5246
- )
5247
- );
5248
- }
5249
4496
  function requireGrant(grant, scope) {
5250
4497
  if (grant.grant.audience !== "siteos-forms" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
5251
4498
  throw new SiteOSAuthApiError({
@@ -5254,23 +4501,6 @@ function requireGrant(grant, scope) {
5254
4501
  });
5255
4502
  }
5256
4503
  }
5257
- function requireProjectOrganization(projects, organizationId) {
5258
- if (projects.some((project) => project.organizationId !== organizationId)) {
5259
- throw new SiteOSFormsApiError({
5260
- code: "INVALID_RESPONSE",
5261
- message: "SiteOS Forms returned an invalid response."
5262
- });
5263
- }
5264
- }
5265
- function formatProjectListOutput(projects) {
5266
- return [
5267
- "SiteOS Forms Projects.",
5268
- `Projects: ${projects.length}`,
5269
- ...projects.map(
5270
- (project) => `- ${project.slug}: ${project.name} (${project.id})`
5271
- )
5272
- ].join("\n");
5273
- }
5274
4504
  function formatCredentialListOutput(input) {
5275
4505
  return [
5276
4506
  "SiteOS Forms credentials.",
@@ -5281,15 +4511,6 @@ function formatCredentialListOutput(input) {
5281
4511
  )
5282
4512
  ].join("\n");
5283
4513
  }
5284
- function formatEnvironmentListOutput(environments) {
5285
- return [
5286
- "SiteOS Forms Environments.",
5287
- `Environments: ${environments.length}`,
5288
- ...environments.map(
5289
- (environment) => `- ${environment.slug}: ${environment.name} (${environment.id})`
5290
- )
5291
- ].join("\n");
5292
- }
5293
4514
  function requireEnvironmentProjectConvergence(environments, projectId) {
5294
4515
  if (environments.some((environment) => environment.projectId !== projectId)) {
5295
4516
  throw new SiteOSFormsApiError({
@@ -5322,12 +4543,12 @@ function readOutputString(value) {
5322
4543
  }
5323
4544
  function createFormsUiOutput(input) {
5324
4545
  const commonProjectId = input.context.commonProjectId;
5325
- const projectId = commonProjectId ?? input.context.project.id;
4546
+ const projectId = commonProjectId;
5326
4547
  if (!projectId) {
5327
4548
  return void 0;
5328
4549
  }
5329
4550
  const url = new URL(
5330
- commonProjectId ? `/projects/${encodeURIComponent(commonProjectId)}/forms` : `/forms/projects/${encodeURIComponent(projectId)}`,
4551
+ `/projects/${encodeURIComponent(commonProjectId)}/forms?env=${encodeURIComponent(input.context.environmentSlug)}`,
5331
4552
  new URL(input.context.apiBaseUrl).origin
5332
4553
  ).toString();
5333
4554
  return {
@@ -5386,11 +4607,11 @@ async function runDeployment(options) {
5386
4607
 
5387
4608
  // src/package-metadata.ts
5388
4609
  import { readFileSync } from "fs";
5389
- import path13 from "path";
4610
+ import path11 from "path";
5390
4611
  import { fileURLToPath } from "url";
5391
4612
  function readPackageMetadata() {
5392
- const packageJsonPath = path13.resolve(
5393
- path13.dirname(fileURLToPath(import.meta.url)),
4613
+ const packageJsonPath = path11.resolve(
4614
+ path11.dirname(fileURLToPath(import.meta.url)),
5394
4615
  "..",
5395
4616
  "package.json"
5396
4617
  );
@@ -5404,7 +4625,7 @@ function readPackageMetadata() {
5404
4625
  }
5405
4626
 
5406
4627
  // src/pulse-command.ts
5407
- import path25 from "path";
4628
+ import path22 from "path";
5408
4629
  import { parseArgs } from "util";
5409
4630
 
5410
4631
  // src/core/errors.ts
@@ -5417,29 +4638,28 @@ function commandError2(input) {
5417
4638
 
5418
4639
  // src/pulse/api-client.ts
5419
4640
  import { readFile as readFile6 } from "fs/promises";
5420
- import { z as z11 } from "zod";
5421
- var projectSchema = z11.object({
5422
- baseUrl: z11.string().url().nullable(),
5423
- checkCount: z11.number().int().min(0),
5424
- id: z11.string().trim().min(1).max(120),
5425
- name: z11.string().trim().min(1).max(120),
5426
- slug: z11.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
4641
+ import { z as z9 } from "zod";
4642
+ var projectSchema = z9.object({
4643
+ baseUrl: z9.string().url().nullable(),
4644
+ checkCount: z9.number().int().min(0),
4645
+ id: z9.string().trim().min(1).max(120),
4646
+ name: z9.string().trim().min(1).max(120),
4647
+ slug: z9.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
5427
4648
  }).strict();
5428
- var projectListSchema = z11.object({ projects: z11.array(projectSchema) }).strict();
5429
- var projectResponseSchema = z11.object({ project: projectSchema }).strict();
5430
- var deploymentResponseSchema2 = z11.object({
5431
- checks: z11.array(
5432
- z11.object({
5433
- checkId: z11.string().min(1),
5434
- created: z11.boolean(),
5435
- deploymentId: z11.string().min(1),
5436
- slug: z11.string().min(1),
5437
- version: z11.number().int().positive()
4649
+ var projectResponseSchema = z9.object({ project: projectSchema }).strict();
4650
+ var deploymentResponseSchema2 = z9.object({
4651
+ checks: z9.array(
4652
+ z9.object({
4653
+ checkId: z9.string().min(1),
4654
+ created: z9.boolean(),
4655
+ deploymentId: z9.string().min(1),
4656
+ slug: z9.string().min(1),
4657
+ version: z9.number().int().positive()
5438
4658
  }).strict()
5439
4659
  ),
5440
- checksum: z11.string().min(1),
5441
- dashboardUrl: z11.string().url().optional(),
5442
- projectId: z11.string().min(1)
4660
+ checksum: z9.string().min(1),
4661
+ dashboardUrl: z9.string().url().nullable().optional(),
4662
+ projectId: z9.string().min(1)
5443
4663
  }).strict();
5444
4664
  function createPulseApiClient(input) {
5445
4665
  const fetchImpl = input.fetchImpl ?? fetch;
@@ -5461,7 +4681,7 @@ function createPulseApiClient(input) {
5461
4681
  "API_UNREACHABLE",
5462
4682
  `Could not reach ${endpoint.origin}.`,
5463
4683
  {
5464
- hint: "Check SITEOS_PULSE_API_URL and the network connection."
4684
+ hint: "Check SITEOS_AUTH_BASE_URL and the network connection."
5465
4685
  }
5466
4686
  );
5467
4687
  }
@@ -5477,21 +4697,6 @@ function createPulseApiClient(input) {
5477
4697
  return parsed.data;
5478
4698
  };
5479
4699
  return {
5480
- async createProject(options) {
5481
- const result = await request({
5482
- body: JSON.stringify({
5483
- baseUrl: options.baseUrl,
5484
- monitoringEnabled: options.monitoringEnabled,
5485
- name: options.name,
5486
- slug: options.slug
5487
- }),
5488
- grant: options.grant,
5489
- method: "POST",
5490
- path: "/api/cli/v1/projects",
5491
- schema: projectResponseSchema
5492
- });
5493
- return result.project;
5494
- },
5495
4700
  async getProject(options) {
5496
4701
  const result = await request({
5497
4702
  grant: options.grant,
@@ -5500,14 +4705,6 @@ function createPulseApiClient(input) {
5500
4705
  });
5501
4706
  return result.project;
5502
4707
  },
5503
- async listProjects(options) {
5504
- const result = await request({
5505
- grant: options.grant,
5506
- path: "/api/cli/v1/projects",
5507
- schema: projectListSchema
5508
- });
5509
- return result.projects;
5510
- },
5511
4708
  async uploadDeployment(options) {
5512
4709
  const form = new FormData();
5513
4710
  const { archivePath: _archivePath, ...publicManifest } = options.manifest;
@@ -5545,122 +4742,23 @@ function pulseApiError(body, status) {
5545
4742
  return new CliError(code, message);
5546
4743
  }
5547
4744
 
5548
- // src/pulse/binding-migration.ts
5549
- import { createHash as createHash5 } from "crypto";
5550
- import { lstat as lstat5, readFile as readFile7, realpath as realpath3 } from "fs/promises";
5551
- import os4 from "os";
5552
- import path14 from "path";
5553
- import { z as z12 } from "zod";
5554
-
5555
- // src/pulse/constants.ts
5556
- var DEFAULT_SITEOS_PULSE_API_URL = "https://app.siteos.sh";
5557
- function normalizeApiUrl(value) {
5558
- let url;
5559
- try {
5560
- url = new URL(value);
5561
- } catch {
5562
- throw new Error(
5563
- "SiteOS Pulse API URL must be an absolute HTTP or HTTPS URL."
5564
- );
5565
- }
5566
- if (url.protocol !== "https:" && url.protocol !== "http:") {
5567
- throw new Error("SiteOS Pulse API URL must use HTTP or HTTPS.");
5568
- }
5569
- return url.origin;
5570
- }
5571
-
5572
- // src/pulse/binding-migration.ts
5573
- var legacyBindingSchema = z12.object({
5574
- apiUrl: z12.string().url(),
5575
- organizationId: z12.string().trim().min(1).max(255),
5576
- projectId: z12.string().trim().min(1).max(255),
5577
- projectRoot: z12.string().refine(path14.isAbsolute),
5578
- projectSlug: z12.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
5579
- }).strict();
5580
- var legacyBindingsSchema = z12.object({
5581
- bindings: z12.record(legacyBindingSchema),
5582
- version: z12.literal(2)
5583
- }).strict();
5584
- async function migrateLegacyPulseBinding(input) {
5585
- const apiOrigin = normalizeApiUrl(input.apiOrigin);
5586
- const repositoryRoot = await realpath3(path14.resolve(input.repositoryRoot));
5587
- const locator = { apiOrigin, repositoryRoot, service: "pulse" };
5588
- const current = await input.projectBindingStore.read(locator);
5589
- if (current) return { binding: current, status: "already-current" };
5590
- const legacy = await readLegacyBindings(
5591
- input.legacyBindingsPath ?? legacyPulseBindingsFilePath()
5592
- );
5593
- if (!legacy) return { binding: null, status: "not-found" };
5594
- const key = legacyBindingKey(apiOrigin, repositoryRoot);
5595
- const candidate = legacy.bindings[key];
5596
- if (!candidate || candidate.apiUrl !== apiOrigin || candidate.projectRoot !== repositoryRoot || candidate.organizationId !== input.organizationId || candidate.projectSlug !== input.projectSlug) {
5597
- return { binding: null, status: "not-found" };
5598
- }
5599
- const imported = await input.projectBindingStore.write({
5600
- ...locator,
5601
- organizationId: candidate.organizationId,
5602
- project: { id: candidate.projectId, slug: candidate.projectSlug }
5603
- });
5604
- const readBack = await input.projectBindingStore.read(locator);
5605
- if (!readBack || readBack.project.id !== imported.project.id) {
5606
- throw new CliError(
5607
- "PROJECT_BINDING_MIGRATION_FAILED",
5608
- "The migrated Pulse Project binding could not be verified."
5609
- );
5610
- }
5611
- return { binding: readBack, status: "imported" };
5612
- }
5613
- function legacyPulseBindingsFilePath(input = {}) {
5614
- const env = input.env ?? process.env;
5615
- const configRoot = env.XDG_CONFIG_HOME ? path14.resolve(env.XDG_CONFIG_HOME) : path14.join(input.homeDir ?? os4.homedir(), ".config");
5616
- return path14.join(configRoot, "siteos", "pulse", "project-bindings.json");
5617
- }
5618
- async function readLegacyBindings(filePath) {
5619
- try {
5620
- const stats = await lstat5(filePath);
5621
- if (stats.isSymbolicLink() || !stats.isFile())
5622
- throw new Error("unsafe file");
5623
- const parsed = legacyBindingsSchema.parse(
5624
- JSON.parse(await readFile7(filePath, "utf8"))
5625
- );
5626
- for (const [key, binding] of Object.entries(parsed.bindings)) {
5627
- if (key !== legacyBindingKey(normalizeApiUrl(binding.apiUrl), binding.projectRoot)) {
5628
- throw new Error("binding key mismatch");
5629
- }
5630
- }
5631
- return parsed;
5632
- } catch (error) {
5633
- if (error.code === "ENOENT") return null;
5634
- throw new CliError(
5635
- "PROJECT_BINDINGS_INVALID",
5636
- "The legacy Pulse Project bindings could not be read safely.",
5637
- {
5638
- hint: "Remove the legacy binding file, then run `siteos pulse project use <slug>`."
5639
- }
5640
- );
5641
- }
5642
- }
5643
- function legacyBindingKey(apiUrl, projectRoot) {
5644
- return createHash5("sha256").update(`${apiUrl}\0${projectRoot}`).digest("hex");
5645
- }
5646
-
5647
4745
  // src/pulse/bundle.ts
5648
- import { createHash as createHash7, randomUUID as randomUUID4 } from "crypto";
4746
+ import { createHash as createHash6, randomUUID as randomUUID4 } from "crypto";
5649
4747
  import {
5650
4748
  access,
5651
4749
  mkdir as mkdir3,
5652
- readFile as readFile9,
4750
+ readFile as readFile8,
5653
4751
  rename as rename5,
5654
4752
  rm as rm4,
5655
4753
  writeFile as writeFile5
5656
4754
  } from "fs/promises";
5657
- import path16 from "path";
4755
+ import path13 from "path";
5658
4756
  import * as tar from "tar";
5659
4757
 
5660
4758
  // src/pulse/project-files.ts
5661
- import { createHash as createHash6 } from "crypto";
5662
- import { lstat as lstat6, readFile as readFile8 } from "fs/promises";
5663
- import path15 from "path";
4759
+ import { createHash as createHash5 } from "crypto";
4760
+ import { lstat as lstat5, readFile as readFile7 } from "fs/promises";
4761
+ import path12 from "path";
5664
4762
  import fg from "fast-glob";
5665
4763
  var MAX_BUNDLE_FILES = 5e3;
5666
4764
  var MAX_BUNDLE_BYTES = 50 * 1024 * 1024;
@@ -5683,7 +4781,7 @@ function isSensitive(relativePath) {
5683
4781
  return SENSITIVE_FILES.some((pattern) => pattern.test(segments.at(-1) ?? ""));
5684
4782
  }
5685
4783
  async function hashFile(filePath) {
5686
- return createHash6("sha256").update(await readFile8(filePath)).digest("hex");
4784
+ return createHash5("sha256").update(await readFile7(filePath)).digest("hex");
5687
4785
  }
5688
4786
  async function discoverProjectFiles(projectRoot, config) {
5689
4787
  const errors = [];
@@ -5756,13 +4854,13 @@ async function discoverProjectFiles(projectRoot, config) {
5756
4854
  errors.push(`Sensitive path cannot be included: ${relativePath}`);
5757
4855
  continue;
5758
4856
  }
5759
- const absolutePath = path15.resolve(projectRoot, relativePath);
5760
- const relativeToRoot = path15.relative(projectRoot, absolutePath);
5761
- if (relativeToRoot.startsWith("..") || path15.isAbsolute(relativeToRoot)) {
4857
+ const absolutePath = path12.resolve(projectRoot, relativePath);
4858
+ const relativeToRoot = path12.relative(projectRoot, absolutePath);
4859
+ if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
5762
4860
  errors.push(`Included path escapes the project root: ${relativePath}`);
5763
4861
  continue;
5764
4862
  }
5765
- const stats = await lstat6(absolutePath);
4863
+ const stats = await lstat5(absolutePath);
5766
4864
  if (!stats.isFile()) continue;
5767
4865
  if (stats.size > MAX_FILE_BYTES) {
5768
4866
  errors.push(`File exceeds the 10 MiB limit: ${relativePath}`);
@@ -5778,8 +4876,8 @@ async function discoverProjectFiles(projectRoot, config) {
5778
4876
  if (totalBytes > MAX_BUNDLE_BYTES)
5779
4877
  errors.push("The bundle exceeds the 50 MiB size limit.");
5780
4878
  try {
5781
- const packageSource = await readFile8(
5782
- path15.join(projectRoot, "package.json"),
4879
+ const packageSource = await readFile7(
4880
+ path12.join(projectRoot, "package.json"),
5783
4881
  "utf8"
5784
4882
  );
5785
4883
  const packageJson = JSON.parse(packageSource);
@@ -5801,10 +4899,10 @@ async function discoverProjectFiles(projectRoot, config) {
5801
4899
 
5802
4900
  // src/pulse/bundle.ts
5803
4901
  async function hashArchive(archivePath) {
5804
- return createHash7("sha256").update(await readFile9(archivePath)).digest("hex");
4902
+ return createHash6("sha256").update(await readFile8(archivePath)).digest("hex");
5805
4903
  }
5806
4904
  async function createDeploymentBundle(input) {
5807
- const projectRoot = path16.resolve(input.projectRoot);
4905
+ const projectRoot = path13.resolve(input.projectRoot);
5808
4906
  const config = await loadChecksConfig(projectRoot);
5809
4907
  const configFile = await findChecksConfigFile(projectRoot) ?? CONFIG_FILE;
5810
4908
  const report = await discoverProjectFiles(projectRoot, config);
@@ -5817,9 +4915,9 @@ async function createDeploymentBundle(input) {
5817
4915
  }
5818
4916
  );
5819
4917
  }
5820
- const outputDirectory = input.output ? path16.dirname(path16.resolve(projectRoot, input.output)) : path16.join(projectRoot, ".siteos", "pulse", "deployments");
4918
+ const outputDirectory = input.output ? path13.dirname(path13.resolve(projectRoot, input.output)) : path13.join(projectRoot, ".siteos", "pulse", "deployments");
5821
4919
  await mkdir3(outputDirectory, { recursive: true });
5822
- const temporaryPath = path16.join(
4920
+ const temporaryPath = path13.join(
5823
4921
  outputDirectory,
5824
4922
  `.siteos-pulse-${randomUUID4()}.tgz`
5825
4923
  );
@@ -5838,7 +4936,7 @@ async function createDeploymentBundle(input) {
5838
4936
  archiveFiles
5839
4937
  );
5840
4938
  const checksum2 = await hashArchive(temporaryPath);
5841
- const archivePath = input.output ? path16.resolve(projectRoot, input.output) : path16.join(outputDirectory, `siteos-pulse-${checksum2.slice(0, 16)}.tgz`);
4939
+ const archivePath = input.output ? path13.resolve(projectRoot, input.output) : path13.join(outputDirectory, `siteos-pulse-${checksum2.slice(0, 16)}.tgz`);
5842
4940
  try {
5843
4941
  await access(archivePath);
5844
4942
  if (input.output) {
@@ -5878,13 +4976,13 @@ async function createDeploymentBundle(input) {
5878
4976
  }
5879
4977
 
5880
4978
  // src/pulse/init.ts
5881
- import { mkdir as mkdir4, readFile as readFile10, writeFile as writeFile6 } from "fs/promises";
5882
- import path17 from "path";
4979
+ import { mkdir as mkdir4, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
4980
+ import path14 from "path";
5883
4981
  var SITEOS_PLAYWRIGHT_CONFIG = "siteos.playwright.config.ts";
5884
4982
  var PULSE_CACHE_DIRECTORY = ".siteos/pulse/";
5885
4983
  async function exists(filePath) {
5886
4984
  try {
5887
- await readFile10(filePath);
4985
+ await readFile9(filePath);
5888
4986
  return true;
5889
4987
  } catch (error) {
5890
4988
  if (error.code === "ENOENT") return false;
@@ -5919,7 +5017,7 @@ export default defineConfig({
5919
5017
  `;
5920
5018
  }
5921
5019
  async function createPulsePlaywrightConfig(input) {
5922
- const configPath = path17.join(input.projectRoot, SITEOS_PLAYWRIGHT_CONFIG);
5020
+ const configPath = path14.join(input.projectRoot, SITEOS_PLAYWRIGHT_CONFIG);
5923
5021
  if (await exists(configPath)) {
5924
5022
  throw new CliError(
5925
5023
  "PULSE_PLAYWRIGHT_CONFIG_EXISTS",
@@ -5936,21 +5034,21 @@ async function createPulsePlaywrightConfig(input) {
5936
5034
  }
5937
5035
  async function detectPackageName(projectRoot) {
5938
5036
  try {
5939
- const contents = await readFile10(
5940
- path17.join(projectRoot, "package.json"),
5037
+ const contents = await readFile9(
5038
+ path14.join(projectRoot, "package.json"),
5941
5039
  "utf8"
5942
5040
  );
5943
5041
  const parsed = JSON.parse(contents);
5944
- return typeof parsed.name === "string" ? parsed.name : path17.basename(projectRoot);
5042
+ return typeof parsed.name === "string" ? parsed.name : path14.basename(projectRoot);
5945
5043
  } catch {
5946
- return path17.basename(projectRoot);
5044
+ return path14.basename(projectRoot);
5947
5045
  }
5948
5046
  }
5949
5047
  async function ensureGitignore(projectRoot) {
5950
- const gitignorePath = path17.join(projectRoot, ".gitignore");
5048
+ const gitignorePath = path14.join(projectRoot, ".gitignore");
5951
5049
  let contents = "";
5952
5050
  try {
5953
- contents = await readFile10(gitignorePath, "utf8");
5051
+ contents = await readFile9(gitignorePath, "utf8");
5954
5052
  } catch (error) {
5955
5053
  if (error.code !== "ENOENT") throw error;
5956
5054
  }
@@ -5965,21 +5063,21 @@ async function ensureGitignore(projectRoot) {
5965
5063
  return true;
5966
5064
  }
5967
5065
  async function initializeProject(input) {
5968
- const projectRoot = path17.resolve(input.projectRoot);
5066
+ const projectRoot = path14.resolve(input.projectRoot);
5969
5067
  const existingConfig = await findChecksConfigFile(projectRoot);
5970
5068
  if (existingConfig) {
5971
5069
  throw new CliError("CONFIG_EXISTS", `${existingConfig} already exists.`, {
5972
5070
  hint: "Edit the existing file or run `siteos pulse validate`."
5973
5071
  });
5974
5072
  }
5975
- const configPath = path17.join(projectRoot, CONFIG_FILE);
5073
+ const configPath = path14.join(projectRoot, CONFIG_FILE);
5976
5074
  const created = [];
5977
5075
  const updated = [];
5978
5076
  const testsDir = input.testsDir ?? "tests/siteos";
5979
5077
  const packageName2 = await detectPackageName(projectRoot);
5980
5078
  const projectName = projectDisplayName(input.project ?? packageName2);
5981
5079
  const checkSlug = projectSlug(input.suite ?? "homepage");
5982
- const exampleTest = path17.posix.join(
5080
+ const exampleTest = path14.posix.join(
5983
5081
  testsDir.replaceAll("\\", "/"),
5984
5082
  `${checkSlug}.spec.ts`
5985
5083
  );
@@ -5992,7 +5090,6 @@ async function initializeProject(input) {
5992
5090
  monitoringEnabled: true
5993
5091
  },
5994
5092
  testsDir,
5995
- apiUrl: DEFAULT_SITEOS_PULSE_API_URL,
5996
5093
  playwrightConfig: SITEOS_PLAYWRIGHT_CONFIG,
5997
5094
  checks: [
5998
5095
  {
@@ -6017,11 +5114,11 @@ async function initializeProject(input) {
6017
5114
  baseUrl: input.baseUrl
6018
5115
  });
6019
5116
  created.push(SITEOS_PLAYWRIGHT_CONFIG);
6020
- const testDirectory = path17.join(projectRoot, testsDir);
5117
+ const testDirectory = path14.join(projectRoot, testsDir);
6021
5118
  await mkdir4(testDirectory, { recursive: true });
6022
- if (!await exists(path17.join(projectRoot, exampleTest))) {
5119
+ if (!await exists(path14.join(projectRoot, exampleTest))) {
6023
5120
  await writeFile6(
6024
- path17.join(projectRoot, exampleTest),
5121
+ path14.join(projectRoot, exampleTest),
6025
5122
  `import { expect, test } from "@playwright/test";
6026
5123
 
6027
5124
  test(${JSON.stringify(`${projectDisplayName(input.suite ?? "homepage")} is reachable`)}, async ({ page }) => {
@@ -6047,14 +5144,14 @@ test(${JSON.stringify(`${projectDisplayName(input.suite ?? "homepage")} is reach
6047
5144
  import fg4 from "fast-glob";
6048
5145
 
6049
5146
  // src/pulse/interactive/discovery.ts
6050
- import { readFile as readFile12 } from "fs/promises";
5147
+ import { readFile as readFile11 } from "fs/promises";
6051
5148
  import { createRequire } from "module";
6052
- import path19 from "path";
5149
+ import path16 from "path";
6053
5150
  import fg2 from "fast-glob";
6054
5151
 
6055
5152
  // src/pulse/interactive/playwright-config.ts
6056
- import { readFile as readFile11 } from "fs/promises";
6057
- import path18 from "path";
5153
+ import { readFile as readFile10 } from "fs/promises";
5154
+ import path15 from "path";
6058
5155
 
6059
5156
  // src/pulse/interactive/discovery.ts
6060
5157
  var PLAYWRIGHT_SPEC_PATTERN = "**/*.{spec,test}.{js,cjs,mjs,ts,cts,mts,jsx,tsx}";
@@ -6099,11 +5196,11 @@ async function discoverPlaywrightSelectorMatches(projectRoot, selectors, testsDi
6099
5196
  }
6100
5197
 
6101
5198
  // src/pulse/sync-plan.ts
6102
- import path20 from "path";
5199
+ import path17 from "path";
6103
5200
  import fg3 from "fast-glob";
6104
5201
  var PLAYWRIGHT_SPEC_FILE = /\.(?:spec|test)\.(?:[cm]?[jt]sx?)$/;
6105
5202
  function defaultNameFromSpec(specPath) {
6106
- const basename = path20.posix.basename(specPath).replace(/\.(?:spec|test)\.[^.]+$/, "");
5203
+ const basename = path17.posix.basename(specPath).replace(/\.(?:spec|test)\.[^.]+$/, "");
6107
5204
  return basename.split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ") || "Smoke";
6108
5205
  }
6109
5206
  function normalizedPaths(paths) {
@@ -6161,8 +5258,8 @@ function buildSyncPlan(input) {
6161
5258
 
6162
5259
  // src/pulse/test-imports.ts
6163
5260
  import { builtinModules } from "module";
6164
- import { readFile as readFile13 } from "fs/promises";
6165
- import path21 from "path";
5261
+ import { readFile as readFile12 } from "fs/promises";
5262
+ import path18 from "path";
6166
5263
  import { build } from "esbuild";
6167
5264
  var ALLOWED_PACKAGES = /* @__PURE__ */ new Set(["@playwright/test"]);
6168
5265
  var BUILTINS = /* @__PURE__ */ new Set([
@@ -6176,9 +5273,9 @@ function packageName(importPath) {
6176
5273
  return importPath.split("/")[0] ?? importPath;
6177
5274
  }
6178
5275
  function normalizedRelativePath(projectRoot, inputPath) {
6179
- const absolute = path21.isAbsolute(inputPath) ? inputPath : path21.resolve(projectRoot, inputPath);
6180
- const relative = path21.relative(projectRoot, absolute).replaceAll("\\", "/");
6181
- if (!relative || relative.startsWith("../") || path21.isAbsolute(relative)) {
5276
+ const absolute = path18.isAbsolute(inputPath) ? inputPath : path18.resolve(projectRoot, inputPath);
5277
+ const relative = path18.relative(projectRoot, absolute).replaceAll("\\", "/");
5278
+ if (!relative || relative.startsWith("../") || path18.isAbsolute(relative)) {
6182
5279
  throw new CliError(
6183
5280
  "IMPORT_OUTSIDE_PROJECT",
6184
5281
  `A selected test imports outside the project: ${inputPath}`
@@ -6187,7 +5284,7 @@ function normalizedRelativePath(projectRoot, inputPath) {
6187
5284
  return relative;
6188
5285
  }
6189
5286
  async function analyzeTestImports(input) {
6190
- const projectRoot = path21.resolve(input.projectRoot);
5287
+ const projectRoot = path18.resolve(input.projectRoot);
6191
5288
  const entryFiles = [
6192
5289
  ...new Set(
6193
5290
  input.entryFiles.map((file) => normalizedRelativePath(projectRoot, file))
@@ -6246,7 +5343,7 @@ async function analyzeTestImports(input) {
6246
5343
  const compatibilityIssues = /* @__PURE__ */ new Set();
6247
5344
  await Promise.all(
6248
5345
  inputs.map(async (file) => {
6249
- const source = await readFile13(path21.join(projectRoot, file), "utf8").catch(
5346
+ const source = await readFile12(path18.join(projectRoot, file), "utf8").catch(
6250
5347
  () => ""
6251
5348
  );
6252
5349
  for (const match of source.matchAll(ENVIRONMENT_PATTERN)) {
@@ -6689,12 +5786,12 @@ async function runSyncCli(input) {
6689
5786
  // src/pulse/playwright.ts
6690
5787
  import { spawn as spawn3 } from "child_process";
6691
5788
  import { createRequire as createRequire2 } from "module";
6692
- import path23 from "path";
5789
+ import path20 from "path";
6693
5790
 
6694
5791
  // src/pulse/package-manager.ts
6695
5792
  import { spawn as spawn2 } from "child_process";
6696
- import { access as access2, readFile as readFile14 } from "fs/promises";
6697
- import path22 from "path";
5793
+ import { access as access2, readFile as readFile13 } from "fs/promises";
5794
+ import path19 from "path";
6698
5795
  var LOCKFILES = [
6699
5796
  { packageManager: "pnpm", filenames: ["pnpm-lock.yaml"] },
6700
5797
  { packageManager: "yarn", filenames: ["yarn.lock"] },
@@ -6716,7 +5813,7 @@ async function fileExists2(filePath) {
6716
5813
  async function declaredPackageManager(projectRoot) {
6717
5814
  let contents;
6718
5815
  try {
6719
- contents = await readFile14(path22.join(projectRoot, "package.json"), "utf8");
5816
+ contents = await readFile13(path19.join(projectRoot, "package.json"), "utf8");
6720
5817
  } catch (error) {
6721
5818
  if (error.code === "ENOENT") return null;
6722
5819
  throw error;
@@ -6753,7 +5850,7 @@ async function declaredPackageManager(projectRoot) {
6753
5850
  );
6754
5851
  }
6755
5852
  async function detectPackageManager(projectRoot) {
6756
- const root = path22.resolve(projectRoot);
5853
+ const root = path19.resolve(projectRoot);
6757
5854
  const declared = await declaredPackageManager(root);
6758
5855
  if (declared) return declared;
6759
5856
  const matches = (await Promise.all(
@@ -6762,7 +5859,7 @@ async function detectPackageManager(projectRoot) {
6762
5859
  filenames: (await Promise.all(
6763
5860
  filenames2.map(async (filename) => ({
6764
5861
  filename,
6765
- exists: await fileExists2(path22.join(root, filename))
5862
+ exists: await fileExists2(path19.join(root, filename))
6766
5863
  }))
6767
5864
  )).filter((entry) => entry.exists).map((entry) => entry.filename)
6768
5865
  }))
@@ -6823,12 +5920,12 @@ function isMissingBrowserDiagnostic(output) {
6823
5920
  function resolvePlaywrightCli(projectRoot) {
6824
5921
  try {
6825
5922
  const requireFromProject = createRequire2(
6826
- path23.join(projectRoot, "package.json")
5923
+ path20.join(projectRoot, "package.json")
6827
5924
  );
6828
5925
  const packageJson = requireFromProject.resolve(
6829
5926
  "@playwright/test/package.json"
6830
5927
  );
6831
- return path23.join(path23.dirname(packageJson), "cli.js");
5928
+ return path20.join(path20.dirname(packageJson), "cli.js");
6832
5929
  } catch {
6833
5930
  throw new CliError(
6834
5931
  "PLAYWRIGHT_NOT_INSTALLED",
@@ -6840,7 +5937,7 @@ function resolvePlaywrightCli(projectRoot) {
6840
5937
  }
6841
5938
  }
6842
5939
  async function runProjectTests(input) {
6843
- const projectRoot = path23.resolve(input.projectRoot);
5940
+ const projectRoot = path20.resolve(input.projectRoot);
6844
5941
  const config = await loadChecksConfig(projectRoot);
6845
5942
  const report = await discoverProjectFiles(projectRoot, config);
6846
5943
  if (!report.valid) {
@@ -6897,9 +5994,9 @@ async function runProjectTests(input) {
6897
5994
  }
6898
5995
 
6899
5996
  // src/pulse/validate.ts
6900
- import path24 from "path";
5997
+ import path21 from "path";
6901
5998
  async function validateProject(projectRoot) {
6902
- const root = path24.resolve(projectRoot);
5999
+ const root = path21.resolve(projectRoot);
6903
6000
  const config = await loadChecksConfig(root);
6904
6001
  return discoverProjectFiles(root, config);
6905
6002
  }
@@ -6908,10 +6005,6 @@ async function validateProject(projectRoot) {
6908
6005
  var HELP_FLAGS3 = /* @__PURE__ */ new Set(["--help", "-h"]);
6909
6006
  var PULSE_SCOPE = "pulse:workspace:write";
6910
6007
  var PULSE_HELP = `Usage:
6911
- siteos pulse project list [--json]
6912
- siteos pulse project create --slug <slug> --name <name> [--json]
6913
- siteos pulse project use <slug> [--replace] [--json]
6914
- siteos pulse project status [--json]
6915
6008
  siteos pulse init [--project <slug>] [--suite <slug>] [--tests-dir <path>] [--base-url <url>]
6916
6009
  siteos pulse validate [--json]
6917
6010
  siteos pulse sync [--check] [--json]
@@ -6925,8 +6018,6 @@ async function runPulseCommand(options) {
6925
6018
  }
6926
6019
  try {
6927
6020
  const [command2, ...args2] = options.args;
6928
- if (command2 === "project")
6929
- return await runProjectCommand2({ ...options, args: args2 });
6930
6021
  if (command2 === "init") return await runInitCommand(options, args2);
6931
6022
  if (command2 === "validate") return await runValidateCommand(options, args2);
6932
6023
  if (command2 === "sync") return await runSyncCommand(options, args2);
@@ -6937,130 +6028,6 @@ async function runPulseCommand(options) {
6937
6028
  return formatPulseError(error, options.args.includes("--json"));
6938
6029
  }
6939
6030
  }
6940
- async function runProjectCommand2(options) {
6941
- const [action, ...args2] = options.args;
6942
- if (!action || !["create", "list", "status", "use"].includes(action)) {
6943
- throw usageError3("Unknown SiteOS Pulse project command.");
6944
- }
6945
- const parsed = parseProjectArguments(action, args2);
6946
- const cwd = options.cwd ?? process.cwd();
6947
- const root = action === "list" ? null : await findRepositoryRoot(cwd);
6948
- const apiOrigin = await resolvePulseApiOrigin({
6949
- cwd: root ?? cwd,
6950
- env: options.env,
6951
- requireConfig: action !== "list"
6952
- });
6953
- const grant = await acquirePulseGrant(options);
6954
- const client = createPulseApiClient({
6955
- apiOrigin,
6956
- fetchImpl: options.fetchImpl
6957
- });
6958
- if (action === "list") {
6959
- const projects = await client.listProjects({ grant: grant.accessToken });
6960
- return success(
6961
- parsed.json,
6962
- { apiOrigin, organizationId: grant.grant.organizationId, projects },
6963
- formatProjectList(projects)
6964
- );
6965
- }
6966
- const repositoryRoot = root;
6967
- const snapshot = await loadChecksConfigSnapshot(repositoryRoot);
6968
- if (action === "create") {
6969
- const baseUrl = snapshot.config.project.baseUrl;
6970
- if (!baseUrl) {
6971
- throw new CliError(
6972
- "PULSE_PROJECT_BASE_URL_REQUIRED",
6973
- "Set project.baseUrl in siteos.config.json before creating the Pulse Project."
6974
- );
6975
- }
6976
- const project = await client.createProject({
6977
- baseUrl,
6978
- grant: grant.accessToken,
6979
- monitoringEnabled: snapshot.config.project.monitoringEnabled,
6980
- name: parsed.name,
6981
- slug: parsed.slug
6982
- });
6983
- return success(
6984
- parsed.json,
6985
- { apiOrigin, project },
6986
- [
6987
- "SiteOS Pulse Project created.",
6988
- `Project: ${project.slug}`,
6989
- `Name: ${project.name}`,
6990
- `Run \`siteos pulse project use ${project.slug}\` to select it for this repository.`
6991
- ].join("\n")
6992
- );
6993
- }
6994
- const store = projectBindingStore2(options);
6995
- const locator = { apiOrigin, repositoryRoot, service: "pulse" };
6996
- if (action === "use") {
6997
- const projects = await client.listProjects({ grant: grant.accessToken });
6998
- const project = uniqueProjectBySlug(projects, parsed.slug);
6999
- const previous = await store.read(locator);
7000
- const replacing = snapshot.config.project.slug !== project.slug || previous !== null && previous.project.id !== project.id;
7001
- if (replacing && !parsed.replace) {
7002
- throw new CliError(
7003
- "PULSE_PROJECT_REFERENCE_CONFLICT",
7004
- "A different Pulse Project is already selected. Use --replace to replace it."
7005
- );
7006
- }
7007
- await store.write({
7008
- ...locator,
7009
- organizationId: grant.grant.organizationId,
7010
- project: { id: project.id, slug: project.slug }
7011
- });
7012
- try {
7013
- await reconcileProjectSlug(repositoryRoot, project.slug, {
7014
- expectedChecksum: snapshot.checksum
7015
- });
7016
- } catch (error) {
7017
- if (previous) await store.write(previous);
7018
- else await store.remove(locator);
7019
- throw error;
7020
- }
7021
- return success(
7022
- parsed.json,
7023
- {
7024
- apiOrigin,
7025
- organizationId: grant.grant.organizationId,
7026
- project,
7027
- referencePath: path25.join(repositoryRoot, CONFIG_FILE)
7028
- },
7029
- [
7030
- "SiteOS Pulse Project selected.",
7031
- `Project: ${project.slug}`,
7032
- `Reference: ${path25.join(repositoryRoot, CONFIG_FILE)}`
7033
- ].join("\n")
7034
- );
7035
- }
7036
- const selected = await requireSelectedProject({
7037
- options,
7038
- apiOrigin,
7039
- client,
7040
- grant,
7041
- legacyBindingsPath: options.legacyBindingsPath,
7042
- projectBindingStore: store,
7043
- projectSlug: snapshot.config.project.slug,
7044
- repositoryRoot
7045
- });
7046
- return success(
7047
- parsed.json,
7048
- {
7049
- apiOrigin,
7050
- connected: true,
7051
- migration: selected.migration,
7052
- organizationId: grant.grant.organizationId,
7053
- project: selected.project,
7054
- repositoryRoot
7055
- },
7056
- [
7057
- "SiteOS Pulse Project connection is valid.",
7058
- `Project: ${selected.project.slug}`,
7059
- `Organization: ${grant.grant.organizationId}`,
7060
- `API: ${apiOrigin}`
7061
- ].join("\n")
7062
- );
7063
- }
7064
6031
  async function runInitCommand(options, args2) {
7065
6032
  const { values } = parseArgs({
7066
6033
  args: args2,
@@ -7179,7 +6146,7 @@ async function runDeployCommand(options, args2) {
7179
6146
  },
7180
6147
  strict: true
7181
6148
  });
7182
- const projectRoot = path25.resolve(options.cwd ?? process.cwd());
6149
+ const projectRoot = path22.resolve(options.cwd ?? process.cwd());
7183
6150
  const repositoryRoot = await findRepositoryRoot(projectRoot);
7184
6151
  const common = await commonServiceContext(options, "pulse");
7185
6152
  if (common && (!common.environmentBinding?.slug || !common.environment.url))
@@ -7203,18 +6170,19 @@ async function runDeployCommand(options, args2) {
7203
6170
  values.json,
7204
6171
  { dryRun: true, manifest },
7205
6172
  [
7206
- `Bundle: ${path25.relative(projectRoot, manifest.archivePath)}`,
6173
+ `Bundle: ${path22.relative(projectRoot, manifest.archivePath)}`,
7207
6174
  `Checksum: ${manifest.checksum}`,
7208
6175
  `Files: ${manifest.fileCount}`,
7209
6176
  "Dry run complete; nothing was uploaded."
7210
6177
  ].join("\n")
7211
6178
  );
7212
6179
  }
7213
- const apiOrigin = await resolvePulseApiOrigin({
7214
- cwd: projectRoot,
7215
- env: options.env,
7216
- requireConfig: true
7217
- });
6180
+ if (!common)
6181
+ throw new CliError(
6182
+ "PROJECT_REQUIRED",
6183
+ "Select a Project with `siteos project use <id-or-slug>` before deploying."
6184
+ );
6185
+ const apiOrigin = common.api.origin;
7218
6186
  const grant = await acquirePulseGrant(options);
7219
6187
  const client = createPulseApiClient({
7220
6188
  apiOrigin,
@@ -7226,8 +6194,6 @@ async function runDeployCommand(options, args2) {
7226
6194
  apiOrigin,
7227
6195
  client,
7228
6196
  grant,
7229
- legacyBindingsPath: options.legacyBindingsPath,
7230
- projectBindingStore: projectBindingStore2(options),
7231
6197
  projectSlug: snapshot.config.project.slug,
7232
6198
  repositoryRoot
7233
6199
  });
@@ -7246,7 +6212,7 @@ async function runDeployCommand(options, args2) {
7246
6212
  values.json,
7247
6213
  { deployment, dryRun: false, manifest },
7248
6214
  [
7249
- `Bundle: ${path25.relative(projectRoot, manifest.archivePath)}`,
6215
+ `Bundle: ${path22.relative(projectRoot, manifest.archivePath)}`,
7250
6216
  `Checksum: ${manifest.checksum}`,
7251
6217
  `Files: ${manifest.fileCount}`,
7252
6218
  `Project ${deployment.projectId} deployed.`,
@@ -7280,124 +6246,22 @@ async function requireSelectedProject(input) {
7280
6246
  "The selected Project and Pulse deployment origin or organization do not match."
7281
6247
  );
7282
6248
  }
7283
- const project2 = await input.client.getProject({
6249
+ const project = await input.client.getProject({
7284
6250
  grant: input.grant.accessToken,
7285
6251
  projectId: common.resourceId
7286
6252
  });
7287
- if (project2.slug !== input.projectSlug && common.overview.project.slug !== input.projectSlug)
6253
+ if (project.slug !== input.projectSlug && common.overview.project.slug !== input.projectSlug)
7288
6254
  throw new CliError(
7289
6255
  "PULSE_PROJECT_BINDING_INVALID",
7290
6256
  `Set project.slug in siteos.config.json to ${common.overview.project.slug} before deploying checks to this Project.`
7291
6257
  );
7292
- return { migration: "not-required", project: project2 };
7293
- }
7294
- const migration = await migrateLegacyPulseBinding({
7295
- apiOrigin: input.apiOrigin,
7296
- legacyBindingsPath: input.legacyBindingsPath,
7297
- organizationId: input.grant.grant.organizationId,
7298
- projectBindingStore: input.projectBindingStore,
7299
- projectSlug: input.projectSlug,
7300
- repositoryRoot: input.repositoryRoot
7301
- });
7302
- const binding = migration.binding;
7303
- if (!binding) {
7304
- throw new CliError(
7305
- "PULSE_PROJECT_BINDING_REQUIRED",
7306
- "Select a Pulse Project for this repository first.",
7307
- { hint: `Run \`siteos pulse project use ${input.projectSlug}\`.` }
7308
- );
7309
- }
7310
- if (binding.organizationId !== input.grant.grant.organizationId || binding.project.slug !== input.projectSlug) {
7311
- throw new CliError(
7312
- "PULSE_PROJECT_BINDING_INVALID",
7313
- "The Pulse Project configuration and private binding do not match.",
7314
- {
7315
- hint: `Run \`siteos pulse project use ${input.projectSlug} --replace\`.`
7316
- }
7317
- );
7318
- }
7319
- const project = await input.client.getProject({
7320
- grant: input.grant.accessToken,
7321
- projectId: binding.project.id
7322
- });
7323
- if (project.slug !== binding.project.slug) {
7324
- throw new CliError(
7325
- "PULSE_PROJECT_BINDING_STALE",
7326
- "The selected Pulse Project is no longer valid.",
7327
- {
7328
- hint: `Run \`siteos pulse project use ${input.projectSlug} --replace\`.`
7329
- }
7330
- );
7331
- }
7332
- return { migration: migration.status, project };
7333
- }
7334
- async function resolvePulseApiOrigin(input) {
7335
- const configured = input.env?.SITEOS_PULSE_API_URL?.trim();
7336
- if (configured) return normalizeApiUrl(configured);
7337
- try {
7338
- const config = await loadChecksConfigFile(input.cwd);
7339
- if (config.apiUrl) return normalizeApiUrl(config.apiUrl);
7340
- } catch (error) {
7341
- if (input.requireConfig || !(error instanceof CliError) || error.code !== "CONFIG_NOT_FOUND") {
7342
- throw error;
7343
- }
6258
+ return { project };
7344
6259
  }
7345
- return DEFAULT_SITEOS_PULSE_API_URL;
7346
- }
7347
- function projectBindingStore2(options) {
7348
- return options.projectBindingStore ?? new NodeProjectBindingStore(
7349
- path25.join(
7350
- resolveSiteOSConfigHome({ env: options.env, homeDir: options.homeDir }),
7351
- "project-bindings.json"
7352
- )
6260
+ throw new CliError(
6261
+ "PROJECT_REQUIRED",
6262
+ "Select a Project with `siteos project use <id-or-slug>` before deploying."
7353
6263
  );
7354
6264
  }
7355
- function parseProjectArguments(action, args2) {
7356
- const { positionals, values } = parseArgs({
7357
- allowPositionals: true,
7358
- args: args2,
7359
- options: {
7360
- json: { default: false, type: "boolean" },
7361
- ...action === "create" ? {
7362
- name: { type: "string" },
7363
- slug: { type: "string" }
7364
- } : {},
7365
- ...action === "use" ? { replace: { default: false, type: "boolean" } } : {}
7366
- },
7367
- strict: true
7368
- });
7369
- if (action === "create" && (!values.slug || !values.name || positionals.length > 0)) {
7370
- throw usageError3(
7371
- "Usage: siteos pulse project create --slug <slug> --name <name> [--json]"
7372
- );
7373
- }
7374
- if (action === "use" && (positionals.length !== 1 || !positionals[0])) {
7375
- throw usageError3(
7376
- "Usage: siteos pulse project use <slug> [--replace] [--json]"
7377
- );
7378
- }
7379
- if ((action === "list" || action === "status") && positionals.length > 0) {
7380
- throw usageError3(
7381
- `siteos pulse project ${action} does not accept positional arguments.`
7382
- );
7383
- }
7384
- return {
7385
- json: Boolean(values.json),
7386
- name: typeof values.name === "string" ? values.name : void 0,
7387
- replace: Boolean(values.replace),
7388
- slug: action === "use" ? positionals[0] : typeof values.slug === "string" ? values.slug : void 0
7389
- };
7390
- }
7391
- function uniqueProjectBySlug(projects, slug2) {
7392
- const matches = projects.filter((project) => project.slug === slug2);
7393
- if (matches.length !== 1) {
7394
- throw new CliError(
7395
- matches.length === 0 ? "PULSE_PROJECT_NOT_FOUND" : "API_INVALID_RESPONSE",
7396
- matches.length === 0 ? "The Pulse Project was not found." : "SiteOS Pulse returned an ambiguous Project list."
7397
- );
7398
- }
7399
- return matches[0];
7400
- }
7401
6265
  function formatValidation(report) {
7402
6266
  return [
7403
6267
  report.valid ? "SiteOS Pulse project is valid." : "SiteOS Pulse project is invalid.",
@@ -7426,15 +6290,6 @@ function formatSyncReport(report) {
7426
6290
  ...report.blockers.map((blocker) => `Blocker: ${blocker.message}`)
7427
6291
  ].join("\n");
7428
6292
  }
7429
- function formatProjectList(projects) {
7430
- return [
7431
- "SiteOS Pulse Projects.",
7432
- `Projects: ${projects.length}`,
7433
- ...projects.map(
7434
- (project) => `- ${project.slug}: ${project.name} (${project.checkCount} Check${project.checkCount === 1 ? "" : "s"})`
7435
- )
7436
- ].join("\n");
7437
- }
7438
6293
  function success(json, value, text) {
7439
6294
  return {
7440
6295
  exitCode: CLI_EXIT_CODE.success,
@@ -7496,92 +6351,64 @@ function exitCodeForPulseError(error) {
7496
6351
  return CLI_EXIT_CODE.internal;
7497
6352
  }
7498
6353
 
7499
- // src/search-command.ts
7500
- import path27 from "path";
7501
-
7502
6354
  // src/siteos-search-api.ts
7503
- import { z as z13 } from "zod";
7504
- var DEFAULT_SITEOS_SEARCH_BASE_URL = "https://app.siteos.sh";
7505
- var SITEOS_SEARCH_BASE_URL_ENV = "SITEOS_SEARCH_PUBLIC_URL";
7506
- var permissiveObjectSchema = z13.record(z13.unknown());
7507
- var environmentSlugSchema = z13.string().min(2).max(30).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
7508
- var searchProjectSchema = z13.object({
7509
- createdAt: z13.string().datetime({ offset: true }),
7510
- id: z13.string().trim().min(1).max(255),
7511
- name: z13.string().trim().min(1).max(255),
7512
- organizationId: z13.string().trim().min(1).max(255),
7513
- slug: z13.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
7514
- updatedAt: z13.string().datetime({ offset: true })
7515
- }).strict();
7516
- var searchProjectListResponseSchema = z13.object({ projects: z13.array(searchProjectSchema), success: z13.literal(true) }).strict();
7517
- var searchProjectResponseSchema = z13.object({ project: searchProjectSchema, success: z13.literal(true) }).strict();
7518
- var searchEnvironmentSchema = z13.object({
7519
- createdAt: z13.string().datetime({ offset: true }),
7520
- id: z13.string().trim().min(1).max(255),
7521
- name: z13.string().trim().min(1).max(255),
7522
- projectId: z13.string().trim().min(1).max(255),
7523
- slug: environmentSlugSchema,
7524
- updatedAt: z13.string().datetime({ offset: true })
7525
- }).strict();
7526
- var searchEnvironmentListResponseSchema = z13.object({
7527
- environments: z13.array(searchEnvironmentSchema),
7528
- success: z13.literal(true)
7529
- }).strict();
7530
- var searchEnvironmentResponseSchema = z13.object({ environment: searchEnvironmentSchema, success: z13.literal(true) }).passthrough();
7531
- var searchCredentialMetadataSchema = z13.object({
7532
- createdAt: z13.string().datetime({ offset: true }),
7533
- id: z13.string().trim().min(1).max(255),
7534
- lastUsedAt: z13.string().datetime({ offset: true }).nullable(),
7535
- name: z13.string().trim().min(1).max(255),
7536
- projectEnvironmentId: z13.string().trim().min(1).max(255),
7537
- revokedAt: z13.string().datetime({ offset: true }).nullable(),
7538
- status: z13.enum(["active", "revoked"])
6355
+ import { z as z10 } from "zod";
6356
+ var permissiveObjectSchema = z10.record(z10.unknown());
6357
+ var environmentSlugSchema = z10.string().min(2).max(30).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
6358
+ var searchCredentialMetadataSchema = z10.object({
6359
+ createdAt: z10.string().datetime({ offset: true }),
6360
+ id: z10.string().trim().min(1).max(255),
6361
+ lastUsedAt: z10.string().datetime({ offset: true }).nullable(),
6362
+ name: z10.string().trim().min(1).max(255),
6363
+ projectEnvironmentId: z10.string().trim().min(1).max(255),
6364
+ revokedAt: z10.string().datetime({ offset: true }).nullable(),
6365
+ status: z10.enum(["active", "revoked"])
7539
6366
  }).strict();
7540
- var searchCredentialListResponseSchema = z13.object({
6367
+ var searchCredentialListResponseSchema = z10.object({
7541
6368
  environmentSlug: environmentSlugSchema,
7542
- success: z13.literal(true),
7543
- tokens: z13.array(searchCredentialMetadataSchema)
6369
+ success: z10.literal(true),
6370
+ tokens: z10.array(searchCredentialMetadataSchema)
7544
6371
  }).strict();
7545
- var searchCredentialExchangeResponseSchema = z13.object({
6372
+ var searchCredentialExchangeResponseSchema = z10.object({
7546
6373
  environmentSlug: environmentSlugSchema,
7547
- success: z13.literal(true),
6374
+ success: z10.literal(true),
7548
6375
  token: searchCredentialMetadataSchema.extend({
7549
- token: z13.string().regex(/^psq_[A-Za-z0-9_-]{22}$/)
6376
+ token: z10.string().regex(/^psq_[A-Za-z0-9_-]{22}$/)
7550
6377
  })
7551
6378
  }).strict();
7552
- var searchCredentialRevokeResponseSchema = z13.object({
6379
+ var searchCredentialRevokeResponseSchema = z10.object({
7553
6380
  environmentSlug: environmentSlugSchema,
7554
- success: z13.literal(true),
6381
+ success: z10.literal(true),
7555
6382
  token: searchCredentialMetadataSchema
7556
6383
  }).strict();
7557
- var searchIndexingCredentialListResponseSchema = z13.object({
7558
- credentials: z13.array(searchCredentialMetadataSchema),
6384
+ var searchIndexingCredentialListResponseSchema = z10.object({
6385
+ credentials: z10.array(searchCredentialMetadataSchema),
7559
6386
  environmentSlug: environmentSlugSchema,
7560
- success: z13.literal(true)
6387
+ success: z10.literal(true)
7561
6388
  }).strict();
7562
- var searchIndexingCredentialExchangeResponseSchema = z13.object({
6389
+ var searchIndexingCredentialExchangeResponseSchema = z10.object({
7563
6390
  credential: searchCredentialMetadataSchema.extend({
7564
- credential: z13.string().regex(/^psi_[A-Za-z0-9_-]{22}$/)
6391
+ credential: z10.string().regex(/^psi_[A-Za-z0-9_-]{22}$/)
7565
6392
  }).strict(),
7566
6393
  environmentSlug: environmentSlugSchema,
7567
- success: z13.literal(true)
6394
+ success: z10.literal(true)
7568
6395
  }).strict();
7569
- var searchIndexingCredentialRevokeResponseSchema = z13.object({
6396
+ var searchIndexingCredentialRevokeResponseSchema = z10.object({
7570
6397
  credential: searchCredentialMetadataSchema,
7571
6398
  environmentSlug: environmentSlugSchema,
7572
- success: z13.literal(true)
6399
+ success: z10.literal(true)
7573
6400
  }).strict();
7574
- var nestedApiErrorResponseSchema = z13.object({
7575
- error: z13.object({
7576
- code: z13.string().trim().min(1).optional(),
7577
- message: z13.string().trim().min(1),
7578
- nextActions: z13.array(z13.string()).optional()
6401
+ var nestedApiErrorResponseSchema = z10.object({
6402
+ error: z10.object({
6403
+ code: z10.string().trim().min(1).optional(),
6404
+ message: z10.string().trim().min(1),
6405
+ nextActions: z10.array(z10.string()).optional()
7579
6406
  })
7580
6407
  }).passthrough();
7581
- var directApiErrorResponseSchema = z13.object({
7582
- code: z13.string().trim().min(1).optional(),
7583
- message: z13.string().trim().min(1).optional(),
7584
- status: z13.number().int().optional()
6408
+ var directApiErrorResponseSchema = z10.object({
6409
+ code: z10.string().trim().min(1).optional(),
6410
+ message: z10.string().trim().min(1).optional(),
6411
+ status: z10.number().int().optional()
7585
6412
  }).passthrough();
7586
6413
  var SiteOSSearchApiError = class extends Error {
7587
6414
  code;
@@ -7595,90 +6422,8 @@ var SiteOSSearchApiError = class extends Error {
7595
6422
  this.status = options.status;
7596
6423
  }
7597
6424
  };
7598
- function resolveSiteOSSearchBaseUrl(env = process.env) {
7599
- return normalizeSearchOrigin(
7600
- env[SITEOS_SEARCH_BASE_URL_ENV]?.trim() || DEFAULT_SITEOS_SEARCH_BASE_URL
7601
- );
7602
- }
7603
6425
  function createSiteOSSearchApiClient(options) {
7604
6426
  return {
7605
- createProject: async (input) => {
7606
- const response = await requestJson3({
7607
- apiBaseUrl: options.apiBaseUrl,
7608
- authToken: input.token,
7609
- body: { name: input.name, slug: input.slug },
7610
- fetchImpl: options.fetchImpl,
7611
- method: "POST",
7612
- path: "/api/v1/search/projects",
7613
- responseSchema: searchProjectResponseSchema
7614
- });
7615
- return response.project;
7616
- },
7617
- listProjects: async (input) => {
7618
- const response = await requestJson3({
7619
- apiBaseUrl: options.apiBaseUrl,
7620
- authToken: input.token,
7621
- fetchImpl: options.fetchImpl,
7622
- method: "GET",
7623
- path: "/api/v1/search/projects",
7624
- responseSchema: searchProjectListResponseSchema
7625
- });
7626
- return response.projects;
7627
- },
7628
- listEnvironments: async (input) => {
7629
- const response = await requestJson3({
7630
- apiBaseUrl: options.apiBaseUrl,
7631
- authToken: input.token,
7632
- fetchImpl: options.fetchImpl,
7633
- method: "GET",
7634
- path: environmentCollectionPath2(input.projectId),
7635
- responseSchema: searchEnvironmentListResponseSchema
7636
- });
7637
- return response.environments;
7638
- },
7639
- createEnvironment: async (input) => {
7640
- const response = await requestJson3({
7641
- apiBaseUrl: options.apiBaseUrl,
7642
- authToken: input.token,
7643
- body: { slug: input.slug, name: input.name },
7644
- fetchImpl: options.fetchImpl,
7645
- method: "POST",
7646
- path: environmentCollectionPath2(input.projectId),
7647
- responseSchema: searchEnvironmentResponseSchema
7648
- });
7649
- return response.environment;
7650
- },
7651
- updateEnvironment: async (input) => {
7652
- const response = await requestJson3({
7653
- apiBaseUrl: options.apiBaseUrl,
7654
- authToken: input.token,
7655
- body: { name: input.name },
7656
- fetchImpl: options.fetchImpl,
7657
- method: "PATCH",
7658
- path: environmentPath(input.projectId, input.environmentSlug),
7659
- responseSchema: searchEnvironmentResponseSchema
7660
- });
7661
- return response.environment;
7662
- },
7663
- forkEnvironment: async (input) => {
7664
- const response = await requestJson3({
7665
- apiBaseUrl: options.apiBaseUrl,
7666
- authToken: input.token,
7667
- body: { slug: input.slug, name: input.name },
7668
- fetchImpl: options.fetchImpl,
7669
- method: "POST",
7670
- path: `${environmentPath(input.projectId, input.sourceEnvironmentSlug)}/actions/fork`,
7671
- responseSchema: searchEnvironmentResponseSchema
7672
- });
7673
- return response.environment;
7674
- },
7675
- deleteEnvironment: (input) => requestJson3({
7676
- apiBaseUrl: options.apiBaseUrl,
7677
- authToken: input.token,
7678
- fetchImpl: options.fetchImpl,
7679
- method: "DELETE",
7680
- path: environmentPath(input.projectId, input.environmentSlug)
7681
- }),
7682
6427
  analytics: (input) => requestJson3({
7683
6428
  apiBaseUrl: options.apiBaseUrl,
7684
6429
  authToken: input.token,
@@ -7926,36 +6671,19 @@ function buildApiUrl2(options) {
7926
6671
  }
7927
6672
  return url.toString();
7928
6673
  }
7929
- function normalizeSearchOrigin(value) {
7930
- try {
7931
- const url = new URL(value);
7932
- const loopback = ["localhost", "127.0.0.1", "[::1]", "::1"].includes(
7933
- url.hostname
7934
- );
7935
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
7936
- throw new Error("invalid Search origin");
7937
- }
7938
- return url.origin;
7939
- } catch {
7940
- throw new SiteOSSearchApiError({
7941
- code: "INVALID_SEARCH_BASE_URL",
7942
- message: "The SiteOS Search URL is invalid."
7943
- });
7944
- }
7945
- }
7946
6674
 
7947
6675
  // src/siteos-search-credential.ts
7948
6676
  import { spawn as spawn4 } from "child_process";
7949
6677
  import { randomUUID as randomUUID5 } from "crypto";
7950
6678
  import {
7951
6679
  chmod as chmod4,
7952
- lstat as lstat7,
7953
- readFile as readFile15,
6680
+ lstat as lstat6,
6681
+ readFile as readFile14,
7954
6682
  rename as rename6,
7955
6683
  rm as rm5,
7956
6684
  writeFile as writeFile7
7957
6685
  } from "fs/promises";
7958
- import path26 from "path";
6686
+ import path23 from "path";
7959
6687
  var SITEOS_SEARCH_QUERY_CREDENTIAL_ENV = "SITEOS_SEARCH_TOKEN";
7960
6688
  var SITEOS_SEARCH_ENVIRONMENT_ENV = "SITEOS_SEARCH_ENV";
7961
6689
  var SITEOS_SEARCH_INDEXING_CREDENTIAL_ENV = "SITEOS_SEARCH_INDEXING_CREDENTIAL";
@@ -7973,8 +6701,8 @@ var SiteOSSearchCredentialStorageError = class extends Error {
7973
6701
  }
7974
6702
  };
7975
6703
  async function prepareSiteOSSearchCredentialInstallation(options) {
7976
- const projectRoot = path26.resolve(options.projectRoot);
7977
- const dotenvPath = path26.join(projectRoot, ".env");
6704
+ const projectRoot = path23.resolve(options.projectRoot);
6705
+ const dotenvPath = path23.join(projectRoot, ".env");
7978
6706
  try {
7979
6707
  await assertSafeProjectRoot2(projectRoot);
7980
6708
  if (!await isDotenvIgnored2(projectRoot)) {
@@ -8032,8 +6760,8 @@ async function prepareSiteOSSearchCredentialInstallation(options) {
8032
6760
  }
8033
6761
  }
8034
6762
  async function prepareSiteOSSearchIndexingCredentialInstallation(options) {
8035
- const projectRoot = path26.resolve(options.projectRoot);
8036
- const dotenvPath = path26.join(projectRoot, ".env");
6763
+ const projectRoot = path23.resolve(options.projectRoot);
6764
+ const dotenvPath = path23.join(projectRoot, ".env");
8037
6765
  try {
8038
6766
  await assertSafeProjectRoot2(projectRoot);
8039
6767
  if (!await isDotenvIgnored2(projectRoot)) {
@@ -8092,7 +6820,7 @@ async function prepareSiteOSSearchIndexingCredentialInstallation(options) {
8092
6820
  }
8093
6821
  }
8094
6822
  async function assertSafeProjectRoot2(projectRoot) {
8095
- const projectStats = await lstat7(projectRoot);
6823
+ const projectStats = await lstat6(projectRoot);
8096
6824
  if (!projectStats.isDirectory() || projectStats.isSymbolicLink()) {
8097
6825
  throw new SiteOSSearchCredentialStorageError(
8098
6826
  "SEARCH_CREDENTIAL_STORAGE_INVALID"
@@ -8100,7 +6828,7 @@ async function assertSafeProjectRoot2(projectRoot) {
8100
6828
  }
8101
6829
  }
8102
6830
  async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
8103
- const dotenvStats = await lstat7(dotenvPath).catch((error) => {
6831
+ const dotenvStats = await lstat6(dotenvPath).catch((error) => {
8104
6832
  if (isNodeErrorCode5(error, "ENOENT")) return void 0;
8105
6833
  throw error;
8106
6834
  });
@@ -8109,7 +6837,7 @@ async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
8109
6837
  "SEARCH_CREDENTIAL_STORAGE_INVALID"
8110
6838
  );
8111
6839
  }
8112
- const content = dotenvStats ? await readFile15(dotenvPath, "utf8") : "";
6840
+ const content = dotenvStats ? await readFile14(dotenvPath, "utf8") : "";
8113
6841
  if (managedEnvironmentNames.some(
8114
6842
  (name) => countManagedEntries(content, name) > 1
8115
6843
  )) {
@@ -8120,7 +6848,7 @@ async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
8120
6848
  return content;
8121
6849
  }
8122
6850
  async function writeCredentialAtomically2(options) {
8123
- const temporaryPath = path26.join(
6851
+ const temporaryPath = path23.join(
8124
6852
  options.projectRoot,
8125
6853
  `.siteos-search-credential.${process.pid}.${randomUUID5()}.tmp`
8126
6854
  );
@@ -8199,19 +6927,7 @@ var ENVIRONMENT_FLAG2 = "--environment";
8199
6927
  var CREDENTIAL_FLAG2 = "--credential";
8200
6928
  var INSTALL_FLAG2 = "--install";
8201
6929
  var NAME_FLAG2 = "--name";
8202
- var SLUG_FLAG2 = "--slug";
8203
- var SOURCE_FLAG = "--source";
8204
- var REPLACE_FLAG2 = "--replace";
8205
6930
  var SEARCH_HELP = `Usage:
8206
- siteos search project list [--json]
8207
- siteos search project create --slug <slug> --name <name> [--json]
8208
- siteos search project use <slug> [--replace] [--json]
8209
- siteos search project status [--json]
8210
- siteos search environment list [--json]
8211
- siteos search environment create --slug <slug> --name <name> [--json]
8212
- siteos search environment update --environment <slug> --name <name> [--json]
8213
- siteos search environment fork --source <slug> --slug <slug> --name <name> [--json]
8214
- siteos search environment delete --environment <slug> [--json]
8215
6931
  siteos search analytics --environment <slug> [--json]
8216
6932
  siteos search diagnostics --environment <slug> [--json]
8217
6933
  siteos search doctor --environment <slug> [--json]
@@ -8233,13 +6949,27 @@ async function runSearchCommand(options) {
8233
6949
  if (options.args.some((arg) => splitFlag2(arg)[0] === "--env")) {
8234
6950
  return usageError4("Use --environment for SiteOS search environments.");
8235
6951
  }
8236
- if (options.args[0] !== "project") {
6952
+ const environmentFlags = options.args.flatMap(
6953
+ (arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice(14)] : [arg]
6954
+ );
6955
+ const environmentIndex = environmentFlags.indexOf("--environment");
6956
+ options = {
6957
+ ...options,
6958
+ selectedEnvironment: environmentIndex >= 0 ? environmentFlags[environmentIndex + 1] : void 0
6959
+ };
6960
+ if (["project", "environment"].includes(options.args[0] ?? ""))
6961
+ return usageError4(
6962
+ "Use `siteos project` to manage Projects and environments."
6963
+ );
6964
+ {
8237
6965
  try {
8238
6966
  options = {
8239
6967
  ...options,
8240
6968
  args: await commonEnvironmentArguments(options, "search", options.args)
8241
6969
  };
8242
6970
  } catch (error) {
6971
+ if (error instanceof SiteOSAuthApiError)
6972
+ return formatAuthError2(error).error;
8243
6973
  return {
8244
6974
  exitCode: 1,
8245
6975
  stderr: error instanceof Error ? error.message : "Environment could not be selected."
@@ -8247,12 +6977,6 @@ async function runSearchCommand(options) {
8247
6977
  }
8248
6978
  }
8249
6979
  const [subcommand, ...args2] = options.args;
8250
- if (subcommand === "project") {
8251
- return runProjectCommand3({ ...options, args: args2 });
8252
- }
8253
- if (subcommand === "environment") {
8254
- return runEnvironmentCommand2({ ...options, args: args2 });
8255
- }
8256
6980
  if (subcommand === "credential") {
8257
6981
  return runCredentialCommand2({ ...options, args: args2, credentialKind: "query" });
8258
6982
  }
@@ -8268,269 +6992,6 @@ async function runSearchCommand(options) {
8268
6992
  }
8269
6993
  return usageError4("Unknown SiteOS search command.");
8270
6994
  }
8271
- async function runProjectCommand3(options) {
8272
- const action = options.args[0];
8273
- if (!action || !["create", "list", "status", "use"].includes(action)) {
8274
- return usageError4("Unknown SiteOS search project command.");
8275
- }
8276
- const parsed = parseProjectFlags2(action, options.args.slice(1));
8277
- if (!parsed.ok) return parsed.error;
8278
- if (!options.fetchImpl) {
8279
- return {
8280
- exitCode: 1,
8281
- stderr: "SiteOS API access is unavailable in this runtime."
8282
- };
8283
- }
8284
- try {
8285
- const apiBaseUrl = resolveSiteOSSearchBaseUrl(options.env);
8286
- const grant = await serviceGrantProvider2(options).acquire({
8287
- audience: "siteos-search",
8288
- scopes: ["search:workspace:write"]
8289
- });
8290
- requireGrant2(grant, "search:workspace:write");
8291
- const client = createSiteOSSearchApiClient({
8292
- apiBaseUrl,
8293
- fetchImpl: options.fetchImpl
8294
- });
8295
- if (action === "list") {
8296
- const projects2 = await client.listProjects({ token: grant.accessToken });
8297
- requireProjectOrganization2(projects2, grant.grant.organizationId);
8298
- return {
8299
- exitCode: 0,
8300
- stdout: parsed.json ? stringifySafeJson2({ projects: projects2 }) : formatProjectListOutput2(projects2)
8301
- };
8302
- }
8303
- if (action === "create") {
8304
- const project2 = await client.createProject({
8305
- name: parsed.name,
8306
- slug: parsed.slug,
8307
- token: grant.accessToken
8308
- });
8309
- requireProjectOrganization2([project2], grant.grant.organizationId);
8310
- return {
8311
- exitCode: 0,
8312
- stdout: parsed.json ? stringifySafeJson2({ project: project2 }) : [
8313
- "SiteOS Search Project created.",
8314
- `Project: ${project2.slug}`,
8315
- `Name: ${project2.name}`,
8316
- `Run \`siteos search project use ${project2.slug}\` to select it for this repository.`
8317
- ].join("\n")
8318
- };
8319
- }
8320
- const reference = await inspectSearchProjectReference(
8321
- options.cwd ?? process.cwd()
8322
- );
8323
- const store = projectBindingStore3(options);
8324
- const locator = {
8325
- apiOrigin: apiBaseUrl,
8326
- repositoryRoot: reference.rootDir,
8327
- service: "search"
8328
- };
8329
- if (action === "use") {
8330
- const projects2 = await client.listProjects({ token: grant.accessToken });
8331
- requireProjectOrganization2(projects2, grant.grant.organizationId);
8332
- const matches = projects2.filter(
8333
- (project3) => project3.slug === parsed.slug
8334
- );
8335
- if (matches.length !== 1) {
8336
- throw new SiteOSSearchApiError({
8337
- code: matches.length === 0 ? "PROJECT_NOT_FOUND" : "INVALID_RESPONSE",
8338
- message: matches.length === 0 ? "The Search Project was not found." : "SiteOS Search returned an invalid response.",
8339
- status: matches.length === 0 ? 404 : void 0
8340
- });
8341
- }
8342
- const project2 = matches[0];
8343
- if (reference.status === "loaded" && reference.reference.project.slug !== project2.slug && !parsed.replace) {
8344
- throw new SearchProjectReferenceError(
8345
- "SEARCH_PROJECT_REFERENCE_CONFLICT",
8346
- "A different Search Project is already selected. Use --replace to replace it."
8347
- );
8348
- }
8349
- const previousBinding = await store.read(locator);
8350
- await store.write({
8351
- ...locator,
8352
- organizationId: grant.grant.organizationId,
8353
- project: { id: project2.id, slug: project2.slug }
8354
- });
8355
- try {
8356
- await writeSearchProjectReference({
8357
- expectedChecksum: reference.status === "loaded" ? reference.checksum : null,
8358
- project: { name: project2.name, slug: project2.slug },
8359
- rootDir: reference.rootDir
8360
- });
8361
- } catch (error) {
8362
- if (previousBinding) await store.write(previousBinding);
8363
- else await store.remove(locator);
8364
- throw error;
8365
- }
8366
- const output2 = {
8367
- apiOrigin: apiBaseUrl,
8368
- organizationId: grant.grant.organizationId,
8369
- project: project2,
8370
- referencePath: path27.join(
8371
- reference.rootDir,
8372
- ".siteos",
8373
- "search",
8374
- "project.json"
8375
- )
8376
- };
8377
- return {
8378
- exitCode: 0,
8379
- stdout: parsed.json ? stringifySafeJson2(output2) : [
8380
- "SiteOS Search Project selected.",
8381
- `Project: ${project2.slug}`,
8382
- `Reference: ${output2.referencePath}`
8383
- ].join("\n")
8384
- };
8385
- }
8386
- if (reference.status === "missing") {
8387
- throw new SearchProjectReferenceError(
8388
- "SEARCH_PROJECT_REFERENCE_REQUIRED",
8389
- "Select a Search Project for this repository first."
8390
- );
8391
- }
8392
- const binding = await store.read(locator);
8393
- if (!binding || binding.organizationId !== grant.grant.organizationId || binding.project.slug !== reference.reference.project.slug) {
8394
- throw new SearchProjectReferenceError(
8395
- binding ? "SEARCH_PROJECT_REFERENCE_INVALID" : "SEARCH_PROJECT_REFERENCE_REQUIRED",
8396
- binding ? "The Search Project reference and private binding do not match." : "Select a Search Project for this repository first."
8397
- );
8398
- }
8399
- const projects = await client.listProjects({ token: grant.accessToken });
8400
- requireProjectOrganization2(projects, grant.grant.organizationId);
8401
- const project = projects.find(
8402
- (candidate) => candidate.id === binding.project.id
8403
- );
8404
- if (!project || project.slug !== binding.project.slug) {
8405
- throw new SiteOSSearchApiError({
8406
- code: "PROJECT_NOT_FOUND",
8407
- message: "The Search Project was not found.",
8408
- status: 404
8409
- });
8410
- }
8411
- const output = {
8412
- apiOrigin: apiBaseUrl,
8413
- connected: true,
8414
- organizationId: binding.organizationId,
8415
- project,
8416
- repositoryRoot: reference.rootDir
8417
- };
8418
- return {
8419
- exitCode: 0,
8420
- stdout: parsed.json ? stringifySafeJson2(output) : [
8421
- "SiteOS Search Project connection is valid.",
8422
- `Project: ${project.slug}`,
8423
- `Organization: ${binding.organizationId}`,
8424
- `API: ${apiBaseUrl}`
8425
- ].join("\n")
8426
- };
8427
- } catch (error) {
8428
- return formatProjectError2(error);
8429
- }
8430
- }
8431
- async function runEnvironmentCommand2(options) {
8432
- const [action, ...args2] = options.args;
8433
- if (!action || !["list", "create", "update", "fork", "delete"].includes(action)) {
8434
- return usageError4("Unknown SiteOS search environment command.");
8435
- }
8436
- const parsed = parseEnvironmentFlags2(action, args2);
8437
- if (!parsed.ok) return parsed.error;
8438
- return runWithSearchClient(options, async ({ client, context }) => {
8439
- const authorization = {
8440
- projectId: context.projectId,
8441
- token: context.credential
8442
- };
8443
- if (action === "list") {
8444
- const environments = await client.listEnvironments(authorization);
8445
- return {
8446
- exitCode: 0,
8447
- stdout: parsed.json ? stringifySafeJson2({ environments }) : [
8448
- "SiteOS Search Environments.",
8449
- `Environments: ${environments.length}`,
8450
- ...environments.map(({ slug: slug2, name }) => `- ${slug2}: ${name}`)
8451
- ].join("\n")
8452
- };
8453
- }
8454
- const environment = action === "create" ? await client.createEnvironment({
8455
- ...authorization,
8456
- slug: parsed.slug,
8457
- name: parsed.name
8458
- }) : action === "update" ? await client.updateEnvironment({
8459
- ...authorization,
8460
- environmentSlug: parsed.environmentSlug,
8461
- name: parsed.name
8462
- }) : action === "fork" ? await client.forkEnvironment({
8463
- ...authorization,
8464
- sourceEnvironmentSlug: parsed.sourceSlug,
8465
- slug: parsed.slug,
8466
- name: parsed.name
8467
- }) : void 0;
8468
- if (action === "delete") {
8469
- const result = await client.deleteEnvironment({
8470
- ...authorization,
8471
- environmentSlug: parsed.environmentSlug
8472
- });
8473
- return {
8474
- exitCode: 0,
8475
- stdout: parsed.json ? stringifySafeJson2({ environment: parsed.environmentSlug, result }) : `SiteOS Search Environment ${parsed.environmentSlug} deleted.`
8476
- };
8477
- }
8478
- return {
8479
- exitCode: 0,
8480
- stdout: parsed.json ? stringifySafeJson2({ environment }) : `SiteOS Search Environment ${environment.slug} ${action === "fork" ? "forked" : action === "create" ? "created" : "updated"}.`
8481
- };
8482
- });
8483
- }
8484
- function parseEnvironmentFlags2(action, args2) {
8485
- const required = action === "create" ? [SLUG_FLAG2, NAME_FLAG2] : action === "update" ? [ENVIRONMENT_FLAG2, NAME_FLAG2] : action === "fork" ? [SOURCE_FLAG, SLUG_FLAG2, NAME_FLAG2] : action === "delete" ? [ENVIRONMENT_FLAG2] : [];
8486
- const allowed = /* @__PURE__ */ new Set([JSON_FLAG2, ...required]);
8487
- const flags = /* @__PURE__ */ new Map();
8488
- for (let index = 0; index < args2.length; index += 1) {
8489
- const [flag, inlineValue] = splitFlag2(args2[index]);
8490
- if (!allowed.has(flag) || flags.has(flag)) {
8491
- return { error: usageError4(`Unexpected argument: ${flag}`), ok: false };
8492
- }
8493
- if (flag === JSON_FLAG2) {
8494
- if (inlineValue !== void 0) {
8495
- return {
8496
- error: usageError4("--json does not accept a value."),
8497
- ok: false
8498
- };
8499
- }
8500
- flags.set(flag, true);
8501
- continue;
8502
- }
8503
- const value = inlineValue ?? args2[index + 1];
8504
- if (!value || value.startsWith("--")) {
8505
- return { error: usageError4(`${flag} requires a value.`), ok: false };
8506
- }
8507
- flags.set(flag, value.trim());
8508
- if (inlineValue === void 0) index += 1;
8509
- }
8510
- for (const flag of required) {
8511
- if (!flags.has(flag))
8512
- return { error: usageError4(`${flag} is required.`), ok: false };
8513
- }
8514
- const environmentSlug = readCredentialStringFlag(flags, ENVIRONMENT_FLAG2);
8515
- const sourceSlug = readCredentialStringFlag(flags, SOURCE_FLAG);
8516
- const slug2 = readCredentialStringFlag(flags, SLUG_FLAG2);
8517
- if ([environmentSlug, sourceSlug, slug2].some(
8518
- (value) => value && !isValidEnvironmentSlug(value)
8519
- )) {
8520
- return { error: usageError4("Environment slugs must be valid."), ok: false };
8521
- }
8522
- const name = readCredentialStringFlag(flags, NAME_FLAG2);
8523
- if (name && name.length > 255)
8524
- return { error: usageError4("--name is invalid."), ok: false };
8525
- return {
8526
- ...environmentSlug ? { environmentSlug } : {},
8527
- json: flags.has(JSON_FLAG2),
8528
- ...name ? { name } : {},
8529
- ok: true,
8530
- ...slug2 ? { slug: slug2 } : {},
8531
- ...sourceSlug ? { sourceSlug } : {}
8532
- };
8533
- }
8534
6995
  async function runCredentialCommand2(options) {
8535
6996
  const action = options.args[0];
8536
6997
  if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
@@ -8703,18 +7164,12 @@ async function completeCredentialInstallation(options) {
8703
7164
  async function loadCredentialManagementContext2(options) {
8704
7165
  try {
8705
7166
  const local = await readLocalCommonProject(options);
8706
- let rootDir = local?.rootDir;
8707
- if (!rootDir) {
8708
- const reference = await inspectSearchProjectReference(
8709
- options.cwd ?? process.cwd()
8710
- );
8711
- if (reference.status === "missing")
8712
- throw new SearchProjectReferenceError(
8713
- "SEARCH_PROJECT_REFERENCE_REQUIRED",
8714
- "Select a Search Project for this repository first."
8715
- );
8716
- rootDir = reference.rootDir;
8717
- }
7167
+ if (!local)
7168
+ throw new SiteOSAuthApiError({
7169
+ code: "PROJECT_REQUIRED",
7170
+ message: "Select a Project with `siteos project use <id-or-slug>`."
7171
+ });
7172
+ const rootDir = local.rootDir;
8718
7173
  const installation = options.install ? await (options.credentialKind === "query" ? options.prepareCredentialInstallation ?? prepareSiteOSSearchCredentialInstallation : options.prepareIndexingCredentialInstallation ?? prepareSiteOSSearchIndexingCredentialInstallation)({ projectRoot: rootDir }) : void 0;
8719
7174
  const context = await loadSearchContext(options, "search:credential:issue");
8720
7175
  if (!context.ok) return context;
@@ -8806,21 +7261,30 @@ async function loadSearchContext(options, requiredScope = "search:workspace:writ
8806
7261
  };
8807
7262
  }
8808
7263
  try {
8809
- const common = await commonServiceContext(options, "search");
8810
- if (common) {
8811
- const grant2 = await serviceGrantProvider2(options).acquire({
7264
+ const common = await commonServiceContext(
7265
+ options,
7266
+ "search",
7267
+ options.selectedEnvironment
7268
+ );
7269
+ if (!common)
7270
+ throw new SiteOSAuthApiError({
7271
+ code: "PROJECT_REQUIRED",
7272
+ message: "Select a Project with `siteos project use <id-or-slug>`."
7273
+ });
7274
+ {
7275
+ const grant = await serviceGrantProvider2(options).acquire({
8812
7276
  audience: "siteos-search",
8813
7277
  scopes: [requiredScope]
8814
7278
  });
8815
- requireGrant2(grant2, requiredScope);
8816
- if (grant2.grant.organizationId !== common.overview.project.organizationId)
7279
+ requireGrant2(grant, requiredScope);
7280
+ if (grant.grant.organizationId !== common.overview.project.organizationId)
8817
7281
  throw new SiteOSAuthApiError({
8818
7282
  code: "PROJECT_ORGANIZATION_MISMATCH",
8819
7283
  message: "The Project and service grant belong to different organizations."
8820
7284
  });
8821
7285
  return {
8822
7286
  apiBaseUrl: common.api.origin,
8823
- credential: grant2.accessToken,
7287
+ credential: grant.accessToken,
8824
7288
  ok: true,
8825
7289
  project: {
8826
7290
  id: common.resourceId,
@@ -8831,53 +7295,9 @@ async function loadSearchContext(options, requiredScope = "search:workspace:writ
8831
7295
  rootDir: common.rootDir
8832
7296
  };
8833
7297
  }
8834
- const reference = await inspectSearchProjectReference(
8835
- options.cwd ?? process.cwd()
8836
- );
8837
- if (reference.status === "missing") {
8838
- throw new SearchProjectReferenceError(
8839
- "SEARCH_PROJECT_REFERENCE_REQUIRED",
8840
- "Select a Search Project for this repository first."
8841
- );
8842
- }
8843
- const apiBaseUrl = resolveSiteOSSearchBaseUrl(options.env);
8844
- const binding = await projectBindingStore3(options).read({
8845
- apiOrigin: apiBaseUrl,
8846
- repositoryRoot: reference.rootDir,
8847
- service: "search"
8848
- });
8849
- if (!binding) {
8850
- throw new SearchProjectReferenceError(
8851
- "SEARCH_PROJECT_REFERENCE_REQUIRED",
8852
- "Select a Search Project for this repository first."
8853
- );
8854
- }
8855
- const grant = await serviceGrantProvider2(options).acquire({
8856
- audience: "siteos-search",
8857
- scopes: [requiredScope]
8858
- });
8859
- requireGrant2(grant, requiredScope);
8860
- if (grant.grant.organizationId !== binding.organizationId || binding.project.slug !== reference.reference.project.slug) {
8861
- throw new SearchProjectReferenceError(
8862
- "SEARCH_PROJECT_REFERENCE_INVALID",
8863
- "The Search Project reference, private binding, and Auth Organization do not match."
8864
- );
8865
- }
8866
- return {
8867
- apiBaseUrl,
8868
- credential: grant.accessToken,
8869
- ok: true,
8870
- project: {
8871
- id: binding.project.id,
8872
- name: reference.reference.project.name,
8873
- slug: binding.project.slug
8874
- },
8875
- projectId: binding.project.id,
8876
- rootDir: reference.rootDir
8877
- };
8878
7298
  } catch (error) {
8879
7299
  if (error instanceof SiteOSAuthApiError) return formatAuthError2(error);
8880
- return { error: formatProjectError2(error), ok: false };
7300
+ return { error: formatProjectError(error), ok: false };
8881
7301
  }
8882
7302
  }
8883
7303
  function formatAuthError2(error) {
@@ -8903,92 +7323,6 @@ function formatAuthError2(error) {
8903
7323
  ok: false
8904
7324
  };
8905
7325
  }
8906
- function parseProjectFlags2(action, args2) {
8907
- const flags = /* @__PURE__ */ new Map();
8908
- const positionals = [];
8909
- const allowed = /* @__PURE__ */ new Set([
8910
- JSON_FLAG2,
8911
- ...action === "create" ? [NAME_FLAG2, SLUG_FLAG2] : [],
8912
- ...action === "use" ? [REPLACE_FLAG2] : []
8913
- ]);
8914
- const boolean = /* @__PURE__ */ new Set([JSON_FLAG2, REPLACE_FLAG2]);
8915
- for (let index = 0; index < args2.length; index += 1) {
8916
- const arg = args2[index];
8917
- if (!arg.startsWith("--")) {
8918
- positionals.push(arg);
8919
- continue;
8920
- }
8921
- const [flag, inlineValue] = splitFlag2(arg);
8922
- if (!allowed.has(flag) || flags.has(flag)) {
8923
- return { error: usageError4(`Unexpected argument: ${flag}`), ok: false };
8924
- }
8925
- if (boolean.has(flag)) {
8926
- if (inlineValue !== void 0) {
8927
- return {
8928
- error: usageError4(`${flag} does not accept a value.`),
8929
- ok: false
8930
- };
8931
- }
8932
- flags.set(flag, true);
8933
- continue;
8934
- }
8935
- const value = inlineValue ?? args2[index + 1];
8936
- if (!value || value.startsWith("--")) {
8937
- return { error: usageError4(`${flag} requires a value.`), ok: false };
8938
- }
8939
- flags.set(flag, value.trim());
8940
- if (inlineValue === void 0) index += 1;
8941
- }
8942
- if (action === "use") {
8943
- if (positionals.length !== 1 || !isValidProjectSlug(positionals[0])) {
8944
- return {
8945
- error: usageError4(
8946
- "Project use requires exactly one valid Project slug."
8947
- ),
8948
- ok: false
8949
- };
8950
- }
8951
- return {
8952
- json: flags.has(JSON_FLAG2),
8953
- ok: true,
8954
- replace: flags.has(REPLACE_FLAG2),
8955
- slug: positionals[0]
8956
- };
8957
- }
8958
- if (positionals.length > 0) {
8959
- return {
8960
- error: usageError4(`Unexpected argument: ${positionals[0]}`),
8961
- ok: false
8962
- };
8963
- }
8964
- if (action !== "create") {
8965
- return { json: flags.has(JSON_FLAG2), ok: true, replace: false };
8966
- }
8967
- const slug2 = readCredentialStringFlag(flags, SLUG_FLAG2);
8968
- const name = readCredentialStringFlag(flags, NAME_FLAG2);
8969
- if (!slug2 || !isValidProjectSlug(slug2)) {
8970
- return {
8971
- error: usageError4("--slug is required and must be valid."),
8972
- ok: false
8973
- };
8974
- }
8975
- if (!name || name.length > 255) {
8976
- return {
8977
- error: usageError4("--name is required and must be valid."),
8978
- ok: false
8979
- };
8980
- }
8981
- return {
8982
- json: flags.has(JSON_FLAG2),
8983
- name,
8984
- ok: true,
8985
- replace: false,
8986
- slug: slug2
8987
- };
8988
- }
8989
- function isValidProjectSlug(value) {
8990
- return value.length >= 1 && value.length <= 120 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
8991
- }
8992
7326
  function parseCredentialFlags2(action, args2, credentialKind) {
8993
7327
  const installs = action === "issue" || action === "rotate";
8994
7328
  const revokes = action === "revoke";
@@ -9120,7 +7454,7 @@ function formatCredentialError2(error) {
9120
7454
  stderr: "SiteOS Search credential request failed."
9121
7455
  };
9122
7456
  }
9123
- function formatProjectError2(error) {
7457
+ function formatProjectError(error) {
9124
7458
  if (error instanceof SiteOSAuthApiError) return formatAuthError2(error).error;
9125
7459
  if (error instanceof SiteOSSearchApiError) {
9126
7460
  return {
@@ -9132,7 +7466,7 @@ function formatProjectError2(error) {
9132
7466
  ].filter((line) => Boolean(line)).join("\n")
9133
7467
  };
9134
7468
  }
9135
- if (error instanceof SearchProjectReferenceError || error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
7469
+ if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
9136
7470
  return {
9137
7471
  exitCode: 1,
9138
7472
  stderr: [
@@ -9150,14 +7484,6 @@ function serviceGrantProvider2(options) {
9150
7484
  fetchImpl: options.fetchImpl
9151
7485
  });
9152
7486
  }
9153
- function projectBindingStore3(options) {
9154
- return options.projectBindingStore ?? new NodeProjectBindingStore(
9155
- path27.join(
9156
- resolveSiteOSConfigHome({ env: options.env }),
9157
- "project-bindings.json"
9158
- )
9159
- );
9160
- }
9161
7487
  function requireGrant2(grant, scope) {
9162
7488
  if (grant.grant.audience !== "siteos-search" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
9163
7489
  throw new SiteOSAuthApiError({
@@ -9166,23 +7492,6 @@ function requireGrant2(grant, scope) {
9166
7492
  });
9167
7493
  }
9168
7494
  }
9169
- function requireProjectOrganization2(projects, organizationId) {
9170
- if (projects.some((project) => project.organizationId !== organizationId)) {
9171
- throw new SiteOSSearchApiError({
9172
- code: "INVALID_RESPONSE",
9173
- message: "SiteOS Search returned an invalid response."
9174
- });
9175
- }
9176
- }
9177
- function formatProjectListOutput2(projects) {
9178
- return [
9179
- "SiteOS Search Projects.",
9180
- `Projects: ${projects.length}`,
9181
- ...projects.map(
9182
- (project) => `- ${project.slug}: ${project.name} (${project.id})`
9183
- )
9184
- ].join("\n");
9185
- }
9186
7495
  function formatCredentialListOutput2(input) {
9187
7496
  return [
9188
7497
  `SiteOS Search ${credentialKindLabel(input.credentialKind)} credentials.`,
@@ -9254,7 +7563,7 @@ var PROJECT_HELP = `One Project for your website and all its services.
9254
7563
  Usage:
9255
7564
  siteos project list [--json]
9256
7565
  siteos project create --name <name> --slug <slug> [--url <url>] [--domain <domain>] [--json]
9257
- siteos project use <id-or-slug> [--json]
7566
+ siteos project use <id-or-slug> [--environment <slug>] [--json]
9258
7567
  siteos project update [--name <name>] [--slug <slug>] [--url <production-url>] [--json]
9259
7568
  siteos project status [--json]
9260
7569
  siteos project connect <pulse|cookie|forms|search|trace|seo|analytics> [--resource <id>] [--json]
@@ -9268,13 +7577,13 @@ Usage:
9268
7577
  Select a Project once per repository. Service commands use its configured resources.
9269
7578
  Connect creates a draft workspace, or explicitly attaches an existing resource.
9270
7579
  It does not publish a banner, install a script, send a notification or deploy checks.`;
9271
- async function runProjectCommand4(options) {
7580
+ async function runProjectCommand(options) {
9272
7581
  if (!options.args.length || options.args.some((arg) => arg === "--help" || arg === "-h"))
9273
7582
  return { exitCode: 0, stdout: PROJECT_HELP };
9274
7583
  try {
9275
7584
  const [action, ...args2] = options.args;
9276
7585
  if (action === "environment")
9277
- return await runEnvironmentCommand3({ ...options, args: args2 });
7586
+ return await runEnvironmentCommand({ ...options, args: args2 });
9278
7587
  if (!["list", "create", "use", "status", "connect", "update"].includes(
9279
7588
  action
9280
7589
  ))
@@ -9285,6 +7594,7 @@ async function runProjectCommand4(options) {
9285
7594
  strict: true,
9286
7595
  options: {
9287
7596
  json: { type: "boolean" },
7597
+ ...action === "use" ? { environment: { type: "string" } } : {},
9288
7598
  ...action === "create" || action === "update" ? {
9289
7599
  name: { type: "string" },
9290
7600
  slug: { type: "string" },
@@ -9324,15 +7634,23 @@ Select it with \`siteos project use ${project.slug}\`.`;
9324
7634
  matches.length ? "Use the exact Project ID to disambiguate this selection." : "Project not found in the active organization."
9325
7635
  );
9326
7636
  const project = matches[0];
7637
+ const environment = project.environments.find(
7638
+ (item) => item.slug === (parsed.values.environment ?? "production")
7639
+ );
7640
+ if (!environment)
7641
+ throw new Error(
7642
+ "Select an available Project environment with --environment <slug>."
7643
+ );
9327
7644
  await store.write({
9328
7645
  apiOrigin: api.origin,
9329
7646
  repositoryRoot: await findRepositoryRoot(options.cwd ?? process.cwd()),
9330
7647
  service: "project",
9331
7648
  organizationId: project.organizationId,
9332
- project: { id: project.id, slug: project.slug }
7649
+ project: { id: project.id, slug: project.slug },
7650
+ environmentSlug: environment.slug
9333
7651
  });
9334
- result = { project };
9335
- message = `Selected ${project.name} for this repository.
7652
+ result = { project, environment };
7653
+ message = `Selected ${project.name} / ${environment.name} for this repository.
9336
7654
  Run \`siteos project status\` to inspect its services.`;
9337
7655
  } else {
9338
7656
  const context = await readCommonProject(options);
@@ -9388,7 +7706,7 @@ ${overview.services.map((service) => `${service.service}: ${service.observation?
9388
7706
  function projectLabel(project) {
9389
7707
  return `${project.name} (${project.slug})`;
9390
7708
  }
9391
- async function runEnvironmentCommand3(options) {
7709
+ async function runEnvironmentCommand(options) {
9392
7710
  const [action, ...args2] = options.args;
9393
7711
  if (!["list", "create", "connect", "resources", "use", "update"].includes(
9394
7712
  action
@@ -9424,7 +7742,7 @@ async function runEnvironmentCommand3(options) {
9424
7742
  throw new Error("Choose a Project environment with --environment <slug>.");
9425
7743
  const context = await readCommonProject(
9426
7744
  options,
9427
- action === "use" ? "production" : void 0
7745
+ action === "use" ? positionals[0] : void 0
9428
7746
  );
9429
7747
  if (!context)
9430
7748
  throw new Error("Select a Project with `siteos project use` first.");
@@ -9501,13 +7819,13 @@ async function runEnvironmentCommand3(options) {
9501
7819
  }
9502
7820
 
9503
7821
  // src/services/service-command.ts
9504
- import { readFile as readFile16, stat } from "fs/promises";
9505
- import path28 from "path";
7822
+ import { readFile as readFile15, stat } from "fs/promises";
7823
+ import path24 from "path";
9506
7824
  import { parseArgs as parseArgs3 } from "util";
9507
- import { z as z16 } from "zod";
7825
+ import { z as z13 } from "zod";
9508
7826
 
9509
7827
  // src/services/trace-explorer-command.ts
9510
- import { z as z14 } from "zod";
7828
+ import { z as z11 } from "zod";
9511
7829
  var filters = [
9512
7830
  "environment",
9513
7831
  "provider",
@@ -9530,8 +7848,8 @@ var TRACE_EXPLORER_FLAGS = {
9530
7848
  "issue show": ["environment", "id", "cursor"],
9531
7849
  "observation show": ["environment", "batch-id", "event-id"]
9532
7850
  };
9533
- var FilterValues = z14.object({
9534
- provider: z14.enum([
7851
+ var FilterValues = z11.object({
7852
+ provider: z11.enum([
9535
7853
  "siteos_analytics",
9536
7854
  "ga4",
9537
7855
  "google_ads",
@@ -9539,11 +7857,11 @@ var FilterValues = z14.object({
9539
7857
  "meta",
9540
7858
  "custom"
9541
7859
  ]).optional(),
9542
- event: z14.string().min(1).max(160).optional(),
9543
- property: z14.string().min(1).max(160).optional(),
9544
- "page-view": z14.string().uuid().optional(),
9545
- search: z14.string().max(160).optional(),
9546
- state: z14.enum([
7860
+ event: z11.string().min(1).max(160).optional(),
7861
+ property: z11.string().min(1).max(160).optional(),
7862
+ "page-view": z11.string().uuid().optional(),
7863
+ search: z11.string().max(160).optional(),
7864
+ state: z11.enum([
9547
7865
  "all",
9548
7866
  "active",
9549
7867
  "snoozed",
@@ -9553,8 +7871,8 @@ var FilterValues = z14.object({
9553
7871
  "tracked",
9554
7872
  "ignored"
9555
7873
  ]).optional(),
9556
- rule: z14.string().min(1).max(80).optional(),
9557
- kind: z14.enum([
7874
+ rule: z11.string().min(1).max(80).optional(),
7875
+ kind: z11.enum([
9558
7876
  "data_layer",
9559
7877
  "fetch",
9560
7878
  "xhr",
@@ -9564,8 +7882,8 @@ var FilterValues = z14.object({
9564
7882
  "heartbeat",
9565
7883
  "runtime_diagnostic"
9566
7884
  ]).optional(),
9567
- period: z14.enum(["24h", "7d"]).optional(),
9568
- cursor: z14.string().min(1).max(4096).optional()
7885
+ period: z11.enum(["24h", "7d"]).optional(),
7886
+ cursor: z11.string().min(1).max(4096).optional()
9569
7887
  });
9570
7888
  function traceExplorerSuffix(route, values) {
9571
7889
  if (!TRACE_EXPLORER_FLAGS[route]) return null;
@@ -9573,11 +7891,11 @@ function traceExplorerSuffix(route, values) {
9573
7891
  if (route === "issue show" || route === "observation show") {
9574
7892
  const keys = route === "issue show" ? ["id"] : ["batch-id", "event-id"];
9575
7893
  for (const key of keys) {
9576
- if (!z14.string().uuid().safeParse(values[key]).success)
7894
+ if (!z11.string().uuid().safeParse(values[key]).success)
9577
7895
  throw new Error(`Use --${key} with the UUID returned by Trace.`);
9578
7896
  }
9579
7897
  if (values.cursor !== void 0) {
9580
- if (!z14.string().uuid().safeParse(values.cursor).success)
7898
+ if (!z11.string().uuid().safeParse(values.cursor).success)
9581
7899
  throw new Error(
9582
7900
  "Use --cursor with the nextCursor returned by this issue."
9583
7901
  );
@@ -9814,8 +8132,8 @@ async function runServiceCommand(service, options) {
9814
8132
  );
9815
8133
  const result2 = await response.json();
9816
8134
  if (!response.ok) {
9817
- const error = z16.object({
9818
- error: z16.object({ code: z16.string(), message: z16.string().max(500) })
8135
+ const error = z13.object({
8136
+ error: z13.object({ code: z13.string(), message: z13.string().max(500) })
9819
8137
  }).safeParse(result2);
9820
8138
  throw new SiteOSAuthApiError({
9821
8139
  code: error.success ? error.data.error.code : "SERVICE_REQUEST_FAILED",
@@ -9828,11 +8146,11 @@ async function runServiceCommand(service, options) {
9828
8146
  async function inputFile() {
9829
8147
  if (!values.input)
9830
8148
  throw new Error("This operation requires --input <json-file>.");
9831
- const filename = path28.resolve(options.cwd ?? process.cwd(), values.input);
8149
+ const filename = path24.resolve(options.cwd ?? process.cwd(), values.input);
9832
8150
  const info = await stat(filename);
9833
8151
  if (!info.isFile() || info.size > 512 * 1024)
9834
8152
  throw new Error("Use a JSON file smaller than 512 KB.");
9835
- return JSON.parse(await readFile16(filename, "utf8"));
8153
+ return JSON.parse(await readFile15(filename, "utf8"));
9836
8154
  }
9837
8155
  const site = common ? `/sites/${encodeURIComponent(common.resourceId)}` : "";
9838
8156
  let result;
@@ -9852,9 +8170,9 @@ async function runServiceCommand(service, options) {
9852
8170
  await inputFile(),
9853
8171
  "cookie:workspace:read"
9854
8172
  );
9855
- const validation = z16.object({
9856
- valid: z16.boolean(),
9857
- draftVersionMatches: z16.boolean().optional()
8173
+ const validation = z13.object({
8174
+ valid: z13.boolean(),
8175
+ draftVersionMatches: z13.boolean().optional()
9858
8176
  }).parse(result);
9859
8177
  if (!validation.valid || validation.draftVersionMatches === false)
9860
8178
  return { exitCode: 2, stdout: JSON.stringify(result, null, 2) };
@@ -9893,11 +8211,11 @@ async function runServiceCommand(service, options) {
9893
8211
  } else if (action === "installation")
9894
8212
  result = await request(`${site}/installation`);
9895
8213
  else if (action === "draft" && subaction === "get" && positionals.length === 2) {
9896
- const response = z16.object({
9897
- name: z16.string(),
9898
- hostname: z16.string(),
9899
- draftVersion: z16.number(),
9900
- draft: z16.unknown()
8214
+ const response = z13.object({
8215
+ name: z13.string(),
8216
+ hostname: z13.string(),
8217
+ draftVersion: z13.number(),
8218
+ draft: z13.unknown()
9901
8219
  }).parse(await request(site));
9902
8220
  result = {
9903
8221
  name: response.name,
@@ -9929,9 +8247,9 @@ async function runServiceCommand(service, options) {
9929
8247
  else if (action === "environments" && positionals.length === 1)
9930
8248
  result = await request(`${site}/environments`);
9931
8249
  else if (action === "report" || action === "installation" || action === "tracking-plan" || explorerSuffix !== null) {
9932
- const response = z16.object({
9933
- environments: z16.array(
9934
- z16.object({ id: z16.string(), slug: z16.string() })
8250
+ const response = z13.object({
8251
+ environments: z13.array(
8252
+ z13.object({ id: z13.string(), slug: z13.string() })
9935
8253
  )
9936
8254
  }).parse(await request(`${site}/environments`));
9937
8255
  const environment = common.overview.project.environments.find(
@@ -9958,11 +8276,11 @@ async function runServiceCommand(service, options) {
9958
8276
  if (explorerSuffix !== null) {
9959
8277
  result = await request(`${base}${explorerSuffix}`);
9960
8278
  } else if (action === "report" && positionals.length === 1) {
9961
- const detail = z16.object({
9962
- site: z16.object({
9963
- id: z16.literal(common.resourceId),
9964
- environments: z16.array(
9965
- z16.object({ id: z16.string(), evidence: z16.unknown() })
8279
+ const detail = z13.object({
8280
+ site: z13.object({
8281
+ id: z13.literal(common.resourceId),
8282
+ environments: z13.array(
8283
+ z13.object({ id: z13.string(), evidence: z13.unknown() })
9966
8284
  )
9967
8285
  })
9968
8286
  }).parse(await request(site));
@@ -10020,16 +8338,16 @@ async function runServiceCommand(service, options) {
10020
8338
  } catch (cause) {
10021
8339
  return {
10022
8340
  exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
10023
- stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof z16.ZodError) && cause instanceof Error ? cause.message : "The service returned an invalid response."
8341
+ stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof z13.ZodError) && cause instanceof Error ? cause.message : "The service returned an invalid response."
10024
8342
  };
10025
8343
  }
10026
8344
  }
10027
8345
 
10028
8346
  // src/services/analytics-command.ts
10029
- import { readFile as readFile17, stat as stat2 } from "fs/promises";
10030
- import path29 from "path";
8347
+ import { readFile as readFile16, stat as stat2 } from "fs/promises";
8348
+ import path25 from "path";
10031
8349
  import { parseArgs as parseArgs4 } from "util";
10032
- import { z as z17 } from "zod";
8350
+ import { z as z14 } from "zod";
10033
8351
  var ANALYTICS_HELP = `Set up website Analytics in the selected Project environment.
10034
8352
 
10035
8353
  Usage:
@@ -10060,27 +8378,27 @@ Settings require an owner/admin, the current revision and at least one change.
10060
8378
  Catalog files are bounded JSON using the documented event/campaign/goal/funnel contracts.
10061
8379
  Monitoring preparation creates a Trace draft only; publication remains a separate operation.
10062
8380
  Analytics is Unlimited during early access. No synthetic events are sent by these commands.`;
10063
- var EventInput = z17.object({
10064
- name: z17.string().regex(/^[a-z][a-z0-9_]{0,63}$/u).refine((v) => v !== "pageview" && !v.startsWith("cookie_")),
10065
- label: z17.string().trim().min(1).max(80),
10066
- properties: z17.record(
10067
- z17.string().regex(/^[a-z][a-z0-9_]{0,39}$/u),
10068
- z17.array(
10069
- z17.string().min(1).max(80).regex(/^[a-zA-Z0-9 _./:-]+$/u)
8381
+ var EventInput = z14.object({
8382
+ name: z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/u).refine((v) => v !== "pageview" && !v.startsWith("cookie_")),
8383
+ label: z14.string().trim().min(1).max(80),
8384
+ properties: z14.record(
8385
+ z14.string().regex(/^[a-z][a-z0-9_]{0,39}$/u),
8386
+ z14.array(
8387
+ z14.string().min(1).max(80).regex(/^[a-zA-Z0-9 _./:-]+$/u)
10070
8388
  ).min(1).max(20)
10071
8389
  ).refine((v) => Object.keys(v).length <= 8)
10072
8390
  }).strict();
10073
- var Resource = z17.object({
10074
- id: z17.string(),
10075
- organizationId: z17.string(),
10076
- name: z17.string(),
10077
- slug: z17.string(),
10078
- origin: z17.string().url(),
10079
- publicKey: z17.string(),
10080
- revision: z17.number().int().positive(),
10081
- enabled: z17.boolean(),
10082
- cookieEvents: z17.boolean(),
10083
- minimalRealtime: z17.boolean()
8391
+ var Resource = z14.object({
8392
+ id: z14.string(),
8393
+ organizationId: z14.string(),
8394
+ name: z14.string(),
8395
+ slug: z14.string(),
8396
+ origin: z14.string().url(),
8397
+ publicKey: z14.string(),
8398
+ revision: z14.number().int().positive(),
8399
+ enabled: z14.boolean(),
8400
+ cookieEvents: z14.boolean(),
8401
+ minimalRealtime: z14.boolean()
10084
8402
  });
10085
8403
  var readKeys = [
10086
8404
  "days",
@@ -10210,7 +8528,7 @@ async function runAnalyticsCommand(options) {
10210
8528
  throw new Error("Use --days 1, 7 or 28.");
10211
8529
  if (values.country && !/^(?:[A-Z]{2}|unknown)$/u.test(values.country))
10212
8530
  throw new Error("Use an uppercase ISO country code or unknown.");
10213
- if (values.campaign) z17.string().uuid().parse(values.campaign);
8531
+ if (values.campaign) z14.string().uuid().parse(values.campaign);
10214
8532
  const setting = route === "settings set", creating = positionals[1] === "create", archive = positionals[1] === "archive";
10215
8533
  let body;
10216
8534
  if (setting) {
@@ -10234,10 +8552,10 @@ async function runAnalyticsCommand(options) {
10234
8552
  } else if (creating) {
10235
8553
  if (!values.file)
10236
8554
  throw new Error("Creation requires --file with a JSON definition.");
10237
- const filename = path29.resolve(options.cwd ?? process.cwd(), values.file);
8555
+ const filename = path25.resolve(options.cwd ?? process.cwd(), values.file);
10238
8556
  if ((await stat2(filename)).size > 16384)
10239
8557
  throw new Error("The definition must not exceed 16 KiB.");
10240
- const text = await readFile17(filename, "utf8");
8558
+ const text = await readFile16(filename, "utf8");
10241
8559
  if (Buffer.byteLength(text) > 16384)
10242
8560
  throw new Error("The definition must not exceed 16 KiB.");
10243
8561
  let definition;
@@ -10246,9 +8564,9 @@ async function runAnalyticsCommand(options) {
10246
8564
  } catch {
10247
8565
  throw new Error("The definition must contain valid JSON.");
10248
8566
  }
10249
- body = z17.record(z17.unknown()).parse(definition);
8567
+ body = z14.record(z14.unknown()).parse(definition);
10250
8568
  if (action === "events") body = EventInput.parse(body);
10251
- } else if (archive) body = { id: z17.string().uuid().parse(positionals[2]) };
8569
+ } else if (archive) body = { id: z14.string().uuid().parse(positionals[2]) };
10252
8570
  const context = await commonServiceContext(
10253
8571
  options,
10254
8572
  "analytics",
@@ -10295,8 +8613,8 @@ async function runAnalyticsCommand(options) {
10295
8613
  );
10296
8614
  const value = await response.json();
10297
8615
  if (!response.ok) {
10298
- const error = z17.object({
10299
- error: z17.object({ code: z17.string(), message: z17.string().max(500) })
8616
+ const error = z14.object({
8617
+ error: z14.object({ code: z14.string(), message: z14.string().max(500) })
10300
8618
  }).safeParse(value);
10301
8619
  throw new SiteOSAuthApiError({
10302
8620
  code: error.success ? error.data.error.code : "ANALYTICS_REQUEST_FAILED",
@@ -10304,9 +8622,9 @@ async function runAnalyticsCommand(options) {
10304
8622
  status: response.status
10305
8623
  });
10306
8624
  }
10307
- const record = z17.object({
10308
- contractVersion: z17.literal(1),
10309
- resourceId: z17.literal(context.resourceId)
8625
+ const record = z14.object({
8626
+ contractVersion: z14.literal(1),
8627
+ resourceId: z14.literal(context.resourceId)
10310
8628
  }).passthrough().parse(value);
10311
8629
  let output;
10312
8630
  if (setting) {
@@ -10325,16 +8643,16 @@ async function runAnalyticsCommand(options) {
10325
8643
  throw new Error("The saved event does not match this definition.");
10326
8644
  } else
10327
8645
  output = {
10328
- id: z17.string().uuid().parse(record.id),
8646
+ id: z14.string().uuid().parse(record.id),
10329
8647
  ...pick(
10330
8648
  record,
10331
8649
  action === "campaigns" ? ["label", "source", "medium", "campaign"] : action === "goals" ? ["label", "match"] : ["label", "steps"]
10332
8650
  )
10333
8651
  };
10334
8652
  } else if (archive)
10335
- output = { archived: z17.literal(true).parse(record.archived) };
8653
+ output = { archived: z14.literal(true).parse(record.archived) };
10336
8654
  else if (route === "monitoring prepare")
10337
- output = { state: z17.literal("prepared").parse(record.state) };
8655
+ output = { state: z14.literal("prepared").parse(record.state) };
10338
8656
  else if (action === "realtime") output = pick(record, liveKeys);
10339
8657
  else {
10340
8658
  const resource = Resource.parse(record.resource);
@@ -10346,8 +8664,8 @@ async function runAnalyticsCommand(options) {
10346
8664
  output = {
10347
8665
  resource,
10348
8666
  lastReceivedAt: record.lastReceivedAt,
10349
- consentSource: z17.object({
10350
- consentSource: z17.enum([
8667
+ consentSource: z14.object({
8668
+ consentSource: z14.enum([
10351
8669
  "cookie",
10352
8670
  "external",
10353
8671
  "waiting_for_cookie",
@@ -10359,11 +8677,11 @@ async function runAnalyticsCommand(options) {
10359
8677
  else if (action === "installation")
10360
8678
  output = {
10361
8679
  resource,
10362
- installation: z17.string().parse(record.installation),
8680
+ installation: z14.string().parse(record.installation),
10363
8681
  configuration: record.configuration
10364
8682
  };
10365
8683
  else if (action === "events") {
10366
- const definitions = z17.array(EventInput).parse(record.definitions);
8684
+ const definitions = z14.array(EventInput).parse(record.definitions);
10367
8685
  if (route === "events snippet") {
10368
8686
  const definition = definitions.find((d) => d.name === positionals[2]);
10369
8687
  if (!definition)
@@ -10377,13 +8695,13 @@ async function runAnalyticsCommand(options) {
10377
8695
  };
10378
8696
  } else output = { definitions, eventCounts: record.eventCounts };
10379
8697
  } else
10380
- output = action === "report" ? pick(record, readKeys) : { [action]: z17.array(z17.unknown()).parse(record[action]) };
8698
+ output = action === "report" ? pick(record, readKeys) : { [action]: z14.array(z14.unknown()).parse(record[action]) };
10381
8699
  }
10382
8700
  return { exitCode: 0, stdout: JSON.stringify(output, null, 2) };
10383
8701
  } catch (cause) {
10384
8702
  const error = cause instanceof SiteOSAuthApiError ? { code: cause.code, message: cause.message } : {
10385
8703
  code: "ANALYTICS_COMMAND_FAILED",
10386
- message: cause instanceof z17.ZodError ? "The Analytics input or response does not match the supported contract." : cause instanceof Error ? cause.message : "The Analytics command failed."
8704
+ message: cause instanceof z14.ZodError ? "The Analytics input or response does not match the supported contract." : cause instanceof Error ? cause.message : "The Analytics command failed."
10387
8705
  };
10388
8706
  return {
10389
8707
  exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
@@ -10394,20 +8712,20 @@ async function runAnalyticsCommand(options) {
10394
8712
 
10395
8713
  // src/services/seo-command.ts
10396
8714
  import { writeFile as writeFile10 } from "fs/promises";
10397
- import path32 from "path";
8715
+ import path28 from "path";
10398
8716
  import { parseArgs as parseArgs8 } from "util";
10399
- import { z as z22 } from "zod";
8717
+ import { z as z19 } from "zod";
10400
8718
 
10401
8719
  // src/services/seo-research-command.ts
10402
8720
  import { randomUUID as randomUUID6 } from "crypto";
10403
8721
  import { setTimeout as setTimeout2 } from "timers/promises";
10404
8722
  import { isDeepStrictEqual, parseArgs as parseArgs5 } from "util";
10405
- import { z as z19 } from "zod";
8723
+ import { z as z16 } from "zod";
10406
8724
 
10407
8725
  // src/services/seo-report-client.ts
10408
8726
  import { open, writeFile as writeFile8 } from "fs/promises";
10409
- import path30 from "path";
10410
- import { z as z18 } from "zod";
8727
+ import path26 from "path";
8728
+ import { z as z15 } from "zod";
10411
8729
  async function seoReportClient(options, environment) {
10412
8730
  const context = await commonServiceContext(options, "seo", environment);
10413
8731
  if (!context)
@@ -10442,8 +8760,8 @@ async function seoReportClient(options, environment) {
10442
8760
  }
10443
8761
  );
10444
8762
  if (!response.ok) {
10445
- const result = z18.object({
10446
- error: z18.object({ code: z18.string(), message: z18.string().max(500) })
8763
+ const result = z15.object({
8764
+ error: z15.object({ code: z15.string(), message: z15.string().max(500) })
10447
8765
  }).safeParse(await response.json());
10448
8766
  throw new SiteOSAuthApiError({
10449
8767
  code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
@@ -10457,9 +8775,9 @@ async function seoReportClient(options, environment) {
10457
8775
  }
10458
8776
  };
10459
8777
  }
10460
- var versionedReport = z18.object({ contractVersion: z18.literal(1) }).passthrough();
8778
+ var versionedReport = z15.object({ contractVersion: z15.literal(1) }).passthrough();
10461
8779
  async function readSeoInput(cwd, filename) {
10462
- const file = await open(path30.resolve(cwd ?? process.cwd(), filename), "r");
8780
+ const file = await open(path26.resolve(cwd ?? process.cwd(), filename), "r");
10463
8781
  try {
10464
8782
  const stat3 = await file.stat();
10465
8783
  if (!stat3.isFile() || stat3.size > 32e3)
@@ -10483,14 +8801,14 @@ async function readSeoInput(cwd, filename) {
10483
8801
  }
10484
8802
  }
10485
8803
  async function writeSeoReport(options, filename, content) {
10486
- const output = path30.resolve(options.cwd ?? process.cwd(), filename);
8804
+ const output = path26.resolve(options.cwd ?? process.cwd(), filename);
10487
8805
  await writeFile8(output, content, { flag: "wx", mode: 384 });
10488
8806
  return output;
10489
8807
  }
10490
8808
  function seoReportFailure(cause, json, idempotencyKey) {
10491
8809
  const error = {
10492
8810
  code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
10493
- message: cause instanceof z18.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
8811
+ message: cause instanceof z15.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
10494
8812
  };
10495
8813
  return {
10496
8814
  exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
@@ -10546,11 +8864,11 @@ var kinds = [
10546
8864
  "brand",
10547
8865
  "ai-visibility"
10548
8866
  ];
10549
- var requestSchema = z19.object({
10550
- kind: z19.enum(["domain", ...kinds]).transform((kind) => kind === "domain" ? "competitors" : kind),
10551
- target: z19.string().min(1).max(253)
8867
+ var requestSchema = z16.object({
8868
+ kind: z16.enum(["domain", ...kinds]).transform((kind) => kind === "domain" ? "competitors" : kind),
8869
+ target: z16.string().min(1).max(253)
10552
8870
  }).passthrough();
10553
- var runStates = z19.enum([
8871
+ var runStates = z16.enum([
10554
8872
  "queued",
10555
8873
  "running",
10556
8874
  "completed",
@@ -10647,26 +8965,26 @@ async function runSeoResearchCommand(options) {
10647
8965
  );
10648
8966
  }
10649
8967
  const client = await seoReportClient(options, values.environment);
10650
- const resourceSchema = z19.object({
10651
- id: z19.literal(client.resourceId),
10652
- organizationId: z19.literal(client.organizationId)
8968
+ const resourceSchema = z16.object({
8969
+ id: z16.literal(client.resourceId),
8970
+ organizationId: z16.literal(client.organizationId)
10653
8971
  }).passthrough();
10654
- const runSchema = z19.object({
10655
- id: z19.string(),
10656
- resourceId: z19.literal(client.resourceId),
10657
- organizationId: z19.literal(client.organizationId),
10658
- websiteUrl: z19.string(),
8972
+ const runSchema = z16.object({
8973
+ id: z16.string(),
8974
+ resourceId: z16.literal(client.resourceId),
8975
+ organizationId: z16.literal(client.organizationId),
8976
+ websiteUrl: z16.string(),
10659
8977
  request: requestSchema,
10660
8978
  state: runStates,
10661
- createdAt: z19.string(),
10662
- finishedAt: z19.string().nullable(),
10663
- parts: z19.array(
10664
- z19.object({
10665
- key: z19.string(),
10666
- state: z19.enum(["completed", "failed"]),
10667
- error: z19.string().nullable(),
10668
- dataset: z19.record(z19.unknown()).nullable(),
10669
- observedAt: z19.string()
8979
+ createdAt: z16.string(),
8980
+ finishedAt: z16.string().nullable(),
8981
+ parts: z16.array(
8982
+ z16.object({
8983
+ key: z16.string(),
8984
+ state: z16.enum(["completed", "failed"]),
8985
+ error: z16.string().nullable(),
8986
+ dataset: z16.record(z16.unknown()).nullable(),
8987
+ observedAt: z16.string()
10670
8988
  }).passthrough()
10671
8989
  )
10672
8990
  }).passthrough();
@@ -10680,36 +8998,36 @@ async function runSeoResearchCommand(options) {
10680
8998
  const query = `?kind=${encodeURIComponent(values.kind ?? "rankings")}`;
10681
8999
  let record;
10682
9000
  if (action.startsWith("serp ")) {
10683
- const snapshotSchema = z19.object({
10684
- id: z19.string(),
10685
- organizationId: z19.literal(client.organizationId),
10686
- resourceId: z19.literal(client.resourceId),
10687
- sourceRunId: z19.literal(id),
9001
+ const snapshotSchema = z16.object({
9002
+ id: z16.string(),
9003
+ organizationId: z16.literal(client.organizationId),
9004
+ resourceId: z16.literal(client.resourceId),
9005
+ sourceRunId: z16.literal(id),
10688
9006
  request: requestSchema,
10689
- keywordKey: z19.literal(
9007
+ keywordKey: z16.literal(
10690
9008
  values.keyword.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, " ")
10691
9009
  ),
10692
- state: z19.enum([
9010
+ state: z16.enum([
10693
9011
  "queued",
10694
9012
  "running",
10695
9013
  "completed",
10696
9014
  "failed",
10697
9015
  "cancelled"
10698
9016
  ]),
10699
- dataset: z19.object({
10700
- type: z19.literal("serp"),
10701
- keyword: z19.string(),
10702
- country: z19.string(),
10703
- language: z19.string(),
10704
- device: z19.enum(["desktop", "mobile"]),
10705
- observedAt: z19.string(),
10706
- rows: z19.array(
10707
- z19.object({
10708
- position: z19.number(),
10709
- title: z19.string(),
10710
- url: z19.string(),
10711
- domain: z19.string(),
10712
- description: z19.string()
9017
+ dataset: z16.object({
9018
+ type: z16.literal("serp"),
9019
+ keyword: z16.string(),
9020
+ country: z16.string(),
9021
+ language: z16.string(),
9022
+ device: z16.enum(["desktop", "mobile"]),
9023
+ observedAt: z16.string(),
9024
+ rows: z16.array(
9025
+ z16.object({
9026
+ position: z16.number(),
9027
+ title: z16.string(),
9028
+ url: z16.string(),
9029
+ domain: z16.string(),
9030
+ description: z16.string()
10713
9031
  })
10714
9032
  )
10715
9033
  }).nullable()
@@ -10802,9 +9120,9 @@ async function runSeoResearchCommand(options) {
10802
9120
  name: values.name.trim(),
10803
9121
  ...values.id ? { id: values.id } : {}
10804
9122
  });
10805
- const saved = z19.object({
10806
- id: z19.string(),
10807
- name: z19.literal(values.name.trim()),
9123
+ const saved = z16.object({
9124
+ id: z16.string(),
9125
+ name: z16.literal(values.name.trim()),
10808
9126
  request: requestSchema
10809
9127
  }).parse(record.saved);
10810
9128
  if (values.id && saved.id !== values.id || !isDeepStrictEqual(saved.request, plan.request))
@@ -10818,23 +9136,23 @@ async function runSeoResearchCommand(options) {
10818
9136
  action === "cancel" ? "run" : "write",
10819
9137
  {}
10820
9138
  );
10821
- z19.literal(true).parse(
9139
+ z16.literal(true).parse(
10822
9140
  record[action === "cancel" ? "cancelled" : "removed"]
10823
9141
  );
10824
9142
  } else if (action === "summary") {
10825
9143
  record = await get("/summary");
10826
9144
  resourceSchema.parse(record.resource);
10827
- z19.array(z19.object({ kind: z19.enum(kinds), summary: z19.unknown() })).parse(
9145
+ z16.array(z16.object({ kind: z16.enum(kinds), summary: z16.unknown() })).parse(
10828
9146
  record.checks
10829
9147
  );
10830
9148
  } else if (["status", "history", "saved list"].includes(action)) {
10831
9149
  const view = await get(query);
10832
9150
  resourceSchema.parse(view.resource);
10833
- const runs = z19.array(runSchema).parse(view.runs);
10834
- const saved = z19.array(
10835
- z19.object({
10836
- id: z19.string(),
10837
- name: z19.string(),
9151
+ const runs = z16.array(runSchema).parse(view.runs);
9152
+ const saved = z16.array(
9153
+ z16.object({
9154
+ id: z16.string(),
9155
+ name: z16.string(),
10838
9156
  request: requestSchema
10839
9157
  }).passthrough()
10840
9158
  ).parse(view.saved);
@@ -10951,7 +9269,7 @@ async function runSeoResearchCommand(options) {
10951
9269
 
10952
9270
  // src/services/seo-gsc-command.ts
10953
9271
  import { parseArgs as parseArgs6 } from "util";
10954
- import { z as z20 } from "zod";
9272
+ import { z as z17 } from "zod";
10955
9273
  var GSC_HELP = `
10956
9274
  siteos seo gsc status [--environment <slug>] [--json]
10957
9275
  siteos seo gsc report [--dataset <pages|queries>] [--query <text>] [--filter <all|issues|declining>] [--sort <clicks|change|impressions>] [--page <number>] [--url <page-url>] [--environment <slug>] [--json]
@@ -11051,13 +9369,13 @@ async function runSeoGscCommand(options) {
11051
9369
  `seo:search:${action === "sync" ? "sync" : writing ? "write" : "read"}`,
11052
9370
  body
11053
9371
  );
11054
- const runSchema = z20.object({
11055
- id: z20.string(),
11056
- resourceId: z20.literal(client.resourceId),
11057
- organizationId: z20.literal(client.organizationId),
11058
- websiteUrl: z20.string(),
11059
- siteUrl: z20.string(),
11060
- state: z20.enum([
9372
+ const runSchema = z17.object({
9373
+ id: z17.string(),
9374
+ resourceId: z17.literal(client.resourceId),
9375
+ organizationId: z17.literal(client.organizationId),
9376
+ websiteUrl: z17.string(),
9377
+ siteUrl: z17.string(),
9378
+ state: z17.enum([
11061
9379
  "queued",
11062
9380
  "running",
11063
9381
  "completed",
@@ -11065,32 +9383,32 @@ async function runSeoGscCommand(options) {
11065
9383
  "failed",
11066
9384
  "cancelled"
11067
9385
  ]),
11068
- dates: z20.unknown()
9386
+ dates: z17.unknown()
11069
9387
  }).passthrough();
11070
- const bindingSchema = z20.object({
11071
- resourceId: z20.literal(client.resourceId),
11072
- organizationId: z20.literal(client.organizationId),
11073
- websiteUrl: z20.string(),
11074
- siteUrl: z20.string(),
11075
- revision: z20.number().int().positive()
9388
+ const bindingSchema = z17.object({
9389
+ resourceId: z17.literal(client.resourceId),
9390
+ organizationId: z17.literal(client.organizationId),
9391
+ websiteUrl: z17.string(),
9392
+ siteUrl: z17.string(),
9393
+ revision: z17.number().int().positive()
11076
9394
  }).passthrough();
11077
- const metrics = z20.object({
11078
- clicks: z20.number(),
11079
- impressions: z20.number(),
11080
- ctr: z20.number(),
11081
- position: z20.number()
9395
+ const metrics = z17.object({
9396
+ clicks: z17.number(),
9397
+ impressions: z17.number(),
9398
+ ctr: z17.number(),
9399
+ position: z17.number()
11082
9400
  }).passthrough().nullable();
11083
9401
  const validateView = (data) => {
11084
9402
  const record2 = versionedReport.parse(data);
11085
- z20.literal(client.resourceId).parse(record2.resourceId);
9403
+ z17.literal(client.resourceId).parse(record2.resourceId);
11086
9404
  bindingSchema.nullable().parse(record2.binding);
11087
9405
  runSchema.nullable().parse(record2.latest);
11088
9406
  runSchema.nullable().parse(record2.report);
11089
- z20.array(
11090
- z20.object({ key: z20.string(), current: metrics, previous: metrics }).passthrough()
9407
+ z17.array(
9408
+ z17.object({ key: z17.string(), current: metrics, previous: metrics }).passthrough()
11091
9409
  ).parse(record2.rows);
11092
- z20.number().int().nonnegative().parse(record2.total);
11093
- z20.literal(values.dataset ?? "pages").parse(record2.dataset);
9410
+ z17.number().int().nonnegative().parse(record2.total);
9411
+ z17.literal(values.dataset ?? "pages").parse(record2.dataset);
11094
9412
  return record2;
11095
9413
  };
11096
9414
  if (action === "export") {
@@ -11106,9 +9424,9 @@ async function runSeoGscCommand(options) {
11106
9424
  const text = await response.text();
11107
9425
  if (values.format === "json") {
11108
9426
  const report = validateView(JSON.parse(text));
11109
- z20.literal(reportId).parse(runSchema.parse(report.report).id);
11110
- z20.array(z20.unknown()).length(rows).parse(report.rows);
11111
- z20.literal(truncated === "true").parse(report.truncated);
9427
+ z17.literal(reportId).parse(runSchema.parse(report.report).id);
9428
+ z17.array(z17.unknown()).length(rows).parse(report.rows);
9429
+ z17.literal(truncated === "true").parse(report.truncated);
11112
9430
  }
11113
9431
  const output = await writeSeoReport(options, values.output, text);
11114
9432
  return {
@@ -11129,7 +9447,7 @@ async function runSeoGscCommand(options) {
11129
9447
  };
11130
9448
  }
11131
9449
  const record = versionedReport.parse(await response.json());
11132
- if (action === "disconnect") z20.literal(true).parse(record.unbound);
9450
+ if (action === "disconnect") z17.literal(true).parse(record.unbound);
11133
9451
  else if (writing) {
11134
9452
  runSchema.parse(record.run);
11135
9453
  if (action === "bind") {
@@ -11149,10 +9467,10 @@ async function runSeoGscCommand(options) {
11149
9467
  // src/services/seo-performance-command.ts
11150
9468
  import { randomUUID as randomUUID7 } from "crypto";
11151
9469
  import { writeFile as writeFile9 } from "fs/promises";
11152
- import path31 from "path";
9470
+ import path27 from "path";
11153
9471
  import { setTimeout as setTimeout3 } from "timers/promises";
11154
9472
  import { parseArgs as parseArgs7 } from "util";
11155
- import { z as z21 } from "zod";
9473
+ import { z as z18 } from "zod";
11156
9474
  var PERFORMANCE_HELP = `
11157
9475
  siteos seo performance run --audit <id> --url <url> [--url <url>...] [--device <mobile|desktop>] [--idempotency-key <key>] [--environment <slug>] [--json]
11158
9476
  siteos seo performance list [--device <mobile|desktop>] [--environment <slug>] [--json]
@@ -11240,12 +9558,12 @@ async function runSeoPerformanceCommand(options) {
11240
9558
  const runtime = commonProjectRuntime(options);
11241
9559
  const writing = ["run", "cancel"].includes(action);
11242
9560
  const scope = writing ? "seo:audits:write" : "seo:workspace:read";
11243
- const batchSchema = z21.object({
11244
- id: z21.string(),
11245
- resourceId: z21.literal(context.resourceId),
11246
- organizationId: z21.literal(context.overview.project.organizationId),
11247
- sourceAuditId: z21.string(),
11248
- state: z21.enum([
9561
+ const batchSchema = z18.object({
9562
+ id: z18.string(),
9563
+ resourceId: z18.literal(context.resourceId),
9564
+ organizationId: z18.literal(context.overview.project.organizationId),
9565
+ sourceAuditId: z18.string(),
9566
+ state: z18.enum([
11249
9567
  "queued",
11250
9568
  "running",
11251
9569
  "completed",
@@ -11253,8 +9571,8 @@ async function runSeoPerformanceCommand(options) {
11253
9571
  "failed",
11254
9572
  "cancelled"
11255
9573
  ]),
11256
- device: z21.enum(["mobile", "desktop"]),
11257
- urls: z21.array(z21.string()).min(1).max(10)
9574
+ device: z18.enum(["mobile", "desktop"]),
9575
+ urls: z18.array(z18.string()).min(1).max(10)
11258
9576
  }).passthrough();
11259
9577
  const query = new URLSearchParams();
11260
9578
  if (values.device) query.set("device", values.device);
@@ -11302,17 +9620,17 @@ async function runSeoPerformanceCommand(options) {
11302
9620
  );
11303
9621
  const text = await response.text();
11304
9622
  if (values.format === "json") {
11305
- const parsed = z21.object({
11306
- contractVersion: z21.literal(1),
9623
+ const parsed = z18.object({
9624
+ contractVersion: z18.literal(1),
11307
9625
  batch: batchSchema,
11308
- pages: z21.array(z21.unknown())
9626
+ pages: z18.array(z18.unknown())
11309
9627
  }).parse(JSON.parse(text));
11310
9628
  if (parsed.batch.id !== id)
11311
9629
  throw new Error(
11312
9630
  "The export response does not match the selected check."
11313
9631
  );
11314
9632
  }
11315
- const output = path31.resolve(
9633
+ const output = path27.resolve(
11316
9634
  options.cwd ?? process.cwd(),
11317
9635
  values.output
11318
9636
  );
@@ -11328,8 +9646,8 @@ async function runSeoPerformanceCommand(options) {
11328
9646
  }
11329
9647
  const data = await response.json();
11330
9648
  if (!response.ok) {
11331
- const error = z21.object({
11332
- error: z21.object({ code: z21.string(), message: z21.string().max(500) })
9649
+ const error = z18.object({
9650
+ error: z18.object({ code: z18.string(), message: z18.string().max(500) })
11333
9651
  }).safeParse(data);
11334
9652
  throw new SiteOSAuthApiError({
11335
9653
  code: error.success ? error.data.error.code : "SEO_REQUEST_FAILED",
@@ -11337,8 +9655,8 @@ async function runSeoPerformanceCommand(options) {
11337
9655
  status: response.status
11338
9656
  });
11339
9657
  }
11340
- const record = z21.object({ contractVersion: z21.literal(1) }).passthrough().parse(data);
11341
- if (action === "cancel") z21.literal(true).parse(record.cancelled);
9658
+ const record = z18.object({ contractVersion: z18.literal(1) }).passthrough().parse(data);
9659
+ if (action === "cancel") z18.literal(true).parse(record.cancelled);
11342
9660
  else if (action === "run") {
11343
9661
  const accepted = batchSchema.parse(record.batch);
11344
9662
  const normalize = (url) => {
@@ -11351,8 +9669,8 @@ async function runSeoPerformanceCommand(options) {
11351
9669
  "The queued check does not match the requested source, device and URLs."
11352
9670
  );
11353
9671
  } else {
11354
- z21.literal(context.resourceId).parse(record.resourceId);
11355
- z21.array(batchSchema).parse(record.batches);
9672
+ z18.literal(context.resourceId).parse(record.resourceId);
9673
+ z18.array(batchSchema).parse(record.batches);
11356
9674
  const selected = batchSchema.nullable().parse(record.batch);
11357
9675
  if (id && selected?.id !== id)
11358
9676
  throw new Error(
@@ -11379,7 +9697,7 @@ async function runSeoPerformanceCommand(options) {
11379
9697
  } catch (cause) {
11380
9698
  const error = {
11381
9699
  code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
11382
- message: cause instanceof z21.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The performance command failed."
9700
+ message: cause instanceof z18.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The performance command failed."
11383
9701
  };
11384
9702
  return {
11385
9703
  exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
@@ -11659,17 +9977,17 @@ async function runSeoCommand(options) {
11659
9977
  );
11660
9978
  const text = await response.text();
11661
9979
  if (values.format === "json")
11662
- z22.object({
11663
- contractVersion: z22.literal(1),
11664
- audit: z22.object({
11665
- id: z22.literal(values.audit),
11666
- resourceId: z22.literal(context.resourceId)
9980
+ z19.object({
9981
+ contractVersion: z19.literal(1),
9982
+ audit: z19.object({
9983
+ id: z19.literal(values.audit),
9984
+ resourceId: z19.literal(context.resourceId)
11667
9985
  }),
11668
- kind: z22.literal(values.kind),
11669
- totalRows: z22.literal(rows),
11670
- rows: z22.array(z22.unknown()).length(rows)
9986
+ kind: z19.literal(values.kind),
9987
+ totalRows: z19.literal(rows),
9988
+ rows: z19.array(z19.unknown()).length(rows)
11671
9989
  }).parse(JSON.parse(text));
11672
- const output = path32.resolve(options.cwd ?? process.cwd(), values.output);
9990
+ const output = path28.resolve(options.cwd ?? process.cwd(), values.output);
11673
9991
  await writeFile10(output, text, { flag: "wx", mode: 384 });
11674
9992
  return {
11675
9993
  exitCode: 0,
@@ -11688,8 +10006,8 @@ async function runSeoCommand(options) {
11688
10006
  }
11689
10007
  const data = await response.json();
11690
10008
  if (!response.ok) {
11691
- const result = z22.object({
11692
- error: z22.object({ code: z22.string(), message: z22.string().max(500) })
10009
+ const result = z19.object({
10010
+ error: z19.object({ code: z19.string(), message: z19.string().max(500) })
11693
10011
  }).safeParse(data);
11694
10012
  throw new SiteOSAuthApiError({
11695
10013
  code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
@@ -11697,34 +10015,34 @@ async function runSeoCommand(options) {
11697
10015
  status: response.status
11698
10016
  });
11699
10017
  }
11700
- const record = z22.object({ contractVersion: z22.literal(1) }).passthrough().parse(data);
10018
+ const record = z19.object({ contractVersion: z19.literal(1) }).passthrough().parse(data);
11701
10019
  if (automation) {
11702
- z22.literal(context.resourceId).parse(record.resourceId);
11703
- const schedule = z22.object({
11704
- enabled: z22.boolean(),
11705
- weekday: z22.number().int().min(1).max(7),
11706
- time: z22.string(),
11707
- timeZone: z22.string(),
11708
- revision: z22.number().int().min(0),
11709
- nextRunAt: z22.string().nullable()
10020
+ z19.literal(context.resourceId).parse(record.resourceId);
10021
+ const schedule = z19.object({
10022
+ enabled: z19.boolean(),
10023
+ weekday: z19.number().int().min(1).max(7),
10024
+ time: z19.string(),
10025
+ timeZone: z19.string(),
10026
+ revision: z19.number().int().min(0),
10027
+ nextRunAt: z19.string().nullable()
11710
10028
  });
11711
- const notificationRoute = z22.object({
11712
- enabled: z22.boolean(),
11713
- minimumSeverity: z22.enum(["error", "warning"]),
11714
- includeFailures: z22.boolean(),
11715
- revision: z22.number().int().min(0),
11716
- destinationId: z22.string().nullable()
10029
+ const notificationRoute = z19.object({
10030
+ enabled: z19.boolean(),
10031
+ minimumSeverity: z19.enum(["error", "warning"]),
10032
+ includeFailures: z19.boolean(),
10033
+ revision: z19.number().int().min(0),
10034
+ destinationId: z19.string().nullable()
11717
10035
  });
11718
10036
  if (retryNotification) {
11719
- z22.literal(true).parse(record.retryQueued);
11720
- z22.literal(positionals[2]).parse(record.notificationId);
10037
+ z19.literal(true).parse(record.retryQueued);
10038
+ z19.literal(positionals[2]).parse(record.notificationId);
11721
10039
  } else if (route === "notifications destinations")
11722
- z22.object({
11723
- candidates: z22.array(
11724
- z22.object({
11725
- candidateId: z22.string(),
11726
- label: z22.string(),
11727
- availability: z22.literal("available")
10040
+ z19.object({
10041
+ candidates: z19.array(
10042
+ z19.object({
10043
+ candidateId: z19.string(),
10044
+ label: z19.string(),
10045
+ availability: z19.literal("available")
11728
10046
  })
11729
10047
  )
11730
10048
  }).parse(record);
@@ -11737,46 +10055,46 @@ async function runSeoCommand(options) {
11737
10055
  notificationRoute.parse(record.route);
11738
10056
  }
11739
10057
  } else if (!writing) {
11740
- const validated = z22.object({
11741
- resource: z22.object({
11742
- id: z22.literal(context.resourceId),
11743
- organizationId: z22.literal(context.overview.project.organizationId)
10058
+ const validated = z19.object({
10059
+ resource: z19.object({
10060
+ id: z19.literal(context.resourceId),
10061
+ organizationId: z19.literal(context.overview.project.organizationId)
11744
10062
  }),
11745
- audits: z22.array(z22.object({ id: z22.string() }).passthrough()),
11746
- audit: z22.object({
11747
- id: z22.string(),
11748
- resourceId: z22.literal(context.resourceId)
10063
+ audits: z19.array(z19.object({ id: z19.string() }).passthrough()),
10064
+ audit: z19.object({
10065
+ id: z19.string(),
10066
+ resourceId: z19.literal(context.resourceId)
11749
10067
  }).passthrough().nullable(),
11750
- pages: z22.array(z22.unknown()),
11751
- issues: z22.array(z22.unknown()),
11752
- changes: z22.array(z22.unknown()),
11753
- totalChanges: z22.number(),
11754
- dispositions: z22.array(z22.unknown())
10068
+ pages: z19.array(z19.unknown()),
10069
+ issues: z19.array(z19.unknown()),
10070
+ changes: z19.array(z19.unknown()),
10071
+ totalChanges: z19.number(),
10072
+ dispositions: z19.array(z19.unknown())
11755
10073
  }).passthrough().parse(record);
11756
10074
  const selected = query.get("audit");
11757
10075
  if (selected && validated.audit?.id !== selected)
11758
10076
  throw new Error("The SEO response does not match the requested audit.");
11759
10077
  } else if (record.audit)
11760
- z22.object({
11761
- id: z22.string(),
11762
- resourceId: z22.literal(context.resourceId),
11763
- organizationId: z22.literal(context.overview.project.organizationId),
11764
- state: z22.literal("queued")
10078
+ z19.object({
10079
+ id: z19.string(),
10080
+ resourceId: z19.literal(context.resourceId),
10081
+ organizationId: z19.literal(context.overview.project.organizationId),
10082
+ state: z19.literal("queued")
11765
10083
  }).parse(record.audit);
11766
- else if (route === "audit cancel") z22.literal(true).parse(record.cancelled);
10084
+ else if (route === "audit cancel") z19.literal(true).parse(record.cancelled);
11767
10085
  else if (action === "issue")
11768
- z22.object({
11769
- url: z22.literal(values.url),
11770
- ruleId: z22.literal(values.rule),
11771
- ignored: z22.literal(positionals[1] === "ignore"),
11772
- revision: z22.literal(Number(values.revision) + 1)
10086
+ z19.object({
10087
+ url: z19.literal(values.url),
10088
+ ruleId: z19.literal(values.rule),
10089
+ ignored: z19.literal(positionals[1] === "ignore"),
10090
+ revision: z19.literal(Number(values.revision) + 1)
11773
10091
  }).parse(record.disposition);
11774
10092
  else throw new Error("The SEO service returned an invalid response.");
11775
10093
  return { exitCode: 0, stdout: JSON.stringify(record, null, 2) };
11776
10094
  } catch (cause) {
11777
10095
  const error = {
11778
10096
  code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
11779
- message: cause instanceof z22.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
10097
+ message: cause instanceof z19.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
11780
10098
  };
11781
10099
  return {
11782
10100
  exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
@@ -11831,7 +10149,7 @@ function rootCommandRegistry() {
11831
10149
  fetchImpl: globalThis.fetch
11832
10150
  }),
11833
10151
  "health-check": runHealthCheck,
11834
- project: (args2) => runProjectCommand4({
10152
+ project: (args2) => runProjectCommand({
11835
10153
  args: args2,
11836
10154
  cwd: process.cwd(),
11837
10155
  env: process.env,