anhedral 0.8.6 → 0.9.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 (125) hide show
  1. package/README.md +141 -38
  2. package/assets/anhedral-cli-init-technical.svg +15 -15
  3. package/assets/anhedral-cli-init.svg +16 -16
  4. package/dist/access.d.ts +10 -0
  5. package/dist/access.js +93 -0
  6. package/dist/auth-schema-snapshot.d.ts +346 -0
  7. package/dist/auth-schema-snapshot.js +347 -0
  8. package/dist/auth-schema.d.ts +1 -0
  9. package/dist/auth-schema.js +57 -0
  10. package/dist/bin.js +345 -39
  11. package/dist/bounded-file.d.ts +2 -0
  12. package/dist/bounded-file.js +30 -0
  13. package/dist/capabilities.d.ts +24 -42
  14. package/dist/capabilities.js +73 -75
  15. package/dist/cloudflare.d.ts +14 -0
  16. package/dist/cloudflare.js +66 -0
  17. package/dist/command.js +12 -3
  18. package/dist/delivery.d.ts +118 -0
  19. package/dist/delivery.js +611 -0
  20. package/dist/dependencies.d.ts +24 -3
  21. package/dist/dependencies.js +112 -74
  22. package/dist/dependency-order.d.ts +2 -0
  23. package/dist/dependency-order.js +24 -0
  24. package/dist/index.d.ts +18 -3
  25. package/dist/index.js +12 -2
  26. package/dist/managed-hosting.d.ts +49 -0
  27. package/dist/managed-hosting.js +373 -0
  28. package/dist/management.d.ts +3 -0
  29. package/dist/management.js +47 -0
  30. package/dist/platforms/desktop.d.ts +2 -2
  31. package/dist/platforms/desktop.js +25 -15
  32. package/dist/platforms/extension.d.ts +2 -2
  33. package/dist/platforms/extension.js +104 -66
  34. package/dist/platforms/mobile.d.ts +2 -2
  35. package/dist/platforms/mobile.js +13 -7
  36. package/dist/pnpm-policy.d.ts +0 -2
  37. package/dist/pnpm-policy.js +18 -13
  38. package/dist/project-state.d.ts +28 -0
  39. package/dist/project-state.js +226 -0
  40. package/dist/provider-readiness.d.ts +30 -0
  41. package/dist/provider-readiness.js +87 -0
  42. package/dist/provision.d.ts +46 -0
  43. package/dist/provision.js +197 -0
  44. package/dist/readiness.d.ts +4 -2
  45. package/dist/readiness.js +81 -14
  46. package/dist/registry/add.d.ts +22 -0
  47. package/dist/registry/add.js +198 -0
  48. package/dist/registry/bootstrap.d.ts +2 -0
  49. package/dist/registry/bootstrap.js +14 -0
  50. package/dist/registry/commands.d.ts +2 -0
  51. package/dist/registry/commands.js +99 -0
  52. package/dist/registry/context.d.ts +3 -0
  53. package/dist/registry/context.js +21 -0
  54. package/dist/registry/options.d.ts +2 -0
  55. package/dist/registry/options.js +65 -0
  56. package/dist/registry/receipt.d.ts +3 -0
  57. package/dist/registry/receipt.js +73 -0
  58. package/dist/registry/remote.d.ts +25 -0
  59. package/dist/registry/remote.js +168 -0
  60. package/dist/registry/resolve.d.ts +10 -0
  61. package/dist/registry/resolve.js +98 -0
  62. package/dist/registry/types.d.ts +64 -0
  63. package/dist/registry/usage.d.ts +1 -0
  64. package/dist/registry/usage.js +38 -0
  65. package/dist/render.d.ts +0 -4
  66. package/dist/render.js +3 -16
  67. package/dist/repository.d.ts +24 -0
  68. package/dist/repository.js +96 -0
  69. package/dist/scaffold/api.d.ts +2 -0
  70. package/dist/scaffold/api.js +13 -0
  71. package/dist/scaffold/auth.d.ts +3 -0
  72. package/dist/scaffold/auth.js +95 -0
  73. package/dist/scaffold/bootstrap.d.ts +2 -0
  74. package/dist/scaffold/bootstrap.js +34 -0
  75. package/dist/scaffold/compose.d.ts +4 -0
  76. package/dist/scaffold/compose.js +34 -0
  77. package/dist/scaffold/database.d.ts +2 -0
  78. package/dist/scaffold/database.js +43 -0
  79. package/dist/scaffold/documentation.d.ts +3 -0
  80. package/dist/scaffold/documentation.js +91 -0
  81. package/dist/scaffold/environment.d.ts +2 -0
  82. package/dist/scaffold/environment.js +5 -0
  83. package/dist/scaffold/files.d.ts +25 -0
  84. package/dist/scaffold/files.js +108 -0
  85. package/dist/scaffold/integrations.d.ts +3 -0
  86. package/dist/scaffold/integrations.js +7 -0
  87. package/dist/scaffold/services.d.ts +5 -0
  88. package/dist/scaffold/services.js +84 -0
  89. package/dist/scaffold/web.d.ts +2 -0
  90. package/dist/scaffold/web.js +102 -0
  91. package/dist/scaffold/workspace.d.ts +3 -0
  92. package/dist/scaffold/workspace.js +150 -0
  93. package/dist/security-backports.js +7 -2
  94. package/dist/stack-registry.d.ts +80 -0
  95. package/dist/stack-registry.js +424 -0
  96. package/dist/standard.d.ts +6 -19
  97. package/dist/standard.js +46 -653
  98. package/dist/transaction.js +47 -56
  99. package/dist/util.js +12 -2
  100. package/dist/vercel.d.ts +98 -0
  101. package/dist/vercel.js +796 -0
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/dist/vinext.d.ts +1 -0
  105. package/dist/vinext.js +83 -0
  106. package/dist/workspace-graph.d.ts +7 -0
  107. package/dist/workspace-graph.js +73 -0
  108. package/docs/application-stack-standard.md +76 -91
  109. package/docs/delivery-workflow.md +83 -0
  110. package/docs/managed-hosting-architecture.md +87 -0
  111. package/docs/sponsorships.md +25 -0
  112. package/package.json +23 -29
  113. package/dist/evidence-validation.d.ts +0 -2
  114. package/dist/evidence-validation.js +0 -18
  115. package/dist/foundation.d.ts +0 -6
  116. package/dist/foundation.js +0 -49
  117. package/dist/progress-view.d.ts +0 -57
  118. package/dist/progress-view.js +0 -69
  119. package/dist/progress.d.ts +0 -95
  120. package/dist/progress.js +0 -327
  121. package/dist/project.d.ts +0 -5
  122. package/dist/standard-products.d.ts +0 -2
  123. package/dist/standard-products.js +0 -6
  124. /package/assets/{images/svg/logo-white-subtract.svg → anhedral-mark.svg} +0 -0
  125. /package/dist/{project.js → registry/types.js} +0 -0
