@open-mercato/cli 0.6.3-develop.3894.1.352abf4240 → 0.6.3
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.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +1 -1
- package/dist/agentic/shared/AGENTS.md.template +1 -0
- package/dist/lib/dev-env-reload.js +40 -1
- package/dist/lib/dev-env-reload.js.map +2 -2
- package/dist/lib/generate-watch-structure.js +153 -0
- package/dist/lib/generate-watch-structure.js.map +7 -0
- package/dist/lib/testing/integration.js +14 -0
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +244 -98
- package/dist/mercato.js.map +2 -2
- package/package.json +7 -8
- package/src/__tests__/mercato.test.ts +13 -3
- package/src/lib/__tests__/dev-env-reload.test.ts +21 -1
- package/src/lib/__tests__/generate-watch-structure.test.ts +80 -0
- package/src/lib/dev-env-reload.ts +47 -0
- package/src/lib/generate-watch-structure.ts +170 -0
- package/src/lib/testing/integration.ts +14 -0
- package/src/mercato.ts +241 -67
package/src/mercato.ts
CHANGED
|
@@ -341,6 +341,122 @@ type DevServerRestartResult = {
|
|
|
341
341
|
|
|
342
342
|
type DevServerExitResult = ManagedProcessExitResult | DevServerRestartResult
|
|
343
343
|
|
|
344
|
+
function resolveDevRuntimeBaseUrl(environment: NodeJS.ProcessEnv = process.env): string {
|
|
345
|
+
const configured =
|
|
346
|
+
environment.APP_URL
|
|
347
|
+
?? environment.NEXT_PUBLIC_APP_URL
|
|
348
|
+
?? environment.NEXTAUTH_URL
|
|
349
|
+
if (configured?.trim()) {
|
|
350
|
+
return configured.trim().replace(/\/+$/, '')
|
|
351
|
+
}
|
|
352
|
+
return `http://localhost:${environment.PORT?.trim() || '3000'}`
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function writeDevSplashChildState(state: Record<string, unknown>): void {
|
|
356
|
+
if (process.env.OM_DEV_SPLASH_RUNTIME_WRAPPER === '1') return
|
|
357
|
+
const stateFile = process.env.OM_DEV_SPLASH_CHILD_STATE_FILE
|
|
358
|
+
if (!stateFile?.trim()) return
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
fs.mkdirSync(path.dirname(stateFile), { recursive: true })
|
|
362
|
+
fs.writeFileSync(stateFile, `${JSON.stringify({
|
|
363
|
+
mode: process.env.OM_DEV_SPLASH_MODE || 'dev',
|
|
364
|
+
failed: false,
|
|
365
|
+
failureLines: [],
|
|
366
|
+
failureCommand: null,
|
|
367
|
+
...state,
|
|
368
|
+
}, null, 2)}\n`)
|
|
369
|
+
} catch {
|
|
370
|
+
// Splash state is best-effort; terminal logs remain authoritative.
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function writeDevSplashRuntimeStarting(detail = 'Starting Next.js dev server'): void {
|
|
375
|
+
writeDevSplashChildState({
|
|
376
|
+
phase: 'Preparing app runtime',
|
|
377
|
+
detail,
|
|
378
|
+
ready: false,
|
|
379
|
+
readyUrl: null,
|
|
380
|
+
loginUrl: null,
|
|
381
|
+
progressLabel: 'Launching app runtime',
|
|
382
|
+
activity: detail,
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function resolveSplashProgressFallback(): { current: number; total: number } {
|
|
387
|
+
const current = Number.parseInt(process.env.OM_DEV_SPLASH_STAGE_CURRENT ?? '', 10)
|
|
388
|
+
const total = Number.parseInt(process.env.OM_DEV_SPLASH_STAGE_TOTAL ?? '', 10)
|
|
389
|
+
if (Number.isFinite(current) && Number.isFinite(total) && total > 0) {
|
|
390
|
+
return { current, total }
|
|
391
|
+
}
|
|
392
|
+
if (process.env.OM_DEV_SPLASH_MODE === 'greenfield' || process.env.OM_DEV_SPLASH_MODE === 'setup') {
|
|
393
|
+
return { current: 5, total: 5 }
|
|
394
|
+
}
|
|
395
|
+
return { current: 3, total: 3 }
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function writeDevSplashRuntimeRestarting(reason: string): void {
|
|
399
|
+
const progress = resolveSplashProgressFallback()
|
|
400
|
+
writeDevSplashChildState({
|
|
401
|
+
phase: 'App runtime is restarting',
|
|
402
|
+
detail: `Reason: ${reason}`,
|
|
403
|
+
ready: false,
|
|
404
|
+
readyUrl: null,
|
|
405
|
+
loginUrl: null,
|
|
406
|
+
progressCurrent: progress.current,
|
|
407
|
+
progressTotal: progress.total,
|
|
408
|
+
progressLabel: 'Restarting app runtime',
|
|
409
|
+
activity: `App runtime restart: ${reason}`,
|
|
410
|
+
})
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function writeDevSplashRuntimeReady(reason?: string): void {
|
|
414
|
+
const readyUrl = resolveDevRuntimeBaseUrl()
|
|
415
|
+
const progress = resolveSplashProgressFallback()
|
|
416
|
+
writeDevSplashChildState({
|
|
417
|
+
phase: 'App is ready',
|
|
418
|
+
detail: reason ? `Restart completed after ${reason}` : 'Next.js dev server is ready',
|
|
419
|
+
ready: true,
|
|
420
|
+
readyUrl,
|
|
421
|
+
loginUrl: `${readyUrl}/login`,
|
|
422
|
+
progressCurrent: progress.current,
|
|
423
|
+
progressTotal: progress.total,
|
|
424
|
+
progressPercent: 100,
|
|
425
|
+
progressLabel: 'App is ready',
|
|
426
|
+
activity: reason ? `Restart completed after ${reason}` : 'App runtime is ready',
|
|
427
|
+
})
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function resolveDevWarmupReadyTimeoutMs(environment: NodeJS.ProcessEnv = process.env): number {
|
|
431
|
+
const parsed = Number.parseInt(environment.OM_DEV_WARMUP_READY_TIMEOUT_MS ?? '', 10)
|
|
432
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed
|
|
433
|
+
return 300_000
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async function waitForDevWarmupReadyFile(
|
|
437
|
+
filePath: string | undefined,
|
|
438
|
+
options: {
|
|
439
|
+
timeoutMs?: number
|
|
440
|
+
signal?: AbortSignal
|
|
441
|
+
} = {},
|
|
442
|
+
): Promise<'ready' | 'timeout' | 'aborted'> {
|
|
443
|
+
const normalized = filePath?.trim()
|
|
444
|
+
if (!normalized) return 'ready'
|
|
445
|
+
const timeoutMs = options.timeoutMs ?? resolveDevWarmupReadyTimeoutMs()
|
|
446
|
+
const startedAt = Date.now()
|
|
447
|
+
|
|
448
|
+
while (true) {
|
|
449
|
+
if (options.signal?.aborted) return 'aborted'
|
|
450
|
+
try {
|
|
451
|
+
if (fs.existsSync(normalized)) return 'ready'
|
|
452
|
+
} catch {
|
|
453
|
+
// Keep polling; the runtime wrapper owns this best-effort marker.
|
|
454
|
+
}
|
|
455
|
+
if (timeoutMs >= 0 && Date.now() - startedAt >= timeoutMs) return 'timeout'
|
|
456
|
+
await new Promise((resolve) => setTimeout(resolve, 250))
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
344
460
|
type ModuleCommandLookupResult =
|
|
345
461
|
| {
|
|
346
462
|
status: 'ok'
|
|
@@ -601,18 +717,17 @@ async function runGeneratorSuite(quiet: boolean): Promise<void> {
|
|
|
601
717
|
function createGenerateWatchChecksumFn(): () => Promise<string> {
|
|
602
718
|
return async () => {
|
|
603
719
|
const { createResolver } = await import('./lib/resolver')
|
|
604
|
-
const {
|
|
720
|
+
const { calculateGenerateWatchStructureChecksum } = await import('./lib/generate-watch-structure')
|
|
605
721
|
const resolver = createResolver()
|
|
606
|
-
const
|
|
607
|
-
path.join(resolver.getAppDir(), 'src', 'modules.ts'),
|
|
608
|
-
path.join(resolver.getAppDir(), 'src', 'modules'),
|
|
609
|
-
])
|
|
722
|
+
const moduleRoots = []
|
|
610
723
|
for (const entry of resolver.loadEnabledModules()) {
|
|
611
724
|
const roots = resolver.getModulePaths(entry)
|
|
612
|
-
|
|
613
|
-
tracked.add(roots.pkgBase)
|
|
725
|
+
moduleRoots.push({ appBase: roots.appBase, pkgBase: roots.pkgBase })
|
|
614
726
|
}
|
|
615
|
-
return
|
|
727
|
+
return calculateGenerateWatchStructureChecksum({
|
|
728
|
+
modulesFile: path.join(resolver.getAppDir(), 'src', 'modules.ts'),
|
|
729
|
+
moduleRoots,
|
|
730
|
+
})
|
|
616
731
|
}
|
|
617
732
|
}
|
|
618
733
|
|
|
@@ -1690,10 +1805,11 @@ export async function run(argv = process.argv) {
|
|
|
1690
1805
|
let processes: ChildProcess[] = []
|
|
1691
1806
|
let didRetryCorruptedTurbopackCache = false
|
|
1692
1807
|
let stopping = false
|
|
1693
|
-
let
|
|
1808
|
+
let devRestartPromiseResolve: ((result: DevServerRestartResult) => void) | null = null
|
|
1694
1809
|
let activeLazySupervisor: ReturnType<typeof startLazyWorkerSupervisor> | null = null
|
|
1695
1810
|
let activeLazySchedulerSupervisor: ReturnType<typeof startLazySchedulerSupervisor> | null = null
|
|
1696
1811
|
let activeGenerateWatcher: GenerateWatcherHandle | null = null
|
|
1812
|
+
let lastRestartReason: string | null = null
|
|
1697
1813
|
const generateWatcherMode: GenerateWatcherMode = resolveGenerateWatcherMode(process.env)
|
|
1698
1814
|
const envReloader = createDevEnvReloader(appDir, process.env, initialProcessEnvironmentEntries)
|
|
1699
1815
|
|
|
@@ -1781,20 +1897,31 @@ export async function run(argv = process.argv) {
|
|
|
1781
1897
|
const mercatoBin = resolveInstalledBinary(nodeModulesBases, '@open-mercato/cli/bin/mercato')
|
|
1782
1898
|
|
|
1783
1899
|
const stopEnvWatcher = watchDevEnvFiles(appDir, (filePath) => {
|
|
1784
|
-
|
|
1900
|
+
devRestartPromiseResolve?.({
|
|
1785
1901
|
label: 'Environment file change',
|
|
1786
1902
|
restart: true,
|
|
1787
1903
|
filePath,
|
|
1788
1904
|
})
|
|
1789
1905
|
})
|
|
1790
|
-
|
|
1791
|
-
const waitForEnvChange = (): Promise<DevServerRestartResult> =>
|
|
1906
|
+
const waitForDevRestart = (): Promise<DevServerRestartResult> =>
|
|
1792
1907
|
new Promise((resolve) => {
|
|
1793
|
-
|
|
1908
|
+
devRestartPromiseResolve = resolve
|
|
1794
1909
|
})
|
|
1795
1910
|
|
|
1796
|
-
const startNextDev = (runtimeEnv: NodeJS.ProcessEnv):
|
|
1797
|
-
|
|
1911
|
+
const startNextDev = (runtimeEnv: NodeJS.ProcessEnv): {
|
|
1912
|
+
exitPromise: Promise<ManagedProcessExitResult>
|
|
1913
|
+
readyPromise: Promise<void>
|
|
1914
|
+
} => {
|
|
1915
|
+
let readyResolve: () => void = () => undefined
|
|
1916
|
+
const readyPromise = new Promise<void>((resolve) => {
|
|
1917
|
+
readyResolve = resolve
|
|
1918
|
+
})
|
|
1919
|
+
const exitPromise = new Promise<ManagedProcessExitResult>((resolve) => {
|
|
1920
|
+
writeDevSplashRuntimeStarting(
|
|
1921
|
+
lastRestartReason
|
|
1922
|
+
? `Restarting Next.js dev server. Reason: ${lastRestartReason}`
|
|
1923
|
+
: 'Starting Next.js dev server',
|
|
1924
|
+
)
|
|
1798
1925
|
const nextProcess = spawn('node', [nextBin, 'dev', '--turbopack'], {
|
|
1799
1926
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
1800
1927
|
env: runtimeEnv,
|
|
@@ -1803,11 +1930,18 @@ export async function run(argv = process.argv) {
|
|
|
1803
1930
|
processes.push(nextProcess)
|
|
1804
1931
|
|
|
1805
1932
|
let combinedOutput = ''
|
|
1933
|
+
let reportedReady = false
|
|
1806
1934
|
const appendOutput = (chunk: string) => {
|
|
1807
1935
|
combinedOutput += chunk
|
|
1808
1936
|
if (combinedOutput.length > 32_768) {
|
|
1809
1937
|
combinedOutput = combinedOutput.slice(-32_768)
|
|
1810
1938
|
}
|
|
1939
|
+
if (!reportedReady && /\bready in\b/i.test(chunk)) {
|
|
1940
|
+
reportedReady = true
|
|
1941
|
+
writeDevSplashRuntimeReady(lastRestartReason ?? undefined)
|
|
1942
|
+
lastRestartReason = null
|
|
1943
|
+
readyResolve()
|
|
1944
|
+
}
|
|
1811
1945
|
}
|
|
1812
1946
|
|
|
1813
1947
|
nextProcess.stdout?.on('data', (chunk: Buffer | string) => {
|
|
@@ -1824,9 +1958,13 @@ export async function run(argv = process.argv) {
|
|
|
1824
1958
|
nextProcess.on('exit', async (code, signal) => {
|
|
1825
1959
|
if (!didRetryCorruptedTurbopackCache && isTurbopackCacheCorruption(combinedOutput)) {
|
|
1826
1960
|
didRetryCorruptedTurbopackCache = true
|
|
1961
|
+
lastRestartReason = 'corrupted Turbopack dev cache'
|
|
1962
|
+
writeDevSplashRuntimeRestarting(lastRestartReason)
|
|
1827
1963
|
console.log('[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...')
|
|
1828
1964
|
removeTurbopackDevCache(appDir)
|
|
1829
|
-
|
|
1965
|
+
const restarted = startNextDev(runtimeEnv)
|
|
1966
|
+
restarted.readyPromise.then(readyResolve)
|
|
1967
|
+
return resolve(await restarted.exitPromise)
|
|
1830
1968
|
}
|
|
1831
1969
|
resolve({
|
|
1832
1970
|
label: 'Next.js dev server',
|
|
@@ -1835,6 +1973,8 @@ export async function run(argv = process.argv) {
|
|
|
1835
1973
|
})
|
|
1836
1974
|
})
|
|
1837
1975
|
})
|
|
1976
|
+
return { exitPromise, readyPromise }
|
|
1977
|
+
}
|
|
1838
1978
|
|
|
1839
1979
|
try {
|
|
1840
1980
|
while (!stopping) {
|
|
@@ -1844,62 +1984,92 @@ export async function run(argv = process.argv) {
|
|
|
1844
1984
|
const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env)
|
|
1845
1985
|
const queueStrategy = process.env.QUEUE_STRATEGY || 'local'
|
|
1846
1986
|
const schedulerCommand = lookupModuleCommand(getCliModules(), 'scheduler', 'start')
|
|
1987
|
+
const nextRuntime = startNextDev(runtimeEnv)
|
|
1988
|
+
const restartPromise = waitForDevRestart()
|
|
1989
|
+
const backgroundStartAbort = new AbortController()
|
|
1990
|
+
const cancelBackgroundStart = () => backgroundStartAbort.abort()
|
|
1991
|
+
nextRuntime.exitPromise.finally(cancelBackgroundStart)
|
|
1992
|
+
restartPromise.then(cancelBackgroundStart)
|
|
1993
|
+
let backgroundExitResolve: (result: ManagedProcessExitResult) => void = () => undefined
|
|
1994
|
+
const backgroundExitPromise = new Promise<ManagedProcessExitResult>((resolve) => {
|
|
1995
|
+
backgroundExitResolve = resolve
|
|
1996
|
+
})
|
|
1847
1997
|
const managedExitPromises: Promise<DevServerExitResult>[] = [
|
|
1848
|
-
|
|
1849
|
-
|
|
1998
|
+
nextRuntime.exitPromise,
|
|
1999
|
+
restartPromise,
|
|
2000
|
+
backgroundExitPromise,
|
|
1850
2001
|
]
|
|
1851
2002
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
restartOnUnexpectedExit: resolveLazyRestart(process.env),
|
|
1867
|
-
})
|
|
1868
|
-
} else {
|
|
1869
|
-
console.log('[server] Eager worker auto-spawn enabled - starting workers for all queues...')
|
|
1870
|
-
const workerProcess = spawn('node', [mercatoBin, 'queue', 'worker', '--all'], {
|
|
1871
|
-
stdio: 'inherit',
|
|
1872
|
-
env: runtimeEnv,
|
|
1873
|
-
cwd: appDir,
|
|
1874
|
-
})
|
|
1875
|
-
processes.push(workerProcess)
|
|
1876
|
-
managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)))
|
|
2003
|
+
const startBackgroundServices = async () => {
|
|
2004
|
+
if (stopping || backgroundStartAbort.signal.aborted) return
|
|
2005
|
+
|
|
2006
|
+
// Keep first-route compilation responsive: greenfield setup can
|
|
2007
|
+
// leave vector/fulltext jobs ready. When the dev wrapper is
|
|
2008
|
+
// active, wait for its /login + /backend warmup marker before
|
|
2009
|
+
// workers and scheduler begin consuming CPU and database I/O.
|
|
2010
|
+
const warmupReady = await waitForDevWarmupReadyFile(process.env.OM_DEV_WARMUP_READY_FILE, {
|
|
2011
|
+
timeoutMs: resolveDevWarmupReadyTimeoutMs(process.env),
|
|
2012
|
+
signal: backgroundStartAbort.signal,
|
|
2013
|
+
})
|
|
2014
|
+
if (warmupReady === 'aborted' || stopping || backgroundStartAbort.signal.aborted) return
|
|
2015
|
+
if (warmupReady === 'timeout') {
|
|
2016
|
+
console.warn('[server] Timed out waiting for dev warmup marker; starting background services anyway.')
|
|
1877
2017
|
}
|
|
1878
|
-
}
|
|
1879
2018
|
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2019
|
+
if (autoSpawnWorkersMode !== 'off') {
|
|
2020
|
+
const discoveredWorkers = getRegisteredCliWorkers()
|
|
2021
|
+
const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))]
|
|
2022
|
+
if (discoveredWorkerQueues.length === 0) {
|
|
2023
|
+
console.error('[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run `yarn generate` and verify `.mercato/generated/modules.cli.generated.ts` contains worker entries. Continuing without auto-spawned workers.')
|
|
2024
|
+
} else if (autoSpawnWorkersMode === 'lazy') {
|
|
2025
|
+
console.log(`[server] Lazy worker auto-spawn enabled — workers will start on first job (${discoveredWorkerQueues.length} queue(s) watched).`)
|
|
2026
|
+
activeLazySupervisor = startLazyWorkerSupervisor({
|
|
2027
|
+
mercatoBin,
|
|
2028
|
+
appDir,
|
|
2029
|
+
runtimeEnv,
|
|
2030
|
+
workers: discoveredWorkers,
|
|
2031
|
+
pollMs: resolveLazyPollMs(process.env),
|
|
2032
|
+
restartOnUnexpectedExit: resolveLazyRestart(process.env),
|
|
2033
|
+
})
|
|
2034
|
+
} else {
|
|
2035
|
+
console.log('[server] Eager worker auto-spawn enabled - starting workers for all queues...')
|
|
2036
|
+
const workerProcess = spawn('node', [mercatoBin, 'queue', 'worker', '--all'], {
|
|
2037
|
+
stdio: 'inherit',
|
|
2038
|
+
env: runtimeEnv,
|
|
2039
|
+
cwd: appDir,
|
|
2040
|
+
})
|
|
2041
|
+
processes.push(workerProcess)
|
|
2042
|
+
waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)).then(backgroundExitResolve)
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
if (autoSpawnSchedulerMode !== 'off' && queueStrategy === 'local') {
|
|
2047
|
+
if (schedulerCommand.status !== 'ok') {
|
|
2048
|
+
console.log(`[server] Skipping scheduler auto-start — ${describeMissingModuleCommand(schedulerCommand)}`)
|
|
2049
|
+
} else if (autoSpawnSchedulerMode === 'lazy') {
|
|
2050
|
+
console.log('[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.')
|
|
2051
|
+
activeLazySchedulerSupervisor = startLazySchedulerSupervisor({
|
|
2052
|
+
mercatoBin,
|
|
2053
|
+
appDir,
|
|
2054
|
+
runtimeEnv,
|
|
2055
|
+
pollMs: resolveLazySchedulerPollMs(process.env),
|
|
2056
|
+
restartOnUnexpectedExit: resolveLazySchedulerRestart(process.env),
|
|
2057
|
+
})
|
|
2058
|
+
} else {
|
|
2059
|
+
console.log('[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...')
|
|
2060
|
+
const schedulerProcess = spawn('node', [mercatoBin, 'scheduler', 'start'], {
|
|
2061
|
+
stdio: 'inherit',
|
|
2062
|
+
env: runtimeEnv,
|
|
2063
|
+
cwd: appDir,
|
|
2064
|
+
})
|
|
2065
|
+
processes.push(schedulerProcess)
|
|
2066
|
+
waitForManagedProcessExit(schedulerProcess, 'Scheduler polling engine').then(backgroundExitResolve)
|
|
2067
|
+
}
|
|
1901
2068
|
}
|
|
1902
2069
|
}
|
|
2070
|
+
nextRuntime.readyPromise.then(() => {
|
|
2071
|
+
void startBackgroundServices()
|
|
2072
|
+
})
|
|
1903
2073
|
|
|
1904
2074
|
if (generateWatcherMode === 'in-process') {
|
|
1905
2075
|
// Run the structural regeneration watcher inside this process
|
|
@@ -1927,11 +2097,15 @@ export async function run(argv = process.argv) {
|
|
|
1927
2097
|
}
|
|
1928
2098
|
|
|
1929
2099
|
const firstExit = await Promise.race(managedExitPromises)
|
|
2100
|
+
if (isDevServerRestartResult(firstExit)) {
|
|
2101
|
+
lastRestartReason = `${firstExit.label.toLowerCase()} (${path.basename(firstExit.filePath)})`
|
|
2102
|
+
writeDevSplashRuntimeRestarting(lastRestartReason)
|
|
2103
|
+
}
|
|
1930
2104
|
await cleanupAndWait()
|
|
1931
|
-
|
|
2105
|
+
devRestartPromiseResolve = null
|
|
1932
2106
|
|
|
1933
2107
|
if (isDevServerRestartResult(firstExit)) {
|
|
1934
|
-
console.log(`[server] Detected
|
|
2108
|
+
console.log(`[server] Detected ${firstExit.label.toLowerCase()} (${path.basename(firstExit.filePath)}). Restarting app runtime...`)
|
|
1935
2109
|
continue
|
|
1936
2110
|
}
|
|
1937
2111
|
|