@open-mercato/cli 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
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/dist/agentic/shared/AGENTS.md.template +1 -1
- package/dist/lib/__integration__/TC-INT-007.spec.js +201 -0
- package/dist/lib/__integration__/TC-INT-007.spec.js.map +7 -0
- package/dist/lib/dev-env-reload.js +89 -0
- package/dist/lib/dev-env-reload.js.map +7 -0
- package/dist/lib/generators/extensions/ai-agents.js +218 -0
- package/dist/lib/generators/extensions/ai-agents.js.map +7 -0
- package/dist/lib/generators/extensions/ai-tools.js +56 -1
- package/dist/lib/generators/extensions/ai-tools.js.map +2 -2
- package/dist/lib/generators/extensions/index.js +2 -0
- package/dist/lib/generators/extensions/index.js.map +2 -2
- package/dist/lib/testing/integration-discovery.js +102 -5
- package/dist/lib/testing/integration-discovery.js.map +2 -2
- package/dist/mercato.js +85 -44
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/__tests__/mercato.test.ts +112 -0
- package/src/lib/__integration__/TC-INT-007.spec.ts +228 -0
- package/src/lib/__tests__/dev-env-reload.test.ts +62 -0
- package/src/lib/dev-env-reload.ts +110 -0
- package/src/lib/generators/__tests__/module-subset.test.ts +14 -0
- package/src/lib/generators/__tests__/output-snapshots.test.ts +17 -0
- package/src/lib/generators/__tests__/scanner.test.ts +1 -1
- package/src/lib/generators/__tests__/structural-contracts.test.ts +26 -0
- package/src/lib/generators/extensions/ai-agents.ts +240 -0
- package/src/lib/generators/extensions/ai-tools.ts +72 -1
- package/src/lib/generators/extensions/index.ts +2 -0
- package/src/lib/testing/__tests__/integration-discovery.test.ts +68 -0
- package/src/lib/testing/integration-discovery.ts +127 -3
- package/src/mercato.ts +100 -46
package/src/mercato.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { resolveInitDerivedSecrets } from './lib/init-secrets'
|
|
|
12
12
|
import { parseModuleInstallArgs } from './lib/module-install-args'
|
|
13
13
|
import { resolveNextBuildIdCandidate } from './lib/next-build-id'
|
|
14
14
|
import { acquireServerStartLock } from './lib/server-start-lock'
|
|
15
|
+
import { createDevEnvReloader, watchDevEnvFiles } from './lib/dev-env-reload'
|
|
15
16
|
// Lazy-imported to avoid pulling in `testcontainers` (devDependency) at startup
|
|
16
17
|
const lazyIntegration = () => import('./lib/testing/integration')
|
|
17
18
|
import type { ChildProcess } from 'node:child_process'
|
|
@@ -19,6 +20,7 @@ import path from 'node:path'
|
|
|
19
20
|
import fs from 'node:fs'
|
|
20
21
|
|
|
21
22
|
let envLoaded = false
|
|
23
|
+
const initialProcessEnvironmentEntries = Object.entries(process.env)
|
|
22
24
|
|
|
23
25
|
async function runWithCapturedExitCode(action: () => Promise<void>): Promise<number> {
|
|
24
26
|
const previousExitCode = process.exitCode
|
|
@@ -311,6 +313,14 @@ type ManagedProcessExitResult = {
|
|
|
311
313
|
signal: NodeJS.Signals | null
|
|
312
314
|
}
|
|
313
315
|
|
|
316
|
+
type DevServerRestartResult = {
|
|
317
|
+
label: string
|
|
318
|
+
restart: true
|
|
319
|
+
filePath: string
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
type DevServerExitResult = ManagedProcessExitResult | DevServerRestartResult
|
|
323
|
+
|
|
314
324
|
type ModuleCommandLookupResult =
|
|
315
325
|
| {
|
|
316
326
|
status: 'ok'
|
|
@@ -347,6 +357,10 @@ function createManagedProcessExitError(result: ManagedProcessExitResult): Error
|
|
|
347
357
|
return new Error(`[server] ${result.label} exited unexpectedly with ${formatManagedProcessExitStatus(result)}.`)
|
|
348
358
|
}
|
|
349
359
|
|
|
360
|
+
function isDevServerRestartResult(result: DevServerExitResult): result is DevServerRestartResult {
|
|
361
|
+
return 'restart' in result && result.restart === true
|
|
362
|
+
}
|
|
363
|
+
|
|
350
364
|
function formatQueueWorkerLabel(queueNames: string[]): string {
|
|
351
365
|
if (queueNames.length === 0) return 'Queue worker'
|
|
352
366
|
const sorted = [...queueNames].sort((a, b) => a.localeCompare(b))
|
|
@@ -1642,12 +1656,11 @@ export async function run(argv = process.argv) {
|
|
|
1642
1656
|
const appDir = env.appDir
|
|
1643
1657
|
const nodeModulesBases = Array.from(new Set([env.rootDir, appDir]))
|
|
1644
1658
|
|
|
1645
|
-
|
|
1646
|
-
const autoSpawnWorkers = process.env.AUTO_SPAWN_WORKERS !== 'false'
|
|
1647
|
-
const autoSpawnScheduler = process.env.AUTO_SPAWN_SCHEDULER !== 'false'
|
|
1648
|
-
const queueStrategy = process.env.QUEUE_STRATEGY || 'local'
|
|
1659
|
+
let processes: ChildProcess[] = []
|
|
1649
1660
|
let didRetryCorruptedTurbopackCache = false
|
|
1650
|
-
|
|
1661
|
+
let stopping = false
|
|
1662
|
+
let envChangePromiseResolve: ((result: DevServerRestartResult) => void) | null = null
|
|
1663
|
+
const envReloader = createDevEnvReloader(appDir, process.env, initialProcessEnvironmentEntries)
|
|
1651
1664
|
|
|
1652
1665
|
function cleanup() {
|
|
1653
1666
|
console.log('[server] Shutting down...')
|
|
@@ -1677,10 +1690,17 @@ export async function run(argv = process.argv) {
|
|
|
1677
1690
|
} catch {
|
|
1678
1691
|
// Lock file may already be removed by Next.js — ignore
|
|
1679
1692
|
}
|
|
1693
|
+
processes = []
|
|
1680
1694
|
}
|
|
1681
1695
|
|
|
1682
|
-
process.on('SIGTERM',
|
|
1683
|
-
|
|
1696
|
+
process.on('SIGTERM', () => {
|
|
1697
|
+
stopping = true
|
|
1698
|
+
cleanup()
|
|
1699
|
+
})
|
|
1700
|
+
process.on('SIGINT', () => {
|
|
1701
|
+
stopping = true
|
|
1702
|
+
cleanup()
|
|
1703
|
+
})
|
|
1684
1704
|
|
|
1685
1705
|
console.log('[server] Starting Open Mercato in dev mode...')
|
|
1686
1706
|
|
|
@@ -1692,11 +1712,24 @@ export async function run(argv = process.argv) {
|
|
|
1692
1712
|
const nextBin = resolveInstalledBinary(nodeModulesBases, 'next/dist/bin/next')
|
|
1693
1713
|
const mercatoBin = resolveInstalledBinary(nodeModulesBases, '@open-mercato/cli/bin/mercato')
|
|
1694
1714
|
|
|
1695
|
-
const
|
|
1715
|
+
const stopEnvWatcher = watchDevEnvFiles(appDir, (filePath) => {
|
|
1716
|
+
envChangePromiseResolve?.({
|
|
1717
|
+
label: 'Environment file change',
|
|
1718
|
+
restart: true,
|
|
1719
|
+
filePath,
|
|
1720
|
+
})
|
|
1721
|
+
})
|
|
1722
|
+
|
|
1723
|
+
const waitForEnvChange = (): Promise<DevServerRestartResult> =>
|
|
1724
|
+
new Promise((resolve) => {
|
|
1725
|
+
envChangePromiseResolve = resolve
|
|
1726
|
+
})
|
|
1727
|
+
|
|
1728
|
+
const startNextDev = (runtimeEnv: NodeJS.ProcessEnv): Promise<ManagedProcessExitResult> =>
|
|
1696
1729
|
new Promise((resolve) => {
|
|
1697
1730
|
const nextProcess = spawn('node', [nextBin, 'dev', '--turbopack'], {
|
|
1698
1731
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
1699
|
-
env:
|
|
1732
|
+
env: runtimeEnv,
|
|
1700
1733
|
cwd: appDir,
|
|
1701
1734
|
})
|
|
1702
1735
|
processes.push(nextProcess)
|
|
@@ -1725,7 +1758,7 @@ export async function run(argv = process.argv) {
|
|
|
1725
1758
|
didRetryCorruptedTurbopackCache = true
|
|
1726
1759
|
console.log('[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...')
|
|
1727
1760
|
removeTurbopackDevCache(appDir)
|
|
1728
|
-
return resolve(await startNextDev())
|
|
1761
|
+
return resolve(await startNextDev(runtimeEnv))
|
|
1729
1762
|
}
|
|
1730
1763
|
resolve({
|
|
1731
1764
|
label: 'Next.js dev server',
|
|
@@ -1735,47 +1768,68 @@ export async function run(argv = process.argv) {
|
|
|
1735
1768
|
})
|
|
1736
1769
|
})
|
|
1737
1770
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1771
|
+
try {
|
|
1772
|
+
while (!stopping) {
|
|
1773
|
+
envReloader.reload()
|
|
1774
|
+
const runtimeEnv = buildServerProcessEnvironment(process.env)
|
|
1775
|
+
const autoSpawnWorkers = process.env.AUTO_SPAWN_WORKERS !== 'false'
|
|
1776
|
+
const autoSpawnScheduler = process.env.AUTO_SPAWN_SCHEDULER !== 'false'
|
|
1777
|
+
const queueStrategy = process.env.QUEUE_STRATEGY || 'local'
|
|
1778
|
+
const schedulerCommand = lookupModuleCommand(getCliModules(), 'scheduler', 'start')
|
|
1779
|
+
const managedExitPromises: Promise<DevServerExitResult>[] = [
|
|
1780
|
+
startNextDev(runtimeEnv),
|
|
1781
|
+
waitForEnvChange(),
|
|
1782
|
+
]
|
|
1783
|
+
|
|
1784
|
+
// Start workers if enabled
|
|
1785
|
+
if (autoSpawnWorkers) {
|
|
1786
|
+
const discoveredWorkerQueues = [...new Set(getRegisteredCliWorkers().map((worker) => worker.queue))]
|
|
1787
|
+
if (discoveredWorkerQueues.length === 0) {
|
|
1788
|
+
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.')
|
|
1789
|
+
} else {
|
|
1790
|
+
console.log('[server] Starting workers for all queues...')
|
|
1791
|
+
const workerProcess = spawn('node', [mercatoBin, 'queue', 'worker', '--all'], {
|
|
1792
|
+
stdio: 'inherit',
|
|
1793
|
+
env: runtimeEnv,
|
|
1794
|
+
cwd: appDir,
|
|
1795
|
+
})
|
|
1796
|
+
processes.push(workerProcess)
|
|
1797
|
+
managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)))
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1740
1800
|
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1801
|
+
if (autoSpawnScheduler && queueStrategy === 'local') {
|
|
1802
|
+
if (schedulerCommand.status !== 'ok') {
|
|
1803
|
+
console.log(`[server] Skipping scheduler auto-start — ${describeMissingModuleCommand(schedulerCommand)}`)
|
|
1804
|
+
} else {
|
|
1805
|
+
console.log('[server] Starting scheduler polling engine...')
|
|
1806
|
+
const schedulerProcess = spawn('node', [mercatoBin, 'scheduler', 'start'], {
|
|
1807
|
+
stdio: 'inherit',
|
|
1808
|
+
env: runtimeEnv,
|
|
1809
|
+
cwd: appDir,
|
|
1810
|
+
})
|
|
1811
|
+
processes.push(schedulerProcess)
|
|
1812
|
+
managedExitPromises.push(waitForManagedProcessExit(schedulerProcess, 'Scheduler polling engine'))
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1757
1815
|
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
} else {
|
|
1762
|
-
console.log('[server] Starting scheduler polling engine...')
|
|
1763
|
-
const schedulerProcess = spawn('node', [mercatoBin, 'scheduler', 'start'], {
|
|
1764
|
-
stdio: 'inherit',
|
|
1765
|
-
env: process.env,
|
|
1766
|
-
cwd: appDir,
|
|
1767
|
-
})
|
|
1768
|
-
processes.push(schedulerProcess)
|
|
1769
|
-
managedExitPromises.push(waitForManagedProcessExit(schedulerProcess, 'Scheduler polling engine'))
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1816
|
+
const firstExit = await Promise.race(managedExitPromises)
|
|
1817
|
+
await cleanupAndWait()
|
|
1818
|
+
envChangePromiseResolve = null
|
|
1772
1819
|
|
|
1773
|
-
|
|
1820
|
+
if (isDevServerRestartResult(firstExit)) {
|
|
1821
|
+
console.log(`[server] Detected environment file change (${path.basename(firstExit.filePath)}). Restarting app runtime...`)
|
|
1822
|
+
continue
|
|
1823
|
+
}
|
|
1774
1824
|
|
|
1775
|
-
|
|
1825
|
+
if (!isExpectedManagedExitSignal(firstExit.signal)) {
|
|
1826
|
+
throw createManagedProcessExitError(firstExit)
|
|
1827
|
+
}
|
|
1776
1828
|
|
|
1777
|
-
|
|
1778
|
-
|
|
1829
|
+
stopping = true
|
|
1830
|
+
}
|
|
1831
|
+
} finally {
|
|
1832
|
+
stopEnvWatcher()
|
|
1779
1833
|
}
|
|
1780
1834
|
},
|
|
1781
1835
|
},
|