@@ -1,4 +1,5 @@
1
- import { closeSync, constants, fstatSync, cpSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmdirSync, rmSync, unlinkSync, writeFileSync, } from 'node:fs';
1
+ import { readBoundedFile } from './bounded-file.js';
2
+ import { closeSync, cpSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmdirSync, rmSync, unlinkSync, writeFileSync, } from 'node:fs';
2
3
  import { createHash, randomUUID } from 'node:crypto';
3
4
  import os from 'node:os';
4
5
  import path from 'node:path';
@@ -18,10 +19,10 @@ function assertRelativePath(relativePath) {
18
19
  normalized === '.' ||
19
20
  normalized === '..' ||
20
21
  normalized.startsWith(`..${path.sep}`) ||
21
- normalized.split(path.sep).includes('..')
22
- || rawSegments[0] === TRANSACTION_DIRECTORY
23
- || rawSegments[0] === LOCK_FILE
24
- || rawSegments[0] === JOURNAL_FILE) {
22
+ normalized.split(path.sep).includes('..') ||
23
+ rawSegments[0] === TRANSACTION_DIRECTORY ||
24
+ rawSegments[0] === LOCK_FILE ||
25
+ rawSegments[0] === JOURNAL_FILE) {
25
26
  throw new Error(`Unsafe transaction path: ${relativePath}`);
26
27
  }
27
28
  }
