vercel 59.11.2 → 59.11.7

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 (154) hide show
  1. package/dist/chunks/{add-BKSHWTPX.js → add-KSJQYR5C.js} +23 -18
  2. package/dist/chunks/{add-RBW7QITR.js → add-PERLOALD.js} +37 -23
  3. package/dist/chunks/{add-HPLJZFM2.js → add-WU2QYHYL.js} +23 -18
  4. package/dist/chunks/{build-V4ZLAJWB.js → build-F3J6FLPD.js} +23 -18
  5. package/dist/chunks/{chunk-NGGLYKNU.js → chunk-26CU4Q3C.js} +3 -115
  6. package/dist/chunks/{chunk-QFAS4OVW.js → chunk-2JIX6UMI.js} +3 -84
  7. package/dist/chunks/chunk-2TSBB22D.js +14059 -0
  8. package/dist/chunks/chunk-332LMJLZ.js +16014 -0
  9. package/dist/chunks/{chunk-AYLY3ZVL.js → chunk-3VM7HWF6.js} +2 -2
  10. package/dist/chunks/chunk-4IALDGB7.js +22 -0
  11. package/dist/chunks/chunk-4IVSM24H.js +522 -0
  12. package/dist/chunks/{chunk-5XECIWME.js → chunk-5NF5HOBJ.js} +5 -3
  13. package/dist/chunks/chunk-6E6KPBXY.js +43 -0
  14. package/dist/chunks/chunk-7KROIXQM.js +59 -0
  15. package/dist/chunks/{chunk-ASBP32T6.js → chunk-7MRDIPJY.js} +1 -1
  16. package/dist/chunks/chunk-A5JZS6ZN.js +92 -0
  17. package/dist/chunks/{chunk-7ST552E3.js → chunk-AKLTIZCU.js} +1 -1
  18. package/dist/chunks/{chunk-26XDDLXM.js → chunk-ARU7VBKR.js} +2 -2
  19. package/dist/chunks/chunk-B5XLQKHI.js +849 -0
  20. package/dist/chunks/chunk-C762AAVU.js +137 -0
  21. package/dist/chunks/{chunk-WA2SJE5S.js → chunk-CEDN47PH.js} +4 -4
  22. package/dist/chunks/{chunk-ONRLTUP2.js → chunk-CNDPIHY5.js} +24 -22
  23. package/dist/chunks/{chunk-BMKU5KEL.js → chunk-CV5YC2EN.js} +1 -1
  24. package/dist/chunks/chunk-DBYHS3CK.js +257 -0
  25. package/dist/chunks/{chunk-HDBQPBL6.js → chunk-DSTNNQVV.js} +12 -8
  26. package/dist/chunks/{chunk-QAT3CW4G.js → chunk-EFYMIIER.js} +2 -2
  27. package/dist/chunks/{chunk-NBW3BWOJ.js → chunk-EPOLDWRA.js} +2 -2
  28. package/dist/chunks/{chunk-B4TXCKXE.js → chunk-EZQDYIVB.js} +10 -8
  29. package/dist/chunks/{chunk-2EAIC3SH.js → chunk-FL4JLNT2.js} +8 -8
  30. package/dist/chunks/chunk-FRVG4OW3.js +7438 -0
  31. package/dist/chunks/{chunk-FKDO3CM4.js → chunk-FVNJTRCE.js} +17 -13
  32. package/dist/chunks/chunk-FVT74RZ5.js +1536 -0
  33. package/dist/chunks/chunk-G3PXSXIB.js +18188 -0
  34. package/dist/chunks/chunk-G5FBSUL4.js +822 -0
  35. package/dist/chunks/{chunk-FRAXI2WT.js → chunk-GCVXKRR5.js} +3 -3
  36. package/dist/chunks/chunk-GHKJAK5V.js +1288 -0
  37. package/dist/chunks/{chunk-Q5K5DEOK.js → chunk-GUU4Z2AQ.js} +42 -28
  38. package/dist/chunks/{chunk-OQ3C5VXZ.js → chunk-GVNCVKCI.js} +4 -2
  39. package/dist/chunks/chunk-HB4UKFDO.js +1295 -0
  40. package/dist/chunks/chunk-HRXRELD3.js +338 -0
  41. package/dist/chunks/{chunk-IJ4X426J.js → chunk-IIMSID24.js} +1 -1
  42. package/dist/chunks/{chunk-O75LSD3C.js → chunk-JSD4EZL3.js} +1 -1
  43. package/dist/chunks/{chunk-7AEEQOD4.js → chunk-K3RED3VO.js} +1 -1
  44. package/dist/chunks/{chunk-RSEAADCE.js → chunk-KEKR7OCB.js} +6 -4
  45. package/dist/chunks/{chunk-3T7WSWZH.js → chunk-KFWQ3EFH.js} +1 -1
  46. package/dist/chunks/{chunk-L3UXB2CW.js → chunk-KW7BS25T.js} +1 -1
  47. package/dist/chunks/{chunk-RO44KX6Y.js → chunk-N4QHMXOO.js} +11 -7
  48. package/dist/chunks/{chunk-XRWOTCDO.js → chunk-ND5CF2H3.js} +1 -1
  49. package/dist/chunks/{chunk-RSJBU3ON.js → chunk-NSOYO6JQ.js} +35 -27
  50. package/dist/chunks/{chunk-RKDCNQ4S.js → chunk-NW34PW6V.js} +3 -105
  51. package/dist/chunks/{chunk-C5HKWXRR.js → chunk-OAMU5QO6.js} +1 -1
  52. package/dist/chunks/{chunk-MTWHQEXI.js → chunk-OIH6FP5Y.js} +5 -3
  53. package/dist/chunks/chunk-P7VSBDR4.js +827 -0
  54. package/dist/chunks/chunk-PEC3CQSK.js +90 -0
  55. package/dist/chunks/{chunk-QDV5LZ4Q.js → chunk-PFM75KY3.js} +12 -8
  56. package/dist/chunks/chunk-PJXMXMCO.js +81 -0
  57. package/dist/chunks/chunk-PNGVSHR3.js +40 -0
  58. package/dist/chunks/{chunk-TPATD2MM.js → chunk-QHS645AZ.js} +14 -6
  59. package/dist/chunks/{chunk-OTXE7MHI.js → chunk-QKX7WKIN.js} +8 -6
  60. package/dist/chunks/chunk-QOPTXV4G.js +417 -0
  61. package/dist/chunks/chunk-RN6V5ODW.js +114 -0
  62. package/dist/chunks/chunk-RVBZ64EQ.js +52 -0
  63. package/dist/chunks/chunk-SHFNEZVI.js +49 -0
  64. package/dist/chunks/{chunk-OO3OF6MK.js → chunk-TGNEG57M.js} +44 -15
  65. package/dist/chunks/{chunk-WNAKOXGK.js → chunk-TO7QZGYK.js} +1 -1
  66. package/dist/chunks/chunk-UARGTFCT.js +875 -0
  67. package/dist/chunks/{chunk-FWKSJYDV.js → chunk-UG2WOB5L.js} +1 -1
  68. package/dist/chunks/chunk-V4RMJKQP.js +36 -0
  69. package/dist/chunks/chunk-VT3Z7HF6.js +233 -0
  70. package/dist/chunks/chunk-VUS2JQB2.js +121 -0
  71. package/dist/chunks/{chunk-6CZZ3SH3.js → chunk-VYC45Q4Z.js} +2 -2
  72. package/dist/chunks/{chunk-4KVJ2M4J.js → chunk-WL6QYSGD.js} +78 -17
  73. package/dist/chunks/{chunk-FZRBF25Y.js → chunk-X7DBBZQD.js} +4 -4
  74. package/dist/chunks/{chunk-2NJJ2K5S.js → chunk-XD4DCYMX.js} +6 -6
  75. package/dist/chunks/{chunk-ZSFEACZU.js → chunk-XFF5TGRA.js} +1 -1
  76. package/dist/chunks/{chunk-6TBDHUXK.js → chunk-XIFATBH5.js} +21 -15
  77. package/dist/chunks/chunk-XNIZGCN5.js +58 -0
  78. package/dist/chunks/chunk-XPJLPUKO.js +117 -0
  79. package/dist/chunks/{chunk-FXD67VN5.js → chunk-XUAWTW4W.js} +1 -1
  80. package/dist/chunks/{chunk-I526H4AS.js → chunk-YS76T533.js} +2 -2
  81. package/dist/chunks/chunk-Z7JWYFOY.js +58 -0
  82. package/dist/chunks/{chunk-6JPVTPTU.js → chunk-ZBEECGFD.js} +3 -3
  83. package/dist/chunks/{chunk-52QYYTM5.js → chunk-ZDU2NODC.js} +3 -127
  84. package/dist/chunks/chunk-ZW6HETRE.js +97 -0
  85. package/dist/chunks/{clear-IYGWCNXT.js → clear-XUQO4ZTK.js} +23 -18
  86. package/dist/chunks/{compile-vercel-config-NEEBZRUJ.js → compile-vercel-config-D3ARNHTN.js} +8 -11
  87. package/dist/chunks/{config-6DS6BBR2.js → config-37OAE7QJ.js} +22 -17
  88. package/dist/chunks/{config-NTB5EMV4.js → config-MEDLXUVM.js} +23 -18
  89. package/dist/chunks/{delete-LLC2OGHA.js → delete-3N3YZZOF.js} +16 -12
  90. package/dist/chunks/{delete-LSGID5FV.js → delete-VSWDZ2SW.js} +19 -14
  91. package/dist/chunks/detect-projects-ODNU4PK2.js +18 -0
  92. package/dist/chunks/detect-services-TESZCQWG.js +40 -0
  93. package/dist/chunks/{disable-H4EXEQK7.js → disable-A4FLFMC7.js} +17 -13
  94. package/dist/chunks/{discard-FG6VKHWN.js → discard-CHGFULBZ.js} +17 -13
  95. package/dist/chunks/{edit-YE7D3CPJ.js → edit-JZ63AJYQ.js} +17 -13
  96. package/dist/chunks/{edit-BZJSGUHT.js → edit-MHSYAPDR.js} +19 -15
  97. package/dist/chunks/{enable-6ESD4QTE.js → enable-KD46SEC5.js} +17 -13
  98. package/dist/chunks/{exec-XH4K34JM.js → exec-4IPHZ55G.js} +9 -5
  99. package/dist/chunks/{export-QWSJROLG.js → export-42QZLBSN.js} +16 -13
  100. package/dist/chunks/{image-LTHQMKFG.js → image-GP4H73A2.js} +11 -8
  101. package/dist/chunks/{import-builders-6O7ILGQJ.js → import-builders-6TBLMPL2.js} +18 -13
  102. package/dist/chunks/{inspect-2C4ZSNYC.js → inspect-5FMWMY3C.js} +22 -18
  103. package/dist/chunks/{inspect-N6SMHV3Z.js → inspect-MUVK6MMT.js} +18 -14
  104. package/dist/chunks/{inspect-F7KCTHIL.js → inspect-Q3DWW7MC.js} +22 -18
  105. package/dist/chunks/{inspect-TWDPMXZ5.js → inspect-QFXAOUL4.js} +18 -14
  106. package/dist/chunks/{inspect-ICKNCDMT.js → inspect-RNTSYM6O.js} +18 -14
  107. package/dist/chunks/{list-NWTIJF3L.js → list-IHHIPXEC.js} +20 -16
  108. package/dist/chunks/{list-IPGQVBJO.js → list-JRNWLSO5.js} +16 -14
  109. package/dist/chunks/{list-DS7ZOUXA.js → list-XHD5DLEX.js} +23 -19
  110. package/dist/chunks/{login-F7A7ONKC.js → login-PCT6KFWY.js} +23 -18
  111. package/dist/chunks/{ls-NBDX3MKN.js → ls-GPEHEFCF.js} +24 -18
  112. package/dist/chunks/{ls-RNGO257R.js → ls-PF7F4PP4.js} +27 -23
  113. package/dist/chunks/{ls-XINES6PL.js → ls-PQZ2RIDX.js} +24 -18
  114. package/dist/chunks/{ls-D4TUDBIH.js → ls-SVOHC3XW.js} +24 -18
  115. package/dist/chunks/{ls-2QW3ZSM6.js → ls-TGHCCARZ.js} +24 -18
  116. package/dist/chunks/{ls-LSJEUPFX.js → ls-VRIH5WA3.js} +22 -15
  117. package/dist/chunks/{open-VRQDWZAW.js → open-E7DEKYDU.js} +18 -13
  118. package/dist/chunks/{permissions-6C5C7TEV.js → permissions-JKOONWVL.js} +14 -11
  119. package/dist/chunks/{publish-GVIZPNLN.js → publish-EDDELDE5.js} +17 -13
  120. package/dist/chunks/pull-646WEVDE.js +45 -0
  121. package/dist/chunks/{push-EFZ5P5Z6.js → push-LTNW5OVD.js} +23 -18
  122. package/dist/chunks/{query-GBS2PIT4.js → query-LU4N6KPO.js} +22 -19
  123. package/dist/chunks/{reorder-TN65IFRL.js → reorder-22PKJMZP.js} +17 -13
  124. package/dist/chunks/{reply-DYVEV3PY.js → reply-SF2EZMVZ.js} +17 -13
  125. package/dist/chunks/{resolve-JAWFBPUM.js → resolve-ZCZGXTOT.js} +16 -12
  126. package/dist/chunks/resolve-deployment-framework-preset-NPE6RLV3.js +36 -0
  127. package/dist/chunks/{restore-TJVMHUBQ.js → restore-VJAWZXB4.js} +17 -13
  128. package/dist/chunks/{rm-7XACNZ2U.js → rm-KN2QFCKO.js} +23 -18
  129. package/dist/chunks/{rm-REJVXALW.js → rm-KVEAJPRE.js} +23 -18
  130. package/dist/chunks/{rm-CBPNMSRP.js → rm-OSZ5FZUM.js} +23 -16
  131. package/dist/chunks/{rm-5B5VHWWN.js → rm-W722Q2AO.js} +21 -18
  132. package/dist/chunks/{rm-HQ5CYNJA.js → rm-WNPGTUBH.js} +23 -18
  133. package/dist/chunks/{routes-2OLIBRYX.js → routes-QVMBXOSX.js} +7 -3
  134. package/dist/chunks/{rule-inspect-ZSTDDFID.js → rule-inspect-25Z6SNX3.js} +28 -24
  135. package/dist/chunks/{rules-VGV4M4KY.js → rules-65LKAQ35.js} +15 -12
  136. package/dist/chunks/{schema-45SJNY5L.js → schema-7D6IGJEJ.js} +9 -7
  137. package/dist/chunks/{schema-GMTQOQCV.js → schema-NXCW4M75.js} +19 -17
  138. package/dist/chunks/{set-Z5FO2FCC.js → set-FYJVKMPV.js} +20 -13
  139. package/dist/chunks/setup-and-link-KXPZE32P.js +65 -0
  140. package/dist/chunks/{tags-SDRXWJ63.js → tags-ANIRP5E3.js} +10 -7
  141. package/dist/chunks/{types-JGANJ5EQ.js → types-4GAJ7XQQ.js} +9 -7
  142. package/dist/chunks/{update-JBQBC3IV.js → update-UT6CTKVG.js} +32 -19
  143. package/dist/commands/build/index.js +86 -49
  144. package/dist/commands/deploy/index.js +75 -66
  145. package/dist/commands/dev/index.js +98 -52
  146. package/dist/commands/env/index.js +67 -43
  147. package/dist/commands/link/index.js +48 -27
  148. package/dist/commands/list/index.js +33 -22
  149. package/dist/commands-bulk.js +1659 -1287
  150. package/dist/index.js +62 -40
  151. package/dist/version.mjs +1 -1
  152. package/package.json +46 -46
  153. package/dist/chunks/chunk-WYU64FLP.js +0 -62123
  154. package/dist/chunks/chunk-XNFHNTS2.js +0 -2939
