@open-mercato/cli 0.6.8-develop.6891.1.4dca3f1ad3 → 0.6.8-develop.6893.1.7af3b3a72d

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 (106) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/AGENTS.md +6 -1
  3. package/dist/agentic/guides/module-facts.json +113 -113
  4. package/dist/agentic/guides/modules/ai_assistant.md +1 -1
  5. package/dist/agentic/guides/modules/api_docs.md +1 -1
  6. package/dist/agentic/guides/modules/api_keys.md +1 -1
  7. package/dist/agentic/guides/modules/attachments.md +1 -1
  8. package/dist/agentic/guides/modules/audit_logs.md +1 -1
  9. package/dist/agentic/guides/modules/auth.md +1 -1
  10. package/dist/agentic/guides/modules/business_rules.md +1 -1
  11. package/dist/agentic/guides/modules/catalog.md +1 -1
  12. package/dist/agentic/guides/modules/channel_gmail.md +1 -1
  13. package/dist/agentic/guides/modules/channel_imap.md +1 -1
  14. package/dist/agentic/guides/modules/checkout.md +1 -1
  15. package/dist/agentic/guides/modules/communication_channels.md +3 -3
  16. package/dist/agentic/guides/modules/configs.md +1 -1
  17. package/dist/agentic/guides/modules/content.md +1 -1
  18. package/dist/agentic/guides/modules/currencies.md +1 -1
  19. package/dist/agentic/guides/modules/customer_accounts.md +1 -1
  20. package/dist/agentic/guides/modules/customers.md +1 -1
  21. package/dist/agentic/guides/modules/dashboards.md +1 -1
  22. package/dist/agentic/guides/modules/data_sync.md +1 -1
  23. package/dist/agentic/guides/modules/design_system.md +1 -1
  24. package/dist/agentic/guides/modules/dictionaries.md +1 -1
  25. package/dist/agentic/guides/modules/directory.md +1 -1
  26. package/dist/agentic/guides/modules/entities.md +1 -1
  27. package/dist/agentic/guides/modules/events.md +1 -1
  28. package/dist/agentic/guides/modules/feature_toggles.md +1 -1
  29. package/dist/agentic/guides/modules/gateway_stripe.md +1 -1
  30. package/dist/agentic/guides/modules/generators.md +1 -1
  31. package/dist/agentic/guides/modules/inbox_ops.md +1 -1
  32. package/dist/agentic/guides/modules/integrations.md +1 -1
  33. package/dist/agentic/guides/modules/messages.md +1 -1
  34. package/dist/agentic/guides/modules/notifications.md +1 -1
  35. package/dist/agentic/guides/modules/onboarding.md +1 -1
  36. package/dist/agentic/guides/modules/payment_gateways.md +1 -1
  37. package/dist/agentic/guides/modules/perspectives.md +1 -1
  38. package/dist/agentic/guides/modules/planner.md +1 -1
  39. package/dist/agentic/guides/modules/portal.md +1 -1
  40. package/dist/agentic/guides/modules/progress.md +1 -1
  41. package/dist/agentic/guides/modules/query_index.md +1 -1
  42. package/dist/agentic/guides/modules/record_locks.md +1 -1
  43. package/dist/agentic/guides/modules/resources.md +1 -1
  44. package/dist/agentic/guides/modules/sales.md +1 -1
  45. package/dist/agentic/guides/modules/scheduler.md +1 -1
  46. package/dist/agentic/guides/modules/search.md +1 -1
  47. package/dist/agentic/guides/modules/security.md +1 -1
  48. package/dist/agentic/guides/modules/shipping_carriers.md +1 -1
  49. package/dist/agentic/guides/modules/sso.md +1 -1
  50. package/dist/agentic/guides/modules/staff.md +1 -1
  51. package/dist/agentic/guides/modules/storage_s3.md +1 -1
  52. package/dist/agentic/guides/modules/sync_akeneo.md +1 -1
  53. package/dist/agentic/guides/modules/sync_excel.md +1 -1
  54. package/dist/agentic/guides/modules/system_status_overlays.md +1 -1
  55. package/dist/agentic/guides/modules/translations.md +1 -1
  56. package/dist/agentic/guides/modules/webhooks.md +1 -1
  57. package/dist/agentic/guides/modules/wms.md +1 -1
  58. package/dist/agentic/guides/modules/workflows.md +1 -1
  59. package/dist/agentic/guides/upstream/AGENTS.md +2 -1
  60. package/dist/agentic/guides/upstream/manifest.json +2 -2
  61. package/dist/bin.js +20 -34
  62. package/dist/bin.js.map +2 -2
  63. package/dist/lib/cli-bootstrap-mode.js +32 -0
  64. package/dist/lib/cli-bootstrap-mode.js.map +7 -0
  65. package/dist/lib/dev-supervisor-manifest.js +105 -0
  66. package/dist/lib/dev-supervisor-manifest.js.map +7 -0
  67. package/dist/lib/generators/entity-ids.js +11 -24
  68. package/dist/lib/generators/entity-ids.js.map +2 -2
  69. package/dist/lib/generators/module-di.js +10 -23
  70. package/dist/lib/generators/module-di.js.map +2 -2
  71. package/dist/lib/generators/module-entities.js +10 -23
  72. package/dist/lib/generators/module-entities.js.map +2 -2
  73. package/dist/lib/generators/module-registry.js +394 -31
  74. package/dist/lib/generators/module-registry.js.map +2 -2
  75. package/dist/lib/generators/route-manifest-shards.js +170 -0
  76. package/dist/lib/generators/route-manifest-shards.js.map +7 -0
  77. package/dist/lib/queue-worker-supervisor.js.map +2 -2
  78. package/dist/lib/resolver.js +26 -3
  79. package/dist/lib/resolver.js.map +2 -2
  80. package/dist/lib/utils.js +15 -8
  81. package/dist/lib/utils.js.map +2 -2
  82. package/dist/mercato.js +9 -6
  83. package/dist/mercato.js.map +2 -2
  84. package/package.json +6 -6
  85. package/src/__tests__/mercato.test.ts +144 -0
  86. package/src/bin.ts +28 -42
  87. package/src/lib/__tests__/cli-bootstrap-mode.test.ts +22 -0
  88. package/src/lib/__tests__/content-stable-writes.test.ts +74 -0
  89. package/src/lib/__tests__/dev-supervisor-manifest.test.ts +131 -0
  90. package/src/lib/__tests__/queue-worker-supervisor.test.ts +33 -0
  91. package/src/lib/__tests__/resolver.enterprise.test.ts +50 -0
  92. package/src/lib/cli-bootstrap-mode.ts +31 -0
  93. package/src/lib/dev-supervisor-manifest.ts +142 -0
  94. package/src/lib/generators/__tests__/entity-ids.test.ts +32 -0
  95. package/src/lib/generators/__tests__/module-subset.test.ts +248 -0
  96. package/src/lib/generators/__tests__/output-snapshots.test.ts +3 -3
  97. package/src/lib/generators/__tests__/route-manifest-shards.test.ts +62 -0
  98. package/src/lib/generators/entity-ids.ts +10 -26
  99. package/src/lib/generators/module-di.ts +9 -25
  100. package/src/lib/generators/module-entities.ts +9 -25
  101. package/src/lib/generators/module-registry.ts +432 -29
  102. package/src/lib/generators/route-manifest-shards.ts +146 -0
  103. package/src/lib/queue-worker-supervisor.ts +7 -2
  104. package/src/lib/resolver.ts +31 -3
  105. package/src/lib/utils.ts +24 -16
  106. package/src/mercato.ts +15 -6
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/utils.ts"],
4
- "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport { pathToFileURL } from 'node:url'\n\nexport type ChecksumRecord = {\n content: string\n structure: string\n}\n\nexport interface GeneratorResult {\n filesWritten: string[]\n filesUnchanged: string[]\n errors: string[]\n}\n\nexport function calculateChecksum(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex')\n}\n\nexport function readChecksumRecord(filePath: string): ChecksumRecord | null {\n if (!fs.existsSync(filePath)) {\n return null\n }\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<ChecksumRecord>\n if (parsed && typeof parsed.content === 'string' && typeof parsed.structure === 'string') {\n return { content: parsed.content, structure: parsed.structure }\n }\n } catch {\n // Invalid checksum file\n }\n return null\n}\n\nexport function writeChecksumRecord(filePath: string, record: ChecksumRecord): void {\n fs.writeFileSync(filePath, JSON.stringify(record) + '\\n')\n}\n\nfunction collectStructureEntries(target: string, base: string, acc: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(target, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))\n } catch (err) {\n acc.push(`error:${path.relative(base, target)}:${(err as Error).message}`)\n return\n }\n\n for (const entry of entries) {\n const fullPath = path.join(target, entry.name)\n const rel = path.relative(base, fullPath)\n try {\n const stat = fs.statSync(fullPath)\n if (entry.isDirectory()) {\n acc.push(`dir:${rel}:${stat.mtimeMs}`)\n collectStructureEntries(fullPath, base, acc)\n } else if (entry.isFile()) {\n acc.push(`file:${rel}:${stat.size}:${stat.mtimeMs}`)\n } else {\n acc.push(`other:${rel}:${stat.mtimeMs}`)\n }\n } catch {\n // File was deleted between readdir and stat - skip it\n continue\n }\n }\n}\n\nexport function calculateStructureChecksum(paths: string[]): string {\n const normalized = Array.from(new Set(paths.map((p) => path.resolve(p)))).sort((a, b) => a.localeCompare(b))\n const entries: string[] = []\n for (const target of normalized) {\n if (!fs.existsSync(target)) {\n entries.push(`missing:${target}`)\n continue\n }\n const stat = fs.statSync(target)\n entries.push(`${stat.isDirectory() ? 'dir' : 'file'}:${target}:${stat.mtimeMs}`)\n if (stat.isDirectory()) collectStructureEntries(target, target, entries)\n }\n return calculateChecksum(entries.join('\\n'))\n}\n\nexport function writeIfChanged(\n filePath: string,\n content: string,\n checksumPath?: string,\n structureChecksum?: string\n): boolean {\n const newChecksum = calculateChecksum(content)\n\n if (checksumPath) {\n const existingRecord = readChecksumRecord(checksumPath)\n const newRecord: ChecksumRecord = {\n content: newChecksum,\n structure: structureChecksum || '',\n }\n\n const shouldWrite =\n !existingRecord ||\n existingRecord.content !== newRecord.content ||\n (structureChecksum && existingRecord.structure !== newRecord.structure)\n\n if (shouldWrite) {\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n writeChecksumRecord(checksumPath, newRecord)\n return true\n }\n return false\n }\n\n // Simple comparison without checksum file\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf8')\n if (existing === content) {\n return false\n }\n }\n\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n return true\n}\n\nexport function ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n}\n\n// Allowed path substrings for safe deletion. Include both POSIX and Windows separators.\nconst ALLOWED_RIMRAF_PATTERNS = [\n '/generated/',\n '/dist/',\n '/.mercato/',\n '/entities/',\n '\\\\generated\\\\',\n '\\\\dist\\\\',\n '\\\\.mercato\\\\',\n '\\\\entities\\\\',\n]\n\nexport function rimrafDir(dir: string, opts?: { allowedPatterns?: string[] }): void {\n if (!fs.existsSync(dir)) return\n\n // Safety check: only allow deletion within known safe directories\n const resolved = path.resolve(dir)\n const allowed = opts?.allowedPatterns ?? ALLOWED_RIMRAF_PATTERNS\n\n // Normalize resolved path to support matching against both POSIX and Windows patterns\n const normalized = {\n posix: resolved.replace(/\\\\/g, '/'),\n win: resolved.replace(/\\//g, '\\\\'),\n }\n\n if (!allowed.some((pattern) => normalized.posix.includes(pattern) || normalized.win.includes(pattern))) {\n throw new Error(`Refusing to delete directory outside allowed paths: ${resolved}. Allowed patterns: ${allowed.join(', ')}`)\n }\n\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, entry.name)\n if (entry.isDirectory()) rimrafDir(p, opts)\n else fs.unlinkSync(p)\n }\n fs.rmdirSync(dir)\n}\n\nexport function toVar(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n}\n\nexport function toSnake(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/\\W+/g, '_')\n .replace(/_{2,}/g, '_')\n .replace(/(?:^_+|_+$)/g, '')\n .toLowerCase()\n}\n\nexport function sourceFileHasNamedExport(filePath: string, exportName: string): boolean {\n let source: string\n try {\n source = fs.readFileSync(filePath, 'utf8')\n } catch {\n return false\n }\n\n const escaped = exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n if (new RegExp(`export\\\\s+(?:const|let|var|function|class|async\\\\s+function)\\\\s+${escaped}\\\\b`).test(source)) {\n return true\n }\n if (new RegExp(`export\\\\s+\\\\{[^}]*\\\\b${escaped}\\\\b[^}]*\\\\}`).test(source)) {\n return true\n }\n return false\n}\n\nexport async function moduleHasExport(filePath: string, exportName: string): Promise<boolean> {\n if (sourceFileHasNamedExport(filePath, exportName)) {\n return true\n }\n try {\n const isAbsolutePath = path.isAbsolute(filePath)\n const importUrl = isAbsolutePath ? pathToFileURL(filePath).href : filePath\n const mod = await import(importUrl)\n return mod != null && Object.prototype.hasOwnProperty.call(mod, exportName)\n } catch {\n return false\n }\n}\n\nexport function logGenerationResult(label: string, changed: boolean): void {\n if (changed) {\n console.log(`Generated ${label}`)\n }\n}\n\nexport function createGeneratorResult(): GeneratorResult {\n return {\n filesWritten: [],\n filesUnchanged: [],\n errors: [],\n }\n}\n\nexport function writeGeneratedFile(options: {\n outFile: string\n checksumFile: string\n content: string\n structureChecksum: string\n result: GeneratorResult\n quiet?: boolean\n}): void {\n const { outFile, checksumFile, content, structureChecksum, result, quiet } = options\n const checksum = { content: calculateChecksum(content), structure: structureChecksum }\n const existing = readChecksumRecord(checksumFile)\n const shouldWrite =\n !fs.existsSync(outFile) ||\n !existing ||\n existing.content !== checksum.content ||\n existing.structure !== checksum.structure\n if (shouldWrite) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n fs.writeFileSync(outFile, content)\n writeChecksumRecord(checksumFile, checksum)\n result.filesWritten.push(outFile)\n } else {\n result.filesUnchanged.push(outFile)\n }\n if (!quiet) logGenerationResult(path.relative(process.cwd(), outFile), shouldWrite)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport { pathToFileURL } from 'node:url'\n\nexport type ChecksumRecord = {\n content: string\n structure: string\n}\n\nexport interface GeneratorResult {\n filesWritten: string[]\n filesUnchanged: string[]\n errors: string[]\n}\n\nexport function calculateChecksum(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex')\n}\n\nexport function readChecksumRecord(filePath: string): ChecksumRecord | null {\n if (!fs.existsSync(filePath)) {\n return null\n }\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<ChecksumRecord>\n if (parsed && typeof parsed.content === 'string' && typeof parsed.structure === 'string') {\n return { content: parsed.content, structure: parsed.structure }\n }\n } catch {\n // Invalid checksum file\n }\n return null\n}\n\nexport function writeChecksumRecord(filePath: string, record: ChecksumRecord): void {\n fs.writeFileSync(filePath, JSON.stringify(record) + '\\n')\n}\n\nfunction collectStructureEntries(target: string, base: string, acc: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(target, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))\n } catch (err) {\n acc.push(`error:${path.relative(base, target)}:${(err as Error).message}`)\n return\n }\n\n for (const entry of entries) {\n const fullPath = path.join(target, entry.name)\n const rel = path.relative(base, fullPath)\n try {\n const stat = fs.statSync(fullPath)\n if (entry.isDirectory()) {\n acc.push(`dir:${rel}:${stat.mtimeMs}`)\n collectStructureEntries(fullPath, base, acc)\n } else if (entry.isFile()) {\n acc.push(`file:${rel}:${stat.size}:${stat.mtimeMs}`)\n } else {\n acc.push(`other:${rel}:${stat.mtimeMs}`)\n }\n } catch {\n // File was deleted between readdir and stat - skip it\n continue\n }\n }\n}\n\nexport function calculateStructureChecksum(paths: string[]): string {\n const normalized = Array.from(new Set(paths.map((p) => path.resolve(p)))).sort((a, b) => a.localeCompare(b))\n const entries: string[] = []\n for (const target of normalized) {\n if (!fs.existsSync(target)) {\n entries.push(`missing:${target}`)\n continue\n }\n const stat = fs.statSync(target)\n entries.push(`${stat.isDirectory() ? 'dir' : 'file'}:${target}:${stat.mtimeMs}`)\n if (stat.isDirectory()) collectStructureEntries(target, target, entries)\n }\n return calculateChecksum(entries.join('\\n'))\n}\n\nexport function writeIfChanged(\n filePath: string,\n content: string,\n checksumPath?: string,\n structureChecksum?: string\n): boolean {\n const newChecksum = calculateChecksum(content)\n\n if (checksumPath) {\n const existingRecord = readChecksumRecord(checksumPath)\n const newRecord: ChecksumRecord = {\n content: newChecksum,\n structure: structureChecksum || '',\n }\n\n const outputChanged = !fs.existsSync(filePath) || fs.readFileSync(filePath, 'utf8') !== content\n if (outputChanged) {\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n }\n\n const checksumChanged =\n !existingRecord ||\n existingRecord.content !== newRecord.content ||\n existingRecord.structure !== newRecord.structure\n if (checksumChanged) {\n ensureDir(checksumPath)\n writeChecksumRecord(checksumPath, newRecord)\n }\n\n return outputChanged\n }\n\n // Simple comparison without checksum file\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf8')\n if (existing === content) {\n return false\n }\n }\n\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n return true\n}\n\nexport function ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n}\n\n// Allowed path substrings for safe deletion. Include both POSIX and Windows separators.\nconst ALLOWED_RIMRAF_PATTERNS = [\n '/generated/',\n '/dist/',\n '/.mercato/',\n '/entities/',\n '\\\\generated\\\\',\n '\\\\dist\\\\',\n '\\\\.mercato\\\\',\n '\\\\entities\\\\',\n]\n\nexport function rimrafDir(dir: string, opts?: { allowedPatterns?: string[] }): void {\n if (!fs.existsSync(dir)) return\n\n // Safety check: only allow deletion within known safe directories\n const resolved = path.resolve(dir)\n const allowed = opts?.allowedPatterns ?? ALLOWED_RIMRAF_PATTERNS\n\n // Normalize resolved path to support matching against both POSIX and Windows patterns\n const normalized = {\n posix: resolved.replace(/\\\\/g, '/'),\n win: resolved.replace(/\\//g, '\\\\'),\n }\n\n if (!allowed.some((pattern) => normalized.posix.includes(pattern) || normalized.win.includes(pattern))) {\n throw new Error(`Refusing to delete directory outside allowed paths: ${resolved}. Allowed patterns: ${allowed.join(', ')}`)\n }\n\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, entry.name)\n if (entry.isDirectory()) rimrafDir(p, opts)\n else fs.unlinkSync(p)\n }\n fs.rmdirSync(dir)\n}\n\nexport function toVar(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n}\n\nexport function toSnake(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/\\W+/g, '_')\n .replace(/_{2,}/g, '_')\n .replace(/(?:^_+|_+$)/g, '')\n .toLowerCase()\n}\n\nexport function sourceFileHasNamedExport(filePath: string, exportName: string): boolean {\n let source: string\n try {\n source = fs.readFileSync(filePath, 'utf8')\n } catch {\n return false\n }\n\n const escaped = exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n if (new RegExp(`export\\\\s+(?:const|let|var|function|class|async\\\\s+function)\\\\s+${escaped}\\\\b`).test(source)) {\n return true\n }\n if (new RegExp(`export\\\\s+\\\\{[^}]*\\\\b${escaped}\\\\b[^}]*\\\\}`).test(source)) {\n return true\n }\n return false\n}\n\nexport async function moduleHasExport(filePath: string, exportName: string): Promise<boolean> {\n if (sourceFileHasNamedExport(filePath, exportName)) {\n return true\n }\n try {\n const isAbsolutePath = path.isAbsolute(filePath)\n const importUrl = isAbsolutePath ? pathToFileURL(filePath).href : filePath\n const mod = await import(importUrl)\n return mod != null && Object.prototype.hasOwnProperty.call(mod, exportName)\n } catch {\n return false\n }\n}\n\nexport function logGenerationResult(label: string, changed: boolean): void {\n if (changed) {\n console.log(`Generated ${label}`)\n }\n}\n\nexport function createGeneratorResult(): GeneratorResult {\n return {\n filesWritten: [],\n filesUnchanged: [],\n errors: [],\n }\n}\n\nexport function writeGeneratedFile(options: {\n outFile: string\n checksumFile: string\n content: string\n structureChecksum: string\n result: GeneratorResult\n quiet?: boolean\n}): void {\n const { outFile, checksumFile, content, structureChecksum, result, quiet } = options\n const checksum = { content: calculateChecksum(content), structure: structureChecksum }\n const existing = readChecksumRecord(checksumFile)\n const outputChanged = !fs.existsSync(outFile) || fs.readFileSync(outFile, 'utf8') !== content\n if (outputChanged) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n fs.writeFileSync(outFile, content)\n result.filesWritten.push(outFile)\n } else {\n result.filesUnchanged.push(outFile)\n }\n\n const checksumChanged =\n !existing ||\n existing.content !== checksum.content ||\n existing.structure !== checksum.structure\n if (checksumChanged) {\n fs.mkdirSync(path.dirname(checksumFile), { recursive: true })\n writeChecksumRecord(checksumFile, checksum)\n }\n if (!quiet) logGenerationResult(path.relative(process.cwd(), outFile), outputChanged)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/mercato.js CHANGED
@@ -35,6 +35,7 @@ import { acquireServerStartLock } from "./lib/server-start-lock.js";
35
35
  import { assertSingleInstanceStrategies } from "./lib/single-instance-strategy-guard.js";