@@ -81,8 +82,8 @@ function normalizeTransactionPaths(rawCommitPaths, rawDeletePaths) {
81
82
  for (const written of commitPaths) {
82
83
  const deletedAncestor = ancestorInSet(written, deleteSet);
83
84
  if (deleteSet.has(written) || deletedAncestor || deleteAncestorPaths.has(written)) {
84
- throw new Error(`Ambiguous transaction write/delete paths include ${written}`
85
- + (deletedAncestor ? ` below ${deletedAncestor}` : ''));
85
+ throw new Error(`Ambiguous transaction write/delete paths include ${written}` +
86
+ (deletedAncestor ? ` below ${deletedAncestor}` : ''));
86
87
  }
87
88
  }
88
89
  const uniquePaths = [...commitPaths, ...deletePaths].sort();
@@ -100,7 +101,9 @@ function assertExactObjectKeys(value, expected, context) {
100
101
  const details = [
101
102
  missing.length > 0 ? `missing ${missing.join(', ')}` : null,
102
103
  unknown.length > 0 ? `unknown ${unknown.join(', ')}` : null,
103
- ].filter((entry) => entry !== null).join('; ');
104
+ ]
105
+ .filter((entry) => entry !== null)
106
+ .join('; ');
104
107
  throw new Error(`Invalid ${context} fields (${details}).`);
105
108
  }
