163 const current = await readWixEnvValues(wixEnvPath);
164 if (current.WIX_SITE_ID !== siteId) {
165 throw new Error(
166 `config/wix.env's WIX_SITE_ID (${current.WIX_SITE_ID}) no longer matches the scaffold's own wix.config.json (${siteId}); refusing to overwrite a different destination.`,
186 // Case 1: config/wix.env already names a destination — checked first, independent of
187 // wix.config.json, so an env-only receipt (adopted/existing destination, or a lost
188 // frontend folder) can never fall through to spawning a second site.
189 if (wixConfig && wixConfig.siteId !== envValues.WIX_SITE_ID) {
190 // 1b — conflicting.
191 throw new Error(
192 `config/wix.env already has WIX_SITE_ID=${envValues.WIX_SITE_ID}, but ${frontendDir}/wix.config.json names a different siteId=${wixConfig.siteId}. Refusing to create or adopt a second destination — resolve the conflict manually.`,
193 );
194 }
195 // 1a — consistent (wix.config.json is absent, has no siteId, or matches).
196 const status = envValues.WIX_SCAFFOLD_STATUS;
197 if (status === undefined || status === 'complete') {
198 return { siteId: envValues.WIX_SITE_ID };
199 }
200 if (status === 'incomplete') {
201 throw new Error(
202 `Destination ${envValues.WIX_SITE_ID} already exists, but a prior scaffold attempt did not complete (WIX_SCAFFOLD_STATUS=incomplete). Refusing to spawn again — that would risk a duplicate site. Resolve manually before retrying.`,
203 );
204 }
205 throw new Error(
206 `config/wix.env has an unrecognized WIX_SCAFFOLD_STATUS value (${JSON.stringify(status)}); expected "complete", "incomplete", or the key to be absent. Refusing to proceed.`,
207 );
208 }
209
210 // Case 2: no confirmed real WIX_SITE_ID (missing, blank, or a placeholder — all treated
211 // alike here, matching case 1's classification). PR #184 review correction: this branch
212 // must also inspect WIX_SCAFFOLD_STATUS, not just wix.config.json's existence — a bare
229 `A prior scaffold attempt was interrupted before it could record its outcome (WIX_SCAFFOLD_STATUS=in_progress), but a destination was found (WIX_SITE_ID=${wixConfig.siteId}). Persisted as incomplete — resolve manually before retrying.`,
230 );
231 }
232 // PR #184 review correction (round 6): no local receipt either does NOT mean nothing
233 // was created remotely — a crash could have happened after a remote site was created
234 // but before wix.config.json was written locally (or even before the frontend folder
235 // existed at all), which isNonEmptyDir below cannot detect. Fail closed
236 // unconditionally rather than falling through to 2b/2c; the one case that clears this
237 // marker for a safe automatic retry is a genuine spawn-launch failure (see 2c) — that
238 // is handled before this marker is ever left behind, not by re-reading it here.
239 throw new Error(
240 'A prior scaffold attempt was interrupted before it could record any outcome (WIX_SCAFFOLD_STATUS=in_progress) and no local destination receipt (wix.config.json) exists either. This cannot be safely distinguished from a remote site having been created before a local receipt was written. Refusing to retry automatically — confirm whether a destination already exists, then either record its WIX_SITE_ID manually or clear WIX_SCAFFOLD_STATUS from config/wix.env if nothing was actually created.',
241 );
242 }
243 if (status !== undefined) {
244 // WIX_SCAFFOLD_STATUS is set to something else (a known-ambiguous marker from this
245 // script, or corrupted state) while no real WIX_SITE_ID exists. Fail closed rather
246 // than silently proceeding as though nothing were recorded.
247 throw new Error(
248 `config/wix.env has WIX_SCAFFOLD_STATUS=${JSON.stringify(status)} but no valid WIX_SITE_ID; this cannot be automatically resolved. Refusing to proceed automatically — resolve manually.`,
249 );
250 }
251
252 if (wixConfig) {
253 // 2a — adopt a receipt with no status marker at all: a genuinely legacy/host-adopted
254 // destination, or one scaffolded before this script wrote WIX_SCAFFOLD_STATUS.
260 // 2b — genuinely ambiguous state this script cannot resolve on its own.
261 throw new Error(
262 `${frontendDir} already exists and is not empty, but no valid wix.config.json was found there and config/wix.env has no WIX_SITE_ID. Refusing to scaffold into this folder automatically — resolve manually before retrying.`,
263 );
264 }
265
266 // 2c — nothing exists yet; mark in_progress before spawning so a crash between now and
267 // persisting a final outcome always leaves a distinguishable trace instead of silently
299 `Scaffold process exited with code ${code}, but a destination was created (WIX_SITE_ID=${postConfig.siteId}); persisted as incomplete. Do not retry automatically — resolve the underlying failure first.`,
300 );
301 }
302 // The child process definitely ran to completion (it returned an exit code), but no
303 // valid local receipt was found. This must NOT be left as a retryable in_progress
304 // marker: a remote site could still have been created before a local write failed.
305 // Convert it to a durable, always-blocked marker instead.
308 throw new Error('Scaffold process exited 0, but no wix.config.json with a siteId was found afterward — cannot confirm whether a destination was created. Marked ambiguous; resolve manually before retrying.');
309 }
310 throw new Error(`Scaffold process exited with code ${code} and no destination receipt was found — cannot confirm whether a destination was created. Marked ambiguous; resolve manually before retrying.`);