@@ -0,0 +1,1536 @@
1
+ import { createRequire as __createRequire } from 'node:module';
2
+ import { fileURLToPath as __fileURLToPath } from 'node:url';
3
+ import { dirname as __dirname_ } from 'node:path';
4
+ const require = __createRequire(import.meta.url);
5
+ const __filename = __fileURLToPath(import.meta.url);
6
+ const __dirname = __dirname_(__filename);
7
+ import {
8
+ detectProjects
9
+ } from "./chunk-RVBZ64EQ.js";
10
+ import {
11
+ createDetectEntrypoint,
12
+ getServicesConfigWriteBlocker,
13
+ writeServicesConfig
14
+ } from "./chunk-VT3Z7HF6.js";
15
+ import {
16
+ validateRootDirectory
17
+ } from "./chunk-A5JZS6ZN.js";
18
+ import {
19
+ getLocalPathConfig
20
+ } from "./chunk-Z7JWYFOY.js";
21
+ import {
22
+ isPromptBackError,
23
+ isPromptCanceledError
24
+ } from "./chunk-V4RMJKQP.js";
25
+ import {
26
+ require_dist as require_dist2
27
+ } from "./chunk-UARGTFCT.js";
28
+ import {
29
+ require_dist2 as require_dist
30
+ } from "./chunk-332LMJLZ.js";
31
+ import {
32
+ readJSONFile
33
+ } from "./chunk-SHFNEZVI.js";
34
+ import {
35
+ compileVercelConfig,
36
+ findSourceVercelConfigFile
37
+ } from "./chunk-QOPTXV4G.js";
38
+ import {
39
+ pull
40
+ } from "./chunk-GHKJAK5V.js";
41
+ import {
42
+ require_frameworks
43
+ } from "./chunk-FRVG4OW3.js";
44
+ import {
45
+ table
46
+ } from "./chunk-NW34PW6V.js";
47
+ import {
48
+ printError
49
+ } from "./chunk-3VM7HWF6.js";
50
+ import {
51
+ Separator,
52
+ VERCEL_DIR_PROJECT,
53
+ VERCEL_DIR_README,
54
+ checkExistsAndConnect,
55
+ createProject,
56
+ fetchProjectsForRepoUrl,
57
+ findProjectsFromPath,
58
+ findRepoRoot,
59
+ getGitConfigPath,
60
+ getLinkedProject,
61
+ getProjectByNameOrId,
62
+ getRemoteUrls,
63
+ getVercelDirectory,
64
+ humanizePath,
65
+ isDirectory,
66
+ linkFolderToProject,
67
+ linkRepoProject,
68
+ parseGitConfig,
69
+ parseRepoUrl,
70
+ pluckRemoteUrls,
71
+ printAlignedLabel,
72
+ require_lib,
73
+ require_slugify,
74
+ resolveGitRemote,
75
+ selectAndParseRemoteUrl,
76
+ selectOrg
77
+ } from "./chunk-2TSBB22D.js";
78
+ import {
79
+ CantParseJSONFile,
80
+ ProjectNotFound,
81
+ isAPIError
82
+ } from "./chunk-CV5YC2EN.js";
83
+ import {
84
+ output_manager_default
85
+ } from "./chunk-2JIX6UMI.js";
86
+ import {
87
+ require_source
88
+ } from "./chunk-S7KYDPEM.js";
89
+ import {
90
+ __toESM
91
+ } from "./chunk-TZ2YI2VH.js";
92
+
93
+ // src/util/link/setup-and-link.ts
94
+ var import_fs_extra = __toESM(require_lib(), 1);
95
+ var import_fs_detectors2 = __toESM(require_dist(), 1);
96
+ import { join as join3, basename } from "path";
97
+ import { getPlatformEnv } from "@vercel/build-utils";
98
+
99
+ // src/util/input/input-project.ts
100
+ var import_chalk = __toESM(require_source(), 1);
101
+ var import_slugify = __toESM(require_slugify(), 1);
102
+ var SEARCH_ALL_PROJECTS = "search-all-projects";
103
+ var CREATE_NEW_PROJECT = "create-new-project";
104
+ var BACK_TO_PROJECT_SELECTION = Symbol("back-to-project-selection");
105
+ var BACK_TO_TEAM_SELECTION = Symbol("back-to-team-selection");
106
+ var SWITCH_GIT_REMOTE = Symbol("switch-git-remote");
107
+ var NO_EXISTING_PROJECTS = Symbol("no-existing-projects");
108
+ async function inputProjectDecision(client, defaultDecision) {
109
+ const createChoice = {
110
+ name: "Create new project",
111
+ value: "create"
112
+ };
113
+ const existingChoice = {
114
+ name: "Link existing project",
115
+ value: "existing"
116
+ };
117
+ return await client.input.select({
118
+ message: "Project?",
119
+ choices: defaultDecision === "existing" ? [existingChoice, createChoice] : [createChoice, existingChoice]
120
+ });
121
+ }
122
+ function randomNameSuffix() {
123
+ return Math.random().toString(36).slice(2, 6).padEnd(4, "0");
124
+ }
125
+ async function suggestNewProjectName(client, org, slugifiedName, knownTaken) {
126
+ let taken = knownTaken;
127
+ if (!taken) {
128
+ try {
129
+ const existing = await getProjectByNameOrId(
130
+ client,
131
+ slugifiedName,
132
+ org.id
133
+ );
134
+ taken = !(existing instanceof ProjectNotFound);
135
+ } catch {
136
+ taken = false;
137
+ }
138
+ }
139
+ return taken ? `${slugifiedName}-${randomNameSuffix()}` : slugifiedName;
140
+ }
141
+ function promptForProjectName(client, org, defaultName, message = "Name?") {
142
+ return client.input.text({
143
+ message,
144
+ default: defaultName,
145
+ validate: async (val) => {
146
+ if (!val) {
147
+ return "Project name cannot be empty";
148
+ }
149
+ const project = await getProjectByNameOrId(client, val, org.id);
150
+ if (!(project instanceof ProjectNotFound)) {
151
+ return "Project already exists";
152
+ }
153
+ return true;
154
+ }
155
+ });
156
+ }
157
+ async function promptForProjectNameWithBack(client, org, defaultName) {
158
+ try {
159
+ return await client.withPromptBackNavigation(
160
+ () => promptForProjectName(
161
+ client,
162
+ org,
163
+ defaultName,
164
+ `Name? ${import_chalk.default.dim("Press \u2191 to return to project options")}`
165
+ )
166
+ );
167
+ } catch (error) {
168
+ if (isPromptBackError(error)) {
169
+ return BACK_TO_PROJECT_SELECTION;
170
+ }
171
+ throw error;
172
+ }
173
+ }
174
+ async function searchExistingProjects(client, org, allowBack) {
175
+ const firstPage = await client.fetch(`/v9/projects?limit=100`, { accountId: org.id });
176
+ const projects = firstPage.projects;
177
+ const hasMoreProjects = firstPage.pagination.next != null;
178
+ if (projects.length === 0) {
179
+ output_manager_default.log(
180
+ `No existing projects found under ${import_chalk.default.bold(org.slug)}. Creating new project.`
181
+ );
182
+ return NO_EXISTING_PROJECTS;
183
+ }
184
+ const pageSize = 15;
185
+ const countHint = projects.length > pageSize ? ` ${import_chalk.default.dim(
186
+ `(${hasMoreProjects ? "100+" : projects.length} projects)`
187
+ )}` : "";
188
+ return await client.input.search({
189
+ message: `Which project?${countHint}`,
190
+ pageSize,
191
+ source: async (term, { signal }) => {
192
+ const searchTerm = term?.trim();
193
+ let matchingProjects = projects;
194
+ if (searchTerm) {
195
+ if (hasMoreProjects) {
196
+ matchingProjects = (await client.fetch(
197
+ `/v9/projects?search=${encodeURIComponent(searchTerm)}&limit=20`,
198
+ {
199
+ accountId: org.id,
200
+ signal
201
+ }
202
+ )).projects;
203
+ } else {
204
+ const normalizedSearchTerm = searchTerm.toLowerCase();
205
+ matchingProjects = projects.filter(
206
+ (project) => project.name.toLowerCase().includes(normalizedSearchTerm) || project.id === searchTerm
207
+ );
208
+ }
209
+ }
210
+ const choices = matchingProjects.slice().sort((a, b) => b.updatedAt - a.updatedAt).map((project) => ({
211
+ name: project.name,
212
+ value: project
213
+ }));
214
+ if (!allowBack) {
215
+ return choices;
216
+ }
217
+ const backChoice = {
218
+ name: "Back to project options",
219
+ value: BACK_TO_PROJECT_SELECTION
220
+ };
221
+ if (choices.length === 0) {
222
+ return [backChoice];
223
+ }
224
+ if (searchTerm) {
225
+ return choices;
226
+ }
227
+ return [...choices, new Separator(), backChoice];
228
+ }
229
+ });
230
+ }
231
+ async function inputProject(client, org, detectedProjectName, autoConfirm = false, skipAutoDetect = false, showProjectSuggestions = false, allowTeamSelectionBack = false, repoMatches = [], gitRemoteOptions) {
232
+ const slugifiedName = (0, import_slugify.default)(detectedProjectName);
233
+ const canSwitchGitRemote = (gitRemoteOptions?.remoteNames.length ?? 0) > 1;
234
+ let detectedProject = null;
235
+ if (!skipAutoDetect && repoMatches.length === 0) {
236
+ output_manager_default.spinner("Searching for existing projects\u2026", 1e3);
237
+ const [project, slugifiedProject] = await Promise.all([
238
+ getProjectByNameOrId(client, detectedProjectName, org.id),
239
+ slugifiedName !== detectedProjectName ? getProjectByNameOrId(client, slugifiedName, org.id) : null
240
+ ]);
241
+ detectedProject = !(project instanceof ProjectNotFound) ? project : !(slugifiedProject instanceof ProjectNotFound) ? slugifiedProject : null;
242
+ if (detectedProject && !detectedProject.id) {
243
+ throw new Error(`Detected linked project does not have "id".`);
244
+ }
245
+ output_manager_default.stopSpinner();
246
+ }
247
+ if (autoConfirm) {
248
+ if (repoMatches.length === 1) {
249
+ return repoMatches[0];
250
+ }
251
+ return detectedProject || detectedProjectName;
252
+ }
253
+ if (client.nonInteractive) {
254
+ if (detectedProject) {
255
+ return detectedProject;
256
+ }
257
+ const err = new Error("Confirmation required");
258
+ err.code = "HEADLESS";
259
+ throw err;
260
+ }
261
+ const slugifiedNameKnownFree = !skipAutoDetect && repoMatches.length === 0 && !detectedProject;
262
+ let memoizedDefaultName;
263
+ async function defaultNewProjectName() {
264
+ if (memoizedDefaultName === void 0) {
265
+ memoizedDefaultName = slugifiedNameKnownFree ? slugifiedName : await suggestNewProjectName(
266
+ client,
267
+ org,
268
+ slugifiedName,
269
+ detectedProject?.name === slugifiedName
270
+ );
271
+ }
272
+ return memoizedDefaultName;
273
+ }
274
+ let shouldLinkProject;
275
+ if (showProjectSuggestions && !skipAutoDetect) {
276
+ for (; ; ) {
277
+ const choices = [];
278
+ if (repoMatches.length > 0) {
279
+ choices.push(
280
+ ...repoMatches.map((match) => ({
281
+ name: `${match.project.name} ${import_chalk.default.gray("(linked by git)")}`,
282
+ value: match
283
+ })),
284
+ new Separator()
285
+ );
286
+ } else if (detectedProject) {
287
+ choices.push(
288
+ {
289
+ name: `${detectedProject.name} ${import_chalk.default.gray("(folder name)")}`,
290
+ value: detectedProject
291
+ },
292
+ new Separator()
293
+ );
294
+ }
295
+ choices.push(
296
+ {
297
+ name: "Search all projects",
298
+ value: SEARCH_ALL_PROJECTS,
299
+ description: "Browse or search every project in this team"
300
+ },
301
+ {
302
+ name: "Create a new project",
303
+ value: CREATE_NEW_PROJECT,
304
+ description: `Create it under ${org.slug}`
305
+ }
306
+ );
307
+ if (canSwitchGitRemote) {
308
+ const current = gitRemoteOptions?.currentRemoteName;
309
+ choices.push({
310
+ name: "Switch Git remote",
311
+ value: SWITCH_GIT_REMOTE,
312
+ description: current ? `Suggestions are from ${current}` : "Search projects linked to a different remote"
313
+ });
314
+ }
315
+ if (allowTeamSelectionBack) {
316
+ choices.push({
317
+ name: "Choose a different team",
318
+ value: BACK_TO_TEAM_SELECTION,
319
+ description: "Return to team selection"
320
+ });
321
+ }
322
+ const selected = await client.input.select({
323
+ message: "Which project?",
324
+ choices
325
+ });
326
+ if (selected === BACK_TO_TEAM_SELECTION) {
327
+ return BACK_TO_TEAM_SELECTION;
328
+ }
329
+ if (selected === SWITCH_GIT_REMOTE) {
330
+ return SWITCH_GIT_REMOTE;
331
+ }
332
+ if (selected === CREATE_NEW_PROJECT) {
333
+ const projectName = await promptForProjectNameWithBack(
334
+ client,
335
+ org,
336
+ await defaultNewProjectName()
337
+ );
338
+ if (projectName === BACK_TO_PROJECT_SELECTION) {
339
+ continue;
340
+ }
341
+ return projectName;
342
+ }
343
+ if (selected !== SEARCH_ALL_PROJECTS) {
344
+ return selected;
345
+ }
346
+ const existingProject = await searchExistingProjects(client, org, true);
347
+ if (existingProject === BACK_TO_PROJECT_SELECTION) {
348
+ continue;
349
+ }
350
+ if (existingProject === NO_EXISTING_PROJECTS) {
351
+ const projectName = await promptForProjectNameWithBack(
352
+ client,
353
+ org,
354
+ slugifiedName
355
+ );
356
+ if (projectName === BACK_TO_PROJECT_SELECTION) {
357
+ continue;
358
+ }
359
+ return projectName;
360
+ }
361
+ return existingProject;
362
+ }
363
+ } else if (!detectedProject) {
364
+ const decision = await inputProjectDecision(
365
+ client,
366
+ skipAutoDetect ? "existing" : "create"
367
+ );
368
+ shouldLinkProject = decision === "existing";
369
+ } else {
370
+ output_manager_default.print(` ${import_chalk.default.bold("Found existing project")}
371
+ `);
372
+ printAlignedLabel("Project", `${org.slug}/${detectedProject.name}`);
373
+ if (await client.input.confirm(`Link directory to project?`, true)) {
374
+ return detectedProject;
375
+ }
376
+ const decision = await inputProjectDecision(client, "existing");
377
+ shouldLinkProject = decision === "existing";
378
+ }
379
+ if (shouldLinkProject) {
380
+ const existingProject = await searchExistingProjects(client, org, false);
381
+ if (existingProject !== NO_EXISTING_PROJECTS && existingProject !== BACK_TO_PROJECT_SELECTION) {
382
+ return existingProject;
383
+ }
384
+ }
385
+ return await promptForProjectName(client, org, await defaultNewProjectName());
386
+ }
387
+
388
+ // src/util/input/input-root-directory.ts
389
+ var import_chalk2 = __toESM(require_source(), 1);
390
+ import { normalizePath } from "@vercel/build-utils";
391
+ import path from "path";
392
+ async function inputRootDirectory(client, cwd, autoConfirm = false) {
393
+ if (autoConfirm) {
394
+ return null;
395
+ }
396
+ while (true) {
397
+ const rootDirectory = await client.input.text({
398
+ message: `Code directory?`,
399
+ transformer: (input) => {
400
+ return `${import_chalk2.default.dim(`./`)}${input}`;
401
+ }
402
+ });
403
+ if (!rootDirectory) {
404
+ return null;
405
+ }
406
+ const normal = path.normalize(rootDirectory);
407
+ if (normal === "." || normal === "./") {
408
+ return null;
409
+ }
410
+ const fullPath = path.join(cwd, normal);
411
+ if (await validateRootDirectory(
412
+ cwd,
413
+ fullPath,
414
+ "Please choose a different one."
415
+ ) === false) {
416
+ continue;
417
+ }
418
+ return normalizePath(normal);
419
+ }
420
+ }
421
+
422
+ // src/util/input/edit-project-settings.ts
423
+ var import_chalk3 = __toESM(require_source(), 1);
424
+ var import_frameworks = __toESM(require_frameworks(), 1);
425
+
426
+ // src/util/is-setting-value.ts
427
+ function isSettingValue(setting) {
428
+ return setting && typeof setting.value === "string";
429
+ }
430
+
431
+ // src/util/input/edit-project-settings.ts
432
+ var settingMap = {
433
+ buildCommand: "Build Command",
434
+ devCommand: "Development Command",
435
+ commandForIgnoringBuildStep: "Ignore Command",
436
+ installCommand: "Install Command",
437
+ outputDirectory: "Output Directory",
438
+ framework: "Framework"
439
+ };
440
+ var settingKeys = Object.keys(settingMap).sort();
441
+ async function editProjectSettings(client, projectSettings, framework, autoConfirm, localConfigurationOverrides, configFileName = "vercel.json") {
442
+ const settings = Object.assign(
443
+ {
444
+ buildCommand: null,
445
+ devCommand: null,
446
+ framework: null,
447
+ commandForIgnoringBuildStep: null,
448
+ installCommand: null,
449
+ outputDirectory: null
450
+ },
451
+ projectSettings
452
+ );
453
+ const hasLocalConfigurationOverrides = localConfigurationOverrides && Object.values(localConfigurationOverrides ?? {}).some(Boolean);
454
+ if (hasLocalConfigurationOverrides) {
455
+ for (const setting of settingKeys) {
456
+ const localConfigValue = localConfigurationOverrides[setting];
457
+ if (localConfigValue)
458
+ settings[setting] = localConfigValue;
459
+ }
460
+ output_manager_default.print(` Local settings detected in ${configFileName}:
461
+ `);
462
+ for (const setting of settingKeys) {
463
+ const override = localConfigurationOverrides[setting];
464
+ if (override) {
465
+ output_manager_default.print(
466
+ ` ${import_chalk3.default.dim(
467
+ `${import_chalk3.default.bold(`${settingMap[setting]}:`)} ${override}`
468
+ )}
469
+ `
470
+ );
471
+ }
472
+ }
473
+ if (localConfigurationOverrides.framework) {
474
+ const overrideFramework = import_frameworks.frameworkList.find(
475
+ (f) => f.slug === localConfigurationOverrides.framework
476
+ );
477
+ if (overrideFramework) {
478
+ framework = overrideFramework;
479
+ output_manager_default.print(
480
+ ` Merging default Project Settings for ${framework.name}. Previously listed overrides are prioritized.
481
+ `
482
+ );
483
+ }
484
+ }
485
+ }
486
+ if (!framework) {
487
+ settings.framework = null;
488
+ return settings;
489
+ }
490
+ output_manager_default.print("\n");
491
+ if (!framework.slug) {
492
+ output_manager_default.print(` No framework detected. Default Project Settings:
493
+ `);
494
+ } else {
495
+ const buildCmd = framework.settings.buildCommand?.value ?? null;
496
+ const outputSetting = framework.settings.outputDirectory;
497
+ const outputDir = outputSetting ? isSettingValue(outputSetting) ? outputSetting.value : outputSetting.placeholder : null;
498
+ const inline = [
499
+ buildCmd ? `${settingMap.buildCommand}: ${buildCmd}` : null,
500
+ outputDir ? `${settingMap.outputDirectory}: ${outputDir}` : null
501
+ ].filter(Boolean);
502
+ const detail = inline.length ? import_chalk3.default.dim(` (${inline.join(", ")})`) : "";
503
+ output_manager_default.print(` ${import_chalk3.default.bold("Detected")} ${framework.name}${detail}
504
+ `);
505
+ }
506
+ settings.framework = framework.slug;
507
+ if (!framework.slug) {
508
+ for (const setting of settingKeys) {
509
+ if (setting === "framework" || setting === "commandForIgnoringBuildStep") {
510
+ continue;
511
+ }
512
+ const defaultSetting = framework.settings[setting];
513
+ const override = localConfigurationOverrides?.[setting];
514
+ if (!override && defaultSetting) {
515
+ output_manager_default.print(
516
+ ` ${import_chalk3.default.dim(
517
+ `${import_chalk3.default.bold(`${settingMap[setting]}:`)} ${isSettingValue(defaultSetting) ? defaultSetting.value : import_chalk3.default.italic(`${defaultSetting.placeholder}`)}`
518
+ )}
519
+ `
520
+ );
521
+ }
522
+ }
523
+ }
524
+ if (autoConfirm || !await client.input.confirm("Customize settings?", false)) {
525
+ return settings;
526
+ }
527
+ const choices = settingKeys.reduce(
528
+ (acc, setting) => {
529
+ const skip = setting === "framework" || setting === "commandForIgnoringBuildStep" || setting === "installCommand" || localConfigurationOverrides?.[setting];
530
+ if (skip)
531
+ return acc;
532
+ return [...acc, { name: settingMap[setting], value: setting }];
533
+ },
534
+ []
535
+ );
536
+ const settingFields = await client.input.checkbox({
537
+ message: "Which settings would you like to overwrite (select multiple)?",
538
+ choices
539
+ });
540
+ for (const setting of settingFields) {
541
+ const field = settingMap[setting];
542
+ settings[setting] = await client.input.text({
543
+ message: `${import_chalk3.default.bold(field)}?`
544
+ });
545
+ }
546
+ return settings;
547
+ }
548
+
549
+ // src/util/config/read-config.ts
550
+ async function readConfig(dir) {
551
+ let pkgFilePath;
552
+ try {
553
+ const compileResult = await compileVercelConfig(dir);
554
+ pkgFilePath = compileResult.configPath || getLocalPathConfig(dir);
555
+ } catch (err) {
556
+ if (err instanceof Error) {
557
+ return err;
558
+ }
559
+ throw err;
560
+ }
561
+ const result = await readJSONFile(pkgFilePath);
562
+ if (result instanceof CantParseJSONFile) {
563
+ return result;
564
+ }
565
+ if (result) {
566
+ return result;
567
+ }
568
+ return null;
569
+ }
570
+
571
+ // src/util/link/setup-and-link.ts
572
+ var import_frameworks3 = __toESM(require_frameworks(), 1);
573
+
574
+ // src/util/input/vercel-auth.ts
575
+ var import_chalk4 = __toESM(require_source(), 1);
576
+ var DEFAULT_VERCEL_AUTH_SETTING = "standard";
577
+ var OPTIONS = {
578
+ message: `What setting do you want to use for Vercel Authentication?`,
579
+ default: DEFAULT_VERCEL_AUTH_SETTING,
580
+ choices: [
581
+ {
582
+ description: "Standard Protection (recommended)",
583
+ name: "standard",
584
+ value: "standard"
585
+ },
586
+ {
587
+ description: "No Protection (all deployments will be public)",
588
+ name: "none",
589
+ value: "none"
590
+ }
591
+ ]
592
+ };
593
+ async function vercelAuth(client, {
594
+ autoConfirm = false
595
+ }) {
596
+ if (autoConfirm || await client.input.confirm(
597
+ `Want to use the default Deployment Protection settings? ${import_chalk4.default.dim(`(Vercel Authentication: Standard Protection)`)}`,
598
+ true
599
+ )) {
600
+ return DEFAULT_VERCEL_AUTH_SETTING;
601
+ }
602
+ const vercelAuth2 = await client.input.select(OPTIONS);
603
+ return vercelAuth2;
604
+ }
605
+
606
+ // src/util/link/services-setup.ts
607
+ var import_fs_detectors = __toESM(require_dist(), 1);
608
+ var import_service_topology = __toESM(require_dist2(), 1);
609
+ import {
610
+ isExperimentalService,
611
+ isExperimentalServiceV2 as isExperimentalServiceV22,
612
+ normalizePath as normalizePath2
613
+ } from "@vercel/build-utils";
614
+ import { join, relative } from "path";
615
+
616
+ // src/util/input/display-services.ts
617
+ var import_frameworks2 = __toESM(require_frameworks(), 1);
618
+ import {
619
+ getServiceQueueTopics,
620
+ isExperimentalServiceV2,
621
+ isQueueTriggeredService,
622
+ isScheduleTriggeredService,
623
+ isWorkflowTriggeredService
624
+ } from "@vercel/build-utils";
625
+ var chalk5 = require_source();
626
+ var frameworksBySlug = new Map(import_frameworks2.frameworkList.map((f) => [f.slug, f]));
627
+ var frameworkColors = {
628
+ // JavaScript/TypeScript frameworks
629
+ nextjs: chalk5.white,
630
+ vite: chalk5.magenta,
631
+ nuxtjs: chalk5.green,
632
+ remix: chalk5.cyan,
633
+ astro: chalk5.magenta,
634
+ gatsby: chalk5.magenta,
635
+ svelte: chalk5.red,
636
+ sveltekit: chalk5.red,
637
+ solidstart: chalk5.blue,
638
+ angular: chalk5.red,
639
+ vue: chalk5.green,
640
+ ember: chalk5.red,
641
+ preact: chalk5.magenta,
642
+ // Python frameworks
643
+ fastapi: chalk5.green,
644
+ flask: chalk5.cyan,
645
+ // Node frameworks
646
+ express: chalk5.yellow,
647
+ nest: chalk5.red,
648
+ hono: chalk5.yellowBright
649
+ };
650
+ var runtimeColors = {
651
+ node: chalk5.green,
652
+ python: chalk5.blue,
653
+ go: chalk5.cyan,
654
+ ruby: chalk5.red,
655
+ rust: chalk5.yellowBright
656
+ };
657
+ function getFrameworkName(slug) {
658
+ if (!slug)
659
+ return void 0;
660
+ return frameworksBySlug.get(slug)?.name;
661
+ }
662
+ function formatRoutePrefix(routePrefix) {
663
+ if (routePrefix === "/") {
664
+ return "/";
665
+ }
666
+ const normalized = routePrefix.startsWith("/") ? routePrefix : `/${routePrefix}`;
667
+ return `${normalized}/*`;
668
+ }
669
+ var jobTriggerLabels = {
670
+ queue: "Job/Queue",
671
+ schedule: "Job/Schedule",
672
+ workflow: "Job/Workflow"
673
+ };
674
+ function getServiceDescriptionInfo(service) {
675
+ if (service.type === "worker" || service.type === "job" || service.type === "cron") {
676
+ const typeLabel = service.type === "worker" ? "Worker" : jobTriggerLabels[service.trigger ?? ""] ?? "Job";
677
+ const typeColorFn = service.type === "worker" ? chalk5.magenta : chalk5.cyan;
678
+ if (service.runtime) {
679
+ const runtimeName = service.runtime.charAt(0).toUpperCase() + service.runtime.slice(1);
680
+ const runtimeColorFn = runtimeColors[service.runtime] || chalk5.yellow;
681
+ const label = `${typeLabel}${chalk5.white("/")}${runtimeColorFn(runtimeName)}`;
682
+ return { label, colorFn: typeColorFn };
683
+ }
684
+ return { label: typeLabel, colorFn: typeColorFn };
685
+ }
686
+ return getFrameworkRuntimeBuilderInfo(service);
687
+ }
688
+ function getFrameworkRuntimeBuilderInfo(service) {
689
+ const frameworkName = getFrameworkName(service.framework);
690
+ if (frameworkName && service.framework) {
691
+ const colorFn = frameworkColors[service.framework] || chalk5.cyan;
692
+ return { label: frameworkName, colorFn };
693
+ } else if (service.runtime) {
694
+ const normalizedRuntime = service.runtime.toLowerCase().replace(/@.*$/, "");
695
+ const colorFn = runtimeColors[normalizedRuntime] || chalk5.yellow;
696
+ return { label: service.runtime, colorFn };
697
+ } else if (service.builder?.use) {
698
+ return { label: service.builder.use, colorFn: chalk5.magenta };
699
+ }
700
+ return { label: "unknown", colorFn: chalk5.dim };
701
+ }
702
+ function getServiceTarget(service) {
703
+ if (isScheduleTriggeredService(service)) {
704
+ return `schedule: ${service.schedule ?? "none"}`;
705
+ }
706
+ if (isQueueTriggeredService(service)) {
707
+ const topics = getServiceQueueTopics(service);
708
+ return `topics: ${topics.join(", ")}`;
709
+ }
710
+ if (isWorkflowTriggeredService(service)) {
711
+ return "workflow";
712
+ }
713
+ return service.routePrefix ? formatRoutePrefix(service.routePrefix) : "no route";
714
+ }
715
+ function displayDetectedServices(services) {
716
+ output_manager_default.print(`Detected services:
717
+ `);
718
+ const rows = services.some(isExperimentalServiceV2) ? buildServiceRowsV2(services.filter(isExperimentalServiceV2)) : buildServiceRowsV1(services);
719
+ const tableOutput = table(rows, { align: ["l", "l", "l", "l"], hsep: 2 });
720
+ output_manager_default.print(`${tableOutput}
721
+ `);
722
+ }
723
+ function buildServiceRowsV1(services) {
724
+ const outputOrder = {
725
+ web: 0,
726
+ cron: 1,
727
+ job: 1,
728
+ worker: 2
729
+ };
730
+ const sorted = [...services].sort(
731
+ (a, b) => (outputOrder[a.type] ?? 3) - (outputOrder[b.type] ?? 3)
732
+ );
733
+ return sorted.map((service) => {
734
+ const descInfo = getServiceDescriptionInfo(service);
735
+ const target = getServiceTarget(service);
736
+ return [
737
+ `\u2022 ${service.name}`,
738
+ descInfo.colorFn(`[${descInfo.label}]`),
739
+ chalk5.dim("\u2192"),
740
+ target
741
+ ];
742
+ });
743
+ }
744
+ function buildServiceRowsV2(services) {
745
+ return services.map((service) => {
746
+ const descInfo = getFrameworkRuntimeBuilderInfo(service);
747
+ return [`\u2022 ${service.name}`, descInfo.colorFn(`[${descInfo.label}]`)];
748
+ });
749
+ }
750
+ function displayServicesConfigNote(configFileName = "vercel.json") {
751
+ output_manager_default.print(
752
+ `
753
+ ${chalk5.dim(`Services are configured via ${configFileName}.`)}
754
+ `
755
+ );
756
+ }
757
+ function displayServiceErrors(errors) {
758
+ for (const error of errors) {
759
+ output_manager_default.warn(error.message);
760
+ }
761
+ }
762
+
763
+ // src/util/link/services-setup.ts
764
+ var SERVICES_DOCS_URL = "https://vercel.com/docs/services";
765
+ var INFERRED_SERVICES_PROMPT = "Multiple services were detected. How would you like to set up this project?";
766
+ async function getServicesSetupState(workPath) {
767
+ const detectServicesResult = await (0, import_service_topology.detectServices)({
768
+ fs: new import_fs_detectors.LocalFileSystemDetector(workPath),
769
+ detectEntrypoint: createDetectEntrypoint(workPath)
770
+ });
771
+ const hasConfiguredServices = detectServicesResult.resolved?.source === "configured";
772
+ const inferredServices = hasConfiguredServices ? null : detectServicesResult.inferred;
773
+ const inferredServicesWriteBlocker = inferredServices ? await getServicesConfigWriteBlocker(workPath, inferredServices.config) : null;
774
+ return {
775
+ detectServicesResult,
776
+ hasConfiguredServices,
777
+ inferredServices,
778
+ inferredServicesWriteBlocker
779
+ };
780
+ }
781
+ function displayConfiguredServicesSetup(detectServicesResult, configFileName = "vercel.json") {
782
+ const v1Services = detectServicesResult.services.filter(
783
+ isExperimentalService
784
+ );
785
+ if (v1Services.length > 0) {
786
+ displayDetectedServices(v1Services);
787
+ }
788
+ if (detectServicesResult.errors.length > 0) {
789
+ displayServiceErrors(detectServicesResult.errors);
790
+ }
791
+ displayServicesConfigNote(configFileName);
792
+ }
793
+ function formatDetectedServicesSummary(services) {
794
+ if (services.length === 0) {
795
+ return "";
796
+ }
797
+ if (services.length === 1) {
798
+ return `"${services[0].name}"`;
799
+ }
800
+ if (services.length === 2) {
801
+ return `"${services[0].name}" + "${services[1].name}"`;
802
+ }
803
+ const othersCount = services.length - 2;
804
+ return `"${services[0].name}" + "${services[1].name}" + ${othersCount} ${othersCount === 1 ? "other" : "others"}`;
805
+ }
806
+ function toProjectRootDirectory(projectPath, selectedPath) {
807
+ const rootDirectory = normalizePath2(relative(projectPath, selectedPath));
808
+ return rootDirectory === "" ? null : rootDirectory;
809
+ }
810
+ async function promptForInferredServicesSetup({
811
+ client,
812
+ autoConfirm,
813
+ nonInteractive,
814
+ workPath,
815
+ inferred,
816
+ inferredWriteBlocker,
817
+ allowChooseDifferentProjectDirectory = false
818
+ }) {
819
+ if (!inferred) {
820
+ return null;
821
+ }
822
+ if (inferredWriteBlocker) {
823
+ output_manager_default.warn(
824
+ `Multiple services were detected, but your existing project config uses \`${inferredWriteBlocker}\`. To deploy multiple services in one project, see ${output_manager_default.link("Services", SERVICES_DOCS_URL)}.`
825
+ );
826
+ return null;
827
+ }
828
+ displayDetectedServices(inferred.services);
829
+ let choice = null;
830
+ if (autoConfirm) {
831
+ choice = { type: "services" };
832
+ } else if (!nonInteractive) {
833
+ const webServices = inferred.services.filter(
834
+ (service) => isExperimentalService(service) ? service.type === "web" : true
835
+ );
836
+ const choices = [
837
+ {
838
+ name: `Set up project with all detected services: ${formatDetectedServicesSummary(
839
+ inferred.services
840
+ )}`,
841
+ value: "services"
842
+ },
843
+ ...webServices.map((service, index) => ({
844
+ name: `Set up project with "${service.name}"`,
845
+ value: `single-app:${index}`
846
+ })),
847
+ ...allowChooseDifferentProjectDirectory ? [
848
+ {
849
+ name: "Choose a different root directory",
850
+ value: "project-directory"
851
+ }
852
+ ] : []
853
+ ];
854
+ const selected = await client.input.select({
855
+ message: INFERRED_SERVICES_PROMPT,
856
+ choices
857
+ });
858
+ if (selected === "services") {
859
+ choice = { type: "services" };
860
+ } else if (selected === "project-directory") {
861
+ choice = { type: "project-directory" };
862
+ } else if (typeof selected === "string" && selected.startsWith("single-app:")) {
863
+ const index = Number.parseInt(selected.slice("single-app:".length), 10);
864
+ const service = webServices[index];
865
+ if (service) {
866
+ const serviceRoot = isExperimentalServiceV22(service) ? service.root : service.workspace;
867
+ choice = {
868
+ type: "single-app",
869
+ selectedPath: serviceRoot === "." ? workPath : join(workPath, serviceRoot)
870
+ };
871
+ }
872
+ }
873
+ }
874
+ if (choice?.type !== "services") {
875
+ return choice;
876
+ }
877
+ const { configFileName } = await writeServicesConfig(
878
+ workPath,
879
+ inferred.config
880
+ );
881
+ output_manager_default.print(` Added services configuration to ${configFileName}.
882
+ `);
883
+ return { type: "services" };
884
+ }
885
+
886
+ // src/util/projects/search-project-across-teams.ts
887
+ var import_slugify2 = __toESM(require_slugify(), 1);
888
+ import { join as join2, relative as relative2 } from "path";
889
+ async function searchProjectsByRepoRoot({
890
+ client,
891
+ cwd,
892
+ gitProjectName,
893
+ orgs,
894
+ remoteName
895
+ }) {
896
+ const empty = { matches: [], remoteNames: [] };
897
+ const rootPath = await findRepoRoot(cwd);
898
+ if (!rootPath) {
899
+ return empty;
900
+ }
901
+ const gitConfigPath = getGitConfigPath({ cwd: rootPath }) ?? join2(rootPath, ".git/config");
902
+ const remoteUrls = await getRemoteUrls(gitConfigPath);
903
+ const remoteNames = remoteUrls ? Object.keys(remoteUrls).sort() : [];
904
+ let remote;
905
+ try {
906
+ remote = await resolveGitRemote(client, rootPath, {
907
+ yes: true,
908
+ existingRemoteName: remoteName
909
+ });
910
+ } catch (error) {
911
+ if (isPromptCanceledError(error)) {
912
+ throw error;
913
+ }
914
+ output_manager_default.debug(`Failed to resolve Git remote for project search: ${error}`);
915
+ return { matches: [], remoteNames };
916
+ }
917
+ if (!remote) {
918
+ return { matches: [], remoteNames };
919
+ }
920
+ const relativePath = relative2(rootPath, cwd);
921
+ const results = await Promise.all(
922
+ orgs.map(async (org) => {
923
+ try {
924
+ const projects = await fetchProjectsForRepoUrl(
925
+ client,
926
+ remote.repoUrl,
927
+ org.id
928
+ );
929
+ const repoProjectConfigs = projects.filter(
930
+ (project) => !gitProjectName || project.id === gitProjectName || project.name === gitProjectName
931
+ ).map((project) => ({
932
+ id: project.id,
933
+ name: project.name,
934
+ directory: project.rootDirectory || ".",
935
+ orgId: org.id
936
+ }));
937
+ const matchingProjects = findProjectsFromPath(
938
+ repoProjectConfigs,
939
+ relativePath
940
+ );
941
+ return matchingProjects.map((match) => {
942
+ const project = projects.find((p) => p.id === match.id);
943
+ if (!project) {
944
+ return null;
945
+ }
946
+ return {
947
+ project,
948
+ org,
949
+ reason: "repo-root",
950
+ repo: {
951
+ ...remote,
952
+ directory: match.directory
953
+ }
954
+ };
955
+ }).filter(Boolean);
956
+ } catch (error) {
957
+ if (isPromptCanceledError(error)) {
958
+ throw error;
959
+ }
960
+ output_manager_default.debug(
961
+ `Failed to search Git-linked projects under ${org.slug}: ${error}`
962
+ );
963
+ return [];
964
+ }
965
+ })
966
+ );
967
+ return {
968
+ matches: results.flat(),
969
+ remote,
970
+ remoteNames
971
+ };
972
+ }
973
+
974
+ // src/util/link/setup-and-link.ts
975
+ function isCrossTeamMatch(value) {
976
+ return typeof value === "object" && value !== null && "project" in value && "org" in value && "reason" in value;
977
+ }
978
+ async function selectOrgForLink(client, autoConfirm, searchable = false, meta) {
979
+ try {
980
+ return await selectOrg(
981
+ client,
982
+ "Which team?",
983
+ autoConfirm,
984
+ searchable,
985
+ meta
986
+ );
987
+ } catch (err) {
988
+ if (isAPIError(err)) {
989
+ if (err.code === "NOT_AUTHORIZED") {
990
+ output_manager_default.prettyError(err);
991
+ return { status: "error", exitCode: 1, reason: "NOT_AUTHORIZED" };
992
+ }
993
+ if (err.code === "TEAM_DELETED") {
994
+ output_manager_default.prettyError(err);
995
+ return { status: "error", exitCode: 1, reason: "TEAM_DELETED" };
996
+ }
997
+ }
998
+ throw err;
999
+ }
1000
+ }
1001
+ function isErrnoException(err) {
1002
+ return err instanceof Error && typeof err.code === "string";
1003
+ }
1004
+ async function hasWorkspaces(cwd) {
1005
+ try {
1006
+ const fs = new import_fs_detectors2.LocalFileSystemDetector(cwd);
1007
+ const workspaces = await (0, import_fs_detectors2.getWorkspaces)({ fs });
1008
+ return workspaces.length > 0;
1009
+ } catch (err) {
1010
+ if (isErrnoException(err) && err.code && ["ENOENT", "EACCES", "ENOTDIR"].includes(err.code)) {
1011
+ output_manager_default.debug(`getWorkspaces failed for ${cwd}: ${err}`);
1012
+ return false;
1013
+ }
1014
+ throw err;
1015
+ }
1016
+ }
1017
+ async function shouldPromptForRootDirectory(opts) {
1018
+ if (opts.servicesChoice?.type === "project-directory") {
1019
+ return true;
1020
+ }
1021
+ if (await hasWorkspaces(opts.path)) {
1022
+ return true;
1023
+ }
1024
+ try {
1025
+ const detected = await detectProjects(opts.path);
1026
+ const frameworksAtRoot = detected.get("") ?? [];
1027
+ return frameworksAtRoot.length === 0;
1028
+ } catch (err) {
1029
+ output_manager_default.debug(`detectProjects failed at root: ${err}`);
1030
+ return true;
1031
+ }
1032
+ }
1033
+ async function maybePullEnvAfterLink(client, path2, autoConfirm, pullEnv) {
1034
+ if (!pullEnv || !client.stdin.isTTY || client.nonInteractive) {
1035
+ return;
1036
+ }
1037
+ output_manager_default.print("\n");
1038
+ const pullEnvConfirmed = autoConfirm || await client.input.confirm(
1039
+ "Pull development environment variables into .env.local?",
1040
+ true
1041
+ );
1042
+ if (!pullEnvConfirmed) {
1043
+ return;
1044
+ }
1045
+ const originalCwd = client.cwd;
1046
+ try {
1047
+ client.cwd = path2;
1048
+ const args = autoConfirm ? ["--yes"] : [];
1049
+ const exitCode = await pull(client, args, "vercel-cli:link");
1050
+ if (exitCode !== 0) {
1051
+ output_manager_default.error(
1052
+ "Failed to pull environment variables. You can run `vc env pull` manually."
1053
+ );
1054
+ }
1055
+ } catch (_error) {
1056
+ output_manager_default.error(
1057
+ "Failed to pull environment variables. You can run `vc env pull` manually."
1058
+ );
1059
+ } finally {
1060
+ client.cwd = originalCwd;
1061
+ }
1062
+ }
1063
+ async function linkCrossTeamMatch({
1064
+ client,
1065
+ path: path2,
1066
+ match,
1067
+ successEmoji,
1068
+ autoConfirm,
1069
+ pullEnv
1070
+ }) {
1071
+ client.config.currentTeam = match.org.type === "team" ? match.org.id : void 0;
1072
+ if (match.reason === "repo-root" && match.repo) {
1073
+ await linkRepoProject(client, path2, {
1074
+ project: match.project,
1075
+ orgId: match.org.id,
1076
+ orgSlug: match.org.slug,
1077
+ remoteName: match.repo.remoteName,
1078
+ successEmoji
1079
+ });
1080
+ await maybePullEnvAfterLink(client, path2, autoConfirm, pullEnv);
1081
+ return {
1082
+ status: "linked",
1083
+ org: match.org,
1084
+ project: match.project,
1085
+ repoRoot: match.repo.rootPath
1086
+ };
1087
+ }
1088
+ await linkFolderToProject(
1089
+ client,
1090
+ path2,
1091
+ { projectId: match.project.id, orgId: match.org.id },
1092
+ match.project.name,
1093
+ match.org.slug,
1094
+ successEmoji,
1095
+ autoConfirm,
1096
+ pullEnv
1097
+ );
1098
+ return { status: "linked", org: match.org, project: match.project };
1099
+ }
1100
+ async function setupAndLink(client, path2, {
1101
+ autoConfirm = false,
1102
+ forceDelete = false,
1103
+ link,
1104
+ selectedOrg,
1105
+ successEmoji = "link",
1106
+ projectName,
1107
+ nonInteractive = false,
1108
+ pullEnv = true,
1109
+ v0
1110
+ }) {
1111
+ const { config } = client;
1112
+ const gitProjectName = projectName;
1113
+ projectName = projectName ?? basename(path2);
1114
+ if (!isDirectory(path2)) {
1115
+ output_manager_default.error(`Expected directory but found file: ${path2}`);
1116
+ return { status: "error", exitCode: 1, reason: "PATH_IS_FILE" };
1117
+ }
1118
+ if (!link) {
1119
+ link = await getLinkedProject(client, { cwd: path2 });
1120
+ }
1121
+ const isTTY = client.stdin.isTTY;
1122
+ let rootDirectory = null;
1123
+ let newProjectName;
1124
+ let org = selectedOrg;
1125
+ if (!forceDelete && link.status === "linked") {
1126
+ return link;
1127
+ }
1128
+ if (getPlatformEnv("ORG_ID") && getPlatformEnv("PROJECT_ID")) {
1129
+ const envLink = await getLinkedProject(client, { cwd: path2 });
1130
+ if (envLink.status === "error") {
1131
+ return envLink;
1132
+ }
1133
+ if (envLink.status === "linked") {
1134
+ config.currentTeam = envLink.org.type === "team" ? envLink.org.id : void 0;
1135
+ output_manager_default.print("\n");
1136
+ printAlignedLabel("Directory", humanizePath(path2));
1137
+ printAlignedLabel("Source", "VERCEL_ORG_ID and VERCEL_PROJECT_ID");
1138
+ output_manager_default.print("\n");
1139
+ printAlignedLabel(
1140
+ "Linked",
1141
+ `${envLink.org.slug}/${envLink.project.name}`,
1142
+ { gutter: "\u2713" }
1143
+ );
1144
+ return envLink;
1145
+ }
1146
+ }
1147
+ if (!isTTY && !autoConfirm && !nonInteractive) {
1148
+ return { status: "error", exitCode: 1, reason: "HEADLESS" };
1149
+ }
1150
+ if (!org && (nonInteractive || !isTTY)) {
1151
+ const resolved = await selectOrgForLink(client, autoConfirm);
1152
+ if ("status" in resolved) {
1153
+ return resolved;
1154
+ }
1155
+ org = resolved;
1156
+ }
1157
+ if (forceDelete) {
1158
+ const vercelDir = getVercelDirectory(path2);
1159
+ (0, import_fs_extra.remove)(join3(vercelDir, VERCEL_DIR_README));
1160
+ (0, import_fs_extra.remove)(join3(vercelDir, VERCEL_DIR_PROJECT));
1161
+ }
1162
+ output_manager_default.print("\n");
1163
+ printAlignedLabel("Directory", humanizePath(path2));
1164
+ output_manager_default.print("\n");
1165
+ const interactive = isTTY && !nonInteractive;
1166
+ const searchableTeamPicker = interactive;
1167
+ const showProjectSuggestions = interactive && !gitProjectName;
1168
+ let projectOrNewProjectName;
1169
+ let teamAutoSelected = false;
1170
+ let selectedGitRemoteName;
1171
+ for (; ; ) {
1172
+ if (!org) {
1173
+ const orgMeta = {};
1174
+ const resolved = await selectOrgForLink(
1175
+ client,
1176
+ autoConfirm,
1177
+ searchableTeamPicker,
1178
+ orgMeta
1179
+ );
1180
+ if ("status" in resolved) {
1181
+ return resolved;
1182
+ }
1183
+ org = resolved;
1184
+ teamAutoSelected = orgMeta.choiceCount === 1;
1185
+ }
1186
+ let repoMatches = [];
1187
+ let gitRemoteNames = [];
1188
+ let currentGitRemoteName;
1189
+ if (showProjectSuggestions) {
1190
+ output_manager_default.spinner("Searching for existing projects\u2026", 1e3);
1191
+ try {
1192
+ const repoSearch = await searchProjectsByRepoRoot({
1193
+ client,
1194
+ cwd: path2,
1195
+ gitProjectName,
1196
+ orgs: [org],
1197
+ remoteName: selectedGitRemoteName
1198
+ });
1199
+ repoMatches = repoSearch.matches;
1200
+ gitRemoteNames = repoSearch.remoteNames;
1201
+ currentGitRemoteName = repoSearch.remote?.remoteName;
1202
+ } catch (err) {
1203
+ if (isPromptCanceledError(err)) {
1204
+ throw err;
1205
+ }
1206
+ output_manager_default.debug(`Git-linked project search failed: ${err}`);
1207
+ } finally {
1208
+ output_manager_default.stopSpinner();
1209
+ }
1210
+ }
1211
+ try {
1212
+ projectOrNewProjectName = await inputProject(
1213
+ client,
1214
+ org,
1215
+ projectName,
1216
+ autoConfirm,
1217
+ false,
1218
+ showProjectSuggestions,
1219
+ searchableTeamPicker && !selectedOrg && !teamAutoSelected,
1220
+ repoMatches,
1221
+ {
1222
+ remoteNames: gitRemoteNames,
1223
+ currentRemoteName: currentGitRemoteName
1224
+ }
1225
+ );
1226
+ } catch (err) {
1227
+ if (err instanceof Error && err.code === "HEADLESS") {
1228
+ return { status: "error", exitCode: 1, reason: "HEADLESS" };
1229
+ }
1230
+ throw err;
1231
+ }
1232
+ if (projectOrNewProjectName === BACK_TO_TEAM_SELECTION) {
1233
+ org = void 0;
1234
+ selectedGitRemoteName = void 0;
1235
+ continue;
1236
+ }
1237
+ if (projectOrNewProjectName === SWITCH_GIT_REMOTE) {
1238
+ const rootPath = await findRepoRoot(path2);
1239
+ if (!rootPath) {
1240
+ continue;
1241
+ }
1242
+ try {
1243
+ const remote = await resolveGitRemote(client, rootPath, {
1244
+ yes: false
1245
+ });
1246
+ selectedGitRemoteName = remote?.remoteName;
1247
+ } catch (err) {
1248
+ if (isPromptCanceledError(err)) {
1249
+ throw err;
1250
+ }
1251
+ output_manager_default.debug(`Failed to switch Git remote: ${err}`);
1252
+ }
1253
+ continue;
1254
+ }
1255
+ break;
1256
+ }
1257
+ if (typeof projectOrNewProjectName === "string") {
1258
+ newProjectName = projectOrNewProjectName;
1259
+ } else if (isCrossTeamMatch(projectOrNewProjectName)) {
1260
+ return await linkCrossTeamMatch({
1261
+ client,
1262
+ path: path2,
1263
+ match: projectOrNewProjectName,
1264
+ successEmoji,
1265
+ autoConfirm,
1266
+ pullEnv
1267
+ });
1268
+ } else {
1269
+ const project = projectOrNewProjectName;
1270
+ await linkFolderToProject(
1271
+ client,
1272
+ path2,
1273
+ {
1274
+ projectId: project.id,
1275
+ orgId: org.id
1276
+ },
1277
+ project.name,
1278
+ org.slug,
1279
+ successEmoji,
1280
+ autoConfirm,
1281
+ pullEnv
1282
+ );
1283
+ return { status: "linked", org, project };
1284
+ }
1285
+ config.currentTeam = org.type === "team" ? org.id : void 0;
1286
+ const gitConnectIntent = await resolveGitConnectIntent(
1287
+ client,
1288
+ path2,
1289
+ autoConfirm
1290
+ );
1291
+ const rootServicesSetup = await getServicesSetupState(path2);
1292
+ const configFileName = await findSourceVercelConfigFile(path2) ?? "vercel.json";
1293
+ try {
1294
+ let settings = {};
1295
+ let pathWithRootDirectory = path2;
1296
+ let rootInferredServicesChoice = null;
1297
+ if (!rootServicesSetup.hasConfiguredServices) {
1298
+ rootInferredServicesChoice = await promptForInferredServicesSetup({
1299
+ client,
1300
+ autoConfirm,
1301
+ nonInteractive,
1302
+ workPath: path2,
1303
+ inferred: rootServicesSetup.inferredServices,
1304
+ inferredWriteBlocker: rootServicesSetup.inferredServicesWriteBlocker,
1305
+ allowChooseDifferentProjectDirectory: true
1306
+ });
1307
+ }
1308
+ if (rootServicesSetup.hasConfiguredServices) {
1309
+ displayConfiguredServicesSetup(
1310
+ rootServicesSetup.detectServicesResult,
1311
+ configFileName
1312
+ );
1313
+ settings.framework = "services";
1314
+ } else if (rootInferredServicesChoice?.type === "services") {
1315
+ settings.framework = "services";
1316
+ } else {
1317
+ const skipSelectedRootInferredServicesPrompt = rootInferredServicesChoice?.type === "single-app";
1318
+ if (rootInferredServicesChoice?.type === "single-app") {
1319
+ rootDirectory = toProjectRootDirectory(
1320
+ path2,
1321
+ rootInferredServicesChoice.selectedPath
1322
+ );
1323
+ } else {
1324
+ const shouldPromptRoot = await shouldPromptForRootDirectory({
1325
+ path: path2,
1326
+ servicesChoice: rootInferredServicesChoice
1327
+ });
1328
+ if (shouldPromptRoot) {
1329
+ rootDirectory = await inputRootDirectory(client, path2, autoConfirm);
1330
+ if (rootDirectory && !await validateRootDirectory(path2, join3(path2, rootDirectory))) {
1331
+ return {
1332
+ status: "error",
1333
+ exitCode: 1,
1334
+ reason: "INVALID_ROOT_DIRECTORY"
1335
+ };
1336
+ }
1337
+ }
1338
+ }
1339
+ pathWithRootDirectory = rootDirectory ? join3(path2, rootDirectory) : path2;
1340
+ const selectedRootServicesSetup = pathWithRootDirectory === path2 ? null : await getServicesSetupState(pathWithRootDirectory);
1341
+ let selectedRootInferredServicesChoice = null;
1342
+ if (!skipSelectedRootInferredServicesPrompt) {
1343
+ selectedRootInferredServicesChoice = await promptForInferredServicesSetup({
1344
+ client,
1345
+ autoConfirm,
1346
+ nonInteractive,
1347
+ workPath: pathWithRootDirectory,
1348
+ inferred: selectedRootServicesSetup?.inferredServices ?? null,
1349
+ inferredWriteBlocker: selectedRootServicesSetup?.inferredServicesWriteBlocker ?? null
1350
+ });
1351
+ }
1352
+ if (selectedRootServicesSetup?.hasConfiguredServices) {
1353
+ displayConfiguredServicesSetup(
1354
+ selectedRootServicesSetup.detectServicesResult,
1355
+ configFileName
1356
+ );
1357
+ settings.framework = "services";
1358
+ } else if (selectedRootInferredServicesChoice?.type === "services") {
1359
+ settings.framework = "services";
1360
+ } else {
1361
+ if (selectedRootInferredServicesChoice?.type === "single-app") {
1362
+ rootDirectory = toProjectRootDirectory(
1363
+ path2,
1364
+ selectedRootInferredServicesChoice.selectedPath
1365
+ );
1366
+ pathWithRootDirectory = rootDirectory ? join3(path2, rootDirectory) : path2;
1367
+ }
1368
+ const localConfig = await readConfig(pathWithRootDirectory);
1369
+ if (localConfig instanceof CantParseJSONFile) {
1370
+ output_manager_default.prettyError(localConfig);
1371
+ return { status: "error", exitCode: 1 };
1372
+ }
1373
+ const isZeroConfig = !localConfig || !localConfig.builds || localConfig.builds.length === 0;
1374
+ if (isZeroConfig) {
1375
+ const localConfigurationOverrides = {
1376
+ buildCommand: localConfig?.buildCommand,
1377
+ devCommand: localConfig?.devCommand,
1378
+ framework: localConfig?.framework,
1379
+ commandForIgnoringBuildStep: localConfig?.ignoreCommand,
1380
+ installCommand: localConfig?.installCommand,
1381
+ outputDirectory: localConfig?.outputDirectory
1382
+ };
1383
+ const detectedProjectsForWorkspace = await detectProjects(
1384
+ pathWithRootDirectory
1385
+ );
1386
+ const detectedProjects = detectedProjectsForWorkspace.get("") || [];
1387
+ const framework = detectedProjects[0] ?? import_frameworks3.frameworkList.find((f) => f.slug === null);
1388
+ settings = await editProjectSettings(
1389
+ client,
1390
+ {},
1391
+ framework,
1392
+ autoConfirm,
1393
+ localConfigurationOverrides,
1394
+ configFileName
1395
+ );
1396
+ }
1397
+ }
1398
+ }
1399
+ const changeAdditionalSettings = false;
1400
+ let vercelAuthSetting = DEFAULT_VERCEL_AUTH_SETTING;
1401
+ if (changeAdditionalSettings) {
1402
+ vercelAuthSetting = await vercelAuth(client, {
1403
+ autoConfirm
1404
+ });
1405
+ }
1406
+ if (rootDirectory) {
1407
+ settings.rootDirectory = rootDirectory;
1408
+ }
1409
+ const project = await createProject(client, {
1410
+ ...settings,
1411
+ name: newProjectName,
1412
+ vercelAuth: vercelAuthSetting,
1413
+ v0
1414
+ });
1415
+ await linkFolderToProject(
1416
+ client,
1417
+ path2,
1418
+ {
1419
+ projectId: project.id,
1420
+ orgId: org.id
1421
+ },
1422
+ project.name,
1423
+ org.slug,
1424
+ successEmoji,
1425
+ autoConfirm,
1426
+ false,
1427
+ // don't prompt to pull env for newly created projects
1428
+ "Created"
1429
+ );
1430
+ await applyGitConnectIntent(
1431
+ client,
1432
+ gitConnectIntent,
1433
+ project,
1434
+ autoConfirm,
1435
+ org
1436
+ );
1437
+ return {
1438
+ status: "linked",
1439
+ org,
1440
+ project,
1441
+ ...gitConnectIntent?.offered && { gitConnectOffered: true }
1442
+ };
1443
+ } catch (err) {
1444
+ if (isPromptCanceledError(err)) {
1445
+ throw err;
1446
+ }
1447
+ if (isAPIError(err) && err.code === "too_many_projects") {
1448
+ output_manager_default.prettyError(err);
1449
+ return { status: "error", exitCode: 1, reason: "TOO_MANY_PROJECTS" };
1450
+ }
1451
+ if (err instanceof Error && err.code === "HEADLESS") {
1452
+ return { status: "error", exitCode: 1, reason: "HEADLESS" };
1453
+ }
1454
+ printError(err);
1455
+ return { status: "error", exitCode: 1 };
1456
+ }
1457
+ }
1458
+ async function resolveGitConnectIntent(client, path2, autoConfirm) {
1459
+ try {
1460
+ const gitConfigPath = getGitConfigPath({ cwd: path2 }) ?? join3(path2, ".git/config");
1461
+ const gitConfig = await parseGitConfig(gitConfigPath);
1462
+ if (!gitConfig) {
1463
+ return null;
1464
+ }
1465
+ const remoteUrls = pluckRemoteUrls(gitConfig);
1466
+ if (!remoteUrls || Object.keys(remoteUrls).length === 0) {
1467
+ return null;
1468
+ }
1469
+ const skipPrompts = autoConfirm || client.nonInteractive;
1470
+ const shouldConnect = skipPrompts || await client.input.confirm(
1471
+ `Connect this Git repository to automatically deploy changes on every push?`,
1472
+ false
1473
+ );
1474
+ if (!shouldConnect) {
1475
+ return { offered: true };
1476
+ }
1477
+ const repoInfo = skipPrompts ? parseRepoUrl(remoteUrls.origin ?? Object.values(remoteUrls)[0]) : await selectAndParseRemoteUrl(client, remoteUrls);
1478
+ if (!repoInfo) {
1479
+ return null;
1480
+ }
1481
+ return { repoInfo, offered: !skipPrompts };
1482
+ } catch (error) {
1483
+ if (isPromptCanceledError(error)) {
1484
+ throw error;
1485
+ }
1486
+ output_manager_default.debug(`Failed to detect git repository: ${error}`);
1487
+ return null;
1488
+ }
1489
+ }
1490
+ async function applyGitConnectIntent(client, intent, project, autoConfirm, org) {
1491
+ if (!intent?.repoInfo) {
1492
+ return;
1493
+ }
1494
+ const { repoInfo } = intent;
1495
+ try {
1496
+ await checkExistsAndConnect({
1497
+ client,
1498
+ confirm: autoConfirm,
1499
+ gitProviderLink: project.link,
1500
+ org,
1501
+ gitOrg: repoInfo.org,
1502
+ project,
1503
+ // Type assertion since we only need the id
1504
+ provider: repoInfo.provider,
1505
+ repo: repoInfo.repo,
1506
+ repoPath: `${repoInfo.org}/${repoInfo.repo}`
1507
+ });
1508
+ } catch (error) {
1509
+ if (isPromptCanceledError(error)) {
1510
+ return;
1511
+ }
1512
+ output_manager_default.debug(`Failed to connect git repository: ${error}`);
1513
+ }
1514
+ }
1515
+ async function connectGitRepository(client, path2, project, autoConfirm, org) {
1516
+ let intent;
1517
+ try {
1518
+ intent = await resolveGitConnectIntent(client, path2, autoConfirm);
1519
+ } catch (error) {
1520
+ if (isPromptCanceledError(error)) {
1521
+ return;
1522
+ }
1523
+ throw error;
1524
+ }
1525
+ await applyGitConnectIntent(client, intent, project, autoConfirm, org);
1526
+ }
1527
+
1528
+ export {
1529
+ readConfig,
1530
+ displayDetectedServices,
1531
+ shouldPromptForRootDirectory,
1532
+ setupAndLink,
1533
+ resolveGitConnectIntent,
1534
+ applyGitConnectIntent,
1535
+ connectGitRepository
1536
+ };