106
109
  function lstatIfPresent(target) {
@@ -232,42 +235,13 @@ function removeEntryDurably(target) {
232
235
  if (pathEntryExists(parent))
233
236
  syncDirectory(parent);
234
237
  }
235
- /** Reserved recovery metadata must never read devices, pipes or unbounded files. */
236
- function readRecoveryMetadata(filePath, maximumBytes) {
237
- const stat = lstatSync(filePath);
238
- if (!stat.isFile() || stat.isSymbolicLink())
239
- throw new Error(`Recovery metadata must be a regular file: ${filePath}`);
240
- const descriptor = openSync(filePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
241
- try {
242
- const opened = fstatSync(descriptor);
243
- if (!opened.isFile())
244
- throw new Error(`Recovery metadata must be a regular file: ${filePath}`);
245
- if (opened.size > maximumBytes)
246
- throw new Error(`Recovery metadata exceeds size limit: ${filePath}`);
247
- const chunks = [];
248
- let total = 0;
249
- for (;;) {
250
- const chunk = Buffer.alloc(Math.min(8192, maximumBytes + 1 - total));
251
- const length = readSync(descriptor, chunk, 0, chunk.length, null);
252
- if (!length)
253
- return Buffer.concat(chunks).toString('utf8');
254
- total += length;
255
- if (total > maximumBytes)
256
- throw new Error(`Recovery metadata exceeds size limit: ${filePath}`);
257
- chunks.push(chunk.subarray(0, length));
258
- }
259
- }
260
- finally {
261
- closeSync(descriptor);
262
- }
263
- }
264
238
  function parseLockOwner(lockPath) {
265
239
  if (lstatSync(lockPath).isSymbolicLink()) {
266
240
  throw new Error(`Refusing symbolic-link transaction lock at ${lockPath}.`);
267
241
  }
268
242
  let value;
269
243
  try {
270
- value = JSON.parse(readRecoveryMetadata(lockPath, 16 * 1024));
244
+ value = JSON.parse(readBoundedFile(lockPath, 16 * 1024).toString('utf8'));
271
245
  }
272
246
  catch (error) {
273
247
  throw new Error(`Cannot read transaction lock owner at ${lockPath}; remove it only after confirming no Anhedral process is running.`, { cause: error });
@@ -430,7 +404,11 @@ function acquireTransactionLock(root) {
430
404
  createdAt: new Date().toISOString(),
431
405
  };
432
406
  const temporaryPath = `${lockPath}.${owner.token}.tmp`;
433
- writeFileSync(temporaryPath, JSON.stringify(owner) + '\n', { encoding: 'utf8', flag: 'wx', mode: 0o600 });
407
+ writeFileSync(temporaryPath, JSON.stringify(owner) + '\n', {
408
+ encoding: 'utf8',
409
+ flag: 'wx',
410
+ mode: 0o600,
411
+ });
434
412
  try {
435
413
  for (let attempt = 0; attempt < 3; attempt += 1) {
436
414
  if (clearDeadReclaimer(lockPath, reclaimPath, owner)) {
@@ -518,13 +496,17 @@ function validateJournal(root, value) {
518
496
  throw new Error(`Cannot recover unsupported transaction journal at ${path.join(root, JOURNAL_FILE)}`);
519
497
  }
520
498
  assertExactObjectKeys(value, ['version', 'backupRoot', 'stageRoot', 'entries', 'createdDirectories'], 'transaction journal');
521
- if (typeof value.backupRoot !== 'string' || typeof value.stageRoot !== 'string' || !Array.isArray(value.entries)) {
499
+ if (typeof value.backupRoot !== 'string' ||
500
+ typeof value.stageRoot !== 'string' ||
501
+ !Array.isArray(value.entries)) {
522
502
  throw new Error(`Invalid transaction journal at ${path.join(root, JOURNAL_FILE)}`);
523
503
  }
524
504
  assertJournalRoots(root, value.backupRoot, value.stageRoot);
525
505
  const seen = new Set();
526
506
  const entries = value.entries.map((entry, index) => {
527
- if (!isRecord(entry) || typeof entry.relativePath !== 'string' || typeof entry.installed !== 'boolean') {
507
+ if (!isRecord(entry) ||
508
+ typeof entry.relativePath !== 'string' ||
509
+ typeof entry.installed !== 'boolean') {
528
510
  throw new Error(`Invalid transaction journal entry at index ${index}`);
529
511
  }
530
512
  assertExactObjectKeys(entry, ['relativePath', 'backupPath', 'installed', 'installedFingerprint'], `transaction journal entry at index ${index}`);
@@ -536,15 +518,16 @@ function validateJournal(root, value) {
536
518
  throw new Error(`Invalid transaction backup path at index ${index}`);
537
519
  }
538
520
  const installedFingerprint = entry.installedFingerprint;
539
- if (installedFingerprint !== null
540
- && (typeof installedFingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(installedFingerprint))) {
521
+ if (installedFingerprint !== null &&
522
+ (typeof installedFingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(installedFingerprint))) {
541
523
  throw new Error(`Invalid installed transaction fingerprint at index ${index}`);
542
524
  }
543
525
  if (entry.installed ? installedFingerprint === null : installedFingerprint !== null) {
544
526
  throw new Error(`Transaction journal entry fingerprint state is inconsistent at index ${index}`);
545
527
  }
546
528
  const expectedBackup = resolveTransactionPath(value.backupRoot, entry.relativePath);
547
- if (entry.backupPath !== null && path.resolve(entry.backupPath) !== path.resolve(expectedBackup)) {
529
+ if (entry.backupPath !== null &&
530
+ path.resolve(entry.backupPath) !== path.resolve(expectedBackup)) {
548
531
  throw new Error(`Unsafe transaction backup path: ${entry.backupPath}`);
549
532
  }
550
533
  return {
@@ -573,7 +556,13 @@ function validateJournal(root, value) {
573
556
  throw new Error(`Transaction created directory is not a parent of any journal entry: ${directory}`);
574
557
  }
575
558
  }
576
- return { version: JOURNAL_VERSION, backupRoot: value.backupRoot, stageRoot: value.stageRoot, entries, createdDirectories };
559
+ return {
560
+ version: JOURNAL_VERSION,
561
+ backupRoot: value.backupRoot,
562
+ stageRoot: value.stageRoot,
563
+ entries,
564
+ createdDirectories,
565
+ };
577
566
  }
578
567
  function writeJournal(root, journal) {
579
568
  const journalPath = path.join(root, JOURNAL_FILE);
@@ -646,13 +635,13 @@ function restoreInstalledEntry(root, journal, entry, target) {
646
635
  if (entry.installed) {
647
636
  if (pathEntryExists(target)) {
648
637
  if (entry.installedFingerprint === null) {
649
- throw new Error(`Installed transaction path has no trusted fingerprint: ${entry.relativePath}. `
650
- + 'Recovery stopped without modifying it; inspect the journal, target, and backup manually.');
638
+ throw new Error(`Installed transaction path has no trusted fingerprint: ${entry.relativePath}. ` +
639
+ 'Recovery stopped without modifying it; inspect the journal, target, and backup manually.');
651
640
  }
652
641
  const actualFingerprint = fingerprintEntry(target);
653
642
  if (actualFingerprint !== entry.installedFingerprint) {
654
- throw new Error(`Installed transaction path changed after an interrupted commit: ${entry.relativePath}. `
655
- + 'Recovery stopped without modifying it; inspect the journal, target, and backup manually.');
643
+ throw new Error(`Installed transaction path changed after an interrupted commit: ${entry.relativePath}. ` +
644
+ 'Recovery stopped without modifying it; inspect the journal, target, and backup manually.');
656
645
  }
657
646
  }
658
647
  removeEntryDurably(target);
@@ -679,8 +668,7 @@ function restoreJournal(root, journal) {
679
668
  writeJournal(root, journal);
680
669
  }
681
670
  }
682
- for (const relativePath of [...journal.createdDirectories]
683
- .sort((left, right) => right.split('/').length - left.split('/').length || right.localeCompare(left))) {
671
+ for (const relativePath of [...journal.createdDirectories].sort((left, right) => right.split('/').length - left.split('/').length || right.localeCompare(left))) {
684
672
  assertNoSymlinkComponents(root, relativePath);
685
673
  const target = resolveTransactionPath(root, relativePath);
686
674
  try {
@@ -705,7 +693,7 @@ function recoverInterruptedTransactionUnlocked(root) {
705
693
  if (lstatSync(journalPath).isSymbolicLink()) {
706
694
  throw new Error(`Refusing symbolic-link transaction journal at ${journalPath}.`);
707
695
  }
708
- const journal = validateJournal(root, JSON.parse(readRecoveryMetadata(journalPath, 16 * 1024 * 1024)));
696
+ const journal = validateJournal(root, JSON.parse(readBoundedFile(journalPath, 16 * 1024 * 1024).toString('utf8')));
709
697
  restoreJournal(root, journal);
710
698
  return true;
711
699
  }
@@ -726,8 +714,8 @@ export class PostCommitError extends Error {
726
714
  committedPaths;
727
715
  constructor(committedPaths, cause) {
728
716
  const causeMessage = cause instanceof Error ? cause.message : String(cause);
729
- super(`Generated files were saved, but the follow-up action failed: ${causeMessage}. `
730
- + 'The generated files were kept; resolve the failure and rerun the failed command.', { cause });
717
+ super(`Changes were committed successfully, but the post-commit action failed: ${causeMessage}. ` +
718
+ 'The generated files were kept; resolve the failure and rerun the post-commit command.', { cause });
731
719
  this.name = 'PostCommitError';
732
720
  this.committedPaths = Object.freeze([...committedPaths]);
733
721
  }
@@ -742,7 +730,10 @@ function assertTransactionNamespace(transactionDirectory) {
742
730
  for (const entry of readdirSync(transactionDirectory)) {
743
731
  const candidate = path.join(transactionDirectory, entry);
744
732
  const stat = lstatIfPresent(candidate);
745
- if (!LOCAL_TRANSACTION_ROOT_PATTERN.test(entry) || !stat || stat.isSymbolicLink() || !stat.isDirectory()) {
733
+ if (!LOCAL_TRANSACTION_ROOT_PATTERN.test(entry) ||
734
+ !stat ||
735
+ stat.isSymbolicLink() ||
736
+ !stat.isDirectory()) {
746
737
  throw new Error(`Unknown or unsafe artifact in reserved transaction namespace requires manual inspection: ${candidate}`);
747
738
  }
748
739
  }
@@ -835,7 +826,7 @@ export async function runStagedTransaction(root, options) {
835
826
  recoverInterruptedTransactionUnlocked(root);
836
827
  if (!options.dryRun)
837
828
  cleanupOrphanTransactionRoots(root);
838
- if (await options.prepare?.() === false)
829
+ if ((await options.prepare?.()) === false)
839
830
  return Object.freeze([]);
840
831
  assertTransactionNamespace(transactionDirectory);
841
832
  namespaceValidated = true;
package/dist/util.js CHANGED
@@ -20,7 +20,13 @@ export function appendGitignore(root, lines) {
20
20
  const additions = [...new Set(lines)].filter((line) => !existingLines.has(line));
21
21
  if (additions.length === 0)
22
22
  return;
23
- const newline = existing.includes('\r\n') ? '\r\n' : existing.includes('\n') ? '\n' : existing.includes('\r') ? '\r' : '\n';
23
+ const newline = existing.includes('\r\n')
24
+ ? '\r\n'
25
+ : existing.includes('\n')
26
+ ? '\n'
27
+ : existing.includes('\r')
28
+ ? '\r'
29
+ : '\n';
24
30
  const separator = existing.length > 0 && !/(?:\r\n|\n|\r)$/.test(existing) ? newline : '';
25
31
  writeFile(filePath, `${existing}${separator}${additions.join(newline)}${newline}`);
26
32
  }
@@ -56,7 +62,11 @@ export function execFile(executable, args, cwd) {
56
62
  const display = [executable, ...args].join(' ');
57
63
  if (process.env.ANHEDRAL_VERBOSE === '1' && !quiet) {
58
64
  console.log(` $ ${display}`);
59
- const result = spawnSync(invocation.command, invocation.args, { cwd, stdio: 'inherit', shell: false });
65
+ const result = spawnSync(invocation.command, invocation.args, {
66
+ cwd,
67
+ stdio: 'inherit',
68
+ shell: false,
69
+ });
60
70
  if (result.error || result.status !== 0) {
61
71
  throw new Error(`Command failed (exit ${result.status ?? '?'}): ${display}`, result.error ? { cause: result.error } : undefined);
62
72
  }
@@ -0,0 +1,98 @@
1
+ import { type DeliveryRunner } from './project-state.js';
2
+ interface WebProject {
3
+ schemaVersion: 1;
4
+ id: string;
5
+ name: string;
6
+ ownership: 'customer';
7
+ provider: 'vercel';
8
+ directory: 'apps/web';
9
+ teamId: string | null;
10
+ projectId: string | null;
11
+ scope: string | null;
12
+ audience: 'unconfigured' | 'public' | 'private';
13
+ use: 'unconfigured' | 'personal' | 'commercial';
14
+ repository?: {
15
+ repoId: number;
16
+ nameWithOwner: string;
17
+ productionBranch?: string;
18
+ };
19
+ }
20
+ interface WebRelease {
21
+ id: string;
22
+ commit: string;
23
+ operation: 'ship' | 'rollback' | 'adopt' | 'recover';
24
+ provenance?: 'cli' | 'git';
25
+ branch?: string;
26
+ state: 'running' | 'deployed' | 'failed';
27
+ startedAt: string;
28
+ deploymentId?: string;
29
+ url?: string;
30
+ deploymentUrl?: string;
31
+ restoredReleaseId?: string;
32
+ verification?: {
33
+ state: 'passed' | 'failed';
34
+ checkedAt: string;
35
+ };
36
+ }
37
+ export declare function registerVercelApplication(root: string): WebProject;
38
+ export declare function connectVercelApplication(root: string, options: {
39
+ scope?: string;
40
+ audience: 'public' | 'private';
41
+ use: 'personal' | 'commercial';
42
+ create?: boolean;
43
+ git?: boolean;
44
+ }, run?: DeliveryRunner): Promise<{
45
+ project: WebProject;
46
+ plan: any;
47
+ planActivated: boolean;
48
+ }>;
49
+ export declare function adoptVercelApplication(root: string, run?: DeliveryRunner): Promise<{
50
+ projectId: string;
51
+ release: WebRelease;
52
+ adopted: boolean;
53
+ productVerification: string;
54
+ }>;
55
+ export declare function recoverVercelApplication(root: string, run?: DeliveryRunner): Promise<{
56
+ projectId: string;
57
+ release: WebRelease;
58
+ adopted: boolean;
59
+ productVerification: string;
60
+ }>;
61
+ export declare function planVercelDelivery(root: string): {
62
+ project: WebProject;
63
+ checks: string[];
64
+ deployment: string[];
65
+ cloudflareServices: string;
66
+ mutation: boolean;
67
+ };
68
+ export declare function vercelApplicationStatus(root: string, refresh?: boolean, run?: DeliveryRunner): Promise<{
69
+ project: WebProject;
70
+ releases: WebRelease[];
71
+ activeRecordedVersion: boolean | undefined;
72
+ evidence: string;
73
+ productVerification: string;
74
+ management: string | null;
75
+ }>;
76
+ export declare function shipVercelApplication(root: string, run?: DeliveryRunner): Promise<{
77
+ projectId: string;
78
+ release: WebRelease;
79
+ productVerification: string;
80
+ }>;
81
+ export declare function verifyVercelApplication(root: string, run?: DeliveryRunner): Promise<{
82
+ projectId: string;
83
+ releaseId: string;
84
+ verification: {
85
+ state: "passed" | "failed";
86
+ checkedAt: string;
87
+ };
88
+ }>;
89
+ export declare function rollbackVercelApplication(root: string, releaseId: string, dataCompatible: boolean, run?: DeliveryRunner): Promise<{
90
+ projectId: string;
91
+ release: WebRelease;
92
+ dataRestored: boolean;
93
+ productVerification: string;
94
+ automaticProductionUpdates: string;
95
+ nextAction: string;
96
+ }>;
97
+ export declare function writeVercelOverview(root: string, snapshot: Awaited<ReturnType<typeof vercelApplicationStatus>>): string;
98
+ export {};