36
36
  import { createDevEnvReloader, watchDevEnvFiles } from "./lib/dev-env-reload.js";
37
37
  import { quotePostgresIdentifier } from "./lib/db/identifiers.js";
38
+ import { getRegisteredDevSupervisorManifest } from "./lib/dev-supervisor-manifest.js";
38
39
  const lazyIntegration = () => import("./lib/testing/integration.js");
39
40
  import path from "node:path";
40
41
  import fs from "node:fs";
@@ -1626,6 +1627,7 @@ async function run(argv = process.argv) {
1626
1627
  let lastRestartReason = null;
1627
1628
  const generateWatcherMode = resolveGenerateWatcherMode(process.env);
1628
1629
  const envReloader = createDevEnvReloader(appDir, process.env, initialProcessEnvironmentEntries);
1630
+ const devSupervisorManifest = getRegisteredDevSupervisorManifest();
1629
1631
  function cleanup() {
1630
1632
  console.log("[server] Shutting down...");
1631
1633
  for (const proc of processes) {
@@ -1786,8 +1788,8 @@ async function run(argv = process.argv) {
1786
1788
  applyEventsSingleDeliveryGuard({ processEnv: process.env, runtimeEnv, autoSpawnWorkersMode });
1787
1789
  const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env);
1788
1790
  const queueStrategy = process.env.QUEUE_STRATEGY || "local";
1789
- const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
1790
- const embedSchedulerInSharedWorker = shouldEmbedLocalSchedulerInSharedWorker(process.env) && queueStrategy === "local" && autoSpawnWorkersMode === "lazy" && resolveLazySpawnMode(process.env) === "shared" && autoSpawnSchedulerMode !== "off" && schedulerCommand.status === "ok";
1791
+ const schedulerStartStatus = devSupervisorManifest?.schedulerStartStatus ?? lookupModuleCommand(getCliModules(), "scheduler", "start").status;
1792
+ const embedSchedulerInSharedWorker = shouldEmbedLocalSchedulerInSharedWorker(process.env) && queueStrategy === "local" && autoSpawnWorkersMode === "lazy" && resolveLazySpawnMode(process.env) === "shared" && autoSpawnSchedulerMode !== "off" && schedulerStartStatus === "ok";
1791
1793
  const nextRuntime = startNextDev(runtimeEnv);
1792
1794
  const restartPromise = waitForDevRestart();
1793
1795
  const backgroundStartAbort = new AbortController();
@@ -1814,10 +1816,11 @@ async function run(argv = process.argv) {
1814
1816
  console.warn("[server] Timed out waiting for dev warmup marker; starting background services anyway.");
1815
1817
  }
1816
1818
  if (autoSpawnWorkersMode !== "off") {
1817
- const discoveredWorkers = getRegisteredCliWorkers();
1819
+ const discoveredWorkers = devSupervisorManifest?.workers ?? getRegisteredCliWorkers();
1818
1820
  const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))];
1819
1821
  if (discoveredWorkerQueues.length === 0) {
1820
- 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.");
1822
+ const workerRegistryFile = devSupervisorManifest ? "dev-supervisor.generated.json" : "modules.cli.generated.ts";
1823
+ console.error(`[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run \`yarn generate\` and verify \`.mercato/generated/${workerRegistryFile}\` contains worker entries. Continuing without auto-spawned workers.`);
1821
1824
  } else if (autoSpawnWorkersMode === "lazy") {
1822
1825
  const lazySpawnMode = resolveLazySpawnMode(process.env);
1823
1826
  const lazyModeHint = lazySpawnMode === "shared" ? "shared worker mode \u2014 one `queue worker --all` process; set OM_AUTO_SPAWN_WORKERS_LAZY_MODE=per-queue to change" : "per-queue worker mode \u2014 one process per queue; set OM_AUTO_SPAWN_WORKERS_LAZY_MODE=shared to change";
@@ -1858,8 +1861,8 @@ async function run(argv = process.argv) {
1858
1861
  if (embedSchedulerInSharedWorker && activeLazySupervisor) {
1859
1862
  console.log("[server] Local scheduler will run inside the lazy shared worker process.");
1860
1863
  } else if (autoSpawnSchedulerMode !== "off" && queueStrategy === "local") {
1861
- if (schedulerCommand.status !== "ok") {
1862
- console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
1864
+ if (schedulerStartStatus !== "ok") {
1865
+ console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand({ status: schedulerStartStatus })}`);
1863
1866
  } else if (autoSpawnSchedulerMode === "lazy") {
1864
1867
  console.log("[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.");
1865
1868
  activeLazySchedulerSupervisor = startLazySchedulerSupervisor({